- [Core] Project restructure

This commit is contained in:
Razmoth
2023-10-03 01:39:59 +04:00
parent caaab48cc0
commit ebf626d10a
127 changed files with 156 additions and 228 deletions

129
AssetStudio.GUI/App.config Normal file
View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="AssetStudio.GUI.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<AssetStudio.GUI.Properties.Settings>
<setting name="displayAll" serializeAs="String">
<value>False</value>
</setting>
<setting name="enablePreview" serializeAs="String">
<value>True</value>
</setting>
<setting name="displayInfo" serializeAs="String">
<value>True</value>
</setting>
<setting name="openAfterExport" serializeAs="String">
<value>True</value>
</setting>
<setting name="assetGroupOption" serializeAs="String">
<value>0</value>
</setting>
<setting name="convertTexture" serializeAs="String">
<value>True</value>
</setting>
<setting name="convertAudio" serializeAs="String">
<value>True</value>
</setting>
<setting name="eulerFilter" serializeAs="String">
<value>True</value>
</setting>
<setting name="filterPrecision" serializeAs="String">
<value>0.25</value>
</setting>
<setting name="exportAllNodes" serializeAs="String">
<value>True</value>
</setting>
<setting name="exportSkins" serializeAs="String">
<value>True</value>
</setting>
<setting name="exportAnimations" serializeAs="String">
<value>True</value>
</setting>
<setting name="boneSize" serializeAs="String">
<value>10</value>
</setting>
<setting name="fbxVersion" serializeAs="String">
<value>3</value>
</setting>
<setting name="fbxFormat" serializeAs="String">
<value>0</value>
</setting>
<setting name="scaleFactor" serializeAs="String">
<value>1</value>
</setting>
<setting name="exportBlendShape" serializeAs="String">
<value>True</value>
</setting>
<setting name="castToBone" serializeAs="String">
<value>False</value>
</setting>
<setting name="restoreExtensionName" serializeAs="String">
<value>True</value>
</setting>
<setting name="exportAllUvsAsDiffuseMaps" serializeAs="String">
<value>False</value>
</setting>
<setting name="key" serializeAs="String">
<value>147</value>
</setting>
<setting name="enableConsole" serializeAs="String">
<value>True</value>
</setting>
<setting name="encrypted" serializeAs="String">
<value>True</value>
</setting>
<setting name="selectedGame" serializeAs="String">
<value>0</value>
</setting>
<setting name="enableResolveDependencies" serializeAs="String">
<value>True</value>
</setting>
<setting name="selectedAssetMapType" serializeAs="String">
<value>0</value>
</setting>
<setting name="collectAnimations" serializeAs="String">
<value>True</value>
</setting>
<setting name="skipContainer" serializeAs="String">
<value>False</value>
</setting>
<setting name="exportUV0UV1" serializeAs="String">
<value>False</value>
</setting>
<setting name="disableShader" serializeAs="String">
<value>False</value>
</setting>
<setting name="disableRenderer" serializeAs="String">
<value>False</value>
</setting>
<setting name="minimalAssetMap" serializeAs="String">
<value>True</value>
</setting>
<setting name="modelsOnly" serializeAs="String">
<value>False</value>
</setting>
<setting name="enableModelPreview" serializeAs="String">
<value>False</value>
</setting>
<setting name="selectedUnityCNKey" serializeAs="String">
<value>0</value>
</setting>
<setting name="selectedCABMapName" serializeAs="String">
<value />
</setting>
<setting name="disableAnimationClip" serializeAs="String">
<value>False</value>
</setting>
<setting name="enableFileLogging" serializeAs="String">
<value>True</value>
</setting>
<setting name="enableVerbose" serializeAs="String">
<value>False</value>
</setting>
</AssetStudio.GUI.Properties.Settings>
</userSettings>
</configuration>

163
AssetStudio.GUI/AssetBrowser.Designer.cs generated Normal file
View File

@@ -0,0 +1,163 @@
using System.Windows.Forms;
namespace AssetStudio.GUI
{
partial class AssetBrowser
{
/// <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()
{
assetListView = new DataGridView();
tableLayoutPanel1 = new TableLayoutPanel();
tableLayoutPanel2 = new TableLayoutPanel();
loadAssetMap = new Button();
clear = new Button();
loadSelected = new Button();
searchTextBox = new TextBox();
((System.ComponentModel.ISupportInitialize)assetListView).BeginInit();
tableLayoutPanel1.SuspendLayout();
tableLayoutPanel2.SuspendLayout();
SuspendLayout();
//
// assetListView
//
assetListView.AllowUserToAddRows = false;
assetListView.AllowUserToDeleteRows = false;
assetListView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
assetListView.Dock = DockStyle.Fill;
assetListView.Location = new System.Drawing.Point(3, 38);
assetListView.Name = "assetListView";
assetListView.ReadOnly = true;
assetListView.RowTemplate.Height = 25;
assetListView.Size = new System.Drawing.Size(518, 250);
assetListView.TabIndex = 2;
//
// tableLayoutPanel1
//
tableLayoutPanel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
tableLayoutPanel1.ColumnCount = 1;
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
tableLayoutPanel1.Controls.Add(assetListView, 0, 1);
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 0);
tableLayoutPanel1.Location = new System.Drawing.Point(12, 12);
tableLayoutPanel1.Name = "tableLayoutPanel1";
tableLayoutPanel1.RowCount = 2;
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 35F));
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.Size = new System.Drawing.Size(524, 283);
tableLayoutPanel1.TabIndex = 3;
//
// tableLayoutPanel2
//
tableLayoutPanel2.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
tableLayoutPanel2.ColumnCount = 4;
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 120F));
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 60F));
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100F));
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle());
tableLayoutPanel2.Controls.Add(loadAssetMap, 0, 0);
tableLayoutPanel2.Controls.Add(clear, 1, 0);
tableLayoutPanel2.Controls.Add(loadSelected, 2, 0);
tableLayoutPanel2.Controls.Add(searchTextBox, 3, 0);
tableLayoutPanel2.Location = new System.Drawing.Point(3, 3);
tableLayoutPanel2.Name = "tableLayoutPanel2";
tableLayoutPanel2.RowCount = 1;
tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
tableLayoutPanel2.Size = new System.Drawing.Size(518, 29);
tableLayoutPanel2.TabIndex = 3;
//
// loadAssetMap
//
loadAssetMap.Dock = DockStyle.Fill;
loadAssetMap.Location = new System.Drawing.Point(3, 3);
loadAssetMap.Name = "loadAssetMap";
loadAssetMap.Size = new System.Drawing.Size(114, 23);
loadAssetMap.TabIndex = 0;
loadAssetMap.Text = "Load AssetMap";
loadAssetMap.UseVisualStyleBackColor = true;
loadAssetMap.Click += loadAssetMap_Click;
//
// clear
//
clear.Dock = DockStyle.Fill;
clear.Location = new System.Drawing.Point(123, 3);
clear.Name = "clear";
clear.Size = new System.Drawing.Size(54, 23);
clear.TabIndex = 1;
clear.Text = "Clear";
clear.UseVisualStyleBackColor = true;
clear.Click += clear_Click;
//
// loadSelected
//
loadSelected.Dock = DockStyle.Fill;
loadSelected.Location = new System.Drawing.Point(183, 3);
loadSelected.Name = "loadSelected";
loadSelected.Size = new System.Drawing.Size(94, 23);
loadSelected.TabIndex = 2;
loadSelected.Text = "Load Selected";
loadSelected.UseVisualStyleBackColor = true;
loadSelected.Click += loadSelected_Click;
//
// searchTextBox
//
searchTextBox.Dock = DockStyle.Fill;
searchTextBox.Location = new System.Drawing.Point(283, 3);
searchTextBox.Name = "searchTextBox";
searchTextBox.PlaceholderText = "Column Name=Regex{space}....";
searchTextBox.Size = new System.Drawing.Size(232, 23);
searchTextBox.TabIndex = 3;
searchTextBox.KeyPress += searchTextBox_KeyPress;
//
// AssetBrowser
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(548, 307);
Controls.Add(tableLayoutPanel1);
Name = "AssetBrowser";
ShowIcon = false;
StartPosition = FormStartPosition.CenterScreen;
Text = "Asset Browser";
((System.ComponentModel.ISupportInitialize)assetListView).EndInit();
tableLayoutPanel1.ResumeLayout(false);
tableLayoutPanel2.ResumeLayout(false);
tableLayoutPanel2.PerformLayout();
ResumeLayout(false);
}
#endregion
private System.Windows.Forms.DataGridView assetListView;
private TableLayoutPanel tableLayoutPanel1;
private TableLayoutPanel tableLayoutPanel2;
private Button loadAssetMap;
private Button clear;
private Button loadSelected;
private TextBox searchTextBox;
}
}

