mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-07-16 19:14:15 -04:00
Improve integration with Live2D assets
This commit is contained in:
@ -293,7 +293,7 @@ namespace AssetStudioGUI
|
||||
|
||||
var types = new SortedSet<string>();
|
||||
types.UnionWith(exportableAssets.Select(x => x.TypeString));
|
||||
if (Studio.cubismMocList.Count > 0)
|
||||
if (Studio.l2dModelDict.Count > 0)
|
||||
{
|
||||
types.Add("MonoBehaviour (Live2D Model)");
|
||||
}
|
||||
@ -1181,19 +1181,19 @@ namespace AssetStudioGUI
|
||||
|
||||
private void PreviewMoc(AssetItem assetItem, MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
using (var cubismModel = new CubismModel(m_MonoBehaviour))
|
||||
using (var cubismMoc = new CubismMoc(m_MonoBehaviour))
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"SDK Version: {cubismModel.VersionDescription}");
|
||||
if (cubismModel.Version > 0)
|
||||
sb.AppendLine($"SDK Version: {cubismMoc.VersionDescription}");
|
||||
if (cubismMoc.Version > 0)
|
||||
{
|
||||
sb.AppendLine($"Canvas Width: {cubismModel.CanvasWidth}");
|
||||
sb.AppendLine($"Canvas Height: {cubismModel.CanvasHeight}");
|
||||
sb.AppendLine($"Center X: {cubismModel.CentralPosX}");
|
||||
sb.AppendLine($"Center Y: {cubismModel.CentralPosY}");
|
||||
sb.AppendLine($"Pixel Per Unit: {cubismModel.PixelPerUnit}");
|
||||
sb.AppendLine($"Parameter Count: {cubismModel.ParamCount}");
|
||||
sb.AppendLine($"Part Count: {cubismModel.PartCount}");
|
||||
sb.AppendLine($"Canvas Width: {cubismMoc.CanvasWidth}");
|
||||
sb.AppendLine($"Canvas Height: {cubismMoc.CanvasHeight}");
|
||||
sb.AppendLine($"Center X: {cubismMoc.CentralPosX}");
|
||||
sb.AppendLine($"Center Y: {cubismMoc.CentralPosY}");
|
||||
sb.AppendLine($"Pixel Per Unit: {cubismMoc.PixelPerUnit}");
|
||||
sb.AppendLine($"Parameter Count: {cubismMoc.ParamCount}");
|
||||
sb.AppendLine($"Part Count: {cubismMoc.PartCount}");
|
||||
}
|
||||
assetItem.InfoText = sb.ToString();
|
||||
}
|
||||
@ -1484,6 +1484,7 @@ namespace AssetStudioGUI
|
||||
assemblyLoader.Clear();
|
||||
exportableAssets.Clear();
|
||||
visibleAssets.Clear();
|
||||
l2dModelDict.Clear();
|
||||
sceneTreeView.Nodes.Clear();
|
||||
assetListView.VirtualListSize = 0;
|
||||
assetListView.Items.Clear();
|
||||
@ -1491,7 +1492,6 @@ namespace AssetStudioGUI
|
||||
classesListView.Groups.Clear();
|
||||
selectedAnimationAssetsList.Clear();
|
||||
selectedIndicesPrevList.Clear();
|
||||
cubismMocList.Clear();
|
||||
previewPanel.Image = Properties.Resources.preview;
|
||||
previewPanel.SizeMode = PictureBoxSizeMode.CenterImage;
|
||||
imageTexture?.Dispose();
|
||||
@ -1556,7 +1556,7 @@ namespace AssetStudioGUI
|
||||
switch (asset.Asset)
|
||||
{
|
||||
case MonoBehaviour m_MonoBehaviour:
|
||||
if (Studio.cubismMocList.Count > 0 && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
if (Studio.l2dModelDict.Count > 0 && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
if (m_Script.m_ClassName == "CubismMoc")
|
||||
{
|
||||
@ -1892,7 +1892,7 @@ namespace AssetStudioGUI
|
||||
}
|
||||
}
|
||||
visibleAssets = filterMoc
|
||||
? exportableAssets.FindAll(x => cubismMocList.Contains(x.Asset) || show.Contains(x.Type))
|
||||
? exportableAssets.FindAll(x => (x.Asset is MonoBehaviour monoBehaviour && l2dModelDict.ContainsKey(monoBehaviour)) || show.Contains(x.Type))
|
||||
: exportableAssets.FindAll(x => show.Contains(x.Type));
|
||||
}
|
||||
else
|
||||
@ -2217,7 +2217,7 @@ namespace AssetStudioGUI
|
||||
{
|
||||
if (exportableAssets.Count > 0)
|
||||
{
|
||||
if (Studio.cubismMocList.Count == 0)
|
||||
if (Studio.l2dModelDict.Count == 0)
|
||||
{
|
||||
Logger.Info("Live2D Cubism models were not found.");
|
||||
return;
|
||||
@ -2257,7 +2257,7 @@ namespace AssetStudioGUI
|
||||
Logger.Info("No exportable assets loaded");
|
||||
return;
|
||||
}
|
||||
if (Studio.cubismMocList.Count == 0)
|
||||
if (Studio.l2dModelDict.Count == 0)
|
||||
{
|
||||
Logger.Info("Live2D Cubism models were not found.");
|
||||
return;
|
||||
|
67
AssetStudioGUI/ExportOptions.Designer.cs
generated
67
AssetStudioGUI/ExportOptions.Designer.cs
generated
@ -51,6 +51,9 @@
|
||||
this.tobmp = new System.Windows.Forms.RadioButton();
|
||||
this.converttexture = new System.Windows.Forms.CheckBox();
|
||||
this.l2dGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.l2dAssetSearchByFilenameCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.l2dModelGroupComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.l2dModelGroupLabel = new System.Windows.Forms.Label();
|
||||
this.l2dMotionExportMethodPanel = new System.Windows.Forms.Panel();
|
||||
this.l2dMonoBehaviourRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.l2dAnimationClipRadioButton = new System.Windows.Forms.RadioButton();
|
||||
@ -89,7 +92,7 @@
|
||||
// OKbutton
|
||||
//
|
||||
this.OKbutton.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.OKbutton.Location = new System.Drawing.Point(396, 380);
|
||||
this.OKbutton.Location = new System.Drawing.Point(396, 430);
|
||||
this.OKbutton.Name = "OKbutton";
|
||||
this.OKbutton.Size = new System.Drawing.Size(75, 23);
|
||||
this.OKbutton.TabIndex = 4;
|
||||
@ -101,7 +104,7 @@
|
||||
//
|
||||
this.Cancel.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.Cancel.Location = new System.Drawing.Point(477, 380);
|
||||
this.Cancel.Location = new System.Drawing.Point(477, 430);
|
||||
this.Cancel.Name = "Cancel";
|
||||
this.Cancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.Cancel.TabIndex = 5;
|
||||
@ -193,8 +196,8 @@
|
||||
this.filenameFormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.filenameFormatComboBox.FormattingEnabled = true;
|
||||
this.filenameFormatComboBox.Items.AddRange(new object[] {
|
||||
"assetName",
|
||||
"assetName@pathID",
|
||||
"asset name",
|
||||
"asset name@pathID",
|
||||
"pathID"});
|
||||
this.filenameFormatComboBox.Location = new System.Drawing.Point(177, 35);
|
||||
this.filenameFormatComboBox.Name = "filenameFormatComboBox";
|
||||
@ -353,24 +356,59 @@
|
||||
//
|
||||
// l2dGroupBox
|
||||
//
|
||||
this.l2dGroupBox.Controls.Add(this.l2dAssetSearchByFilenameCheckBox);
|
||||
this.l2dGroupBox.Controls.Add(this.l2dModelGroupComboBox);
|
||||
this.l2dGroupBox.Controls.Add(this.l2dModelGroupLabel);
|
||||
this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodPanel);
|
||||
this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodLabel);
|
||||
this.l2dGroupBox.Controls.Add(this.l2dForceBezierCheckBox);
|
||||
this.l2dGroupBox.Location = new System.Drawing.Point(12, 275);
|
||||
this.l2dGroupBox.Name = "l2dGroupBox";
|
||||
this.l2dGroupBox.Size = new System.Drawing.Size(316, 100);
|
||||
this.l2dGroupBox.Size = new System.Drawing.Size(316, 149);
|
||||
this.l2dGroupBox.TabIndex = 2;
|
||||
this.l2dGroupBox.TabStop = false;
|
||||
this.l2dGroupBox.Text = "Cubism Live2D";
|
||||
//
|
||||
// l2dAssetSearchByFilenameCheckBox
|
||||
//
|
||||
this.l2dAssetSearchByFilenameCheckBox.AutoSize = true;
|
||||
this.l2dAssetSearchByFilenameCheckBox.Location = new System.Drawing.Point(6, 45);
|
||||
this.l2dAssetSearchByFilenameCheckBox.Name = "l2dAssetSearchByFilenameCheckBox";
|
||||
this.l2dAssetSearchByFilenameCheckBox.Size = new System.Drawing.Size(270, 17);
|
||||
this.l2dAssetSearchByFilenameCheckBox.TabIndex = 3;
|
||||
this.l2dAssetSearchByFilenameCheckBox.Text = "Search for model-related Live2D assets by file name";
|
||||
this.optionTooltip.SetToolTip(this.l2dAssetSearchByFilenameCheckBox, "Preferred option when all model-related assets are stored in a single file");
|
||||
this.l2dAssetSearchByFilenameCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// l2dModelGroupComboBox
|
||||
//
|
||||
this.l2dModelGroupComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.l2dModelGroupComboBox.FormattingEnabled = true;
|
||||
this.l2dModelGroupComboBox.Items.AddRange(new object[] {
|
||||
"container path",
|
||||
"source file name"});
|
||||
this.l2dModelGroupComboBox.Location = new System.Drawing.Point(142, 18);
|
||||
this.l2dModelGroupComboBox.Name = "l2dModelGroupComboBox";
|
||||
this.l2dModelGroupComboBox.Size = new System.Drawing.Size(154, 21);
|
||||
this.l2dModelGroupComboBox.TabIndex = 2;
|
||||
//
|
||||
// l2dModelGroupLabel
|
||||
//
|
||||
this.l2dModelGroupLabel.AutoSize = true;
|
||||
this.l2dModelGroupLabel.Location = new System.Drawing.Point(6, 21);
|
||||
this.l2dModelGroupLabel.Name = "l2dModelGroupLabel";
|
||||
this.l2dModelGroupLabel.Size = new System.Drawing.Size(130, 13);
|
||||
this.l2dModelGroupLabel.TabIndex = 1;
|
||||
this.l2dModelGroupLabel.Text = "Group exported models by";
|
||||
//
|
||||
// l2dMotionExportMethodPanel
|
||||
//
|
||||
this.l2dMotionExportMethodPanel.Controls.Add(this.l2dMonoBehaviourRadioButton);
|
||||
this.l2dMotionExportMethodPanel.Controls.Add(this.l2dAnimationClipRadioButton);
|
||||
this.l2dMotionExportMethodPanel.Location = new System.Drawing.Point(18, 40);
|
||||
this.l2dMotionExportMethodPanel.Location = new System.Drawing.Point(18, 89);
|
||||
this.l2dMotionExportMethodPanel.Name = "l2dMotionExportMethodPanel";
|
||||
this.l2dMotionExportMethodPanel.Size = new System.Drawing.Size(279, 27);
|
||||
this.l2dMotionExportMethodPanel.TabIndex = 2;
|
||||
this.l2dMotionExportMethodPanel.TabIndex = 5;
|
||||
//
|
||||
// l2dMonoBehaviourRadioButton
|
||||
//
|
||||
@ -400,19 +438,19 @@
|
||||
// l2dMotionExportMethodLabel
|
||||
//
|
||||
this.l2dMotionExportMethodLabel.AutoSize = true;
|
||||
this.l2dMotionExportMethodLabel.Location = new System.Drawing.Point(6, 21);
|
||||
this.l2dMotionExportMethodLabel.Location = new System.Drawing.Point(6, 70);
|
||||
this.l2dMotionExportMethodLabel.Name = "l2dMotionExportMethodLabel";
|
||||
this.l2dMotionExportMethodLabel.Size = new System.Drawing.Size(109, 13);
|
||||
this.l2dMotionExportMethodLabel.TabIndex = 1;
|
||||
this.l2dMotionExportMethodLabel.TabIndex = 4;
|
||||
this.l2dMotionExportMethodLabel.Text = "Motion export method";
|
||||
//
|
||||
// l2dForceBezierCheckBox
|
||||
//
|
||||
this.l2dForceBezierCheckBox.AutoSize = true;
|
||||
this.l2dForceBezierCheckBox.Location = new System.Drawing.Point(6, 77);
|
||||
this.l2dForceBezierCheckBox.Location = new System.Drawing.Point(6, 122);
|
||||
this.l2dForceBezierCheckBox.Name = "l2dForceBezierCheckBox";
|
||||
this.l2dForceBezierCheckBox.Size = new System.Drawing.Size(278, 17);
|
||||
this.l2dForceBezierCheckBox.TabIndex = 3;
|
||||
this.l2dForceBezierCheckBox.TabIndex = 6;
|
||||
this.l2dForceBezierCheckBox.Text = "Calculate Linear motion segments as Bezier segments";
|
||||
this.optionTooltip.SetToolTip(this.l2dForceBezierCheckBox, "May help if the exported motions look jerky/not smooth enough");
|
||||
this.l2dForceBezierCheckBox.UseVisualStyleBackColor = true;
|
||||
@ -439,7 +477,7 @@
|
||||
this.groupBox2.Controls.Add(this.eulerFilter);
|
||||
this.groupBox2.Location = new System.Drawing.Point(328, 13);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(224, 362);
|
||||
this.groupBox2.Size = new System.Drawing.Size(224, 411);
|
||||
this.groupBox2.TabIndex = 3;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Fbx";
|
||||
@ -655,7 +693,7 @@
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.Cancel;
|
||||
this.ClientSize = new System.Drawing.Size(564, 416);
|
||||
this.ClientSize = new System.Drawing.Size(564, 461);
|
||||
this.Controls.Add(this.l2dGroupBox);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
@ -735,5 +773,8 @@
|
||||
private System.Windows.Forms.NumericUpDown parallelExportUpDown;
|
||||
private System.Windows.Forms.CheckBox parallelExportCheckBox;
|
||||
private System.Windows.Forms.Label parallelExportMaxLabel;
|
||||
private System.Windows.Forms.Label l2dModelGroupLabel;
|
||||
private System.Windows.Forms.ComboBox l2dModelGroupComboBox;
|
||||
private System.Windows.Forms.CheckBox l2dAssetSearchByFilenameCheckBox;
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ namespace AssetStudioGUI
|
||||
{
|
||||
InitializeComponent();
|
||||
assetGroupOptions.SelectedIndex = Properties.Settings.Default.assetGroupOption;
|
||||
filenameFormatComboBox.SelectedIndex = Properties.Settings.Default.filenameFormat;
|
||||
restoreExtensionName.Checked = Properties.Settings.Default.restoreExtensionName;
|
||||
converttexture.Checked = Properties.Settings.Default.convertTexture;
|
||||
exportSpriteWithAlphaMask.Checked = Properties.Settings.Default.exportSpriteWithMask;
|
||||
@ -18,6 +19,12 @@ namespace AssetStudioGUI
|
||||
var defaultImageType = Properties.Settings.Default.convertType.ToString();
|
||||
((RadioButton)panel1.Controls.Cast<Control>().First(x => x.Text == defaultImageType)).Checked = true;
|
||||
openAfterExport.Checked = Properties.Settings.Default.openAfterExport;
|
||||
var maxParallelTasks = Environment.ProcessorCount;
|
||||
var taskCount = Properties.Settings.Default.parallelExportCount;
|
||||
parallelExportUpDown.Maximum = maxParallelTasks;
|
||||
parallelExportUpDown.Value = taskCount <= 0 ? maxParallelTasks : Math.Min(taskCount, maxParallelTasks);
|
||||
parallelExportMaxLabel.Text += maxParallelTasks;
|
||||
parallelExportCheckBox.Checked = Properties.Settings.Default.parallelExport;
|
||||
eulerFilter.Checked = Properties.Settings.Default.eulerFilter;
|
||||
filterPrecision.Value = Properties.Settings.Default.filterPrecision;
|
||||
exportAllNodes.Checked = Properties.Settings.Default.exportAllNodes;
|
||||
@ -30,21 +37,17 @@ namespace AssetStudioGUI
|
||||
scaleFactor.Value = Properties.Settings.Default.scaleFactor;
|
||||
fbxVersion.SelectedIndex = Properties.Settings.Default.fbxVersion;
|
||||
fbxFormat.SelectedIndex = Properties.Settings.Default.fbxFormat;
|
||||
l2dModelGroupComboBox.SelectedIndex = (int)Properties.Settings.Default.l2dModelGroupOption;
|
||||
l2dAssetSearchByFilenameCheckBox.Checked = Properties.Settings.Default.l2dAssetSearchByFilename;
|
||||
var defaultMotionMode = Properties.Settings.Default.l2dMotionMode.ToString();
|
||||
((RadioButton)l2dMotionExportMethodPanel.Controls.Cast<Control>().First(x => x.AccessibleName == defaultMotionMode)).Checked = true;
|
||||
l2dForceBezierCheckBox.Checked = Properties.Settings.Default.l2dForceBezier;
|
||||
filenameFormatComboBox.SelectedIndex = Properties.Settings.Default.filenameFormat;
|
||||
var maxParallelTasks = Environment.ProcessorCount;
|
||||
var taskCount = Properties.Settings.Default.parallelExportCount;
|
||||
parallelExportUpDown.Maximum = maxParallelTasks;
|
||||
parallelExportUpDown.Value = taskCount <= 0 ? maxParallelTasks : Math.Min(taskCount, maxParallelTasks);
|
||||
parallelExportMaxLabel.Text += maxParallelTasks;
|
||||
parallelExportCheckBox.Checked = Properties.Settings.Default.parallelExport;
|
||||
}
|
||||
|
||||
private void OKbutton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.assetGroupOption = assetGroupOptions.SelectedIndex;
|
||||
Properties.Settings.Default.filenameFormat = filenameFormatComboBox.SelectedIndex;
|
||||
Properties.Settings.Default.restoreExtensionName = restoreExtensionName.Checked;
|
||||
Properties.Settings.Default.convertTexture = converttexture.Checked;
|
||||
Properties.Settings.Default.exportSpriteWithMask = exportSpriteWithAlphaMask.Checked;
|
||||
@ -52,6 +55,8 @@ namespace AssetStudioGUI
|
||||
var checkedImageType = (RadioButton)panel1.Controls.Cast<Control>().First(x => ((RadioButton)x).Checked);
|
||||
Properties.Settings.Default.convertType = (ImageFormat)Enum.Parse(typeof(ImageFormat), checkedImageType.Text);
|
||||
Properties.Settings.Default.openAfterExport = openAfterExport.Checked;
|
||||
Properties.Settings.Default.parallelExport = parallelExportCheckBox.Checked;
|
||||
Properties.Settings.Default.parallelExportCount = (int)parallelExportUpDown.Value;
|
||||
Properties.Settings.Default.eulerFilter = eulerFilter.Checked;
|
||||
Properties.Settings.Default.filterPrecision = filterPrecision.Value;
|
||||
Properties.Settings.Default.exportAllNodes = exportAllNodes.Checked;
|
||||
@ -64,12 +69,11 @@ namespace AssetStudioGUI
|
||||
Properties.Settings.Default.scaleFactor = scaleFactor.Value;
|
||||
Properties.Settings.Default.fbxVersion = fbxVersion.SelectedIndex;
|
||||
Properties.Settings.Default.fbxFormat = fbxFormat.SelectedIndex;
|
||||
Properties.Settings.Default.l2dModelGroupOption = (CubismLive2DExtractor.Live2DModelGroupOption)l2dModelGroupComboBox.SelectedIndex;
|
||||
Properties.Settings.Default.l2dAssetSearchByFilename = l2dAssetSearchByFilenameCheckBox.Checked;
|
||||
var checkedMotionMode = (RadioButton)l2dMotionExportMethodPanel.Controls.Cast<Control>().First(x => ((RadioButton)x).Checked);
|
||||
Properties.Settings.Default.l2dMotionMode = (CubismLive2DExtractor.Live2DMotionMode)Enum.Parse(typeof(CubismLive2DExtractor.Live2DMotionMode), checkedMotionMode.AccessibleName);
|
||||
Properties.Settings.Default.l2dForceBezier = l2dForceBezierCheckBox.Checked;
|
||||
Properties.Settings.Default.filenameFormat = filenameFormatComboBox.SelectedIndex;
|
||||
Properties.Settings.Default.parallelExport = parallelExportCheckBox.Checked;
|
||||
Properties.Settings.Default.parallelExportCount = (int)parallelExportUpDown.Value;
|
||||
Properties.Settings.Default.Save();
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
|
@ -120,7 +120,4 @@
|
||||
<metadata name="optionTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="optionTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
24
AssetStudioGUI/Properties/Settings.Designer.cs
generated
24
AssetStudioGUI/Properties/Settings.Designer.cs
generated
@ -406,5 +406,29 @@ namespace AssetStudioGUI.Properties {
|
||||
this["guiColorTheme"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("ContainerPath")]
|
||||
public global::CubismLive2DExtractor.Live2DModelGroupOption l2dModelGroupOption {
|
||||
get {
|
||||
return ((global::CubismLive2DExtractor.Live2DModelGroupOption)(this["l2dModelGroupOption"]));
|
||||
}
|
||||
set {
|
||||
this["l2dModelGroupOption"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool l2dAssetSearchByFilename {
|
||||
get {
|
||||
return ((bool)(this["l2dAssetSearchByFilename"]));
|
||||
}
|
||||
set {
|
||||
this["l2dAssetSearchByFilename"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,5 +98,11 @@
|
||||
<Setting Name="guiColorTheme" Type="AssetStudioGUI.GuiColorTheme" Scope="User">
|
||||
<Value Profile="(Default)">Light</Value>
|
||||
</Setting>
|
||||
<Setting Name="l2dModelGroupOption" Type="CubismLive2DExtractor.Live2DModelGroupOption" Scope="User">
|
||||
<Value Profile="(Default)">ContainerPath</Value>
|
||||
</Setting>
|
||||
<Setting Name="l2dAssetSearchByFilename" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
@ -3,6 +3,7 @@ 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;
|
||||
@ -84,8 +85,8 @@ 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 List<MonoBehaviour> cubismMocList = new List<MonoBehaviour>();
|
||||
private static Dictionary<Object, string> l2dResourceContainers = new Dictionary<Object, string>();
|
||||
public static Dictionary<MonoBehaviour, CubismModel> l2dModelDict = new Dictionary<MonoBehaviour, CubismModel>();
|
||||
private static Dictionary<Object, string> l2dAssetContainers = new Dictionary<Object, string>();
|
||||
internal static Action<string> StatusStripUpdate = x => { };
|
||||
|
||||
public static int ExtractFolder(string path, string savePath)
|
||||
@ -189,7 +190,8 @@ namespace AssetStudioGUI
|
||||
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
|
||||
var containers = new List<(PPtr<Object>, string)>();
|
||||
var tex2dArrayAssetList = new List<AssetItem>();
|
||||
l2dResourceContainers.Clear();
|
||||
var l2dSearchByFilename = Properties.Settings.Default.l2dAssetSearchByFilename;
|
||||
l2dAssetContainers.Clear();
|
||||
var i = 0;
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||
@ -209,6 +211,14 @@ 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))
|
||||
{
|
||||
l2dModelDict[mocMono] = m_GameObject.CubismModel;
|
||||
if (!m_GameObject.CubismModel.IsRoot)
|
||||
{
|
||||
FixCubismModelName(m_GameObject);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Texture2D m_Texture2D:
|
||||
if (!string.IsNullOrEmpty(m_Texture2D.m_StreamData?.path))
|
||||
@ -260,9 +270,26 @@ namespace AssetStudioGUI
|
||||
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
assetName = assetName == "" ? m_Script.m_ClassName : assetName;
|
||||
if (m_Script.m_ClassName == "CubismMoc")
|
||||
switch (m_Script.m_ClassName)
|
||||
{
|
||||
cubismMocList.Add(m_MonoBehaviour);
|
||||
case "CubismMoc":
|
||||
if (!l2dModelDict.ContainsKey(m_MonoBehaviour))
|
||||
{
|
||||
l2dModelDict.Add(m_MonoBehaviour, null);
|
||||
}
|
||||
break;
|
||||
case "CubismRenderer":
|
||||
BindCubismRenderer(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismDisplayInfoParameterName":
|
||||
BindParamDisplayInfo(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismDisplayInfoPartName":
|
||||
BindPartDisplayInfo(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismPosePart":
|
||||
BindCubismPosePart(m_MonoBehaviour);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assetItem.Text = assetName;
|
||||
@ -319,11 +346,18 @@ namespace AssetStudioGUI
|
||||
objectAssetItemDic[obj].Container = container;
|
||||
switch (obj)
|
||||
{
|
||||
case GameObject m_GameObject:
|
||||
if (m_GameObject.CubismModel != null)
|
||||
{
|
||||
m_GameObject.CubismModel.Container = container;
|
||||
}
|
||||
break;
|
||||
case AnimationClip _:
|
||||
case GameObject _:
|
||||
case Texture2D _:
|
||||
case MonoBehaviour _:
|
||||
l2dResourceContainers[obj] = container;
|
||||
l2dAssetContainers[obj] = l2dSearchByFilename
|
||||
? Path.GetFileName(obj.assetsFile.originalPath)
|
||||
: container;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -943,105 +977,239 @@ 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 FixCubismModelName(GameObject m_GameObject)
|
||||
{
|
||||
var rootTransform = GetRootTransform(m_GameObject.m_Transform);
|
||||
if (rootTransform.m_GameObject.TryGet(out var rootGameObject))
|
||||
{
|
||||
m_GameObject.CubismModel.Name = rootGameObject.m_Name;
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindCubismRenderer(MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
if (!m_MonoBehaviour.m_GameObject.TryGet(out var m_GameObject))
|
||||
return;
|
||||
|
||||
var rootTransform = GetRootTransform(m_GameObject.m_Transform);
|
||||
if (rootTransform.m_GameObject.TryGet(out var rootGameObject) && rootGameObject.CubismModel != null)
|
||||
{
|
||||
rootGameObject.CubismModel.RenderTextureList.Add(m_MonoBehaviour);
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindParamDisplayInfo(MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
if (!m_MonoBehaviour.m_GameObject.TryGet(out var m_GameObject))
|
||||
return;
|
||||
|
||||
var rootTransform = GetRootTransform(m_GameObject.m_Transform);
|
||||
if (rootTransform.m_GameObject.TryGet(out var rootGameObject) && rootGameObject.CubismModel != null)
|
||||
{
|
||||
rootGameObject.CubismModel.ParamDisplayInfoList.Add(m_MonoBehaviour);
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindPartDisplayInfo(MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
if (!m_MonoBehaviour.m_GameObject.TryGet(out var m_GameObject))
|
||||
return;
|
||||
|
||||
var rootTransform = GetRootTransform(m_GameObject.m_Transform);
|
||||
if (rootTransform.m_GameObject.TryGet(out var rootGameObject) && rootGameObject.CubismModel != null)
|
||||
{
|
||||
rootGameObject.CubismModel.PartDisplayInfoList.Add(m_MonoBehaviour);
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindCubismPosePart(MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
if (!m_MonoBehaviour.m_GameObject.TryGet(out var m_GameObject))
|
||||
return;
|
||||
|
||||
var rootTransform = GetRootTransform(m_GameObject.m_Transform);
|
||||
if (rootTransform.m_GameObject.TryGet(out var rootGameObject) && rootGameObject.CubismModel != null)
|
||||
{
|
||||
rootGameObject.CubismModel.PosePartList.Add(m_MonoBehaviour);
|
||||
}
|
||||
}
|
||||
|
||||
private static Transform GetRootTransform(Transform m_Transform)
|
||||
{
|
||||
if (m_Transform == null)
|
||||
return null;
|
||||
|
||||
while (m_Transform.m_Father.TryGet(out var m_Father))
|
||||
{
|
||||
m_Transform = m_Father;
|
||||
}
|
||||
return m_Transform;
|
||||
}
|
||||
|
||||
private static List<string> GenerateMocPathList(Dictionary<MonoBehaviour, CubismModel> mocDict, bool searchByFilename, ref bool useFullContainerPath)
|
||||
{
|
||||
var mocPathDict = new Dictionary<MonoBehaviour, (string, string)>();
|
||||
var mocPathList = new List<string>();
|
||||
foreach (var mocMono in l2dModelDict.Keys)
|
||||
{
|
||||
if (!l2dAssetContainers.TryGetValue(mocMono, out var containerPath))
|
||||
continue;
|
||||
var fullContainerPath = searchByFilename
|
||||
? l2dModelDict[mocMono]?.Container ?? containerPath
|
||||
: containerPath;
|
||||
var pathSepIndex = fullContainerPath.LastIndexOf('/');
|
||||
var basePath = pathSepIndex > 0
|
||||
? fullContainerPath.Substring(0, pathSepIndex)
|
||||
: fullContainerPath;
|
||||
mocPathDict.Add(mocMono, (fullContainerPath, basePath));
|
||||
}
|
||||
|
||||
if (mocPathDict.Count > 0)
|
||||
{
|
||||
var basePathSet = mocPathDict.Values.Select(x => x.Item2).ToHashSet();
|
||||
useFullContainerPath = mocPathDict.Count != basePathSet.Count;
|
||||
foreach (var moc in mocDict.Keys)
|
||||
{
|
||||
var mocPath = useFullContainerPath
|
||||
? mocPathDict[moc].Item1 //fullContainerPath
|
||||
: mocPathDict[moc].Item2; //basePath
|
||||
if (searchByFilename)
|
||||
{
|
||||
mocPathList.Add(l2dAssetContainers[moc]);
|
||||
if (mocDict.TryGetValue(moc, out var model) && model != null)
|
||||
model.Container = mocPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
mocPathList.Add(mocPath);
|
||||
}
|
||||
}
|
||||
mocPathDict.Clear();
|
||||
}
|
||||
return mocPathList;
|
||||
}
|
||||
|
||||
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");
|
||||
var forceBezier = Properties.Settings.Default.l2dForceBezier;
|
||||
var mocList = selMocs ?? cubismMocList;
|
||||
var modelGroupOption = Properties.Settings.Default.l2dModelGroupOption;
|
||||
var searchByFilename = Properties.Settings.Default.l2dAssetSearchByFilename;
|
||||
var motionMode = Properties.Settings.Default.l2dMotionMode;
|
||||
if (selClipMotions != null)
|
||||
motionMode = Live2DMotionMode.AnimationClipV2;
|
||||
else if (selFadeMotions != null || selFadeLst != null)
|
||||
motionMode = Live2DMotionMode.MonoBehaviour;
|
||||
var mocDict = selMocs != null
|
||||
? selMocs.ToDictionary(moc => moc, moc => l2dModelDict[moc])
|
||||
: l2dModelDict;
|
||||
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
Logger.Info($"Searching for Live2D files...");
|
||||
Logger.Info("Searching for Live2D assets...");
|
||||
|
||||
var mocPathDict = new Dictionary<MonoBehaviour, (string, string)>();
|
||||
var mocPathList = new List<string>();
|
||||
foreach (var mocMonoBehaviour in cubismMocList)
|
||||
var useFullContainerPath = true;
|
||||
var mocPathList = GenerateMocPathList(mocDict, searchByFilename, ref useFullContainerPath);
|
||||
|
||||
#if NET9_0_OR_GREATER
|
||||
var assetDict = new Dictionary<string, List<Object>>();
|
||||
foreach (var (asset, container) in l2dAssetContainers)
|
||||
{
|
||||
if (!l2dResourceContainers.TryGetValue(mocMonoBehaviour, out var fullContainerPath))
|
||||
continue;
|
||||
|
||||
var pathSepIndex = fullContainerPath.LastIndexOf('/');
|
||||
var basePath = pathSepIndex > 0
|
||||
? fullContainerPath.Substring(0, pathSepIndex)
|
||||
: fullContainerPath;
|
||||
mocPathDict.Add(mocMonoBehaviour, (fullContainerPath, basePath));
|
||||
var result = mocPathList.Find(mocPath =>
|
||||
{
|
||||
if (!container.Contains(mocPath))
|
||||
return false;
|
||||
var mocPathSpan = mocPath.AsSpan();
|
||||
var mocPathLastSlice = mocPathSpan[(mocPathSpan.LastIndexOf('/') + 1)..];
|
||||
foreach (var range in container.AsSpan().Split('/'))
|
||||
{
|
||||
if (mocPathLastSlice.SequenceEqual(container.AsSpan()[range]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (result != null)
|
||||
{
|
||||
if (assetDict.TryGetValue(result, out var assets))
|
||||
assets.Add(asset);
|
||||
else
|
||||
assetDict[result] = [asset];
|
||||
}
|
||||
}
|
||||
if (mocPathDict.Count == 0)
|
||||
{
|
||||
Logger.Error("Live2D Cubism export error\r\nCannot find any model related files");
|
||||
StatusStripUpdate("Live2D export canceled");
|
||||
Progress.Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
var basePathSet = mocPathDict.Values.Select(x => x.Item2).ToHashSet();
|
||||
var useFullContainerPath = mocPathDict.Count != basePathSet.Count;
|
||||
foreach (var moc in mocList)
|
||||
{
|
||||
var mocPath = useFullContainerPath
|
||||
? mocPathDict[moc].Item1 //fullContainerPath
|
||||
: mocPathDict[moc].Item2; //basePath
|
||||
mocPathList.Add(mocPath);
|
||||
}
|
||||
mocPathDict.Clear();
|
||||
|
||||
var lookup = l2dResourceContainers.AsParallel().ToLookup(
|
||||
#else
|
||||
var assetDict = l2dAssetContainers.AsParallel().ToLookup(
|
||||
x => mocPathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
||||
x => x.Key
|
||||
);
|
||||
).Where(x => x.Key != null).ToDictionary(x=> x.Key, x => x.ToList());
|
||||
#endif
|
||||
|
||||
if (mocList[0].serializedType?.m_Type == null && !assemblyLoader.Loaded)
|
||||
if (mocDict.Keys.First().serializedType?.m_Type == null && !assemblyLoader.Loaded)
|
||||
{
|
||||
Logger.Warning("Specifying the assembly folder may be needed for proper extraction");
|
||||
SelectAssemblyFolder();
|
||||
}
|
||||
|
||||
var totalModelCount = lookup.LongCount(x => x.Key != null);
|
||||
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;
|
||||
foreach (var assets in lookup)
|
||||
Live2DExtractor.MocDict = mocDict;
|
||||
Live2DExtractor.Assembly = assemblyLoader;
|
||||
foreach (var assetKvp in assetDict)
|
||||
{
|
||||
var srcContainer = assets.Key;
|
||||
if (srcContainer == null)
|
||||
continue;
|
||||
var container = srcContainer;
|
||||
var srcContainer = assetKvp.Key;
|
||||
|
||||
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{srcContainer}\"...");
|
||||
try
|
||||
{
|
||||
var modelName = useFullContainerPath
|
||||
? Path.GetFileNameWithoutExtension(container)
|
||||
: container.Substring(container.LastIndexOf('/') + 1);
|
||||
container = Path.HasExtension(container)
|
||||
? container.Replace(Path.GetExtension(container), "")
|
||||
: container;
|
||||
var destPath = Path.Combine(baseDestPath, container) + Path.DirectorySeparatorChar;
|
||||
|
||||
var modelExtractor = new Live2DExtractor(assets, selClipMotions, selFadeMotions, selFadeLst);
|
||||
modelExtractor.ExtractCubismModel(destPath, modelName, motionMode, assemblyLoader, forceBezier, parallelExportCount);
|
||||
var cubismExtractor = new Live2DExtractor(assetKvp.Value, selClipMotions, selFadeMotions, selFadeLst);
|
||||
string modelPath;
|
||||
if (modelGroupOption == Live2DModelGroupOption.SourceFileName)
|
||||
{
|
||||
modelPath = Path.GetFileNameWithoutExtension(cubismExtractor.MocMono.assetsFile.originalPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
var container = searchByFilename && cubismExtractor.Model != null
|
||||
? cubismExtractor.Model.Container
|
||||
: srcContainer;
|
||||
modelPath = Path.HasExtension(container)
|
||||
? container.Replace(Path.GetExtension(container), "")
|
||||
: container;
|
||||
}
|
||||
|
||||
var destPath = Path.Combine(baseDestPath, modelPath) + Path.DirectorySeparatorChar;
|
||||
cubismExtractor.ExtractCubismModel(destPath, motionMode, forceBezier, parallelExportCount);
|
||||
modelCounter++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"Live2D model export error: \"{srcContainer}\"", ex);
|
||||
}
|
||||
Progress.Report(modelCounter, (int)totalModelCount);
|
||||
Progress.Report(modelCounter, totalModelCount);
|
||||
}
|
||||
|
||||
Logger.Info($"Finished exporting [{modelCounter}/{totalModelCount}] Live2D model(s).");
|
||||
if (modelCounter < totalModelCount)
|
||||
{
|
||||
var total = (int)totalModelCount;
|
||||
Progress.Report(total, total);
|
||||
}
|
||||
Progress.Report(1, 1);
|
||||
|
||||
if (Properties.Settings.Default.openAfterExport && modelCounter > 0)
|
||||
{
|
||||
OpenFolderInExplorer(exportPath);
|
||||
|
Reference in New Issue
Block a user