diff --git a/AssetStudio/AssetsManager.cs b/AssetStudio/AssetsManager.cs index ec24ae2..a141ce4 100644 --- a/AssetStudio/AssetsManager.cs +++ b/AssetStudio/AssetsManager.cs @@ -79,6 +79,18 @@ namespace AssetStudio { filteredAssetTypesList.Add(ClassIDType.AnimatorController); filteredAssetTypesList.Add(ClassIDType.AnimatorOverrideController); + filteredAssetTypesList.Add(ClassIDType.Animation); + filteredAssetTypesList.Add(ClassIDType.AnimationClip); + filteredAssetTypesList.Add(ClassIDType.Avatar); + filteredAssetTypesList.Add(ClassIDType.Material); + filteredAssetTypesList.Add(ClassIDType.MeshFilter); + filteredAssetTypesList.Add(ClassIDType.MeshRenderer); + filteredAssetTypesList.Add(ClassIDType.SkinnedMeshRenderer); + } + if (classIDTypes.Contains(ClassIDType.AnimatorController)) + { + filteredAssetTypesList.Add(ClassIDType.Animator); + filteredAssetTypesList.Add(ClassIDType.AnimatorOverrideController); } filteredAssetTypesList.UnionWith(classIDTypes); diff --git a/AssetStudioCLI/Exporter.cs b/AssetStudioCLI/Exporter.cs index cfad746..17d6b86 100644 --- a/AssetStudioCLI/Exporter.cs +++ b/AssetStudioCLI/Exporter.cs @@ -10,199 +10,6 @@ namespace AssetStudioCLI { internal static class Exporter { - 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; - - if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug) - { - var sb = new StringBuilder(); - sb.AppendLine($"VideoClip format: {m_VideoClip.m_Format}"); - sb.AppendLine($"VideoClip width: {m_VideoClip.Width}"); - sb.AppendLine($"VideoClip height: {m_VideoClip.Height}"); - sb.AppendLine($"VideoClip frame rate: {m_VideoClip.m_FrameRate:.0##}"); - sb.AppendLine($"VideoClip split alpha: {m_VideoClip.m_HasSplitAlpha}"); - Logger.Debug(sb.ToString()); - } - - m_VideoClip.m_VideoData.WriteData(exportFullPath); - Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{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); - - Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); - 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); - - Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); - return true; - } - - public static bool ExportTextAsset(AssetItem item, string exportPath) - { - var m_TextAsset = (TextAsset)item.Asset; - var extension = ".txt"; - var assetExtension = Path.GetExtension(m_TextAsset.m_Name); - if (!CLIOptions.f_notRestoreExtensionName.Value) - { - if (!string.IsNullOrEmpty(assetExtension)) - { - extension = ""; - } - else if (!string.IsNullOrEmpty(item.Container)) - { - var ext = Path.GetExtension(item.Container); - if (!string.IsNullOrEmpty(item.Container)) - { - extension = ext; - } - } - } - if (!TryExportFile(exportPath, item, extension, out var exportFullPath)) - return false; - File.WriteAllBytes(exportFullPath, m_TextAsset.m_Script); - - Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); - 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 = m_MonoBehaviour.ConvertToTypeTree(Studio.assemblyLoader); - type = m_MonoBehaviour.ToType(m_Type); - } - if (type != null) - { - var str = JsonConvert.SerializeObject(type, Formatting.Indented); - File.WriteAllText(exportFullPath, str); - - Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); - return true; - } - 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); - - Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); - return true; - } - return false; - } - - public static void ExportGameObject(GameObject gameObject, string exportPath, List 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 fbxSettings = new Fbx.Settings - { - BoneSize = CLIOptions.o_fbxBoneSize.Value, - ScaleFactor = CLIOptions.o_fbxScaleFactor.Value, - ExportAllUvsAsDiffuseMaps = CLIOptions.f_fbxUvsAsDiffuseMaps.Value, - }; - ModelExporter.ExportFbx(exportPath, convert, fbxSettings); - } - - public static bool ExportRawFile(AssetItem item, string exportPath) - { - if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath, mode: "ExportRaw")) - return false; - switch (item.Asset) - { - case Texture2D m_Texture2D: - if (!string.IsNullOrEmpty(m_Texture2D.m_StreamData?.path)) - { - m_Texture2D.image_data.WriteData(exportFullPath.Replace(".dat", "_data.dat")); - } - break; - case AudioClip m_AudioClip: - if (!string.IsNullOrEmpty(m_AudioClip.m_Source)) - { - m_AudioClip.m_AudioData.WriteData(exportFullPath.Replace(".dat", "_data.dat")); - } - break; - case VideoClip m_VideoClip: - if (!string.IsNullOrEmpty(m_VideoClip.m_ExternalResources.m_Source)) - { - m_VideoClip.m_VideoData.WriteData(exportFullPath.Replace(".dat", "_data.dat")); - } - break; - } - File.WriteAllBytes(exportFullPath, item.Asset.GetRawData()); - - Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); - return true; - } - - public static bool ExportDumpFile(AssetItem item, string exportPath) - { - if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath, mode: "Dump")) - return false; - var str = item.Asset.Dump(); - if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour) - { - var m_Type = m_MonoBehaviour.ConvertToTypeTree(Studio.assemblyLoader); - str = m_MonoBehaviour.Dump(m_Type); - } - if (string.IsNullOrEmpty(str)) - { - str = item.Asset.DumpObject(); - } - if (str != null) - { - File.WriteAllText(exportFullPath, str); - Logger.Debug($"{item.TypeString} \"{item.Text}\" saved to \"{exportFullPath}\""); - return true; - } - return false; - } - private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string mode = "Export") { var fileName = FixFileName(item.Text); @@ -235,6 +42,125 @@ namespace AssetStudioCLI return false; } + private 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; + + if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug) + { + var sb = new StringBuilder(); + sb.AppendLine($"VideoClip format: {m_VideoClip.m_Format}"); + sb.AppendLine($"VideoClip width: {m_VideoClip.Width}"); + sb.AppendLine($"VideoClip height: {m_VideoClip.Height}"); + sb.AppendLine($"VideoClip frame rate: {m_VideoClip.m_FrameRate:.0##}"); + sb.AppendLine($"VideoClip split alpha: {m_VideoClip.m_HasSplitAlpha}"); + Logger.Debug(sb.ToString()); + } + + m_VideoClip.m_VideoData.WriteData(exportFullPath); + Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); + return true; + } + return false; + } + + private 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); + + Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); + return true; + } + + private 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); + + Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); + return true; + } + + private static bool ExportTextAsset(AssetItem item, string exportPath) + { + var m_TextAsset = (TextAsset)item.Asset; + var extension = ".txt"; + var assetExtension = Path.GetExtension(m_TextAsset.m_Name); + if (!CLIOptions.f_notRestoreExtensionName.Value) + { + if (!string.IsNullOrEmpty(assetExtension)) + { + extension = ""; + } + else if (!string.IsNullOrEmpty(item.Container)) + { + var ext = Path.GetExtension(item.Container); + if (!string.IsNullOrEmpty(item.Container)) + { + extension = ext; + } + } + } + if (!TryExportFile(exportPath, item, extension, out var exportFullPath)) + return false; + File.WriteAllBytes(exportFullPath, m_TextAsset.m_Script); + + Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); + return true; + } + + private 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 = m_MonoBehaviour.ConvertToTypeTree(Studio.assemblyLoader); + type = m_MonoBehaviour.ToType(m_Type); + } + if (type != null) + { + var str = JsonConvert.SerializeObject(type, Formatting.Indented); + File.WriteAllText(exportFullPath, str); + + Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); + return true; + } + return false; + } + + private 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); + + Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); + return true; + } + return false; + } + private static bool ExportMesh(AssetItem item, string exportPath) { var m_Mesh = (Mesh)item.Asset; @@ -332,6 +258,87 @@ namespace AssetStudioCLI return true; } + public static bool ExportAnimator(AssetItem item, string exportPath, List animationList = null) + { + var exportFullPath = Path.Combine(exportPath, "FBX_Animator", 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, CLIOptions.o_imageFormat.Value, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) + : new ModelConverter(m_Animator, CLIOptions.o_imageFormat.Value); + ExportFbx(convert, exportFullPath); + return true; + } + + private static void ExportFbx(IImported convert, string exportPath) + { + var fbxSettings = new Fbx.Settings + { + BoneSize = CLIOptions.o_fbxBoneSize.Value, + ScaleFactor = CLIOptions.o_fbxScaleFactor.Value, + ExportAllUvsAsDiffuseMaps = CLIOptions.f_fbxUvsAsDiffuseMaps.Value, + ExportAnimations = CLIOptions.o_fbxAnimMode.Value != AnimationExportMode.Skip, + }; + ModelExporter.ExportFbx(exportPath, convert, fbxSettings); + } + + public static bool ExportRawFile(AssetItem item, string exportPath) + { + if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath, mode: "ExportRaw")) + return false; + switch (item.Asset) + { + case Texture2D m_Texture2D: + if (!string.IsNullOrEmpty(m_Texture2D.m_StreamData?.path)) + { + m_Texture2D.image_data.WriteData(exportFullPath.Replace(".dat", "_data.dat")); + } + break; + case AudioClip m_AudioClip: + if (!string.IsNullOrEmpty(m_AudioClip.m_Source)) + { + m_AudioClip.m_AudioData.WriteData(exportFullPath.Replace(".dat", "_data.dat")); + } + break; + case VideoClip m_VideoClip: + if (!string.IsNullOrEmpty(m_VideoClip.m_ExternalResources.m_Source)) + { + m_VideoClip.m_VideoData.WriteData(exportFullPath.Replace(".dat", "_data.dat")); + } + break; + } + File.WriteAllBytes(exportFullPath, item.Asset.GetRawData()); + + Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); + return true; + } + + public static bool ExportDumpFile(AssetItem item, string exportPath) + { + if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath, mode: "Dump")) + return false; + var str = item.Asset.Dump(); + if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour) + { + var m_Type = m_MonoBehaviour.ConvertToTypeTree(Studio.assemblyLoader); + str = m_MonoBehaviour.Dump(m_Type); + } + if (string.IsNullOrEmpty(str)) + { + str = item.Asset.DumpObject(); + } + if (str != null) + { + File.WriteAllText(exportFullPath, str); + Logger.Debug($"{item.TypeString} \"{item.Text}\" saved to \"{exportFullPath}\""); + return true; + } + return false; + } + public static bool ExportConvertFile(AssetItem item, string exportPath) { switch (item.Type) @@ -360,6 +367,15 @@ namespace AssetStudioCLI } } + public static void ExportGameObject(GameObject gameObject, string exportPath, List 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); + } + public static string FixFileName(string str) { return str.Length >= 260 diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index 4e9828f..f6c1de2 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -27,6 +27,7 @@ namespace AssetStudioCLI.Options Info, Live2D, SplitObjects, + Animator, } internal enum AssetGroupOption @@ -68,6 +69,13 @@ namespace AssetStudioCLI.Options NameAndContainer, } + internal enum AnimationExportMode + { + Auto, + Skip, + All, + } + internal static class CLIOptions { public static bool isParsed; @@ -102,6 +110,7 @@ namespace AssetStudioCLI.Options //fbx public static Option o_fbxScaleFactor; public static Option o_fbxBoneSize; + public static Option o_fbxAnimMode; public static Option f_fbxUvsAsDiffuseMaps; //filter public static Option> o_filterByName; @@ -186,14 +195,15 @@ namespace AssetStudioCLI.Options optionDefaultValue: WorkMode.Export, optionName: "-m, --mode ", optionDescription: "Specify working mode\n" + - "\n" + - "Extract - Extracts(Decompresses) asset bundles\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 models\n" + - "SplitObjects - Exports split objects (fbx)\n", + "\n" + + "Extract - Extract(Decompress) asset bundles\n" + + "Export - Convert and export assets\n" + + "ExportRaw - Export raw assets\n" + + "Dump - Generate json dumps of loaded asset\n" + + "Info - Load file(s) and show the number of available for export assets\n" + + "Live2D - Export Live2D Cubism models\n" + + "SplitObjects - Export all model objects (split) (fbx)\n" + + "Animator - Export Animator assets (fbx)\n", optionExample: "Example: \"-m info\"\n", optionHelpGroup: HelpGroups.General ); @@ -368,6 +378,18 @@ namespace AssetStudioCLI.Options optionExample: "Example: \"--fbx-bone-size 10\"\n", optionHelpGroup: HelpGroups.FBX ); + o_fbxAnimMode = new GroupedOption + ( + optionDefaultValue: AnimationExportMode.Auto, + optionName: "--fbx-animation", + optionDescription: "Specify the FBX animation export mode\n" + + "\n" + + "Auto - Search for model-related animations and export model with them\n" + + "Skip - Don't export animations\n" + + "All - Try to bind all loaded animations to each loaded model\n", + optionExample: "--fbx-animation skip\n", + optionHelpGroup: HelpGroups.FBX + ); f_fbxUvsAsDiffuseMaps = new GroupedOption ( optionDefaultValue: false, @@ -613,22 +635,23 @@ namespace AssetStudioCLI.Options o_workMode.Value = WorkMode.Live2D; o_exportAssetTypes.Value = new List { + ClassIDType.Animation, ClassIDType.AnimationClip, - ClassIDType.Animator, + ClassIDType.AnimatorController, ClassIDType.MonoBehaviour, ClassIDType.Texture2D, }; break; + case "animator": case "splitobjects": - o_workMode.Value = WorkMode.SplitObjects; + o_workMode.Value = value.ToLower() == "animator" + ? WorkMode.Animator + : WorkMode.SplitObjects; o_exportAssetTypes.Value = new List { - ClassIDType.Texture2D, - ClassIDType.Material, + ClassIDType.Animator, ClassIDType.Mesh, - ClassIDType.MeshRenderer, - ClassIDType.MeshFilter, - ClassIDType.SkinnedMeshRenderer, + ClassIDType.Texture2D, }; break; default: @@ -719,13 +742,19 @@ namespace AssetStudioCLI.Options { case "-t": case "--asset-type": - if (o_workMode.Value == WorkMode.Live2D || o_workMode.Value == WorkMode.SplitObjects) + if (o_workMode.Value == WorkMode.Live2D || o_workMode.Value == WorkMode.SplitObjects || o_workMode.Value == WorkMode.Animator) { i++; continue; } var splittedTypes = ValueSplitter(value); o_exportAssetTypes.Value = new List(); + if (splittedTypes.Contains("all", StringComparer.OrdinalIgnoreCase)) + { + o_exportAssetTypes.Value = exportableAssetTypes; + i++; + continue; + } foreach (var type in splittedTypes) { switch (type.ToLower()) @@ -742,8 +771,14 @@ namespace AssetStudioCLI.Options case "video": o_exportAssetTypes.Value.Add(ClassIDType.VideoClip); break; - case "all": - o_exportAssetTypes.Value = exportableAssetTypes; + case "animator": + if (o_workMode.Value == WorkMode.Export) + { + Console.WriteLine($"{"Not supported in current mode".Color(brightYellow)}. To export Animator assets use \"Animator mode\".\n"); + ShowOptionDescription(o_workMode); + return; + } + o_exportAssetTypes.Value.Add(ClassIDType.Animator); break; default: var isKnownType = knownAssetTypesDict.TryGetValue(type.ToLower(), out var assetType); @@ -1007,6 +1042,24 @@ namespace AssetStudioCLI.Options } break; } + case "--fbx-animation": + switch (value.ToLower()) + { + case "auto": + o_fbxAnimMode.Value = AnimationExportMode.Auto; + break; + case "skip": + o_fbxAnimMode.Value = AnimationExportMode.Skip; + break; + case "all": + o_fbxAnimMode.Value = AnimationExportMode.All; + break; + default: + Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option.Color(brightYellow)}] option. Unsupported animation export mode: [{value.Color(brightRed)}].\n"); + ShowOptionDescription(o_fbxAnimMode); + return; + } + break; case "--blockinfo-comp": switch (value.ToLower()) { @@ -1357,15 +1410,17 @@ namespace AssetStudioCLI.Options break; case WorkMode.Live2D: case WorkMode.SplitObjects: + case WorkMode.Animator: 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) + if (o_workMode.Value == WorkMode.SplitObjects || o_workMode.Value == WorkMode.Animator) { sb.AppendLine($"# Export Image Format: {o_imageFormat}"); sb.AppendLine($"# Filter by Name(s): \"{string.Join("\", \"", o_filterByName.Value)}\""); sb.AppendLine($"# FBX Scale Factor: {o_fbxScaleFactor}"); sb.AppendLine($"# FBX Bone Size: {o_fbxBoneSize}"); + sb.AppendLine($"# FBX Animation Mode: {o_fbxAnimMode}"); sb.AppendLine($"# FBX UVs as Diffuse Maps: {f_fbxUvsAsDiffuseMaps}"); } else diff --git a/AssetStudioCLI/Program.cs b/AssetStudioCLI/Program.cs index 3aa73e2..d036299 100644 --- a/AssetStudioCLI/Program.cs +++ b/AssetStudioCLI/Program.cs @@ -58,6 +58,9 @@ namespace AssetStudioCLI case WorkMode.SplitObjects: Studio.ExportSplitObjects(); break; + case WorkMode.Animator: + Studio.ExportAnimator(); + break; default: Studio.ExportAssets(); break; diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index 1962706..f99c5c3 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -526,6 +526,7 @@ namespace AssetStudioCLI { case WorkMode.Live2D: case WorkMode.SplitObjects: + case WorkMode.Animator: break; default: FilterAssets(); @@ -917,6 +918,62 @@ namespace AssetStudioCLI } } + public static void ExportAnimator() + { + var animationList = CLIOptions.o_fbxAnimMode.Value == AnimationExportMode.Auto + ? null + : new List(); + var exportAllAnimations = CLIOptions.o_fbxAnimMode.Value == AnimationExportMode.All; + + Logger.Info("Searching for Animator assets..."); + var animatorList = new List(); + foreach (var asset in parsedAssetsList) + { + switch (asset.Type) + { + case ClassIDType.Animator: + animatorList.Add(asset); + break; + case ClassIDType.AnimationClip when exportAllAnimations: + animationList?.Add(asset); + break; + } + } + parsedAssetsList = animatorList; + Logger.Info($"Found {parsedAssetsList.Count} exportable Animator asset(s)."); + if (parsedAssetsList.Count > 0 && CLIOptions.filterBy != FilterBy.None) + { + FilterAssets(); + } + + var savePath = CLIOptions.o_outputFolder.Value; + var toExportCount = parsedAssetsList.Count; + var exportedCount = 0; + Progress.Reset(); + foreach (var asset in parsedAssetsList) + { + var isExported = false; + Logger.Info($"[{exportedCount + 1}/{toExportCount}] Exporting \"{asset.Text}\"..."); + try + { + Logger.Debug($"Animator Export: {asset.Type} : {asset.Container} : {asset.Text}"); + isExported = Exporter.ExportAnimator(asset, savePath, animationList); + } + catch (Exception ex) + { + Logger.Error($"{asset.SourceFile.originalPath ?? asset.SourceFile.fullName}: [{$"{asset.Type}: {asset.Text}".Color(Ansi.BrightRed)}] : Export error\n{ex}"); + } + if (isExported) + { + exportedCount++; + } + } + var status = exportedCount > 0 + ? $"Finished exporting [{exportedCount}/{toExportCount}] Animator asset(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightCyan)}\"" + : "Nothing exported"; + Logger.Default.Log(LoggerEvent.Info, status, ignoreLevel: true); + } + private static bool TryGetCubismMoc(MonoBehaviour m_MonoBehaviour, out MonoBehaviour mocMono) { mocMono = null;