Add project files.

This commit is contained in:
Razmoth
2022-09-27 17:40:31 +04:00
parent 871d908948
commit a476ace7d7
305 changed files with 71340 additions and 84 deletions

View File

@@ -0,0 +1,107 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net472;net5.0-windows;net6.0-windows</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
<Version>0.18.00</Version>
<AssemblyVersion>0.18.00</AssemblyVersion>
<FileVersion>0.18.00</FileVersion>
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj" />
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Update="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<Compile Update="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Libraries\x86\fmod.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x86\fmod.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x64\fmod.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x64\fmod.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Libraries\x86\acl.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x86\acl.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x64\acl.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x64\acl.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Libraries\x86\sracl.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x86\sracl.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x64\sracl.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x64\sracl.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
<PackageReference Include="OpenTK" Version="4.6.7" />
<Reference Include="OpenTK.WinForms">
<HintPath>Libraries\OpenTK.WinForms.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
<PackageReference Include="OpenTK" Version="3.1.0" />
<PackageReference Include="OpenTK.GLControl" Version="3.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
<Target Name="CopyExtraFiles" AfterTargets="AfterBuild">
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)x86" ContinueOnError="true" />
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)x64" ContinueOnError="true" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)x86" ContinueOnError="true" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)x64" ContinueOnError="true" />
</Target>
<Target Name="PublishExtraFiles" AfterTargets="Publish">
<Copy SourceFiles="$(TargetDir)x86\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)x86" ContinueOnError="true" />
<Copy SourceFiles="$(TargetDir)x64\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)x64" ContinueOnError="true" />
<Copy SourceFiles="$(TargetDir)x86\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)x86" ContinueOnError="true" />
<Copy SourceFiles="$(TargetDir)x64\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)x64" ContinueOnError="true" />
</Target>
</Project>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>312, 17</value>
</metadata>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>432, 17</value>
</metadata>
<data name="fontPreviewBox.Text" xml:space="preserve">
<value>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ
1234567890.:,;'\"(!?)+-*/=
The quick brown fox jumps over the lazy dog. 1234567890
The quick brown fox jumps over the lazy dog. 1234567890
The quick brown fox jumps over the lazy dog. 1234567890
The quick brown fox jumps over the lazy dog. 1234567890
The quick brown fox jumps over the lazy dog. 1234567890
The quick brown fox jumps over the lazy dog. 1234567890
The quick brown fox jumps over the lazy dog. 1234567890</value>
</data>
<metadata name="timer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>553, 17</value>
</metadata>
<metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>636, 17</value>
</metadata>
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>147, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>67</value>
</metadata>
</root>

View File

