Merge branch 'AssetStudioMod' into ArknightsStudio

This commit is contained in:
VaDiM 2023-09-15 21:31:38 +03:00
commit 5c489c5f83
27 changed files with 854 additions and 332 deletions

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.17.2.0</Version>
<Version>1.0.0</Version>
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<Version>0.17.2.0</Version>
<Version>1.0.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>

View File

@ -91,7 +91,14 @@ namespace AssetStudio
}
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
{
var m_IgnoreMasterTextureLimit = reader.ReadBoolean();
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 2)) //2022.2 and up
{
var m_IgnoreMipmapLimit = reader.ReadBoolean();
}
else
{
var m_IgnoreMasterTextureLimit = reader.ReadBoolean();
}
}
if (version[0] >= 3) //3.0.0 - 5.4
{
@ -100,6 +107,11 @@ namespace AssetStudio
var m_ReadAllowed = reader.ReadBoolean();
}
}
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 2)) //2022.2 and up
{
var m_MipmapLimitGroupName = reader.ReadAlignedString();
reader.AlignStream();
}
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
{
var m_StreamingMipmaps = reader.ReadBoolean();

View File

@ -3,9 +3,9 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
<AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle>
<AssemblyName>AssetStudioModCLI</AssemblyName>
<Version>0.17.2.0</Version>
<AssemblyTitle>ArknightsStudio by aelurum</AssemblyTitle>
<AssemblyName>ArknightsStudioCLI</AssemblyName>
<Version>1.0.0</Version>
<Copyright>Copyright © Perfare; Copyright © aelurum 2023</Copyright>
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>embedded</DebugType>
@ -24,6 +24,8 @@
<Target Name="CopyExtraFilesPortable" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == '' ">
<Message Text="Copying windows extra files for $(TargetFramework)... " Importance="high" />
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\win-x86\fmod.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
@ -32,6 +34,9 @@
<Target Name="CopyExtraFilesPortableNet" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == '' AND '$(TargetFramework)' != 'net472' ">
<Message Text="Copying other platforms extra files for $(TargetFramework)... " Importance="high" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libAssetStudioFBXNative.so" DestinationFolder="$(TargetDir)runtimes\linux-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\osx-x64\libAssetStudioFBXNative.dylib" DestinationFolder="$(TargetDir)runtimes\osx-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\osx-arm64\libAssetStudioFBXNative.dylib" DestinationFolder="$(TargetDir)runtimes\osx-arm64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x86\libfmod.so" DestinationFolder="$(TargetDir)runtimes\linux-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libfmod.so" DestinationFolder="$(TargetDir)runtimes\linux-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\osx-x64\libfmod.dylib" DestinationFolder="$(TargetDir)runtimes\osx-x64\native" ContinueOnError="false" />
@ -42,6 +47,8 @@
The dll is cross-platform while the executable isn't -->
<Target Name="PublishExtraFilesPortable" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == '' ">
<Message Text="Publishing windows extra files for Portable build ($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x64\native\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x64\native\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\fmod.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
@ -50,6 +57,9 @@
<Target Name="PublishExtraFilesPortableNet" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == '' AND '$(TargetFramework)' != 'net472' ">
<Message Text="Publishing other platforms extra files for Portable build ($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)runtimes\linux-x64\native\libAssetStudioFBXNative.so" DestinationFolder="$(PublishDir)runtimes\linux-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\osx-x64\native\libAssetStudioFBXNative.dylib" DestinationFolder="$(PublishDir)runtimes\osx-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\osx-arm64\native\libAssetStudioFBXNative.dylib" DestinationFolder="$(PublishDir)runtimes\osx-arm64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\linux-x86\native\libfmod.so" DestinationFolder="$(PublishDir)runtimes\linux-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\linux-x64\native\libfmod.so" DestinationFolder="$(PublishDir)runtimes\linux-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\osx-x64\native\libfmod.dylib" DestinationFolder="$(PublishDir)runtimes\osx-x64\native" ContinueOnError="false" />
@ -58,39 +68,46 @@
<Target Name="CopyExtraFilesWin86" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'win-x86' ">
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\win-x86\fmod.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
</Target>
<Target Name="CopyExtraFilesWin64" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'win-x64' ">
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\win-x64\fmod.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
</Target>
<Target Name="PublishExtraFilesWin" AfterTargets="Publish" Condition=" $(RuntimeIdentifier.Contains('win-x')) ">
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)\fmod.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
</Target>
<Target Name="CopyExtraFilesLinux64" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'linux-x64' ">
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libAssetStudioFBXNative.so" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libfmod.so" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
</Target>
<Target Name="PublishExtraFilesLinux64" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == 'linux-x64' ">
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)\libAssetStudioFBXNative.so" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)\libfmod.so" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
</Target>
<Target Name="CopyExtraFilesMac" AfterTargets="AfterBuild" Condition=" $(RuntimeIdentifier.Contains('osx-')) ">
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(ProjectDir)Libraries\$(RuntimeIdentifier)\libAssetStudioFBXNative.dylib" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\$(RuntimeIdentifier)\libfmod.dylib" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
</Target>
<Target Name="PublishExtraFilesMac" AfterTargets="Publish" Condition=" $(RuntimeIdentifier.Contains('osx-')) ">
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)\libAssetStudioFBXNative.dylib" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)\libfmod.dylib" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
</Target>

View File

