mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -04:00
Improve integration with Live2D assets
This commit is contained in:
parent
59db27de3a
commit
064f5cbe57
@ -701,6 +701,34 @@ namespace AssetStudio
|
|||||||
case Animation m_Animation:
|
case Animation m_Animation:
|
||||||
m_GameObject.m_Animation = m_Animation;
|
m_GameObject.m_Animation = m_Animation;
|
||||||
break;
|
break;
|
||||||
|
case MonoBehaviour m_MonoBehaviour:
|
||||||
|
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||||
|
{
|
||||||
|
switch (m_Script.m_ClassName)
|
||||||
|
{
|
||||||
|
case "CubismModel":
|
||||||
|
if (m_GameObject.m_Transform == null)
|
||||||
|
break;
|
||||||
|
m_GameObject.CubismModel = new CubismModel(m_GameObject)
|
||||||
|
{
|
||||||
|
CubismModelMono = m_MonoBehaviour
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case "CubismPhysicsController":
|
||||||
|
if (m_GameObject.CubismModel != null)
|
||||||
|
m_GameObject.CubismModel.PhysicsController = m_MonoBehaviour;
|
||||||
|
break;
|
||||||
|
case "CubismFadeController":
|
||||||
|
if (m_GameObject.CubismModel != null)
|
||||||
|
m_GameObject.CubismModel.FadeController = m_MonoBehaviour;
|
||||||
|
break;
|
||||||
|
case "CubismExpressionController":
|
||||||
|
if (m_GameObject.CubismModel != null)
|
||||||
|
m_GameObject.CubismModel.ExpressionController = m_MonoBehaviour;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
using System;
|
namespace AssetStudio
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace AssetStudio
|
|
||||||
{
|
{
|
||||||
public abstract class Behaviour : Component
|
public abstract class Behaviour : Component
|
||||||
{
|
{
|
||||||
public byte m_Enabled;
|
public byte m_Enabled;
|
||||||
|
|
||||||
|
public Behaviour() { }
|
||||||
|
|
||||||
protected Behaviour(ObjectReader reader) : base(reader)
|
protected Behaviour(ObjectReader reader) : base(reader)
|
||||||
{
|
{
|
||||||
m_Enabled = reader.ReadByte();
|
m_Enabled = reader.ReadByte();
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
using System;
|
namespace AssetStudio
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace AssetStudio
|
|
||||||
{
|
{
|
||||||
public abstract class Component : EditorExtension
|
public abstract class Component : EditorExtension
|
||||||
{
|
{
|
||||||
public PPtr<GameObject> m_GameObject;
|
public PPtr<GameObject> m_GameObject;
|
||||||
|
|
||||||
|
public Component() { }
|
||||||
|
|
||||||
protected Component(ObjectReader reader) : base(reader)
|
protected Component(ObjectReader reader) : base(reader)
|
||||||
{
|
{
|
||||||
m_GameObject = new PPtr<GameObject>(reader);
|
m_GameObject = new PPtr<GameObject>(reader);
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System.Text.Json.Serialization;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
@ -16,6 +13,8 @@ namespace AssetStudio
|
|||||||
public SkinnedMeshRenderer m_SkinnedMeshRenderer;
|
public SkinnedMeshRenderer m_SkinnedMeshRenderer;
|
||||||
public Animator m_Animator;
|
public Animator m_Animator;
|
||||||
public Animation m_Animation;
|
public Animation m_Animation;
|
||||||
|
[JsonIgnore]
|
||||||
|
public CubismModel CubismModel;
|
||||||
|
|
||||||
public GameObject(ObjectReader reader) : base(reader)
|
public GameObject(ObjectReader reader) : base(reader)
|
||||||
{
|
{
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
using System;
|
namespace AssetStudio
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace AssetStudio
|
|
||||||
{
|
{
|
||||||
public sealed class MonoBehaviour : Behaviour
|
public class MonoBehaviour : Behaviour
|
||||||
{
|
{
|
||||||
public PPtr<MonoScript> m_Script;
|
public PPtr<MonoScript> m_Script;
|
||||||
public string m_Name;
|
public string m_Name;
|
||||||
|
|
||||||
|
public MonoBehaviour() { }
|
||||||
|
|
||||||
public MonoBehaviour(ObjectReader reader) : base(reader)
|
public MonoBehaviour(ObjectReader reader) : base(reader)
|
||||||
{
|
{
|
||||||
m_Script = new PPtr<MonoScript>(reader);
|
m_Script = new PPtr<MonoScript>(reader);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
@ -6,10 +7,16 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public int m_FileID;
|
public int m_FileID;
|
||||||
public long m_PathID;
|
public long m_PathID;
|
||||||
public string Name => TryGet(out var result) ? result.Name : string.Empty;
|
public string Name => _assetsFile != null && TryGet(out var result) ? result.Name : string.Empty;
|
||||||
|
|
||||||
private SerializedFile _assetsFile;
|
|
||||||
private int _index = -2; //-2 - Prepare, -1 - Missing
|
private int _index = -2; //-2 - Prepare, -1 - Missing
|
||||||
|
private SerializedFile _assetsFile;
|
||||||
|
[JsonIgnore]
|
||||||
|
public SerializedFile AssetsFile
|
||||||
|
{
|
||||||
|
get => _assetsFile;
|
||||||
|
set => _assetsFile = value;
|
||||||
|
}
|
||||||
|
|
||||||
public PPtr(ObjectReader reader)
|
public PPtr(ObjectReader reader)
|
||||||
{
|
{
|
||||||
@ -20,11 +27,6 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public PPtr() { }
|
public PPtr() { }
|
||||||
|
|
||||||
public void SetAssetsFile(SerializedFile assetsFile)
|
|
||||||
{
|
|
||||||
_assetsFile = assetsFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryGetAssetsFile(out SerializedFile result)
|
private bool TryGetAssetsFile(out SerializedFile result)
|
||||||
{
|
{
|
||||||
result = null;
|
result = null;
|
||||||
|
143
AssetStudio/CubismMoc.cs
Normal file
143
AssetStudio/CubismMoc.cs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using static AssetStudio.EndianSpanReader;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public enum CubismSDKVersion : byte
|
||||||
|
{
|
||||||
|
V30 = 1,
|
||||||
|
V33,
|
||||||
|
V40,
|
||||||
|
V42,
|
||||||
|
V50
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class CubismMoc : IDisposable
|
||||||
|
{
|
||||||
|
public CubismSDKVersion Version { get; }
|
||||||
|
public string VersionDescription { get; }
|
||||||
|
public float CanvasWidth { get; }
|
||||||
|
public float CanvasHeight { get; }
|
||||||
|
public float CentralPosX { get; }
|
||||||
|
public float CentralPosY { get; }
|
||||||
|
public float PixelPerUnit { get; }
|
||||||
|
public uint PartCount { get; }
|
||||||
|
public uint ParamCount { get; }
|
||||||
|
public HashSet<string> PartNames { get; }
|
||||||
|
public HashSet<string> ParamNames { get; }
|
||||||
|
|
||||||
|
private byte[] modelData;
|
||||||
|
private int modelDataSize;
|
||||||
|
private bool isBigEndian;
|
||||||
|
|
||||||
|
public CubismMoc(MonoBehaviour moc)
|
||||||
|
{
|
||||||
|
var reader = moc.reader;
|
||||||
|
reader.Reset();
|
||||||
|
reader.Position += 28; //PPtr<GameObject> m_GameObject, m_Enabled, PPtr<MonoScript>
|
||||||
|
reader.ReadAlignedString(); //m_Name
|
||||||
|
modelDataSize = (int)reader.ReadUInt32();
|
||||||
|
modelData = BigArrayPool<byte>.Shared.Rent(modelDataSize);
|
||||||
|
_ = reader.Read(modelData, 0, modelDataSize);
|
||||||
|
|
||||||
|
var sdkVer = modelData[4];
|
||||||
|
if (Enum.IsDefined(typeof(CubismSDKVersion), sdkVer))
|
||||||
|
{
|
||||||
|
Version = (CubismSDKVersion)sdkVer;
|
||||||
|
VersionDescription = ParseVersion();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var msg = $"Unknown SDK version ({sdkVer})";
|
||||||
|
VersionDescription = msg;
|
||||||
|
Version = 0;
|
||||||
|
Logger.Warning($"Live2D model \"{moc.m_Name}\": " + msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isBigEndian = BitConverter.ToBoolean(modelData, 5);
|
||||||
|
|
||||||
|
//offsets
|
||||||
|
var countInfoTableOffset = (int)SpanToUint32(modelData, 64, isBigEndian);
|
||||||
|
var canvasInfoOffset = (int)SpanToUint32(modelData, 68, isBigEndian);
|
||||||
|
var partIdsOffset = SpanToUint32(modelData, 76, isBigEndian);
|
||||||
|
var parameterIdsOffset = SpanToUint32(modelData, 264, isBigEndian);
|
||||||
|
|
||||||
|
//canvas
|
||||||
|
PixelPerUnit = ToSingle(modelData, canvasInfoOffset, isBigEndian);
|
||||||
|
CentralPosX = ToSingle(modelData, canvasInfoOffset + 4, isBigEndian);
|
||||||
|
CentralPosY = ToSingle(modelData, canvasInfoOffset + 8, isBigEndian);
|
||||||
|
CanvasWidth = ToSingle(modelData, canvasInfoOffset + 12, isBigEndian);
|
||||||
|
CanvasHeight = ToSingle(modelData, canvasInfoOffset + 16, isBigEndian);
|
||||||
|
|
||||||
|
//model
|
||||||
|
PartCount = SpanToUint32(modelData, countInfoTableOffset, isBigEndian);
|
||||||
|
ParamCount = SpanToUint32(modelData, countInfoTableOffset + 20, isBigEndian);
|
||||||
|
PartNames = ReadMocStringHashSet(modelData, (int)partIdsOffset, (int)PartCount);
|
||||||
|
ParamNames = ReadMocStringHashSet(modelData, (int)parameterIdsOffset, (int)ParamCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveMoc3(string savePath)
|
||||||
|
{
|
||||||
|
if (!savePath.EndsWith(".moc3"))
|
||||||
|
savePath += ".moc3";
|
||||||
|
|
||||||
|
using (var file = File.OpenWrite(savePath))
|
||||||
|
{
|
||||||
|
file.Write(modelData, 0, modelDataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ParseVersion()
|
||||||
|
{
|
||||||
|
switch (Version)
|
||||||
|
{
|
||||||
|
case CubismSDKVersion.V30: return "SDK3.0/Cubism3.0(3.2)";
|
||||||
|
case CubismSDKVersion.V33: return "SDK3.3/Cubism3.3";
|
||||||
|
case CubismSDKVersion.V40: return "SDK4.0/Cubism4.0";
|
||||||
|
case CubismSDKVersion.V42: return "SDK4.2/Cubism4.2";
|
||||||
|
case CubismSDKVersion.V50: return "SDK5.0/Cubism5.0";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float ToSingle(ReadOnlySpan<byte> data, int index, bool isBigEndian) //net framework ver
|
||||||
|
{
|
||||||
|
var bytes = data.Slice(index, index + 4).ToArray();
|
||||||
|
if ((isBigEndian && BitConverter.IsLittleEndian) || (!isBigEndian && !BitConverter.IsLittleEndian))
|
||||||
|
(bytes[0], bytes[1], bytes[2], bytes[3]) = (bytes[3], bytes[2], bytes[1], bytes[0]);
|
||||||
|
|
||||||
|
return BitConverter.ToSingle(bytes, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HashSet<string> ReadMocStringHashSet(ReadOnlySpan<byte> data, int index, int count)
|
||||||
|
{
|
||||||
|
const int strLen = 64;
|
||||||
|
var strHashSet = new HashSet<string>();
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (index + i * strLen <= data.Length)
|
||||||
|
{
|
||||||
|
var buff = data.Slice(index + i * strLen, strLen);
|
||||||
|
strHashSet.Add(Encoding.UTF8.GetString(buff.ToArray()).TrimEnd('\0'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strHashSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
BigArrayPool<byte>.Shared.Return(modelData, clearArray: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,149 +1,31 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using static AssetStudio.EndianSpanReader;
|
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
public enum CubismSDKVersion : byte
|
public class CubismModel
|
||||||
{
|
{
|
||||||
V30 = 1,
|
public string Name { get; set; }
|
||||||
V33,
|
public string Container { get; set; }
|
||||||
V40,
|
public bool IsRoot { get; set; }
|
||||||
V42,
|
public MonoBehaviour CubismModelMono { get; set; }
|
||||||
V50
|
public MonoBehaviour PhysicsController { get; set; }
|
||||||
}
|
public MonoBehaviour FadeController { get; set; }
|
||||||
|
public MonoBehaviour ExpressionController { get; set; }
|
||||||
|
public List<MonoBehaviour> RenderTextureList { get; set; }
|
||||||
|
public List<MonoBehaviour> ParamDisplayInfoList { get; set; }
|
||||||
|
public List<MonoBehaviour> PartDisplayInfoList { get; set; }
|
||||||
|
public List<MonoBehaviour> PosePartList { get; set; }
|
||||||
|
public GameObject ModelGameObject { get; set; }
|
||||||
|
|
||||||
public sealed class CubismModel : IDisposable
|
public CubismModel(GameObject m_GameObject)
|
||||||
{
|
|
||||||
public CubismSDKVersion Version { get; }
|
|
||||||
public string VersionDescription { get; }
|
|
||||||
public float CanvasWidth { get; }
|
|
||||||
public float CanvasHeight { get; }
|
|
||||||
public float CentralPosX { get; }
|
|
||||||
public float CentralPosY { get; }
|
|
||||||
public float PixelPerUnit { get; }
|
|
||||||
public uint PartCount { get; }
|
|
||||||
public uint ParamCount { get; }
|
|
||||||
public HashSet<string> PartNames { get; }
|
|
||||||
public HashSet<string> ParamNames { get; }
|
|
||||||
|
|
||||||
private byte[] modelData;
|
|
||||||
private int modelDataSize;
|
|
||||||
private bool isBigEndian;
|
|
||||||
|
|
||||||
public CubismModel(MonoBehaviour moc)
|
|
||||||
{
|
{
|
||||||
var reader = moc.reader;
|
Name = m_GameObject.m_Name;
|
||||||
reader.Reset();
|
IsRoot = m_GameObject.m_Transform.m_Father.IsNull;
|
||||||
reader.Position += 28; //PPtr<GameObject> m_GameObject, m_Enabled, PPtr<MonoScript>
|
ModelGameObject = m_GameObject;
|
||||||
reader.ReadAlignedString(); //m_Name
|
RenderTextureList = new List<MonoBehaviour>();
|
||||||
modelDataSize = (int)reader.ReadUInt32();
|
ParamDisplayInfoList = new List<MonoBehaviour>();
|
||||||
modelData = BigArrayPool<byte>.Shared.Rent(modelDataSize);
|
PartDisplayInfoList = new List<MonoBehaviour>();
|
||||||
_ = reader.Read(modelData, 0, modelDataSize);
|
PosePartList = new List<MonoBehaviour>();
|
||||||
|
|
||||||
var sdkVer = modelData[4];
|
|
||||||
if (Enum.IsDefined(typeof(CubismSDKVersion), sdkVer))
|
|
||||||
{
|
|
||||||
Version = (CubismSDKVersion)sdkVer;
|
|
||||||
VersionDescription = ParseVersion();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var msg = $"Unknown SDK version ({sdkVer})";
|
|
||||||
VersionDescription = msg;
|
|
||||||
Version = 0;
|
|
||||||
Logger.Warning($"Live2D model \"{moc.m_Name}\": " + msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
isBigEndian = BitConverter.ToBoolean(modelData, 5);
|
|
||||||
|
|
||||||
//offsets
|
|
||||||
var countInfoTableOffset = (int)SpanToUint32(modelData, 64, isBigEndian);
|
|
||||||
var canvasInfoOffset = (int)SpanToUint32(modelData, 68, isBigEndian);
|
|
||||||
var partIdsOffset = SpanToUint32(modelData, 76, isBigEndian);
|
|
||||||
var parameterIdsOffset = SpanToUint32(modelData, 264, isBigEndian);
|
|
||||||
|
|
||||||
//canvas
|
|
||||||
PixelPerUnit = ToSingle(modelData, canvasInfoOffset, isBigEndian);
|
|
||||||
CentralPosX = ToSingle(modelData, canvasInfoOffset + 4, isBigEndian);
|
|
||||||
CentralPosY = ToSingle(modelData, canvasInfoOffset + 8, isBigEndian);
|
|
||||||
CanvasWidth = ToSingle(modelData, canvasInfoOffset + 12, isBigEndian);
|
|
||||||
CanvasHeight = ToSingle(modelData, canvasInfoOffset + 16, isBigEndian);
|
|
||||||
|
|
||||||
//model
|
|
||||||
PartCount = SpanToUint32(modelData, countInfoTableOffset, isBigEndian);
|
|
||||||
ParamCount = SpanToUint32(modelData, countInfoTableOffset + 20, isBigEndian);
|
|
||||||
PartNames = ReadMocStringHashSet(modelData, (int)partIdsOffset, (int)PartCount);
|
|
||||||
ParamNames = ReadMocStringHashSet(modelData, (int)parameterIdsOffset, (int)ParamCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveMoc3(string savePath)
|
|
||||||
{
|
|
||||||
if (!savePath.EndsWith(".moc3"))
|
|
||||||
savePath += ".moc3";
|
|
||||||
|
|
||||||
using (var file = File.OpenWrite(savePath))
|
|
||||||
{
|
|
||||||
file.Write(modelData, 0, modelDataSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string ParseVersion()
|
|
||||||
{
|
|
||||||
switch (Version)
|
|
||||||
{
|
|
||||||
case CubismSDKVersion.V30:
|
|
||||||
return "SDK3.0/Cubism3.0(3.2)";
|
|
||||||
case CubismSDKVersion.V33:
|
|
||||||
return "SDK3.3/Cubism3.3";
|
|
||||||
case CubismSDKVersion.V40:
|
|
||||||
return "SDK4.0/Cubism4.0";
|
|
||||||
case CubismSDKVersion.V42:
|
|
||||||
return "SDK4.2/Cubism4.2";
|
|
||||||
case CubismSDKVersion.V50:
|
|
||||||
return "SDK5.0/Cubism5.0";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float ToSingle(ReadOnlySpan<byte> data, int index, bool isBigEndian) //net framework ver
|
|
||||||
{
|
|
||||||
var bytes = data.Slice(index, index + 4).ToArray();
|
|
||||||
if ((isBigEndian && BitConverter.IsLittleEndian) || (!isBigEndian && !BitConverter.IsLittleEndian))
|
|
||||||
(bytes[0], bytes[1], bytes[2], bytes[3]) = (bytes[3], bytes[2], bytes[1], bytes[0]);
|
|
||||||
|
|
||||||
return BitConverter.ToSingle(bytes, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HashSet<string> ReadMocStringHashSet(ReadOnlySpan<byte> data, int index, int count)
|
|
||||||
{
|
|
||||||
const int strLen = 64;
|
|
||||||
var strHashSet = new HashSet<string>();
|
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (index + i * strLen <= data.Length)
|
|
||||||
{
|
|
||||||
var buff = data.Slice(index + i * strLen, strLen);
|
|
||||||
strHashSet.Add(Encoding.UTF8.GetString(buff.ToArray()).TrimEnd('\0'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strHashSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
BigArrayPool<byte>.Shared.Return(modelData, clearArray: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ namespace AssetStudio
|
|||||||
public override PPtr<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override PPtr<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
var pptrObj = JsonSerializer.Deserialize<PPtr<T>>(ref reader, new JsonSerializerOptions { IncludeFields = true });
|
var pptrObj = JsonSerializer.Deserialize<PPtr<T>>(ref reader, new JsonSerializerOptions { IncludeFields = true });
|
||||||
pptrObj.SetAssetsFile(_assetsFile);
|
pptrObj.AssetsFile = _assetsFile;
|
||||||
return pptrObj;
|
return pptrObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,17 +24,26 @@ namespace AssetStudio
|
|||||||
public static string ReadTypeString(TypeTree m_Type, ObjectReader reader)
|
public static string ReadTypeString(TypeTree m_Type, ObjectReader reader)
|
||||||
{
|
{
|
||||||
reader.Reset();
|
reader.Reset();
|
||||||
|
var readed = 0L;
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
var m_Nodes = m_Type.m_Nodes;
|
var m_Nodes = m_Type.m_Nodes;
|
||||||
for (int i = 0; i < m_Nodes.Count; i++)
|
try
|
||||||
{
|
{
|
||||||
ReadStringValue(sb, m_Nodes, reader, ref i);
|
for (int i = 0; i < m_Nodes.Count; i++)
|
||||||
|
{
|
||||||
|
ReadStringValue(sb, m_Nodes, reader, ref i);
|
||||||
|
}
|
||||||
|
readed = reader.Position - reader.byteStart;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
//Ignore
|
||||||
}
|
}
|
||||||
var readed = reader.Position - reader.byteStart;
|
|
||||||
if (readed != reader.byteSize)
|
if (readed != reader.byteSize)
|
||||||
{
|
{
|
||||||
Logger.Info($"Failed to read type, read {readed} bytes but expected {reader.byteSize} bytes");
|
Logger.Info($"Failed to read type, read {readed} bytes but expected {reader.byteSize} bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +100,8 @@ namespace AssetStudioCLI.Options
|
|||||||
public static Option<ImageFormat> o_imageFormat;
|
public static Option<ImageFormat> o_imageFormat;
|
||||||
public static Option<AudioFormat> o_audioFormat;
|
public static Option<AudioFormat> o_audioFormat;
|
||||||
//live2d
|
//live2d
|
||||||
|
public static Option<CubismLive2DExtractor.Live2DModelGroupOption> o_l2dGroupOption;
|
||||||
|
public static Option<bool> f_l2dAssetSearchByFilename;
|
||||||
public static Option<CubismLive2DExtractor.Live2DMotionMode> o_l2dMotionMode;
|
public static Option<CubismLive2DExtractor.Live2DMotionMode> o_l2dMotionMode;
|
||||||
public static Option<bool> f_l2dForceBezier;
|
public static Option<bool> f_l2dForceBezier;
|
||||||
//fbx
|
//fbx
|
||||||
@ -228,10 +230,10 @@ namespace AssetStudioCLI.Options
|
|||||||
optionDefaultValue: FilenameFormat.AssetName,
|
optionDefaultValue: FilenameFormat.AssetName,
|
||||||
optionName: "-f, --filename-format <value>",
|
optionName: "-f, --filename-format <value>",
|
||||||
optionDescription: "Specify the file name format for exported assets\n" +
|
optionDescription: "Specify the file name format for exported assets\n" +
|
||||||
"<Value: assetName(default) | assetName_pathID | pathID>\n" +
|
"<Value: assetName(default) | assetName_pathID | pathID>\n" +
|
||||||
"AssetName - Asset file names will look like \"assetName.extension\"\n" +
|
"AssetName - Asset file names will look like \"assetName.extension\"\n" +
|
||||||
"AssetName_pathID - Asset file names will look like \"assetName @pathID.extension\"\n" +
|
"AssetName_pathID - Asset file names will look like \"assetName @pathID.extension\"\n" +
|
||||||
"PathID - Asset file names will look like \"pathID.extension\"\n",
|
"PathID - Asset file names will look like \"pathID.extension\"\n",
|
||||||
optionExample: "Example: \"-f assetName_pathID\"\n",
|
optionExample: "Example: \"-f assetName_pathID\"\n",
|
||||||
optionHelpGroup: HelpGroups.General
|
optionHelpGroup: HelpGroups.General
|
||||||
);
|
);
|
||||||
@ -293,13 +295,24 @@ namespace AssetStudioCLI.Options
|
|||||||
optionName: "--audio-format <value>",
|
optionName: "--audio-format <value>",
|
||||||
optionDescription: "Specify the format for converting FMOD audio assets\n" +
|
optionDescription: "Specify the format for converting FMOD audio assets\n" +
|
||||||
"<Value: none | wav(default)>\n" +
|
"<Value: none | wav(default)>\n" +
|
||||||
"None - Do not convert fmod audios and export them in their own format\n",
|
"None - Do not convert FMOD audios and export them in their own format\n",
|
||||||
optionExample: "Example: \"--audio-format wav\"",
|
optionExample: "Example: \"--audio-format wav\"",
|
||||||
optionHelpGroup: HelpGroups.Convert
|
optionHelpGroup: HelpGroups.Convert
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Init Cubism Live2D Options
|
#region Init Cubism Live2D Options
|
||||||
|
o_l2dGroupOption = new GroupedOption<CubismLive2DExtractor.Live2DModelGroupOption>
|
||||||
|
(
|
||||||
|
optionDefaultValue: CubismLive2DExtractor.Live2DModelGroupOption.ContainerPath,
|
||||||
|
optionName: "--l2d-group-option <value>",
|
||||||
|
optionDescription: "Specify the way in which exported models should be grouped\n" +
|
||||||
|
"<Value: container(default) | filename >\n" +
|
||||||
|
"Container - Group exported models by container path\n" +
|
||||||
|
"Filename - Group exported models by source file name\n",
|
||||||
|
optionExample: "Example: \"--l2d-group-option filename\"\n",
|
||||||
|
optionHelpGroup: HelpGroups.Live2D
|
||||||
|
);
|
||||||
o_l2dMotionMode = new GroupedOption<CubismLive2DExtractor.Live2DMotionMode>
|
o_l2dMotionMode = new GroupedOption<CubismLive2DExtractor.Live2DMotionMode>
|
||||||
(
|
(
|
||||||
optionDefaultValue: CubismLive2DExtractor.Live2DMotionMode.MonoBehaviour,
|
optionDefaultValue: CubismLive2DExtractor.Live2DMotionMode.MonoBehaviour,
|
||||||
@ -312,6 +325,17 @@ namespace AssetStudioCLI.Options
|
|||||||
optionExample: "Example: \"--l2d-motion-mode animationClip\"\n",
|
optionExample: "Example: \"--l2d-motion-mode animationClip\"\n",
|
||||||
optionHelpGroup: HelpGroups.Live2D
|
optionHelpGroup: HelpGroups.Live2D
|
||||||
);
|
);
|
||||||
|
f_l2dAssetSearchByFilename = new GroupedOption<bool>
|
||||||
|
(
|
||||||
|
optionDefaultValue: false,
|
||||||
|
optionName: "--l2d-search-by-filename",
|
||||||
|
optionDescription: "(Flag) If specified, Studio will search for model-related Live2D assets by file name\n" +
|
||||||
|
"rather than by container\n" +
|
||||||
|
"(Preferred option when all model-related assets are stored in a single file)\n",
|
||||||
|
optionExample: "",
|
||||||
|
optionHelpGroup: HelpGroups.Live2D,
|
||||||
|
isFlag: true
|
||||||
|
);
|
||||||
f_l2dForceBezier = new GroupedOption<bool>
|
f_l2dForceBezier = new GroupedOption<bool>
|
||||||
(
|
(
|
||||||
optionDefaultValue: false,
|
optionDefaultValue: false,
|
||||||
@ -569,12 +593,22 @@ namespace AssetStudioCLI.Options
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Parse Flags
|
#region Parse Flags
|
||||||
for (int i = 0; i < resplittedArgs.Count; i++)
|
for (var i = 0; i < resplittedArgs.Count; i++)
|
||||||
{
|
{
|
||||||
string flag = resplittedArgs[i].ToLower();
|
var flag = resplittedArgs[i].ToLower();
|
||||||
|
|
||||||
switch(flag)
|
switch(flag)
|
||||||
{
|
{
|
||||||
|
case "--l2d-search-by-filename":
|
||||||
|
if (o_workMode.Value != WorkMode.Live2D)
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
ShowOptionDescription(o_workMode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f_l2dAssetSearchByFilename.Value = true;
|
||||||
|
resplittedArgs.RemoveAt(i);
|
||||||
|
break;
|
||||||
case "--l2d-force-bezier":
|
case "--l2d-force-bezier":
|
||||||
if (o_workMode.Value != WorkMode.Live2D)
|
if (o_workMode.Value != WorkMode.Live2D)
|
||||||
{
|
{
|
||||||
@ -831,6 +865,27 @@ namespace AssetStudioCLI.Options
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "--l2d-group-option":
|
||||||
|
if (o_workMode.Value != WorkMode.Live2D)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option.Color(brightYellow)}] option. This option is not suitable for the current working mode [{o_workMode.Value}].\n");
|
||||||
|
ShowOptionDescription(o_workMode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (value.ToLower())
|
||||||
|
{
|
||||||
|
case "container":
|
||||||
|
o_l2dGroupOption.Value = CubismLive2DExtractor.Live2DModelGroupOption.ContainerPath;
|
||||||
|
break;
|
||||||
|
case "filename":
|
||||||
|
o_l2dGroupOption.Value = CubismLive2DExtractor.Live2DModelGroupOption.SourceFileName;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option.Color(brightYellow)}] option. Unsupported model grouping option: [{value.Color(brightRed)}].\n");
|
||||||
|
ShowOptionDescription(o_l2dGroupOption);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "--l2d-motion-mode":
|
case "--l2d-motion-mode":
|
||||||
if (o_workMode.Value != WorkMode.Live2D)
|
if (o_workMode.Value != WorkMode.Live2D)
|
||||||
{
|
{
|
||||||
@ -1199,7 +1254,9 @@ namespace AssetStudioCLI.Options
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb.AppendLine($"# Live2D Motion Export Method: {o_l2dMotionMode}");
|
sb.AppendLine($"# Model Group Option: {o_l2dGroupOption}");
|
||||||
|
sb.AppendFormat("# Search model-related assets by: {0}", f_l2dAssetSearchByFilename.Value ? "Filename" : "Container");
|
||||||
|
sb.AppendLine($"# Motion Export Method: {o_l2dMotionMode}");
|
||||||
sb.AppendLine($"# Force Bezier: {f_l2dForceBezier }");
|
sb.AppendLine($"# Force Bezier: {f_l2dForceBezier }");
|
||||||
sb.AppendLine($"# Assembly Path: \"{o_assemblyPath}\"");
|
sb.AppendLine($"# Assembly Path: \"{o_assemblyPath}\"");
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using CubismLive2DExtractor;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -20,7 +21,7 @@ namespace AssetStudioCLI
|
|||||||
public static List<AssetItem> parsedAssetsList = new List<AssetItem>();
|
public static List<AssetItem> parsedAssetsList = new List<AssetItem>();
|
||||||
public static List<BaseNode> gameObjectTree = new List<BaseNode>();
|
public static List<BaseNode> gameObjectTree = new List<BaseNode>();
|
||||||
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
|
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
|
||||||
public static List<MonoBehaviour> cubismMocList = new List<MonoBehaviour>();
|
public static Dictionary<MonoBehaviour, CubismModel> l2dModelDict = new Dictionary<MonoBehaviour, CubismModel>();
|
||||||
private static Dictionary<AssetStudio.Object, string> containers = new Dictionary<AssetStudio.Object, string>();
|
private static Dictionary<AssetStudio.Object, string> containers = new Dictionary<AssetStudio.Object, string>();
|
||||||
|
|
||||||
static Studio()
|
static Studio()
|
||||||
@ -65,6 +66,8 @@ namespace AssetStudioCLI
|
|||||||
var tex2dArrayAssetList = new List<AssetItem>();
|
var tex2dArrayAssetList = new List<AssetItem>();
|
||||||
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
|
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
|
||||||
var objectAssetItemDic = new Dictionary<AssetStudio.Object, AssetItem>(objectCount);
|
var objectAssetItemDic = new Dictionary<AssetStudio.Object, AssetItem>(objectCount);
|
||||||
|
var isL2dMode = CLIOptions.o_workMode.Value == WorkMode.Live2D;
|
||||||
|
var l2dSearchByFilename = CLIOptions.f_l2dAssetSearchByFilename.Value;
|
||||||
|
|
||||||
Progress.Reset();
|
Progress.Reset();
|
||||||
var i = 0;
|
var i = 0;
|
||||||
@ -143,15 +146,40 @@ namespace AssetStudioCLI
|
|||||||
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||||
{
|
{
|
||||||
assetName = assetName == "" ? m_Script.m_ClassName : assetName;
|
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;
|
assetItem.Text = assetName;
|
||||||
break;
|
break;
|
||||||
case GameObject m_GameObject:
|
case GameObject m_GameObject:
|
||||||
assetItem.Text = m_GameObject.m_Name;
|
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;
|
break;
|
||||||
case Animator m_Animator:
|
case Animator m_Animator:
|
||||||
if (m_Animator.m_GameObject.TryGet(out var gameObject))
|
if (m_Animator.m_GameObject.TryGet(out var gameObject))
|
||||||
@ -177,11 +205,19 @@ namespace AssetStudioCLI
|
|||||||
asset.Name = assetItem.Text;
|
asset.Name = assetItem.Text;
|
||||||
Progress.Report(++i, objectCount);
|
Progress.Report(++i, objectCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var asset in fileAssetsList)
|
foreach (var asset in fileAssetsList)
|
||||||
{
|
{
|
||||||
if (containers.TryGetValue(asset.Asset, out var container))
|
if (containers.TryGetValue(asset.Asset, out var container))
|
||||||
{
|
{
|
||||||
asset.Container = container;
|
asset.Container = isL2dMode && l2dSearchByFilename
|
||||||
|
? Path.GetFileName(asset.Asset.assetsFile.originalPath)
|
||||||
|
: container;
|
||||||
|
|
||||||
|
if (asset.Asset is GameObject m_GameObject && m_GameObject.CubismModel != null)
|
||||||
|
{
|
||||||
|
m_GameObject.CubismModel.Container = container;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var tex2dAssetItem in tex2dArrayAssetList)
|
foreach (var tex2dAssetItem in tex2dArrayAssetList)
|
||||||
@ -196,7 +232,7 @@ namespace AssetStudioCLI
|
|||||||
parsedAssetsList.AddRange(fileAssetsList);
|
parsedAssetsList.AddRange(fileAssetsList);
|
||||||
fileAssetsList.Clear();
|
fileAssetsList.Clear();
|
||||||
tex2dArrayAssetList.Clear();
|
tex2dArrayAssetList.Clear();
|
||||||
if (CLIOptions.o_workMode.Value != WorkMode.Live2D)
|
if (!isL2dMode)
|
||||||
{
|
{
|
||||||
containers.Clear();
|
containers.Clear();
|
||||||
}
|
}
|
||||||
@ -726,16 +762,145 @@ namespace AssetStudioCLI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (!containers.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(containers[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()
|
public static void ExportLive2D()
|
||||||
{
|
{
|
||||||
var baseDestPath = Path.Combine(CLIOptions.o_outputFolder.Value, "Live2DOutput");
|
var baseDestPath = Path.Combine(CLIOptions.o_outputFolder.Value, "Live2DOutput");
|
||||||
var useFullContainerPath = true;
|
var useFullContainerPath = true;
|
||||||
var mocPathList = new List<string>();
|
|
||||||
var basePathSet = new HashSet<string>();
|
|
||||||
var motionMode = CLIOptions.o_l2dMotionMode.Value;
|
var motionMode = CLIOptions.o_l2dMotionMode.Value;
|
||||||
var forceBezier = CLIOptions.f_l2dForceBezier.Value;
|
var forceBezier = CLIOptions.f_l2dForceBezier.Value;
|
||||||
|
var modelGroupOption = CLIOptions.o_l2dGroupOption.Value;
|
||||||
|
var searchByFilename = CLIOptions.f_l2dAssetSearchByFilename.Value;
|
||||||
|
var mocDict = l2dModelDict; //TODO: filter by name
|
||||||
|
|
||||||
if (cubismMocList.Count == 0)
|
if (l2dModelDict.Count == 0)
|
||||||
{
|
{
|
||||||
Logger.Default.Log(LoggerEvent.Info, "Live2D Cubism models were not found.", ignoreLevel: true);
|
Logger.Default.Log(LoggerEvent.Info, "Live2D Cubism models were not found.", ignoreLevel: true);
|
||||||
return;
|
return;
|
||||||
@ -744,66 +909,75 @@ namespace AssetStudioCLI
|
|||||||
Progress.Reset();
|
Progress.Reset();
|
||||||
Logger.Info($"Searching for Live2D files...");
|
Logger.Info($"Searching for Live2D files...");
|
||||||
|
|
||||||
foreach (var mocMonoBehaviour in cubismMocList)
|
var mocPathList = GenerateMocPathList(mocDict, searchByFilename, ref useFullContainerPath);
|
||||||
{
|
|
||||||
if (!containers.TryGetValue(mocMonoBehaviour, out var fullContainerPath))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var pathSepIndex = fullContainerPath.LastIndexOf('/');
|
#if NET9_0_OR_GREATER
|
||||||
var basePath = pathSepIndex > 0
|
var assetDict = new Dictionary<string, List<AssetStudio.Object>>();
|
||||||
? fullContainerPath.Substring(0, pathSepIndex)
|
foreach (var (asset, container) in containers)
|
||||||
: fullContainerPath;
|
{
|
||||||
basePathSet.Add(basePath);
|
var result = mocPathList.Find(mocPath =>
|
||||||
mocPathList.Add(fullContainerPath);
|
{
|
||||||
}
|
if (!container.Contains(mocPath))
|
||||||
|
return false;
|
||||||
if (mocPathList.Count == 0)
|
var mocPathSpan = mocPath.AsSpan();
|
||||||
{
|
var mocPathLastSlice = mocPathSpan[(mocPathSpan.LastIndexOf('/') + 1)..];
|
||||||
Logger.Error("Live2D Cubism export error: Cannot find any model related files.");
|
foreach (var range in container.AsSpan().Split('/'))
|
||||||
return;
|
{
|
||||||
}
|
if (mocPathLastSlice.SequenceEqual(container.AsSpan()[range]))
|
||||||
if (basePathSet.Count == mocPathList.Count)
|
return true;
|
||||||
{
|
}
|
||||||
mocPathList = basePathSet.ToList();
|
return false;
|
||||||
useFullContainerPath = false;
|
});
|
||||||
Logger.Debug($"useFullContainerPath: {useFullContainerPath}");
|
if (result != null)
|
||||||
}
|
{
|
||||||
basePathSet.Clear();
|
if (assetDict.TryGetValue(result, out var assets))
|
||||||
|
assets.Add(asset);
|
||||||
var lookup = containers.AsParallel().ToLookup(
|
else
|
||||||
|
assetDict[result] = [asset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
var assetDict = containers.AsParallel().ToLookup(
|
||||||
x => mocPathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
x => mocPathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
||||||
x => x.Key
|
x => x.Key
|
||||||
);
|
).Where(x => x.Key != null).ToDictionary(x => x.Key, x => x.ToList());
|
||||||
|
#endif
|
||||||
if (cubismMocList[0].serializedType?.m_Type == null && CLIOptions.o_assemblyPath.Value == "")
|
if (mocDict.Keys.First().serializedType?.m_Type == null && CLIOptions.o_assemblyPath.Value == "")
|
||||||
{
|
{
|
||||||
Logger.Warning("Specifying the assembly folder may be needed for proper extraction");
|
Logger.Warning("Specifying the assembly folder may be needed for proper extraction");
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalModelCount = lookup.LongCount(x => x.Key != null);
|
var totalModelCount = assetDict.Count;
|
||||||
Logger.Info($"Found {totalModelCount} model(s).");
|
Logger.Info($"Found {totalModelCount} model(s).");
|
||||||
var parallelTaskCount = CLIOptions.o_maxParallelExportTasks.Value;
|
var parallelTaskCount = CLIOptions.o_maxParallelExportTasks.Value;
|
||||||
var modelCounter = 0;
|
var modelCounter = 0;
|
||||||
foreach (var assets in lookup)
|
Live2DExtractor.MocDict = mocDict;
|
||||||
|
Live2DExtractor.Assembly = assemblyLoader;
|
||||||
|
foreach (var assetKvp in assetDict)
|
||||||
{
|
{
|
||||||
var srcContainer = assets.Key;
|
var srcContainer = assetKvp.Key;
|
||||||
if (srcContainer == null)
|
|
||||||
continue;
|
|
||||||
var container = srcContainer;
|
|
||||||
|
|
||||||
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{srcContainer.Color(Ansi.BrightCyan)}\"");
|
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{srcContainer.Color(Ansi.BrightCyan)}\"");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var modelName = useFullContainerPath
|
var cubismExtractor = new Live2DExtractor(assetKvp.Value);
|
||||||
? Path.GetFileNameWithoutExtension(container)
|
string modelPath;
|
||||||
: container.Substring(container.LastIndexOf('/') + 1);
|
if (modelGroupOption == Live2DModelGroupOption.SourceFileName)
|
||||||
container = Path.HasExtension(container)
|
{
|
||||||
? container.Replace(Path.GetExtension(container), "")
|
modelPath = Path.GetFileNameWithoutExtension(cubismExtractor.MocMono.assetsFile.originalPath);
|
||||||
: container;
|
}
|
||||||
var destPath = Path.Combine(baseDestPath, container) + Path.DirectorySeparatorChar;
|
else
|
||||||
|
{
|
||||||
|
var container = searchByFilename && cubismExtractor.Model != null
|
||||||
|
? cubismExtractor.Model.Container
|
||||||
|
: srcContainer;
|
||||||
|
modelPath = Path.HasExtension(container)
|
||||||
|
? container.Replace(Path.GetExtension(container), "")
|
||||||
|
: container;
|
||||||
|
}
|
||||||
|
|
||||||
var modelExtractor = new Live2DExtractor(assets);
|
var destPath = Path.Combine(baseDestPath, modelPath) + Path.DirectorySeparatorChar;
|
||||||
modelExtractor.ExtractCubismModel(destPath, modelName, motionMode, assemblyLoader, forceBezier, parallelTaskCount);
|
cubismExtractor.ExtractCubismModel(destPath, motionMode, forceBezier, parallelTaskCount);
|
||||||
modelCounter++;
|
modelCounter++;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -293,7 +293,7 @@ namespace AssetStudioGUI
|
|||||||
|
|
||||||
var types = new SortedSet<string>();
|
var types = new SortedSet<string>();
|
||||||
types.UnionWith(exportableAssets.Select(x => x.TypeString));
|
types.UnionWith(exportableAssets.Select(x => x.TypeString));
|
||||||
if (Studio.cubismMocList.Count > 0)
|
if (Studio.l2dModelDict.Count > 0)
|
||||||
{
|
{
|
||||||
types.Add("MonoBehaviour (Live2D Model)");
|
types.Add("MonoBehaviour (Live2D Model)");
|
||||||
}
|
}
|
||||||
@ -1181,19 +1181,19 @@ namespace AssetStudioGUI
|
|||||||
|
|
||||||
private void PreviewMoc(AssetItem assetItem, MonoBehaviour m_MonoBehaviour)
|
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();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine($"SDK Version: {cubismModel.VersionDescription}");
|
sb.AppendLine($"SDK Version: {cubismMoc.VersionDescription}");
|
||||||
if (cubismModel.Version > 0)
|
if (cubismMoc.Version > 0)
|
||||||
{
|
{
|
||||||
sb.AppendLine($"Canvas Width: {cubismModel.CanvasWidth}");
|
sb.AppendLine($"Canvas Width: {cubismMoc.CanvasWidth}");
|
||||||
sb.AppendLine($"Canvas Height: {cubismModel.CanvasHeight}");
|
sb.AppendLine($"Canvas Height: {cubismMoc.CanvasHeight}");
|
||||||
sb.AppendLine($"Center X: {cubismModel.CentralPosX}");
|
sb.AppendLine($"Center X: {cubismMoc.CentralPosX}");
|
||||||
sb.AppendLine($"Center Y: {cubismModel.CentralPosY}");
|
sb.AppendLine($"Center Y: {cubismMoc.CentralPosY}");
|
||||||
sb.AppendLine($"Pixel Per Unit: {cubismModel.PixelPerUnit}");
|
sb.AppendLine($"Pixel Per Unit: {cubismMoc.PixelPerUnit}");
|
||||||
sb.AppendLine($"Parameter Count: {cubismModel.ParamCount}");
|
sb.AppendLine($"Parameter Count: {cubismMoc.ParamCount}");
|
||||||
sb.AppendLine($"Part Count: {cubismModel.PartCount}");
|
sb.AppendLine($"Part Count: {cubismMoc.PartCount}");
|
||||||
}
|
}
|
||||||
assetItem.InfoText = sb.ToString();
|
assetItem.InfoText = sb.ToString();
|
||||||
}
|
}
|
||||||
@ -1484,6 +1484,7 @@ namespace AssetStudioGUI
|
|||||||
assemblyLoader.Clear();
|
assemblyLoader.Clear();
|
||||||
exportableAssets.Clear();
|
exportableAssets.Clear();
|
||||||
visibleAssets.Clear();
|
visibleAssets.Clear();
|
||||||
|
l2dModelDict.Clear();
|
||||||
sceneTreeView.Nodes.Clear();
|
sceneTreeView.Nodes.Clear();
|
||||||
assetListView.VirtualListSize = 0;
|
assetListView.VirtualListSize = 0;
|
||||||
assetListView.Items.Clear();
|
assetListView.Items.Clear();
|
||||||
@ -1491,7 +1492,6 @@ namespace AssetStudioGUI
|
|||||||
classesListView.Groups.Clear();
|
classesListView.Groups.Clear();
|
||||||
selectedAnimationAssetsList.Clear();
|
selectedAnimationAssetsList.Clear();
|
||||||
selectedIndicesPrevList.Clear();
|
selectedIndicesPrevList.Clear();
|
||||||
cubismMocList.Clear();
|
|
||||||
previewPanel.Image = Properties.Resources.preview;
|
previewPanel.Image = Properties.Resources.preview;
|
||||||
previewPanel.SizeMode = PictureBoxSizeMode.CenterImage;
|
previewPanel.SizeMode = PictureBoxSizeMode.CenterImage;
|
||||||
imageTexture?.Dispose();
|
imageTexture?.Dispose();
|
||||||
@ -1556,7 +1556,7 @@ namespace AssetStudioGUI
|
|||||||
switch (asset.Asset)
|
switch (asset.Asset)
|
||||||
{
|
{
|
||||||
case MonoBehaviour m_MonoBehaviour:
|
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")
|
if (m_Script.m_ClassName == "CubismMoc")
|
||||||
{
|
{
|
||||||
@ -1892,7 +1892,7 @@ namespace AssetStudioGUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
visibleAssets = filterMoc
|
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));
|
: exportableAssets.FindAll(x => show.Contains(x.Type));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2217,7 +2217,7 @@ namespace AssetStudioGUI
|
|||||||
{
|
{
|
||||||
if (exportableAssets.Count > 0)
|
if (exportableAssets.Count > 0)
|
||||||
{
|
{
|
||||||
if (Studio.cubismMocList.Count == 0)
|
if (Studio.l2dModelDict.Count == 0)
|
||||||
{
|
{
|
||||||
Logger.Info("Live2D Cubism models were not found.");
|
Logger.Info("Live2D Cubism models were not found.");
|
||||||
return;
|
return;
|
||||||
@ -2257,7 +2257,7 @@ namespace AssetStudioGUI
|
|||||||
Logger.Info("No exportable assets loaded");
|
Logger.Info("No exportable assets loaded");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Studio.cubismMocList.Count == 0)
|
if (Studio.l2dModelDict.Count == 0)
|
||||||
{
|
{
|
||||||
Logger.Info("Live2D Cubism models were not found.");
|
Logger.Info("Live2D Cubism models were not found.");
|
||||||
return;
|
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.tobmp = new System.Windows.Forms.RadioButton();
|
||||||
this.converttexture = new System.Windows.Forms.CheckBox();
|
this.converttexture = new System.Windows.Forms.CheckBox();
|
||||||
this.l2dGroupBox = new System.Windows.Forms.GroupBox();
|
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.l2dMotionExportMethodPanel = new System.Windows.Forms.Panel();
|
||||||
this.l2dMonoBehaviourRadioButton = new System.Windows.Forms.RadioButton();
|
this.l2dMonoBehaviourRadioButton = new System.Windows.Forms.RadioButton();
|
||||||
this.l2dAnimationClipRadioButton = new System.Windows.Forms.RadioButton();
|
this.l2dAnimationClipRadioButton = new System.Windows.Forms.RadioButton();
|
||||||
@ -89,7 +92,7 @@
|
|||||||
// OKbutton
|
// OKbutton
|
||||||
//
|
//
|
||||||
this.OKbutton.BackColor = System.Drawing.SystemColors.ButtonFace;
|
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.Name = "OKbutton";
|
||||||
this.OKbutton.Size = new System.Drawing.Size(75, 23);
|
this.OKbutton.Size = new System.Drawing.Size(75, 23);
|
||||||
this.OKbutton.TabIndex = 4;
|
this.OKbutton.TabIndex = 4;
|
||||||
@ -101,7 +104,7 @@
|
|||||||
//
|
//
|
||||||
this.Cancel.BackColor = System.Drawing.SystemColors.ButtonFace;
|
this.Cancel.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||||
this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
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.Name = "Cancel";
|
||||||
this.Cancel.Size = new System.Drawing.Size(75, 23);
|
this.Cancel.Size = new System.Drawing.Size(75, 23);
|
||||||
this.Cancel.TabIndex = 5;
|
this.Cancel.TabIndex = 5;
|
||||||
@ -193,8 +196,8 @@
|
|||||||
this.filenameFormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
this.filenameFormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
this.filenameFormatComboBox.FormattingEnabled = true;
|
this.filenameFormatComboBox.FormattingEnabled = true;
|
||||||
this.filenameFormatComboBox.Items.AddRange(new object[] {
|
this.filenameFormatComboBox.Items.AddRange(new object[] {
|
||||||
"assetName",
|
"asset name",
|
||||||
"assetName@pathID",
|
"asset name@pathID",
|
||||||
"pathID"});
|
"pathID"});
|
||||||
this.filenameFormatComboBox.Location = new System.Drawing.Point(177, 35);
|
this.filenameFormatComboBox.Location = new System.Drawing.Point(177, 35);
|
||||||
this.filenameFormatComboBox.Name = "filenameFormatComboBox";
|
this.filenameFormatComboBox.Name = "filenameFormatComboBox";
|
||||||
@ -353,24 +356,59 @@
|
|||||||
//
|
//
|
||||||
// l2dGroupBox
|
// 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.l2dMotionExportMethodPanel);
|
||||||
this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodLabel);
|
this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodLabel);
|
||||||
this.l2dGroupBox.Controls.Add(this.l2dForceBezierCheckBox);
|
this.l2dGroupBox.Controls.Add(this.l2dForceBezierCheckBox);
|
||||||
this.l2dGroupBox.Location = new System.Drawing.Point(12, 275);
|
this.l2dGroupBox.Location = new System.Drawing.Point(12, 275);
|
||||||
this.l2dGroupBox.Name = "l2dGroupBox";
|
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.TabIndex = 2;
|
||||||
this.l2dGroupBox.TabStop = false;
|
this.l2dGroupBox.TabStop = false;
|
||||||
this.l2dGroupBox.Text = "Cubism Live2D";
|
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
|
// l2dMotionExportMethodPanel
|
||||||
//
|
//
|
||||||
this.l2dMotionExportMethodPanel.Controls.Add(this.l2dMonoBehaviourRadioButton);
|
this.l2dMotionExportMethodPanel.Controls.Add(this.l2dMonoBehaviourRadioButton);
|
||||||
this.l2dMotionExportMethodPanel.Controls.Add(this.l2dAnimationClipRadioButton);
|
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.Name = "l2dMotionExportMethodPanel";
|
||||||
this.l2dMotionExportMethodPanel.Size = new System.Drawing.Size(279, 27);
|
this.l2dMotionExportMethodPanel.Size = new System.Drawing.Size(279, 27);
|
||||||
this.l2dMotionExportMethodPanel.TabIndex = 2;
|
this.l2dMotionExportMethodPanel.TabIndex = 5;
|
||||||
//
|
//
|
||||||
// l2dMonoBehaviourRadioButton
|
// l2dMonoBehaviourRadioButton
|
||||||
//
|
//
|
||||||
@ -400,19 +438,19 @@
|
|||||||
// l2dMotionExportMethodLabel
|
// l2dMotionExportMethodLabel
|
||||||
//
|
//
|
||||||
this.l2dMotionExportMethodLabel.AutoSize = true;
|
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.Name = "l2dMotionExportMethodLabel";
|
||||||
this.l2dMotionExportMethodLabel.Size = new System.Drawing.Size(109, 13);
|
this.l2dMotionExportMethodLabel.Size = new System.Drawing.Size(109, 13);
|
||||||
this.l2dMotionExportMethodLabel.TabIndex = 1;
|
this.l2dMotionExportMethodLabel.TabIndex = 4;
|
||||||
this.l2dMotionExportMethodLabel.Text = "Motion export method";
|
this.l2dMotionExportMethodLabel.Text = "Motion export method";
|
||||||
//
|
//
|
||||||
// l2dForceBezierCheckBox
|
// l2dForceBezierCheckBox
|
||||||
//
|
//
|
||||||
this.l2dForceBezierCheckBox.AutoSize = true;
|
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.Name = "l2dForceBezierCheckBox";
|
||||||
this.l2dForceBezierCheckBox.Size = new System.Drawing.Size(278, 17);
|
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.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.optionTooltip.SetToolTip(this.l2dForceBezierCheckBox, "May help if the exported motions look jerky/not smooth enough");
|
||||||
this.l2dForceBezierCheckBox.UseVisualStyleBackColor = true;
|
this.l2dForceBezierCheckBox.UseVisualStyleBackColor = true;
|
||||||
@ -439,7 +477,7 @@
|
|||||||
this.groupBox2.Controls.Add(this.eulerFilter);
|
this.groupBox2.Controls.Add(this.eulerFilter);
|
||||||
this.groupBox2.Location = new System.Drawing.Point(328, 13);
|
this.groupBox2.Location = new System.Drawing.Point(328, 13);
|
||||||
this.groupBox2.Name = "groupBox2";
|
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.TabIndex = 3;
|
||||||
this.groupBox2.TabStop = false;
|
this.groupBox2.TabStop = false;
|
||||||
this.groupBox2.Text = "Fbx";
|
this.groupBox2.Text = "Fbx";
|
||||||
@ -655,7 +693,7 @@
|
|||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.CancelButton = this.Cancel;
|
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.l2dGroupBox);
|
||||||
this.Controls.Add(this.groupBox2);
|
this.Controls.Add(this.groupBox2);
|
||||||
this.Controls.Add(this.groupBox1);
|
this.Controls.Add(this.groupBox1);
|
||||||
@ -735,5 +773,8 @@
|
|||||||
private System.Windows.Forms.NumericUpDown parallelExportUpDown;
|
private System.Windows.Forms.NumericUpDown parallelExportUpDown;
|
||||||
private System.Windows.Forms.CheckBox parallelExportCheckBox;
|
private System.Windows.Forms.CheckBox parallelExportCheckBox;
|
||||||
private System.Windows.Forms.Label parallelExportMaxLabel;
|
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();
|
InitializeComponent();
|
||||||
assetGroupOptions.SelectedIndex = Properties.Settings.Default.assetGroupOption;
|
assetGroupOptions.SelectedIndex = Properties.Settings.Default.assetGroupOption;
|
||||||
|
filenameFormatComboBox.SelectedIndex = Properties.Settings.Default.filenameFormat;
|
||||||
restoreExtensionName.Checked = Properties.Settings.Default.restoreExtensionName;
|
restoreExtensionName.Checked = Properties.Settings.Default.restoreExtensionName;
|
||||||
converttexture.Checked = Properties.Settings.Default.convertTexture;
|
converttexture.Checked = Properties.Settings.Default.convertTexture;
|
||||||
exportSpriteWithAlphaMask.Checked = Properties.Settings.Default.exportSpriteWithMask;
|
exportSpriteWithAlphaMask.Checked = Properties.Settings.Default.exportSpriteWithMask;
|
||||||
@ -18,6 +19,12 @@ namespace AssetStudioGUI
|
|||||||
var defaultImageType = Properties.Settings.Default.convertType.ToString();
|
var defaultImageType = Properties.Settings.Default.convertType.ToString();
|
||||||
((RadioButton)panel1.Controls.Cast<Control>().First(x => x.Text == defaultImageType)).Checked = true;
|
((RadioButton)panel1.Controls.Cast<Control>().First(x => x.Text == defaultImageType)).Checked = true;
|
||||||
openAfterExport.Checked = Properties.Settings.Default.openAfterExport;
|
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;
|
eulerFilter.Checked = Properties.Settings.Default.eulerFilter;
|
||||||
filterPrecision.Value = Properties.Settings.Default.filterPrecision;
|
filterPrecision.Value = Properties.Settings.Default.filterPrecision;
|
||||||
exportAllNodes.Checked = Properties.Settings.Default.exportAllNodes;
|
exportAllNodes.Checked = Properties.Settings.Default.exportAllNodes;
|
||||||
@ -30,21 +37,17 @@ namespace AssetStudioGUI
|
|||||||
scaleFactor.Value = Properties.Settings.Default.scaleFactor;
|
scaleFactor.Value = Properties.Settings.Default.scaleFactor;
|
||||||
fbxVersion.SelectedIndex = Properties.Settings.Default.fbxVersion;
|
fbxVersion.SelectedIndex = Properties.Settings.Default.fbxVersion;
|
||||||
fbxFormat.SelectedIndex = Properties.Settings.Default.fbxFormat;
|
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();
|
var defaultMotionMode = Properties.Settings.Default.l2dMotionMode.ToString();
|
||||||
((RadioButton)l2dMotionExportMethodPanel.Controls.Cast<Control>().First(x => x.AccessibleName == defaultMotionMode)).Checked = true;
|
((RadioButton)l2dMotionExportMethodPanel.Controls.Cast<Control>().First(x => x.AccessibleName == defaultMotionMode)).Checked = true;
|
||||||
l2dForceBezierCheckBox.Checked = Properties.Settings.Default.l2dForceBezier;
|
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)
|
private void OKbutton_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Properties.Settings.Default.assetGroupOption = assetGroupOptions.SelectedIndex;
|
Properties.Settings.Default.assetGroupOption = assetGroupOptions.SelectedIndex;
|
||||||
|
Properties.Settings.Default.filenameFormat = filenameFormatComboBox.SelectedIndex;
|
||||||
Properties.Settings.Default.restoreExtensionName = restoreExtensionName.Checked;
|
Properties.Settings.Default.restoreExtensionName = restoreExtensionName.Checked;
|
||||||
Properties.Settings.Default.convertTexture = converttexture.Checked;
|
Properties.Settings.Default.convertTexture = converttexture.Checked;
|
||||||
Properties.Settings.Default.exportSpriteWithMask = exportSpriteWithAlphaMask.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);
|
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.convertType = (ImageFormat)Enum.Parse(typeof(ImageFormat), checkedImageType.Text);
|
||||||
Properties.Settings.Default.openAfterExport = openAfterExport.Checked;
|
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.eulerFilter = eulerFilter.Checked;
|
||||||
Properties.Settings.Default.filterPrecision = filterPrecision.Value;
|
Properties.Settings.Default.filterPrecision = filterPrecision.Value;
|
||||||
Properties.Settings.Default.exportAllNodes = exportAllNodes.Checked;
|
Properties.Settings.Default.exportAllNodes = exportAllNodes.Checked;
|
||||||
@ -64,12 +69,11 @@ namespace AssetStudioGUI
|
|||||||
Properties.Settings.Default.scaleFactor = scaleFactor.Value;
|
Properties.Settings.Default.scaleFactor = scaleFactor.Value;
|
||||||
Properties.Settings.Default.fbxVersion = fbxVersion.SelectedIndex;
|
Properties.Settings.Default.fbxVersion = fbxVersion.SelectedIndex;
|
||||||
Properties.Settings.Default.fbxFormat = fbxFormat.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);
|
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.l2dMotionMode = (CubismLive2DExtractor.Live2DMotionMode)Enum.Parse(typeof(CubismLive2DExtractor.Live2DMotionMode), checkedMotionMode.AccessibleName);
|
||||||
Properties.Settings.Default.l2dForceBezier = l2dForceBezierCheckBox.Checked;
|
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();
|
Properties.Settings.Default.Save();
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
Close();
|
Close();
|
||||||
|
@ -120,7 +120,4 @@
|
|||||||
<metadata name="optionTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="optionTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>17, 17</value>
|
<value>17, 17</value>
|
||||||
</metadata>
|
</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>
|
</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;
|
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">
|
<Setting Name="guiColorTheme" Type="AssetStudioGUI.GuiColorTheme" Scope="User">
|
||||||
<Value Profile="(Default)">Light</Value>
|
<Value Profile="(Default)">Light</Value>
|
||||||
</Setting>
|
</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>
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
@ -3,6 +3,7 @@ using CubismLive2DExtractor;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -84,8 +85,8 @@ namespace AssetStudioGUI
|
|||||||
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
|
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
|
||||||
public static List<AssetItem> exportableAssets = new List<AssetItem>();
|
public static List<AssetItem> exportableAssets = new List<AssetItem>();
|
||||||
public static List<AssetItem> visibleAssets = new List<AssetItem>();
|
public static List<AssetItem> visibleAssets = new List<AssetItem>();
|
||||||
public static List<MonoBehaviour> cubismMocList = new List<MonoBehaviour>();
|
public static Dictionary<MonoBehaviour, CubismModel> l2dModelDict = new Dictionary<MonoBehaviour, CubismModel>();
|
||||||
private static Dictionary<Object, string> l2dResourceContainers = new Dictionary<Object, string>();
|
private static Dictionary<Object, string> l2dAssetContainers = new Dictionary<Object, string>();
|
||||||
internal static Action<string> StatusStripUpdate = x => { };
|
internal static Action<string> StatusStripUpdate = x => { };
|
||||||
|
|
||||||
public static int ExtractFolder(string path, string savePath)
|
public static int ExtractFolder(string path, string savePath)
|
||||||
@ -189,7 +190,8 @@ namespace AssetStudioGUI
|
|||||||
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
|
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
|
||||||
var containers = new List<(PPtr<Object>, string)>();
|
var containers = new List<(PPtr<Object>, string)>();
|
||||||
var tex2dArrayAssetList = new List<AssetItem>();
|
var tex2dArrayAssetList = new List<AssetItem>();
|
||||||
l2dResourceContainers.Clear();
|
var l2dSearchByFilename = Properties.Settings.Default.l2dAssetSearchByFilename;
|
||||||
|
l2dAssetContainers.Clear();
|
||||||
var i = 0;
|
var i = 0;
|
||||||
Progress.Reset();
|
Progress.Reset();
|
||||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||||
@ -209,6 +211,14 @@ namespace AssetStudioGUI
|
|||||||
break;
|
break;
|
||||||
case GameObject m_GameObject:
|
case GameObject m_GameObject:
|
||||||
assetItem.Text = m_GameObject.m_Name;
|
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;
|
break;
|
||||||
case Texture2D m_Texture2D:
|
case Texture2D m_Texture2D:
|
||||||
if (!string.IsNullOrEmpty(m_Texture2D.m_StreamData?.path))
|
if (!string.IsNullOrEmpty(m_Texture2D.m_StreamData?.path))
|
||||||
@ -260,9 +270,26 @@ namespace AssetStudioGUI
|
|||||||
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||||
{
|
{
|
||||||
assetName = assetName == "" ? m_Script.m_ClassName : assetName;
|
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;
|
assetItem.Text = assetName;
|
||||||
@ -319,11 +346,18 @@ namespace AssetStudioGUI
|
|||||||
objectAssetItemDic[obj].Container = container;
|
objectAssetItemDic[obj].Container = container;
|
||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
|
case GameObject m_GameObject:
|
||||||
|
if (m_GameObject.CubismModel != null)
|
||||||
|
{
|
||||||
|
m_GameObject.CubismModel.Container = container;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case AnimationClip _:
|
case AnimationClip _:
|
||||||
case GameObject _:
|
|
||||||
case Texture2D _:
|
case Texture2D _:
|
||||||
case MonoBehaviour _:
|
case MonoBehaviour _:
|
||||||
l2dResourceContainers[obj] = container;
|
l2dAssetContainers[obj] = l2dSearchByFilename
|
||||||
|
? Path.GetFileName(obj.assetsFile.originalPath)
|
||||||
|
: container;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -943,105 +977,239 @@ namespace AssetStudioGUI
|
|||||||
Process.Start(info);
|
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)
|
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 baseDestPath = Path.Combine(exportPath, "Live2DOutput");
|
||||||
var forceBezier = Properties.Settings.Default.l2dForceBezier;
|
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;
|
var motionMode = Properties.Settings.Default.l2dMotionMode;
|
||||||
if (selClipMotions != null)
|
if (selClipMotions != null)
|
||||||
motionMode = Live2DMotionMode.AnimationClipV2;
|
motionMode = Live2DMotionMode.AnimationClipV2;
|
||||||
else if (selFadeMotions != null || selFadeLst != null)
|
else if (selFadeMotions != null || selFadeLst != null)
|
||||||
motionMode = Live2DMotionMode.MonoBehaviour;
|
motionMode = Live2DMotionMode.MonoBehaviour;
|
||||||
|
var mocDict = selMocs != null
|
||||||
|
? selMocs.ToDictionary(moc => moc, moc => l2dModelDict[moc])
|
||||||
|
: l2dModelDict;
|
||||||
|
|
||||||
ThreadPool.QueueUserWorkItem(state =>
|
ThreadPool.QueueUserWorkItem(state =>
|
||||||
{
|
{
|
||||||
Logger.Info($"Searching for Live2D files...");
|
Logger.Info("Searching for Live2D assets...");
|
||||||
|
|
||||||
var mocPathDict = new Dictionary<MonoBehaviour, (string, string)>();
|
var useFullContainerPath = true;
|
||||||
var mocPathList = new List<string>();
|
var mocPathList = GenerateMocPathList(mocDict, searchByFilename, ref useFullContainerPath);
|
||||||
foreach (var mocMonoBehaviour in cubismMocList)
|
|
||||||
|
#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))
|
var result = mocPathList.Find(mocPath =>
|
||||||
continue;
|
{
|
||||||
|
if (!container.Contains(mocPath))
|
||||||
var pathSepIndex = fullContainerPath.LastIndexOf('/');
|
return false;
|
||||||
var basePath = pathSepIndex > 0
|
var mocPathSpan = mocPath.AsSpan();
|
||||||
? fullContainerPath.Substring(0, pathSepIndex)
|
var mocPathLastSlice = mocPathSpan[(mocPathSpan.LastIndexOf('/') + 1)..];
|
||||||
: fullContainerPath;
|
foreach (var range in container.AsSpan().Split('/'))
|
||||||
mocPathDict.Add(mocMonoBehaviour, (fullContainerPath, basePath));
|
{
|
||||||
|
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)
|
#else
|
||||||
{
|
var assetDict = l2dAssetContainers.AsParallel().ToLookup(
|
||||||
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(
|
|
||||||
x => mocPathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
x => mocPathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
||||||
x => x.Key
|
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");
|
Logger.Warning("Specifying the assembly folder may be needed for proper extraction");
|
||||||
SelectAssemblyFolder();
|
SelectAssemblyFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalModelCount = lookup.LongCount(x => x.Key != null);
|
var totalModelCount = assetDict.Count;
|
||||||
var modelCounter = 0;
|
var modelCounter = 0;
|
||||||
var parallelExportCount = Properties.Settings.Default.parallelExportCount <= 0
|
var parallelExportCount = Properties.Settings.Default.parallelExportCount <= 0
|
||||||
? Environment.ProcessorCount - 1
|
? Environment.ProcessorCount - 1
|
||||||
: Math.Min(Properties.Settings.Default.parallelExportCount, Environment.ProcessorCount - 1);
|
: Math.Min(Properties.Settings.Default.parallelExportCount, Environment.ProcessorCount - 1);
|
||||||
parallelExportCount = Properties.Settings.Default.parallelExport ? parallelExportCount : 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;
|
var srcContainer = assetKvp.Key;
|
||||||
if (srcContainer == null)
|
|
||||||
continue;
|
|
||||||
var container = srcContainer;
|
|
||||||
|
|
||||||
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{srcContainer}\"...");
|
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{srcContainer}\"...");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var modelName = useFullContainerPath
|
var cubismExtractor = new Live2DExtractor(assetKvp.Value, selClipMotions, selFadeMotions, selFadeLst);
|
||||||
? Path.GetFileNameWithoutExtension(container)
|
string modelPath;
|
||||||
: container.Substring(container.LastIndexOf('/') + 1);
|
if (modelGroupOption == Live2DModelGroupOption.SourceFileName)
|
||||||
container = Path.HasExtension(container)
|
{
|
||||||
? container.Replace(Path.GetExtension(container), "")
|
modelPath = Path.GetFileNameWithoutExtension(cubismExtractor.MocMono.assetsFile.originalPath);
|
||||||
: container;
|
}
|
||||||
var destPath = Path.Combine(baseDestPath, container) + Path.DirectorySeparatorChar;
|
else
|
||||||
|
{
|
||||||
|
var container = searchByFilename && cubismExtractor.Model != null
|
||||||
|
? cubismExtractor.Model.Container
|
||||||
|
: srcContainer;
|
||||||
|
modelPath = Path.HasExtension(container)
|
||||||
|
? container.Replace(Path.GetExtension(container), "")
|
||||||
|
: container;
|
||||||
|
}
|
||||||
|
|
||||||
var modelExtractor = new Live2DExtractor(assets, selClipMotions, selFadeMotions, selFadeLst);
|
var destPath = Path.Combine(baseDestPath, modelPath) + Path.DirectorySeparatorChar;
|
||||||
modelExtractor.ExtractCubismModel(destPath, modelName, motionMode, assemblyLoader, forceBezier, parallelExportCount);
|
cubismExtractor.ExtractCubismModel(destPath, motionMode, forceBezier, parallelExportCount);
|
||||||
modelCounter++;
|
modelCounter++;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error($"Live2D model export error: \"{srcContainer}\"", 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).");
|
Logger.Info($"Finished exporting [{modelCounter}/{totalModelCount}] Live2D model(s).");
|
||||||
if (modelCounter < totalModelCount)
|
Progress.Report(1, 1);
|
||||||
{
|
|
||||||
var total = (int)totalModelCount;
|
|
||||||
Progress.Report(total, total);
|
|
||||||
}
|
|
||||||
if (Properties.Settings.Default.openAfterExport && modelCounter > 0)
|
if (Properties.Settings.Default.openAfterExport && modelCounter > 0)
|
||||||
{
|
{
|
||||||
OpenFolderInExplorer(exportPath);
|
OpenFolderInExplorer(exportPath);
|
||||||
|
9
AssetStudioUtility/CubismLive2DExtractor/BlendType.cs
Normal file
9
AssetStudioUtility/CubismLive2DExtractor/BlendType.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace CubismLive2DExtractor
|
||||||
|
{
|
||||||
|
public enum BlendType
|
||||||
|
{
|
||||||
|
Add,
|
||||||
|
Multiply,
|
||||||
|
Overwrite,
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +1,17 @@
|
|||||||
namespace CubismLive2DExtractor
|
namespace CubismLive2DExtractor
|
||||||
{
|
{
|
||||||
public enum BlendType
|
|
||||||
{
|
|
||||||
Add,
|
|
||||||
Multiply,
|
|
||||||
Overwrite,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CubismExpression3Json
|
public class CubismExpression3Json
|
||||||
{
|
{
|
||||||
public string Type;
|
public string Type { get; set; }
|
||||||
public float FadeInTime;
|
public float FadeInTime { get; set; }
|
||||||
public float FadeOutTime;
|
public float FadeOutTime { get; set; }
|
||||||
public SerializableExpressionParameter[] Parameters;
|
public SerializableExpressionParameter[] Parameters { get; set; }
|
||||||
|
|
||||||
public class SerializableExpressionParameter
|
public class SerializableExpressionParameter
|
||||||
{
|
{
|
||||||
public string Id;
|
public string Id { get; set; }
|
||||||
public float Value;
|
public float Value { get; set; }
|
||||||
public BlendType Blend;
|
public BlendType Blend { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace CubismLive2DExtractor
|
|
||||||
{
|
|
||||||
public sealed class AnimationCurve
|
|
||||||
{
|
|
||||||
public CubismKeyframeData[] m_Curve { get; set; }
|
|
||||||
public int m_PreInfinity { get; set; }
|
|
||||||
public int m_PostInfinity { get; set; }
|
|
||||||
public int m_RotationOrder { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class CubismFadeMotion
|
|
||||||
{
|
|
||||||
public string m_Name { get; set; }
|
|
||||||
public string MotionName { get; set; }
|
|
||||||
public float FadeInTime { get; set; }
|
|
||||||
public float FadeOutTime { get; set; }
|
|
||||||
public string[] ParameterIds { get; set; }
|
|
||||||
public AnimationCurve[] ParameterCurves { get; set; }
|
|
||||||
public float[] ParameterFadeInTimes { get; set; }
|
|
||||||
public float[] ParameterFadeOutTimes { get; set; }
|
|
||||||
public float MotionLength { get; set; }
|
|
||||||
|
|
||||||
public CubismFadeMotion()
|
|
||||||
{
|
|
||||||
ParameterIds = Array.Empty<string>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
namespace CubismLive2DExtractor
|
|
||||||
{
|
|
||||||
public class CubismKeyframeData
|
|
||||||
{
|
|
||||||
public float time { get; set; }
|
|
||||||
public float value { get; set; }
|
|
||||||
public float inSlope { get; set; }
|
|
||||||
public float outSlope { get; set; }
|
|
||||||
public int weightedMode { get; set; }
|
|
||||||
public float inWeight { get; set; }
|
|
||||||
public float outWeight { get; set; }
|
|
||||||
|
|
||||||
public CubismKeyframeData() { }
|
|
||||||
|
|
||||||
public CubismKeyframeData(ImportedKeyframe<float> keyframe)
|
|
||||||
{
|
|
||||||
time = keyframe.time;
|
|
||||||
value = keyframe.value;
|
|
||||||
inSlope = keyframe.inSlope;
|
|
||||||
outSlope = keyframe.outSlope;
|
|
||||||
weightedMode = 0;
|
|
||||||
inWeight = 0;
|
|
||||||
outWeight = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using AssetStudio;
|
||||||
|
|
||||||
namespace CubismLive2DExtractor
|
namespace CubismLive2DExtractor
|
||||||
{
|
{
|
||||||
@ -45,9 +46,9 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void AddSegments(
|
private static void AddSegments(
|
||||||
CubismKeyframeData curve,
|
Keyframe<float> curve,
|
||||||
CubismKeyframeData preCurve,
|
Keyframe<float> preCurve,
|
||||||
CubismKeyframeData nextCurve,
|
Keyframe<float> nextCurve,
|
||||||
SerializableCurve cubismCurve,
|
SerializableCurve cubismCurve,
|
||||||
bool forceBezier,
|
bool forceBezier,
|
||||||
ref int totalPointCount,
|
ref int totalPointCount,
|
||||||
@ -97,7 +98,7 @@ namespace CubismLive2DExtractor
|
|||||||
totalSegmentCount++;
|
totalSegmentCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CubismMotion3Json(CubismFadeMotion fadeMotion, HashSet<string> paramNames, HashSet<string> partNames, bool forceBezier)
|
public CubismMotion3Json(CubismUnityClasses.CubismFadeMotionData fadeMotion, HashSet<string> paramNames, HashSet<string> partNames, bool forceBezier)
|
||||||
{
|
{
|
||||||
Version = 3;
|
Version = 3;
|
||||||
Meta = new SerializableMeta
|
Meta = new SerializableMeta
|
||||||
@ -151,7 +152,7 @@ namespace CubismLive2DExtractor
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
target = paramId.ToLower().Contains("part") ? "PartOpacity" : "Parameter";
|
target = paramId.ToLower().Contains("part") ? "PartOpacity" : "Parameter";
|
||||||
AssetStudio.Logger.Warning($"[{fadeMotion.m_Name}] Binding error: Unable to find \"{paramId}\" among the model parts/parameters");
|
Logger.Warning($"[{fadeMotion.m_Name}] Binding error: Unable to find \"{paramId}\" among the model parts/parameters");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -178,7 +179,7 @@ namespace CubismLive2DExtractor
|
|||||||
var curve = fadeMotion.ParameterCurves[i].m_Curve[j];
|
var curve = fadeMotion.ParameterCurves[i].m_Curve[j];
|
||||||
var preCurve = fadeMotion.ParameterCurves[i].m_Curve[j - 1];
|
var preCurve = fadeMotion.ParameterCurves[i].m_Curve[j - 1];
|
||||||
var next = fadeMotion.ParameterCurves[i].m_Curve.ElementAtOrDefault(j + 1);
|
var next = fadeMotion.ParameterCurves[i].m_Curve.ElementAtOrDefault(j + 1);
|
||||||
var nextCurve = next ?? new CubismKeyframeData();
|
var nextCurve = next ?? new Keyframe<float>();
|
||||||
AddSegments(curve, preCurve, nextCurve, Curves[actualCurveCount], forceBezier, ref totalPointCount, ref totalSegmentCount, ref j);
|
AddSegments(curve, preCurve, nextCurve, Curves[actualCurveCount], forceBezier, ref totalPointCount, ref totalSegmentCount, ref j);
|
||||||
}
|
}
|
||||||
actualCurveCount++;
|
actualCurveCount++;
|
||||||
@ -230,10 +231,10 @@ namespace CubismLive2DExtractor
|
|||||||
};
|
};
|
||||||
for (var j = 1; j < track.Curve.Count; j++)
|
for (var j = 1; j < track.Curve.Count; j++)
|
||||||
{
|
{
|
||||||
var curve = new CubismKeyframeData(track.Curve[j]);
|
var curve = CreateKeyFrame(track.Curve[j]);
|
||||||
var preCurve = new CubismKeyframeData(track.Curve[j - 1]);
|
var preCurve = CreateKeyFrame(track.Curve[j - 1]);
|
||||||
var next = track.Curve.ElementAtOrDefault(j + 1);
|
var next = track.Curve.ElementAtOrDefault(j + 1);
|
||||||
var nextCurve = next != null ? new CubismKeyframeData(next) : new CubismKeyframeData();
|
var nextCurve = next != null ? CreateKeyFrame(next) : new Keyframe<float>();
|
||||||
AddSegments(curve, preCurve, nextCurve, Curves[i], forceBezier, ref totalPointCount, ref totalSegmentCount, ref j);
|
AddSegments(curve, preCurve, nextCurve, Curves[i], forceBezier, ref totalPointCount, ref totalSegmentCount, ref j);
|
||||||
}
|
}
|
||||||
totalPointCount++;
|
totalPointCount++;
|
||||||
@ -255,5 +256,19 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
Meta.TotalUserDataSize = totalUserDataSize;
|
Meta.TotalUserDataSize = totalUserDataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Keyframe<float> CreateKeyFrame(ImportedKeyframe<float> iKeyframe)
|
||||||
|
{
|
||||||
|
return new Keyframe<float>
|
||||||
|
{
|
||||||
|
time = iKeyframe.time,
|
||||||
|
value = iKeyframe.value,
|
||||||
|
inSlope = iKeyframe.inSlope,
|
||||||
|
outSlope = iKeyframe.outSlope,
|
||||||
|
weightedMode = 0,
|
||||||
|
inWeight = 0,
|
||||||
|
outWeight = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using AssetStudio;
|
|
||||||
|
|
||||||
namespace CubismLive2DExtractor
|
|
||||||
{
|
|
||||||
public sealed class CubismObjectList
|
|
||||||
{
|
|
||||||
public static SerializedFile AssetsFile { get; set; }
|
|
||||||
public HashSet<ObjectData> CubismExpressionObjects { get; set; }
|
|
||||||
public HashSet<ObjectData> CubismFadeMotionObjects { get; set; }
|
|
||||||
|
|
||||||
public class ObjectData
|
|
||||||
{
|
|
||||||
private long _pathID;
|
|
||||||
public Object Asset { get; set; }
|
|
||||||
public int m_FileID { get; set; }
|
|
||||||
public long m_PathID
|
|
||||||
{
|
|
||||||
get => _pathID;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_pathID = value;
|
|
||||||
Asset = GetObjByPathID(_pathID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj is ObjectData objectData && _pathID == objectData.m_PathID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return _pathID.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MonoBehaviour> GetFadeMotionAssetList()
|
|
||||||
{
|
|
||||||
return CubismFadeMotionObjects?.Where(x => x.Asset != null).Select(x => (MonoBehaviour)x.Asset).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MonoBehaviour> GetExpressionList()
|
|
||||||
{
|
|
||||||
return CubismExpressionObjects?.Where(x => x.Asset != null).Select(x => (MonoBehaviour)x.Asset).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Object GetObjByPathID(long pathID)
|
|
||||||
{
|
|
||||||
var assetFileList = AssetsFile.assetsManager.assetsFileList;
|
|
||||||
foreach (var assetFile in assetFileList)
|
|
||||||
{
|
|
||||||
if (assetFile.ObjectsDic.TryGetValue(pathID, out var obj))
|
|
||||||
{
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AssetStudio;
|
using AssetStudio;
|
||||||
|
using CubismLive2DExtractor.CubismUnityClasses;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace CubismLive2DExtractor
|
namespace CubismLive2DExtractor
|
||||||
@ -10,20 +11,25 @@ namespace CubismLive2DExtractor
|
|||||||
{
|
{
|
||||||
public enum CubismMonoBehaviourType
|
public enum CubismMonoBehaviourType
|
||||||
{
|
{
|
||||||
|
FadeController,
|
||||||
FadeMotionList,
|
FadeMotionList,
|
||||||
FadeMotion,
|
FadeMotion,
|
||||||
|
ExpressionController,
|
||||||
|
ExpressionList,
|
||||||
Expression,
|
Expression,
|
||||||
Physics,
|
Physics,
|
||||||
DisplayInfo,
|
DisplayInfo,
|
||||||
PosePart,
|
PosePart,
|
||||||
|
Model,
|
||||||
|
RenderTexture,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ParsePhysics(OrderedDictionary physicsDict)
|
public static string ParsePhysics(OrderedDictionary physicsDict, float motionFps)
|
||||||
{
|
{
|
||||||
var cubismPhysicsRig = JsonConvert.DeserializeObject<CubismPhysics>(JsonConvert.SerializeObject(physicsDict))._rig;
|
var cubismPhysicsRig = JsonConvert.DeserializeObject<CubismPhysics>(JsonConvert.SerializeObject(physicsDict)).Rig;
|
||||||
|
|
||||||
var physicsSettings = new CubismPhysics3Json.SerializablePhysicsSettings[cubismPhysicsRig.SubRigs.Length];
|
var physicsSettings = new CubismPhysics3Json.SerializablePhysicsSettings[cubismPhysicsRig.SubRigs.Length];
|
||||||
for (int i = 0; i < physicsSettings.Length; i++)
|
for (var i = 0; i < physicsSettings.Length; i++)
|
||||||
{
|
{
|
||||||
var subRigs = cubismPhysicsRig.SubRigs[i];
|
var subRigs = cubismPhysicsRig.SubRigs[i];
|
||||||
physicsSettings[i] = new CubismPhysics3Json.SerializablePhysicsSettings
|
physicsSettings[i] = new CubismPhysics3Json.SerializablePhysicsSettings
|
||||||
@ -48,7 +54,7 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for (int j = 0; j < subRigs.Input.Length; j++)
|
for (var j = 0; j < subRigs.Input.Length; j++)
|
||||||
{
|
{
|
||||||
var input = subRigs.Input[j];
|
var input = subRigs.Input[j];
|
||||||
physicsSettings[i].Input[j] = new CubismPhysics3Json.SerializableInput
|
physicsSettings[i].Input[j] = new CubismPhysics3Json.SerializableInput
|
||||||
@ -63,7 +69,7 @@ namespace CubismLive2DExtractor
|
|||||||
Reflect = input.IsInverted
|
Reflect = input.IsInverted
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
for (int j = 0; j < subRigs.Output.Length; j++)
|
for (var j = 0; j < subRigs.Output.Length; j++)
|
||||||
{
|
{
|
||||||
var output = subRigs.Output[j];
|
var output = subRigs.Output[j];
|
||||||
physicsSettings[i].Output[j] = new CubismPhysics3Json.SerializableOutput
|
physicsSettings[i].Output[j] = new CubismPhysics3Json.SerializableOutput
|
||||||
@ -80,7 +86,7 @@ namespace CubismLive2DExtractor
|
|||||||
Reflect = output.IsInverted
|
Reflect = output.IsInverted
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
for (int j = 0; j < subRigs.Particles.Length; j++)
|
for (var j = 0; j < subRigs.Particles.Length; j++)
|
||||||
{
|
{
|
||||||
var particles = subRigs.Particles[j];
|
var particles = subRigs.Particles[j];
|
||||||
physicsSettings[i].Vertices[j] = new CubismPhysics3Json.SerializableVertex
|
physicsSettings[i].Vertices[j] = new CubismPhysics3Json.SerializableVertex
|
||||||
@ -94,7 +100,7 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var physicsDictionary = new CubismPhysics3Json.SerializablePhysicsDictionary[physicsSettings.Length];
|
var physicsDictionary = new CubismPhysics3Json.SerializablePhysicsDictionary[physicsSettings.Length];
|
||||||
for (int i = 0; i < physicsSettings.Length; i++)
|
for (var i = 0; i < physicsSettings.Length; i++)
|
||||||
{
|
{
|
||||||
physicsDictionary[i] = new CubismPhysics3Json.SerializablePhysicsDictionary
|
physicsDictionary[i] = new CubismPhysics3Json.SerializablePhysicsDictionary
|
||||||
{
|
{
|
||||||
@ -102,6 +108,8 @@ namespace CubismLive2DExtractor
|
|||||||
Name = $"Dummy{i + 1}"
|
Name = $"Dummy{i + 1}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fps = cubismPhysicsRig.Fps == 0 ? motionFps : cubismPhysicsRig.Fps;
|
||||||
var physicsJson = new CubismPhysics3Json
|
var physicsJson = new CubismPhysics3Json
|
||||||
{
|
{
|
||||||
Version = 3,
|
Version = 3,
|
||||||
@ -111,6 +119,7 @@ namespace CubismLive2DExtractor
|
|||||||
TotalInputCount = cubismPhysicsRig.SubRigs.Sum(x => x.Input.Length),
|
TotalInputCount = cubismPhysicsRig.SubRigs.Sum(x => x.Input.Length),
|
||||||
TotalOutputCount = cubismPhysicsRig.SubRigs.Sum(x => x.Output.Length),
|
TotalOutputCount = cubismPhysicsRig.SubRigs.Sum(x => x.Output.Length),
|
||||||
VertexCount = cubismPhysicsRig.SubRigs.Sum(x => x.Particles.Length),
|
VertexCount = cubismPhysicsRig.SubRigs.Sum(x => x.Particles.Length),
|
||||||
|
Fps = fps == 0 ? 30f : fps,
|
||||||
EffectiveForces = new CubismPhysics3Json.SerializableEffectiveForces
|
EffectiveForces = new CubismPhysics3Json.SerializableEffectiveForces
|
||||||
{
|
{
|
||||||
Gravity = cubismPhysicsRig.Gravity,
|
Gravity = cubismPhysicsRig.Gravity,
|
||||||
@ -133,12 +142,21 @@ namespace CubismLive2DExtractor
|
|||||||
var m_Type = m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
|
var m_Type = m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
|
||||||
switch (cubismMonoBehaviourType)
|
switch (cubismMonoBehaviourType)
|
||||||
{
|
{
|
||||||
|
case CubismMonoBehaviourType.FadeController:
|
||||||
|
fieldName = "cubismfademotionlist";
|
||||||
|
break;
|
||||||
case CubismMonoBehaviourType.FadeMotionList:
|
case CubismMonoBehaviourType.FadeMotionList:
|
||||||
fieldName = "cubismfademotionobjects";
|
fieldName = "cubismfademotionobjects";
|
||||||
break;
|
break;
|
||||||
case CubismMonoBehaviourType.FadeMotion:
|
case CubismMonoBehaviourType.FadeMotion:
|
||||||
fieldName = "parameterids";
|
fieldName = "parameterids";
|
||||||
break;
|
break;
|
||||||
|
case CubismMonoBehaviourType.ExpressionController:
|
||||||
|
fieldName = "expressionslist";
|
||||||
|
break;
|
||||||
|
case CubismMonoBehaviourType.ExpressionList:
|
||||||
|
fieldName = "cubismexpressionobjects";
|
||||||
|
break;
|
||||||
case CubismMonoBehaviourType.Expression:
|
case CubismMonoBehaviourType.Expression:
|
||||||
fieldName = "parameters";
|
fieldName = "parameters";
|
||||||
break;
|
break;
|
||||||
@ -151,6 +169,12 @@ namespace CubismLive2DExtractor
|
|||||||
case CubismMonoBehaviourType.PosePart:
|
case CubismMonoBehaviourType.PosePart:
|
||||||
fieldName = "groupindex";
|
fieldName = "groupindex";
|
||||||
break;
|
break;
|
||||||
|
case CubismMonoBehaviourType.Model:
|
||||||
|
fieldName = "_moc";
|
||||||
|
break;
|
||||||
|
case CubismMonoBehaviourType.RenderTexture:
|
||||||
|
fieldName = "_maintexture";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (m_Type.m_Nodes.FindIndex(x => x.m_Name.ToLower() == fieldName) < 0)
|
if (m_Type.m_Nodes.FindIndex(x => x.m_Name.ToLower() == fieldName) < 0)
|
||||||
{
|
{
|
||||||
|
@ -69,6 +69,7 @@ namespace CubismLive2DExtractor
|
|||||||
public int TotalInputCount;
|
public int TotalInputCount;
|
||||||
public int TotalOutputCount;
|
public int TotalOutputCount;
|
||||||
public int VertexCount;
|
public int VertexCount;
|
||||||
|
public float Fps;
|
||||||
public SerializableEffectiveForces EffectiveForces;
|
public SerializableEffectiveForces EffectiveForces;
|
||||||
public SerializablePhysicsDictionary[] PhysicsDictionary;
|
public SerializablePhysicsDictionary[] PhysicsDictionary;
|
||||||
}
|
}
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
using AssetStudio;
|
|
||||||
|
|
||||||
namespace CubismLive2DExtractor
|
|
||||||
{
|
|
||||||
public class CubismPhysicsNormalizationTuplet
|
|
||||||
{
|
|
||||||
public float Maximum;
|
|
||||||
public float Minimum;
|
|
||||||
public float Default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CubismPhysicsNormalization
|
|
||||||
{
|
|
||||||
public CubismPhysicsNormalizationTuplet Position;
|
|
||||||
public CubismPhysicsNormalizationTuplet Angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CubismPhysicsParticle
|
|
||||||
{
|
|
||||||
public Vector2 InitialPosition;
|
|
||||||
public float Mobility;
|
|
||||||
public float Delay;
|
|
||||||
public float Acceleration;
|
|
||||||
public float Radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CubismPhysicsOutput
|
|
||||||
{
|
|
||||||
public string DestinationId;
|
|
||||||
public int ParticleIndex;
|
|
||||||
public Vector2 TranslationScale;
|
|
||||||
public float AngleScale;
|
|
||||||
public float Weight;
|
|
||||||
public CubismPhysicsSourceComponent SourceComponent;
|
|
||||||
public bool IsInverted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum CubismPhysicsSourceComponent
|
|
||||||
{
|
|
||||||
X,
|
|
||||||
Y,
|
|
||||||
Angle,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CubismPhysicsInput
|
|
||||||
{
|
|
||||||
public string SourceId;
|
|
||||||
public Vector2 ScaleOfTranslation;
|
|
||||||
public float AngleScale;
|
|
||||||
public float Weight;
|
|
||||||
public CubismPhysicsSourceComponent SourceComponent;
|
|
||||||
public bool IsInverted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CubismPhysicsSubRig
|
|
||||||
{
|
|
||||||
public CubismPhysicsInput[] Input;
|
|
||||||
public CubismPhysicsOutput[] Output;
|
|
||||||
public CubismPhysicsParticle[] Particles;
|
|
||||||
public CubismPhysicsNormalization Normalization;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CubismPhysicsRig
|
|
||||||
{
|
|
||||||
public CubismPhysicsSubRig[] SubRigs;
|
|
||||||
public Vector2 Gravity = new Vector2(0, -1);
|
|
||||||
public Vector2 Wind;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CubismPhysics
|
|
||||||
{
|
|
||||||
public string m_Name;
|
|
||||||
public CubismPhysicsRig _rig;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,19 @@
|
|||||||
|
using AssetStudio;
|
||||||
|
|
||||||
|
namespace CubismLive2DExtractor.CubismUnityClasses
|
||||||
|
{
|
||||||
|
public sealed class CubismExpressionData : MonoBehaviour
|
||||||
|
{
|
||||||
|
public string Type { get; set; }
|
||||||
|
public float FadeInTime { get; set; }
|
||||||
|
public float FadeOutTime { get; set; }
|
||||||
|
public SerializableExpressionParameter[] Parameters { get; set; }
|
||||||
|
|
||||||
|
public class SerializableExpressionParameter
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public float Value { get; set; }
|
||||||
|
public BlendType Blend { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
using AssetStudio;
|
||||||
|
|
||||||
|
namespace CubismLive2DExtractor.CubismUnityClasses
|
||||||
|
{
|
||||||
|
public sealed class CubismExpressionList : MonoBehaviour
|
||||||
|
{
|
||||||
|
public PPtr<CubismExpressionData>[] CubismExpressionObjects { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using AssetStudio;
|
||||||
|
|
||||||
|
namespace CubismLive2DExtractor.CubismUnityClasses
|
||||||
|
{
|
||||||
|
public sealed class CubismFadeMotionData : MonoBehaviour
|
||||||
|
{
|
||||||
|
public string MotionName { get; set; }
|
||||||
|
public float FadeInTime { get; set; }
|
||||||
|
public float FadeOutTime { get; set; }
|
||||||
|
public string[] ParameterIds { get; set; } = Array.Empty<string>();
|
||||||
|
public AnimationCurve<float>[] ParameterCurves { get; set; }
|
||||||
|
public float[] ParameterFadeInTimes { get; set; }
|
||||||
|
public float[] ParameterFadeOutTimes { get; set; }
|
||||||
|
public float MotionLength { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
using AssetStudio;
|
||||||
|
|
||||||
|
namespace CubismLive2DExtractor.CubismUnityClasses
|
||||||
|
{
|
||||||
|
public sealed class CubismFadeMotionList : MonoBehaviour
|
||||||
|
{
|
||||||
|
public int[] MotionInstanceIds { get; set; }
|
||||||
|
public PPtr<CubismFadeMotionData>[] CubismFadeMotionObjects { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
using AssetStudio;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace CubismLive2DExtractor.CubismUnityClasses
|
||||||
|
{
|
||||||
|
public class CubismPhysicsNormalizationTuplet
|
||||||
|
{
|
||||||
|
public float Maximum { get; set; }
|
||||||
|
public float Minimum { get; set; }
|
||||||
|
public float Default { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CubismPhysicsNormalization
|
||||||
|
{
|
||||||
|
public CubismPhysicsNormalizationTuplet Position { get; set; }
|
||||||
|
public CubismPhysicsNormalizationTuplet Angle { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CubismPhysicsParticle
|
||||||
|
{
|
||||||
|
public Vector2 InitialPosition { get; set; }
|
||||||
|
public float Mobility { get; set; }
|
||||||
|
public float Delay { get; set; }
|
||||||
|
public float Acceleration { get; set; }
|
||||||
|
public float Radius { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CubismPhysicsOutput
|
||||||
|
{
|
||||||
|
public string DestinationId { get; set; }
|
||||||
|
public int ParticleIndex { get; set; }
|
||||||
|
public Vector2 TranslationScale { get; set; }
|
||||||
|
public float AngleScale { get; set; }
|
||||||
|
public float Weight { get; set; }
|
||||||
|
public CubismPhysicsSourceComponent SourceComponent { get; set; }
|
||||||
|
public bool IsInverted { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CubismPhysicsSourceComponent
|
||||||
|
{
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Angle,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CubismPhysicsInput
|
||||||
|
{
|
||||||
|
public string SourceId { get; set; }
|
||||||
|
public Vector2 ScaleOfTranslation { get; set; }
|
||||||
|
public float AngleScale { get; set; }
|
||||||
|
public float Weight { get; set; }
|
||||||
|
public CubismPhysicsSourceComponent SourceComponent { get; set; }
|
||||||
|
public bool IsInverted { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CubismPhysicsSubRig
|
||||||
|
{
|
||||||
|
public CubismPhysicsInput[] Input { get; set; }
|
||||||
|
public CubismPhysicsOutput[] Output { get; set; }
|
||||||
|
public CubismPhysicsParticle[] Particles { get; set; }
|
||||||
|
public CubismPhysicsNormalization Normalization { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CubismPhysicsRig
|
||||||
|
{
|
||||||
|
public CubismPhysicsSubRig[] SubRigs { get; set; }
|
||||||
|
public Vector2 Gravity { get; set; } = new Vector2(0, -1);
|
||||||
|
public Vector2 Wind { get; set; }
|
||||||
|
public float Fps { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class CubismPhysics : MonoBehaviour
|
||||||
|
{
|
||||||
|
[JsonProperty("_rig")]
|
||||||
|
public CubismPhysicsRig Rig { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -6,41 +6,46 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AssetStudio;
|
using AssetStudio;
|
||||||
|
using CubismLive2DExtractor.CubismUnityClasses;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using static CubismLive2DExtractor.CubismParsers;
|
using static CubismLive2DExtractor.CubismParsers;
|
||||||
|
using Object = AssetStudio.Object;
|
||||||
|
|
||||||
namespace CubismLive2DExtractor
|
namespace CubismLive2DExtractor
|
||||||
{
|
{
|
||||||
public sealed class Live2DExtractor
|
public sealed class Live2DExtractor
|
||||||
{
|
{
|
||||||
private List<MonoBehaviour> Expressions { get; set; }
|
public static Dictionary<MonoBehaviour, CubismModel> MocDict { get; set; }
|
||||||
|
public static AssemblyLoader Assembly { get; set; }
|
||||||
|
public CubismModel Model { get; set; }
|
||||||
private List<MonoBehaviour> FadeMotions { get; set; }
|
private List<MonoBehaviour> FadeMotions { get; set; }
|
||||||
private List<GameObject> GameObjects { get; set; }
|
|
||||||
private List<AnimationClip> AnimationClips { get; set; }
|
private List<AnimationClip> AnimationClips { get; set; }
|
||||||
private List<Texture2D> Texture2Ds { get; set; }
|
private List<MonoBehaviour> Expressions { get; set; }
|
||||||
private HashSet<string> EyeBlinkParameters { get; set; }
|
|
||||||
private HashSet<string> LipSyncParameters { get; set; }
|
|
||||||
private HashSet<string> ParameterNames { get; set; }
|
|
||||||
private HashSet<string> PartNames { get; set; }
|
|
||||||
private MonoBehaviour MocMono { get; set; }
|
|
||||||
private MonoBehaviour PhysicsMono { get; set; }
|
|
||||||
private MonoBehaviour FadeMotionLst { get; set; }
|
|
||||||
private List<MonoBehaviour> ParametersCdi { get; set; }
|
private List<MonoBehaviour> ParametersCdi { get; set; }
|
||||||
private List<MonoBehaviour> PartsCdi { get; set; }
|
private List<MonoBehaviour> PartsCdi { get; set; }
|
||||||
private List<MonoBehaviour> PoseParts { get; set; }
|
private List<MonoBehaviour> PoseParts { get; set; }
|
||||||
|
private List<Texture2D> Texture2Ds { get; set; }
|
||||||
|
public MonoBehaviour MocMono { get; set; }
|
||||||
|
private MonoBehaviour PhysicsMono { get; set; }
|
||||||
|
private MonoBehaviour FadeMotionLst { get; set; }
|
||||||
|
private MonoBehaviour ExpressionLst { get; set; }
|
||||||
|
private HashSet<string> ParameterNames { get; set; }
|
||||||
|
private HashSet<string> PartNames { get; set; }
|
||||||
|
private HashSet<string> EyeBlinkParameters { get; set; }
|
||||||
|
private HashSet<string> LipSyncParameters { get; set; }
|
||||||
|
|
||||||
public Live2DExtractor(IGrouping<string, AssetStudio.Object> assets, List<AnimationClip> inClipMotions = null, List<MonoBehaviour> inFadeMotions = null, MonoBehaviour inFadeMotionLst = null)
|
public Live2DExtractor(List<Object> assets, List<AnimationClip> inClipMotions = null, List<MonoBehaviour> inFadeMotions = null, MonoBehaviour inFadeMotionLst = null)
|
||||||
{
|
{
|
||||||
Expressions = new List<MonoBehaviour>();
|
Expressions = new List<MonoBehaviour>();
|
||||||
FadeMotions = inFadeMotions ?? new List<MonoBehaviour>();
|
FadeMotions = inFadeMotions ?? new List<MonoBehaviour>();
|
||||||
AnimationClips = inClipMotions ?? new List<AnimationClip>();
|
AnimationClips = inClipMotions ?? new List<AnimationClip>();
|
||||||
GameObjects = new List<GameObject>();
|
|
||||||
Texture2Ds = new List<Texture2D>();
|
Texture2Ds = new List<Texture2D>();
|
||||||
EyeBlinkParameters = new HashSet<string>();
|
EyeBlinkParameters = new HashSet<string>();
|
||||||
LipSyncParameters = new HashSet<string>();
|
LipSyncParameters = new HashSet<string>();
|
||||||
@ -50,6 +55,12 @@ namespace CubismLive2DExtractor
|
|||||||
ParametersCdi = new List<MonoBehaviour>();
|
ParametersCdi = new List<MonoBehaviour>();
|
||||||
PartsCdi = new List<MonoBehaviour>();
|
PartsCdi = new List<MonoBehaviour>();
|
||||||
PoseParts = new List<MonoBehaviour>();
|
PoseParts = new List<MonoBehaviour>();
|
||||||
|
var renderTextureSet = new HashSet<Texture2D>();
|
||||||
|
var isRenderReadable = true;
|
||||||
|
var searchRenderTextures = true;
|
||||||
|
var searchModelParamCdi = true;
|
||||||
|
var searchModelPartCdi = true;
|
||||||
|
var searchPoseParts = true;
|
||||||
|
|
||||||
Logger.Debug("Sorting model assets..");
|
Logger.Debug("Sorting model assets..");
|
||||||
foreach (var asset in assets)
|
foreach (var asset in assets)
|
||||||
@ -63,12 +74,53 @@ namespace CubismLive2DExtractor
|
|||||||
{
|
{
|
||||||
case "CubismMoc":
|
case "CubismMoc":
|
||||||
MocMono = m_MonoBehaviour;
|
MocMono = m_MonoBehaviour;
|
||||||
|
Model = MocDict[MocMono];
|
||||||
|
if (Model != null)
|
||||||
|
{
|
||||||
|
PhysicsMono = Model.PhysicsController;
|
||||||
|
if (inFadeMotionLst == null && TryGetFadeList(Model.FadeController, out var fadeMono))
|
||||||
|
{
|
||||||
|
FadeMotionLst = inFadeMotionLst = fadeMono;
|
||||||
|
}
|
||||||
|
if (TryGetExpressionList(Model.ExpressionController, out var expressionMono))
|
||||||
|
{
|
||||||
|
ExpressionLst = expressionMono;
|
||||||
|
}
|
||||||
|
if (Model.RenderTextureList.Count > 0)
|
||||||
|
{
|
||||||
|
var renderList = Model.RenderTextureList;
|
||||||
|
foreach (var renderMono in renderList)
|
||||||
|
{
|
||||||
|
if (!TryGetRenderTexture(renderMono, out var tex))
|
||||||
|
break;
|
||||||
|
renderTextureSet.Add(tex);
|
||||||
|
}
|
||||||
|
searchRenderTextures = renderTextureSet.Count == 0;
|
||||||
|
}
|
||||||
|
if (Model.ParamDisplayInfoList.Count > 0)
|
||||||
|
{
|
||||||
|
ParametersCdi = Model.ParamDisplayInfoList;
|
||||||
|
searchModelParamCdi = false;
|
||||||
|
}
|
||||||
|
if (Model.PartDisplayInfoList.Count > 0)
|
||||||
|
{
|
||||||
|
PartsCdi = Model.PartDisplayInfoList;
|
||||||
|
searchModelPartCdi = false;
|
||||||
|
}
|
||||||
|
if (Model.PosePartList.Count > 0)
|
||||||
|
{
|
||||||
|
PoseParts = Model.PosePartList;
|
||||||
|
searchPoseParts = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "CubismPhysicsController":
|
case "CubismPhysicsController":
|
||||||
PhysicsMono = m_MonoBehaviour;
|
if (PhysicsMono == null)
|
||||||
|
PhysicsMono = m_MonoBehaviour;
|
||||||
break;
|
break;
|
||||||
case "CubismExpressionData":
|
case "CubismExpressionData":
|
||||||
Expressions.Add(m_MonoBehaviour);
|
if (ExpressionLst == null)
|
||||||
|
Expressions.Add(m_MonoBehaviour);
|
||||||
break;
|
break;
|
||||||
case "CubismFadeMotionData":
|
case "CubismFadeMotionData":
|
||||||
if (inFadeMotions == null && inFadeMotionLst == null)
|
if (inFadeMotions == null && inFadeMotionLst == null)
|
||||||
@ -107,23 +159,31 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "CubismDisplayInfoParameterName":
|
case "CubismDisplayInfoParameterName":
|
||||||
if (m_MonoBehaviour.m_GameObject.TryGet(out _))
|
if (searchModelParamCdi && m_MonoBehaviour.m_GameObject.TryGet(out _))
|
||||||
{
|
{
|
||||||
ParametersCdi.Add(m_MonoBehaviour);
|
ParametersCdi.Add(m_MonoBehaviour);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "CubismDisplayInfoPartName":
|
case "CubismDisplayInfoPartName":
|
||||||
if (m_MonoBehaviour.m_GameObject.TryGet(out _))
|
if (searchModelPartCdi && m_MonoBehaviour.m_GameObject.TryGet(out _))
|
||||||
{
|
{
|
||||||
PartsCdi.Add(m_MonoBehaviour);
|
PartsCdi.Add(m_MonoBehaviour);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "CubismPosePart":
|
case "CubismPosePart":
|
||||||
if (m_MonoBehaviour.m_GameObject.TryGet(out _))
|
if (searchPoseParts && m_MonoBehaviour.m_GameObject.TryGet(out _))
|
||||||
{
|
{
|
||||||
PoseParts.Add(m_MonoBehaviour);
|
PoseParts.Add(m_MonoBehaviour);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "CubismRenderer":
|
||||||
|
if (searchRenderTextures && isRenderReadable)
|
||||||
|
{
|
||||||
|
isRenderReadable = TryGetRenderTexture(m_MonoBehaviour, out var renderTex);
|
||||||
|
if (isRenderReadable)
|
||||||
|
renderTextureSet.Add(renderTex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -133,41 +193,43 @@ namespace CubismLive2DExtractor
|
|||||||
AnimationClips.Add(m_AnimationClip);
|
AnimationClips.Add(m_AnimationClip);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GameObject m_GameObject:
|
|
||||||
GameObjects.Add(m_GameObject);
|
|
||||||
break;
|
|
||||||
case Texture2D m_Texture2D:
|
case Texture2D m_Texture2D:
|
||||||
Texture2Ds.Add(m_Texture2D);
|
Texture2Ds.Add(m_Texture2D);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (renderTextureSet.Count > 0)
|
||||||
|
{
|
||||||
|
Texture2Ds = renderTextureSet.ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExtractCubismModel(string destPath, string modelName, Live2DMotionMode motionMode, AssemblyLoader assemblyLoader, bool forceBezier = false, int parallelTaskCount = 1)
|
public void ExtractCubismModel(string destPath, Live2DMotionMode motionMode, bool forceBezier = false, int parallelTaskCount = 1)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(destPath);
|
Directory.CreateDirectory(destPath);
|
||||||
|
var modelName = Model?.Name ?? "model";
|
||||||
|
|
||||||
#region moc3
|
#region moc3
|
||||||
using (var cubismModel = new CubismModel(MocMono))
|
using (var cubismMoc = new CubismMoc(MocMono))
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine("Model Stats:");
|
sb.AppendLine("Model Stats:");
|
||||||
sb.AppendLine($"SDK Version: {cubismModel.VersionDescription}");
|
sb.AppendLine($"SDK Version: {cubismMoc.VersionDescription}");
|
||||||
if (cubismModel.Version > 0)
|
if (cubismMoc.Version > 0)
|
||||||
{
|
{
|
||||||
sb.AppendLine($"Canvas Width: {cubismModel.CanvasWidth}");
|
sb.AppendLine($"Canvas Width: {cubismMoc.CanvasWidth}");
|
||||||
sb.AppendLine($"Canvas Height: {cubismModel.CanvasHeight}");
|
sb.AppendLine($"Canvas Height: {cubismMoc.CanvasHeight}");
|
||||||
sb.AppendLine($"Center X: {cubismModel.CentralPosX}");
|
sb.AppendLine($"Center X: {cubismMoc.CentralPosX}");
|
||||||
sb.AppendLine($"Center Y: {cubismModel.CentralPosY}");
|
sb.AppendLine($"Center Y: {cubismMoc.CentralPosY}");
|
||||||
sb.AppendLine($"Pixel Per Unit: {cubismModel.PixelPerUnit}");
|
sb.AppendLine($"Pixel Per Unit: {cubismMoc.PixelPerUnit}");
|
||||||
sb.AppendLine($"Part Count: {cubismModel.PartCount}");
|
sb.AppendLine($"Part Count: {cubismMoc.PartCount}");
|
||||||
sb.AppendLine($"Parameter Count: {cubismModel.ParamCount}");
|
sb.AppendLine($"Parameter Count: {cubismMoc.ParamCount}");
|
||||||
Logger.Debug(sb.ToString());
|
Logger.Debug(sb.ToString());
|
||||||
|
|
||||||
ParameterNames = cubismModel.ParamNames;
|
ParameterNames = cubismMoc.ParamNames;
|
||||||
PartNames = cubismModel.PartNames;
|
PartNames = cubismMoc.PartNames;
|
||||||
}
|
}
|
||||||
cubismModel.SaveMoc3($"{destPath}{modelName}.moc3");
|
cubismMoc.SaveMoc3($"{destPath}{modelName}.moc3");
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -204,34 +266,13 @@ namespace CubismLive2DExtractor
|
|||||||
textures.UnionWith(textureBag);
|
textures.UnionWith(textureBag);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region physics3.json
|
|
||||||
var isPhysicsExported = false;
|
|
||||||
if (PhysicsMono != null)
|
|
||||||
{
|
|
||||||
var physicsDict = ParseMonoBehaviour(PhysicsMono, CubismMonoBehaviourType.Physics, assemblyLoader);
|
|
||||||
if (physicsDict != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var buff = ParsePhysics(physicsDict);
|
|
||||||
File.WriteAllText($"{destPath}{modelName}.physics3.json", buff);
|
|
||||||
isPhysicsExported = true;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Warning($"Error in parsing physics data: {e.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region cdi3.json
|
#region cdi3.json
|
||||||
var isCdiExported = false;
|
var isCdiExported = false;
|
||||||
if (ParametersCdi.Count > 0 || PartsCdi.Count > 0)
|
if (ParametersCdi.Count > 0 || PartsCdi.Count > 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
isCdiExported = ExportCdiJson(destPath, modelName, assemblyLoader);
|
isCdiExported = ExportCdiJson(destPath, modelName);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -243,26 +284,34 @@ namespace CubismLive2DExtractor
|
|||||||
#region motion3.json
|
#region motion3.json
|
||||||
var motions = new SortedDictionary<string, JArray>();
|
var motions = new SortedDictionary<string, JArray>();
|
||||||
var destMotionPath = Path.Combine(destPath, "motions") + Path.DirectorySeparatorChar;
|
var destMotionPath = Path.Combine(destPath, "motions") + Path.DirectorySeparatorChar;
|
||||||
|
var motionFps = 0f;
|
||||||
|
|
||||||
if (motionMode == Live2DMotionMode.MonoBehaviour && FadeMotionLst != null) //Fade motions from Fade Motion List
|
if (motionMode == Live2DMotionMode.MonoBehaviour && FadeMotionLst != null) //Fade motions from Fade Motion List
|
||||||
{
|
{
|
||||||
Logger.Debug("Motion export method: MonoBehaviour (Fade motion)");
|
Logger.Debug("Motion export method: MonoBehaviour (Fade motion)");
|
||||||
var fadeMotionLstDict = ParseMonoBehaviour(FadeMotionLst, CubismMonoBehaviourType.FadeMotionList, assemblyLoader);
|
var fadeMotionLstDict = ParseMonoBehaviour(FadeMotionLst, CubismMonoBehaviourType.FadeMotionList, Assembly);
|
||||||
if (fadeMotionLstDict != null)
|
if (fadeMotionLstDict != null)
|
||||||
{
|
{
|
||||||
CubismObjectList.AssetsFile = FadeMotionLst.assetsFile;
|
var cubismFadeList = JsonConvert.DeserializeObject<CubismFadeMotionList>(JsonConvert.SerializeObject(fadeMotionLstDict));
|
||||||
var fadeMotionAssetList = JsonConvert.DeserializeObject<CubismObjectList>(JsonConvert.SerializeObject(fadeMotionLstDict)).GetFadeMotionAssetList();
|
var fadeMotionAssetList = new List<MonoBehaviour>();
|
||||||
if (fadeMotionAssetList?.Count > 0)
|
foreach (var motionPPtr in cubismFadeList.CubismFadeMotionObjects)
|
||||||
|
{
|
||||||
|
if (motionPPtr.TryGet<MonoBehaviour>(out var fadeMono, FadeMotionLst.assetsFile))
|
||||||
|
{
|
||||||
|
fadeMotionAssetList.Add(fadeMono);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fadeMotionAssetList.Count > 0)
|
||||||
{
|
{
|
||||||
FadeMotions = fadeMotionAssetList;
|
FadeMotions = fadeMotionAssetList;
|
||||||
Logger.Debug($"\"{FadeMotionLst.m_Name}\": found {fadeMotionAssetList.Count} motion(s)");
|
Logger.Debug($"\"{FadeMotionLst.m_Name}\": found {fadeMotionAssetList.Count} motion(s)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (motionMode == Live2DMotionMode.MonoBehaviour && FadeMotions.Count > 0) //motion from MonoBehaviour
|
if (motionMode == Live2DMotionMode.MonoBehaviour && FadeMotions.Count > 0) //motion from MonoBehaviour
|
||||||
{
|
{
|
||||||
ExportFadeMotions(destMotionPath, assemblyLoader, forceBezier, motions);
|
ExportFadeMotions(destMotionPath, forceBezier, motions, ref motionFps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (motions.Count == 0) //motion from AnimationClip
|
if (motions.Count == 0) //motion from AnimationClip
|
||||||
@ -274,16 +323,10 @@ namespace CubismLive2DExtractor
|
|||||||
exportMethod += "V2";
|
exportMethod += "V2";
|
||||||
converter = new CubismMotion3Converter(AnimationClips, PartNames, ParameterNames);
|
converter = new CubismMotion3Converter(AnimationClips, PartNames, ParameterNames);
|
||||||
}
|
}
|
||||||
else if (GameObjects.Count > 0) //AnimationClipV1
|
else if (Model?.ModelGameObject != null) //AnimationClipV1
|
||||||
{
|
{
|
||||||
exportMethod += "V1";
|
exportMethod += "V1";
|
||||||
var rootTransform = GameObjects[0].m_Transform;
|
converter = new CubismMotion3Converter(Model.ModelGameObject, AnimationClips);
|
||||||
while (rootTransform.m_Father.TryGet(out var m_Father))
|
|
||||||
{
|
|
||||||
rootTransform = m_Father;
|
|
||||||
}
|
|
||||||
rootTransform.m_GameObject.TryGet(out var rootGameObject);
|
|
||||||
converter = new CubismMotion3Converter(rootGameObject, AnimationClips);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (motionMode == Live2DMotionMode.MonoBehaviour)
|
if (motionMode == Live2DMotionMode.MonoBehaviour)
|
||||||
@ -294,7 +337,7 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
Logger.Debug($"Motion export method: {exportMethod}");
|
Logger.Debug($"Motion export method: {exportMethod}");
|
||||||
|
|
||||||
ExportClipMotions(destMotionPath, converter, forceBezier, motions);
|
ExportClipMotions(destMotionPath, converter, forceBezier, motions, ref motionFps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (motions.Count == 0)
|
if (motions.Count == 0)
|
||||||
@ -311,6 +354,30 @@ namespace CubismLive2DExtractor
|
|||||||
var expressions = new JArray();
|
var expressions = new JArray();
|
||||||
var destExpressionPath = Path.Combine(destPath, "expressions") + Path.DirectorySeparatorChar;
|
var destExpressionPath = Path.Combine(destPath, "expressions") + Path.DirectorySeparatorChar;
|
||||||
|
|
||||||
|
if (ExpressionLst != null) //Expressions from Expression List
|
||||||
|
{
|
||||||
|
Logger.Debug("Parsing expression list..");
|
||||||
|
var expLstDict = ParseMonoBehaviour(ExpressionLst, CubismMonoBehaviourType.ExpressionList, Assembly);
|
||||||
|
if (expLstDict != null)
|
||||||
|
{
|
||||||
|
var cubismExpList = JsonConvert.DeserializeObject<CubismExpressionList>(JsonConvert.SerializeObject(expLstDict));
|
||||||
|
var expAssetList = new List<MonoBehaviour>();
|
||||||
|
foreach (var expPPtr in cubismExpList.CubismExpressionObjects)
|
||||||
|
{
|
||||||
|
if (expPPtr.TryGet<MonoBehaviour>(out var expMono, ExpressionLst.assetsFile))
|
||||||
|
{
|
||||||
|
expAssetList.Add(expMono);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expAssetList.Count > 0)
|
||||||
|
{
|
||||||
|
Expressions = expAssetList;
|
||||||
|
Logger.Debug($"\"{ExpressionLst.m_Name}\": found {expAssetList.Count} expression(s)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Expressions.Count > 0)
|
if (Expressions.Count > 0)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(destExpressionPath);
|
Directory.CreateDirectory(destExpressionPath);
|
||||||
@ -318,7 +385,7 @@ namespace CubismLive2DExtractor
|
|||||||
foreach (var monoBehaviour in Expressions)
|
foreach (var monoBehaviour in Expressions)
|
||||||
{
|
{
|
||||||
var expressionName = monoBehaviour.m_Name.Replace(".exp3", "");
|
var expressionName = monoBehaviour.m_Name.Replace(".exp3", "");
|
||||||
var expressionDict = ParseMonoBehaviour(monoBehaviour, CubismMonoBehaviourType.Expression, assemblyLoader);
|
var expressionDict = ParseMonoBehaviour(monoBehaviour, CubismMonoBehaviourType.Expression, Assembly);
|
||||||
if (expressionDict == null)
|
if (expressionDict == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -339,7 +406,7 @@ namespace CubismLive2DExtractor
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
isPoseExported = ExportPoseJson(destPath, modelName, assemblyLoader);
|
isPoseExported = ExportPoseJson(destPath, modelName);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -348,6 +415,27 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region physics3.json
|
||||||
|
var isPhysicsExported = false;
|
||||||
|
if (PhysicsMono != null)
|
||||||
|
{
|
||||||
|
var physicsDict = ParseMonoBehaviour(PhysicsMono, CubismMonoBehaviourType.Physics, Assembly);
|
||||||
|
if (physicsDict != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var buff = ParsePhysics(physicsDict, motionFps);
|
||||||
|
File.WriteAllText($"{destPath}{modelName}.physics3.json", buff);
|
||||||
|
isPhysicsExported = true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Warning($"Error in parsing physics data: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region model3.json
|
#region model3.json
|
||||||
var groups = new List<CubismModel3Json.SerializableGroup>();
|
var groups = new List<CubismModel3Json.SerializableGroup>();
|
||||||
|
|
||||||
@ -402,20 +490,21 @@ namespace CubismLive2DExtractor
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExportFadeMotions(string destMotionPath, AssemblyLoader assemblyLoader, bool forceBezier, SortedDictionary<string, JArray> motions)
|
private void ExportFadeMotions(string destMotionPath, bool forceBezier, SortedDictionary<string, JArray> motions, ref float fps)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(destMotionPath);
|
Directory.CreateDirectory(destMotionPath);
|
||||||
foreach (var fadeMotionMono in FadeMotions)
|
foreach (var fadeMotionMono in FadeMotions)
|
||||||
{
|
{
|
||||||
var fadeMotionDict = ParseMonoBehaviour(fadeMotionMono, CubismMonoBehaviourType.FadeMotion, assemblyLoader);
|
var fadeMotionDict = ParseMonoBehaviour(fadeMotionMono, CubismMonoBehaviourType.FadeMotion, Assembly);
|
||||||
if (fadeMotionDict == null)
|
if (fadeMotionDict == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var fadeMotion = JsonConvert.DeserializeObject<CubismFadeMotion>(JsonConvert.SerializeObject(fadeMotionDict));
|
var fadeMotion = JsonConvert.DeserializeObject<CubismFadeMotionData>(JsonConvert.SerializeObject(fadeMotionDict));
|
||||||
if (fadeMotion.ParameterIds.Length == 0)
|
if (fadeMotion.ParameterIds.Length == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var motionJson = new CubismMotion3Json(fadeMotion, ParameterNames, PartNames, forceBezier);
|
var motionJson = new CubismMotion3Json(fadeMotion, ParameterNames, PartNames, forceBezier);
|
||||||
|
fps = motionJson.Meta.Fps;
|
||||||
|
|
||||||
var animName = Path.GetFileNameWithoutExtension(fadeMotion.m_Name);
|
var animName = Path.GetFileNameWithoutExtension(fadeMotion.m_Name);
|
||||||
if (motions.ContainsKey(animName))
|
if (motions.ContainsKey(animName))
|
||||||
@ -430,7 +519,7 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ExportClipMotions(string destMotionPath, CubismMotion3Converter converter, bool forceBezier, SortedDictionary<string, JArray> motions)
|
private static void ExportClipMotions(string destMotionPath, CubismMotion3Converter converter, bool forceBezier, SortedDictionary<string, JArray> motions, ref float fps)
|
||||||
{
|
{
|
||||||
if (converter == null)
|
if (converter == null)
|
||||||
return;
|
return;
|
||||||
@ -448,6 +537,7 @@ namespace CubismLive2DExtractor
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var motionJson = new CubismMotion3Json(animation, forceBezier);
|
var motionJson = new CubismMotion3Json(animation, forceBezier);
|
||||||
|
fps = motionJson.Meta.Fps;
|
||||||
|
|
||||||
if (motions.ContainsKey(animName))
|
if (motions.ContainsKey(animName))
|
||||||
{
|
{
|
||||||
@ -462,12 +552,12 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ExportPoseJson(string destPath, string modelName, AssemblyLoader assemblyLoader)
|
private bool ExportPoseJson(string destPath, string modelName)
|
||||||
{
|
{
|
||||||
var groupDict = new SortedDictionary<int, List<CubismPose3Json.ControlNode>>();
|
var groupDict = new SortedDictionary<int, List<CubismPose3Json.ControlNode>>();
|
||||||
foreach (var posePartMono in PoseParts)
|
foreach (var posePartMono in PoseParts)
|
||||||
{
|
{
|
||||||
var posePartDict = ParseMonoBehaviour(posePartMono, CubismMonoBehaviourType.PosePart, assemblyLoader);
|
var posePartDict = ParseMonoBehaviour(posePartMono, CubismMonoBehaviourType.PosePart, Assembly);
|
||||||
if (posePartDict == null)
|
if (posePartDict == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -507,7 +597,7 @@ namespace CubismLive2DExtractor
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ExportCdiJson(string destPath, string modelName, AssemblyLoader assemblyLoader)
|
private bool ExportCdiJson(string destPath, string modelName)
|
||||||
{
|
{
|
||||||
var cdiJson = new CubismCdi3Json
|
var cdiJson = new CubismCdi3Json
|
||||||
{
|
{
|
||||||
@ -518,7 +608,7 @@ namespace CubismLive2DExtractor
|
|||||||
var parameters = new SortedSet<CubismCdi3Json.ParamGroupArray>();
|
var parameters = new SortedSet<CubismCdi3Json.ParamGroupArray>();
|
||||||
foreach (var paramMono in ParametersCdi)
|
foreach (var paramMono in ParametersCdi)
|
||||||
{
|
{
|
||||||
var displayName = GetDisplayName(paramMono, assemblyLoader);
|
var displayName = GetDisplayName(paramMono);
|
||||||
if (displayName == null)
|
if (displayName == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -536,7 +626,7 @@ namespace CubismLive2DExtractor
|
|||||||
var parts = new SortedSet<CubismCdi3Json.PartArray>();
|
var parts = new SortedSet<CubismCdi3Json.PartArray>();
|
||||||
foreach (var partMono in PartsCdi)
|
foreach (var partMono in PartsCdi)
|
||||||
{
|
{
|
||||||
var displayName = GetDisplayName(partMono, assemblyLoader);
|
var displayName = GetDisplayName(partMono);
|
||||||
if (displayName == null)
|
if (displayName == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -557,9 +647,9 @@ namespace CubismLive2DExtractor
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetDisplayName(MonoBehaviour cdiMono, AssemblyLoader assemblyLoader)
|
private string GetDisplayName(MonoBehaviour cdiMono)
|
||||||
{
|
{
|
||||||
var dict = ParseMonoBehaviour(cdiMono, CubismMonoBehaviourType.DisplayInfo, assemblyLoader);
|
var dict = ParseMonoBehaviour(cdiMono, CubismMonoBehaviourType.DisplayInfo, Assembly);
|
||||||
if (dict == null)
|
if (dict == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -571,5 +661,44 @@ namespace CubismLive2DExtractor
|
|||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool TryGetFadeList(MonoBehaviour m_MonoBehaviour, out MonoBehaviour listMono)
|
||||||
|
{
|
||||||
|
return TryGetAsset(m_MonoBehaviour, CubismMonoBehaviourType.FadeController, "CubismFadeMotionList", out listMono);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetExpressionList(MonoBehaviour m_MonoBehaviour, out MonoBehaviour listMono)
|
||||||
|
{
|
||||||
|
return TryGetAsset(m_MonoBehaviour, CubismMonoBehaviourType.ExpressionController, "ExpressionsList", out listMono);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetRenderTexture(MonoBehaviour m_MonoBehaviour, out Texture2D renderTex)
|
||||||
|
{
|
||||||
|
return TryGetAsset(m_MonoBehaviour, CubismMonoBehaviourType.RenderTexture, "_mainTexture", out renderTex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetAsset<T>(MonoBehaviour m_MonoBehaviour, CubismMonoBehaviourType cubismMonoType, string pptrField, out T result) where T : Object
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
if (m_MonoBehaviour == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var pptrDict = (OrderedDictionary)ParseMonoBehaviour(m_MonoBehaviour, cubismMonoType, Assembly)?[pptrField];
|
||||||
|
if (pptrDict == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var resultPPtr = GeneratePPtr<T>(pptrDict, m_MonoBehaviour.assetsFile);
|
||||||
|
return resultPPtr.TryGet(out result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PPtr<T> GeneratePPtr<T>(OrderedDictionary pptrDict, SerializedFile assetsFile = null) where T : Object
|
||||||
|
{
|
||||||
|
return new PPtr<T>
|
||||||
|
{
|
||||||
|
m_FileID = (int)pptrDict["m_FileID"],
|
||||||
|
m_PathID = (long)pptrDict["m_PathID"],
|
||||||
|
AssetsFile = assetsFile
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
namespace CubismLive2DExtractor
|
||||||
|
{
|
||||||
|
public enum Live2DModelGroupOption
|
||||||
|
{
|
||||||
|
ContainerPath,
|
||||||
|
SourceFileName,
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,45 @@ namespace AssetStudio
|
|||||||
var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, helper, 1);
|
var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, helper, 1);
|
||||||
m_Type.m_Nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNodes());
|
m_Type.m_Nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNodes());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (m_Script.m_ClassName)
|
||||||
|
{
|
||||||
|
case "CubismModel":
|
||||||
|
helper.AddMonoCubismModel(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismMoc":
|
||||||
|
helper.AddMonoCubismMoc(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismFadeController":
|
||||||
|
helper.AddMonoCubismFadeController(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismFadeMotionList":
|
||||||
|
helper.AddMonoCubismFadeList(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismFadeMotionData":
|
||||||
|
helper.AddMonoCubismFadeData(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismExpressionController":
|
||||||
|
helper.AddMonoCubismExpressionController(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismExpressionList":
|
||||||
|
helper.AddMonoCubismExpressionList(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismExpressionData":
|
||||||
|
helper.AddMonoCubismExpressionData(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismDisplayInfoParameterName":
|
||||||
|
helper.AddMonoCubismDisplayInfo(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismDisplayInfoPartName":
|
||||||
|
helper.AddMonoCubismDisplayInfo(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
case "CubismPosePart":
|
||||||
|
helper.AddMonoCubismPosePart(m_Type.m_Nodes, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return m_Type;
|
return m_Type;
|
||||||
}
|
}
|
||||||
|
@ -277,5 +277,100 @@ namespace AssetStudio
|
|||||||
nodes.Add(new TypeTreeNode("PropertyName", name, indent, false));
|
nodes.Add(new TypeTreeNode("PropertyName", name, indent, false));
|
||||||
AddString(nodes, "id", indent + 1);
|
AddString(nodes, "id", indent + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region CubismLive2D
|
||||||
|
public void AddMonoCubismModel(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
AddPPtr(nodes, "CubismMoc", "_moc", indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMonoCubismMoc(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
nodes.Add(new TypeTreeNode("vector", "_bytes", indent, align: true));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
nodes.Add(new TypeTreeNode("UInt8", "data", indent + 2, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMonoCubismPosePart(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
nodes.Add(new TypeTreeNode("int", "GroupIndex", indent, false));
|
||||||
|
nodes.Add(new TypeTreeNode("int", "PartIndex", indent, false));
|
||||||
|
nodes.Add(new TypeTreeNode("vector", "Link", indent, align: false));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
AddString(nodes, "data", indent + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMonoCubismDisplayInfo(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
AddString(nodes, "Name", indent);
|
||||||
|
AddString(nodes, "DisplayName", indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMonoCubismFadeController(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
AddPPtr(nodes, "CubismFadeMotionList", "CubismFadeMotionList", indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMonoCubismFadeList(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
nodes.Add(new TypeTreeNode("vector", "MotionInstanceIds", indent, align: false));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
nodes.Add(new TypeTreeNode("int", "data", indent + 2, align: false));
|
||||||
|
nodes.Add(new TypeTreeNode("vector", "CubismFadeMotionObjects", indent, align: false));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
AddPPtr(nodes, "CubismFadeMotionData", "data", indent + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMonoCubismFadeData(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
AddString(nodes, "MotionName", indent);
|
||||||
|
nodes.Add(new TypeTreeNode("float", "FadeInTime", indent, false));
|
||||||
|
nodes.Add(new TypeTreeNode("float", "FadeOutTime", indent, false));
|
||||||
|
nodes.Add(new TypeTreeNode("vector", "ParameterIds", indent, align: false));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
AddString(nodes, "data", indent + 2);
|
||||||
|
nodes.Add(new TypeTreeNode("vector", "ParameterCurves", indent, align: false));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
AddAnimationCurve(nodes, "data", indent + 2);
|
||||||
|
nodes.Add(new TypeTreeNode("vector", "ParameterFadeInTimes", indent, align: false));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
nodes.Add(new TypeTreeNode("float", "data", indent + 2, align: false));
|
||||||
|
nodes.Add(new TypeTreeNode("vector", "ParameterFadeOutTimes", indent, align: false));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
nodes.Add(new TypeTreeNode("float", "data", indent + 2, align: false));
|
||||||
|
nodes.Add(new TypeTreeNode("float", "MotionLength", indent , align: false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMonoCubismExpressionController(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
AddPPtr(nodes, "CubismExpressionList", "ExpressionsList", indent);
|
||||||
|
nodes.Add(new TypeTreeNode("int", "CurrentExpressionIndex", indent, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMonoCubismExpressionList(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
nodes.Add(new TypeTreeNode("vector", "CubismExpressionObjects", indent, align: false));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
AddPPtr(nodes, "CubismExpressionData", "data", indent + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddMonoCubismExpressionParameter(List<TypeTreeNode> nodes, string name, int indent)
|
||||||
|
{
|
||||||
|
nodes.Add(new TypeTreeNode("SerializableExpressionParameter", name, indent, false));
|
||||||
|
AddString(nodes, "Id", indent + 1);
|
||||||
|
nodes.Add(new TypeTreeNode("float", "Value", indent + 1, false));
|
||||||
|
nodes.Add(new TypeTreeNode("int", "Blend", indent + 1, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMonoCubismExpressionData(List<TypeTreeNode> nodes, int indent)
|
||||||
|
{
|
||||||
|
AddString(nodes, "Type", indent);
|
||||||
|
nodes.Add(new TypeTreeNode("float", "FadeInTime", indent, false));
|
||||||
|
nodes.Add(new TypeTreeNode("float", "FadeOutTime", indent, false));
|
||||||
|
nodes.Add(new TypeTreeNode("SerializableExpressionParameter", "Parameters", indent, align: false));
|
||||||
|
AddArray(nodes, indent + 2);
|
||||||
|
AddMonoCubismExpressionParameter(nodes, "data", indent + 2);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user