@@ -0,0 +1,40 @@
using System.Windows.Forms;
using AssetStudio;
namespace AssetStudioGUI
{
public class AssetItem : ListViewItem
{
public Object Asset;
public SerializedFile SourceFile;
public string Container = string.Empty;
public string TypeString;
public long m_PathID;
public long FullSize;
public ClassIDType Type;
public string InfoText;
public string UniqueID;
public GameObjectTreeNode TreeNode;
public AssetItem(Object asset)
{
Asset = asset;
SourceFile = asset.assetsFile;
Type = asset.type;
TypeString = Type.ToString();
m_PathID = asset.m_PathID;
FullSize = asset.byteSize;
}
public void SetSubItems()
{
SubItems.AddRange(new[]
{
Container, //Container
TypeString, //Type
m_PathID.ToString(), //PathID
FullSize.ToString(), //Size
});
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace AssetStudioGUI
{
internal class GOHierarchy : TreeView
{
protected override void WndProc(ref Message m)
{
// Filter WM_LBUTTONDBLCLK
if (m.Msg != 0x203) base.WndProc(ref m);
}
}
}

View File

@@ -0,0 +1,16 @@
using System.Windows.Forms;
using AssetStudio;
namespace AssetStudioGUI
{
public class GameObjectTreeNode : TreeNode
{
public GameObject gameObject;
public GameObjectTreeNode(GameObject gameObject)
{
this.gameObject = gameObject;
Text = gameObject.m_Name;
}
}
}

View File

@@ -0,0 +1,229 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace AssetStudioGUI
{
internal class OpenFolderDialog
{
public string InitialFolder { get; set; }
public string DefaultFolder { get; set; }
public string Folder { get; private set; }
public string Title { get; set; }
internal DialogResult ShowDialog(IWin32Window owner = null)
{
if (Environment.OSVersion.Version.Major >= 6)
{
return ShowVistaDialog(owner);
}
return ShowFolderBrowserDialog(owner);
}
private DialogResult ShowVistaDialog(IWin32Window owner)
{
var frm = (NativeMethods.IFileDialog)(new NativeMethods.FileOpenDialogRCW());
frm.GetOptions(out var options);
options |= NativeMethods.FOS_PICKFOLDERS | NativeMethods.FOS_FORCEFILESYSTEM | NativeMethods.FOS_NOVALIDATE | NativeMethods.FOS_NOTESTFILECREATE | NativeMethods.FOS_DONTADDTORECENT;
frm.SetOptions(options);
if (!string.IsNullOrEmpty(Title))
{
frm.SetTitle(Title);
}
if (!string.IsNullOrEmpty(InitialFolder))
{
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(InitialFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
{
frm.SetFolder(directoryShellItem);
}
}
if (!string.IsNullOrEmpty(DefaultFolder))
{
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(DefaultFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
{
frm.SetDefaultFolder(directoryShellItem);
}
}
if ((owner == null ? frm.Show() : frm.Show(owner.Handle)) == NativeMethods.S_OK)
{
if (frm.GetResult(out var shellItem) == NativeMethods.S_OK)
{
if (shellItem.GetDisplayName(NativeMethods.SIGDN_FILESYSPATH, out var pszString) == NativeMethods.S_OK)
{
if (pszString != IntPtr.Zero)
{
try
{
Folder = Marshal.PtrToStringAuto(pszString);
return DialogResult.OK;
}
finally
{
Marshal.FreeCoTaskMem(pszString);
}
}
}
}
}
return DialogResult.Cancel;
}
private DialogResult ShowFolderBrowserDialog(IWin32Window owner)
{
using (var frm = new FolderBrowserDialog())
{
if (InitialFolder != null)
{
frm.SelectedPath = InitialFolder;
}
#if !NETFRAMEWORK
if (Title != null)
{
frm.Description = Title;
frm.UseDescriptionForTitle = true;
}
#endif
var result = owner == null ? frm.ShowDialog() : frm.ShowDialog(owner);
if (result == DialogResult.OK)
{
Folder = frm.SelectedPath;
return result;
}
return result;
}
}
}
internal static class NativeMethods
{
#region Constants
public const uint FOS_PICKFOLDERS = 0x00000020;
public const uint FOS_FORCEFILESYSTEM = 0x00000040;
public const uint FOS_NOVALIDATE = 0x00000100;
public const uint FOS_NOTESTFILECREATE = 0x00010000;
public const uint FOS_DONTADDTORECENT = 0x02000000;
public const uint S_OK = 0x0000;
public const uint SIGDN_FILESYSPATH = 0x80058000;
#endregion
#region COM
[ComImport, ClassInterface(ClassInterfaceType.None), TypeLibType(TypeLibTypeFlags.FCanCreate), Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")]
internal class FileOpenDialogRCW { }
[ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IFileDialog
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig()]
uint Show([In, Optional] IntPtr hwndOwner); //IModalWindow
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOptions([In] uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetOptions(out uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint ClearClientData();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
}
[ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItem
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint BindToHandler([In] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IntPtr ppvOut);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetDisplayName([In] uint sigdnName, out IntPtr ppszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
}
#endregion
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
}
}

View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using AssetStudio;
namespace AssetStudioGUI
{
internal class TypeTreeItem : ListViewItem
{
private TypeTree m_Type;
public TypeTreeItem(int typeID, TypeTree m_Type)
{
this.m_Type = m_Type;
Text = m_Type.m_Nodes[0].m_Type + " " + m_Type.m_Nodes[0].m_Name;
SubItems.Add(typeID.ToString());
}
public override string ToString()
{
var sb = new StringBuilder();
foreach (var i in m_Type.m_Nodes)
{
sb.AppendFormat("{0}{1} {2} {3} {4}\r\n", new string('\t', i.m_Level), i.m_Type, i.m_Name, i.m_ByteSize, (i.m_MetaFlag & 0x4000) != 0);
}
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace AssetStudioGUI
{
public sealed class DirectBitmap : IDisposable
{
public DirectBitmap(byte[] buff, int width, int height)
{
Width = width;
Height = height;
Bits = buff;
m_handle = GCHandle.Alloc(Bits, GCHandleType.Pinned);
m_bitmap = new Bitmap(Width, Height, Stride, PixelFormat.Format32bppArgb, m_handle.AddrOfPinnedObject());
}
private void Dispose(bool disposing)
{
if (disposing)
{
m_bitmap.Dispose();
m_handle.Free();
}
m_bitmap = null;
}
public void Dispose()
{
Dispose(true);
}
public int Height { get; }
public int Width { get; }
public int Stride => Width * 4;
public byte[] Bits { get; }
public Bitmap Bitmap => m_bitmap;
private Bitmap m_bitmap;
private readonly GCHandle m_handle;
}
}

667
AssetStudioGUI/ExportOptions.Designer.cs generated Normal file
View File

@@ -0,0 +1,667 @@
namespace AssetStudioGUI
{
partial class ExportOptions
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.OKbutton = new System.Windows.Forms.Button();
this.Cancel = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.disableShader = new System.Windows.Forms.CheckBox();
this.ignoreController = new System.Windows.Forms.CheckBox();
this.disableRndrr = new System.Windows.Forms.CheckBox();
this.exportIndexObject = new System.Windows.Forms.CheckBox();
this.exportAssetBundle = new System.Windows.Forms.CheckBox();
this.openAfterExport = new System.Windows.Forms.CheckBox();
this.restoreExtensionName = new System.Windows.Forms.CheckBox();
this.assetGroupOptions = new System.Windows.Forms.ComboBox();
this.label6 = new System.Windows.Forms.Label();
this.convertAudio = new System.Windows.Forms.CheckBox();
this.panel1 = new System.Windows.Forms.Panel();
this.totga = new System.Windows.Forms.RadioButton();
this.tojpg = new System.Windows.Forms.RadioButton();
this.topng = new System.Windows.Forms.RadioButton();
this.tobmp = new System.Windows.Forms.RadioButton();
this.converttexture = new System.Windows.Forms.CheckBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.exportAllUvsAsDiffuseMaps = new System.Windows.Forms.CheckBox();
this.exportBlendShape = new System.Windows.Forms.CheckBox();
this.exportAnimations = new System.Windows.Forms.CheckBox();
this.scaleFactor = new System.Windows.Forms.NumericUpDown();
this.label5 = new System.Windows.Forms.Label();
this.fbxFormat = new System.Windows.Forms.ComboBox();
this.label4 = new System.Windows.Forms.Label();
this.fbxVersion = new System.Windows.Forms.ComboBox();
this.label3 = new System.Windows.Forms.Label();
this.boneSize = new System.Windows.Forms.NumericUpDown();
this.label2 = new System.Windows.Forms.Label();
this.exportSkins = new System.Windows.Forms.CheckBox();
this.label1 = new System.Windows.Forms.Label();
this.filterPrecision = new System.Windows.Forms.NumericUpDown();
this.castToBone = new System.Windows.Forms.CheckBox();
this.exportAllNodes = new System.Windows.Forms.CheckBox();
this.eulerFilter = new System.Windows.Forms.CheckBox();
this.exportUvsTooltip = new System.Windows.Forms.ToolTip(this.components);
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.enableXor = new System.Windows.Forms.CheckBox();
this.key = new System.Windows.Forms.NumericUpDown();
this.label7 = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.panel1.SuspendLayout();
this.groupBox2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.boneSize)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.filterPrecision)).BeginInit();
this.groupBox3.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.key)).BeginInit();
this.SuspendLayout();
//
// OKbutton
//
this.OKbutton.Location = new System.Drawing.Point(318, 380);
this.OKbutton.Name = "OKbutton";
this.OKbutton.Size = new System.Drawing.Size(75, 23);
this.OKbutton.TabIndex = 6;
this.OKbutton.Text = "OK";
this.OKbutton.UseVisualStyleBackColor = true;
this.OKbutton.Click += new System.EventHandler(this.OKbutton_Click);
//
// Cancel
//
this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.Cancel.Location = new System.Drawing.Point(399, 380);
this.Cancel.Name = "Cancel";
this.Cancel.Size = new System.Drawing.Size(75, 23);
this.Cancel.TabIndex = 7;
this.Cancel.Text = "Cancel";
this.Cancel.UseVisualStyleBackColor = true;
this.Cancel.Click += new System.EventHandler(this.Cancel_Click);
//
// groupBox1
//
this.groupBox1.AutoSize = true;
this.groupBox1.Controls.Add(this.disableShader);
this.groupBox1.Controls.Add(this.ignoreController);
this.groupBox1.Controls.Add(this.disableRndrr);
this.groupBox1.Controls.Add(this.exportIndexObject);
this.groupBox1.Controls.Add(this.exportAssetBundle);
this.groupBox1.Controls.Add(this.openAfterExport);
this.groupBox1.Controls.Add(this.restoreExtensionName);
this.groupBox1.Controls.Add(this.assetGroupOptions);
this.groupBox1.Controls.Add(this.label6);
this.groupBox1.Controls.Add(this.convertAudio);
this.groupBox1.Controls.Add(this.panel1);
this.groupBox1.Controls.Add(this.converttexture);
this.groupBox1.Location = new System.Drawing.Point(12, 13);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(232, 277);
this.groupBox1.TabIndex = 9;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Export";
//
// disableShader
//
this.disableShader.AutoSize = true;
this.disableShader.Location = new System.Drawing.Point(97, 219);
this.disableShader.Name = "disableShader";
this.disableShader.Size = new System.Drawing.Size(98, 17);
this.disableShader.TabIndex = 22;
this.disableShader.Text = "Disable Shader";
this.disableShader.UseVisualStyleBackColor = true;
//
// ignoreController
//
this.ignoreController.AutoSize = true;
this.ignoreController.Checked = true;
this.ignoreController.CheckState = System.Windows.Forms.CheckState.Checked;
this.ignoreController.Location = new System.Drawing.Point(6, 241);
this.ignoreController.Name = "ignoreController";
this.ignoreController.Size = new System.Drawing.Size(152, 17);
this.ignoreController.TabIndex = 21;
this.ignoreController.Text = "Ignore Controller Animation";
this.ignoreController.UseVisualStyleBackColor = true;
//
// disableRndrr
//
this.disableRndrr.AutoSize = true;
this.disableRndrr.Location = new System.Drawing.Point(97, 196);
this.disableRndrr.Name = "disableRndrr";
this.disableRndrr.Size = new System.Drawing.Size(113, 17);
this.disableRndrr.TabIndex = 13;
this.disableRndrr.Text = "Disable Renderers";
this.disableRndrr.UseVisualStyleBackColor = true;
//
// exportIndexObject
//
this.exportIndexObject.AutoSize = true;
this.exportIndexObject.Checked = true;
this.exportIndexObject.CheckState = System.Windows.Forms.CheckState.Checked;
this.exportIndexObject.Location = new System.Drawing.Point(6, 219);
this.exportIndexObject.Name = "exportIndexObject";
this.exportIndexObject.Size = new System.Drawing.Size(83, 17);
this.exportIndexObject.TabIndex = 12;
this.exportIndexObject.Text = "IndexObject";
this.exportIndexObject.UseVisualStyleBackColor = true;
//
// exportAssetBundle
//
this.exportAssetBundle.AutoSize = true;
this.exportAssetBundle.Checked = true;
this.exportAssetBundle.CheckState = System.Windows.Forms.CheckState.Checked;
this.exportAssetBundle.Location = new System.Drawing.Point(6, 196);
this.exportAssetBundle.Name = "exportAssetBundle";
this.exportAssetBundle.Size = new System.Drawing.Size(85, 17);
this.exportAssetBundle.TabIndex = 11;
this.exportAssetBundle.Text = "AssetBundle";
this.exportAssetBundle.UseVisualStyleBackColor = true;
//
// openAfterExport
//
this.openAfterExport.AutoSize = true;
this.openAfterExport.Checked = true;
this.openAfterExport.CheckState = System.Windows.Forms.CheckState.Checked;
this.openAfterExport.Location = new System.Drawing.Point(6, 173);
this.openAfterExport.Name = "openAfterExport";
this.openAfterExport.Size = new System.Drawing.Size(137, 17);
this.openAfterExport.TabIndex = 10;
this.openAfterExport.Text = "Open folder after export";
this.openAfterExport.UseVisualStyleBackColor = true;
//
// restoreExtensionName
//
this.restoreExtensionName.AutoSize = true;
this.restoreExtensionName.Checked = true;
this.restoreExtensionName.CheckState = System.Windows.Forms.CheckState.Checked;
this.restoreExtensionName.Location = new System.Drawing.Point(6, 63);
this.restoreExtensionName.Name = "restoreExtensionName";
this.restoreExtensionName.Size = new System.Drawing.Size(190, 17);
this.restoreExtensionName.TabIndex = 9;
this.restoreExtensionName.Text = "Restore TextAsset extension name";
this.restoreExtensionName.UseVisualStyleBackColor = true;
//
// assetGroupOptions
//
this.assetGroupOptions.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.assetGroupOptions.FormattingEnabled = true;
this.assetGroupOptions.Items.AddRange(new object[] {
"type name",
"container path",
"source file name",
"do not group"});
this.assetGroupOptions.Location = new System.Drawing.Point(6, 35);
this.assetGroupOptions.Name = "assetGroupOptions";
this.assetGroupOptions.Size = new System.Drawing.Size(149, 21);
this.assetGroupOptions.TabIndex = 8;
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(6, 18);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(127, 13);
this.label6.TabIndex = 7;
this.label6.Text = "Group exported assets by";
//
// convertAudio
//
this.convertAudio.AutoSize = true;
this.convertAudio.Checked = true;
this.convertAudio.CheckState = System.Windows.Forms.CheckState.Checked;
this.convertAudio.Location = new System.Drawing.Point(6, 150);
this.convertAudio.Name = "convertAudio";
this.convertAudio.Size = new System.Drawing.Size(179, 17);
this.convertAudio.TabIndex = 6;
this.convertAudio.Text = "Convert AudioClip to WAV(PCM)";
this.convertAudio.UseVisualStyleBackColor = true;
//
// panel1
//
this.panel1.Controls.Add(this.totga);
this.panel1.Controls.Add(this.tojpg);
this.panel1.Controls.Add(this.topng);
this.panel1.Controls.Add(this.tobmp);
this.panel1.Location = new System.Drawing.Point(20, 111);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(202, 32);
this.panel1.TabIndex = 5;
//
// totga
//
this.totga.AutoSize = true;
this.totga.Location = new System.Drawing.Point(150, 6);
this.totga.Name = "totga";
this.totga.Size = new System.Drawing.Size(44, 17);
this.totga.TabIndex = 2;
this.totga.Text = "Tga";
this.totga.UseVisualStyleBackColor = true;
//
// tojpg
//
this.tojpg.AutoSize = true;
this.tojpg.Location = new System.Drawing.Point(97, 6);
this.tojpg.Name = "tojpg";
this.tojpg.Size = new System.Drawing.Size(48, 17);
this.tojpg.TabIndex = 4;
this.tojpg.Text = "Jpeg";
this.tojpg.UseVisualStyleBackColor = true;
//
// topng
//
this.topng.AutoSize = true;
this.topng.Checked = true;
this.topng.Location = new System.Drawing.Point(50, 6);
this.topng.Name = "topng";
this.topng.Size = new System.Drawing.Size(44, 17);
this.topng.TabIndex = 3;
this.topng.TabStop = true;
this.topng.Text = "Png";
this.topng.UseVisualStyleBackColor = true;
//
// tobmp
//
this.tobmp.AutoSize = true;
this.tobmp.Location = new System.Drawing.Point(3, 6);
this.tobmp.Name = "tobmp";
this.tobmp.Size = new System.Drawing.Size(46, 17);
this.tobmp.TabIndex = 2;
this.tobmp.Text = "Bmp";
this.tobmp.UseVisualStyleBackColor = true;
//
// converttexture
//
this.converttexture.AutoSize = true;
this.converttexture.Checked = true;
this.converttexture.CheckState = System.Windows.Forms.CheckState.Checked;
this.converttexture.Location = new System.Drawing.Point(6, 87);
this.converttexture.Name = "converttexture";
this.converttexture.Size = new System.Drawing.Size(116, 17);
this.converttexture.TabIndex = 1;
this.converttexture.Text = "Convert Texture2D";
this.converttexture.UseVisualStyleBackColor = true;
//
// groupBox2
//
this.groupBox2.AutoSize = true;
this.groupBox2.Controls.Add(this.exportAllUvsAsDiffuseMaps);
this.groupBox2.Controls.Add(this.exportBlendShape);
this.groupBox2.Controls.Add(this.exportAnimations);
this.groupBox2.Controls.Add(this.scaleFactor);
this.groupBox2.Controls.Add(this.label5);
this.groupBox2.Controls.Add(this.fbxFormat);
this.groupBox2.Controls.Add(this.label4);
this.groupBox2.Controls.Add(this.fbxVersion);
this.groupBox2.Controls.Add(this.label3);
this.groupBox2.Controls.Add(this.boneSize);
this.groupBox2.Controls.Add(this.label2);
this.groupBox2.Controls.Add(this.exportSkins);
this.groupBox2.Controls.Add(this.label1);
this.groupBox2.Controls.Add(this.filterPrecision);
this.groupBox2.Controls.Add(this.castToBone);
this.groupBox2.Controls.Add(this.exportAllNodes);
this.groupBox2.Controls.Add(this.eulerFilter);
this.groupBox2.Location = new System.Drawing.Point(250, 13);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(224, 362);
this.groupBox2.TabIndex = 11;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Fbx";
//
// exportAllUvsAsDiffuseMaps
//
this.exportAllUvsAsDiffuseMaps.AccessibleDescription = "";
this.exportAllUvsAsDiffuseMaps.AutoSize = true;
this.exportAllUvsAsDiffuseMaps.Location = new System.Drawing.Point(6, 185);
this.exportAllUvsAsDiffuseMaps.Name = "exportAllUvsAsDiffuseMaps";
this.exportAllUvsAsDiffuseMaps.Size = new System.Drawing.Size(168, 17);
this.exportAllUvsAsDiffuseMaps.TabIndex = 23;
this.exportAllUvsAsDiffuseMaps.Text = "Export all UVs as diffuse maps";
this.exportUvsTooltip.SetToolTip(this.exportAllUvsAsDiffuseMaps, "Unchecked: UV1 exported as normal map. Check this if your export is missing a UV " +
"map.");
this.exportAllUvsAsDiffuseMaps.UseVisualStyleBackColor = true;
//
// exportBlendShape
//
this.exportBlendShape.AutoSize = true;
this.exportBlendShape.Checked = true;
this.exportBlendShape.CheckState = System.Windows.Forms.CheckState.Checked;
this.exportBlendShape.Location = new System.Drawing.Point(6, 138);
this.exportBlendShape.Name = "exportBlendShape";
this.exportBlendShape.Size = new System.Drawing.Size(114, 17);
this.exportBlendShape.TabIndex = 22;
this.exportBlendShape.Text = "Export blendshape";
this.exportBlendShape.UseVisualStyleBackColor = true;
//
// exportAnimations
//
this.exportAnimations.AutoSize = true;
this.exportAnimations.Checked = true;
this.exportAnimations.CheckState = System.Windows.Forms.CheckState.Checked;
this.exportAnimations.Location = new System.Drawing.Point(6, 114);
this.exportAnimations.Name = "exportAnimations";
this.exportAnimations.Size = new System.Drawing.Size(109, 17);
this.exportAnimations.TabIndex = 21;
this.exportAnimations.Text = "Export animations";
this.exportAnimations.UseVisualStyleBackColor = true;
//
// scaleFactor
//
this.scaleFactor.DecimalPlaces = 2;
this.scaleFactor.Increment = new decimal(new int[] {
1,
0,
0,
131072});
this.scaleFactor.Location = new System.Drawing.Point(83, 243);
this.scaleFactor.Name = "scaleFactor";
this.scaleFactor.Size = new System.Drawing.Size(60, 20);
this.scaleFactor.TabIndex = 20;
this.scaleFactor.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.scaleFactor.Value = new decimal(new int[] {
1,
0,
0,
0});
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(6, 245);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(64, 13);
this.label5.TabIndex = 19;
this.label5.Text = "ScaleFactor";
//
// fbxFormat
//
this.fbxFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.fbxFormat.FormattingEnabled = true;
this.fbxFormat.Items.AddRange(new object[] {
"Binary",
"Ascii"});
this.fbxFormat.Location = new System.Drawing.Point(77, 275);
this.fbxFormat.Name = "fbxFormat";
this.fbxFormat.Size = new System.Drawing.Size(61, 21);
this.fbxFormat.TabIndex = 18;
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(6, 280);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(59, 13);
this.label4.TabIndex = 17;
this.label4.Text = "FBXFormat";
//
// fbxVersion
//
this.fbxVersion.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.fbxVersion.FormattingEnabled = true;
this.fbxVersion.Items.AddRange(new object[] {
"6.1",
"7.1",
"7.2",
"7.3",
"7.4",
"7.5"});
this.fbxVersion.Location = new System.Drawing.Point(77, 308);
this.fbxVersion.Name = "fbxVersion";
this.fbxVersion.Size = new System.Drawing.Size(47, 21);
this.fbxVersion.TabIndex = 16;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(6, 311);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(62, 13);
this.label3.TabIndex = 15;
this.label3.Text = "FBXVersion";
//
// boneSize
//
this.boneSize.Location = new System.Drawing.Point(65, 213);
this.boneSize.Name = "boneSize";
this.boneSize.Size = new System.Drawing.Size(46, 20);
this.boneSize.TabIndex = 11;
this.boneSize.Value = new decimal(new int[] {
10,
0,
0,
0});
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(6, 216);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(52, 13);
this.label2.TabIndex = 10;
this.label2.Text = "BoneSize";
//
// exportSkins
//
this.exportSkins.AutoSize = true;
this.exportSkins.Checked = true;
this.exportSkins.CheckState = System.Windows.Forms.CheckState.Checked;
this.exportSkins.Location = new System.Drawing.Point(6, 90);
this.exportSkins.Name = "exportSkins";
this.exportSkins.Size = new System.Drawing.Size(83, 17);
this.exportSkins.TabIndex = 8;
this.exportSkins.Text = "Export skins";
this.exportSkins.UseVisualStyleBackColor = true;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(26, 42);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(72, 13);
this.label1.TabIndex = 7;
this.label1.Text = "FilterPrecision";
//
// filterPrecision
//
this.filterPrecision.DecimalPlaces = 2;
this.filterPrecision.Increment = new decimal(new int[] {
1,
0,
0,
131072});
this.filterPrecision.Location = new System.Drawing.Point(127, 40);
this.filterPrecision.Name = "filterPrecision";
this.filterPrecision.Size = new System.Drawing.Size(51, 20);
this.filterPrecision.TabIndex = 6;
this.filterPrecision.Value = new decimal(new int[] {
25,
0,
0,
131072});
//
// castToBone
//
this.castToBone.AutoSize = true;
this.castToBone.Location = new System.Drawing.Point(6, 161);
this.castToBone.Name = "castToBone";
this.castToBone.Size = new System.Drawing.Size(131, 17);
this.castToBone.TabIndex = 5;
this.castToBone.Text = "All nodes cast to bone";
this.castToBone.UseVisualStyleBackColor = true;
//
// exportAllNodes
//
this.exportAllNodes.AutoSize = true;
this.exportAllNodes.Checked = true;
this.exportAllNodes.CheckState = System.Windows.Forms.CheckState.Checked;
this.exportAllNodes.Location = new System.Drawing.Point(6, 66);
this.exportAllNodes.Name = "exportAllNodes";
this.exportAllNodes.Size = new System.Drawing.Size(101, 17);
this.exportAllNodes.TabIndex = 4;
this.exportAllNodes.Text = "Export all nodes";
this.exportAllNodes.UseVisualStyleBackColor = true;
//
// eulerFilter
//
this.eulerFilter.AutoSize = true;
this.eulerFilter.Checked = true;
this.eulerFilter.CheckState = System.Windows.Forms.CheckState.Checked;
this.eulerFilter.Location = new System.Drawing.Point(6, 22);
this.eulerFilter.Name = "eulerFilter";
this.eulerFilter.Size = new System.Drawing.Size(72, 17);
this.eulerFilter.TabIndex = 3;
this.eulerFilter.Text = "EulerFilter";
this.eulerFilter.UseVisualStyleBackColor = true;
//
// groupBox3
//
this.groupBox3.AutoSize = true;
this.groupBox3.Controls.Add(this.enableXor);
this.groupBox3.Controls.Add(this.key);
this.groupBox3.Controls.Add(this.label7);
this.groupBox3.Location = new System.Drawing.Point(12, 296);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(232, 79);
this.groupBox3.TabIndex = 11;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "MiHoYoBinData";
//
// enableXor
//
this.enableXor.AutoSize = true;
this.enableXor.Checked = true;
this.enableXor.CheckState = System.Windows.Forms.CheckState.Checked;
this.enableXor.Location = new System.Drawing.Point(9, 24);
this.enableXor.Name = "enableXor";
this.enableXor.Size = new System.Drawing.Size(85, 17);
this.enableXor.TabIndex = 12;
this.enableXor.Text = "Enable XOR";
this.enableXor.UseVisualStyleBackColor = true;
//
// key
//
this.key.Hexadecimal = true;
this.key.Location = new System.Drawing.Point(124, 21);
this.key.Maximum = new decimal(new int[] {
255,
0,
0,
0});
this.key.Name = "key";
this.key.Size = new System.Drawing.Size(61, 20);
this.key.TabIndex = 8;
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(97, 25);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(25, 13);
this.label7.TabIndex = 7;
this.label7.Text = "Key";
//
// ExportOptions
//
this.AcceptButton = this.OKbutton;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.Cancel;
this.ClientSize = new System.Drawing.Size(486, 416);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.Cancel);
this.Controls.Add(this.OKbutton);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ExportOptions";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Export options";
this.TopMost = true;
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.boneSize)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.filterPrecision)).EndInit();
this.groupBox3.ResumeLayout(false);
this.groupBox3.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.key)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button OKbutton;
private System.Windows.Forms.Button Cancel;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.CheckBox converttexture;
private System.Windows.Forms.RadioButton tojpg;
private System.Windows.Forms.RadioButton topng;
private System.Windows.Forms.RadioButton tobmp;
private System.Windows.Forms.RadioButton totga;
private System.Windows.Forms.CheckBox convertAudio;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.NumericUpDown boneSize;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.CheckBox exportSkins;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.NumericUpDown filterPrecision;
private System.Windows.Forms.CheckBox castToBone;
private System.Windows.Forms.CheckBox exportAllNodes;
private System.Windows.Forms.CheckBox eulerFilter;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.ComboBox fbxVersion;
private System.Windows.Forms.ComboBox fbxFormat;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.NumericUpDown scaleFactor;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.CheckBox exportBlendShape;
private System.Windows.Forms.CheckBox exportAnimations;
private System.Windows.Forms.ComboBox assetGroupOptions;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.CheckBox restoreExtensionName;
private System.Windows.Forms.CheckBox openAfterExport;
private System.Windows.Forms.CheckBox exportAllUvsAsDiffuseMaps;
private System.Windows.Forms.ToolTip exportUvsTooltip;
private System.Windows.Forms.CheckBox exportIndexObject;
private System.Windows.Forms.CheckBox exportAssetBundle;
private System.Windows.Forms.GroupBox groupBox3;
private System.Windows.Forms.NumericUpDown key;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.CheckBox enableXor;
private System.Windows.Forms.CheckBox disableRndrr;
private System.Windows.Forms.CheckBox ignoreController;
private System.Windows.Forms.CheckBox disableShader;
}
}