@ -148,11 +148,11 @@ namespace Arknights
bool resized = false;
if (tex.Width != texMask.Width || tex.Height != texMask.Height)
{
texMask.Mutate(x => x.Resize(tex.Width, tex.Height, CLIOptions.o_akAlphaMaskResampler.Value));
texMask.Mutate(x => x.Resize(tex.Width, tex.Height, CLIOptions.o_akAlphaTexResampler.Value));
resized = true;
}
var invGamma = 1.0 / (1.0 + CLIOptions.o_akAlphaMaskGamma.Value / 10.0);
var invGamma = 1.0 / (1.0 + CLIOptions.o_akShadowGamma.Value / 10.0);
if (CLIOptions.akResizedOnly && !resized)
{
invGamma = 1.0;

View File

@ -14,6 +14,7 @@ namespace AssetStudioCLI
public ClassIDType Type;
public string Text;
public string UniqueID;
public GameObjectNode Node;
public PortraitSprite AkPortraitSprite;
public AssetItem(Object asset)

View File

@ -0,0 +1,16 @@
using AssetStudio;
using System.Collections.Generic;
namespace AssetStudioCLI
{
internal class BaseNode
{
public List<BaseNode> nodes = new List<BaseNode>();
public BaseNode()
{
}
}
}

View File

@ -0,0 +1,16 @@
using AssetStudio;
using System.Collections.Generic;
namespace AssetStudioCLI
{
internal class GameObjectNode : BaseNode
{
public GameObject gameObject;
public GameObjectNode(GameObject gameObject)
{
this.gameObject = gameObject;
}
}
}

View File

@ -4,6 +4,7 @@ using AssetStudioCLI.Options;
using Newtonsoft.Json;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@ -243,7 +244,7 @@ namespace AssetStudioCLI
var alias = "";
var m_Sprite = (Sprite)item.Asset;
var type = CLIOptions.o_imageFormat.Value;
var spriteMaskMode = CLIOptions.o_akSpriteMaskMode.Value != AkSpriteMaskMode.None ? SpriteMaskMode.Export : SpriteMaskMode.Off;
var spriteMaskMode = CLIOptions.o_akSpriteAlphaMode.Value != AkSpriteAlphaMode.None ? SpriteMaskMode.Export : SpriteMaskMode.Off;
var isCharAvgSprite = item.Container.Contains("avg/characters");
var isCharArt = item.Container.Contains("arts/characters");
@ -271,7 +272,7 @@ namespace AssetStudioCLI
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath, alias))
return false;
if (CLIOptions.o_akSpriteMaskMode.Value == AkSpriteMaskMode.External && (isCharAvgSprite || isCharArt))
if (CLIOptions.o_akSpriteAlphaMode.Value == AkSpriteAlphaMode.SearchExternal && (isCharAvgSprite || isCharArt))
{
if (m_Sprite.m_RD.alphaTexture.IsNull)
{
@ -307,7 +308,7 @@ namespace AssetStudioCLI
public static bool ExportPortraitSprite(AssetItem item, string exportPath)
{
var type = CLIOptions.o_imageFormat.Value;
var spriteMaskMode = CLIOptions.o_akSpriteMaskMode.Value != AkSpriteMaskMode.None ? SpriteMaskMode.Export : SpriteMaskMode.Off;
var spriteMaskMode = CLIOptions.o_akSpriteAlphaMode.Value != AkSpriteAlphaMode.None ? SpriteMaskMode.Export : SpriteMaskMode.Off;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
@ -342,6 +343,33 @@ namespace AssetStudioCLI
return true;
}
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
{
var convert = animationList != null
? new ModelConverter(gameObject, CLIOptions.o_imageFormat.Value, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(gameObject, CLIOptions.o_imageFormat.Value);
exportPath = exportPath + FixFileName(gameObject.m_Name) + ".fbx";
ExportFbx(convert, exportPath);
}
private static void ExportFbx(IImported convert, string exportPath)
{
var eulerFilter = true;
var filterPrecision = (float)0.25f;
var exportAllNodes = true;
var exportSkins = true;
var exportAnimations = true;
var exportBlendShape = true;
var castToBone = false;
var boneSize = CLIOptions.o_fbxBoneSize.Value;
var exportAllUvsAsDiffuseMaps = false;
var scaleFactor = CLIOptions.o_fbxScaleFactor.Value;
var fbxVersion = 3;
var fbxFormat = 0;
ModelExporter.ExportFbx(exportPath, convert, eulerFilter, filterPrecision,
exportAllNodes, exportSkins, exportAnimations, exportBlendShape, castToBone, boneSize, exportAllUvsAsDiffuseMaps, scaleFactor, fbxVersion, fbxFormat == 1);
}
public static bool ExportDumpFile(AssetItem item, string exportPath)
{
if (item.Asset == null)

View File

@ -14,6 +14,8 @@ namespace AssetStudioCLI.Options
General,
Convert,
Logger,
FBX,
Filter,
Arknights,
Advanced,
}
@ -25,6 +27,7 @@ namespace AssetStudioCLI.Options
Dump,
Info,
ExportLive2D,
SplitObjects,
}
internal enum AssetGroupOption
@ -58,11 +61,11 @@ namespace AssetStudioCLI.Options
NameAndContainer,
}
internal enum AkSpriteMaskMode
internal enum AkSpriteAlphaMode
{
None,
Internal,
External
InternalOnly,
SearchExternal
}
internal static class CLIOptions
@ -75,7 +78,8 @@ namespace AssetStudioCLI.Options
private static Dictionary<string, string> optionsDict;
private static Dictionary<string, string> flagsDict;
private static Dictionary<HelpGroups, Dictionary<string, string>> optionGroups;
private static List<ClassIDType> supportedAssetTypes;
private static List<ClassIDType> exportableAssetTypes;
private static Dictionary<string, ClassIDType> knownAssetTypesDict;
//general
public static Option<WorkMode> o_workMode;
public static Option<List<ClassIDType>> o_exportAssetTypes;
@ -89,23 +93,28 @@ namespace AssetStudioCLI.Options
public static bool convertTexture;
public static Option<ImageFormat> o_imageFormat;
public static Option<AudioFormat> o_audioFormat;
//arknights
public static bool akResizedOnly;
public static Option<AkSpriteMaskMode> o_akSpriteMaskMode;
public static Option<IResampler> o_akAlphaMaskResampler;
private static string resamplerName;
public static Option<int> o_akAlphaMaskGamma;
public static Option<bool> f_akOriginalAvgNames;
public static Option<bool> f_akAddAliases;
//advanced
public static Option<ExportListType> o_exportAssetList;
//fbx
public static Option<float> o_fbxScaleFactor;
public static Option<int> o_fbxBoneSize;
//filter
public static Option<List<string>> o_filterByName;
public static Option<List<string>> o_filterByContainer;
public static Option<List<string>> o_filterByPathID;
public static Option<List<string>> o_filterByText;
//arknights
public static bool akResizedOnly;
public static Option<AkSpriteAlphaMode> o_akSpriteAlphaMode;
public static Option<IResampler> o_akAlphaTexResampler;
private static string resamplerName;
public static Option<int> o_akShadowGamma;
public static Option<bool> f_akOriginalAvgNames;
public static Option<bool> f_akAddAliases;
//advanced
public static Option<ExportListType> o_exportAssetList;
public static Option<string> o_assemblyPath;
public static Option<string> o_unityVersion;
public static Option<bool> f_notRestoreExtensionName;
public static Option<bool> f_loadAllAssets;
static CLIOptions()
{
@ -150,7 +159,7 @@ namespace AssetStudioCLI.Options
optionsDict = new Dictionary<string, string>();
flagsDict = new Dictionary<string, string>();
optionGroups = new Dictionary<HelpGroups, Dictionary<string, string>>();
supportedAssetTypes = new List<ClassIDType>
exportableAssetTypes = new List<ClassIDType>
{
ClassIDType.Texture2D,
ClassIDType.Sprite,
@ -164,6 +173,7 @@ namespace AssetStudioCLI.Options
ClassIDType.MovieTexture,
ClassIDType.Mesh,
};
knownAssetTypesDict = ((ClassIDType[])Enum.GetValues(typeof(ClassIDType))).ToHashSet().ToDictionary(x => x.ToString().ToLower(), y => y);
#region Init General Options
o_workMode = new GroupedOption<WorkMode>
@ -171,18 +181,19 @@ namespace AssetStudioCLI.Options
optionDefaultValue: WorkMode.Export,
optionName: "-m, --mode <value>",
optionDescription: "Specify working mode\n" +
"<Value: export(default) | exportRaw | dump | info | live2d>\n" +
"<Value: export(default) | exportRaw | dump | info | live2d | splitObjects>\n" +
"Export - Exports converted assets\n" +
"ExportRaw - Exports raw data\n" +
"Dump - Makes asset dumps\n" +
"Info - Loads file(s), shows the number of available for export assets and exits\n" +
"Live2D - Exports Live2D Cubism 3 models\n" +
"SplitObjects - Exports split objects (fbx)\n" +
"Example: \"-m info\"\n",
optionHelpGroup: HelpGroups.General
);
o_exportAssetTypes = new GroupedOption<List<ClassIDType>>
(
optionDefaultValue: supportedAssetTypes,
optionDefaultValue: exportableAssetTypes,
optionName: "-t, --asset-type <value(s)>",
optionDescription: "Specify asset type(s) to export\n" +
"<Value(s): tex2d, sprite, akPortrait, textAsset, monoBehaviour, font, shader,\n" +
@ -208,7 +219,7 @@ namespace AssetStudioCLI.Options
);
o_outputFolder = new GroupedOption<string>
(
optionDefaultValue: "",
optionDefaultValue: "ASExport",
optionName: "-o, --output <path>",
optionDescription: "Specify path to the output folder\n" +
"If path isn't specifyed, 'ASExport' folder will be created in the program's work folder\n",
@ -268,52 +279,113 @@ namespace AssetStudioCLI.Options
);
#endregion
#region Init FBX Options
o_fbxScaleFactor = new GroupedOption<float>
(
optionDefaultValue: 1f,
optionName: "--fbx-scale-factor <value>",
optionDescription: "Specify the FBX Scale Factor\n" +
"<Value: float number from 0 to 100 (default=1)\n" +
"Example: \"--fbx-scale-factor 50\"\n",
optionHelpGroup: HelpGroups.FBX
);
o_fbxBoneSize = new GroupedOption<int>
(
optionDefaultValue: 10,
optionName: "--fbx-bone-size <value>",
optionDescription: "Specify the FBX Bone Size\n" +
"<Value: integer number from 0 to 100 (default=10)\n" +
"Example: \"--fbx-bone-size 10\"",
optionHelpGroup: HelpGroups.FBX
);
#endregion
#region Init Filter Options
o_filterByName = new GroupedOption<List<string>>
(
optionDefaultValue: new List<string>(),
optionName: "--filter-by-name <text>",
optionDescription: "Specify the name by which assets should be filtered\n" +
"*To specify multiple names write them separated by ',' or ';' without spaces\n" +
"Example: \"--filter-by-name char\" or \"--filter-by-name char,bg\"\n",
optionHelpGroup: HelpGroups.Filter
);
o_filterByContainer = new GroupedOption<List<string>>
(
optionDefaultValue: new List<string>(),
optionName: "--filter-by-container <text>",
optionDescription: "Specify the container by which assets should be filtered\n" +
"*To specify multiple containers write them separated by ',' or ';' without spaces\n" +
"Example: \"--filter-by-container arts\" or \"--filter-by-container arts,icons\"\n",
optionHelpGroup: HelpGroups.Filter
);
o_filterByPathID = new GroupedOption<List<string>>
(
optionDefaultValue: new List<string>(),
optionName: "--filter-by-pathid <text>",
optionDescription: "Specify the PathID by which assets should be filtered\n" +
"*To specify multiple PathIDs write them separated by ',' or ';' without spaces\n" +
"Example: \"--filter-by-pathid 7238605633795851352,-2430306240205277265\"\n",
optionHelpGroup: HelpGroups.Filter
);
o_filterByText = new GroupedOption<List<string>>
(
optionDefaultValue: new List<string>(),
optionName: "--filter-by-text <text>",
optionDescription: "Specify the text by which assets should be filtered\n" +
"Looks for assets that contain the specified text in their names or containers\n" +
"*To specify multiple values write them separated by ',' or ';' without spaces\n" +
"Example: \"--filter-by-text portrait\" or \"--filter-by-text portrait,art\"\n",
optionHelpGroup: HelpGroups.Filter
);
#endregion
#region Arknights Options
akResizedOnly = true;
o_akSpriteMaskMode = new GroupedOption<AkSpriteMaskMode>
o_akSpriteAlphaMode = new GroupedOption<AkSpriteAlphaMode>
(
optionDefaultValue: AkSpriteMaskMode.External,
optionName: "--spritemask-mode <value>",
optionDescription: "Specify the mode in which you want to export sprites with alpha mask\n" +
optionDefaultValue: AkSpriteAlphaMode.SearchExternal,
optionName: "--spritealpha-mode <value>",
optionDescription: "Specify the mode in which you want to export sprites with alpha texture\n" +
"<Value: none | internalOnly | searchExternal(default)>\n" +
"None - Export sprites without alpha mask applied\n" +
"Internal - Export sprites with internal alpha mask applied (if exist)\n" +
"SearchExternal - Export sprites with internal alpha mask applied,\n" +
"and in case it doesn't exist, Studio will try to find an external alpha mask\n" +
"Example: \"--spritemask-mode internalOnly\"\n",
"None - Export sprites without alpha texture applied\n" +
"InternalOnly - Export sprites with internal alpha texture applied (if exist)\n" +
"SearchExternal - Export sprites with internal alpha texture applied,\n" +
"and in case it doesn't exist, Studio will try to find an external alpha texture\n" +
"Example: \"--spritealpha-mode internalOnly\"\n",
optionHelpGroup: HelpGroups.Arknights
);
o_akAlphaMaskResampler = new GroupedOption<IResampler>
o_akAlphaTexResampler = new GroupedOption<IResampler>
(
optionDefaultValue: KnownResamplers.MitchellNetravali,
optionName: "--alphamask-resampler <value>",
optionDescription: "Specify the alpha mask upscale algorithm for 2048x2048 sprites\n" +
optionName: "--alphatex-resampler <value>",
optionDescription: "Specify the alpha texture upscale algorithm for 2048x2048 sprites\n" +
"<Value: nearest | bilinear | bicubic | mitchell(default) | spline | welch>\n" +
"Mitchell - Mitchell Netravali algorithm. Yields good equilibrium between \n" +
"sharpness and smoothness (produces less artifacts than bicubic in case of alpha masks)\n" +
"sharpness and smoothness (produces less artifacts than bicubic in the current use case)\n" +
"Spline - Similar to Mitchell Netravali but yielding smoother results\n" +
"Welch - A high speed algorithm that delivers very sharpened results\n" +
"Example: \"--alphamask-resampler bicubic\"\n",
"Example: \"--alphatex-resampler bicubic\"\n",
optionHelpGroup: HelpGroups.Arknights
);
resamplerName = "Mitchell";
o_akAlphaMaskGamma = new GroupedOption<int>
o_akShadowGamma = new GroupedOption<int>
(
optionDefaultValue: 2,
optionName: "--alphamask-gamma <value>",
optionDescription: "Specify the alpha mask gamma correction for 2048x2048 sprites\n" +
optionName: "--shadow-gamma <value>",
optionDescription: "Specify the gamma correction of semi-transparent shadow for 2048x2048 sprites\n" +
"<Value: integer number from -5 to 5 (default=2)>\n" +
"<0 - Make the alpha mask darker\n" +
"0 - Do not change the gamma of alpha mask\n" +
">0 - Make the alpha mask lighter\n" +
"Example: \"--alphamask-gamma 0\"\n",
"<0 - Make the shadow darker\n" +
"0 - Do not change the brightness of the shadow\n" +
">0 - Make the shadow lighter\n" +
"Example: \"--shadow-gamma 0\"\n",
optionHelpGroup: HelpGroups.Arknights
);
f_akOriginalAvgNames = new GroupedOption<bool>
(
optionDefaultValue: false,
optionName: "--original-avg-names",
optionDescription: "(Flag) If specified, names of avg sprites with faces will not be fixed\n",
optionDescription: "(Flag) If specified, names of avg character sprites will not be fixed\n",
optionHelpGroup: HelpGroups.Arknights,
isFlag: true
);
@ -321,7 +393,7 @@ namespace AssetStudioCLI.Options
(
optionDefaultValue: false,
optionName: "--add-aliases",
optionDescription: "(Flag) If specified, aliases will be added to avg sprite names (if exist)",
optionDescription: "(Flag) If specified, aliases will be added to avg character sprite names (if exist)",
optionHelpGroup: HelpGroups.Arknights,
isFlag: true
);
@ -338,62 +410,33 @@ namespace AssetStudioCLI.Options
"Example: \"--export-asset-list xml\"\n",
optionHelpGroup: HelpGroups.Advanced
);
o_filterByName = new GroupedOption<List<string>>
(
optionDefaultValue: new List<string>(),
optionName: "--filter-by-name <text>",
optionDescription: "Specify the name by which assets should be filtered\n" +
"*To specify multiple names write them separated by ',' or ';' without spaces\n" +
"Example: \"--filter-by-name char\" or \"--filter-by-name char,bg\"\n",
optionHelpGroup: HelpGroups.Advanced
);
o_filterByContainer = new GroupedOption<List<string>>
(
optionDefaultValue: new List<string>(),
optionName: "--filter-by-container <text>",
optionDescription: "Specify the container by which assets should be filtered\n" +
"*To specify multiple containers write them separated by ',' or ';' without spaces\n" +
"Example: \"--filter-by-container arts\" or \"--filter-by-container arts,icons\"\n",
optionHelpGroup: HelpGroups.Advanced
);
o_filterByPathID = new GroupedOption<List<string>>
(
optionDefaultValue: new List<string>(),
optionName: "--filter-by-pathid <text>",
optionDescription: "Specify the PathID by which assets should be filtered\n" +
"*To specify multiple PathIDs write them separated by ',' or ';' without spaces\n" +
"Example: \"--filter-by-pathid 7238605633795851352,-2430306240205277265\"\n",
optionHelpGroup: HelpGroups.Advanced
);
o_filterByText = new GroupedOption<List<string>>
(
optionDefaultValue: new List<string>(),
optionName: "--filter-by-text <text>",
optionDescription: "Specify the text by which assets should be filtered\n" +
"Looks for assets that contain the specified text in their names or containers\n" +
"*To specify multiple values write them separated by ',' or ';' without spaces\n" +
"Example: \"--filter-by-text portrait\" or \"--filter-by-text portrait,art\"\n",
optionHelpGroup: HelpGroups.Advanced
);
o_assemblyPath = new GroupedOption<string>
(
optionDefaultValue: "",
optionName: "--assembly-folder <path>",
optionDescription: "Specify the path to the assembly folder",
optionDescription: "Specify the path to the assembly folder\n",
optionHelpGroup: HelpGroups.Advanced
);
o_unityVersion = new GroupedOption<string>
(
optionDefaultValue: "",
optionName: "--unity-version <text>",
optionDescription: "Specify Unity version. Example: \"--unity-version 2017.4.39f1\"",
optionDescription: "Specify Unity version\nExample: \"--unity-version 2017.4.39f1\"\n",
optionHelpGroup: HelpGroups.Advanced
);
f_notRestoreExtensionName = new GroupedOption<bool>
(
optionDefaultValue: false,
optionName: "--not-restore-extension",
optionDescription: "(Flag) If specified, Studio will not try to use/restore original TextAsset\nextension name, and will just export all TextAssets with the \".txt\" extension",
optionDescription: "(Flag) If specified, Studio will not try to use/restore original TextAsset\nextension name, and will just export all TextAssets with the \".txt\" extension\n",
optionHelpGroup: HelpGroups.Advanced,
isFlag: true
);
f_loadAllAssets = new GroupedOption<bool>
(
optionDefaultValue: false,
optionName: "--load-all",
optionDescription: "(Flag) If specified, Studio will load assets of all types\n(Only for Dump, Info and ExportRaw modes)",
optionHelpGroup: HelpGroups.Advanced,
isFlag: true
);
@ -407,7 +450,7 @@ namespace AssetStudioCLI.Options
var brightYellow = CLIAnsiColors.BrightYellow;
var brightRed = CLIAnsiColors.BrightRed;
if (args.Length == 0 || args.Any(x => x == "-h" || x == "--help"))
if (args.Length == 0 || args.Any(x => x.ToLower() == "-h" || x.ToLower() == "--help" || x.ToLower() == "-?"))
{
showHelp = true;
return;
@ -422,7 +465,6 @@ namespace AssetStudioCLI.Options
$"Specified file or folder was not found. The input path must be specified as the first argument.");
return;
}
o_outputFolder.Value = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ASExport");
}
else
{
@ -447,6 +489,64 @@ namespace AssetStudioCLI.Options
}
};
var workModeOptionIndex = resplittedArgs.FindIndex(x => x.ToLower() == "-m" || x.ToLower() == "--mode");
if (workModeOptionIndex >= 0)
{
var option = resplittedArgs[workModeOptionIndex];
if (workModeOptionIndex + 1 >= resplittedArgs.Count)
{
Console.WriteLine($"{"Error during parsing options:".Color(brightRed)} Value for [{option.Color(brightRed)}] option was not found.\n");
TryFindOptionDescription(option, optionsDict);
return;
}
var value = resplittedArgs[workModeOptionIndex + 1];
switch (value.ToLower())
{
case "export":
o_workMode.Value = WorkMode.Export;
break;
case "raw":
case "exportraw":
o_workMode.Value = WorkMode.ExportRaw;
break;
case "dump":
o_workMode.Value = WorkMode.Dump;
break;
case "info":
o_workMode.Value = WorkMode.Info;
break;
case "live2d":
o_workMode.Value = WorkMode.ExportLive2D;
o_exportAssetTypes.Value = new List<ClassIDType>()
{
ClassIDType.AnimationClip,
ClassIDType.GameObject,
ClassIDType.MonoBehaviour,
ClassIDType.Texture2D,
ClassIDType.Transform,
};
break;
case "splitobjects":
o_workMode.Value = WorkMode.SplitObjects;
o_exportAssetTypes.Value = new List<ClassIDType>()
{
ClassIDType.GameObject,
ClassIDType.Texture2D,
ClassIDType.Material,
ClassIDType.Transform,
ClassIDType.Mesh,
ClassIDType.MeshRenderer,
ClassIDType.MeshFilter,
};
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported working mode: [{value.Color(brightRed)}].\n");
ShowOptionDescription(o_workMode.Description);
return;
}
resplittedArgs.RemoveRange(workModeOptionIndex, 2);
}
#region Parse Flags
for (int i = 0; i < resplittedArgs.Count; i++)
{
@ -458,6 +558,21 @@ namespace AssetStudioCLI.Options
f_notRestoreExtensionName.Value = true;
resplittedArgs.RemoveAt(i);
break;
case "--load-all":
switch (o_workMode.Value)
{
case WorkMode.ExportRaw:
case WorkMode.Dump:
case WorkMode.Info:
f_loadAllAssets.Value = true;
resplittedArgs.RemoveAt(i);
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{flag}] flag. This flag is not suitable for the current working mode [{o_workMode.Value}].\n");
ShowOptionDescription(f_loadAllAssets.Description, isFlag: true);
return;
}
break;
case "--original-avg-names":
f_akOriginalAvgNames.Value = true;
resplittedArgs.RemoveAt(i);
@ -479,43 +594,9 @@ namespace AssetStudioCLI.Options
var value = resplittedArgs[i + 1].Replace("\"", "");
switch (option)
{
case "-m":
case "--mode":
switch (value.ToLower())
{
case "export":
o_workMode.Value = WorkMode.Export;
break;
case "raw":
case "exportraw":
o_workMode.Value = WorkMode.ExportRaw;
break;
case "dump":
o_workMode.Value = WorkMode.Dump;
break;
case "info":
o_workMode.Value = WorkMode.Info;
break;
case "live2d":
o_workMode.Value = WorkMode.ExportLive2D;
o_exportAssetTypes.Value = new List<ClassIDType>()
{
ClassIDType.AnimationClip,
ClassIDType.GameObject,
ClassIDType.MonoBehaviour,
ClassIDType.Texture2D,
ClassIDType.Transform,
};
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported working mode: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_workMode.Description);
return;
}
break;
case "-t":
case "--asset-type":
if (o_workMode.Value == WorkMode.ExportLive2D)
if (o_workMode.Value == WorkMode.ExportLive2D || o_workMode.Value == WorkMode.SplitObjects)
{
i++;
continue;
@ -527,47 +608,38 @@ namespace AssetStudioCLI.Options
switch (type.ToLower())
{
case "tex2d":
case "texture2d":
o_exportAssetTypes.Value.Add(ClassIDType.Texture2D);
break;
case "sprite":
o_exportAssetTypes.Value.Add(ClassIDType.Sprite);
break;
case "akportrait":
o_exportAssetTypes.Value.Add(ClassIDType.AkPortraitSprite);
break;
case "textasset":
o_exportAssetTypes.Value.Add(ClassIDType.TextAsset);
break;
case "monobehaviour":
o_exportAssetTypes.Value.Add(ClassIDType.MonoBehaviour);
break;
case "font":
o_exportAssetTypes.Value.Add(ClassIDType.Font);
break;
case "shader":
o_exportAssetTypes.Value.Add(ClassIDType.Shader);
break;
case "audio":
case "audioclip":
o_exportAssetTypes.Value.Add(ClassIDType.AudioClip);
break;
case "video":
case "videoclip":
o_exportAssetTypes.Value.Add(ClassIDType.VideoClip);
break;
case "movietexture":
o_exportAssetTypes.Value.Add(ClassIDType.MovieTexture);
break;
case "mesh":
o_exportAssetTypes.Value.Add(ClassIDType.Mesh);
break;
case "all":
o_exportAssetTypes.Value = supportedAssetTypes;
o_exportAssetTypes.Value = exportableAssetTypes;
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported asset type: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_exportAssetTypes.Description);
var isKnownType = knownAssetTypesDict.TryGetValue(type.ToLower(), out var assetType);
if (isKnownType)
{
if (f_loadAllAssets.Value || exportableAssetTypes.Contains(assetType))
{
o_exportAssetTypes.Value.Add(assetType);
break;
}
}
else
{
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unknown asset type specified [{type.Color(brightRed)}].\n");
ShowOptionDescription(o_exportAssetTypes.Description);
return;
}
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Asset type [{type.Color(brightRed)}] is not supported for exporting.\n");
ShowOptionDescription(o_exportAssetTypes.Description);
return;
}
}
@ -593,7 +665,7 @@ namespace AssetStudioCLI.Options
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported grouping option: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_groupAssetsBy.Description);
ShowOptionDescription(o_groupAssetsBy.Description);
return;
}
break;
@ -606,6 +678,10 @@ namespace AssetStudioCLI.Options
{
Directory.CreateDirectory(value);
}
if (!value.EndsWith($"{Path.DirectorySeparatorChar}"))
{
value += Path.DirectorySeparatorChar;
}
o_outputFolder.Value = value;
}
catch (Exception ex)
@ -640,7 +716,7 @@ namespace AssetStudioCLI.Options
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported log level value: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_logLevel.Description);
ShowOptionDescription(o_logLevel.Description);
return;
}
break;
@ -658,7 +734,7 @@ namespace AssetStudioCLI.Options
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported log output mode: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_logOutput.Description);
ShowOptionDescription(o_logOutput.Description);
return;
}
break;
@ -686,7 +762,7 @@ namespace AssetStudioCLI.Options
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported image format: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_imageFormat.Description);
ShowOptionDescription(o_imageFormat.Description);
return;
}
break;
@ -702,84 +778,40 @@ namespace AssetStudioCLI.Options
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported audio format: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_audioFormat.Description);
ShowOptionDescription(o_audioFormat.Description);
return;
}
break;
case "--spritemask-mode":
switch (value.ToLower())
case "--fbx-scale-factor":
{
case "none":
o_akSpriteMaskMode.Value = AkSpriteMaskMode.None;
break;
case "internal":
o_akSpriteMaskMode.Value = AkSpriteMaskMode.Internal;
break;
case "searchexternal":
o_akSpriteMaskMode.Value = AkSpriteMaskMode.External;
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported sprite mask mode: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_akSpriteMaskMode.Description);
var isFloat = float.TryParse(value, out float floatValue);
if (isFloat && floatValue >= 0 && floatValue <= 100)
{
o_fbxScaleFactor.Value = floatValue;
}
else
{
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported scale factor value: [{value.Color(brightRed)}].\n");
ShowOptionDescription(o_fbxScaleFactor.Description);
return;
}
break;
}
break;
case "--alphamask-resampler":
switch (value.ToLower())
case "--fbx-bone-size":
{
case "nearest":
o_akAlphaMaskResampler.Value = KnownResamplers.NearestNeighbor;
break;
case "bilinear":
o_akAlphaMaskResampler.Value = KnownResamplers.Triangle;
break;
case "bicubic":
o_akAlphaMaskResampler.Value = KnownResamplers.Bicubic;
break;
case "mitchell":
o_akAlphaMaskResampler.Value = KnownResamplers.MitchellNetravali;
break;
case "spline":
o_akAlphaMaskResampler.Value = KnownResamplers.Spline;
break;
case "welch":
o_akAlphaMaskResampler.Value = KnownResamplers.Welch;
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported alpha mask resampler: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_akAlphaMaskResampler.Description);
var isInt = int.TryParse(value, out int intValue);
if (isInt && intValue >= 0 && intValue <= 100)
{
o_fbxBoneSize.Value = intValue;
}
else
{
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported bone size value: [{value.Color(brightRed)}].\n");
ShowOptionDescription(o_fbxBoneSize.Description);
return;
}
break;
}
resamplerName = value.ToLower();
break;
case "--alphamask-gamma":
var isInt = int.TryParse(value, out int intValue);
if (isInt && intValue >= -5 && intValue <= 5)
{
o_akAlphaMaskGamma.Value = intValue;
}
else
{
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported gamma correction value: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_akAlphaMaskGamma.Description);
return;
}
break;
case "--export-asset-list":
switch (value.ToLower())
{
case "xml":
o_exportAssetList.Value = ExportListType.XML;
break;
case "none":
o_exportAssetList.Value = ExportListType.None;
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported asset list export option: [{value.Color(brightRed)}].\n");
Console.WriteLine(o_exportAssetList.Description);
return;
}
break;
case "--filter-by-name":
o_filterByName.Value.AddRange(ValueSplitter(value));
filterBy = filterBy == FilterBy.None ? FilterBy.Name : filterBy == FilterBy.Container ? FilterBy.NameAndContainer : filterBy;
@ -796,6 +828,82 @@ namespace AssetStudioCLI.Options
o_filterByText.Value.AddRange(ValueSplitter(value));
filterBy = FilterBy.NameOrContainer;
break;
case "--spritealpha-mode":
switch (value.ToLower())
{
case "none":
o_akSpriteAlphaMode.Value = AkSpriteAlphaMode.None;
break;
case "internalonly":
o_akSpriteAlphaMode.Value = AkSpriteAlphaMode.InternalOnly;
break;
case "searchexternal":
o_akSpriteAlphaMode.Value = AkSpriteAlphaMode.SearchExternal;
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported sprite alpha mode: [{value.Color(brightRed)}].\n");
ShowOptionDescription(o_akSpriteAlphaMode.Description);
return;
}
break;
case "--alphatex-resampler":
switch (value.ToLower())
{
case "nearest":
o_akAlphaTexResampler.Value = KnownResamplers.NearestNeighbor;
break;
case "bilinear":
o_akAlphaTexResampler.Value = KnownResamplers.Triangle;
break;
case "bicubic":
o_akAlphaTexResampler.Value = KnownResamplers.Bicubic;
break;
case "mitchell":
o_akAlphaTexResampler.Value = KnownResamplers.MitchellNetravali;
break;
case "spline":
o_akAlphaTexResampler.Value = KnownResamplers.Spline;
break;
case "welch":
o_akAlphaTexResampler.Value = KnownResamplers.Welch;
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported alpha texture resampler: [{value.Color(brightRed)}].\n");
ShowOptionDescription(o_akAlphaTexResampler.Description);
return;
}
resamplerName = value.ToLower();
break;
case "--shadow-gamma":
{
var isInt = int.TryParse(value, out int intValue);
if (isInt && intValue >= -5 && intValue <= 5)
{
o_akShadowGamma.Value = intValue;
}
else
{
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported gamma correction value: [{value.Color(brightRed)}].\n");
ShowOptionDescription(o_akShadowGamma.Description);
return;
}
break;
}
case "--export-asset-list":
switch (value.ToLower())
{
case "xml":
o_exportAssetList.Value = ExportListType.XML;
break;
case "none":
o_exportAssetList.Value = ExportListType.None;
break;
default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported asset list export option: [{value.Color(brightRed)}].\n");
ShowOptionDescription(o_exportAssetList.Description);
return;
}
break;
case "--assembly-folder":
if (Directory.Exists(value))
{
@ -813,9 +921,9 @@ namespace AssetStudioCLI.Options
break;
default:
Console.WriteLine($"{"Error:".Color(brightRed)} Unknown option [{option.Color(brightRed)}].\n");
if (!TryShowOptionDescription(option, optionsDict))
if (!TryFindOptionDescription(option, optionsDict))
{
TryShowOptionDescription(option, flagsDict);
TryFindOptionDescription(option, flagsDict, isFlag: true);
}
return;
}
@ -826,12 +934,12 @@ namespace AssetStudioCLI.Options
if (optionsDict.Any(x => x.Key.Contains(option)))
{
Console.WriteLine($"{"Error during parsing options:".Color(brightRed)} Value for [{option.Color(brightRed)}] option was not found.\n");
TryShowOptionDescription(option, optionsDict);
TryFindOptionDescription(option, optionsDict);
}
else if (flagsDict.Any(x => x.Key.Contains(option)))
{
Console.WriteLine($"{"Error:".Color(brightRed)} Unknown flag [{option.Color(brightRed)}].\n");
TryShowOptionDescription(option, flagsDict);
TryFindOptionDescription(option, flagsDict, isFlag: true);
}
else
{
@ -852,6 +960,15 @@ namespace AssetStudioCLI.Options
{
Studio.assemblyLoader.Loaded = true;
}
if (o_outputFolder.Value == o_outputFolder.DefaultValue)
{
var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, o_outputFolder.DefaultValue + Path.DirectorySeparatorChar);
if (!Directory.Exists(fullPath))
{
Directory.CreateDirectory(fullPath);
}
o_outputFolder.Value = fullPath;
}
isParsed = true;
}
@ -861,14 +978,21 @@ namespace AssetStudioCLI.Options
return value.Split(separator);
}
private static bool TryShowOptionDescription(string option, Dictionary<string, string> descDict)
private static void ShowOptionDescription(string desc, bool isFlag = false)
{
var optionDesc = descDict.Where(x => x.Key.Contains(option));
var arg = isFlag ? "Flag" : "Option";
Console.WriteLine($"{arg} description:\n{desc}");
}
private static bool TryFindOptionDescription(string option, Dictionary<string, string> dict, bool isFlag = false)
{
var optionDesc = dict.Where(x => x.Key.Contains(option));
if (optionDesc.Any())
{
var arg = isFlag ? "flag" : "option";
var rand = new Random();
var rndOption = optionDesc.ElementAt(rand.Next(0, optionDesc.Count()));
Console.WriteLine($"Did you mean [{ $"{rndOption.Key}".Color(CLIAnsiColors.BrightYellow) }] option?");
Console.WriteLine($"Did you mean [{ $"{rndOption.Key}".Color(CLIAnsiColors.BrightYellow) }] {arg}?");
Console.WriteLine($"Here's a description of it: \n\n{rndOption.Value}");
return true;
@ -910,7 +1034,7 @@ namespace AssetStudioCLI.Options
else
{
var arch = Environment.Is64BitProcess ? "x64" : "x32";
Console.WriteLine($"# {appAssembly.Name} [{arch}]\n# Based on AssetStudioMod v{appAssembly.Version}\n");
Console.WriteLine($"# {appAssembly.Name} [{arch}]\n# v{appAssembly.Version}\n# Based on AssetStudioMod v0.17.3\n");
Console.WriteLine($"{usage}\n\n{helpMessage}");
}
}
@ -934,6 +1058,21 @@ namespace AssetStudioCLI.Options
}
}
private static string ShowExportTypes()
{
switch (o_workMode.Value)
{
case WorkMode.ExportRaw:
case WorkMode.Dump:
case WorkMode.Info:
return f_loadAllAssets.Value && o_exportAssetTypes.Value == o_exportAssetTypes.DefaultValue
? $"# Export Asset Type(s): All"
: $"# Export Asset Type(s): {string.Join(", ", o_exportAssetTypes.Value)}";
default:
return $"# Export Asset Type(s): {string.Join(", ", o_exportAssetTypes.Value)}";
}
}
public static void ShowCurrentOptions()
{
var sb = new StringBuilder();
@ -942,31 +1081,24 @@ namespace AssetStudioCLI.Options
sb.AppendLine($"# Input Path: \"{inputPath}\"");
switch (o_workMode.Value)
{
case WorkMode.Info:
sb.AppendLine($"# Export Asset Type(s): {string.Join(", ", o_exportAssetTypes.Value)}");
sb.AppendLine($"# Log Level: {o_logLevel}");
sb.AppendLine($"# Log Output: {o_logOutput}");
sb.AppendLine($"# Export Asset List: {o_exportAssetList}");
sb.AppendLine(ShowCurrentFilter());
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
break;
case WorkMode.ExportLive2D:
case WorkMode.Export:
case WorkMode.ExportRaw:
case WorkMode.Dump:
sb.AppendLine($"# Output Path: \"{o_outputFolder}\"");
sb.AppendLine($"# Log Level: {o_logLevel}");
sb.AppendLine($"# Log Output: {o_logOutput}");
sb.AppendLine($"# Export Asset List: {o_exportAssetList}");
sb.AppendLine($"# Assebmly Path: \"{o_assemblyPath}\"");
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
break;
default:
sb.AppendLine($"# Output Path: \"{o_outputFolder}\"");
sb.AppendLine($"# Export Asset Type(s): {string.Join(", ", o_exportAssetTypes.Value)}");
if (o_workMode.Value != WorkMode.Export)
{
sb.AppendLine($"# Load All Assets: {f_loadAllAssets}");
}
sb.AppendLine(ShowExportTypes());
sb.AppendLine($"# Asset Group Option: {o_groupAssetsBy}");
sb.AppendLine($"# Export Image Format: {o_imageFormat}");
sb.AppendLine($"# Export Audio Format: {o_audioFormat}");
sb.AppendLine($"# [Arkingths] Sprite Mask Mode: {o_akSpriteMaskMode}");
sb.AppendLine($"# [Arknights] Mask Resampler: {resamplerName}");
sb.AppendLine($"# [Arknights] Mask Gamma Correction: {o_akAlphaMaskGamma.Value * 10:+#;-#;0}%");
if (o_workMode.Value == WorkMode.Export)
{
sb.AppendLine($"# Export Image Format: {o_imageFormat}");
sb.AppendLine($"# Export Audio Format: {o_audioFormat}");
sb.AppendLine($"# [Arkingths] Sprite Alpha Mode: {o_akSpriteAlphaMode}");
sb.AppendLine($"# [Arknights] Alpha Texture Resampler: {resamplerName}");
sb.AppendLine($"# [Arknights] Shadow Gamma Correction: {o_akShadowGamma.Value * 10:+#;-#;0}%");
}
sb.AppendLine($"# [Arknights] Don't Fix Avg Names: {f_akOriginalAvgNames}");
sb.AppendLine($"# [Arknights] Add Aliases: {f_akAddAliases}");
sb.AppendLine($"# Log Level: {o_logLevel}");
@ -975,7 +1107,36 @@ namespace AssetStudioCLI.Options
sb.AppendLine(ShowCurrentFilter());
sb.AppendLine($"# Assebmly Path: \"{o_assemblyPath}\"");
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
sb.AppendLine($"# Restore TextAsset Extension: {!f_notRestoreExtensionName.Value}");
if (o_workMode.Value == WorkMode.Export)
{
sb.AppendLine($"# Restore TextAsset Extension: {!f_notRestoreExtensionName.Value}");
}
break;
case WorkMode.Info:
sb.AppendLine($"# Load All Assets: {f_loadAllAssets}");
sb.AppendLine(ShowExportTypes());
sb.AppendLine($"# Log Level: {o_logLevel}");
sb.AppendLine($"# Log Output: {o_logOutput}");
sb.AppendLine($"# Export Asset List: {o_exportAssetList}");
sb.AppendLine(ShowCurrentFilter());
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
break;
case WorkMode.ExportLive2D:
case WorkMode.SplitObjects:
sb.AppendLine($"# Output Path: \"{o_outputFolder}\"");
sb.AppendLine($"# Log Level: {o_logLevel}");
sb.AppendLine($"# Log Output: {o_logOutput}");
sb.AppendLine($"# Export Asset List: {o_exportAssetList}");
if (o_workMode.Value == WorkMode.SplitObjects)
{
sb.AppendLine($"# Export Image Format: {o_imageFormat}");
sb.AppendLine($"# Filter by Name(s): \"{string.Join("\", \"", o_filterByName.Value)}\"");
}
else
{
sb.AppendLine($"# Assebmly Path: \"{o_assemblyPath}\"");
}
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
break;
}
sb.AppendLine("======");