View File

@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using AssetStudio;
namespace AssetStudio.GUI
{
partial class AssetBrowser : Form
{
private readonly MainForm _parent;
public AssetBrowser(MainForm form)
{
InitializeComponent();
_parent = form;
FormClosing += AssetBrowser_FormClosing;
}
private async void loadAssetMap_Click(object sender, EventArgs e)
{
loadAssetMap.Enabled = false;
var openFileDialog = new OpenFileDialog() { Multiselect = false, Filter = "MessagePack AssetMap File|*.map" };
if (openFileDialog.ShowDialog(this) == DialogResult.OK)
{
var path = openFileDialog.FileName;
Logger.Info($"Loading AssetMap...");
await Task.Run(() => ResourceMap.FromFile(path));
assetListView.DataSource = ResourceMap.GetEntries();
assetListView.Columns.GetLastColumn(DataGridViewElementStates.None, DataGridViewElementStates.None).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
loadAssetMap.Enabled = true;
}
private void clear_Click(object sender, EventArgs e)
{
Clear();
Logger.Info($"Cleared !!");
}
private async void loadSelected_Click(object sender, EventArgs e)
{
var files = assetListView.SelectedRows.Cast<DataGridViewRow>().Select(x => x.DataBoundItem as AssetEntry).Select(x => x.Source).ToHashSet();
var missingFiles = files.Where(x => !File.Exists(x));
foreach (var file in missingFiles)
{
Logger.Warning($"Unable to find file {file}, skipping...");
files.Remove(file);
}
if (files.Count != 0 && !files.Any(string.IsNullOrEmpty))
{
Logger.Info("Loading...");
_parent.Invoke(() => _parent.LoadPaths(files.ToArray()));
}
}
private void searchTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
var filters = new Dictionary<string, Regex>();
var names = typeof(AssetEntry).GetProperties().Select(x => x.Name).ToList();
var value = searchTextBox.Text;
var options = value.Split(' ');
for (int i = 0; i < options.Length; i++)
{
var option = options[i];
var arguments = option.Split('=');
if (arguments.Length != 2)
{
Logger.Error($"Invalid argument at index {i + 1}");
continue;
}
var (name, regex) = (arguments[0], arguments[1]);
if (!names.Contains(name, StringComparer.OrdinalIgnoreCase))
{
Logger.Error($"Unknonw argument {name}");
continue;
}
filters[name] = new Regex(regex, RegexOptions.IgnoreCase);
}
var assets = ResourceMap.GetEntries();
if (assets.Length != 0)
{
var regex = new Regex(value, RegexOptions.IgnoreCase);
assetListView.DataSource = Array.FindAll(assets, x => x.Matches(filters));
}
else
{
assetListView.DataSource = assets;
}
}
}
private void AssetBrowser_FormClosing(object sender, FormClosingEventArgs e)
{
Clear();
base.OnClosing(e);
}
public void Clear()
{
ResourceMap.Clear();
assetListView.DataSource = Array.Empty<AssetEntry>();
}
}
}

View File

@@ -0,0 +1,60 @@
<root>
<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>
</root>

View File

@@ -0,0 +1,116 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net6.0-windows;net7.0-windows</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
<Version>1.00.00</Version>
<AssemblyVersion>1.00.00</AssemblyVersion>
<FileVersion>1.00.00</FileVersion>
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AssetStudio.Utility\AssetStudio.Utility.csproj" />
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
</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>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Libraries\x86\AssetStudio.FBXNative.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x86\AssetStudio.FBXNative.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x64\AssetStudio.FBXNative.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x64\AssetStudio.FBXNative.dll</TargetPath>
</ContentWithTargetPath>
</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>
<ContentWithTargetPath Include="Libraries\x86\acldb.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x86\acldb.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x64\acldb.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>x64\acldb.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="OpenTK" Version="4.8.0" />
<Reference Include="OpenTK.WinForms">
<HintPath>Libraries\OpenTK.WinForms.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<None Update="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<Target Name="CopyExtraFiles" AfterTargets="AfterBuild">
<Copy SourceFiles="$(SolutionDir)AssetStudio.FBXNative\bin\Win32\$(Configuration)\AssetStudio.FBXNative.dll" DestinationFolder="$(TargetDir)x86" ContinueOnError="true" />
<Copy SourceFiles="$(SolutionDir)AssetStudio.FBXNative\bin\x64\$(Configuration)\AssetStudio.FBXNative.dll" DestinationFolder="$(TargetDir)x64" ContinueOnError="true" />
</Target>
<Target Name="PublishExtraFiles" AfterTargets="Publish">
<Copy SourceFiles="$(TargetDir)x86\AssetStudio.FBXNative.dll" DestinationFolder="$(PublishDir)x86" ContinueOnError="true" />
<Copy SourceFiles="$(TargetDir)x64\AssetStudio.FBXNative.dll" DestinationFolder="$(PublishDir)x64" ContinueOnError="true" />
</Target>
</Project>

View File