View File

@@ -0,0 +1,98 @@
using AssetStudio;
using System;
using System.Windows.Forms;
namespace AssetStudioGUI
{
public partial class ExportOptions : Form
{
public ExportOptions()
{
InitializeComponent();
assetGroupOptions.SelectedIndex = Properties.Settings.Default.assetGroupOption;
restoreExtensionName.Checked = Properties.Settings.Default.restoreExtensionName;
converttexture.Checked = Properties.Settings.Default.convertTexture;
convertAudio.Checked = Properties.Settings.Default.convertAudio;
var str = Properties.Settings.Default.convertType.ToString();
foreach (Control c in panel1.Controls)
{
if (c.Text == str)
{
((RadioButton)c).Checked = true;
break;
}
}
openAfterExport.Checked = Properties.Settings.Default.openAfterExport;
exportAssetBundle.Checked = Properties.Settings.Default.exportAssetBundle;
exportIndexObject.Checked = Properties.Settings.Default.exportIndexObject;
disableRndrr.Checked = Properties.Settings.Default.disableRndrr;
disableShader.Checked = Properties.Settings.Default.disableShader;
key.Value = Properties.Settings.Default.key;
enableXor.Checked = Properties.Settings.Default.enableXor;
ignoreController.Checked = Properties.Settings.Default.ignoreController;
eulerFilter.Checked = Properties.Settings.Default.eulerFilter;
filterPrecision.Value = Properties.Settings.Default.filterPrecision;
exportAllNodes.Checked = Properties.Settings.Default.exportAllNodes;
exportSkins.Checked = Properties.Settings.Default.exportSkins;
exportAnimations.Checked = Properties.Settings.Default.exportAnimations;
exportBlendShape.Checked = Properties.Settings.Default.exportBlendShape;
castToBone.Checked = Properties.Settings.Default.castToBone;
exportAllUvsAsDiffuseMaps.Checked = Properties.Settings.Default.exportAllUvsAsDiffuseMaps;
boneSize.Value = Properties.Settings.Default.boneSize;
scaleFactor.Value = Properties.Settings.Default.scaleFactor;
fbxVersion.SelectedIndex = Properties.Settings.Default.fbxVersion;
fbxFormat.SelectedIndex = Properties.Settings.Default.fbxFormat;
}
private void OKbutton_Click(object sender, EventArgs e)
{
Properties.Settings.Default.assetGroupOption = assetGroupOptions.SelectedIndex;
Properties.Settings.Default.restoreExtensionName = restoreExtensionName.Checked;
Properties.Settings.Default.convertTexture = converttexture.Checked;
Properties.Settings.Default.convertAudio = convertAudio.Checked;
foreach (Control c in panel1.Controls)
{
if (((RadioButton)c).Checked)
{
Properties.Settings.Default.convertType = (ImageFormat)Enum.Parse(typeof(ImageFormat), c.Text);
break;
}
}
Properties.Settings.Default.openAfterExport = openAfterExport.Checked;
Properties.Settings.Default.exportAssetBundle = exportAssetBundle.Checked;
AssetBundle.Exportable = Properties.Settings.Default.exportAssetBundle;
Properties.Settings.Default.exportIndexObject = exportIndexObject.Checked;
IndexObject.Exportable = Properties.Settings.Default.exportAssetBundle;
Properties.Settings.Default.disableRndrr = disableRndrr.Checked;
Renderer.Parsable = !Properties.Settings.Default.disableRndrr;
Properties.Settings.Default.disableShader = disableShader.Checked;
Shader.Parsable = !Properties.Settings.Default.disableShader;
Properties.Settings.Default.key = (byte)key.Value;
Properties.Settings.Default.enableXor = enableXor.Checked;
MiHoYoBinData.Key = (byte)key.Value;
MiHoYoBinData.doXOR = enableXor.Checked;
Properties.Settings.Default.ignoreController = ignoreController.Checked;
Properties.Settings.Default.eulerFilter = eulerFilter.Checked;
Properties.Settings.Default.filterPrecision = filterPrecision.Value;
Properties.Settings.Default.exportAllNodes = exportAllNodes.Checked;
Properties.Settings.Default.exportSkins = exportSkins.Checked;
Properties.Settings.Default.exportAnimations = exportAnimations.Checked;
Properties.Settings.Default.exportBlendShape = exportBlendShape.Checked;
Properties.Settings.Default.castToBone = castToBone.Checked;
Properties.Settings.Default.exportAllUvsAsDiffuseMaps = exportAllUvsAsDiffuseMaps.Checked;
Properties.Settings.Default.boneSize = boneSize.Value;
Properties.Settings.Default.scaleFactor = scaleFactor.Value;
Properties.Settings.Default.fbxVersion = fbxVersion.SelectedIndex;
Properties.Settings.Default.fbxFormat = fbxFormat.SelectedIndex;
Properties.Settings.Default.Save();
DialogResult = DialogResult.OK;
Close();
}
private void Cancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
}
}

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="exportUvsTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