View File

@ -35,9 +35,9 @@ namespace AssetStudioCLI
if (Studio.LoadAssets())
{
Studio.ParseAssets();
if (CLIOptions.filterBy != FilterBy.None && CLIOptions.o_workMode.Value != WorkMode.ExportLive2D)
if (CLIOptions.filterBy != FilterBy.None)
{
Studio.FilterAssets();
Studio.Filter();
}
if (CLIOptions.o_exportAssetList.Value != ExportListType.None)
{
@ -51,6 +51,9 @@ namespace AssetStudioCLI
case WorkMode.ExportLive2D:
Studio.ExportLive2D();
break;
case WorkMode.SplitObjects:
Studio.ExportSplitObjects();
break;
default:
Studio.ExportAssets();
break;

View File

@ -16,6 +16,7 @@ namespace AssetStudioCLI
public static AssetsManager assetsManager = new AssetsManager();
public static List<AssetItem> exportableAssetsList = new List<AssetItem>();
public static List<AssetItem> loadedAssetsList = new List<AssetItem>();
public static List<BaseNode> gameObjectTree = new List<BaseNode>();
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
private static Dictionary<AssetStudio.Object, string> containers = new Dictionary<AssetStudio.Object, string>();
@ -33,8 +34,10 @@ namespace AssetStudioCLI
{
var isLoaded = false;
assetsManager.SpecifyUnityVersion = CLIOptions.o_unityVersion.Value;
assetsManager.SetAssetFilter(CLIOptions.o_exportAssetTypes.Value);
if (!CLIOptions.f_loadAllAssets.Value)
{
assetsManager.SetAssetFilter(CLIOptions.o_exportAssetTypes.Value);
}
assetsManager.LoadFilesAndFolders(CLIOptions.inputPath);
if (assetsManager.assetsFileList.Count == 0)
{
@ -53,6 +56,7 @@ namespace AssetStudioCLI
Logger.Info("Parse assets...");
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
var objectAssetItemDic = new Dictionary<AssetStudio.Object, AssetItem>(objectCount);
Progress.Reset();
var i = 0;
@ -61,6 +65,7 @@ namespace AssetStudioCLI
foreach (var asset in assetsFile.Objects)
{
var assetItem = new AssetItem(asset);
objectAssetItemDic.Add(asset, assetItem);
assetItem.UniqueID = "_#" + i;
var isExportable = false;
switch (asset)
@ -80,6 +85,7 @@ namespace AssetStudioCLI
}
}
}
assetItem.Text = m_AssetBundle.m_Name;
break;
case ResourceManager m_ResourceManager:
foreach (var m_Container in m_ResourceManager.m_Container)
@ -104,14 +110,7 @@ namespace AssetStudioCLI
if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath))
assetItem.FullSize = asset.byteSize + m_VideoClip.m_ExternalResources.m_Size;
assetItem.Text = m_VideoClip.m_Name;
break;
case Mesh _:
case MovieTexture _:
case TextAsset _:
case Font _:
case Sprite _:
assetItem.Text = ((NamedObject)asset).m_Name;
break;
break;
case Shader m_Shader:
assetItem.Text = m_Shader.m_ParsedForm?.m_Name ?? m_Shader.m_Name;
break;
@ -125,15 +124,27 @@ namespace AssetStudioCLI
assetItem.Text = m_MonoBehaviour.m_Name;
}
break;
case GameObject m_GameObject:
assetItem.Text = m_GameObject.m_Name;
break;
case Animator m_Animator:
if (m_Animator.m_GameObject.TryGet(out var gameObject))
{
assetItem.Text = gameObject.m_Name;
}
break;
case NamedObject m_NamedObject:
assetItem.Text = m_NamedObject.m_Name;
break;
}
if (assetItem.Text == "")
if (string.IsNullOrEmpty(assetItem.Text))
{
assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
}
loadedAssetsList.Add(assetItem);
isExportable = CLIOptions.o_exportAssetTypes.Value.Contains(asset.type);
if (isExportable)
if (isExportable || (CLIOptions.f_loadAllAssets.Value && CLIOptions.o_exportAssetTypes.Value == CLIOptions.o_exportAssetTypes.DefaultValue))
{
exportableAssetsList.Add(assetItem);
}
@ -161,6 +172,11 @@ namespace AssetStudioCLI
containers.Clear();
}
}
if (CLIOptions.o_workMode.Value == WorkMode.SplitObjects)
{
BuildTreeStructure(objectAssetItemDic);
}
var log = $"Finished loading {assetsManager.assetsFileList.Count} files with {exportableAssetsList.Count} exportable assets";
var unityVer = assetsManager.assetsFileList[0].version;
long m_ObjectsCount;
@ -183,6 +199,85 @@ namespace AssetStudioCLI
Logger.Info(log);
}
public static void BuildTreeStructure(Dictionary<AssetStudio.Object, AssetItem> objectAssetItemDic)
{
Logger.Info("Building tree structure...");
var treeNodeDictionary = new Dictionary<GameObject, GameObjectNode>();
var assetsFileCount = assetsManager.assetsFileList.Count;
int j = 0;
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
var fileNode = new BaseNode(); //RootNode
foreach (var obj in assetsFile.Objects)
{
if (obj is GameObject m_GameObject)
{
if (!treeNodeDictionary.TryGetValue(m_GameObject, out var currentNode))
{
currentNode = new GameObjectNode(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].Node = currentNode;
if (m_Component is MeshFilter m_MeshFilter)
{
if (m_MeshFilter.m_Mesh.TryGet(out var m_Mesh))
{
objectAssetItemDic[m_Mesh].Node = currentNode;
}
}
else if (m_Component is SkinnedMeshRenderer m_SkinnedMeshRenderer)
{
if (m_SkinnedMeshRenderer.m_Mesh.TryGet(out var m_Mesh))
{
objectAssetItemDic[m_Mesh].Node = currentNode;
}
}
}
}
var parentNode = fileNode;
if (m_GameObject.m_Transform != null)
{
if (m_GameObject.m_Transform.m_Father.TryGet(out var m_Father))
{
if (m_Father.m_GameObject.TryGet(out var parentGameObject))
{
if (!treeNodeDictionary.TryGetValue(parentGameObject, out var parentGameObjectNode))
{
parentGameObjectNode = new GameObjectNode(parentGameObject);
treeNodeDictionary.Add(parentGameObject, parentGameObjectNode);
}
parentNode = parentGameObjectNode;
}
}
}
parentNode.nodes.Add(currentNode);
}
}
if (fileNode.nodes.Count > 0)
{
gameObjectTree.Add(fileNode);
}
Progress.Report(++j, assetsFileCount);
}
treeNodeDictionary.Clear();
objectAssetItemDic.Clear();
}
public static void ShowExportableAssetsInfo()
{
var exportableAssetsCountDict = new Dictionary<ClassIDType, int>();
@ -226,7 +321,20 @@ namespace AssetStudioCLI
}
}
public static void FilterAssets()
public static void Filter()
{
switch (CLIOptions.o_workMode.Value)
{
case WorkMode.ExportLive2D:
case WorkMode.SplitObjects:
break;
default:
FilterAssets();
break;
}
}
private static void FilterAssets()
{
var assetsCount = exportableAssetsList.Count;
var filteredAssets = new List<AssetItem>();
@ -234,14 +342,14 @@ namespace AssetStudioCLI
switch(CLIOptions.filterBy)
{
case FilterBy.Name:
filteredAssets = exportableAssetsList.FindAll(x => CLIOptions.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
filteredAssets = exportableAssetsList.FindAll(x => CLIOptions.o_filterByName.Value.Any(y => x.Text.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
$"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names."
);
break;
case FilterBy.Container:
filteredAssets = exportableAssetsList.FindAll(x => CLIOptions.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
filteredAssets = exportableAssetsList.FindAll(x => CLIOptions.o_filterByContainer.Value.Any(y => x.Container.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
$"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers."
@ -256,8 +364,8 @@ namespace AssetStudioCLI
break;
case FilterBy.NameOrContainer:
filteredAssets = exportableAssetsList.FindAll(x =>
CLIOptions.o_filterByText.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) ||
CLIOptions.o_filterByText.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
CLIOptions.o_filterByText.Value.Any(y => x.Text.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) ||
CLIOptions.o_filterByText.Value.Any(y => x.Container.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
);
Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
@ -266,8 +374,8 @@ namespace AssetStudioCLI
break;
case FilterBy.NameAndContainer:
filteredAssets = exportableAssetsList.FindAll(x =>
CLIOptions.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) &&
CLIOptions.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
CLIOptions.o_filterByName.Value.Any(y => x.Text.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) &&
CLIOptions.o_filterByContainer.Value.Any(y => x.Container.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
);
Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
@ -411,6 +519,101 @@ namespace AssetStudioCLI
Logger.Info($"Finished exporting asset list with {exportableAssetsList.Count} items.");
}
public static void ExportSplitObjects()
{
var savePath = CLIOptions.o_outputFolder.Value;
var searchList = CLIOptions.o_filterByName.Value;
var isFiltered = CLIOptions.filterBy == FilterBy.Name;
var exportableObjects = new List<GameObjectNode>();
var exportedCount = 0;
var k = 0;
Logger.Info($"Searching for objects to export..");
Progress.Reset();
var count = gameObjectTree.Sum(x => x.nodes.Count);
foreach (var node in gameObjectTree)
{
foreach (GameObjectNode j in node.nodes)
{
if (isFiltered)
{
if (!searchList.Any(searchText => j.gameObject.m_Name.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0))
continue;
}
var gameObjects = new List<GameObject>();
CollectNode(j, gameObjects);
if (gameObjects.All(x => x.m_SkinnedMeshRenderer == null && x.m_MeshFilter == null))
{
Progress.Report(++k, count);
continue;
}
exportableObjects.Add(j);
}
}
gameObjectTree.Clear();
var exportableCount = exportableObjects.Count;
var log = $"Found {exportableCount} exportable object(s) ";
if (isFiltered)
{
log += $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names";
}
Logger.Info(log);
if (exportableCount > 0)
{
Progress.Reset();
k = 0;
foreach (var gameObjectNode in exportableObjects)
{
var gameObject = gameObjectNode.gameObject;
var filename = FixFileName(gameObject.m_Name);
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
Logger.Info($"Exporting {filename}.fbx");
Progress.Report(k, exportableCount);
try
{
ExportGameObject(gameObject, targetPath);
Logger.Debug($"{gameObject.type} \"{filename}\" saved to \"{targetPath}\"");
exportedCount++;
}
catch (Exception ex)
{
Logger.Error($"Export GameObject:{gameObject.m_Name} error", ex);
}
k++;
}
}
var status = exportedCount > 0
? $"Finished exporting [{exportedCount}/{exportableCount}] object(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightCyan)}\""
: "Nothing exported";
Logger.Default.Log(LoggerEvent.Info, status, ignoreLevel: true);
}
private static void CollectNode(GameObjectNode node, List<GameObject> gameObjects)
{
gameObjects.Add(node.gameObject);
foreach (GameObjectNode i in node.nodes)
{
CollectNode(i, gameObjects);
}
}
public static void ExportLive2D()
{
var baseDestPath = Path.Combine(CLIOptions.o_outputFolder.Value, "Live2DOutput");

View File

@ -0,0 +1,22 @@
# Set the minimum version of CMake that can be used
cmake_minimum_required (VERSION 3.8)
# Set the project name
project("AssetStudioFBXNative")
# Set the C++ standard to C++ 14
set(CMAKE_CXX_STANDARD 14)
# Generate the shared library from the library sources
add_library(AssetStudioFBXNative SHARED
asfbx_skin_context.cpp
asfbx_morph_context.cpp
api.cpp
utils.cpp
asfbx_context.cpp
asfbx_anim_context.cpp)
# Add the given directories to those the compiler uses to search for include files
target_include_directories(AssetStudioFBXNative PRIVATE .)
target_link_libraries(AssetStudioFBXNative PRIVATE fbxsdk xml2)

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.17.2.0</Version>
<Version>1.0.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>

View File

@ -49,7 +49,7 @@
this.label7 = new System.Windows.Forms.Label();
this.modVersionLabel = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.label8 = new System.Windows.Forms.Label();
this.basedOnLabel = new System.Windows.Forms.Label();
this.checkUpdatesLinkLabel = new System.Windows.Forms.LinkLabel();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.licenseRichTextBox = new System.Windows.Forms.RichTextBox();
@ -116,8 +116,7 @@
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(347, 46);
this.label2.TabIndex = 0;
this.label2.Text = "AssetStudio is a tool for exploring, extracting, and exporting assets and asset b" +
"undles.";
this.label2.Text = "ArknightsStudio is a modified version of AssetStudio designed for Arknights.";
this.label2.UseCompatibleTextRendering = true;
//
// textBox2
@ -164,7 +163,7 @@
this.tableLayoutPanel2.ColumnCount = 3;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 41.37931F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 58.62069F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 111F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 113F));
this.tableLayoutPanel2.Controls.Add(this.label16, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.label17, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.gitPerfareLinkLabel, 2, 0);
@ -194,7 +193,7 @@
//
this.label17.AutoSize = true;
this.label17.BackColor = System.Drawing.Color.Transparent;
this.label17.Location = new System.Drawing.Point(102, 2);
this.label17.Location = new System.Drawing.Point(101, 2);
this.label17.Name = "label17";
this.label17.Size = new System.Drawing.Size(110, 13);
this.label17.TabIndex = 10;
@ -204,7 +203,7 @@
//
this.gitPerfareLinkLabel.AutoSize = true;
this.gitPerfareLinkLabel.BackColor = System.Drawing.Color.Transparent;
this.gitPerfareLinkLabel.Location = new System.Drawing.Point(239, 2);
this.gitPerfareLinkLabel.Location = new System.Drawing.Point(237, 2);
this.gitPerfareLinkLabel.Name = "gitPerfareLinkLabel";
this.gitPerfareLinkLabel.Size = new System.Drawing.Size(67, 13);
this.gitPerfareLinkLabel.TabIndex = 11;
@ -226,7 +225,7 @@
//
this.label19.AutoSize = true;
this.label19.BackColor = System.Drawing.Color.Transparent;
this.label19.Location = new System.Drawing.Point(102, 20);
this.label19.Location = new System.Drawing.Point(101, 20);
this.label19.Name = "label19";
this.label19.Size = new System.Drawing.Size(113, 13);
this.label19.TabIndex = 13;
@ -236,7 +235,7 @@
//
this.gitAelurumLinkLabel.AutoSize = true;
this.gitAelurumLinkLabel.BackColor = System.Drawing.Color.Transparent;
this.gitAelurumLinkLabel.Location = new System.Drawing.Point(239, 20);
this.gitAelurumLinkLabel.Location = new System.Drawing.Point(237, 20);
this.gitAelurumLinkLabel.Name = "gitAelurumLinkLabel";
this.gitAelurumLinkLabel.Size = new System.Drawing.Size(67, 13);
this.gitAelurumLinkLabel.TabIndex = 14;
@ -250,13 +249,13 @@
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 41.37931F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 58.62069F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 111F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 113F));
this.tableLayoutPanel1.Controls.Add(this.label5, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.productNamelabel, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.label7, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.modVersionLabel, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.label4, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.label8, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.basedOnLabel, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.checkUpdatesLinkLabel, 2, 1);
this.tableLayoutPanel1.Location = new System.Drawing.Point(6, 80);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
@ -285,11 +284,11 @@
//
this.productNamelabel.AutoSize = true;
this.productNamelabel.BackColor = System.Drawing.Color.Transparent;
this.productNamelabel.Location = new System.Drawing.Point(102, 2);
this.productNamelabel.Location = new System.Drawing.Point(101, 2);
this.productNamelabel.Name = "productNamelabel";
this.productNamelabel.Size = new System.Drawing.Size(103, 13);
this.productNamelabel.Size = new System.Drawing.Size(100, 13);
this.productNamelabel.TabIndex = 1;
this.productNamelabel.Text = "AssetStudioModGUI";
this.productNamelabel.Text = "ArknightsStudioGUI";
//
// label7
//
@ -297,16 +296,16 @@
this.label7.BackColor = System.Drawing.Color.Transparent;
this.label7.Location = new System.Drawing.Point(5, 20);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(68, 13);
this.label7.Size = new System.Drawing.Size(45, 13);
this.label7.TabIndex = 2;
this.label7.Text = "Mod version:";
this.label7.Text = "Version:";
//
// modVersionLabel
//
this.modVersionLabel.AutoSize = true;
this.modVersionLabel.BackColor = System.Drawing.Color.Transparent;
this.modVersionLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.modVersionLabel.Location = new System.Drawing.Point(102, 20);
this.modVersionLabel.Location = new System.Drawing.Point(101, 20);
this.modVersionLabel.Name = "modVersionLabel";
this.modVersionLabel.Size = new System.Drawing.Size(52, 13);
this.modVersionLabel.TabIndex = 3;
@ -323,21 +322,21 @@
this.label4.TabIndex = 4;
this.label4.Text = "Based on:";
//
// label8
// basedOnLabel
//
this.label8.AutoSize = true;
this.label8.BackColor = System.Drawing.Color.Transparent;
this.label8.Location = new System.Drawing.Point(102, 38);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(108, 13);
this.label8.TabIndex = 5;
this.label8.Text = "AssetStudio v0.16.47";
this.basedOnLabel.AutoSize = true;
this.basedOnLabel.BackColor = System.Drawing.Color.Transparent;
this.basedOnLabel.Location = new System.Drawing.Point(101, 38);
this.basedOnLabel.Name = "basedOnLabel";
this.basedOnLabel.Size = new System.Drawing.Size(123, 13);
this.basedOnLabel.TabIndex = 5;
this.basedOnLabel.Text = "AssetStudioMod v0.17.0";
//
// checkUpdatesLinkLabel
//
this.checkUpdatesLinkLabel.AutoSize = true;
this.checkUpdatesLinkLabel.BackColor = System.Drawing.Color.Transparent;
this.checkUpdatesLinkLabel.Location = new System.Drawing.Point(239, 20);
this.checkUpdatesLinkLabel.Location = new System.Drawing.Point(237, 20);
this.checkUpdatesLinkLabel.Name = "checkUpdatesLinkLabel";
this.checkUpdatesLinkLabel.Size = new System.Drawing.Size(96, 13);
this.checkUpdatesLinkLabel.TabIndex = 6;
@ -391,7 +390,7 @@
this.productTitleLabel.Name = "productTitleLabel";
this.productTitleLabel.Size = new System.Drawing.Size(384, 30);
this.productTitleLabel.TabIndex = 1;
this.productTitleLabel.Text = "AssetStudioModGUI";
this.productTitleLabel.Text = "ArknightsStudioGUI";
this.productTitleLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// CloseButton
@ -492,7 +491,7 @@
private System.Windows.Forms.Label label7;
private System.Windows.Forms.Label modVersionLabel;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.Label basedOnLabel;
private System.Windows.Forms.LinkLabel checkUpdatesLinkLabel;
private System.Windows.Forms.RichTextBox licenseRichTextBox;
private System.Windows.Forms.TextBox textBox2;

View File

@ -17,6 +17,7 @@ namespace AssetStudioGUI
productVersionLabel.Text = $"v{Application.ProductVersion} [{arch}]";
productNamelabel.Text = productName;
modVersionLabel.Text = Application.ProductVersion;
basedOnLabel.Text = "AssetStudioMod v0.17.3";
licenseRichTextBox.Text = GetLicenseText();
}
@ -41,7 +42,7 @@ namespace AssetStudioGUI
private void checkUpdatesLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var ps = new ProcessStartInfo("https://github.com/aelurum/AssetStudio/releases")
var ps = new ProcessStartInfo("https://github.com/aelurum/AssetStudio/tags")
{
UseShellExecute = true
};

View File

@ -5,9 +5,9 @@
<TargetFrameworks>net472;net6.0-windows;net7.0-windows</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
<AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle>
<AssemblyName>AssetStudioModGUI</AssemblyName>
<Version>0.17.2.0</Version>
<AssemblyTitle>ArknightsStudio by aelurum</AssemblyTitle>
<AssemblyName>ArknightsStudioGUI</AssemblyName>
<Version>1.0.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2021-2023</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>

View File

@ -293,7 +293,7 @@
this.akTitleMenuItem.Name = "akTitleMenuItem";
this.akTitleMenuItem.ShowShortcutKeys = false;
this.akTitleMenuItem.Size = new System.Drawing.Size(265, 22);
this.akTitleMenuItem.Text = "Arknighs";
this.akTitleMenuItem.Text = "Arknights";
//
// akFixFaceSpriteNamesToolStripMenuItem
//
@ -302,7 +302,7 @@
this.akFixFaceSpriteNamesToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.akFixFaceSpriteNamesToolStripMenuItem.Name = "akFixFaceSpriteNamesToolStripMenuItem";
this.akFixFaceSpriteNamesToolStripMenuItem.Size = new System.Drawing.Size(265, 22);
this.akFixFaceSpriteNamesToolStripMenuItem.Text = "Fix names of avg face sprites";
this.akFixFaceSpriteNamesToolStripMenuItem.Text = "Fix names of avg character sprites";
this.akFixFaceSpriteNamesToolStripMenuItem.ToolTipText = "Rename face sprites with numeric names to correct ones";
this.akFixFaceSpriteNamesToolStripMenuItem.CheckedChanged += new System.EventHandler(this.akFixFaceSpriteNamesToolStripMenuItem_Check);
//

View File

@ -512,9 +512,9 @@
this.akResamplerLabel.AutoSize = true;
this.akResamplerLabel.Location = new System.Drawing.Point(6, 21);
this.akResamplerLabel.Name = "akResamplerLabel";
this.akResamplerLabel.Size = new System.Drawing.Size(113, 13);
this.akResamplerLabel.Size = new System.Drawing.Size(120, 13);
this.akResamplerLabel.TabIndex = 5;
this.akResamplerLabel.Text = "Alpha mask resampler:";
this.akResamplerLabel.Text = "Alpha texture resampler:";
this.exportUvsTooltip.SetToolTip(this.akResamplerLabel, "Only affects exported images");
//
// akResamplerComboBox
@ -528,9 +528,9 @@
"Mitchell-Netravali",
"Spline",
"Welch"});
this.akResamplerComboBox.Location = new System.Drawing.Point(125, 18);
this.akResamplerComboBox.Location = new System.Drawing.Point(132, 18);
this.akResamplerComboBox.Name = "akResamplerComboBox";
this.akResamplerComboBox.Size = new System.Drawing.Size(169, 21);
this.akResamplerComboBox.Size = new System.Drawing.Size(162, 21);
this.akResamplerComboBox.TabIndex = 4;
this.exportUvsTooltip.SetToolTip(this.akResamplerComboBox, "Only affects exported images");
//
@ -549,7 +549,7 @@
this.akSpritesAlphaGroupBox.Size = new System.Drawing.Size(300, 178);
this.akSpritesAlphaGroupBox.TabIndex = 12;
this.akSpritesAlphaGroupBox.TabStop = false;
this.akSpritesAlphaGroupBox.Text = "Sprites: Alpha Mask [Arknights]";
this.akSpritesAlphaGroupBox.Text = "Sprites: Alpha Texture [Arknights]";
//
// akGammaNoteLabel
//
@ -567,9 +567,9 @@
this.akResamplerDescLabel.ForeColor = System.Drawing.SystemColors.GrayText;
this.akResamplerDescLabel.Location = new System.Drawing.Point(6, 43);
this.akResamplerDescLabel.Name = "akResamplerDescLabel";
this.akResamplerDescLabel.Size = new System.Drawing.Size(244, 13);
this.akResamplerDescLabel.Size = new System.Drawing.Size(251, 13);
this.akResamplerDescLabel.TabIndex = 6;
this.akResamplerDescLabel.Text = "Alpha mask upscale method for 2048x2048 sprites";
this.akResamplerDescLabel.Text = "Alpha texture upscale method for 2048x2048 sprites";
//
// akResizedOnlyCheckBox
//
@ -597,9 +597,9 @@
this.akGammaLabel.AutoSize = true;
this.akGammaLabel.Location = new System.Drawing.Point(6, 86);
this.akGammaLabel.Name = "akGammaLabel";
this.akGammaLabel.Size = new System.Drawing.Size(102, 13);
this.akGammaLabel.Size = new System.Drawing.Size(86, 13);
this.akGammaLabel.TabIndex = 1;
this.akGammaLabel.Text = "Alpha mask gamma:";
this.akGammaLabel.Text = "Shadow gamma:";
//
// akAlphaMaskGammaTrackBar
//
@ -627,9 +627,9 @@
this.akAddAliasesCheckBox.AutoSize = true;
this.akAddAliasesCheckBox.Location = new System.Drawing.Point(6, 28);
this.akAddAliasesCheckBox.Name = "akAddAliasesCheckBox";
this.akAddAliasesCheckBox.Size = new System.Drawing.Size(213, 17);
this.akAddAliasesCheckBox.Size = new System.Drawing.Size(261, 17);
this.akAddAliasesCheckBox.TabIndex = 0;
this.akAddAliasesCheckBox.Text = "Add aliases to avg sprite names (if exist)";
this.akAddAliasesCheckBox.Text = "Add aliases to avg character sprite names (if exist)";
this.akAddAliasesCheckBox.UseVisualStyleBackColor = true;
//
// ExportOptions