@@ -0,0 +1,40 @@
using System.Windows.Forms;
namespace AssetStudio.GUI
{
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;
Text = asset.Name;
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 AssetStudio.GUI
{
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,15 @@
using System.Windows.Forms;
namespace AssetStudio.GUI
{
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 AssetStudio.GUI
{
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,28 @@
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace AssetStudio.GUI
{
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 AssetStudio.GUI
{
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;
}
}

691
AssetStudio.GUI/ExportOptions.Designer.cs generated Normal file
View File

@@ -0,0 +1,691 @@
using System;
using System.Linq;
namespace AssetStudio.GUI
{
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()
{
components = new System.ComponentModel.Container();
OKbutton = new System.Windows.Forms.Button();
Cancel = new System.Windows.Forms.Button();
groupBox1 = new System.Windows.Forms.GroupBox();
assetGroupOptions = new System.Windows.Forms.ComboBox();
label7 = new System.Windows.Forms.Label();
openAfterExport = new System.Windows.Forms.CheckBox();
restoreExtensionName = new System.Windows.Forms.CheckBox();
label6 = new System.Windows.Forms.Label();
convertAudio = new System.Windows.Forms.CheckBox();
panel1 = new System.Windows.Forms.Panel();
totga = new System.Windows.Forms.RadioButton();
tojpg = new System.Windows.Forms.RadioButton();
topng = new System.Windows.Forms.RadioButton();
tobmp = new System.Windows.Forms.RadioButton();
converttexture = new System.Windows.Forms.CheckBox();
collectAnimations = new System.Windows.Forms.CheckBox();
groupBox2 = new System.Windows.Forms.GroupBox();
exportUV0UV1 = new System.Windows.Forms.CheckBox();
exportAllUvsAsDiffuseMaps = new System.Windows.Forms.CheckBox();
exportBlendShape = new System.Windows.Forms.CheckBox();
exportAnimations = new System.Windows.Forms.CheckBox();
scaleFactor = new System.Windows.Forms.NumericUpDown();
label5 = new System.Windows.Forms.Label();
fbxFormat = new System.Windows.Forms.ComboBox();
label4 = new System.Windows.Forms.Label();
fbxVersion = new System.Windows.Forms.ComboBox();
label3 = new System.Windows.Forms.Label();
boneSize = new System.Windows.Forms.NumericUpDown();
label2 = new System.Windows.Forms.Label();
exportSkins = new System.Windows.Forms.CheckBox();
label1 = new System.Windows.Forms.Label();
filterPrecision = new System.Windows.Forms.NumericUpDown();
castToBone = new System.Windows.Forms.CheckBox();
exportAllNodes = new System.Windows.Forms.CheckBox();
eulerFilter = new System.Windows.Forms.CheckBox();
exportUvsTooltip = new System.Windows.Forms.ToolTip(components);
encrypted = new System.Windows.Forms.CheckBox();
key = new System.Windows.Forms.NumericUpDown();
keyToolTip = new System.Windows.Forms.ToolTip(components);
groupBox4 = new System.Windows.Forms.GroupBox();
disableAnimationClip = new System.Windows.Forms.CheckBox();
minimalAssetMap = new System.Windows.Forms.CheckBox();
disableShader = new System.Windows.Forms.CheckBox();
disableRenderer = new System.Windows.Forms.CheckBox();
groupBox1.SuspendLayout();
panel1.SuspendLayout();
groupBox2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)scaleFactor).BeginInit();
((System.ComponentModel.ISupportInitialize)boneSize).BeginInit();
((System.ComponentModel.ISupportInitialize)filterPrecision).BeginInit();
((System.ComponentModel.ISupportInitialize)key).BeginInit();
groupBox4.SuspendLayout();
SuspendLayout();
//
// OKbutton
//
OKbutton.Location = new System.Drawing.Point(371, 439);
OKbutton.Margin = new System.Windows.Forms.Padding(4);
OKbutton.Name = "OKbutton";
OKbutton.Size = new System.Drawing.Size(88, 26);
OKbutton.TabIndex = 6;
OKbutton.Text = "OK";
OKbutton.UseVisualStyleBackColor = true;
OKbutton.Click += OKbutton_Click;
//
// Cancel
//
Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
Cancel.Location = new System.Drawing.Point(465, 439);
Cancel.Margin = new System.Windows.Forms.Padding(4);
Cancel.Name = "Cancel";
Cancel.Size = new System.Drawing.Size(88, 26);
Cancel.TabIndex = 7;
Cancel.Text = "Cancel";
Cancel.UseVisualStyleBackColor = true;
Cancel.Click += Cancel_Click;
//
// groupBox1
//
groupBox1.AutoSize = true;
groupBox1.Controls.Add(assetGroupOptions);
groupBox1.Controls.Add(label7);
groupBox1.Controls.Add(openAfterExport);
groupBox1.Controls.Add(restoreExtensionName);
groupBox1.Controls.Add(label6);
groupBox1.Controls.Add(convertAudio);
groupBox1.Controls.Add(panel1);
groupBox1.Controls.Add(converttexture);
groupBox1.Location = new System.Drawing.Point(14, 15);
groupBox1.Margin = new System.Windows.Forms.Padding(4);
groupBox1.Name = "groupBox1";
groupBox1.Padding = new System.Windows.Forms.Padding(4);
groupBox1.Size = new System.Drawing.Size(271, 273);
groupBox1.TabIndex = 9;
groupBox1.TabStop = false;
groupBox1.Text = "Export";
//
// assetGroupOptions
//
assetGroupOptions.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
assetGroupOptions.FormattingEnabled = true;
assetGroupOptions.Items.AddRange(new object[] { "type name", "container path", "source file name", "do not group" });
assetGroupOptions.Location = new System.Drawing.Point(7, 83);
assetGroupOptions.Margin = new System.Windows.Forms.Padding(4);
assetGroupOptions.Name = "assetGroupOptions";
assetGroupOptions.Size = new System.Drawing.Size(173, 23);
assetGroupOptions.TabIndex = 12;
//
// label7
//
label7.AutoSize = true;
label7.Location = new System.Drawing.Point(7, 64);
label7.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label7.Name = "label7";
label7.Size = new System.Drawing.Size(140, 15);
label7.TabIndex = 11;
label7.Text = "Group exported assets by";
//
// openAfterExport
//
openAfterExport.AutoSize = true;
openAfterExport.Checked = true;
openAfterExport.CheckState = System.Windows.Forms.CheckState.Checked;
openAfterExport.Location = new System.Drawing.Point(8, 230);
openAfterExport.Margin = new System.Windows.Forms.Padding(4);
openAfterExport.Name = "openAfterExport";
openAfterExport.Size = new System.Drawing.Size(153, 19);
openAfterExport.TabIndex = 10;
openAfterExport.Text = "Open folder after export";
openAfterExport.UseVisualStyleBackColor = true;
//
// restoreExtensionName
//
restoreExtensionName.AutoSize = true;
restoreExtensionName.Checked = true;
restoreExtensionName.CheckState = System.Windows.Forms.CheckState.Checked;
restoreExtensionName.Location = new System.Drawing.Point(7, 109);
restoreExtensionName.Margin = new System.Windows.Forms.Padding(4);
restoreExtensionName.Name = "restoreExtensionName";
restoreExtensionName.Size = new System.Drawing.Size(204, 19);
restoreExtensionName.TabIndex = 9;
restoreExtensionName.Text = "Restore TextAsset extension name";
restoreExtensionName.UseVisualStyleBackColor = true;
//
// label6
//
label6.AutoSize = true;
label6.Location = new System.Drawing.Point(7, 21);
label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label6.Name = "label6";
label6.Size = new System.Drawing.Size(80, 15);
label6.TabIndex = 7;
label6.Text = "Group exported assets by";
//
// convertAudio
//
convertAudio.AutoSize = true;
convertAudio.Checked = true;
convertAudio.CheckState = System.Windows.Forms.CheckState.Checked;
convertAudio.Location = new System.Drawing.Point(7, 204);
convertAudio.Margin = new System.Windows.Forms.Padding(4);
convertAudio.Name = "convertAudio";
convertAudio.Size = new System.Drawing.Size(200, 19);
convertAudio.TabIndex = 6;
convertAudio.Text = "Convert AudioClip to WAV(PCM)";
convertAudio.UseVisualStyleBackColor = true;
//
// panel1
//
panel1.Controls.Add(totga);
panel1.Controls.Add(tojpg);
panel1.Controls.Add(topng);
panel1.Controls.Add(tobmp);
panel1.Location = new System.Drawing.Point(23, 164);
panel1.Margin = new System.Windows.Forms.Padding(4);
panel1.Name = "panel1";
panel1.Size = new System.Drawing.Size(236, 38);
panel1.TabIndex = 5;
//
// totga
//
totga.AutoSize = true;
totga.Location = new System.Drawing.Point(175, 8);
totga.Margin = new System.Windows.Forms.Padding(4);
totga.Name = "totga";
totga.Size = new System.Drawing.Size(43, 19);
totga.TabIndex = 2;
totga.Text = "Tga";
totga.UseVisualStyleBackColor = true;
//
// tojpg
//
tojpg.AutoSize = true;
tojpg.Location = new System.Drawing.Point(113, 8);
tojpg.Margin = new System.Windows.Forms.Padding(4);
tojpg.Name = "tojpg";
tojpg.Size = new System.Drawing.Size(49, 19);
tojpg.TabIndex = 4;
tojpg.Text = "Jpeg";
tojpg.UseVisualStyleBackColor = true;
//
// topng
//
topng.AutoSize = true;
topng.Checked = true;
topng.Location = new System.Drawing.Point(58, 8);
topng.Margin = new System.Windows.Forms.Padding(4);
topng.Name = "topng";
topng.Size = new System.Drawing.Size(46, 19);
topng.TabIndex = 3;
topng.TabStop = true;
topng.Text = "Png";
topng.UseVisualStyleBackColor = true;
//
// tobmp
//
tobmp.AutoSize = true;
tobmp.Location = new System.Drawing.Point(4, 8);
tobmp.Margin = new System.Windows.Forms.Padding(4);
tobmp.Name = "tobmp";
tobmp.Size = new System.Drawing.Size(50, 19);
tobmp.TabIndex = 2;
tobmp.Text = "Bmp";
tobmp.UseVisualStyleBackColor = true;
//
// converttexture
//
converttexture.AutoSize = true;
converttexture.Checked = true;
converttexture.CheckState = System.Windows.Forms.CheckState.Checked;
converttexture.Location = new System.Drawing.Point(7, 136);
converttexture.Margin = new System.Windows.Forms.Padding(4);
converttexture.Name = "converttexture";
converttexture.Size = new System.Drawing.Size(123, 19);
converttexture.TabIndex = 1;
converttexture.Text = "Convert Texture2D";
converttexture.UseVisualStyleBackColor = true;
//
// collectAnimations
//
collectAnimations.AutoSize = true;
collectAnimations.Checked = true;
collectAnimations.CheckState = System.Windows.Forms.CheckState.Checked;
collectAnimations.Location = new System.Drawing.Point(8, 113);
collectAnimations.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
collectAnimations.Name = "collectAnimations";
collectAnimations.Size = new System.Drawing.Size(125, 19);
collectAnimations.TabIndex = 24;
collectAnimations.Text = "Collect animations";
collectAnimations.UseVisualStyleBackColor = true;
//
// groupBox2
//
groupBox2.AutoSize = true;
groupBox2.Controls.Add(exportUV0UV1);
groupBox2.Controls.Add(collectAnimations);
groupBox2.Controls.Add(exportAllUvsAsDiffuseMaps);
groupBox2.Controls.Add(exportBlendShape);
groupBox2.Controls.Add(exportAnimations);
groupBox2.Controls.Add(scaleFactor);
groupBox2.Controls.Add(label5);
groupBox2.Controls.Add(fbxFormat);
groupBox2.Controls.Add(label4);
groupBox2.Controls.Add(fbxVersion);
groupBox2.Controls.Add(label3);
groupBox2.Controls.Add(boneSize);
groupBox2.Controls.Add(label2);
groupBox2.Controls.Add(exportSkins);
groupBox2.Controls.Add(label1);
groupBox2.Controls.Add(filterPrecision);
groupBox2.Controls.Add(castToBone);
groupBox2.Controls.Add(exportAllNodes);
groupBox2.Controls.Add(eulerFilter);
groupBox2.Location = new System.Drawing.Point(292, 15);
groupBox2.Margin = new System.Windows.Forms.Padding(4);
groupBox2.Name = "groupBox2";
groupBox2.Padding = new System.Windows.Forms.Padding(4);
groupBox2.Size = new System.Drawing.Size(261, 418);
groupBox2.TabIndex = 11;
groupBox2.TabStop = false;
groupBox2.Text = "Fbx";
//
// exportUV0UV1
//
exportUV0UV1.AccessibleDescription = "";
exportUV0UV1.AutoSize = true;
exportUV0UV1.Location = new System.Drawing.Point(8, 243);
exportUV0UV1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
exportUV0UV1.Name = "exportUV0UV1";
exportUV0UV1.Size = new System.Drawing.Size(124, 19);
exportUV0UV1.TabIndex = 25;
exportUV0UV1.Text = "Export UV 0/1 only";
exportUvsTooltip.SetToolTip(exportUV0UV1, "Unchecked: Export UV0/UV1 only. Check this if your facing issues with vertex color/tangent.");
exportUV0UV1.UseVisualStyleBackColor = true;
//
// exportAllUvsAsDiffuseMaps
//
exportAllUvsAsDiffuseMaps.AccessibleDescription = "";
exportAllUvsAsDiffuseMaps.AutoSize = true;
exportAllUvsAsDiffuseMaps.Location = new System.Drawing.Point(8, 217);
exportAllUvsAsDiffuseMaps.Margin = new System.Windows.Forms.Padding(4);
exportAllUvsAsDiffuseMaps.Name = "exportAllUvsAsDiffuseMaps";
exportAllUvsAsDiffuseMaps.Size = new System.Drawing.Size(183, 19);
exportAllUvsAsDiffuseMaps.TabIndex = 23;
exportAllUvsAsDiffuseMaps.Text = "Export all UVs as diffuse maps";
exportUvsTooltip.SetToolTip(exportAllUvsAsDiffuseMaps, "Unchecked: UV1 exported as normal map. Check this if your export is missing a UV map.");
exportAllUvsAsDiffuseMaps.UseVisualStyleBackColor = true;
//
// exportBlendShape
//
exportBlendShape.AutoSize = true;
exportBlendShape.Checked = true;
exportBlendShape.CheckState = System.Windows.Forms.CheckState.Checked;
exportBlendShape.Location = new System.Drawing.Point(8, 163);
exportBlendShape.Margin = new System.Windows.Forms.Padding(4);
exportBlendShape.Name = "exportBlendShape";
exportBlendShape.Size = new System.Drawing.Size(124, 19);
exportBlendShape.TabIndex = 22;
exportBlendShape.Text = "Export blendshape";
exportBlendShape.UseVisualStyleBackColor = true;
//
// exportAnimations
//
exportAnimations.AutoSize = true;
exportAnimations.Checked = true;
exportAnimations.CheckState = System.Windows.Forms.CheckState.Checked;
exportAnimations.Location = new System.Drawing.Point(8, 136);
exportAnimations.Margin = new System.Windows.Forms.Padding(4);
exportAnimations.Name = "exportAnimations";
exportAnimations.Size = new System.Drawing.Size(122, 19);
exportAnimations.TabIndex = 21;
exportAnimations.Text = "Export animations";
exportAnimations.UseVisualStyleBackColor = true;
//
// scaleFactor
//
scaleFactor.DecimalPlaces = 2;
scaleFactor.Increment = new decimal(new int[] { 1, 0, 0, 131072 });
scaleFactor.Location = new System.Drawing.Point(98, 305);
scaleFactor.Margin = new System.Windows.Forms.Padding(4);
scaleFactor.Name = "scaleFactor";
scaleFactor.Size = new System.Drawing.Size(70, 23);
scaleFactor.TabIndex = 20;
scaleFactor.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
scaleFactor.Value = new decimal(new int[] { 1, 0, 0, 0 });
//
// label5
//
label5.AutoSize = true;
label5.Location = new System.Drawing.Point(8, 307);
label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label5.Name = "label5";
label5.Size = new System.Drawing.Size(67, 15);
label5.TabIndex = 19;
label5.Text = "ScaleFactor";
//
// fbxFormat
//
fbxFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
fbxFormat.FormattingEnabled = true;
fbxFormat.Items.AddRange(new object[] { "Binary", "Ascii" });
fbxFormat.Location = new System.Drawing.Point(91, 339);
fbxFormat.Margin = new System.Windows.Forms.Padding(4);
fbxFormat.Name = "fbxFormat";
fbxFormat.Size = new System.Drawing.Size(70, 23);
fbxFormat.TabIndex = 18;
//
// label4
//
label4.AutoSize = true;
label4.Location = new System.Drawing.Point(8, 343);
label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label4.Name = "label4";
label4.Size = new System.Drawing.Size(65, 15);
label4.TabIndex = 17;
label4.Text = "FBXFormat";
//
// fbxVersion
//
fbxVersion.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
fbxVersion.FormattingEnabled = true;
fbxVersion.Items.AddRange(new object[] { "6.1", "7.1", "7.2", "7.3", "7.4", "7.5" });
fbxVersion.Location = new System.Drawing.Point(91, 371);
fbxVersion.Margin = new System.Windows.Forms.Padding(4);
fbxVersion.Name = "fbxVersion";
fbxVersion.Size = new System.Drawing.Size(54, 23);
fbxVersion.TabIndex = 16;
//
// label3
//
label3.AutoSize = true;
label3.Location = new System.Drawing.Point(8, 375);
label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label3.Name = "label3";
label3.Size = new System.Drawing.Size(65, 15);
label3.TabIndex = 15;
label3.Text = "FBXVersion";
//
// boneSize
//
boneSize.Location = new System.Drawing.Point(77, 270);
boneSize.Margin = new System.Windows.Forms.Padding(4);
boneSize.Name = "boneSize";
boneSize.Size = new System.Drawing.Size(54, 23);
boneSize.TabIndex = 11;
boneSize.Value = new decimal(new int[] { 10, 0, 0, 0 });
//
// label2
//
label2.AutoSize = true;
label2.Location = new System.Drawing.Point(8, 272);
label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label2.Name = "label2";
label2.Size = new System.Drawing.Size(54, 15);
label2.TabIndex = 10;
label2.Text = "BoneSize";
//
// exportSkins
//
exportSkins.AutoSize = true;
exportSkins.Checked = true;
exportSkins.CheckState = System.Windows.Forms.CheckState.Checked;
exportSkins.Location = new System.Drawing.Point(8, 87);
exportSkins.Margin = new System.Windows.Forms.Padding(4);
exportSkins.Name = "exportSkins";
exportSkins.Size = new System.Drawing.Size(89, 19);
exportSkins.TabIndex = 8;
exportSkins.Text = "Export skins";
exportSkins.UseVisualStyleBackColor = true;
//
// label1
//
label1.AutoSize = true;
label1.Location = new System.Drawing.Point(31, 41);
label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label1.Name = "label1";
label1.Size = new System.Drawing.Size(81, 15);
label1.TabIndex = 7;
label1.Text = "FilterPrecision";
//
// filterPrecision
//
filterPrecision.DecimalPlaces = 2;
filterPrecision.Increment = new decimal(new int[] { 1, 0, 0, 131072 });
filterPrecision.Location = new System.Drawing.Point(149, 38);
filterPrecision.Margin = new System.Windows.Forms.Padding(4);
filterPrecision.Name = "filterPrecision";
filterPrecision.Size = new System.Drawing.Size(59, 23);
filterPrecision.TabIndex = 6;
filterPrecision.Value = new decimal(new int[] { 25, 0, 0, 131072 });
//
// castToBone
//
castToBone.AutoSize = true;
castToBone.Location = new System.Drawing.Point(8, 190);
castToBone.Margin = new System.Windows.Forms.Padding(4);
castToBone.Name = "castToBone";
castToBone.Size = new System.Drawing.Size(143, 19);
castToBone.TabIndex = 5;
castToBone.Text = "All nodes cast to bone";
castToBone.UseVisualStyleBackColor = true;
//
// exportAllNodes
//
exportAllNodes.AutoSize = true;
exportAllNodes.Checked = true;
exportAllNodes.CheckState = System.Windows.Forms.CheckState.Checked;
exportAllNodes.Location = new System.Drawing.Point(8, 60);
exportAllNodes.Margin = new System.Windows.Forms.Padding(4);
exportAllNodes.Name = "exportAllNodes";
exportAllNodes.Size = new System.Drawing.Size(110, 19);
exportAllNodes.TabIndex = 4;
exportAllNodes.Text = "Export all nodes";
exportAllNodes.UseVisualStyleBackColor = true;
//
// eulerFilter
//
eulerFilter.AutoSize = true;
eulerFilter.Checked = true;
eulerFilter.CheckState = System.Windows.Forms.CheckState.Checked;
eulerFilter.Location = new System.Drawing.Point(8, 17);
eulerFilter.Margin = new System.Windows.Forms.Padding(4);
eulerFilter.Name = "eulerFilter";
eulerFilter.Size = new System.Drawing.Size(78, 19);
eulerFilter.TabIndex = 3;
eulerFilter.Text = "EulerFilter";
eulerFilter.UseVisualStyleBackColor = true;
//
// encrypted
//
encrypted.AutoSize = true;
encrypted.Checked = true;
encrypted.CheckState = System.Windows.Forms.CheckState.Checked;
encrypted.Location = new System.Drawing.Point(8, 22);
encrypted.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
encrypted.Name = "encrypted";
encrypted.Size = new System.Drawing.Size(166, 19);
encrypted.TabIndex = 12;
encrypted.Text = "Encrypted MiHoYoBinData\r\n";
encrypted.UseVisualStyleBackColor = true;
//
// key
//
key.Hexadecimal = true;
key.Location = new System.Drawing.Point(199, 18);
key.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
key.Maximum = new decimal(new int[] { 255, 0, 0, 0 });
key.Name = "key";
key.Size = new System.Drawing.Size(55, 23);
key.TabIndex = 8;
keyToolTip.SetToolTip(key, "Key in hex");
//
// groupBox4
//
groupBox4.AutoSize = true;
groupBox4.Controls.Add(disableAnimationClip);
groupBox4.Controls.Add(minimalAssetMap);
groupBox4.Controls.Add(disableShader);
groupBox4.Controls.Add(disableRenderer);
groupBox4.Controls.Add(key);
groupBox4.Controls.Add(encrypted);
groupBox4.Location = new System.Drawing.Point(13, 287);
groupBox4.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
groupBox4.Name = "groupBox4";
groupBox4.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3);
groupBox4.Size = new System.Drawing.Size(272, 146);
groupBox4.TabIndex = 13;
groupBox4.TabStop = false;
groupBox4.Text = "Options";
//
// disableAnimationClip
//
disableAnimationClip.AutoSize = true;
disableAnimationClip.Location = new System.Drawing.Point(119, 72);
disableAnimationClip.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
disableAnimationClip.Name = "disableAnimationClip";
disableAnimationClip.Size = new System.Drawing.Size(144, 19);
disableAnimationClip.TabIndex = 18;
disableAnimationClip.Text = "Disable AnimationClip";
disableAnimationClip.UseVisualStyleBackColor = true;
//
// minimalAssetMap
//
minimalAssetMap.AutoSize = true;
minimalAssetMap.Location = new System.Drawing.Point(8, 97);
minimalAssetMap.Name = "minimalAssetMap";
minimalAssetMap.Size = new System.Drawing.Size(125, 19);
minimalAssetMap.TabIndex = 17;
minimalAssetMap.Text = "Minimal AssetMap";
minimalAssetMap.UseVisualStyleBackColor = true;
//
// disableShader
//
disableShader.AutoSize = true;
disableShader.Location = new System.Drawing.Point(8, 72);
disableShader.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
disableShader.Name = "disableShader";
disableShader.Size = new System.Drawing.Size(103, 19);
disableShader.TabIndex = 16;
disableShader.Text = "Disable Shader";
disableShader.UseVisualStyleBackColor = true;
//
// disableRenderer
//
disableRenderer.AutoSize = true;
disableRenderer.Location = new System.Drawing.Point(8, 47);
disableRenderer.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
disableRenderer.Name = "disableRenderer";
disableRenderer.Size = new System.Drawing.Size(114, 19);
disableRenderer.TabIndex = 15;
disableRenderer.Text = "Disable Renderer";
disableRenderer.UseVisualStyleBackColor = true;
//
// ExportOptions
//
AcceptButton = OKbutton;
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
CancelButton = Cancel;
ClientSize = new System.Drawing.Size(567, 480);
Controls.Add(groupBox4);
Controls.Add(groupBox2);
Controls.Add(groupBox1);
Controls.Add(Cancel);
Controls.Add(OKbutton);
Margin = new System.Windows.Forms.Padding(4);
MaximizeBox = false;
MinimizeBox = false;
Name = "ExportOptions";
ShowIcon = false;
ShowInTaskbar = false;
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
Text = "Export options";
TopMost = true;
groupBox1.ResumeLayout(false);
groupBox1.PerformLayout();
panel1.ResumeLayout(false);
panel1.PerformLayout();
groupBox2.ResumeLayout(false);
groupBox2.PerformLayout();
((System.ComponentModel.ISupportInitialize)scaleFactor).EndInit();
((System.ComponentModel.ISupportInitialize)boneSize).EndInit();
((System.ComponentModel.ISupportInitialize)filterPrecision).EndInit();
((System.ComponentModel.ISupportInitialize)key).EndInit();
groupBox4.ResumeLayout(false);
groupBox4.PerformLayout();
ResumeLayout(false);
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 collectAnimations;
private System.Windows.Forms.CheckBox encrypted;
private System.Windows.Forms.NumericUpDown key;
private System.Windows.Forms.ToolTip keyToolTip;
private System.Windows.Forms.CheckBox exportUV0UV1;
private System.Windows.Forms.GroupBox groupBox4;
private System.Windows.Forms.CheckBox disableShader;
private System.Windows.Forms.CheckBox disableRenderer;
private System.Windows.Forms.CheckBox minimalAssetMap;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.CheckBox disableAnimationClip;
}
}

View File

@@ -0,0 +1,103 @@
using AssetStudio;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace AssetStudio.GUI
{
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;
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;
exportUV0UV1.Checked = Properties.Settings.Default.exportUV0UV1;
boneSize.Value = Properties.Settings.Default.boneSize;
scaleFactor.Value = Properties.Settings.Default.scaleFactor;
fbxVersion.SelectedIndex = Properties.Settings.Default.fbxVersion;
fbxFormat.SelectedIndex = Properties.Settings.Default.fbxFormat;
collectAnimations.Checked = Properties.Settings.Default.collectAnimations;
encrypted.Checked = Properties.Settings.Default.encrypted;
key.Value = Properties.Settings.Default.key;
disableRenderer.Checked = Properties.Settings.Default.disableRenderer;
disableShader.Checked = Properties.Settings.Default.disableShader;
disableAnimationClip.Checked = Properties.Settings.Default.disableAnimationClip;
minimalAssetMap.Checked = Properties.Settings.Default.minimalAssetMap;
}
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.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.exportUV0UV1 = exportUV0UV1.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.collectAnimations = collectAnimations.Checked;
Properties.Settings.Default.encrypted = encrypted.Checked;
Properties.Settings.Default.key = (byte)key.Value;
Properties.Settings.Default.disableRenderer = disableRenderer.Checked;
Properties.Settings.Default.disableShader = disableShader.Checked;
Properties.Settings.Default.disableAnimationClip = disableAnimationClip.Checked;
Properties.Settings.Default.minimalAssetMap = minimalAssetMap.Checked;
Properties.Settings.Default.Save();
MiHoYoBinData.Key = (byte)key.Value;
MiHoYoBinData.Encrypted = encrypted.Checked;
AssetsHelper.Minimal = Properties.Settings.Default.minimalAssetMap;
Renderer.Parsable = !Properties.Settings.Default.disableRenderer;
Shader.Parsable = !Properties.Settings.Default.disableShader;
AnimationClip.Parsable = !Properties.Settings.Default.disableAnimationClip;
DialogResult = DialogResult.OK;
Close();
}
private void Cancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
}
}

