mirror of
https://github.com/aelurum/AssetStudio.git
synced 2026-11-14 11:18:47 -05:00
Some refactor for Live2D code
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
using AssetStudio;
|
||||
using AssetStudio.Addons.CubismLive2D;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using static CubismLive2DExtractor.CubismParsers;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
public class L2DAssetManager
|
||||
{
|
||||
public Dictionary<MonoBehaviour, CubismModel> ModelDict = new Dictionary<MonoBehaviour, CubismModel>();
|
||||
|
||||
public L2DAssetManager () { }
|
||||
|
||||
public void BindCubismAssetsByGO(GameObject m_GameObject, AssemblyLoader assemblyLoader)
|
||||
{
|
||||
if (!TryGetCubismMoc(m_GameObject.CubismModel.CubismModelMono, assemblyLoader, out var mocMono))
|
||||
return;
|
||||
|
||||
ModelDict[mocMono] = m_GameObject.CubismModel;
|
||||
BindAnimationClips(m_GameObject);
|
||||
}
|
||||
|
||||
public void BindCubismAssetsByMono(MonoBehaviour m_MonoBehaviour, string m_ClassName)
|
||||
{
|
||||
if (!m_MonoBehaviour.m_GameObject.TryGet(out var m_GameObject))
|
||||
return;
|
||||
|
||||
if (!TryGetModelGameObject(m_GameObject.m_Transform, out var modelGameObject))
|
||||
return;
|
||||
|
||||
switch (m_ClassName)
|
||||
{
|
||||
case "CubismMoc":
|
||||
if (!ModelDict.ContainsKey(m_MonoBehaviour))
|
||||
{
|
||||
ModelDict.Add(m_MonoBehaviour, null);
|
||||
}
|
||||
break;
|
||||
case "CubismRenderer":
|
||||
modelGameObject.CubismModel.RenderTextureList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismDisplayInfoParameterName":
|
||||
modelGameObject.CubismModel.ParamDisplayInfoList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismDisplayInfoPartName":
|
||||
modelGameObject.CubismModel.PartDisplayInfoList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismPosePart":
|
||||
modelGameObject.CubismModel.PosePartList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetCubismMoc(MonoBehaviour m_MonoBehaviour, AssemblyLoader assemblyLoader, out MonoBehaviour mocMono)
|
||||
{
|
||||
mocMono = null;
|
||||
var pptrDict = (OrderedDictionary)ParseMonoBehaviour(m_MonoBehaviour, CubismMonoBehaviourType.Model, assemblyLoader)?["_moc"];
|
||||
if (pptrDict == null)
|
||||
return false;
|
||||
|
||||
var mocPPtr = new PPtr<MonoBehaviour>
|
||||
{
|
||||
m_FileID = (int)pptrDict["m_FileID"],
|
||||
m_PathID = (long)pptrDict["m_PathID"],
|
||||
AssetsFile = m_MonoBehaviour.assetsFile
|
||||
};
|
||||
return mocPPtr.TryGet(out mocMono);
|
||||
}
|
||||
|
||||
private static void BindAnimationClips(GameObject gameObject)
|
||||
{
|
||||
if (gameObject.m_Animator == null || gameObject.m_Animator.m_Controller.IsNull)
|
||||
return;
|
||||
|
||||
if (!gameObject.m_Animator.m_Controller.TryGet(out var controller))
|
||||
return;
|
||||
|
||||
AnimatorController animatorController;
|
||||
if (controller is AnimatorOverrideController overrideController)
|
||||
{
|
||||
if (!overrideController.m_Controller.TryGet(out animatorController))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
animatorController = (AnimatorController)controller;
|
||||
}
|
||||
|
||||
foreach (var clipPptr in animatorController.m_AnimationClips)
|
||||
{
|
||||
if (clipPptr.TryGet(out var m_AnimationClip))
|
||||
{
|
||||
gameObject.CubismModel.ClipMotionList.Add(m_AnimationClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetModelGameObject(Transform m_Transform, out GameObject m_GameObject)
|
||||
{
|
||||
m_GameObject = null;
|
||||
if (m_Transform == null)
|
||||
return false;
|
||||
|
||||
while (m_Transform.m_Father.TryGet(out var m_Father))
|
||||
{
|
||||
m_Transform = m_Father;
|
||||
if (m_Transform.m_GameObject.TryGet(out m_GameObject) && m_GameObject.CubismModel != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
-156
@@ -5,7 +5,6 @@ using CubismLive2DExtractor;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -13,7 +12,6 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using static AssetStudioCLI.Exporter;
|
||||
using static CubismLive2DExtractor.CubismParsers;
|
||||
using Ansi = AssetStudio.ColorConsole;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
@@ -24,7 +22,7 @@ namespace AssetStudioCLI
|
||||
public static List<AssetItem> parsedAssetsList = new List<AssetItem>();
|
||||
public static List<BaseNode> gameObjectTree = new List<BaseNode>();
|
||||
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
|
||||
public static Dictionary<MonoBehaviour, CubismModel> l2dModelDict = new Dictionary<MonoBehaviour, CubismModel>();
|
||||
public static L2DAssetManager l2dAssetManager = new L2DAssetManager();
|
||||
private static Dictionary<AssetStudio.Object, string> containers = new Dictionary<AssetStudio.Object, string>();
|
||||
|
||||
static Studio()
|
||||
@@ -286,22 +284,11 @@ namespace AssetStudioCLI
|
||||
switch (m_Script.m_ClassName)
|
||||
{
|
||||
case "CubismMoc":
|
||||
if (!l2dModelDict.ContainsKey(m_MonoBehaviour))
|
||||
{
|
||||
l2dModelDict.Add(m_MonoBehaviour, null);
|
||||
}
|
||||
break;
|
||||
case "CubismRenderer":
|
||||
BindCubismAsset(m_MonoBehaviour, CubismMonoBehaviourType.RenderTexture);
|
||||
break;
|
||||
case "CubismDisplayInfoParameterName":
|
||||
BindCubismAsset(m_MonoBehaviour, CubismMonoBehaviourType.DisplayInfo, isParamInfo: true);
|
||||
break;
|
||||
case "CubismDisplayInfoPartName":
|
||||
BindCubismAsset(m_MonoBehaviour, CubismMonoBehaviourType.DisplayInfo);
|
||||
break;
|
||||
case "CubismPosePart":
|
||||
BindCubismAsset(m_MonoBehaviour, CubismMonoBehaviourType.PosePart);
|
||||
l2dAssetManager.BindCubismAssetsByMono(m_MonoBehaviour, m_Script.m_ClassName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -309,10 +296,9 @@ namespace AssetStudioCLI
|
||||
break;
|
||||
case GameObject m_GameObject:
|
||||
assetItem.Text = m_GameObject.m_Name;
|
||||
if (m_GameObject.CubismModel != null && TryGetCubismMoc(m_GameObject.CubismModel.CubismModelMono, out var mocMono))
|
||||
if (m_GameObject.CubismModel != null)
|
||||
{
|
||||
l2dModelDict[mocMono] = m_GameObject.CubismModel;
|
||||
BindAnimationClips(m_GameObject);
|
||||
l2dAssetManager.BindCubismAssetsByGO(m_GameObject, assemblyLoader);
|
||||
}
|
||||
break;
|
||||
case Animator m_Animator:
|
||||
@@ -521,7 +507,7 @@ namespace AssetStudioCLI
|
||||
info += $"\n#\n# Total: {parsedAssetsList.Count} assets";
|
||||
}
|
||||
|
||||
info += $"\n\n[Cubism Live2D]\n# Exportable Models: {l2dModelDict.Count}";
|
||||
info += $"\n\n[Cubism Live2D]\n# Exportable Models: {l2dAssetManager.ModelDict.Count}";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -999,97 +985,11 @@ namespace AssetStudioCLI
|
||||
Logger.Default.Log(LoggerEvent.Info, status, ignoreLevel: true);
|
||||
}
|
||||
|
||||
private static bool TryGetCubismMoc(MonoBehaviour m_MonoBehaviour, out MonoBehaviour mocMono)
|
||||
{
|
||||
mocMono = null;
|
||||
var pptrDict = (OrderedDictionary)CubismParsers.ParseMonoBehaviour(m_MonoBehaviour, CubismMonoBehaviourType.Model, assemblyLoader)?["_moc"];
|
||||
if (pptrDict == null)
|
||||
return false;
|
||||
|
||||
var mocPPtr = new PPtr<MonoBehaviour>
|
||||
{
|
||||
m_FileID = (int)pptrDict["m_FileID"],
|
||||
m_PathID = (long)pptrDict["m_PathID"],
|
||||
AssetsFile = m_MonoBehaviour.assetsFile
|
||||
};
|
||||
return mocPPtr.TryGet(out mocMono);
|
||||
}
|
||||
|
||||
private static void BindCubismAsset(MonoBehaviour m_MonoBehaviour, CubismMonoBehaviourType type, bool isParamInfo = false)
|
||||
{
|
||||
if (!m_MonoBehaviour.m_GameObject.TryGet(out var m_GameObject))
|
||||
return;
|
||||
|
||||
if (!TryGetModelGameObject(m_GameObject.m_Transform, out var modelGameObject))
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CubismMonoBehaviourType.PosePart:
|
||||
modelGameObject.CubismModel.PosePartList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case CubismMonoBehaviourType.DisplayInfo when isParamInfo:
|
||||
modelGameObject.CubismModel.ParamDisplayInfoList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case CubismMonoBehaviourType.DisplayInfo:
|
||||
modelGameObject.CubismModel.PartDisplayInfoList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case CubismMonoBehaviourType.RenderTexture:
|
||||
modelGameObject.CubismModel.RenderTextureList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindAnimationClips(GameObject gameObject)
|
||||
{
|
||||
if (gameObject.m_Animator == null || gameObject.m_Animator.m_Controller.IsNull)
|
||||
return;
|
||||
|
||||
if (!gameObject.m_Animator.m_Controller.TryGet(out var controller))
|
||||
return;
|
||||
|
||||
AnimatorController animatorController;
|
||||
if (controller is AnimatorOverrideController overrideController)
|
||||
{
|
||||
if (!overrideController.m_Controller.TryGet(out animatorController))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
animatorController = (AnimatorController)controller;
|
||||
}
|
||||
|
||||
foreach (var clipPptr in animatorController.m_AnimationClips)
|
||||
{
|
||||
if (clipPptr.TryGet(out var m_AnimationClip))
|
||||
{
|
||||
gameObject.CubismModel.ClipMotionList.Add(m_AnimationClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetModelGameObject(Transform m_Transform, out GameObject m_GameObject)
|
||||
{
|
||||
m_GameObject = null;
|
||||
if (m_Transform == null)
|
||||
return false;
|
||||
|
||||
while (m_Transform.m_Father.TryGet(out var m_Father))
|
||||
{
|
||||
m_Transform = m_Father;
|
||||
if (m_Transform.m_GameObject.TryGet(out m_GameObject) && m_GameObject.CubismModel != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Dictionary<MonoBehaviour, string> GenerateMocPathDict(Dictionary<MonoBehaviour, CubismModel> mocDict, bool searchByFilename)
|
||||
{
|
||||
var tempMocPathDict = new Dictionary<MonoBehaviour, (string, string)>();
|
||||
var mocPathDict = new Dictionary<MonoBehaviour, string>();
|
||||
foreach (var mocMono in l2dModelDict.Keys)
|
||||
foreach (var mocMono in l2dAssetManager.ModelDict.Keys)
|
||||
{
|
||||
if (containers.TryGetValue(mocMono, out var fullContainerPath))
|
||||
{
|
||||
@@ -1130,61 +1030,18 @@ namespace AssetStudioCLI
|
||||
return mocPathDict;
|
||||
}
|
||||
|
||||
public static void ExportLive2D()
|
||||
private static Dictionary<MonoBehaviour, List<AssetStudio.Object>> GenerateMocAssetDict(Dictionary<MonoBehaviour, CubismModel> mocDict)
|
||||
{
|
||||
var baseDestPath = Path.Combine(CLIOptions.o_outputFolder.Value, "Live2DOutput");
|
||||
var motionMode = CLIOptions.o_l2dMotionMode.Value;
|
||||
var forceBezier = CLIOptions.f_l2dForceBezier.Value;
|
||||
var modelGroupOption = CLIOptions.o_l2dGroupOption.Value;
|
||||
var searchByFilename = CLIOptions.f_l2dAssetSearchByFilename.Value;
|
||||
var mocDict = l2dModelDict;
|
||||
var l2dContainers = searchByFilename
|
||||
? new Dictionary<AssetStudio.Object, string>()
|
||||
: containers;
|
||||
|
||||
if (l2dModelDict.Count == 0)
|
||||
{
|
||||
Logger.Default.Log(LoggerEvent.Info, "Live2D Cubism models were not found.", ignoreLevel: true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CLIOptions.filterBy == FilterBy.NameOrContainer)
|
||||
{
|
||||
var regexMode = CLIOptions.f_filterWithRegex.Value;
|
||||
var filterList = CLIOptions.o_filterByText.Value;
|
||||
var filteredDict = new Dictionary<MonoBehaviour, CubismModel>();
|
||||
var regex = regexMode ? new Regex(filterList[0]) : null;
|
||||
foreach (var kvp in l2dModelDict)
|
||||
{
|
||||
var mocName = kvp.Key.m_Name;
|
||||
var mocContainer = containers.TryGetValue(kvp.Key, out var container)
|
||||
? container
|
||||
: "";
|
||||
if (regexMode)
|
||||
{
|
||||
if (regex.IsMatch(mocContainer) || regex.IsMatch(mocName))
|
||||
filteredDict[kvp.Key] = kvp.Value;
|
||||
continue;
|
||||
}
|
||||
if (filterList.Any(str => mocContainer.IndexOf(str, StringComparison.OrdinalIgnoreCase) >= 0 || mocName.IndexOf(str, StringComparison.OrdinalIgnoreCase) >= 0))
|
||||
{
|
||||
filteredDict[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
mocDict = filteredDict;
|
||||
var log = regexMode
|
||||
? $"Found {filteredDict.Count} Live2D model(s) which names or containers match {regex.ToString().Color(Ansi.BrightYellow)} regexp"
|
||||
: $"Found {filteredDict.Count} Live2D model(s) that contain {$"\"{string.Join("\", \"", filterList)}\"".Color(Ansi.BrightYellow)} in their names or containers";
|
||||
Logger.Info(log);
|
||||
}
|
||||
if (mocDict.Count == 0)
|
||||
return;
|
||||
|
||||
Progress.Reset();
|
||||
Logger.Info("Searching for Live2D files...");
|
||||
var mode = searchByFilename ? "file names" : "containers";
|
||||
Logger.Info($"Searching for Live2D assets using {mode}...");
|
||||
|
||||
var mocPathDict = GenerateMocPathDict(mocDict, searchByFilename);
|
||||
if (!searchByFilename && mocPathDict.Count != l2dModelDict.Count)
|
||||
if (!searchByFilename && mocPathDict.Count != mocDict.Count)
|
||||
{
|
||||
Logger.Warning($"Some Live2D models cannot be exported using containers\nTry to specify \"{"--l2d-search-by-filename".Color(Ansi.BrightCyan)}\" flag");
|
||||
}
|
||||
@@ -1237,19 +1094,70 @@ namespace AssetStudioCLI
|
||||
assetDict[mocKvp.Key] = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchByFilename)
|
||||
l2dContainers.Clear();
|
||||
if (mocDict.Keys.First().serializedType?.m_Type == null && CLIOptions.o_assemblyPath.Value == "")
|
||||
|
||||
return assetDict;
|
||||
}
|
||||
|
||||
private static void FilterMocDict()
|
||||
{
|
||||
var regexMode = CLIOptions.f_filterWithRegex.Value;
|
||||
var filterList = CLIOptions.o_filterByText.Value;
|
||||
var filteredDict = new Dictionary<MonoBehaviour, CubismModel>();
|
||||
var regex = regexMode ? new Regex(filterList[0]) : null;
|
||||
foreach (var kvp in l2dAssetManager.ModelDict)
|
||||
{
|
||||
var mocName = kvp.Key.m_Name;
|
||||
var mocContainer = containers.TryGetValue(kvp.Key, out var container)
|
||||
? container
|
||||
: "";
|
||||
if (regexMode)
|
||||
{
|
||||
if (regex.IsMatch(mocContainer) || regex.IsMatch(mocName))
|
||||
filteredDict[kvp.Key] = kvp.Value;
|
||||
continue;
|
||||
}
|
||||
if (filterList.Any(str => mocContainer.IndexOf(str, StringComparison.OrdinalIgnoreCase) >= 0 || mocName.IndexOf(str, StringComparison.OrdinalIgnoreCase) >= 0))
|
||||
{
|
||||
filteredDict[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
var log = regexMode
|
||||
? $"Found {filteredDict.Count} Live2D model(s) which names or containers match {regex.ToString().Color(Ansi.BrightYellow)} regexp"
|
||||
: $"Found {filteredDict.Count} Live2D model(s) that contain {$"\"{string.Join("\", \"", filterList)}\"".Color(Ansi.BrightYellow)} in their names or containers";
|
||||
Logger.Info(log);
|
||||
|
||||
l2dAssetManager.ModelDict = filteredDict;
|
||||
}
|
||||
|
||||
public static void ExportLive2D()
|
||||
{
|
||||
var baseDestPath = Path.Combine(CLIOptions.o_outputFolder.Value, "Live2DOutput");
|
||||
var motionMode = CLIOptions.o_l2dMotionMode.Value;
|
||||
var forceBezier = CLIOptions.f_l2dForceBezier.Value;
|
||||
var modelGroupOption = CLIOptions.o_l2dGroupOption.Value;
|
||||
var searchByFilename = CLIOptions.f_l2dAssetSearchByFilename.Value;
|
||||
if (CLIOptions.filterBy == FilterBy.NameOrContainer)
|
||||
FilterMocDict();
|
||||
if (l2dAssetManager.ModelDict.Count == 0)
|
||||
{
|
||||
Logger.Default.Log(LoggerEvent.Info, "Live2D Cubism models were not found.", ignoreLevel: true);
|
||||
return;
|
||||
}
|
||||
if (l2dAssetManager.ModelDict.Keys.First().serializedType?.m_Type == null && CLIOptions.o_assemblyPath.Value == "")
|
||||
{
|
||||
Logger.Warning("Specifying the assembly folder may be needed for proper extraction\n" +
|
||||
$"Use \"{"--assembly-folder <path>".Color(Ansi.BrightCyan)}\" to specify it");
|
||||
}
|
||||
|
||||
Progress.Reset();
|
||||
var assetDict = GenerateMocAssetDict(l2dAssetManager.ModelDict);
|
||||
var totalModelCount = assetDict.Count;
|
||||
Logger.Info($"Found {totalModelCount} model(s).");
|
||||
var parallelTaskCount = CLIOptions.o_maxParallelExportTasks.Value;
|
||||
var modelCounter = 0;
|
||||
Live2DExtractor.MocDict = mocDict;
|
||||
Live2DExtractor.MocDict = l2dAssetManager.ModelDict;
|
||||
Live2DExtractor.Assembly = assemblyLoader;
|
||||
foreach (var assetGroupKvp in assetDict)
|
||||
{
|
||||
|
||||
@@ -312,7 +312,7 @@ namespace AssetStudioGUI
|
||||
|
||||
var types = new SortedSet<string>();
|
||||
types.UnionWith(exportableAssets.Select(x => x.TypeString));
|
||||
if (Studio.l2dModelDict.Count > 0)
|
||||
if (Studio.l2dAssetManager.ModelDict.Count > 0)
|
||||
{
|
||||
types.Add("MonoBehaviour (Live2D Model)");
|
||||
}
|
||||
@@ -1247,7 +1247,7 @@ namespace AssetStudioGUI
|
||||
using (var cubismMoc = new AssetStudio.Addons.CubismLive2D.CubismMoc(m_MonoBehaviour))
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
if (Studio.l2dModelDict.TryGetValue(m_MonoBehaviour, out var model) && model != null)
|
||||
if (Studio.l2dAssetManager.ModelDict.TryGetValue(m_MonoBehaviour, out var model) && model != null)
|
||||
{
|
||||
sb.AppendLine($"Model Name: {model.Name}");
|
||||
}
|
||||
@@ -1590,7 +1590,7 @@ namespace AssetStudioGUI
|
||||
Studio.assemblyLoader.Clear();
|
||||
Studio.exportableAssets.Clear();
|
||||
Studio.visibleAssets.Clear();
|
||||
Studio.l2dModelDict.Clear();
|
||||
Studio.l2dAssetManager.Clear();
|
||||
sceneTreeView.Nodes.Clear();
|
||||
assetListView.VirtualListSize = 0;
|
||||
assetListView.Items.Clear();
|
||||
@@ -1675,7 +1675,7 @@ namespace AssetStudioGUI
|
||||
switch (asset.Asset)
|
||||
{
|
||||
case MonoBehaviour m_MonoBehaviour:
|
||||
if (Studio.l2dModelDict.Count > 0 && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
if (Studio.l2dAssetManager.ModelDict.Count > 0 && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
if (m_Script.m_ClassName == "CubismMoc")
|
||||
{
|
||||
@@ -1995,7 +1995,7 @@ namespace AssetStudioGUI
|
||||
}
|
||||
}
|
||||
visibleAssets = filterMoc
|
||||
? exportableAssets.FindAll(x => (x.Asset is MonoBehaviour monoBehaviour && l2dModelDict.ContainsKey(monoBehaviour)) || show.Contains(x.Type))
|
||||
? exportableAssets.FindAll(x => (x.Asset is MonoBehaviour monoBehaviour && Studio.l2dAssetManager.ModelDict.ContainsKey(monoBehaviour)) || show.Contains(x.Type))
|
||||
: exportableAssets.FindAll(x => show.Contains(x.Type));
|
||||
}
|
||||
else
|
||||
@@ -2322,7 +2322,7 @@ namespace AssetStudioGUI
|
||||
{
|
||||
if (exportableAssets.Count > 0)
|
||||
{
|
||||
if (Studio.l2dModelDict.Count == 0)
|
||||
if (Studio.l2dAssetManager.ModelDict.Count == 0)
|
||||
{
|
||||
Logger.Info("Live2D Cubism models were not found.");
|
||||
return;
|
||||
@@ -2362,7 +2362,7 @@ namespace AssetStudioGUI
|
||||
Logger.Info("No exportable assets loaded");
|
||||
return;
|
||||
}
|
||||
if (Studio.l2dModelDict.Count == 0)
|
||||
if (Studio.l2dAssetManager.ModelDict.Count == 0)
|
||||
{
|
||||
Logger.Info("Live2D Cubism models were not found.");
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
using AssetStudio;
|
||||
using AssetStudio.Addons.CubismLive2D;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using static CubismLive2DExtractor.CubismParsers;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
public class L2DAssetManager
|
||||
{
|
||||
public readonly Dictionary<MonoBehaviour, CubismModel> ModelDict = new Dictionary<MonoBehaviour, CubismModel>();
|
||||
public readonly Dictionary<Object, string> AssetContainers = new Dictionary<Object, string>();
|
||||
|
||||
public L2DAssetManager () { }
|
||||
|
||||
public void BindCubismAssetsByGO(GameObject m_GameObject, AssemblyLoader assemblyLoader)
|
||||
{
|
||||
if (!TryGetCubismMoc(m_GameObject.CubismModel.CubismModelMono, assemblyLoader, out var mocMono))
|
||||
return;
|
||||
|
||||
ModelDict[mocMono] = m_GameObject.CubismModel;
|
||||
BindAnimationClips(m_GameObject);
|
||||
}
|
||||
|
||||
public void BindCubismAssetsByMono(MonoBehaviour m_MonoBehaviour, string m_ClassName)
|
||||
{
|
||||
if (!m_MonoBehaviour.m_GameObject.TryGet(out var m_GameObject))
|
||||
return;
|
||||
|
||||
if (!TryGetModelGameObject(m_GameObject.m_Transform, out var modelGameObject))
|
||||
return;
|
||||
|
||||
switch (m_ClassName)
|
||||
{
|
||||
case "CubismMoc":
|
||||
if (!ModelDict.ContainsKey(m_MonoBehaviour))
|
||||
{
|
||||
ModelDict.Add(m_MonoBehaviour, null);
|
||||
}
|
||||
break;
|
||||
case "CubismRenderer":
|
||||
modelGameObject.CubismModel.RenderTextureList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismDisplayInfoParameterName":
|
||||
modelGameObject.CubismModel.ParamDisplayInfoList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismDisplayInfoPartName":
|
||||
modelGameObject.CubismModel.PartDisplayInfoList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismPosePart":
|
||||
modelGameObject.CubismModel.PosePartList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetCubismMoc(MonoBehaviour m_MonoBehaviour, AssemblyLoader assemblyLoader, out MonoBehaviour mocMono)
|
||||
{
|
||||
mocMono = null;
|
||||
var pptrDict = (OrderedDictionary)ParseMonoBehaviour(m_MonoBehaviour, CubismMonoBehaviourType.Model, assemblyLoader)?["_moc"];
|
||||
if (pptrDict == null)
|
||||
return false;
|
||||
|
||||
var mocPPtr = new PPtr<MonoBehaviour>
|
||||
{
|
||||
m_FileID = (int)pptrDict["m_FileID"],
|
||||
m_PathID = (long)pptrDict["m_PathID"],
|
||||
AssetsFile = m_MonoBehaviour.assetsFile
|
||||
};
|
||||
return mocPPtr.TryGet(out mocMono);
|
||||
}
|
||||
|
||||
private static void BindAnimationClips(GameObject gameObject)
|
||||
{
|
||||
if (gameObject.m_Animator == null || gameObject.m_Animator.m_Controller.IsNull)
|
||||
return;
|
||||
|
||||
if (!gameObject.m_Animator.m_Controller.TryGet(out var controller))
|
||||
return;
|
||||
|
||||
AnimatorController animatorController;
|
||||
if (controller is AnimatorOverrideController overrideController)
|
||||
{
|
||||
if (!overrideController.m_Controller.TryGet(out animatorController))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
animatorController = (AnimatorController)controller;
|
||||
}
|
||||
|
||||
foreach (var clipPptr in animatorController.m_AnimationClips)
|
||||
{
|
||||
if (clipPptr.TryGet(out var m_AnimationClip))
|
||||
{
|
||||
gameObject.CubismModel.ClipMotionList.Add(m_AnimationClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetModelGameObject(Transform m_Transform, out GameObject m_GameObject)
|
||||
{
|
||||
m_GameObject = null;
|
||||
if (m_Transform == null)
|
||||
return false;
|
||||
|
||||
while (m_Transform.m_Father.TryGet(out var m_Father))
|
||||
{
|
||||
m_Transform = m_Father;
|
||||
if (m_Transform.m_GameObject.TryGet(out m_GameObject) && m_GameObject.CubismModel != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ModelDict.Clear();
|
||||
AssetContainers.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
+92
-184
@@ -4,7 +4,6 @@ using CubismLive2DExtractor;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@@ -15,7 +14,6 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml.Linq;
|
||||
using static AssetStudioGUI.Exporter;
|
||||
using static CubismLive2DExtractor.CubismParsers;
|
||||
using Object = AssetStudio.Object;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
@@ -88,8 +86,7 @@ namespace AssetStudioGUI
|
||||
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
|
||||
public static List<AssetItem> exportableAssets = new List<AssetItem>();
|
||||
public static List<AssetItem> visibleAssets = new List<AssetItem>();
|
||||
public static Dictionary<MonoBehaviour, CubismModel> l2dModelDict = new Dictionary<MonoBehaviour, CubismModel>();
|
||||
private static Dictionary<Object, string> l2dAssetContainers = new Dictionary<Object, string>();
|
||||
public static L2DAssetManager l2dAssetManager = new L2DAssetManager();
|
||||
internal static Action<string> StatusStripUpdate = x => { };
|
||||
internal static Fbx.Settings FbxSettings;
|
||||
|
||||
@@ -225,7 +222,6 @@ namespace AssetStudioGUI
|
||||
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
|
||||
var containers = new List<(PPtr<Object>, string)>();
|
||||
var tex2dArrayAssetList = new List<AssetItem>();
|
||||
l2dAssetContainers.Clear();
|
||||
var i = 0;
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsManager.AssetsFileList)
|
||||
@@ -245,10 +241,9 @@ namespace AssetStudioGUI
|
||||
break;
|
||||
case GameObject m_GameObject:
|
||||
assetItem.Text = m_GameObject.m_Name;
|
||||
if (m_GameObject.CubismModel != null && TryGetCubismMoc(m_GameObject.CubismModel.CubismModelMono, out var mocMono))
|
||||
if (m_GameObject.CubismModel != null)
|
||||
{
|
||||
l2dModelDict[mocMono] = m_GameObject.CubismModel;
|
||||
BindAnimationClips(m_GameObject);
|
||||
l2dAssetManager.BindCubismAssetsByGO(m_GameObject, assemblyLoader);
|
||||
}
|
||||
break;
|
||||
case Texture2D m_Texture2D:
|
||||
@@ -304,22 +299,11 @@ namespace AssetStudioGUI
|
||||
switch (m_Script.m_ClassName)
|
||||
{
|
||||
case "CubismMoc":
|
||||
if (!l2dModelDict.ContainsKey(m_MonoBehaviour))
|
||||
{
|
||||
l2dModelDict.Add(m_MonoBehaviour, null);
|
||||
}
|
||||
break;
|
||||
case "CubismRenderer":
|
||||
BindCubismAsset(m_MonoBehaviour, CubismMonoBehaviourType.RenderTexture);
|
||||
break;
|
||||
case "CubismDisplayInfoParameterName":
|
||||
BindCubismAsset(m_MonoBehaviour, CubismMonoBehaviourType.DisplayInfo, isParamInfo: true);
|
||||
break;
|
||||
case "CubismDisplayInfoPartName":
|
||||
BindCubismAsset(m_MonoBehaviour, CubismMonoBehaviourType.DisplayInfo);
|
||||
break;
|
||||
case "CubismPosePart":
|
||||
BindCubismAsset(m_MonoBehaviour, CubismMonoBehaviourType.PosePart);
|
||||
l2dAssetManager.BindCubismAssetsByMono(m_MonoBehaviour, m_Script.m_ClassName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -389,7 +373,7 @@ namespace AssetStudioGUI
|
||||
case AnimationClip _:
|
||||
case Texture2D _:
|
||||
case MonoBehaviour _:
|
||||
l2dAssetContainers[obj] = container;
|
||||
l2dAssetManager.AssetContainers[obj] = container;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -545,13 +529,10 @@ namespace AssetStudioGUI
|
||||
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
|
||||
|
||||
var groupOption = (AssetGroupOption)Properties.Settings.Default.assetGroupOption;
|
||||
var parallelExportCount = Properties.Settings.Default.parallelExportCount <= 0
|
||||
? Environment.ProcessorCount - 1
|
||||
: Math.Min(Properties.Settings.Default.parallelExportCount, Environment.ProcessorCount - 1);
|
||||
parallelExportCount = Properties.Settings.Default.parallelExport ? parallelExportCount : 1;
|
||||
var toExportAssetDict = new ConcurrentDictionary<AssetItem, string>();
|
||||
var toParallelExportAssetDict = new ConcurrentDictionary<AssetItem, string>();
|
||||
var exceptionMsgs = new ConcurrentDictionary<Exception, string>();
|
||||
var parallelExportCount = GetParallelExportCount();
|
||||
var mode = exportType == ExportType.Dump ? "Dump" : "Export";
|
||||
var toExportCount = toExportAssets.Count;
|
||||
var exportedCount = 0;
|
||||
@@ -1025,99 +1006,13 @@ namespace AssetStudioGUI
|
||||
Process.Start(info);
|
||||
}
|
||||
|
||||
private static bool TryGetCubismMoc(MonoBehaviour m_MonoBehaviour, out MonoBehaviour mocMono)
|
||||
{
|
||||
mocMono = null;
|
||||
var pptrDict = (OrderedDictionary)CubismParsers.ParseMonoBehaviour(m_MonoBehaviour, CubismParsers.CubismMonoBehaviourType.Model, assemblyLoader)?["_moc"];
|
||||
if (pptrDict == null)
|
||||
return false;
|
||||
|
||||
var mocPPtr = new PPtr<MonoBehaviour>
|
||||
{
|
||||
m_FileID = (int)pptrDict["m_FileID"],
|
||||
m_PathID = (long)pptrDict["m_PathID"],
|
||||
AssetsFile = m_MonoBehaviour.assetsFile
|
||||
};
|
||||
return mocPPtr.TryGet(out mocMono);
|
||||
}
|
||||
|
||||
private static void BindCubismAsset(MonoBehaviour m_MonoBehaviour, CubismMonoBehaviourType type, bool isParamInfo = false)
|
||||
{
|
||||
if (!m_MonoBehaviour.m_GameObject.TryGet(out var m_GameObject))
|
||||
return;
|
||||
|
||||
if (!TryGetModelGameObject(m_GameObject.m_Transform, out var modelGameObject))
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CubismMonoBehaviourType.PosePart:
|
||||
modelGameObject.CubismModel.PosePartList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case CubismMonoBehaviourType.DisplayInfo when isParamInfo:
|
||||
modelGameObject.CubismModel.ParamDisplayInfoList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case CubismMonoBehaviourType.DisplayInfo:
|
||||
modelGameObject.CubismModel.PartDisplayInfoList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case CubismMonoBehaviourType.RenderTexture:
|
||||
modelGameObject.CubismModel.RenderTextureList.Add(m_MonoBehaviour);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindAnimationClips(GameObject gameObject)
|
||||
{
|
||||
if (gameObject.m_Animator == null || gameObject.m_Animator.m_Controller.IsNull)
|
||||
return;
|
||||
|
||||
if (!gameObject.m_Animator.m_Controller.TryGet(out var controller))
|
||||
return;
|
||||
|
||||
AnimatorController animatorController;
|
||||
if (controller is AnimatorOverrideController overrideController)
|
||||
{
|
||||
if (!overrideController.m_Controller.TryGet(out animatorController))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
animatorController = (AnimatorController)controller;
|
||||
}
|
||||
|
||||
foreach (var clipPptr in animatorController.m_AnimationClips)
|
||||
{
|
||||
if (clipPptr.TryGet(out var m_AnimationClip))
|
||||
{
|
||||
gameObject.CubismModel.ClipMotionList.Add(m_AnimationClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetModelGameObject(Transform m_Transform, out GameObject m_GameObject)
|
||||
{
|
||||
m_GameObject = null;
|
||||
if (m_Transform == null)
|
||||
return false;
|
||||
|
||||
while (m_Transform.m_Father.TryGet(out var m_Father))
|
||||
{
|
||||
m_Transform = m_Father;
|
||||
if (m_Transform.m_GameObject.TryGet(out m_GameObject) && m_GameObject.CubismModel != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Dictionary<MonoBehaviour, string> GenerateMocPathDict(Dictionary<MonoBehaviour, CubismModel> mocDict, bool searchByFilename)
|
||||
{
|
||||
var tempMocPathDict = new Dictionary<MonoBehaviour, (string, string)>();
|
||||
var mocPathDict = new Dictionary<MonoBehaviour, string>();
|
||||
foreach (var mocMono in l2dModelDict.Keys)
|
||||
foreach (var mocMono in l2dAssetManager.ModelDict.Keys)
|
||||
{
|
||||
if (l2dAssetContainers.TryGetValue(mocMono, out var fullContainerPath))
|
||||
if (l2dAssetManager.AssetContainers.TryGetValue(mocMono, out var fullContainerPath))
|
||||
{
|
||||
var pathSepIndex = fullContainerPath.LastIndexOf('/');
|
||||
var basePath = pathSepIndex > 0
|
||||
@@ -1156,6 +1051,76 @@ namespace AssetStudioGUI
|
||||
return mocPathDict;
|
||||
}
|
||||
|
||||
private static Dictionary<MonoBehaviour, List<Object>> GenerateMocAssetDict(Dictionary<MonoBehaviour, CubismModel> mocDict)
|
||||
{
|
||||
var searchByFilename = Properties.Settings.Default.l2dAssetSearchByFilename;
|
||||
var l2dContainers = searchByFilename
|
||||
? new Dictionary<Object, string>()
|
||||
: l2dAssetManager.AssetContainers;
|
||||
|
||||
var mode = searchByFilename ? "file names" : "containers";
|
||||
Logger.Info($"Searching for Live2D assets using {mode}...");
|
||||
|
||||
var mocPathDict = GenerateMocPathDict(mocDict, searchByFilename);
|
||||
if (!searchByFilename && mocPathDict.Count != mocDict.Count)
|
||||
{
|
||||
Logger.Warning("Some Live2D models cannot be exported using containers\nTry to enable search by file name in the options");
|
||||
}
|
||||
|
||||
if (searchByFilename)
|
||||
{
|
||||
foreach (var asset in exportableAssets)
|
||||
{
|
||||
switch (asset.Type)
|
||||
{
|
||||
case ClassIDType.AnimationClip:
|
||||
case ClassIDType.Texture2D:
|
||||
case ClassIDType.MonoBehaviour:
|
||||
l2dContainers[asset.Asset] = asset.Asset.assetsFile.fullName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var assetDict = new Dictionary<MonoBehaviour, List<Object>>();
|
||||
foreach (var mocKvp in mocPathDict)
|
||||
{
|
||||
var mocPath = searchByFilename
|
||||
? mocKvp.Key.assetsFile.fullName
|
||||
: mocKvp.Value;
|
||||
var result = l2dContainers.Select(assetKvp =>
|
||||
{
|
||||
if (!assetKvp.Value.Contains(mocPath))
|
||||
return null;
|
||||
var mocPathSpan = mocPath.AsSpan();
|
||||
var modelNameFromPath = mocPathSpan.Slice(mocPathSpan.LastIndexOf('/') + 1);
|
||||
#if NET9_0_OR_GREATER
|
||||
foreach (var range in assetKvp.Value.AsSpan().Split('/'))
|
||||
{
|
||||
if (modelNameFromPath.SequenceEqual(assetKvp.Value.AsSpan()[range]))
|
||||
return assetKvp.Key;
|
||||
}
|
||||
#else
|
||||
foreach (var str in assetKvp.Value.Split('/'))
|
||||
{
|
||||
if (modelNameFromPath.SequenceEqual(str.AsSpan()))
|
||||
return assetKvp.Key;
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}).Where(x => x != null).ToList();
|
||||
|
||||
if (result.Count > 0)
|
||||
{
|
||||
assetDict[mocKvp.Key] = result;
|
||||
}
|
||||
}
|
||||
if (searchByFilename)
|
||||
l2dContainers.Clear();
|
||||
|
||||
return assetDict;
|
||||
}
|
||||
|
||||
public static void ExportLive2D(string exportPath, List<MonoBehaviour> selMocs = null, List<AnimationClip> selClipMotions = null, List<MonoBehaviour> selFadeMotions = null, MonoBehaviour selFadeLst = null)
|
||||
{
|
||||
var baseDestPath = Path.Combine(exportPath, "Live2DOutput");
|
||||
@@ -1168,74 +1133,12 @@ namespace AssetStudioGUI
|
||||
else if (selFadeMotions != null || selFadeLst != null)
|
||||
motionMode = Live2DMotionMode.MonoBehaviour;
|
||||
var mocDict = selMocs != null
|
||||
? selMocs.ToDictionary(moc => moc, moc => l2dModelDict[moc])
|
||||
: l2dModelDict;
|
||||
var l2dContainers = searchByFilename
|
||||
? new Dictionary<Object, string>()
|
||||
: l2dAssetContainers;
|
||||
? selMocs.ToDictionary(moc => moc, moc => l2dAssetManager.ModelDict[moc])
|
||||
: l2dAssetManager.ModelDict;
|
||||
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
var mode = searchByFilename ? "file names" : "containers";
|
||||
Logger.Info($"Searching for Live2D assets using {mode}...");
|
||||
|
||||
var mocPathDict = GenerateMocPathDict(mocDict, searchByFilename);
|
||||
if (!searchByFilename && mocPathDict.Count != l2dModelDict.Count)
|
||||
{
|
||||
Logger.Warning("Some Live2D models cannot be exported using containers\nTry to enable search by file name in the options");
|
||||
}
|
||||
|
||||
if (searchByFilename)
|
||||
{
|
||||
foreach (var asset in exportableAssets)
|
||||
{
|
||||
switch (asset.Type)
|
||||
{
|
||||
case ClassIDType.AnimationClip:
|
||||
case ClassIDType.Texture2D:
|
||||
case ClassIDType.MonoBehaviour:
|
||||
l2dContainers[asset.Asset] = asset.Asset.assetsFile.fullName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var assetDict = new Dictionary<MonoBehaviour, List<Object>>();
|
||||
foreach (var mocKvp in mocPathDict)
|
||||
{
|
||||
var mocPath = searchByFilename
|
||||
? mocKvp.Key.assetsFile.fullName
|
||||
: mocKvp.Value;
|
||||
var result = l2dContainers.Select(assetKvp =>
|
||||
{
|
||||
if (!assetKvp.Value.Contains(mocPath))
|
||||
return null;
|
||||
var mocPathSpan = mocPath.AsSpan();
|
||||
var modelNameFromPath = mocPathSpan.Slice(mocPathSpan.LastIndexOf('/') + 1);
|
||||
#if NET9_0_OR_GREATER
|
||||
foreach (var range in assetKvp.Value.AsSpan().Split('/'))
|
||||
{
|
||||
if (modelNameFromPath.SequenceEqual(assetKvp.Value.AsSpan()[range]))
|
||||
return assetKvp.Key;
|
||||
}
|
||||
#else
|
||||
foreach (var str in assetKvp.Value.Split('/'))
|
||||
{
|
||||
if (modelNameFromPath.SequenceEqual(str.AsSpan()))
|
||||
return assetKvp.Key;
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}).Where(x => x != null).ToList();
|
||||
|
||||
if (result.Count > 0)
|
||||
{
|
||||
assetDict[mocKvp.Key] = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchByFilename)
|
||||
l2dContainers.Clear();
|
||||
var assetDict = GenerateMocAssetDict(mocDict);
|
||||
if (mocDict.Keys.First().serializedType?.m_Type == null && !assemblyLoader.Loaded)
|
||||
{
|
||||
Logger.Warning("Specifying the assembly folder may be needed for proper extraction");
|
||||
@@ -1243,15 +1146,11 @@ namespace AssetStudioGUI
|
||||
}
|
||||
var totalModelCount = assetDict.Count;
|
||||
var modelCounter = 0;
|
||||
var parallelExportCount = Properties.Settings.Default.parallelExportCount <= 0
|
||||
? Environment.ProcessorCount - 1
|
||||
: Math.Min(Properties.Settings.Default.parallelExportCount, Environment.ProcessorCount - 1);
|
||||
parallelExportCount = Properties.Settings.Default.parallelExport ? parallelExportCount : 1;
|
||||
Live2DExtractor.MocDict = mocDict;
|
||||
Live2DExtractor.Assembly = assemblyLoader;
|
||||
foreach (var assetGroupKvp in assetDict)
|
||||
{
|
||||
var srcContainer = l2dAssetContainers.TryGetValue(assetGroupKvp.Key, out var result)
|
||||
var srcContainer = l2dAssetManager.AssetContainers.TryGetValue(assetGroupKvp.Key, out var result)
|
||||
? result
|
||||
: assetGroupKvp.Key.assetsFile.fullName;
|
||||
|
||||
@@ -1289,7 +1188,7 @@ namespace AssetStudioGUI
|
||||
break;
|
||||
}
|
||||
var destPath = Path.Combine(baseDestPath, modelPath);
|
||||
cubismExtractor.ExtractCubismModel(destPath, motionMode, forceBezier, parallelExportCount);
|
||||
cubismExtractor.ExtractCubismModel(destPath, motionMode, forceBezier, GetParallelExportCount());
|
||||
modelCounter++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -1308,5 +1207,14 @@ namespace AssetStudioGUI
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static int GetParallelExportCount()
|
||||
{
|
||||
var parallelExportCount = Properties.Settings.Default.parallelExportCount <= 0
|
||||
? Environment.ProcessorCount - 1
|
||||
: Math.Min(Properties.Settings.Default.parallelExportCount, Environment.ProcessorCount - 1);
|
||||
|
||||
return Properties.Settings.Default.parallelExport ? parallelExportCount : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user