View File

@ -33,7 +33,12 @@ namespace AssetStudio
public TypeDefinition GetTypeDefinition(string assemblyName, string fullName)
{
if (moduleDic.TryGetValue(assemblyName, out var module))
moduleDic.TryGetValue(assemblyName, out var module);
if (module == null && !assemblyName.Contains(".dll"))
{
moduleDic.TryGetValue(assemblyName + ".dll", out module);
}
if (module != null)
{
var typeDef = module.GetType(fullName);
if (typeDef == null && assemblyName == "UnityEngine.dll")

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<Version>0.17.2.0</Version>
<Version>1.0.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>

View File

@ -1,5 +1,14 @@
# Changelog
## v0.17.3.0 [13-09-2023]
- [CLI] Added support for exporting split objects (fbx) (https://github.com/aelurum/AssetStudio/pull/10)
- [CLI] Fixed display of asset names in the exported asset list in some working modes
- [CLI] Fixed a bug where the default output folder might not exist
- Added support of Texture2D assets from Unity 2022.2+
- Fixed AssemblyLoader (https://github.com/aelurum/AssetStudio/issues/6)
- [CLI] Added --load-all flag to load assets of all types
- [CLI] Improved option grouping on the help screen
## v0.17.2.0 [27-08-2023]
- [GUI] Improved Scene Hierarchy tab
- Added "Related assets" item to the context menu (https://github.com/aelurum/AssetStudio/issues/7)

View File

@ -70,7 +70,7 @@ You can read CLI readme [here](https://github.com/aelurum/AssetStudio/blob/Asset
```
AssetStudioModCLI <asset folder path> -m info
```
- Export assets of all supported types
- Export assets of all supported for export types
```
AssetStudioModCLI <asset folder path>
```
@ -89,12 +89,22 @@ AssetStudioModCLI <asset folder path> -g type
```
AssetStudioModCLI <asset folder path> -o <output folder path>
```
- Dump assets to a specified output folder
```
AssetStudioModCLI <asset folder path> -m dump -o <output folder path>
```
- Export Live2D Cubism models
```
AssetStudioModCLI <asset folder path> -m live2d
```
> When running in live2d mode you can only specify `-o`, `--log-level`, `--log-output`, `--export-asset-list`, `--unity-version` and `--assembly-folder` options.
Any other options will be ignored.
- Export all FBX objects (similar to "Export all objects (split)" option in the GUI)
```
AssetStudioModCLI <asset folder path> -m splitObjects
```
> When running in splitObjects mode you can only specify `-o`, `--log-level`, `--log-output`, `--export-asset-list`, `--image-format`, `--filter-by-name` and `--unity-version` options.
Any other options will be ignored.
### Advanced Samples
- Export image assets converted to webp format to a specified output folder
@ -109,6 +119,13 @@ AssetStudioModCLI <asset folder path> -m info -t audio --filter-by-name voice
```
AssetStudioModCLI <asset folder path> -t audio --filter-by-name voice
```
- Export audio assets that have "music" or "voice" in their names
```
AssetStudioModCLI <asset folder path> -t audio --filter-by-name music,voice
```
```
AssetStudioModCLI <asset folder path> -t audio --filter-by-name music --filter-by-name voice
```
- Export audio assets that have "char" in their names **or** containers
```
AssetStudioModCLI <asset folder path> -t audio --filter-by-text char
@ -117,6 +134,10 @@ AssetStudioModCLI <asset folder path> -t audio --filter-by-text char
```
AssetStudioModCLI <asset folder path> -t audio --filter-by-name voice --filter-by-container char
```
- Export FBX objects that have "model" or "scene" in their names and set the scale factor to 10
```
AssetStudioModCLI <asset folder path> -m splitObjects --filter-by-name model,scene --fbx-scale-factor 10
```
- Export MonoBehaviour assets that require an assembly folder to read and create a log file
```
AssetStudioModCLI <asset folder path> -t monobehaviour --assembly-folder <assembly folder path> --log-output both
@ -125,6 +146,14 @@ AssetStudioModCLI <asset folder path> -t monobehaviour --assembly-folder <assemb
```
AssetStudioModCLI <asset folder path> --unity-version 2017.4.39f1
```
- Load assets of all types and show them (similar to "Display all assets" option in the GUI)
```
AssetStudioModCLI <asset folder path> -m info --load-all
```
- Load assets of all types and dump Material assets
```
AssetStudioModCLI <asset folder path> -m dump -t material --load-all
```
## GUI Usage
@ -140,7 +169,7 @@ Use **File->Extract file** or **File->Extract folder**.
### Export Assets, Live2D models
use **Export** menu.
Use **Export** menu.
### Export Model

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.17.2.0</Version>
<Version>1.0.0</Version>
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>