View File

@@ -0,0 +1,129 @@
<?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>
<metadata name="keyToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>162, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>57</value>
</metadata>
</root>

468
AssetStudio.GUI/Exporter.cs Normal file
View File

@@ -0,0 +1,468 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace AssetStudio.GUI
{
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();
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 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:
var extension = ".bin";
if (Properties.Settings.Default.restoreExtensionName)
{
if (!string.IsNullOrEmpty(item.Container))
{
extension = Path.GetExtension(item.Container);
}
}
if (!TryExportFile(exportPath, item, extension, out exportFullPath))
return false;
var bytes = m_MiHoYoBinData.Dump() as byte[];
if (!bytes.IsNullOrEmpty())
{
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 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();
if (string.IsNullOrEmpty(str))
return false;
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, Properties.Settings.Default.collectAnimations, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(m_Animator, Properties.Settings.Default.convertType, Studio.Game, Properties.Settings.Default.collectAnimations);
ExportFbx(convert, exportFullPath);
return true;
}
public static bool ExportGameObject(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_GameObject = (GameObject)item.Asset;
ExportGameObject(m_GameObject, exportFullPath, animationList);
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, Properties.Settings.Default.collectAnimations, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(gameObject, Properties.Settings.Default.convertType, Studio.Game, Properties.Settings.Default.collectAnimations);
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, Properties.Settings.Default.collectAnimations, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType, Studio.Game, Properties.Settings.Default.collectAnimations);
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 exportUV0UV1 = Properties.Settings.Default.exportUV0UV1;
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, exportUV0UV1, 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.GameObject:
return ExportGameObject(item, exportPath);
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.Animator:
return ExportAnimator(item, exportPath);
case ClassIDType.AnimationClip:
return ExportAnimationClip(item, exportPath);
case ClassIDType.MiHoYoBinData:
return ExportMiHoYoBinData(item, exportPath);
case ClassIDType.Material:
return ExportJSONFile(item, exportPath);
default:
return ExportRawFile(item, exportPath);
}
}
public static bool ExportJSONFile(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
return false;
var settings = new JsonSerializerSettings();
settings.Converters.Add(new StringEnumConverter());
var str = JsonConvert.SerializeObject(item.Asset, Formatting.Indented, settings);
File.WriteAllText(exportFullPath, str);
return true;
}
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,35 @@
using System;
using System.Windows.Forms;
namespace AssetStudio.GUI
{
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, bool silent = false)
{
if (silent)
return;
switch (loggerEvent)
{
case LoggerEvent.Error:
if (ShowErrorMessage)
{
MessageBox.Show(message);
}
break;
default:
action(message);
break;
}
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1538
AssetStudio.GUI/MainForm.Designer.cs generated Normal file

File diff suppressed because it is too large Load Diff

2871
AssetStudio.GUI/MainForm.cs Normal file

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>
<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="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>432, 17</value>
</metadata>
<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,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AssetStudio.GUI
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}

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 AssetStudio.GUI.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("AssetStudio.GUI.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,506 @@
//------------------------------------------------------------------------------
// <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 AssetStudio.GUI.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.8.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("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 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 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 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;
}
}
[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 enableConsole {
get {
return ((bool)(this["enableConsole"]));
}
set {
this["enableConsole"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool encrypted {
get {
return ((bool)(this["encrypted"]));
}
set {
this["encrypted"] = 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("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("0")]
public int selectedAssetMapType {
get {
return ((int)(this["selectedAssetMapType"]));
}
set {
this["selectedAssetMapType"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool collectAnimations {
get {
return ((bool)(this["collectAnimations"]));
}
set {
this["collectAnimations"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool skipContainer {
get {
return ((bool)(this["skipContainer"]));
}
set {
this["skipContainer"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool exportUV0UV1 {
get {
return ((bool)(this["exportUV0UV1"]));
}
set {
this["exportUV0UV1"] = 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("False")]
public bool disableRenderer {
get {
return ((bool)(this["disableRenderer"]));
}
set {
this["disableRenderer"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool minimalAssetMap {
get {
return ((bool)(this["minimalAssetMap"]));
}
set {
this["minimalAssetMap"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool modelsOnly {
get {
return ((bool)(this["modelsOnly"]));
}
set {
this["modelsOnly"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool enableModelPreview {
get {
return ((bool)(this["enableModelPreview"]));
}
set {
this["enableModelPreview"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int selectedUnityCNKey {
get {
return ((int)(this["selectedUnityCNKey"]));
}
set {
this["selectedUnityCNKey"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string selectedCABMapName {
get {
return ((string)(this["selectedCABMapName"]));
}
set {
this["selectedCABMapName"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool disableAnimationClip {
get {
return ((bool)(this["disableAnimationClip"]));
}
set {
this["disableAnimationClip"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool enableFileLogging {
get {
return ((bool)(this["enableFileLogging"]));
}
set {
this["enableFileLogging"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool enableVerbose {
get {
return ((bool)(this["enableVerbose"]));
}
set {
this["enableVerbose"] = value;
}
}
}
}

View File

@@ -0,0 +1,126 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="AssetStudio.GUI.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="enableConsole" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="encrypted" 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="enableResolveDependencies" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="selectedAssetMapType" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="collectAnimations" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="skipContainer" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="exportUV0UV1" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="disableShader" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="disableRenderer" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="minimalAssetMap" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="modelsOnly" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="enableModelPreview" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="selectedUnityCNKey" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="selectedCABMapName" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="disableAnimationClip" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="enableFileLogging" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="enableVerbose" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</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

949
AssetStudio.GUI/Studio.cs Normal file
View File

@@ -0,0 +1,949 @@
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;
using static AssetStudio.GUI.Exporter;
namespace AssetStudio.GUI
{
internal enum ExportType
{
Convert,
Raw,
Dump,
JSON
}
internal enum ExportFilter
{
All,
Selected,
Filtered
}
internal static class Studio
{
public static Game Game;
public static bool SkipContainer = false;
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 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);
reader = reader.PreProcessing(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.BlkFile)
extractedCount += ExtractBlkFile(reader, savePath);
else if (reader.FileType == FileType.BlockFile)
extractedCount += ExtractBlockFile(reader, savePath);
else
reader.Dispose();
return extractedCount;
}
private static int ExtractBundleFile(FileReader reader, string savePath)
{
StatusStripUpdate($"Decompressing {reader.FileName} ...");
try
{
var bundleFile = new BundleFile(reader, Game);
reader.Dispose();
if (bundleFile.fileList.Length > 0)
{
var extractPath = Path.Combine(savePath, reader.FileName + "_unpacked");
return ExtractStreamFile(extractPath, bundleFile.fileList);
}
}
catch (InvalidCastException)
{
Logger.Error($"Game type mismatch, Expected {nameof(Mr0k)} but got {Game.Name} ({Game.GetType().Name}) !!");
}
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 ExtractBlkFile(FileReader reader, string savePath)
{
int total = 0;
StatusStripUpdate($"Decompressing {reader.FileName} ...");
try
{
using var stream = BlkUtils.Decrypt(reader, (Blk)Game);
do
{
stream.Offset = stream.AbsolutePosition;
var dummyPath = Path.Combine(reader.FullPath, stream.AbsolutePosition.ToString("X8"));
var subReader = new FileReader(dummyPath, stream, true);
var subSavePath = Path.Combine(savePath, reader.FileName + "_unpacked");
switch (subReader.FileType)
{
case FileType.BundleFile:
total += ExtractBundleFile(subReader, subSavePath);
break;
case FileType.Mhy0File:
total += ExtractMhy0File(subReader, subSavePath);
break;
}
} while (stream.Remaining > 0);
}
catch (InvalidCastException)
{
Logger.Error($"Game type mismatch, Expected {nameof(Blk)} but got {Game.Name} ({Game.GetType().Name}) !!");
}
return total;
}
private static int ExtractBlockFile(FileReader reader, string savePath)
{
int total = 0;
StatusStripUpdate($"Decompressing {reader.FileName} ...");
using var stream = new OffsetStream(reader.BaseStream, 0);
do
{
stream.Offset = stream.AbsolutePosition;
var subSavePath = Path.Combine(savePath, reader.FileName + "_unpacked");
var dummyPath = Path.Combine(reader.FullPath, stream.AbsolutePosition.ToString("X8"));
var subReader = new FileReader(dummyPath, stream, true);
total += ExtractBundleFile(subReader, subSavePath);
} while (stream.Remaining > 0);
return total;
}
private static int ExtractMhy0File(FileReader reader, string savePath)
{
StatusStripUpdate($"Decompressing {reader.FileName} ...");
try
{
var mhy0File = new Mhy0File(reader, reader.FullPath, (Mhy0)Game);
reader.Dispose();
if (mhy0File.fileList.Length > 0)
{
var extractPath = Path.Combine(savePath, reader.FileName + "_unpacked");
return ExtractStreamFile(extractPath, mhy0File.fileList);
}
}
catch (InvalidCastException)
{
Logger.Error($"Game type mismatch, Expected {nameof(Mhy0)} but got {Game.Name} ({Game.GetType().Name}) !!");
}
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 void UpdateContainers()
{
if (exportableAssets.Count > 0)
{
Logger.Info("Updating Containers...");
foreach (var asset in exportableAssets)
{
if (int.TryParse(asset.Container, out var value))
{
var last = unchecked((uint)value);
var name = Path.GetFileNameWithoutExtension(asset.SourceFile.originalPath);
if (uint.TryParse(name, out var id))
{
var path = ResourceIndex.GetContainer(id, last);
if (!string.IsNullOrEmpty(path))
{
asset.Container = path;
if (asset.Type == ClassIDType.MiHoYoBinData)
{
asset.Text = Path.GetFileNameWithoutExtension(path);
}
}
}
}
}
Logger.Info("Updated !!");
}
}
public static (string, List<TreeNode>) BuildAssetData()
{
StatusStripUpdate("Building asset list...");
int i = 0;
string productName = null;
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
var mihoyoBinDataNames = new List<(PPtr<Object>, string)>();
var containers = new List<(PPtr<Object>, string)>();
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
foreach (var asset in assetsFile.Objects)
{
if (assetsManager.tokenSource.IsCancellationRequested)
{
Logger.Info("Building asset list has been cancelled !!");
return (string.Empty, Array.Empty<TreeNode>().ToList());
}
var assetItem = new AssetItem(asset);
objectAssetItemDic.Add(asset, assetItem);
assetItem.UniqueID = "#" + i;
var exportable = false;
switch (asset)
{
case Texture2D m_Texture2D:
if (!string.IsNullOrEmpty(m_Texture2D.m_StreamData?.path))
assetItem.FullSize = asset.byteSize + m_Texture2D.m_StreamData.size;
exportable = true;
break;
case AudioClip m_AudioClip:
if (!string.IsNullOrEmpty(m_AudioClip.m_Source))
assetItem.FullSize = asset.byteSize + m_AudioClip.m_Size;
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;
exportable = true;
break;
case PlayerSettings m_PlayerSettings:
productName = m_PlayerSettings.productName;
break;
case AssetBundle m_AssetBundle:
if (!SkipContainer)
{
foreach (var m_Container in m_AssetBundle.m_Container)
{
var preloadIndex = m_Container.Value.preloadIndex;
var preloadSize = m_Container.Value.preloadSize;
var preloadEnd = preloadIndex + preloadSize;
for (int k = preloadIndex; k < preloadEnd; k++)
{
containers.Add((m_AssetBundle.m_PreloadTable[k], m_Container.Key));
}
}
}
break;
case IndexObject m_IndexObject:
foreach(var index in m_IndexObject.AssetMap)
{
mihoyoBinDataNames.Add((index.Value.Object, index.Key));
}
break;
case ResourceManager m_ResourceManager:
foreach (var m_Container in m_ResourceManager.m_Container)
{
containers.Add((m_Container.Value, m_Container.Key));
}
break;
case Mesh _:
case TextAsset _:
case AnimationClip _ when AnimationClip.Parsable:
case Font _:
case MovieTexture _:
case Sprite _:
case Material _:
case MiHoYoBinData _:
case Shader _ when Shader.Parsable:
case Animator _:
case MonoBehaviour _:
exportable = true;
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 name) in mihoyoBinDataNames)
{
if (assetsManager.tokenSource.IsCancellationRequested)
{
Logger.Info("Processing asset namnes has been cancelled !!");
return (string.Empty, Array.Empty<TreeNode>().ToList());
}
if (pptr.TryGet<MiHoYoBinData>(out var obj))
{
var assetItem = objectAssetItemDic[obj];
if (int.TryParse(name, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var hash))
{
assetItem.Text = name;
assetItem.Container = hash.ToString();
}
else assetItem.Text = $"BinFile #{assetItem.m_PathID}";
}
}
if (!SkipContainer)
{
foreach ((var pptr, var container) in containers)
{
if (assetsManager.tokenSource.IsCancellationRequested)
{
Logger.Info("Processing containers been cancelled !!");
return (string.Empty, Array.Empty<TreeNode>().ToList());
}
if (pptr.TryGet(out var obj))
{
objectAssetItemDic[obj].Container = container;
}
}
containers.Clear();
if (Game.Type.IsGISubGroup())
{
UpdateContainers();
}
}
foreach (var tmp in exportableAssets)
{
if (assetsManager.tokenSource.IsCancellationRequested)
{
Logger.Info("Processing subitems been cancelled !!");
return (string.Empty, Array.Empty<TreeNode>().ToList());
}
tmp.SetSubItems();
}
visibleAssets = exportableAssets;
StatusStripUpdate("Building tree structure...");
var treeNodeCollection = new List<TreeNode>();
var treeNodeDictionary = new Dictionary<GameObject, GameObjectTreeNode>();
int j = 0;
Progress.Reset();
var files = assetsManager.assetsFileList.GroupBy(x => x.originalPath ?? string.Empty).OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.ToList());
foreach (var (file, assetsFiles) in files)
{
var fileNode = !string.IsNullOrEmpty(file) ? new TreeNode(Path.GetFileName(file)) : null; //RootNode
foreach (var assetsFile in assetsFiles)
{
var assetsFileNode = new TreeNode(assetsFile.fileName);
foreach (var obj in assetsFile.Objects)
{
if (assetsManager.tokenSource.IsCancellationRequested)
{
Logger.Info("Building tree structure been cancelled !!");
return (string.Empty, Array.Empty<TreeNode>().ToList());
}
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 = assetsFileNode;
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 (assetsFileNode.Nodes.Count > 0)
{
if (fileNode == null)
{
treeNodeCollection.Add(assetsFileNode);
}
else
{
fileNode.Nodes.Add(assetsFileNode);
}
}
}
if (fileNode?.Nodes.Count > 0)
{
treeNodeCollection.Add(fileNode);
}
Progress.Report(++j, files.Count);
}
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 (assetsManager.tokenSource.IsCancellationRequested)
{
Logger.Info("Processing class structure been cancelled !!");
return new Dictionary<string, SortedDictionary<int, TypeTreeItem>>();
}
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 = Path.Combine(savePath, Path.GetDirectoryName(asset.Container));
}
else
{
exportPath = savePath;
}
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;
case ExportType.JSON:
if (ExportJSONFile(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 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 settings = new XmlWriterSettings() { Indent = true };
using (XmlWriter writer = XmlWriter.Create(filename, settings))
{
writer.WriteStartDocument();
writer.WriteStartElement("Assets");
writer.WriteAttributeString("filename", filename);
writer.WriteAttributeString("createdAt", DateTime.UtcNow.ToString("s"));
foreach (var asset in toExportAssets)
{
writer.WriteStartElement("Asset");
writer.WriteElementString("Name", asset.Name);
writer.WriteElementString("Container", asset.Container);
writer.WriteStartElement("Type");
writer.WriteAttributeString("id", ((int)asset.Type).ToString());
writer.WriteValue(asset.TypeString);
writer.WriteEndElement();
writer.WriteElementString("PathID", asset.m_PathID.ToString());
writer.WriteElementString("Source", asset.SourceFile.fullName);
writer.WriteElementString("Size", asset.FullSize.ToString());
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
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 exportNodes = GetNodes(nodes);
var count = exportNodes.Cast<TreeNode>().Sum(x => x.Nodes.Count);
int k = 0;
Progress.Reset();
foreach (TreeNode node in exportNodes)
{
//遍历一级子节点
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);
if (node.Parent != null)
{
filename = Path.Combine(FixFileName(node.Parent.Text), filename);
}
//每个文件存放在单独的文件夹
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");
IEnumerable<TreeNode> GetNodes(TreeNodeCollection nodes)
{
foreach(TreeNode node in nodes)
{
var subNodes = node.Nodes.OfType<TreeNode>().ToArray();
if (subNodes.Length == 0)
{
yield return node;
}
else
{
foreach (TreeNode subNode in subNodes)
{
yield return subNode;
}
}
}
}
});
}
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 ExportNodesWithAnimationClip(string exportPath, List<TreeNode> nodes, List<AssetItem> animationList = null)
{
ThreadPool.QueueUserWorkItem(state =>
{
int i = 0;
Progress.Reset();
foreach (var node in nodes)
{
var name = node.Text;
StatusStripUpdate($"Exporting {name}");
var gameObjects = new List<GameObject>();
GetSelectedParentNode(node.Nodes, gameObjects);
if (gameObjects.Count > 0)
{
var subExportPath = exportPath + Path.Combine(node.Text, FixFileName(node.Text) + ".fbx");
try
{
ExportGameObjectMerge(gameObjects, subExportPath, animationList);
Progress.Report(++i, nodes.Count);
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");
}
}
else
{
StatusStripUpdate("Empty node selected for export.");
}
}
if (Properties.Settings.Default.openAfterExport)
{
OpenFolderInExplorer(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);
}
}
}

94
AssetStudio.GUI/UnityCNForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,94 @@
namespace AssetStudio.GUI
{
partial class UnityCNForm
{
/// <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.specifyUnityCNList = new System.Windows.Forms.DataGridView();
this.NameField = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.KeyField = new System.Windows.Forms.DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize)(this.specifyUnityCNList)).BeginInit();
this.SuspendLayout();
//
// specifyUnityCNList
//
this.specifyUnityCNList.AllowUserToResizeColumns = false;
this.specifyUnityCNList.AllowUserToResizeRows = false;
this.specifyUnityCNList.ClipboardCopyMode = System.Windows.Forms.DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
this.specifyUnityCNList.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.specifyUnityCNList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.NameField,
this.KeyField});
this.specifyUnityCNList.Dock = System.Windows.Forms.DockStyle.Fill;
this.specifyUnityCNList.Location = new System.Drawing.Point(0, 0);
this.specifyUnityCNList.MultiSelect = false;
this.specifyUnityCNList.Name = "specifyUnityCNList";
this.specifyUnityCNList.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
this.specifyUnityCNList.RowTemplate.Height = 25;
this.specifyUnityCNList.Size = new System.Drawing.Size(408, 204);
this.specifyUnityCNList.TabIndex = 0;
this.specifyUnityCNList.RowHeaderMouseDoubleClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.specifyUnityCNList_RowHeaderMouseDoubleClick);
//
// NameField
//
this.NameField.HeaderText = "Name";
this.NameField.Name = "NameField";
this.NameField.Width = 140;
//
// KeyField
//
this.KeyField.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
this.KeyField.HeaderText = "Key";
this.KeyField.Name = "KeyField";
//
// UnityCNForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(408, 204);
this.Controls.Add(this.specifyUnityCNList);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "UnityCNForm";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "UnityCNForm";
this.TopMost = true;
((System.ComponentModel.ISupportInitialize)(this.specifyUnityCNList)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.DataGridView specifyUnityCNList;
private System.Windows.Forms.DataGridViewTextBoxColumn NameField;
private System.Windows.Forms.DataGridViewTextBoxColumn KeyField;
}
}

View File

@@ -0,0 +1,81 @@
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using AssetStudio;
using System.Linq;
namespace AssetStudio.GUI
{
public partial class UnityCNForm : Form
{
public UnityCNForm()
{
InitializeComponent();
var keys = UnityCNManager.GetEntries();
for (int i = 0; i < keys.Length; i++)
{
var key = keys[i];
var rowIdx = specifyUnityCNList.Rows.Add();
specifyUnityCNList.Rows[rowIdx].Cells["NameField"].Value = key.Name;
specifyUnityCNList.Rows[rowIdx].Cells["KeyField"].Value = key.Key;
}
var index = Properties.Settings.Default.selectedUnityCNKey;
if (index >= specifyUnityCNList.RowCount)
{
index = 0;
}
specifyUnityCNList.CurrentCell = specifyUnityCNList.Rows[index].Cells[0];
}
private void specifyUnityCNList_RowHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
{
var keys = new List<UnityCN.Entry>();
for (int i = specifyUnityCNList.Rows.Count - 1; i >= 0; i--)
{
var row = specifyUnityCNList.Rows[i];
var name = row.Cells["NameField"].Value as string;
var key = row.Cells["KeyField"].Value as string;
if (!(string.IsNullOrEmpty(name) || string.IsNullOrEmpty(key)))
{
var unityCN = new UnityCN.Entry(name, key);
if (unityCN.Validate())
{
keys.Add(unityCN);
continue;
}
}
if (specifyUnityCNList.CurrentCell.RowIndex == row.Index)
{
var previousRow = specifyUnityCNList.Rows.Cast<DataGridViewRow>().ElementAtOrDefault(i - 1);
if (previousRow != null)
{
specifyUnityCNList.CurrentCell = previousRow.Cells[0];
}
}
if (i != specifyUnityCNList.RowCount - 1)
{
specifyUnityCNList.Rows.RemoveAt(i);
}
}
UnityCNManager.SaveEntries(keys.Reverse<UnityCN.Entry>().ToList());
if (Studio.Game.Type.IsUnityCN())
{
UnityCNManager.SetKey(specifyUnityCNList.CurrentRow.Index);
}
Properties.Settings.Default.selectedUnityCNKey = specifyUnityCNList.CurrentRow.Index;
Properties.Settings.Default.Save();
DialogResult = DialogResult.OK;
Close();
}
}
}

View File

@@ -0,0 +1,126 @@
<?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="NameField.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="KeyField.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>