466
AssetStudioGUI/Exporter.cs Normal file
View File

@@ -0,0 +1,466 @@
using AssetStudio;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace AssetStudioGUI
{
internal static class Exporter
{
public static bool ExportTexture2D(AssetItem item, string exportPath)
{
var m_Texture2D = (Texture2D)item.Asset;
if (Properties.Settings.Default.convertTexture)
{
var type = Properties.Settings.Default.convertType;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
var image = m_Texture2D.ConvertToImage(true);
if (image == null)
return false;
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
return true;
}
}
else
{
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
return true;
}
}
public static bool ExportAudioClip(AssetItem item, string exportPath)
{
var m_AudioClip = (AudioClip)item.Asset;
var m_AudioData = m_AudioClip.m_AudioData.GetData();
if (m_AudioData == null || m_AudioData.Length == 0)
return false;
var converter = new AudioClipConverter(m_AudioClip);
if (Properties.Settings.Default.convertAudio && converter.IsSupport)
{
if (!TryExportFile(exportPath, item, ".wav", out var exportFullPath))
return false;
var buffer = converter.ConvertToWav();
if (buffer == null)
return false;
File.WriteAllBytes(exportFullPath, buffer);
}
else
{
if (!TryExportFile(exportPath, item, converter.GetExtensionName(), out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_AudioData);
}
return true;
}
public static bool ExportShader(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".shader", out var exportFullPath))
return false;
var m_Shader = (Shader)item.Asset;
var str = m_Shader.Convert(Studio.Game);
File.WriteAllText(exportFullPath, str);
return true;
}
public static bool ExportTextAsset(AssetItem item, string exportPath)
{
var m_TextAsset = (TextAsset)(item.Asset);
var extension = ".txt";
if (Properties.Settings.Default.restoreExtensionName)
{
if (!string.IsNullOrEmpty(item.Container))
{
extension = Path.GetExtension(item.Container);
}
}
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_TextAsset.m_Script);
return true;
}
public static bool ExportMonoBehaviour(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
return false;
var m_MonoBehaviour = (MonoBehaviour)item.Asset;
var type = m_MonoBehaviour.ToType();
if (type == null)
{
var m_Type = Studio.MonoBehaviourToTypeTree(m_MonoBehaviour);
type = m_MonoBehaviour.ToType(m_Type);
}
var str = JsonConvert.SerializeObject(type, Formatting.Indented);
File.WriteAllText(exportFullPath, str);
return true;
}
public static bool ExportAssetBundle(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
return false;
var m_AssetBundle = (AssetBundle)item.Asset;
var str = JsonConvert.SerializeObject(m_AssetBundle, Formatting.Indented);
File.WriteAllText(exportFullPath, str);
return true;
}
public static bool ExportIndexObject(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
return false;
var m_IndexObject = (IndexObject)item.Asset;
var str = JsonConvert.SerializeObject(m_IndexObject, Formatting.Indented);
File.WriteAllText(exportFullPath, str);
return true;
}
public static bool ExportMiHoYoBinData(AssetItem item, string exportPath)
{
string exportFullPath;
if (item.Asset is MiHoYoBinData m_MiHoYoBinData)
{
switch (m_MiHoYoBinData.Type)
{
case MiHoYoBinDataType.JSON:
if (!TryExportFile(exportPath, item, ".json", out exportFullPath))
return false;
var json = m_MiHoYoBinData.Dump() as string;
if (json.Length != 0)
{
File.WriteAllText(exportFullPath, json);
return true;
}
break;
case MiHoYoBinDataType.Bytes:
if (!TryExportFile(exportPath, item, ".bin", out exportFullPath))
return false;
var bytes = m_MiHoYoBinData.Dump() as byte[];
if (bytes.Length != 0)
{
File.WriteAllBytes(exportFullPath, bytes);
return true;
}
break;
}
}
return false;
}
public static bool ExportFont(AssetItem item, string exportPath)
{
var m_Font = (Font)item.Asset;
if (m_Font.m_FontData != null)
{
var extension = ".ttf";
if (m_Font.m_FontData[0] == 79 && m_Font.m_FontData[1] == 84 && m_Font.m_FontData[2] == 84 && m_Font.m_FontData[3] == 79)
{
extension = ".otf";
}
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_Font.m_FontData);
return true;
}
return false;
}
public static bool ExportMesh(AssetItem item, string exportPath)
{
var m_Mesh = (Mesh)item.Asset;
if (m_Mesh.m_VertexCount <= 0)
return false;
if (!TryExportFile(exportPath, item, ".obj", out var exportFullPath))
return false;
var sb = new StringBuilder();
sb.AppendLine("g " + m_Mesh.m_Name);
#region Vertices
if (m_Mesh.m_Vertices == null || m_Mesh.m_Vertices.Length == 0)
{
return false;
}
int c = 3;
if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4)
{
c = 4;
}
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
{
sb.AppendFormat("v {0} {1} {2}\r\n", -m_Mesh.m_Vertices[v * c], m_Mesh.m_Vertices[v * c + 1], m_Mesh.m_Vertices[v * c + 2]);
}
#endregion
#region UV
if (m_Mesh.m_UV0?.Length > 0)
{
c = 4;
if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 2)
{
c = 2;
}
else if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 3)
{
c = 3;
}
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
{
sb.AppendFormat("vt {0} {1}\r\n", m_Mesh.m_UV0[v * c], m_Mesh.m_UV0[v * c + 1]);
}
}
#endregion
#region Normals
if (m_Mesh.m_Normals?.Length > 0)
{
if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3)
{
c = 3;
}
else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4)
{
c = 4;
}
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
{
sb.AppendFormat("vn {0} {1} {2}\r\n", -m_Mesh.m_Normals[v * c], m_Mesh.m_Normals[v * c + 1], m_Mesh.m_Normals[v * c + 2]);
}
}
#endregion
#region Face
int sum = 0;
for (var i = 0; i < m_Mesh.m_SubMeshes.Length; i++)
{
sb.AppendLine($"g {m_Mesh.m_Name}_{i}");
int indexCount = (int)m_Mesh.m_SubMeshes[i].indexCount;
var end = sum + indexCount / 3;
for (int f = sum; f < end; f++)
{
sb.AppendFormat("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\r\n", m_Mesh.m_Indices[f * 3 + 2] + 1, m_Mesh.m_Indices[f * 3 + 1] + 1, m_Mesh.m_Indices[f * 3] + 1);
}
sum = end;
}
#endregion
sb.Replace("NaN", "0");
File.WriteAllText(exportFullPath, sb.ToString());
return true;
}
public static bool ExportVideoClip(AssetItem item, string exportPath)
{
var m_VideoClip = (VideoClip)item.Asset;
if (m_VideoClip.m_ExternalResources.m_Size > 0)
{
if (!TryExportFile(exportPath, item, Path.GetExtension(m_VideoClip.m_OriginalPath), out var exportFullPath))
return false;
m_VideoClip.m_VideoData.WriteData(exportFullPath);
return true;
}
return false;
}
public static bool ExportMovieTexture(AssetItem item, string exportPath)
{
var m_MovieTexture = (MovieTexture)item.Asset;
if (!TryExportFile(exportPath, item, ".ogv", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_MovieTexture.m_MovieData);
return true;
}
public static bool ExportSprite(AssetItem item, string exportPath)
{
var type = Properties.Settings.Default.convertType;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
var image = ((Sprite)item.Asset).GetImage();
if (image != null)
{
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
return true;
}
}
return false;
}
public static bool ExportMaterial(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
return false;
var m_Material = (Material)item.Asset;
var str = JsonConvert.SerializeObject(m_Material, Formatting.Indented);
File.WriteAllText(exportFullPath, str);
return true;
}
public static bool ExportRawFile(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
return true;
}
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath)
{
var fileName = FixFileName(item.Text);
fullPath = Path.Combine(dir, fileName + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
return false;
}
public static bool ExportAnimationClip(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".anim", out var exportFullPath))
return false;
var m_AnimationClip = (AnimationClip)item.Asset;
var str = m_AnimationClip.Convert(Studio.Game);
File.WriteAllText(exportFullPath, str);
return true;
}
public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
{
var exportFullPath = Path.Combine(exportPath, item.Text, item.Text + ".fbx");
if (File.Exists(exportFullPath))
{
exportFullPath = Path.Combine(exportPath, item.Text + item.UniqueID, item.Text + ".fbx");
}
var m_Animator = (Animator)item.Asset;
var convert = animationList != null
? new ModelConverter(m_Animator, Properties.Settings.Default.convertType, Studio.Game, animationList.Select(x => (AnimationClip)x.Asset).ToArray(), Properties.Settings.Default.ignoreController)
: new ModelConverter(m_Animator, Properties.Settings.Default.convertType, Studio.Game, ignoreController: Properties.Settings.Default.ignoreController);
ExportFbx(convert, exportFullPath);
return true;
}
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
{
var convert = animationList != null
? new ModelConverter(gameObject, Properties.Settings.Default.convertType, Studio.Game, animationList.Select(x => (AnimationClip)x.Asset).ToArray(), Properties.Settings.Default.ignoreController)
: new ModelConverter(gameObject, Properties.Settings.Default.convertType, Studio.Game, ignoreController: Properties.Settings.Default.ignoreController);
exportPath = exportPath + FixFileName(gameObject.m_Name) + ".fbx";
ExportFbx(convert, exportPath);
}
public static void ExportGameObjectMerge(List<GameObject> gameObject, string exportPath, List<AssetItem> animationList = null)
{
var rootName = Path.GetFileNameWithoutExtension(exportPath);
var convert = animationList != null
? new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType, Studio.Game, animationList.Select(x => (AnimationClip)x.Asset).ToArray(), Properties.Settings.Default.ignoreController)
: new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType, Studio.Game, ignoreController: Properties.Settings.Default.ignoreController);
ExportFbx(convert, exportPath);
}
private static void ExportFbx(IImported convert, string exportPath)
{
var eulerFilter = Properties.Settings.Default.eulerFilter;
var filterPrecision = (float)Properties.Settings.Default.filterPrecision;
var exportAllNodes = Properties.Settings.Default.exportAllNodes;
var exportSkins = Properties.Settings.Default.exportSkins;
var exportAnimations = Properties.Settings.Default.exportAnimations;
var exportBlendShape = Properties.Settings.Default.exportBlendShape;
var castToBone = Properties.Settings.Default.castToBone;
var boneSize = (int)Properties.Settings.Default.boneSize;
var exportAllUvsAsDiffuseMaps = Properties.Settings.Default.exportAllUvsAsDiffuseMaps;
var scaleFactor = (float)Properties.Settings.Default.scaleFactor;
var fbxVersion = Properties.Settings.Default.fbxVersion;
var fbxFormat = Properties.Settings.Default.fbxFormat;
ModelExporter.ExportFbx(exportPath, convert, eulerFilter, filterPrecision,
exportAllNodes, exportSkins, exportAnimations, exportBlendShape, castToBone, boneSize, exportAllUvsAsDiffuseMaps, scaleFactor, fbxVersion, fbxFormat == 1);
}
public static bool ExportDumpFile(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
return false;
var str = item.Asset.Dump();
if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour)
{
var m_Type = Studio.MonoBehaviourToTypeTree(m_MonoBehaviour);
str = m_MonoBehaviour.Dump(m_Type);
}
if (str != null)
{
File.WriteAllText(exportFullPath, str);
return true;
}
return false;
}
public static bool ExportConvertFile(AssetItem item, string exportPath)
{
switch (item.Type)
{
case ClassIDType.Texture2D:
return ExportTexture2D(item, exportPath);
case ClassIDType.AudioClip:
return ExportAudioClip(item, exportPath);
case ClassIDType.Shader:
return ExportShader(item, exportPath);
case ClassIDType.TextAsset:
return ExportTextAsset(item, exportPath);
case ClassIDType.MonoBehaviour:
return ExportMonoBehaviour(item, exportPath);
case ClassIDType.Font:
return ExportFont(item, exportPath);
case ClassIDType.Mesh:
return ExportMesh(item, exportPath);
case ClassIDType.VideoClip:
return ExportVideoClip(item, exportPath);
case ClassIDType.MovieTexture:
return ExportMovieTexture(item, exportPath);
case ClassIDType.Sprite:
return ExportSprite(item, exportPath);
case ClassIDType.Material:
return ExportMaterial(item, exportPath);
case ClassIDType.Animator:
return ExportAnimator(item, exportPath);
case ClassIDType.AnimationClip:
return ExportAnimationClip(item, exportPath);
case ClassIDType.AssetBundle:
return ExportAssetBundle(item, exportPath);
case ClassIDType.IndexObject:
return ExportIndexObject(item, exportPath);
case ClassIDType.MiHoYoBinData:
return ExportMiHoYoBinData(item, exportPath);
default:
return ExportRawFile(item, exportPath);
}
}
public static string FixFileName(string str)
{
if (str.Length >= 260) return Path.GetRandomFileName();
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
}
}

