Some minor fixes

This commit is contained in:
VaDiM
2025-06-10 01:43:30 +03:00
parent 12799da395
commit a1ee61c542
6 changed files with 165 additions and 177 deletions

View File

@ -372,8 +372,13 @@ namespace AssetStudioCLI
var convert = 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, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(gameObject, CLIOptions.o_imageFormat.Value); : new ModelConverter(gameObject, CLIOptions.o_imageFormat.Value);
exportPath = exportPath + FixFileName(gameObject.m_Name) + ".fbx"; var modelName = FixFileName(gameObject.m_Name);
ExportFbx(convert, exportPath); var exportFullPath = Path.Combine(exportPath, "FBX_GameObjects", modelName, modelName + ".fbx");
if (File.Exists(exportFullPath))
{
exportFullPath = Path.Combine(exportPath, $"{modelName}_{gameObject.GetHashCode():X}", modelName + ".fbx");
}
ExportFbx(convert, exportFullPath);
} }
public static string FixFileName(string str) public static string FixFileName(string str)

View File

@ -79,7 +79,6 @@ namespace AssetStudioCLI.Options
internal static class CLIOptions internal static class CLIOptions
{ {
public static bool isParsed; public static bool isParsed;
public static bool showHelp;
public static string[] cliArgs; public static string[] cliArgs;
public static List<string> inputPathList; public static List<string> inputPathList;
public static FilterBy filterBy; public static FilterBy filterBy;
@ -166,7 +165,6 @@ namespace AssetStudioCLI.Options
private static void InitOptions() private static void InitOptions()
{ {
isParsed = false; isParsed = false;
showHelp = false;
cliArgs = null; cliArgs = null;
inputPathList = new List<string>(); inputPathList = new List<string>();
filterBy = FilterBy.None; filterBy = FilterBy.None;
@ -214,7 +212,7 @@ namespace AssetStudioCLI.Options
optionDescription: "Specify asset type(s) to export\n" + optionDescription: "Specify asset type(s) to export\n" +
"<Value(s): tex2d, tex2dArray, sprite, textAsset, monoBehaviour, font, shader\n" + "<Value(s): tex2d, tex2dArray, sprite, textAsset, monoBehaviour, font, shader\n" +
"movieTexture, audio, video, mesh | all(default)>\n" + "movieTexture, audio, video, mesh | all(default)>\n" +
"All - export all asset types, which are listed in the values\n" + "All - Export all asset types listed in the values\n" +
"*To specify multiple asset types, write them separated by ',' or ';' without spaces\n", "*To specify multiple asset types, write them separated by ',' or ';' without spaces\n",
optionExample: "Examples: \"-t sprite\" or \"-t tex2d,sprite,audio\" or \"-t tex2d;sprite;font\"\n", optionExample: "Examples: \"-t sprite\" or \"-t tex2d,sprite,audio\" or \"-t tex2d;sprite;font\"\n",
optionHelpGroup: HelpGroups.General optionHelpGroup: HelpGroups.General
@ -524,7 +522,7 @@ namespace AssetStudioCLI.Options
( (
optionDefaultValue: false, optionDefaultValue: false,
optionName: "--not-restore-extension", optionName: "--not-restore-extension",
optionDescription: "(Flag) If specified, AssetStudio will not try to use/restore original TextAsset\nextension name, and will just export all TextAssets with the \".txt\" extension\n", optionDescription: "(Flag) If specified, Studio will not try to use/restore original TextAsset extension,\nand will just export all TextAssets with the \".txt\" extension\n",
optionExample: "", optionExample: "",
optionHelpGroup: HelpGroups.Advanced, optionHelpGroup: HelpGroups.Advanced,
isFlag: true isFlag: true
@ -533,7 +531,7 @@ namespace AssetStudioCLI.Options
( (
optionDefaultValue: false, optionDefaultValue: false,
optionName: "--avoid-typetree-loading", optionName: "--avoid-typetree-loading",
optionDescription: "(Flag) If specified, AssetStudio will not try to parse assets at load time\nusing their type tree\n", optionDescription: "(Flag) If specified, Studio will not try to parse assets at load time\nusing their type tree\n",
optionExample: "", optionExample: "",
optionHelpGroup: HelpGroups.Advanced, optionHelpGroup: HelpGroups.Advanced,
isFlag: true isFlag: true
@ -542,7 +540,7 @@ namespace AssetStudioCLI.Options
( (
optionDefaultValue: false, optionDefaultValue: false,
optionName: "--load-all", optionName: "--load-all",
optionDescription: "(Flag) If specified, AssetStudio will load assets of all types\n(Only for Dump, Info and ExportRaw modes)", optionDescription: "(Flag) If specified, Studio will load assets of all types\n(Only for Dump, Info and ExportRaw modes)",
optionExample: "", optionExample: "",
optionHelpGroup: HelpGroups.Advanced, optionHelpGroup: HelpGroups.Advanced,
isFlag: true isFlag: true
@ -559,7 +557,7 @@ namespace AssetStudioCLI.Options
if (args.Length == 0 || args.Any(x => x.ToLower() == "-h" || x.ToLower() == "--help" || x.ToLower() == "-?")) if (args.Length == 0 || args.Any(x => x.ToLower() == "-h" || x.ToLower() == "--help" || x.ToLower() == "-?"))
{ {
showHelp = true; o_displayHelp.Value = true;
return; return;
} }
@ -583,35 +581,34 @@ namespace AssetStudioCLI.Options
return; return;
} }
var resplittedArgs = new List<string>(); var processedArgs = new List<string>();
for (int i = 1; i < args.Length; i++) for (var i = 1; i < args.Length; i++)
{ {
string arg = args[i]; var arg = args[i];
if (arg.Contains('=')) if (arg.Contains('='))
{ {
var splittedArgs = arg.Split('='); var splitArgs = arg.Split('=');
resplittedArgs.Add(splittedArgs[0]); processedArgs.Add(splitArgs[0]);
resplittedArgs.Add(splittedArgs[1]); processedArgs.Add(splitArgs[1]);
} }
else else
{ {
resplittedArgs.Add(arg); processedArgs.Add(arg);
} }
}; }
#region Parse "Working Mode" Option #region Parse "Working Mode" Option
var workModeOptionIndex = resplittedArgs.FindIndex(x => x.ToLower() == "-m" || x.ToLower() == "--mode"); var workModeOptionIndex = processedArgs.FindIndex(x => x.ToLower() == "-m" || x.ToLower() == "--mode");
if (workModeOptionIndex >= 0) if (workModeOptionIndex >= 0)
{ {
var option = resplittedArgs[workModeOptionIndex]; var option = processedArgs[workModeOptionIndex];
if (workModeOptionIndex + 1 >= resplittedArgs.Count) if (workModeOptionIndex + 1 >= processedArgs.Count)
{ {
Console.WriteLine($"{"Error during parsing options:".Color(brightRed)} Value for [{option.Color(brightYellow)}] option was not found.\n"); Console.WriteLine($"{"Error during parsing options:".Color(brightRed)} Value for [{option.Color(brightYellow)}] option was not found.\n");
TryFindOptionDescription(option, optionsDict); TryFindOptionDescription(option, optionsDict);
return; return;
} }
var value = resplittedArgs[workModeOptionIndex + 1]; var value = processedArgs[workModeOptionIndex + 1];
switch (value.ToLower()) switch (value.ToLower())
{ {
case "extract": case "extract":
@ -659,14 +656,14 @@ namespace AssetStudioCLI.Options
ShowOptionDescription(o_workMode); ShowOptionDescription(o_workMode);
return; return;
} }
resplittedArgs.RemoveRange(workModeOptionIndex, 2); processedArgs.RemoveRange(workModeOptionIndex, 2);
} }
#endregion #endregion
#region Parse Flags #region Parse Flags
for (var i = 0; i < resplittedArgs.Count; i++) for (var i = 0; i < processedArgs.Count; i++)
{ {
var flag = resplittedArgs[i].ToLower(); var flag = processedArgs[i].ToLower();
switch(flag) switch(flag)
{ {
@ -678,7 +675,7 @@ namespace AssetStudioCLI.Options
return; return;
} }
f_l2dAssetSearchByFilename.Value = true; f_l2dAssetSearchByFilename.Value = true;
resplittedArgs.RemoveAt(i); processedArgs.RemoveAt(i);
break; break;
case "--l2d-force-bezier": case "--l2d-force-bezier":
if (o_workMode.Value != WorkMode.Live2D) if (o_workMode.Value != WorkMode.Live2D)
@ -688,7 +685,7 @@ namespace AssetStudioCLI.Options
return; return;
} }
f_l2dForceBezier.Value = true; f_l2dForceBezier.Value = true;
resplittedArgs.RemoveAt(i); processedArgs.RemoveAt(i);
break; break;
case "--fbx-uvs-as-diffuse": case "--fbx-uvs-as-diffuse":
if (o_workMode.Value != WorkMode.SplitObjects) if (o_workMode.Value != WorkMode.SplitObjects)
@ -698,19 +695,19 @@ namespace AssetStudioCLI.Options
return; return;
} }
f_fbxUvsAsDiffuseMaps.Value = true; f_fbxUvsAsDiffuseMaps.Value = true;
resplittedArgs.RemoveAt(i); processedArgs.RemoveAt(i);
break; break;
case "--filter-with-regex": case "--filter-with-regex":
f_filterWithRegex.Value = true; f_filterWithRegex.Value = true;
resplittedArgs.RemoveAt(i); processedArgs.RemoveAt(i);
break; break;
case "--not-restore-extension": case "--not-restore-extension":
f_notRestoreExtensionName.Value = true; f_notRestoreExtensionName.Value = true;
resplittedArgs.RemoveAt(i); processedArgs.RemoveAt(i);
break; break;
case "--avoid-typetree-loading": case "--avoid-typetree-loading":
f_avoidLoadingViaTypetree.Value = true; f_avoidLoadingViaTypetree.Value = true;
resplittedArgs.RemoveAt(i); processedArgs.RemoveAt(i);
break; break;
case "--load-all": case "--load-all":
switch (o_workMode.Value) switch (o_workMode.Value)
@ -719,7 +716,7 @@ namespace AssetStudioCLI.Options
case WorkMode.Dump: case WorkMode.Dump:
case WorkMode.Info: case WorkMode.Info:
f_loadAllAssets.Value = true; f_loadAllAssets.Value = true;
resplittedArgs.RemoveAt(i); processedArgs.RemoveAt(i);
break; break;
default: default:
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{flag.Color(brightYellow)}] flag. This flag is not suitable for the current working mode [{o_workMode.Value}].\n"); Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{flag.Color(brightYellow)}] flag. This flag is not suitable for the current working mode [{o_workMode.Value}].\n");
@ -732,12 +729,12 @@ namespace AssetStudioCLI.Options
#endregion #endregion
#region Parse Options #region Parse Options
for (var i = 0; i < resplittedArgs.Count; i++) for (var i = 0; i < processedArgs.Count; i++)
{ {
var option = resplittedArgs[i].ToLower(); var option = processedArgs[i].ToLower();
try try
{ {
var value = resplittedArgs[i + 1].Replace("\"", ""); var value = processedArgs[i + 1].Replace("\"", "");
switch (option) switch (option)
{ {
case "-t": case "-t":
@ -1249,7 +1246,7 @@ namespace AssetStudioCLI.Options
if (isRegex) if (isRegex)
return new[] {value}; return new[] {value};
var separator = value.Contains(';') ? ';' : ','; var separator = value.Contains(',') ? ',' : ';';
return value.Split(separator); return value.Split(separator);
} }
@ -1282,7 +1279,7 @@ namespace AssetStudioCLI.Options
var helpMessage = new StringBuilder(); var helpMessage = new StringBuilder();
var usage = new StringBuilder(); var usage = new StringBuilder();
var appAssembly = typeof(Program).Assembly.GetName(); var appAssembly = typeof(Program).Assembly.GetName();
usage.Append($"{"Usage:".Color(ColorConsole.BrightYellow)} {appAssembly.Name} <input path to asset file/folder> "); usage.Append($"{"Usage:".Color(ColorConsole.BrightYellow)} {appAssembly.Name} <input path to asset file(s)/folder> ");
var i = 0; var i = 0;
foreach (var optionsGroup in optionGroups.Keys) foreach (var optionsGroup in optionGroups.Keys)
@ -1366,8 +1363,8 @@ namespace AssetStudioCLI.Options
{ {
sb.AppendLine($"# Output Path: \"{o_outputFolder}\""); sb.AppendLine($"# Output Path: \"{o_outputFolder}\"");
} }
sb.AppendLine($"Bundle BlockInfo Compression Type: {o_bundleBlockInfoCompression}"); sb.AppendLine($"# Bundle BlockInfo Compression Type: {o_bundleBlockInfoCompression}");
sb.AppendLine($"Bundle Block Compression Type: {o_bundleBlockCompression}"); sb.AppendLine($"# Bundle Block Compression Type: {o_bundleBlockCompression}");
switch (o_workMode.Value) switch (o_workMode.Value)
{ {
case WorkMode.Export: case WorkMode.Export:

View File

@ -13,7 +13,7 @@ namespace AssetStudioCLI
{ {
CLIRun(); CLIRun();
} }
else if (CLIOptions.showHelp) else if (CLIOptions.o_displayHelp.Value)
{ {
CLIOptions.ShowHelp(); CLIOptions.ShowHelp();
} }

View File

@ -861,7 +861,7 @@ namespace AssetStudioCLI
var log = $"Found {exportableCount} exportable object(s) "; var log = $"Found {exportableCount} exportable object(s) ";
if (isFiltered) if (isFiltered)
{ {
log += $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names"; log += $"that contain {$"\"{string.Join("\", \"", searchList)}\"".Color(Ansi.BrightYellow)} in their Names";
} }
Logger.Info(log); Logger.Info(log);
if (exportableCount > 0) if (exportableCount > 0)

View File

@ -9,7 +9,61 @@ namespace AssetStudioGUI
{ {
internal static class Exporter internal static class Exporter
{ {
public static bool ExportShader(AssetItem item, string exportPath) private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string mode = "Export")
{
var fileName = FixFileName(item.Text);
var filenameFormatIndex = Properties.Settings.Default.filenameFormat;
switch (filenameFormatIndex)
{
case 1: //assetName@pathID
fileName = $"{fileName} @{item.m_PathID}";
break;
case 2: //pathID
fileName = item.m_PathID.ToString();
break;
}
fullPath = Path.Combine(dir, fileName + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
if (filenameFormatIndex == 0) //assetName
{
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
}
Logger.Warning($"{mode} failed. File \"{fullPath.Color(ColorConsole.BrightYellow)}\" already exist");
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;
m_VideoClip.m_VideoData.WriteData(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);
return true;
}
private static bool ExportShader(AssetItem item, string exportPath)
{ {
if (!TryExportFile(exportPath, item, ".shader", out var exportFullPath)) if (!TryExportFile(exportPath, item, ".shader", out var exportFullPath))
return false; return false;
@ -19,7 +73,7 @@ namespace AssetStudioGUI
return true; return true;
} }
public static bool ExportTextAsset(AssetItem item, string exportPath) private static bool ExportTextAsset(AssetItem item, string exportPath)
{ {
var m_TextAsset = (TextAsset)item.Asset; var m_TextAsset = (TextAsset)item.Asset;
var extension = ".txt"; var extension = ".txt";
@ -45,7 +99,7 @@ namespace AssetStudioGUI
return true; return true;
} }
public static bool ExportMonoBehaviour(AssetItem item, string exportPath) private static bool ExportMonoBehaviour(AssetItem item, string exportPath)
{ {
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath)) if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
return false; return false;
@ -61,7 +115,7 @@ namespace AssetStudioGUI
return true; return true;
} }
public static bool ExportFont(AssetItem item, string exportPath) private static bool ExportFont(AssetItem item, string exportPath)
{ {
var m_Font = (Font)item.Asset; var m_Font = (Font)item.Asset;
if (m_Font.m_FontData != null) if (m_Font.m_FontData != null)
@ -79,7 +133,7 @@ namespace AssetStudioGUI
return false; return false;
} }
public static bool ExportMesh(AssetItem item, string exportPath) private static bool ExportMesh(AssetItem item, string exportPath)
{ {
var m_Mesh = (Mesh)item.Asset; var m_Mesh = (Mesh)item.Asset;
if (m_Mesh.m_VertexCount <= 0) if (m_Mesh.m_VertexCount <= 0)
@ -161,26 +215,25 @@ namespace AssetStudioGUI
return true; return true;
} }
public static bool ExportVideoClip(AssetItem item, string exportPath) public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
{ {
var m_VideoClip = (VideoClip)item.Asset; var exportFullPath = Path.Combine(exportPath, item.Text, item.Text + ".fbx");
if (m_VideoClip.m_ExternalResources.m_Size > 0) if (File.Exists(exportFullPath))
{ {
if (!TryExportFile(exportPath, item, Path.GetExtension(m_VideoClip.m_OriginalPath), out var exportFullPath)) exportFullPath = Path.Combine(exportPath, item.Text + item.UniqueID, item.Text + ".fbx");
return false;
m_VideoClip.m_VideoData.WriteData(exportFullPath);
return true;
} }
return false; var m_Animator = (Animator)item.Asset;
var convert = animationList != null
? new ModelConverter(m_Animator, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(m_Animator, Properties.Settings.Default.convertType);
ExportFbx(convert, exportFullPath);
return true;
} }
public static bool ExportMovieTexture(AssetItem item, string exportPath) private static void ExportFbx(IImported convert, string exportPath)
{ {
var m_MovieTexture = (MovieTexture)item.Asset; var fbxSettings = Fbx.Settings.FromBase64(Properties.Settings.Default.fbxSettings);
if (!TryExportFile(exportPath, item, ".ogv", out var exportFullPath)) ModelExporter.ExportFbx(exportPath, convert, fbxSettings);
return false;
File.WriteAllBytes(exportFullPath, m_MovieTexture.m_MovieData);
return true;
} }
public static bool ExportRawFile(AssetItem item, string exportPath) public static bool ExportRawFile(AssetItem item, string exportPath)
@ -212,77 +265,6 @@ namespace AssetStudioGUI
return true; return true;
} }
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string mode = "Export")
{
var fileName = FixFileName(item.Text);
var filenameFormatIndex = Properties.Settings.Default.filenameFormat;
switch (filenameFormatIndex)
{
case 1: //assetName@pathID
fileName = $"{fileName} @{item.m_PathID}";
break;
case 2: //pathID
fileName = item.m_PathID.ToString();
break;
}
fullPath = Path.Combine(dir, fileName + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
if (filenameFormatIndex == 0) //assetName
{
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
}
Logger.Warning($"{mode} failed. File \"{fullPath.Color(ColorConsole.BrightYellow)}\" already exist");
return false;
}
public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
{
var exportFullPath = Path.Combine(exportPath, item.Text, item.Text + ".fbx");
if (File.Exists(exportFullPath))
{
exportFullPath = Path.Combine(exportPath, item.Text + item.UniqueID, item.Text + ".fbx");
}
var m_Animator = (Animator)item.Asset;
var convert = animationList != null
? new ModelConverter(m_Animator, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(m_Animator, Properties.Settings.Default.convertType);
ExportFbx(convert, exportFullPath);
return true;
}
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
{
var convert = animationList != null
? new ModelConverter(gameObject, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(gameObject, Properties.Settings.Default.convertType);
exportPath = exportPath + FixFileName(gameObject.m_Name) + ".fbx";
ExportFbx(convert, exportPath);
}
public static void ExportGameObjectMerge(List<GameObject> gameObject, string exportPath, List<AssetItem> animationList = null)
{
var rootName = Path.GetFileNameWithoutExtension(exportPath);
var convert = animationList != null
? new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType);
ExportFbx(convert, exportPath);
}
private static void ExportFbx(IImported convert, string exportPath)
{
var fbxSettings = Fbx.Settings.FromBase64(Properties.Settings.Default.fbxSettings);
ModelExporter.ExportFbx(exportPath, convert, fbxSettings);
}
public static bool ExportDumpFile(AssetItem item, string exportPath) public static bool ExportDumpFile(AssetItem item, string exportPath)
{ {
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath, mode: "Dump")) if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath, mode: "Dump"))
@ -315,6 +297,10 @@ namespace AssetStudioGUI
case ClassIDType.AudioClip: case ClassIDType.AudioClip:
case ClassIDType.Sprite: case ClassIDType.Sprite:
throw new System.NotImplementedException(); throw new System.NotImplementedException();
case ClassIDType.VideoClip:
return ExportVideoClip(item, exportPath);
case ClassIDType.MovieTexture:
return ExportMovieTexture(item, exportPath);
case ClassIDType.Shader: case ClassIDType.Shader:
return ExportShader(item, exportPath); return ExportShader(item, exportPath);
case ClassIDType.TextAsset: case ClassIDType.TextAsset:
@ -325,10 +311,6 @@ namespace AssetStudioGUI
return ExportFont(item, exportPath); return ExportFont(item, exportPath);
case ClassIDType.Mesh: case ClassIDType.Mesh:
return ExportMesh(item, exportPath); return ExportMesh(item, exportPath);
case ClassIDType.VideoClip:
return ExportVideoClip(item, exportPath);
case ClassIDType.MovieTexture:
return ExportMovieTexture(item, exportPath);
case ClassIDType.Animator: case ClassIDType.Animator:
return ExportAnimator(item, exportPath); return ExportAnimator(item, exportPath);
case ClassIDType.AnimationClip: case ClassIDType.AnimationClip:
@ -338,6 +320,24 @@ namespace AssetStudioGUI
} }
} }
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
{
var convert = animationList != null
? new ModelConverter(gameObject, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(gameObject, Properties.Settings.Default.convertType);
exportPath = exportPath + FixFileName(gameObject.m_Name) + ".fbx";
ExportFbx(convert, exportPath);
}
public static void ExportGameObjectMerge(List<GameObject> gameObject, string exportPath, List<AssetItem> animationList = null)
{
var rootName = Path.GetFileNameWithoutExtension(exportPath);
var convert = animationList != null
? new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType);
ExportFbx(convert, exportPath);
}
public static string FixFileName(string str) public static string FixFileName(string str)
{ {
return str.Length >= 260 return str.Length >= 260

View File

@ -178,35 +178,24 @@ namespace AssetStudio
{ {
if (m_Animator.m_Controller.TryGet(out var m_Controller)) if (m_Animator.m_Controller.TryGet(out var m_Controller))
{ {
AnimatorController m_AnimatorController;
var animationList = new List<AnimationClip>(); var animationList = new List<AnimationClip>();
switch (m_Controller) if (m_Controller is AnimatorOverrideController overrideController)
{ {
case AnimatorOverrideController m_AnimatorOverrideController: if (!overrideController.m_Controller.TryGet(out m_AnimatorController))
{ return;
if (m_AnimatorOverrideController.m_Controller.TryGet<AnimatorController>(out var m_AnimatorController)) }
{ else
foreach (var pptr in m_AnimatorController.m_AnimationClips) {
{ m_AnimatorController = (AnimatorController)m_Controller;
if (pptr.TryGet(out var m_AnimationClip)) }
{
animationList.Add(m_AnimationClip);
}
}
}
break;
}
case AnimatorController m_AnimatorController: foreach (var pptr in m_AnimatorController.m_AnimationClips)
{ {
foreach (var pptr in m_AnimatorController.m_AnimationClips) if (pptr.TryGet(out var m_AnimationClip))
{ {
if (pptr.TryGet(out var m_AnimationClip)) animationList.Add(m_AnimationClip);
{ }
animationList.Add(m_AnimationClip);
}
}
break;
}
} }
animationClipUniqArray = animationList.Distinct(animationClipEqComparer).ToArray(); animationClipUniqArray = animationList.Distinct(animationClipEqComparer).ToArray();
} }
@ -795,7 +784,7 @@ namespace AssetStudio
var name = animationClip.m_Name; var name = animationClip.m_Name;
if (AnimationList.Exists(x => x.Name == name)) if (AnimationList.Exists(x => x.Name == name))
{ {
for (int i = 1; ; i++) for (var i = 1; ; i++)
{ {
var fixName = name + $"_{i}"; var fixName = name + $"_{i}";
if (!AnimationList.Exists(x => x.Name == fixName)) if (!AnimationList.Exists(x => x.Name == fixName))
@ -811,7 +800,7 @@ namespace AssetStudio
AnimationList.Add(iAnim); AnimationList.Add(iAnim);
if (animationClip.m_Legacy) if (animationClip.m_Legacy)
{ {
foreach (var m_CompressedRotationCurve in animationClip.m_CompressedRotationCurves) foreach (var m_CompressedRotationCurve in animationClip?.m_CompressedRotationCurves)
{ {
var track = iAnim.FindTrack(FixBonePath(animationClip, m_CompressedRotationCurve.m_Path)); var track = iAnim.FindTrack(FixBonePath(animationClip, m_CompressedRotationCurve.m_Path));
@ -858,15 +847,12 @@ namespace AssetStudio
track.Scalings.Add(new ImportedKeyframe<Vector3>(m_Curve.time, new Vector3(m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z))); track.Scalings.Add(new ImportedKeyframe<Vector3>(m_Curve.time, new Vector3(m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z)));
} }
} }
if (animationClip.m_EulerCurves != null) foreach (var m_EulerCurve in animationClip?.m_EulerCurves)
{ {
foreach (var m_EulerCurve in animationClip.m_EulerCurves) var track = iAnim.FindTrack(FixBonePath(animationClip, m_EulerCurve.path));
foreach (var m_Curve in m_EulerCurve.curve.m_Curve)
{ {
var track = iAnim.FindTrack(FixBonePath(animationClip, m_EulerCurve.path)); track.Rotations.Add(new ImportedKeyframe<Vector3>(m_Curve.time, new Vector3(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z)));
foreach (var m_Curve in m_EulerCurve.curve.m_Curve)
{
track.Rotations.Add(new ImportedKeyframe<Vector3>(m_Curve.time, new Vector3(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z)));
}
} }
} }
foreach (var m_FloatCurve in animationClip.m_FloatCurves) foreach (var m_FloatCurve in animationClip.m_FloatCurves)
@ -900,22 +886,22 @@ namespace AssetStudio
var m_Clip = animationClip.m_MuscleClip.m_Clip.data; var m_Clip = animationClip.m_MuscleClip.m_Clip.data;
var streamedFrames = m_Clip.m_StreamedClip.ReadData(); var streamedFrames = m_Clip.m_StreamedClip.ReadData();
var m_ClipBindingConstant = animationClip.m_ClipBindingConstant ?? m_Clip.ConvertValueArrayToGenericBinding(); var m_ClipBindingConstant = animationClip.m_ClipBindingConstant ?? m_Clip.ConvertValueArrayToGenericBinding();
for (int frameIndex = 1; frameIndex < streamedFrames.Count - 1; frameIndex++) for (var frameIndex = 1; frameIndex < streamedFrames.Count - 1; frameIndex++)
{ {
var frame = streamedFrames[frameIndex]; var frame = streamedFrames[frameIndex];
var streamedValues = frame.keyList.Select(x => x.value).ToArray(); var streamedValues = frame.keyList.Select(x => x.value).ToArray();
for (int curveIndex = 0; curveIndex < frame.keyList.Length;) for (var curveIndex = 0; curveIndex < frame.keyList.Length;)
{ {
ReadCurveData(iAnim, m_ClipBindingConstant, frame.keyList[curveIndex].index, frame.time, streamedValues, 0, ref curveIndex); ReadCurveData(iAnim, m_ClipBindingConstant, frame.keyList[curveIndex].index, frame.time, streamedValues, 0, ref curveIndex);
} }
} }
var m_DenseClip = m_Clip.m_DenseClip; var m_DenseClip = m_Clip.m_DenseClip;
var streamCount = m_Clip.m_StreamedClip.curveCount; var streamCount = m_Clip.m_StreamedClip.curveCount;
for (int frameIndex = 0; frameIndex < m_DenseClip.m_FrameCount; frameIndex++) for (var frameIndex = 0; frameIndex < m_DenseClip.m_FrameCount; frameIndex++)
{ {
var time = m_DenseClip.m_BeginTime + frameIndex / m_DenseClip.m_SampleRate; var time = m_DenseClip.m_BeginTime + frameIndex / m_DenseClip.m_SampleRate;
var frameOffset = frameIndex * m_DenseClip.m_CurveCount; var frameOffset = frameIndex * m_DenseClip.m_CurveCount;
for (int curveIndex = 0; curveIndex < m_DenseClip.m_CurveCount;) for (var curveIndex = 0; curveIndex < m_DenseClip.m_CurveCount;)
{ {
var index = streamCount + curveIndex; var index = streamCount + curveIndex;
ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, time, m_DenseClip.m_SampleArray, (int)frameOffset, ref curveIndex); ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, time, m_DenseClip.m_SampleArray, (int)frameOffset, ref curveIndex);
@ -926,9 +912,9 @@ namespace AssetStudio
var m_ConstantClip = m_Clip.m_ConstantClip; var m_ConstantClip = m_Clip.m_ConstantClip;
var denseCount = m_Clip.m_DenseClip.m_CurveCount; var denseCount = m_Clip.m_DenseClip.m_CurveCount;
var time2 = 0.0f; var time2 = 0.0f;
for (int i = 0; i < 2; i++) for (var i = 0; i < 2; i++)
{ {
for (int curveIndex = 0; curveIndex < m_ConstantClip.data.Length;) for (var curveIndex = 0; curveIndex < m_ConstantClip.data.Length;)
{ {
var index = streamCount + denseCount + curveIndex; var index = streamCount + denseCount + curveIndex;
ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, time2, m_ConstantClip.data, 0, ref curveIndex); ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, time2, m_ConstantClip.data, 0, ref curveIndex);