View File

@@ -0,0 +1,34 @@
using AssetStudio;
using System;
using System.Windows.Forms;
namespace AssetStudioGUI
{
class GUILogger : ILogger
{
public bool ShowErrorMessage = true;
private Action<string> action;
public GUILogger(Action<string> action)
{
this.action = action;
}
public void Log(LoggerEvent loggerEvent, string message)
{
switch (loggerEvent)
{
case LoggerEvent.Error:
if (ShowErrorMessage)
{
MessageBox.Show(message);
}
break;
default:
action(message);
break;
}
}
}
}

Binary file not shown.

25
AssetStudioGUI/Program.cs Normal file
View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AssetStudioGUI
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
#if !NETFRAMEWORK
Application.SetHighDpiMode(HighDpiMode.SystemAware);
#endif
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new AssetStudioGUIForm());
}
}
}

View File

@@ -0,0 +1,166 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AssetStudioGUI.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AssetStudioGUI.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>
internal static System.Drawing.Icon _as {
get {
object obj = ResourceManager.GetObject("_as", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
/// <summary>
/// Looks up a localized string similar to #version 140
///
///in vec3 normal;
///
///out vec4 outputColor;
///
///void main()
///{
/// vec3 unitNormal = normalize(normal);
/// float nDotProduct = clamp(dot(unitNormal, vec3(0.707, 0, 0.707)), 0, 1);
/// vec2 ContributionWeightsSqrt = vec2(0.5, 0.5f) + vec2(0.5f, -0.5f) * unitNormal.y;
/// vec2 ContributionWeights = ContributionWeightsSqrt * ContributionWeightsSqrt;
///
/// vec3 color = nDotProduct * vec3(1, 0.957, 0.839) / 3.14159;
/// color += vec3(0.779, 0.716, 0.453) * ContributionWeights.y;
/// color += vec3(0.368, 0.477, 0. [rest of string was truncated]&quot;;.
/// </summary>
internal static string fs {
get {
return ResourceManager.GetString("fs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to #version 140
///
///out vec4 outputColor;
///
///void main()
///{
/// outputColor = vec4(0, 0, 0, 1);
///}.
/// </summary>
internal static string fsBlack {
get {
return ResourceManager.GetString("fsBlack", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to #version 140
///
///out vec4 outputColor;
///in vec4 color;
///
///void main()
///{
/// outputColor = color;
///}.
/// </summary>
internal static string fsColor {
get {
return ResourceManager.GetString("fsColor", resourceCulture);
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap preview {
get {
object obj = ResourceManager.GetObject("preview", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized string similar to #version 140
///
///in vec3 vertexPosition;
///in vec3 normalDirection;
///in vec4 vertexColor;
///uniform mat4 modelMatrix;
///uniform mat4 viewMatrix;
///uniform mat4 projMatrix;
///
///out vec3 normal;
///out vec4 color;
///
///void main()
///{
/// gl_Position = projMatrix * viewMatrix * modelMatrix * vec4(vertexPosition, 1.0);
/// normal = normalDirection;
/// color = vertexColor;
///}.
/// </summary>
internal static string vs {
get {
return ResourceManager.GetString("vs", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,188 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="fs" xml:space="preserve">
<value>#version 140
in vec3 normal;
out vec4 outputColor;
void main()
{
vec3 unitNormal = normalize(normal);
float nDotProduct = clamp(dot(unitNormal, vec3(0.707, 0, 0.707)), 0, 1);
vec2 ContributionWeightsSqrt = vec2(0.5, 0.5f) + vec2(0.5f, -0.5f) * unitNormal.y;
vec2 ContributionWeights = ContributionWeightsSqrt * ContributionWeightsSqrt;
vec3 color = nDotProduct * vec3(1, 0.957, 0.839) / 3.14159;
color += vec3(0.779, 0.716, 0.453) * ContributionWeights.y;
color += vec3(0.368, 0.477, 0.735) * ContributionWeights.x;
outputColor = vec4(sqrt(color), 1);
}</value>
</data>
<data name="fsBlack" xml:space="preserve">
<value>#version 140
out vec4 outputColor;
void main()
{
outputColor = vec4(0, 0, 0, 1);
}</value>
</data>
<data name="fsColor" xml:space="preserve">
<value>#version 140
out vec4 outputColor;
in vec4 color;
void main()
{
outputColor = color;
}</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="preview" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\preview.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="vs" xml:space="preserve">
<value>#version 140
in vec3 vertexPosition;
in vec3 normalDirection;
in vec4 vertexColor;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projMatrix;
out vec3 normal;
out vec4 color;
void main()
{
gl_Position = projMatrix * viewMatrix * modelMatrix * vec4(vertexPosition, 1.0);
normal = normalDirection;
color = vertexColor;
}</value>
</data>
<data name="_as" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\as.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@@ -0,0 +1,495 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace AssetStudioGUI.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool console
{
get
{
return ((bool)(this["console"]));
}
set
{
this["console"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool displayAll
{
get
{
return ((bool)(this["displayAll"]));
}
set
{
this["displayAll"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool enablePreview
{
get
{
return ((bool)(this["enablePreview"]));
}
set
{
this["enablePreview"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool enableResolveDependencies
{
get
{
return ((bool)(this["enableResolveDependencies"]));
}
set
{
this["enableResolveDependencies"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool displayInfo
{
get
{
return ((bool)(this["displayInfo"]));
}
set
{
this["displayInfo"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool openAfterExport
{
get
{
return ((bool)(this["openAfterExport"]));
}
set
{
this["openAfterExport"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int selectedGame
{
get
{
return ((int)(this["selectedGame"]));
}
set
{
this["selectedGame"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int assetGroupOption
{
get
{
return ((int)(this["assetGroupOption"]));
}
set
{
this["assetGroupOption"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool convertTexture
{
get
{
return ((bool)(this["convertTexture"]));
}
set
{
this["convertTexture"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool convertAudio
{
get
{
return ((bool)(this["convertAudio"]));
}
set
{
this["convertAudio"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Png")]
public global::AssetStudio.ImageFormat convertType
{
get
{
return ((global::AssetStudio.ImageFormat)(this["convertType"]));
}
set
{
this["convertType"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool exportAssetBundle
{
get
{
return ((bool)(this["exportAssetBundle"]));
}
set
{
this["exportAssetBundle"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool exportIndexObject
{
get
{
return ((bool)(this["exportIndexObject"]));
}
set
{
this["exportIndexObject"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool disableRndrr
{
get
{
return ((bool)(this["disableRndrr"]));
}
set
{
this["disableRndrr"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool disableShader
{
get
{
return ((bool)(this["disableShader"]));
}
set
{
this["disableShader"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("147")]
public byte key
{
get
{
return ((byte)(this["key"]));
}
set
{
this["key"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool enableXor
{
get
{
return ((bool)(this["enableXor"]));
}
set
{
this["enableXor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool ignoreController
{
get
{
return ((bool)(this["ignoreController"]));
}
set
{
this["ignoreController"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool eulerFilter
{
get
{
return ((bool)(this["eulerFilter"]));
}
set
{
this["eulerFilter"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0.25")]
public decimal filterPrecision
{
get
{
return ((decimal)(this["filterPrecision"]));
}
set
{
this["filterPrecision"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool exportAllNodes
{
get
{
return ((bool)(this["exportAllNodes"]));
}
set
{
this["exportAllNodes"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool exportSkins
{
get
{
return ((bool)(this["exportSkins"]));
}
set
{
this["exportSkins"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool exportAnimations
{
get
{
return ((bool)(this["exportAnimations"]));
}
set
{
this["exportAnimations"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("10")]
public decimal boneSize
{
get
{
return ((decimal)(this["boneSize"]));
}
set
{
this["boneSize"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("3")]
public int fbxVersion
{
get
{
return ((int)(this["fbxVersion"]));
}
set
{
this["fbxVersion"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int fbxFormat
{
get
{
return ((int)(this["fbxFormat"]));
}
set
{
this["fbxFormat"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("1")]
public decimal scaleFactor
{
get
{
return ((decimal)(this["scaleFactor"]));
}
set
{
this["scaleFactor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool exportBlendShape
{
get
{
return ((bool)(this["exportBlendShape"]));
}
set
{
this["exportBlendShape"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool castToBone
{
get
{
return ((bool)(this["castToBone"]));
}
set
{
this["castToBone"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool restoreExtensionName
{
get
{
return ((bool)(this["restoreExtensionName"]));
}
set
{
this["restoreExtensionName"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool exportAllUvsAsDiffuseMaps
{
get
{
return ((bool)(this["exportAllUvsAsDiffuseMaps"]));
}
set
{
this["exportAllUvsAsDiffuseMaps"] = value;
}
}
}
}

View File

@@ -0,0 +1,99 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="AssetStudioGUI.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="displayAll" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="enablePreview" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="displayInfo" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="openAfterExport" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="assetGroupOption" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="convertTexture" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="convertAudio" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="convertType" Type="AssetStudio.ImageFormat" Scope="User">
<Value Profile="(Default)">Png</Value>
</Setting>
<Setting Name="eulerFilter" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="filterPrecision" Type="System.Decimal" Scope="User">
<Value Profile="(Default)">0.25</Value>
</Setting>
<Setting Name="exportAllNodes" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="exportSkins" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="exportAnimations" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="boneSize" Type="System.Decimal" Scope="User">
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="fbxVersion" Type="System.Int32" Scope="User">
<Value Profile="(Default)">3</Value>
</Setting>
<Setting Name="fbxFormat" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="scaleFactor" Type="System.Decimal" Scope="User">
<Value Profile="(Default)">1</Value>
</Setting>
<Setting Name="exportBlendShape" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="castToBone" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="restoreExtensionName" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="exportAllUvsAsDiffuseMaps" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="key" Type="System.Byte" Scope="User">
<Value Profile="(Default)">147</Value>
</Setting>
<Setting Name="console" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="eanbleXor" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="disableRndrr" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="exportAssetBundle" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="exportIndexObject" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="selectedGame" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="ignoreController" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="disableShader" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="enableResolveDependencies" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
</Settings>
</SettingsFile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

985
AssetStudioGUI/Studio.cs Normal file
View File

@@ -0,0 +1,985 @@
using AssetStudio;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.Xml.Linq;
using static AssetStudioGUI.Exporter;
using Object = AssetStudio.Object;
namespace AssetStudioGUI
{
internal enum ExportType
{
Convert,
Raw,
Dump
}
internal enum ExportFilter
{
All,
Selected,
Filtered
}
internal enum AssetGroupOption
{
ByType,
ByContainer,
BySource,
None
}
internal enum ExportListType
{
XML
}
internal static class Studio
{
public static AssetsManager assetsManager = new AssetsManager();
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
public static List<AssetItem> exportableAssets = new List<AssetItem>();
public static List<AssetItem> visibleAssets = new List<AssetItem>();
internal static Action<string> StatusStripUpdate = x => { };
public static Game Game;
public static int ExtractFolder(string path, string savePath)
{
int extractedCount = 0;
Progress.Reset();
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; i++)
{
var file = files[i];
var fileOriPath = Path.GetDirectoryName(file);
var fileSavePath = fileOriPath.Replace(path, savePath);
extractedCount += ExtractFile(file, fileSavePath);
Progress.Report(i + 1, files.Length);
}
return extractedCount;
}
public static int ExtractFile(string[] fileNames, string savePath)
{
int extractedCount = 0;
Progress.Reset();
for (var i = 0; i < fileNames.Length; i++)
{
var fileName = fileNames[i];
extractedCount += ExtractFile(fileName, savePath);
Progress.Report(i + 1, fileNames.Length);
}
return extractedCount;
}
public static int ExtractFile(string fileName, string savePath)
{
int extractedCount = 0;
var reader = new FileReader(fileName, Game);
if (reader.FileType == FileType.BundleFile)
extractedCount += ExtractBundleFile(reader, savePath);
else if (reader.FileType == FileType.WebFile)
extractedCount += ExtractWebDataFile(reader, savePath);
else if (reader.FileType == FileType.GameFile)
extractedCount += ExtractGameFile(reader, savePath);
else
reader.Dispose();
return extractedCount;
}
private static int ExtractBundleFile(FileReader reader, string savePath)
{
StatusStripUpdate($"Decompressing {reader.FileName} ...");
var bundleFile = new BundleFile(reader);
reader.Dispose();
if (bundleFile.FileList.Length > 0)
{
var extractPath = Path.Combine(savePath, reader.FileName + "_unpacked");
return ExtractStreamFile(extractPath, bundleFile.FileList);
}
return 0;
}
private static int ExtractWebDataFile(FileReader reader, string savePath)
{
StatusStripUpdate($"Decompressing {reader.FileName} ...");
var webFile = new WebFile(reader);
reader.Dispose();
if (webFile.fileList.Length > 0)
{
var extractPath = Path.Combine(savePath, reader.FileName + "_unpacked");
return ExtractStreamFile(extractPath, webFile.fileList);
}
return 0;
}
private static int ExtractGameFile(FileReader reader, string savePath)
{
StatusStripUpdate($"Decompressing {reader.FileName}...");
var gameFile = new GameFile(reader);
reader.Dispose();
var fileList = gameFile.Bundles.SelectMany(x => x.Value).ToList();
if (fileList.Count > 0)
{
var extractPath = Path.Combine(savePath, Path.GetFileNameWithoutExtension(reader.FileName));
return ExtractStreamFile(extractPath, fileList.ToArray());
}
return 0;
}
private static int ExtractStreamFile(string extractPath, StreamFile[] fileList)
{
int extractedCount = 0;
foreach (var file in fileList)
{
var filePath = Path.Combine(extractPath, file.path);
var fileDirectory = Path.GetDirectoryName(filePath);
if (!Directory.Exists(fileDirectory))
{
Directory.CreateDirectory(fileDirectory);
}
if (!File.Exists(filePath))
{
using (var fileStream = File.Create(filePath))
{
file.stream.CopyTo(fileStream);
}
extractedCount += 1;
}
file.stream.Dispose();
}
return extractedCount;
}
public static List<AssetEntry> BuildAssetMap(List<string> files)
{
var assets = new List<AssetEntry>();
for (int i = 0; i < files.Count; i++)
{
var file = files[i];
var reader = new FileReader(file, Game);
var gameFile = new GameFile(reader);
reader.Dispose();
foreach (var bundle in gameFile.Bundles)
{
foreach (var cab in bundle.Value)
{
var dummyPath = Path.Combine(Path.GetDirectoryName(file), cab.fileName);
using (var cabReader = new FileReader(dummyPath, cab.stream, Game))
{
if (cabReader.FileType == FileType.AssetsFile)
{
var assetsFile = new SerializedFile(cabReader, assetsManager, file);
assetsManager.assetsFileList.Add(assetsFile);
assetsFile.m_Objects = assetsFile.m_Objects.Where(x => x.HasExportableType()).ToList();
IndexObject indexObject = null;
var containers = new List<(PPtr<Object>, string)>(assetsFile.m_Objects.Count);
var animators = new List<(PPtr<GameObject>, AssetEntry)>(assetsFile.m_Objects.Count);
var objectAssetItemDic = new Dictionary<Object, AssetEntry>(assetsFile.m_Objects.Count);
foreach (var objInfo in assetsFile.m_Objects)
{
var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objInfo);
var obj = new Object(objectReader);
var asset = new AssetEntry()
{
Source = file,
PathID = objectReader.m_PathID,
Type = objectReader.type,
Container = ""
};
var exportable = true;
switch (objectReader.type)
{
case ClassIDType.AssetBundle:
var assetBundle = new AssetBundle(objectReader);
foreach (var m_Container in assetBundle.Container)
{
var preloadIndex = m_Container.Value.preloadIndex;
var preloadSize = m_Container.Value.preloadSize;
var preloadEnd = preloadIndex + preloadSize;
for (int k = preloadIndex; k < preloadEnd; k++)
{
if (Game.Name == "GI" || Game.Name == "CB2" || Game.Name == "CB3")
{
if (long.TryParse(m_Container.Key, out var containerValue))
{
var last = unchecked((uint)containerValue);
var path = ResourceIndex.GetBundlePath(last);
if (!string.IsNullOrEmpty(path))
{
containers.Add((assetBundle.PreloadTable[k], path));
continue;
}
}
}
containers.Add((assetBundle.PreloadTable[k], m_Container.Key));
}
}
obj = null;
asset.Name = assetBundle.m_Name;
exportable = AssetBundle.Exportable;
break;
case ClassIDType.GameObject:
var gameObject = new GameObject(objectReader);
obj = gameObject;
asset.Name = gameObject.m_Name;
exportable = false;
break;
case ClassIDType.Shader:
asset.Name = objectReader.ReadAlignedString();
if (string.IsNullOrEmpty(asset.Name))
{
var m_parsedForm = new SerializedShader(objectReader);
asset.Name = m_parsedForm.m_Name;
}
break;
case ClassIDType.Animator:
var component = new PPtr<GameObject>(objectReader);
animators.Add((component, asset));
break;
case ClassIDType.MiHoYoBinData:
if (indexObject.Names.TryGetValue(objectReader.m_PathID, out var binName))
{
var path = ResourceIndex.GetContainerFromBinName(file, binName);
asset.Container = path;
asset.Name = !string.IsNullOrEmpty(path) ? Path.GetFileName(path) : binName;
}
exportable = IndexObject.Exportable;
break;
case ClassIDType.IndexObject:
indexObject = new IndexObject(objectReader);
obj = null;
asset.Name = "IndexObject";
exportable = IndexObject.Exportable;
break;
default:
asset.Name = objectReader.ReadAlignedString();
break;
}
if (obj != null)
{
objectAssetItemDic.Add(obj, asset);
assetsFile.AddObject(obj);
}
if (exportable)
{
assets.Add(asset);
}
}
foreach (var pair in animators)
{
if (pair.Item1.TryGet(out var gameObject))
{
pair.Item2.Name = gameObject.m_Name;
}
else
{
Logger.Warning($"Unable to find GameObject with PathID {pair.Item1.m_PathID}, removing...");
assets.Remove(pair.Item2);
}
}
foreach ((var pptr, var container) in containers)
{
if (pptr.TryGet(out var obj))
{
objectAssetItemDic[obj].Container = container;
}
}
assetsManager.assetsFileList.Clear();
}
}
}
}
Logger.Info($"[{i + 1}/{files.Count}] Processed {Path.GetFileName(file)}");
Progress.Report(i + 1, files.Count);
}
return assets;
}
public static (string, List<TreeNode>) BuildAssetData()
{
StatusStripUpdate("Building asset list...");
string productName = null;
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
var containers = new List<(PPtr<Object>, string)>();
int i = 0;
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
foreach (var asset in assetsFile.Objects)
{
var assetItem = new AssetItem(asset);
objectAssetItemDic.Add(asset, assetItem);
assetItem.UniqueID = "#" + i;
var exportable = false;
switch (asset)
{
case GameObject m_GameObject:
assetItem.Text = m_GameObject.m_Name;
break;
case Texture2D m_Texture2D:
if (!string.IsNullOrEmpty(m_Texture2D.m_StreamData?.path))
assetItem.FullSize = asset.byteSize + m_Texture2D.m_StreamData.size;
assetItem.Text = m_Texture2D.m_Name;
exportable = true;
break;
case AudioClip m_AudioClip:
if (!string.IsNullOrEmpty(m_AudioClip.m_Source))
assetItem.FullSize = asset.byteSize + m_AudioClip.m_Size;
assetItem.Text = m_AudioClip.m_Name;
exportable = true;
break;
case VideoClip m_VideoClip:
if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath))
assetItem.FullSize = asset.byteSize + (long)m_VideoClip.m_ExternalResources.m_Size;
assetItem.Text = m_VideoClip.m_Name;
exportable = true;
break;
case Shader m_Shader:
assetItem.Text = m_Shader.m_ParsedForm?.m_Name ?? m_Shader.m_Name;
exportable = true;
break;
case Mesh _:
case TextAsset _:
case AnimationClip _:
case Font _:
case MovieTexture _:
case Sprite _:
case Material _:
assetItem.Text = ((NamedObject)asset).m_Name;
exportable = true;
break;
case Animator m_Animator:
if (m_Animator.m_GameObject.TryGet(out var gameObject))
{
assetItem.Text = gameObject.m_Name;
}
exportable = true;
break;
case MonoBehaviour m_MonoBehaviour:
if (m_MonoBehaviour.m_Name == "" && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{
assetItem.Text = m_Script.m_ClassName;
}
else
{
assetItem.Text = m_MonoBehaviour.m_Name;
}
exportable = true;
break;
case PlayerSettings m_PlayerSettings:
productName = m_PlayerSettings.productName;
break;
case AssetBundle m_AssetBundle:
foreach (var m_Container in m_AssetBundle.Container)
{
var preloadIndex = m_Container.Value.preloadIndex;
var preloadSize = m_Container.Value.preloadSize;
var preloadEnd = preloadIndex + preloadSize;
for (int k = preloadIndex; k < preloadEnd; k++)
{
if (Game.Name == "GI" || Game.Name == "CB2" || Game.Name == "CB3")
{
if (long.TryParse(m_Container.Key, out var containerValue))
{
var last = unchecked((uint)containerValue);
var path = ResourceIndex.GetBundlePath(last);
if (!string.IsNullOrEmpty(path))
{
containers.Add((m_AssetBundle.PreloadTable[k], path));
continue;
}
}
}
containers.Add((m_AssetBundle.PreloadTable[k], m_Container.Key));
}
}
assetItem.Text = m_AssetBundle.m_Name;
exportable = AssetBundle.Exportable;
break;
case IndexObject m_IndexObject:
assetItem.Text = "IndexObject";
exportable = IndexObject.Exportable;
break;
case ResourceManager m_ResourceManager:
foreach (var m_Container in m_ResourceManager.m_Container)
{
containers.Add((m_Container.Value, m_Container.Key));
}
break;
case MiHoYoBinData m_MiHoYoBinData:
if (m_MiHoYoBinData.assetsFile.ObjectsDic.TryGetValue(2, out var obj) && obj is IndexObject indexObject)
{
if (indexObject.Names.TryGetValue(m_MiHoYoBinData.m_PathID, out var binName))
{
string path = "";
var game = GameManager.GetGame("GI");
if (Path.GetExtension(assetsFile.originalPath) == game.Extension)
{
path = ResourceIndex.GetContainerFromBinName(assetsFile.originalPath, binName);
}
else
{
var last = Convert.ToUInt32(binName, 16);
path = ResourceIndex.GetBundlePath(last) ?? "";
}
assetItem.Container = path;
assetItem.Text = !string.IsNullOrEmpty(path) ? Path.GetFileName(path) : binName;
}
}
else assetItem.Text = string.Format("BinFile #{0}", assetItem.m_PathID);
exportable = true;
break;
case NamedObject m_NamedObject:
assetItem.Text = m_NamedObject.m_Name;
break;
}
if (assetItem.Text == "")
{
assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
}
if (Properties.Settings.Default.displayAll || exportable)
{
exportableAssets.Add(assetItem);
}
Progress.Report(++i, objectCount);
}
}
foreach ((var pptr, var container) in containers)
{
if (pptr.TryGet(out var obj))
{
objectAssetItemDic[obj].Container = container;
}
}
foreach (var tmp in exportableAssets)
{
tmp.SetSubItems();
}
containers.Clear();
visibleAssets = exportableAssets;
StatusStripUpdate("Building tree structure...");
var treeNodeCollection = new List<TreeNode>();
var treeNodeDictionary = new Dictionary<GameObject, GameObjectTreeNode>();
var assetsFileCount = assetsManager.assetsFileList.Count;
int j = 0;
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
var fileNode = new TreeNode(assetsFile.fileName); //RootNode
foreach (var obj in assetsFile.Objects)
{
if (obj is GameObject m_GameObject)
{
if (!treeNodeDictionary.TryGetValue(m_GameObject, out var currentNode))
{
currentNode = new GameObjectTreeNode(m_GameObject);
treeNodeDictionary.Add(m_GameObject, currentNode);
}
foreach (var pptr in m_GameObject.m_Components)
{
if (pptr.TryGet(out var m_Component))
{
objectAssetItemDic[m_Component].TreeNode = currentNode;
if (m_Component is MeshFilter m_MeshFilter)
{
if (m_MeshFilter.m_Mesh.TryGet(out var m_Mesh))
{
objectAssetItemDic[m_Mesh].TreeNode = currentNode;
}
}
else if (m_Component is SkinnedMeshRenderer m_SkinnedMeshRenderer)
{
if (m_SkinnedMeshRenderer.m_Mesh.TryGet(out var m_Mesh))
{
objectAssetItemDic[m_Mesh].TreeNode = currentNode;
}
}
}
}
var parentNode = fileNode;
if (m_GameObject.m_Transform != null)
{
if (m_GameObject.m_Transform.m_Father.TryGet(out var m_Father))
{
if (m_Father.m_GameObject.TryGet(out var parentGameObject))
{
if (!treeNodeDictionary.TryGetValue(parentGameObject, out var parentGameObjectNode))
{
parentGameObjectNode = new GameObjectTreeNode(parentGameObject);
treeNodeDictionary.Add(parentGameObject, parentGameObjectNode);
}
parentNode = parentGameObjectNode;
}
}
}
parentNode.Nodes.Add(currentNode);
}
}
if (fileNode.Nodes.Count > 0)
{
treeNodeCollection.Add(fileNode);
}
Progress.Report(++j, assetsFileCount);
}
treeNodeDictionary.Clear();
objectAssetItemDic.Clear();
return (productName, treeNodeCollection);
}
public static Dictionary<string, SortedDictionary<int, TypeTreeItem>> BuildClassStructure()
{
var typeMap = new Dictionary<string, SortedDictionary<int, TypeTreeItem>>();
foreach (var assetsFile in assetsManager.assetsFileList)
{
if (typeMap.TryGetValue(assetsFile.unityVersion, out var curVer))
{
foreach (var type in assetsFile.m_Types.Where(x => x.m_Type != null))
{
var key = type.classID;
if (type.m_ScriptTypeIndex >= 0)
{
key = -1 - type.m_ScriptTypeIndex;
}
curVer[key] = new TypeTreeItem(key, type.m_Type);
}
}
else
{
var items = new SortedDictionary<int, TypeTreeItem>();
foreach (var type in assetsFile.m_Types.Where(x => x.m_Type != null))
{
var key = type.classID;
if (type.m_ScriptTypeIndex >= 0)
{
key = -1 - type.m_ScriptTypeIndex;
}
items[key] = new TypeTreeItem(key, type.m_Type);
}
typeMap.Add(assetsFile.unityVersion, items);
}
}
return typeMap;
}
public static void ExportAssets(string savePath, List<AssetItem> toExportAssets, ExportType exportType)
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
int toExportCount = toExportAssets.Count;
int exportedCount = 0;
int i = 0;
Progress.Reset();
foreach (var asset in toExportAssets)
{
string exportPath;
switch ((AssetGroupOption)Properties.Settings.Default.assetGroupOption)
{
case AssetGroupOption.ByType: //type name
exportPath = Path.Combine(savePath, asset.TypeString);
break;
case AssetGroupOption.ByContainer: //container path
if (!string.IsNullOrEmpty(asset.Container))
{
exportPath = Game.Name == "GI" || Game.Name == "CB2" || Game.Name == "CB3" ? Path.Combine(savePath, Path.GetDirectoryName(asset.Container)) : Path.Combine(savePath, asset.Container);
}
else
{
exportPath = Path.Combine(savePath, asset.TypeString);
}
break;
case AssetGroupOption.BySource: //source file
if (string.IsNullOrEmpty(asset.SourceFile.originalPath))
{
exportPath = Path.Combine(savePath, asset.SourceFile.fileName + "_export");
}
else
{
exportPath = Path.Combine(savePath, Path.GetFileName(asset.SourceFile.originalPath) + "_export", asset.SourceFile.fileName);
}
break;
default:
exportPath = savePath;
break;
}
exportPath += Path.DirectorySeparatorChar;
StatusStripUpdate($"[{exportedCount}/{toExportCount}] Exporting {asset.TypeString}: {asset.Text}");
try
{
switch (exportType)
{
case ExportType.Raw:
if (ExportRawFile(asset, exportPath))
{
exportedCount++;
}
break;
case ExportType.Dump:
if (ExportDumpFile(asset, exportPath))
{
exportedCount++;
}
break;
case ExportType.Convert:
if (ExportConvertFile(asset, exportPath))
{
exportedCount++;
}
break;
}
}
catch (Exception ex)
{
MessageBox.Show($"Export {asset.Type}:{asset.Text} error\r\n{ex.Message}\r\n{ex.StackTrace}");
}
Progress.Report(++i, toExportCount);
}
var statusText = exportedCount == 0 ? "Nothing exported." : $"Finished exporting {exportedCount} assets.";
if (toExportCount > exportedCount)
{
statusText += $" {toExportCount - exportedCount} assets skipped (not extractable or files already exist)";
}
StatusStripUpdate(statusText);
if (Properties.Settings.Default.openAfterExport && exportedCount > 0)
{
OpenFolderInExplorer(savePath);
}
});
}
public static void ExportAssetsMap(string savePath, List<AssetEntry> toExportAssets, ExportListType exportListType)
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Progress.Reset();
string filename;
switch (exportListType)
{
case ExportListType.XML:
filename = Path.Combine(savePath, $"assets_map_{Game.Name}.xml");
var doc = new XDocument(
new XElement("Assets",
new XAttribute("filename", filename),
new XAttribute("createdAt", DateTime.UtcNow.ToString("s")),
toExportAssets.Select(
asset => new XElement("Asset",
new XElement("Name", asset.Name),
new XElement("Container", asset.Container),
new XElement("Type", new XAttribute("id", (int)asset.Type), asset.Type.ToString()),
new XElement("PathID", asset.PathID),
new XElement("Source", asset.Source)
)
)
)
);
doc.Save(filename);
break;
}
var statusText = $"Finished exporting asset list with {toExportAssets.Count()} items.";
StatusStripUpdate(statusText);
Logger.Info($"AssetMap build successfully !!");
if (Properties.Settings.Default.openAfterExport && toExportAssets.Count() > 0)
{
OpenFolderInExplorer(savePath);
}
});
}
public static void ExportAssetsList(string savePath, List<AssetItem> toExportAssets, ExportListType exportListType)
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Progress.Reset();
switch (exportListType)
{
case ExportListType.XML:
var filename = Path.Combine(savePath, "assets.xml");
var doc = new XDocument(
new XElement("Assets",
new XAttribute("filename", filename),
new XAttribute("createdAt", DateTime.UtcNow.ToString("s")),
toExportAssets.Select(
asset => new XElement("Asset",
new XElement("Name", asset.Text),
new XElement("Container", asset.Container),
new XElement("Type", new XAttribute("id", (int)asset.Type), asset.TypeString),
new XElement("PathID", asset.m_PathID),
new XElement("Source", asset.SourceFile.fullName),
new XElement("OriginalPath", asset.SourceFile.originalPath),
new XElement("Size", asset.FullSize)
)
)
)
);
doc.Save(filename);
break;
}
var statusText = $"Finished exporting asset list with {toExportAssets.Count()} items.";
StatusStripUpdate(statusText);
if (Properties.Settings.Default.openAfterExport && toExportAssets.Count() > 0)
{
OpenFolderInExplorer(savePath);
}
});
}
public static void ExportSplitObjects(string savePath, TreeNodeCollection nodes)
{
ThreadPool.QueueUserWorkItem(state =>
{
var count = nodes.Cast<TreeNode>().Sum(x => x.Nodes.Count);
int k = 0;
Progress.Reset();
foreach (TreeNode node in nodes)
{
//遍历一级子节点
foreach (GameObjectTreeNode j in node.Nodes)
{
//收集所有子节点
var gameObjects = new List<GameObject>();
CollectNode(j, gameObjects);
//跳过一些不需要导出的object
if (gameObjects.All(x => x.m_SkinnedMeshRenderer == null && x.m_MeshFilter == null))
{
Progress.Report(++k, count);
continue;
}
//处理非法文件名
var filename = FixFileName(j.Text);
//每个文件存放在单独的文件夹
var targetPath = $"{savePath}{filename}{Path.DirectorySeparatorChar}";
//重名文件处理
for (int i = 1; ; i++)
{
if (Directory.Exists(targetPath))
{
targetPath = $"{savePath}{filename} ({i}){Path.DirectorySeparatorChar}";
}
else
{
break;
}
}
Directory.CreateDirectory(targetPath);
//导出FBX
StatusStripUpdate($"Exporting {filename}.fbx");
try
{
ExportGameObject(j.gameObject, targetPath);
}
catch (Exception ex)
{
MessageBox.Show($"Export GameObject:{j.Text} error\r\n{ex.Message}\r\n{ex.StackTrace}");
}
Progress.Report(++k, count);
StatusStripUpdate($"Finished exporting {filename}.fbx");
}
}
if (Properties.Settings.Default.openAfterExport)
{
OpenFolderInExplorer(savePath);
}
StatusStripUpdate("Finished");
});
}
private static void CollectNode(GameObjectTreeNode node, List<GameObject> gameObjects)
{
gameObjects.Add(node.gameObject);
foreach (GameObjectTreeNode i in node.Nodes)
{
CollectNode(i, gameObjects);
}
}
public static void ExportAnimatorWithAnimationClip(AssetItem animator, List<AssetItem> animationList, string exportPath)
{
ThreadPool.QueueUserWorkItem(state =>
{
Progress.Reset();
StatusStripUpdate($"Exporting {animator.Text}");
try
{
ExportAnimator(animator, exportPath, animationList);
if (Properties.Settings.Default.openAfterExport)
{
OpenFolderInExplorer(exportPath);
}
Progress.Report(1, 1);
StatusStripUpdate($"Finished exporting {animator.Text}");
}
catch (Exception ex)
{
MessageBox.Show($"Export Animator:{animator.Text} error\r\n{ex.Message}\r\n{ex.StackTrace}");
StatusStripUpdate("Error in export");
}
});
}
public static void ExportObjectsWithAnimationClip(string exportPath, TreeNodeCollection nodes, List<AssetItem> animationList = null)
{
ThreadPool.QueueUserWorkItem(state =>
{
var gameObjects = new List<GameObject>();
GetSelectedParentNode(nodes, gameObjects);
if (gameObjects.Count > 0)
{
var count = gameObjects.Count;
int i = 0;
Progress.Reset();
foreach (var gameObject in gameObjects)
{
StatusStripUpdate($"Exporting {gameObject.m_Name}");
try
{
var subExportPath = Path.Combine(exportPath, gameObject.m_Name) + Path.DirectorySeparatorChar;
ExportGameObject(gameObject, subExportPath, animationList);
StatusStripUpdate($"Finished exporting {gameObject.m_Name}");
}
catch (Exception ex)
{
MessageBox.Show($"Export GameObject:{gameObject.m_Name} error\r\n{ex.Message}\r\n{ex.StackTrace}");
StatusStripUpdate("Error in export");
}
Progress.Report(++i, count);
}
if (Properties.Settings.Default.openAfterExport)
{
OpenFolderInExplorer(exportPath);
}
}
else
{
StatusStripUpdate("No Object selected for export.");
}
});
}
public static void ExportObjectsMergeWithAnimationClip(string exportPath, List<GameObject> gameObjects, List<AssetItem> animationList = null)
{
ThreadPool.QueueUserWorkItem(state =>
{
var name = Path.GetFileName(exportPath);
Progress.Reset();
StatusStripUpdate($"Exporting {name}");
try
{
ExportGameObjectMerge(gameObjects, exportPath, animationList);
Progress.Report(1, 1);
StatusStripUpdate($"Finished exporting {name}");
}
catch (Exception ex)
{
MessageBox.Show($"Export Model:{name} error\r\n{ex.Message}\r\n{ex.StackTrace}");
StatusStripUpdate("Error in export");
}
if (Properties.Settings.Default.openAfterExport)
{
OpenFolderInExplorer(Path.GetDirectoryName(exportPath));
}
});
}
public static void GetSelectedParentNode(TreeNodeCollection nodes, List<GameObject> gameObjects)
{
foreach (TreeNode i in nodes)
{
if (i is GameObjectTreeNode gameObjectTreeNode && i.Checked)
{
gameObjects.Add(gameObjectTreeNode.gameObject);
}
else
{
GetSelectedParentNode(i.Nodes, gameObjects);
}
}
}
public static TypeTree MonoBehaviourToTypeTree(MonoBehaviour m_MonoBehaviour)
{
if (!assemblyLoader.Loaded)
{
var openFolderDialog = new OpenFolderDialog();
openFolderDialog.Title = "Select Assembly Folder";
if (openFolderDialog.ShowDialog() == DialogResult.OK)
{
assemblyLoader.Load(openFolderDialog.Folder);
}
else
{
assemblyLoader.Loaded = true;
}
}
return m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
}
public static string DumpAsset(Object obj)
{
var str = obj.Dump();
if (str == null && obj is MonoBehaviour m_MonoBehaviour)
{
var type = MonoBehaviourToTypeTree(m_MonoBehaviour);
str = m_MonoBehaviour.Dump(type);
}
return str;
}
public static void OpenFolderInExplorer(string path)
{
var info = new ProcessStartInfo(path);
info.UseShellExecute = true;
Process.Start(info);
}
}
}