v1.00.00
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -93,15 +93,15 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public class SkeletonPose
|
public class SkeletonPose
|
||||||
{
|
{
|
||||||
public xform[] m_X;
|
public XForm[] m_X;
|
||||||
|
|
||||||
public SkeletonPose(ObjectReader reader)
|
public SkeletonPose(ObjectReader reader)
|
||||||
{
|
{
|
||||||
int numXforms = reader.ReadInt32();
|
int numXforms = reader.ReadInt32();
|
||||||
m_X = new xform[numXforms];
|
m_X = new XForm[numXforms];
|
||||||
for (int i = 0; i < numXforms; i++)
|
for (int i = 0; i < numXforms; i++)
|
||||||
{
|
{
|
||||||
m_X[i] = new xform(reader);
|
m_X[i] = reader.ReadXForm(reader.version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,13 +118,13 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public class Handle
|
public class Handle
|
||||||
{
|
{
|
||||||
public xform m_X;
|
public XForm m_X;
|
||||||
public uint m_ParentHumanIndex;
|
public uint m_ParentHumanIndex;
|
||||||
public uint m_ID;
|
public uint m_ID;
|
||||||
|
|
||||||
public Handle(ObjectReader reader)
|
public Handle(ObjectReader reader)
|
||||||
{
|
{
|
||||||
m_X = new xform(reader);
|
m_X = reader.ReadXForm(reader.version);
|
||||||
m_ParentHumanIndex = reader.ReadUInt32();
|
m_ParentHumanIndex = reader.ReadUInt32();
|
||||||
m_ID = reader.ReadUInt32();
|
m_ID = reader.ReadUInt32();
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public class Collider
|
public class Collider
|
||||||
{
|
{
|
||||||
public xform m_X;
|
public XForm m_X;
|
||||||
public uint m_Type;
|
public uint m_Type;
|
||||||
public uint m_XMotionType;
|
public uint m_XMotionType;
|
||||||
public uint m_YMotionType;
|
public uint m_YMotionType;
|
||||||
@@ -144,7 +144,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public Collider(ObjectReader reader)
|
public Collider(ObjectReader reader)
|
||||||
{
|
{
|
||||||
m_X = new xform(reader);
|
m_X = reader.ReadXForm(reader.version);
|
||||||
m_Type = reader.ReadUInt32();
|
m_Type = reader.ReadUInt32();
|
||||||
m_XMotionType = reader.ReadUInt32();
|
m_XMotionType = reader.ReadUInt32();
|
||||||
m_YMotionType = reader.ReadUInt32();
|
m_YMotionType = reader.ReadUInt32();
|
||||||
@@ -158,7 +158,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public class Human
|
public class Human
|
||||||
{
|
{
|
||||||
public xform m_RootX;
|
public XForm m_RootX;
|
||||||
public Skeleton m_Skeleton;
|
public Skeleton m_Skeleton;
|
||||||
public SkeletonPose m_SkeletonPose;
|
public SkeletonPose m_SkeletonPose;
|
||||||
public Hand m_LeftHand;
|
public Hand m_LeftHand;
|
||||||
@@ -183,7 +183,7 @@ namespace AssetStudio
|
|||||||
public Human(ObjectReader reader)
|
public Human(ObjectReader reader)
|
||||||
{
|
{
|
||||||
var version = reader.version;
|
var version = reader.version;
|
||||||
m_RootX = new xform(reader);
|
m_RootX = reader.ReadXForm(reader.version);
|
||||||
m_Skeleton = new Skeleton(reader);
|
m_Skeleton = new Skeleton(reader);
|
||||||
m_SkeletonPose = new SkeletonPose(reader);
|
m_SkeletonPose = new SkeletonPose(reader);
|
||||||
m_LeftHand = new Hand(reader);
|
m_LeftHand = new Hand(reader);
|
||||||
@@ -243,7 +243,7 @@ namespace AssetStudio
|
|||||||
public int[] m_HumanSkeletonIndexArray;
|
public int[] m_HumanSkeletonIndexArray;
|
||||||
public int[] m_HumanSkeletonReverseIndexArray;
|
public int[] m_HumanSkeletonReverseIndexArray;
|
||||||
public int m_RootMotionBoneIndex;
|
public int m_RootMotionBoneIndex;
|
||||||
public xform m_RootMotionBoneX;
|
public XForm m_RootMotionBoneX;
|
||||||
public Skeleton m_RootMotionSkeleton;
|
public Skeleton m_RootMotionSkeleton;
|
||||||
public SkeletonPose m_RootMotionSkeletonPose;
|
public SkeletonPose m_RootMotionSkeletonPose;
|
||||||
public int[] m_RootMotionSkeletonIndexArray;
|
public int[] m_RootMotionSkeletonIndexArray;
|
||||||
@@ -271,7 +271,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_RootMotionBoneIndex = reader.ReadInt32();
|
m_RootMotionBoneIndex = reader.ReadInt32();
|
||||||
m_RootMotionBoneX = new xform(reader);
|
m_RootMotionBoneX = reader.ReadXForm(reader.version);
|
||||||
|
|
||||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public class MeshBlendShape
|
public class MeshBlendShape
|
||||||
{
|
{
|
||||||
|
public string name;
|
||||||
public uint firstVertex;
|
public uint firstVertex;
|
||||||
public uint vertexCount;
|
public uint vertexCount;
|
||||||
public bool hasNormals;
|
public bool hasNormals;
|
||||||
@@ -308,7 +309,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
if (version[0] == 4 && version[1] < 3) //4.3 down
|
if (version[0] == 4 && version[1] < 3) //4.3 down
|
||||||
{
|
{
|
||||||
var name = reader.ReadAlignedString();
|
name = reader.ReadAlignedString();
|
||||||
}
|
}
|
||||||
firstVertex = reader.ReadUInt32();
|
firstVertex = reader.ReadUInt32();
|
||||||
vertexCount = reader.ReadUInt32();
|
vertexCount = reader.ReadUInt32();
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using static AssetStudio.AssetsHelper;
|
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
public sealed class PPtr<T> where T : Object
|
public sealed class PPtr<T> : IYAMLExportable where T : Object
|
||||||
{
|
{
|
||||||
public int m_FileID;
|
public int m_FileID;
|
||||||
public long m_PathID;
|
public long m_PathID;
|
||||||
@@ -13,6 +12,13 @@ namespace AssetStudio
|
|||||||
private SerializedFile assetsFile;
|
private SerializedFile assetsFile;
|
||||||
private int index = -2; //-2 - Prepare, -1 - Missing
|
private int index = -2; //-2 - Prepare, -1 - Missing
|
||||||
|
|
||||||
|
public PPtr(int m_FileID, long m_PathID, SerializedFile assetsFile)
|
||||||
|
{
|
||||||
|
this.m_FileID = m_FileID;
|
||||||
|
this.m_PathID = m_PathID;
|
||||||
|
this.assetsFile = assetsFile;
|
||||||
|
}
|
||||||
|
|
||||||
public PPtr(ObjectReader reader)
|
public PPtr(ObjectReader reader)
|
||||||
{
|
{
|
||||||
m_FileID = reader.ReadInt32();
|
m_FileID = reader.ReadInt32();
|
||||||
@@ -20,6 +26,14 @@ namespace AssetStudio
|
|||||||
assetsFile = reader.assetsFile;
|
assetsFile = reader.assetsFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public YAMLNode ExportYAML(int[] version)
|
||||||
|
{
|
||||||
|
var node = new YAMLMappingNode();
|
||||||
|
node.Style = MappingStyle.Flow;
|
||||||
|
node.Add("fileID", m_FileID);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
private bool TryGetAssetsFile(out SerializedFile result)
|
private bool TryGetAssetsFile(out SerializedFile result)
|
||||||
{
|
{
|
||||||
result = null;
|
result = null;
|
||||||
@@ -129,6 +143,11 @@ namespace AssetStudio
|
|||||||
m_PathID = m_Object.m_PathID;
|
m_PathID = m_Object.m_PathID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PPtr<T2> Cast<T2>() where T2 : Object
|
||||||
|
{
|
||||||
|
return new PPtr<T2>(m_FileID, m_PathID, assetsFile);
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsNull => m_PathID == 0 || m_FileID < 0;
|
public bool IsNull => m_PathID == 0 || m_FileID < 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,6 +184,20 @@ namespace AssetStudio
|
|||||||
return new Matrix4x4(ReadSingleArray(16));
|
return new Matrix4x4(ReadSingleArray(16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public XForm ReadXForm(int[] version, bool isVector4 = false)
|
||||||
|
{
|
||||||
|
var t = (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) && !isVector4 ? ReadVector3() : (Vector3)ReadVector4();//5.4 and up
|
||||||
|
var q = ReadQuaternion();
|
||||||
|
var s = (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) && !isVector4 ? ReadVector3() : (Vector3)ReadVector4();//5.4 and up
|
||||||
|
|
||||||
|
return new XForm(t, q, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float ReadFloat()
|
||||||
|
{
|
||||||
|
return new Float(ReadSingle());
|
||||||
|
}
|
||||||
|
|
||||||
public int ReadMhy0Int()
|
public int ReadMhy0Int()
|
||||||
{
|
{
|
||||||
var buffer = ReadBytes(6);
|
var buffer = ReadBytes(6);
|
||||||
@@ -224,6 +238,16 @@ namespace AssetStudio
|
|||||||
return ReadBytes(ReadInt32());
|
return ReadBytes(ReadInt32());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public short[] ReadInt16Array()
|
||||||
|
{
|
||||||
|
return ReadArray(ReadInt16, ReadInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
public short[] ReadInt16Array(int length)
|
||||||
|
{
|
||||||
|
return ReadArray(ReadInt16, length);
|
||||||
|
}
|
||||||
|
|
||||||
public ushort[] ReadUInt16Array()
|
public ushort[] ReadUInt16Array()
|
||||||
{
|
{
|
||||||
return ReadArray(ReadUInt16, ReadInt32());
|
return ReadArray(ReadUInt16, ReadInt32());
|
||||||
|
|||||||
@@ -20,5 +20,29 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AlignStream(this Stream stream)
|
||||||
|
{
|
||||||
|
stream.AlignStream(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AlignStream(this Stream stream, int alignment)
|
||||||
|
{
|
||||||
|
var pos = stream.Position;
|
||||||
|
var mod = pos % alignment;
|
||||||
|
if (mod != 0)
|
||||||
|
{
|
||||||
|
var rem = alignment - mod;
|
||||||
|
for (int _ = 0; _ < rem; _++)
|
||||||
|
{
|
||||||
|
if (!stream.CanWrite)
|
||||||
|
{
|
||||||
|
throw new IOException("End of stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.WriteByte(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
AssetStudio/Math/Float.cs
Normal file
27
AssetStudio/Math/Float.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public struct Float : IYAMLExportable
|
||||||
|
{
|
||||||
|
public float Value;
|
||||||
|
|
||||||
|
public Float(float value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Float(float value)
|
||||||
|
{
|
||||||
|
return new Float(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator float(Float value)
|
||||||
|
{
|
||||||
|
return value.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLNode ExportYAML(int[] version)
|
||||||
|
{
|
||||||
|
return new YAMLScalarNode(Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
|||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
public struct Quaternion : IEquatable<Quaternion>
|
public struct Quaternion : IEquatable<Quaternion>, IYAMLExportable
|
||||||
{
|
{
|
||||||
public float X;
|
public float X;
|
||||||
public float Y;
|
public float Y;
|
||||||
@@ -83,6 +83,16 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
public YAMLNode ExportYAML(int[] version)
|
||||||
|
{
|
||||||
|
var node = new YAMLMappingNode();
|
||||||
|
node.Style = MappingStyle.Flow;
|
||||||
|
node.Add("x", X);
|
||||||
|
node.Add("y", Y);
|
||||||
|
node.Add("z", Z);
|
||||||
|
node.Add("w", W);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
private const float kEpsilon = 0.000001F;
|
private const float kEpsilon = 0.000001F;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
|||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
public struct Vector3 : IEquatable<Vector3>
|
public struct Vector3 : IEquatable<Vector3>, IYAMLExportable
|
||||||
{
|
{
|
||||||
public float X;
|
public float X;
|
||||||
public float Y;
|
public float Y;
|
||||||
@@ -87,6 +87,16 @@ namespace AssetStudio
|
|||||||
return X * X + Y * Y + Z * Z;
|
return X * X + Y * Y + Z * Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public YAMLNode ExportYAML(int[] version)
|
||||||
|
{
|
||||||
|
var node = new YAMLMappingNode();
|
||||||
|
node.Style = MappingStyle.Flow;
|
||||||
|
node.Add("x", X);
|
||||||
|
node.Add("y", Y);
|
||||||
|
node.Add("z", Z);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
public static Vector3 Zero => new Vector3();
|
public static Vector3 Zero => new Vector3();
|
||||||
|
|
||||||
public static Vector3 One => new Vector3(1.0f, 1.0f, 1.0f);
|
public static Vector3 One => new Vector3(1.0f, 1.0f, 1.0f);
|
||||||
|
|||||||
71
AssetStudio/Math/XForm.cs
Normal file
71
AssetStudio/Math/XForm.cs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
|
public struct XForm : IEquatable<XForm>
|
||||||
|
{
|
||||||
|
public Vector3 t;
|
||||||
|
public Quaternion q;
|
||||||
|
public Vector3 s;
|
||||||
|
|
||||||
|
public XForm(Vector3 t, Quaternion q, Vector3 s)
|
||||||
|
{
|
||||||
|
this.t = t;
|
||||||
|
this.q = q;
|
||||||
|
this.s = s;
|
||||||
|
}
|
||||||
|
public float this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0: return t.X;
|
||||||
|
case 1: return t.Y;
|
||||||
|
case 2: return t.Z;
|
||||||
|
case 3: return q.X;
|
||||||
|
case 4: return q.Y;
|
||||||
|
case 5: return q.Z;
|
||||||
|
case 6: return q.W;
|
||||||
|
case 7: return s.X;
|
||||||
|
case 8: return s.Y;
|
||||||
|
case 9: return s.Z;
|
||||||
|
default: throw new ArgumentOutOfRangeException(nameof(index), "Invalid xform index!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0: t.X = value; break;
|
||||||
|
case 1: t.Y = value; break;
|
||||||
|
case 2: t.Z = value; break;
|
||||||
|
case 3: q.X = value; break;
|
||||||
|
case 4: q.Y = value; break;
|
||||||
|
case 5: q.Z = value; break;
|
||||||
|
case 6: q.W = value; break;
|
||||||
|
case 7: s.X = value; break;
|
||||||
|
case 8: s.Y = value; break;
|
||||||
|
case 9: s.Z = value; break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index), "Invalid xform index!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return t.GetHashCode() ^ (q.GetHashCode() << 2) ^ (s.GetHashCode() >> 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEquatable<XForm>.Equals(XForm other)
|
||||||
|
{
|
||||||
|
return t.Equals(other.t) && q.Equals(other.q) && s.Equals(other.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XForm Zero => new XForm(Vector3.Zero, Quaternion.Zero, Vector3.One);
|
||||||
|
}
|
||||||
|
}
|
||||||
231
AssetStudio/YAML/Base/Emitter.cs
Normal file
231
AssetStudio/YAML/Base/Emitter.cs
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
internal class Emitter
|
||||||
|
{
|
||||||
|
public Emitter(TextWriter writer, bool formatKeys)
|
||||||
|
{
|
||||||
|
if (writer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(writer));
|
||||||
|
}
|
||||||
|
m_stream = writer;
|
||||||
|
IsFormatKeys = formatKeys;
|
||||||
|
if (formatKeys)
|
||||||
|
{
|
||||||
|
m_sb = new StringBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter IncreaseIndent()
|
||||||
|
{
|
||||||
|
m_indent++;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter DecreaseIndent()
|
||||||
|
{
|
||||||
|
if (m_indent == 0)
|
||||||
|
{
|
||||||
|
throw new Exception($"Increase/decrease indent mismatch");
|
||||||
|
}
|
||||||
|
m_indent--;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(char value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter WriteRaw(char value)
|
||||||
|
{
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(byte value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(ushort value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(short value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(uint value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(int value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(ulong value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(long value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(float value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(double value)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter Write(string value)
|
||||||
|
{
|
||||||
|
if (value.Length > 0)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
m_stream.Write(value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter WriteFormat(string value)
|
||||||
|
{
|
||||||
|
if (value.Length > 0)
|
||||||
|
{
|
||||||
|
WriteDelayed();
|
||||||
|
if (value.Length > 2 && value.StartsWith("m_", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
m_sb.Append(value, 2, value.Length - 2);
|
||||||
|
if (char.IsUpper(m_sb[0]))
|
||||||
|
{
|
||||||
|
m_sb[0] = char.ToLower(m_sb[0]);
|
||||||
|
}
|
||||||
|
value = m_sb.ToString();
|
||||||
|
m_sb.Clear();
|
||||||
|
}
|
||||||
|
m_stream.Write(value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter WriteRaw(string value)
|
||||||
|
{
|
||||||
|
m_stream.Write(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter WriteClose(char @char)
|
||||||
|
{
|
||||||
|
m_isNeedSeparator = false;
|
||||||
|
m_isNeedWhitespace = false;
|
||||||
|
m_isNeedLineBreak = false;
|
||||||
|
return Write(@char);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter WriteClose(string @string)
|
||||||
|
{
|
||||||
|
m_isNeedSeparator = false;
|
||||||
|
m_isNeedWhitespace = false;
|
||||||
|
return Write(@string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter WriteWhitespace()
|
||||||
|
{
|
||||||
|
m_isNeedWhitespace = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter WriteSeparator()
|
||||||
|
{
|
||||||
|
m_isNeedSeparator = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emitter WriteLine()
|
||||||
|
{
|
||||||
|
m_isNeedLineBreak = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteMeta(MetaType type, string value)
|
||||||
|
{
|
||||||
|
Write('%').Write(type.ToString()).WriteWhitespace();
|
||||||
|
Write(value).WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteDelayed()
|
||||||
|
{
|
||||||
|
if (m_isNeedLineBreak)
|
||||||
|
{
|
||||||
|
m_stream.Write('\n');
|
||||||
|
m_isNeedSeparator = false;
|
||||||
|
m_isNeedWhitespace = false;
|
||||||
|
m_isNeedLineBreak = false;
|
||||||
|
WriteIndent();
|
||||||
|
}
|
||||||
|
if (m_isNeedSeparator)
|
||||||
|
{
|
||||||
|
m_stream.Write(',');
|
||||||
|
m_isNeedSeparator = false;
|
||||||
|
}
|
||||||
|
if (m_isNeedWhitespace)
|
||||||
|
{
|
||||||
|
m_stream.Write(' ');
|
||||||
|
m_isNeedWhitespace = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteIndent()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_indent * 2; i++)
|
||||||
|
{
|
||||||
|
m_stream.Write(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFormatKeys { get; }
|
||||||
|
public bool IsKey { get; set; }
|
||||||
|
|
||||||
|
private readonly TextWriter m_stream;
|
||||||
|
private readonly StringBuilder m_sb;
|
||||||
|
|
||||||
|
private int m_indent = 0;
|
||||||
|
private bool m_isNeedWhitespace = false;
|
||||||
|
private bool m_isNeedSeparator = false;
|
||||||
|
private bool m_isNeedLineBreak = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
AssetStudio/YAML/Base/IYAMLExportable.cs
Normal file
7
AssetStudio/YAML/Base/IYAMLExportable.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public interface IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLNode ExportYAML(int[] version);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
AssetStudio/YAML/Base/MappingStyle.cs
Normal file
18
AssetStudio/YAML/Base/MappingStyle.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the style of a mapping.
|
||||||
|
/// </summary>
|
||||||
|
public enum MappingStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The block mapping style.
|
||||||
|
/// </summary>
|
||||||
|
Block,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The flow mapping style.
|
||||||
|
/// </summary>
|
||||||
|
Flow
|
||||||
|
}
|
||||||
|
}
|
||||||
8
AssetStudio/YAML/Base/MetaType.cs
Normal file
8
AssetStudio/YAML/Base/MetaType.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
internal enum MetaType
|
||||||
|
{
|
||||||
|
YAML,
|
||||||
|
TAG,
|
||||||
|
}
|
||||||
|
}
|
||||||
28
AssetStudio/YAML/Base/ScalarStyle.cs
Normal file
28
AssetStudio/YAML/Base/ScalarStyle.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the style of a YAML scalar.
|
||||||
|
/// </summary>
|
||||||
|
public enum ScalarStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The plain scalar style.
|
||||||
|
/// </summary>
|
||||||
|
Plain,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
Hex,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The single-quoted scalar style.
|
||||||
|
/// </summary>
|
||||||
|
SingleQuoted,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The double-quoted scalar style.
|
||||||
|
/// </summary>
|
||||||
|
DoubleQuoted,
|
||||||
|
}
|
||||||
|
}
|
||||||
17
AssetStudio/YAML/Base/ScalarType.cs
Normal file
17
AssetStudio/YAML/Base/ScalarType.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
internal enum ScalarType
|
||||||
|
{
|
||||||
|
Boolean,
|
||||||
|
Byte,
|
||||||
|
UInt16,
|
||||||
|
Int16,
|
||||||
|
UInt32,
|
||||||
|
Int32,
|
||||||
|
UInt64,
|
||||||
|
Int64,
|
||||||
|
Single,
|
||||||
|
Double,
|
||||||
|
String,
|
||||||
|
}
|
||||||
|
}
|
||||||
51
AssetStudio/YAML/Base/SequenceStyle.cs
Normal file
51
AssetStudio/YAML/Base/SequenceStyle.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the style of a sequence.
|
||||||
|
/// </summary>
|
||||||
|
public enum SequenceStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The block sequence style
|
||||||
|
/// </summary>
|
||||||
|
Block,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block sequence style but with curly braces
|
||||||
|
/// </summary>
|
||||||
|
BlockCurve,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The flow sequence style
|
||||||
|
/// </summary>
|
||||||
|
Flow,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Single line with hex data
|
||||||
|
/// </summary>
|
||||||
|
Raw,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SequenceStyleExtensions
|
||||||
|
{
|
||||||
|
public static bool IsRaw(this SequenceStyle _this)
|
||||||
|
{
|
||||||
|
return _this == SequenceStyle.Raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsAnyBlock(this SequenceStyle _this)
|
||||||
|
{
|
||||||
|
return _this == SequenceStyle.Block || _this == SequenceStyle.BlockCurve;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get scalar style corresponding to current sequence style
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_this">Sequence style</param>
|
||||||
|
/// <returns>Corresponding scalar style</returns>
|
||||||
|
public static ScalarStyle ToScalarStyle(this SequenceStyle _this)
|
||||||
|
{
|
||||||
|
return _this == SequenceStyle.Raw ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
AssetStudio/YAML/Base/YAMLDocument.cs
Normal file
42
AssetStudio/YAML/Base/YAMLDocument.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public sealed class YAMLDocument
|
||||||
|
{
|
||||||
|
public YAMLDocument()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode CreateScalarRoot()
|
||||||
|
{
|
||||||
|
YAMLScalarNode root = new YAMLScalarNode();
|
||||||
|
Root = root;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLSequenceNode CreateSequenceRoot()
|
||||||
|
{
|
||||||
|
YAMLSequenceNode root = new YAMLSequenceNode();
|
||||||
|
Root = root;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLMappingNode CreateMappingRoot()
|
||||||
|
{
|
||||||
|
YAMLMappingNode root = new YAMLMappingNode();
|
||||||
|
Root = root;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Emit(Emitter emitter, bool isSeparator)
|
||||||
|
{
|
||||||
|
if(isSeparator)
|
||||||
|
{
|
||||||
|
emitter.Write("---").WriteWhitespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
Root.Emit(emitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLNode Root { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
330
AssetStudio/YAML/Base/YAMLMappingNode.cs
Normal file
330
AssetStudio/YAML/Base/YAMLMappingNode.cs
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public sealed class YAMLMappingNode : YAMLNode
|
||||||
|
{
|
||||||
|
public YAMLMappingNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLMappingNode(MappingStyle style)
|
||||||
|
{
|
||||||
|
Style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(int key, long value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(int key, string value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(int key, YAMLNode value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode keyNode = new YAMLScalarNode(key);
|
||||||
|
InsertEnd(keyNode, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(uint key, string value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(uint key, YAMLNode value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode keyNode = new YAMLScalarNode(key);
|
||||||
|
InsertEnd(keyNode, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(long key, string value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(long key, YAMLNode value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode keyNode = new YAMLScalarNode(key);
|
||||||
|
InsertEnd(keyNode, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, bool value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, byte value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, short value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, ushort value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, int value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, uint value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, long value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, ulong value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, float value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, string value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, YAMLNode value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode keyNode = new YAMLScalarNode(key, true);
|
||||||
|
InsertEnd(keyNode, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, bool value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, byte value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, short value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, ushort value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, int value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, uint value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, long value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, ulong value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, float value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, string value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
Add(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode key, YAMLNode value)
|
||||||
|
{
|
||||||
|
if (key.NodeType != YAMLNodeType.Scalar)
|
||||||
|
{
|
||||||
|
throw new Exception($"Only {YAMLNodeType.Scalar} node as a key supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertEnd(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Append(YAMLMappingNode map)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<YAMLNode, YAMLNode> child in map.m_children)
|
||||||
|
{
|
||||||
|
Add(child.Key, child.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertBegin(string key, int value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode valueNode = new YAMLScalarNode(value);
|
||||||
|
InsertBegin(key, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertBegin(string key, YAMLNode value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode keyNode = new YAMLScalarNode(key, true);
|
||||||
|
InsertBegin(keyNode, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertBegin(YAMLNode key, YAMLNode value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
KeyValuePair<YAMLNode, YAMLNode> pair = new KeyValuePair<YAMLNode, YAMLNode>(key, value);
|
||||||
|
m_children.Insert(0, pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void Emit(Emitter emitter)
|
||||||
|
{
|
||||||
|
base.Emit(emitter);
|
||||||
|
|
||||||
|
StartChildren(emitter);
|
||||||
|
foreach (var kvp in m_children)
|
||||||
|
{
|
||||||
|
YAMLNode key = kvp.Key;
|
||||||
|
YAMLNode value = kvp.Value;
|
||||||
|
|
||||||
|
bool iskey = emitter.IsKey;
|
||||||
|
emitter.IsKey = true;
|
||||||
|
key.Emit(emitter);
|
||||||
|
emitter.IsKey = false;
|
||||||
|
StartTransition(emitter, value);
|
||||||
|
value.Emit(emitter);
|
||||||
|
EndTransition(emitter, value);
|
||||||
|
emitter.IsKey = iskey;
|
||||||
|
}
|
||||||
|
EndChildren(emitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartChildren(Emitter emitter)
|
||||||
|
{
|
||||||
|
if (Style == MappingStyle.Block)
|
||||||
|
{
|
||||||
|
if (m_children.Count == 0)
|
||||||
|
{
|
||||||
|
emitter.Write('{');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Style == MappingStyle.Flow)
|
||||||
|
{
|
||||||
|
emitter.Write('{');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EndChildren(Emitter emitter)
|
||||||
|
{
|
||||||
|
if (Style == MappingStyle.Block)
|
||||||
|
{
|
||||||
|
if (m_children.Count == 0)
|
||||||
|
{
|
||||||
|
emitter.Write('}');
|
||||||
|
}
|
||||||
|
emitter.WriteLine();
|
||||||
|
}
|
||||||
|
else if (Style == MappingStyle.Flow)
|
||||||
|
{
|
||||||
|
emitter.WriteClose('}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartTransition(Emitter emitter, YAMLNode next)
|
||||||
|
{
|
||||||
|
emitter.Write(':').WriteWhitespace();
|
||||||
|
if (Style == MappingStyle.Block)
|
||||||
|
{
|
||||||
|
if (next.IsMultiline)
|
||||||
|
{
|
||||||
|
emitter.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (next.IsIndent)
|
||||||
|
{
|
||||||
|
emitter.IncreaseIndent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EndTransition(Emitter emitter, YAMLNode next)
|
||||||
|
{
|
||||||
|
if (Style == MappingStyle.Block)
|
||||||
|
{
|
||||||
|
emitter.WriteLine();
|
||||||
|
}
|
||||||
|
else if (Style == MappingStyle.Flow)
|
||||||
|
{
|
||||||
|
emitter.WriteSeparator().WriteWhitespace();
|
||||||
|
}
|
||||||
|
if (next.IsIndent)
|
||||||
|
{
|
||||||
|
emitter.DecreaseIndent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InsertEnd(YAMLNode key, YAMLNode value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
KeyValuePair<YAMLNode, YAMLNode> pair = new KeyValuePair<YAMLNode, YAMLNode>(key, value);
|
||||||
|
m_children.Add(pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLMappingNode Empty { get; } = new YAMLMappingNode(MappingStyle.Flow);
|
||||||
|
|
||||||
|
public override YAMLNodeType NodeType => YAMLNodeType.Mapping;
|
||||||
|
public override bool IsMultiline => Style == MappingStyle.Block && m_children.Count > 0;
|
||||||
|
public override bool IsIndent => Style == MappingStyle.Block;
|
||||||
|
|
||||||
|
public MappingStyle Style { get; set; }
|
||||||
|
|
||||||
|
private readonly List<KeyValuePair<YAMLNode, YAMLNode>> m_children = new List<KeyValuePair<YAMLNode, YAMLNode>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
40
AssetStudio/YAML/Base/YAMLNode.cs
Normal file
40
AssetStudio/YAML/Base/YAMLNode.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public abstract class YAMLNode
|
||||||
|
{
|
||||||
|
internal virtual void Emit(Emitter emitter)
|
||||||
|
{
|
||||||
|
bool isWrote = false;
|
||||||
|
if (!CustomTag.IsEmpty)
|
||||||
|
{
|
||||||
|
emitter.Write(CustomTag.ToString()).WriteWhitespace();
|
||||||
|
isWrote = true;
|
||||||
|
}
|
||||||
|
if (Anchor.Length > 0)
|
||||||
|
{
|
||||||
|
emitter.Write("&").Write(Anchor).WriteWhitespace();
|
||||||
|
isWrote = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWrote)
|
||||||
|
{
|
||||||
|
if (IsMultiline)
|
||||||
|
{
|
||||||
|
emitter.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract YAMLNodeType NodeType { get; }
|
||||||
|
public abstract bool IsMultiline { get; }
|
||||||
|
public abstract bool IsIndent { get; }
|
||||||
|
|
||||||
|
public string Tag
|
||||||
|
{
|
||||||
|
get => CustomTag.Content;
|
||||||
|
set => CustomTag = new YAMLTag(YAMLWriter.DefaultTagHandle, value);
|
||||||
|
}
|
||||||
|
public YAMLTag CustomTag { get; set; }
|
||||||
|
public string Anchor { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
AssetStudio/YAML/Base/YAMLNodeType.cs
Normal file
20
AssetStudio/YAML/Base/YAMLNodeType.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public enum YAMLNodeType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The node is a <see cref="YamlMappingNode"/>.
|
||||||
|
/// </summary>
|
||||||
|
Mapping,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The node is a <see cref="YamlScalarNode"/>.
|
||||||
|
/// </summary>
|
||||||
|
Scalar,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The node is a <see cref="YamlSequenceNode"/>.
|
||||||
|
/// </summary>
|
||||||
|
Sequence
|
||||||
|
}
|
||||||
|
}
|
||||||
456
AssetStudio/YAML/Base/YAMLScalarNode.cs
Normal file
456
AssetStudio/YAML/Base/YAMLScalarNode.cs
Normal file
@@ -0,0 +1,456 @@
|
|||||||
|
//#define USE_HEX_FLOAT
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public sealed class YAMLScalarNode : YAMLNode
|
||||||
|
{
|
||||||
|
public YAMLScalarNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(bool value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(bool value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(byte value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(byte value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(short value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(short value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(ushort value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(ushort value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(int value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(int value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(uint value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(uint value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(long value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(long value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(ulong value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(ulong value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(float value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(float value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(double value) :
|
||||||
|
this(value, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(double value, bool isHex)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = isHex ? ScalarStyle.Hex : ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLScalarNode(string value)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = GetStringStyle(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal YAMLScalarNode(string value, bool _)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
Style = ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(bool value)
|
||||||
|
{
|
||||||
|
m_value = value ? 1u : 0u;
|
||||||
|
m_objectType = ScalarType.Boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(byte value)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
m_objectType = ScalarType.Byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(short value)
|
||||||
|
{
|
||||||
|
m_value = unchecked((ushort)value);
|
||||||
|
m_objectType = ScalarType.Int16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(ushort value)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
m_objectType = ScalarType.UInt16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(int value)
|
||||||
|
{
|
||||||
|
m_value = unchecked((uint)value);
|
||||||
|
m_objectType = ScalarType.Int32;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(uint value)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
m_objectType = ScalarType.UInt32;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(long value)
|
||||||
|
{
|
||||||
|
m_value = unchecked((ulong)value);
|
||||||
|
m_objectType = ScalarType.Int64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(ulong value)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
m_objectType = ScalarType.UInt64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(float value)
|
||||||
|
{
|
||||||
|
#if USE_HEX_FLOAT
|
||||||
|
// It is more precise technic but output looks vague and less readable
|
||||||
|
uint hex = BitConverterExtensions.ToUInt32(value);
|
||||||
|
m_string = $"0x{hex.ToHexString()}({value.ToString(CultureInfo.InvariantCulture)})";
|
||||||
|
m_objectType = ScalarType.String;
|
||||||
|
#else
|
||||||
|
m_value = BitConverterExtensions.ToUInt32(value);
|
||||||
|
m_objectType = ScalarType.Single;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(double value)
|
||||||
|
{
|
||||||
|
#if USE_HEX_FLOAT
|
||||||
|
// It is more precise technic but output looks vague and less readable
|
||||||
|
ulong hex = BitConverterExtensions.ToUInt64(value);
|
||||||
|
m_string = $"0x{hex.ToHexString()}({value.ToString(CultureInfo.InvariantCulture)})";
|
||||||
|
m_objectType = ScalarType.String;
|
||||||
|
#else
|
||||||
|
m_value = BitConverterExtensions.ToUInt64(value);
|
||||||
|
m_objectType = ScalarType.Double;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(string value)
|
||||||
|
{
|
||||||
|
m_string = value;
|
||||||
|
m_objectType = ScalarType.String;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Emitter ToString(Emitter emitter)
|
||||||
|
{
|
||||||
|
if (Style == ScalarStyle.Hex)
|
||||||
|
{
|
||||||
|
switch (m_objectType)
|
||||||
|
{
|
||||||
|
case ScalarType.Byte:
|
||||||
|
return emitter.WriteHex((byte)m_value);
|
||||||
|
case ScalarType.Int16:
|
||||||
|
return emitter.WriteHex(unchecked((short)m_value));
|
||||||
|
case ScalarType.UInt16:
|
||||||
|
return emitter.WriteHex((ushort)m_value);
|
||||||
|
case ScalarType.Int32:
|
||||||
|
return emitter.WriteHex(unchecked((int)m_value));
|
||||||
|
case ScalarType.UInt32:
|
||||||
|
return emitter.WriteHex((uint)m_value);
|
||||||
|
case ScalarType.Int64:
|
||||||
|
return emitter.WriteHex(unchecked((long)m_value));
|
||||||
|
case ScalarType.UInt64:
|
||||||
|
return emitter.WriteHex(m_value);
|
||||||
|
case ScalarType.Single:
|
||||||
|
return emitter.WriteHex((uint)m_value);
|
||||||
|
case ScalarType.Double:
|
||||||
|
return emitter.WriteHex(m_value);
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(m_objectType.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_objectType)
|
||||||
|
{
|
||||||
|
case ScalarType.Boolean:
|
||||||
|
return emitter.Write(m_value);
|
||||||
|
case ScalarType.Byte:
|
||||||
|
return emitter.Write(m_value);
|
||||||
|
case ScalarType.Int16:
|
||||||
|
return emitter.Write(unchecked((short)m_value));
|
||||||
|
case ScalarType.UInt16:
|
||||||
|
return emitter.Write(m_value);
|
||||||
|
case ScalarType.Int32:
|
||||||
|
return emitter.Write(unchecked((int)m_value));
|
||||||
|
case ScalarType.UInt32:
|
||||||
|
return emitter.Write(m_value);
|
||||||
|
case ScalarType.Int64:
|
||||||
|
return emitter.Write(unchecked((long)m_value));
|
||||||
|
case ScalarType.UInt64:
|
||||||
|
return emitter.Write(m_value);
|
||||||
|
case ScalarType.Single:
|
||||||
|
return emitter.Write(BitConverterExtensions.ToSingle((uint)m_value));
|
||||||
|
case ScalarType.Double:
|
||||||
|
return emitter.Write(BitConverterExtensions.ToDouble(m_value));
|
||||||
|
case ScalarType.String:
|
||||||
|
return WriteString(emitter);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(m_objectType.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void Emit(Emitter emitter)
|
||||||
|
{
|
||||||
|
base.Emit(emitter);
|
||||||
|
|
||||||
|
switch (Style)
|
||||||
|
{
|
||||||
|
case ScalarStyle.Hex:
|
||||||
|
case ScalarStyle.Plain:
|
||||||
|
ToString(emitter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ScalarStyle.SingleQuoted:
|
||||||
|
emitter.Write('\'');
|
||||||
|
ToString(emitter);
|
||||||
|
emitter.Write('\'');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ScalarStyle.DoubleQuoted:
|
||||||
|
emitter.Write('"');
|
||||||
|
ToString(emitter);
|
||||||
|
emitter.Write('"');
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Exception($"Unsupported scalar style {Style}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Emitter WriteString(Emitter emitter)
|
||||||
|
{
|
||||||
|
if (Style == ScalarStyle.Plain)
|
||||||
|
{
|
||||||
|
if (emitter.IsFormatKeys && emitter.IsKey)
|
||||||
|
{
|
||||||
|
emitter.WriteFormat(m_string);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emitter.Write(m_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Style == ScalarStyle.SingleQuoted)
|
||||||
|
{
|
||||||
|
emitter.WriteDelayed();
|
||||||
|
for (int i = 0; i < m_string.Length; i++)
|
||||||
|
{
|
||||||
|
char c = m_string[i];
|
||||||
|
emitter.WriteRaw(c);
|
||||||
|
if (c == '\'')
|
||||||
|
{
|
||||||
|
emitter.WriteRaw(c);
|
||||||
|
}
|
||||||
|
else if (c == '\n')
|
||||||
|
{
|
||||||
|
emitter.WriteRaw("\n ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Style == ScalarStyle.DoubleQuoted)
|
||||||
|
{
|
||||||
|
emitter.WriteDelayed();
|
||||||
|
for (int i = 0; i < m_string.Length; i++)
|
||||||
|
{
|
||||||
|
char c = m_string[i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\\':
|
||||||
|
emitter.WriteRaw('\\').WriteRaw('\\');
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
emitter.WriteRaw('\\').WriteRaw('n');
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
emitter.WriteRaw('\\').WriteRaw('r');
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
emitter.WriteRaw('\\').WriteRaw('t');
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
emitter.WriteRaw('\\').WriteRaw('"');
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
emitter.WriteRaw(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException(Style.ToString());
|
||||||
|
}
|
||||||
|
return emitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ScalarStyle GetStringStyle(string value)
|
||||||
|
{
|
||||||
|
if (s_illegal.IsMatch(value))
|
||||||
|
{
|
||||||
|
return value.Contains("\n ") ? ScalarStyle.DoubleQuoted : ScalarStyle.SingleQuoted;
|
||||||
|
}
|
||||||
|
return ScalarStyle.Plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLScalarNode Empty { get; } = new YAMLScalarNode();
|
||||||
|
|
||||||
|
public override YAMLNodeType NodeType => YAMLNodeType.Scalar;
|
||||||
|
public override bool IsMultiline => false;
|
||||||
|
public override bool IsIndent => false;
|
||||||
|
|
||||||
|
public string Value
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Style == ScalarStyle.Hex)
|
||||||
|
{
|
||||||
|
switch (m_objectType)
|
||||||
|
{
|
||||||
|
case ScalarType.Byte:
|
||||||
|
return unchecked((byte)m_value).ToHexString();
|
||||||
|
case ScalarType.Int16:
|
||||||
|
return unchecked((short)m_value).ToHexString();
|
||||||
|
case ScalarType.UInt16:
|
||||||
|
return unchecked((ushort)m_value).ToHexString();
|
||||||
|
case ScalarType.Int32:
|
||||||
|
return unchecked((int)m_value).ToHexString();
|
||||||
|
case ScalarType.UInt32:
|
||||||
|
return unchecked((uint)m_value).ToHexString();
|
||||||
|
case ScalarType.Int64:
|
||||||
|
return unchecked((long)m_value).ToHexString();
|
||||||
|
case ScalarType.UInt64:
|
||||||
|
return m_value.ToHexString();
|
||||||
|
case ScalarType.Single:
|
||||||
|
return BitConverterExtensions.ToSingle((uint)m_value).ToHexString();
|
||||||
|
case ScalarType.Double:
|
||||||
|
return BitConverterExtensions.ToDouble(m_value).ToHexString();
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(m_objectType.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_objectType)
|
||||||
|
{
|
||||||
|
case ScalarType.Boolean:
|
||||||
|
return m_value == 1 ? "true" : "false";
|
||||||
|
case ScalarType.Byte:
|
||||||
|
return m_value.ToString();
|
||||||
|
case ScalarType.Int16:
|
||||||
|
return unchecked((short)m_value).ToString();
|
||||||
|
case ScalarType.UInt16:
|
||||||
|
return m_value.ToString();
|
||||||
|
case ScalarType.Int32:
|
||||||
|
return unchecked((int)m_value).ToString();
|
||||||
|
case ScalarType.UInt32:
|
||||||
|
return m_value.ToString();
|
||||||
|
case ScalarType.Int64:
|
||||||
|
return unchecked((long)m_value).ToString();
|
||||||
|
case ScalarType.UInt64:
|
||||||
|
return m_value.ToString();
|
||||||
|
case ScalarType.Single:
|
||||||
|
return BitConverterExtensions.ToSingle((uint)m_value).ToString(CultureInfo.InvariantCulture);
|
||||||
|
case ScalarType.Double:
|
||||||
|
return BitConverterExtensions.ToDouble(m_value).ToString(CultureInfo.InvariantCulture);
|
||||||
|
case ScalarType.String:
|
||||||
|
return m_string;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(m_objectType.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set => m_string = value;
|
||||||
|
}
|
||||||
|
public ScalarStyle Style { get; }
|
||||||
|
|
||||||
|
private static readonly Regex s_illegal = new Regex("(^\\s)|(^-\\s)|(^-$)|(^[\\:\\[\\]'\"*&!@#%{}?<>,\\`])|([:@]\\s)|([\\n\\r])|([:\\s]$)", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private ScalarType m_objectType = ScalarType.String;
|
||||||
|
private string m_string = string.Empty;
|
||||||
|
private ulong m_value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
213
AssetStudio/YAML/Base/YAMLSequenceNode.cs
Normal file
213
AssetStudio/YAML/Base/YAMLSequenceNode.cs
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public sealed class YAMLSequenceNode : YAMLNode
|
||||||
|
{
|
||||||
|
public YAMLSequenceNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YAMLSequenceNode(SequenceStyle style)
|
||||||
|
{
|
||||||
|
Style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(bool value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(byte value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(short value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(ushort value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(int value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(uint value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(long value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(ulong value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(float value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(double value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value, Style.IsRaw());
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string value)
|
||||||
|
{
|
||||||
|
YAMLScalarNode node = new YAMLScalarNode(value);
|
||||||
|
Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(YAMLNode child)
|
||||||
|
{
|
||||||
|
m_children.Add(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void Emit(Emitter emitter)
|
||||||
|
{
|
||||||
|
base.Emit(emitter);
|
||||||
|
|
||||||
|
StartChildren(emitter);
|
||||||
|
foreach (YAMLNode child in m_children)
|
||||||
|
{
|
||||||
|
StartChild(emitter, child);
|
||||||
|
child.Emit(emitter);
|
||||||
|
EndChild(emitter, child);
|
||||||
|
}
|
||||||
|
EndChildren(emitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartChildren(Emitter emitter)
|
||||||
|
{
|
||||||
|
switch (Style)
|
||||||
|
{
|
||||||
|
case SequenceStyle.Block:
|
||||||
|
if (m_children.Count == 0)
|
||||||
|
{
|
||||||
|
emitter.Write('[');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SequenceStyle.BlockCurve:
|
||||||
|
if (m_children.Count == 0)
|
||||||
|
{
|
||||||
|
emitter.Write('{');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SequenceStyle.Flow:
|
||||||
|
emitter.Write('[');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SequenceStyle.Raw:
|
||||||
|
if (m_children.Count == 0)
|
||||||
|
{
|
||||||
|
emitter.Write('[');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EndChildren(Emitter emitter)
|
||||||
|
{
|
||||||
|
switch (Style)
|
||||||
|
{
|
||||||
|
case SequenceStyle.Block:
|
||||||
|
if (m_children.Count == 0)
|
||||||
|
{
|
||||||
|
emitter.Write(']');
|
||||||
|
}
|
||||||
|
emitter.WriteLine();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SequenceStyle.BlockCurve:
|
||||||
|
if (m_children.Count == 0)
|
||||||
|
{
|
||||||
|
emitter.WriteClose('}');
|
||||||
|
}
|
||||||
|
emitter.WriteLine();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SequenceStyle.Flow:
|
||||||
|
emitter.WriteClose(']');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SequenceStyle.Raw:
|
||||||
|
if (m_children.Count == 0)
|
||||||
|
{
|
||||||
|
emitter.Write(']');
|
||||||
|
}
|
||||||
|
emitter.WriteLine();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartChild(Emitter emitter, YAMLNode next)
|
||||||
|
{
|
||||||
|
if (Style.IsAnyBlock())
|
||||||
|
{
|
||||||
|
emitter.Write('-').Write(' ');
|
||||||
|
|
||||||
|
if (next.NodeType == NodeType)
|
||||||
|
{
|
||||||
|
emitter.IncreaseIndent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (next.IsIndent)
|
||||||
|
{
|
||||||
|
emitter.IncreaseIndent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EndChild(Emitter emitter, YAMLNode next)
|
||||||
|
{
|
||||||
|
if (Style.IsAnyBlock())
|
||||||
|
{
|
||||||
|
emitter.WriteLine();
|
||||||
|
if (next.NodeType == NodeType)
|
||||||
|
{
|
||||||
|
emitter.DecreaseIndent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Style == SequenceStyle.Flow)
|
||||||
|
{
|
||||||
|
emitter.WriteSeparator().WriteWhitespace();
|
||||||
|
}
|
||||||
|
if (next.IsIndent)
|
||||||
|
{
|
||||||
|
emitter.DecreaseIndent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLSequenceNode Empty { get; } = new YAMLSequenceNode();
|
||||||
|
|
||||||
|
public override YAMLNodeType NodeType => YAMLNodeType.Sequence;
|
||||||
|
public override bool IsMultiline => Style.IsAnyBlock() && m_children.Count > 0;
|
||||||
|
public override bool IsIndent => false;
|
||||||
|
|
||||||
|
public SequenceStyle Style { get; }
|
||||||
|
|
||||||
|
private readonly List<YAMLNode> m_children = new List<YAMLNode>();
|
||||||
|
}
|
||||||
|
}
|
||||||
26
AssetStudio/YAML/Base/YAMLTag.cs
Normal file
26
AssetStudio/YAML/Base/YAMLTag.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public readonly struct YAMLTag
|
||||||
|
{
|
||||||
|
public YAMLTag(string handle, string content)
|
||||||
|
{
|
||||||
|
Handle = handle;
|
||||||
|
Content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return IsEmpty ? string.Empty : $"{Handle}{Content}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToHeaderString()
|
||||||
|
{
|
||||||
|
return IsEmpty ? string.Empty : $"{Handle} {Content}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEmpty => string.IsNullOrEmpty(Handle);
|
||||||
|
|
||||||
|
public string Handle { get; }
|
||||||
|
public string Content { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
98
AssetStudio/YAML/Base/YAMLWriter.cs
Normal file
98
AssetStudio/YAML/Base/YAMLWriter.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
using Version = System.Version;
|
||||||
|
|
||||||
|
public class YAMLWriter
|
||||||
|
{
|
||||||
|
public void AddDocument(YAMLDocument document)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if (document == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(document));
|
||||||
|
}
|
||||||
|
if (m_documents.Contains(document))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Document {document} is added already", nameof(document));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
m_documents.Add(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddTag(string handle, string content)
|
||||||
|
{
|
||||||
|
if(m_tags.Any(t => t.Handle == handle))
|
||||||
|
{
|
||||||
|
throw new Exception($"Writer already contains tag {handle}");
|
||||||
|
}
|
||||||
|
YAMLTag tag = new YAMLTag(handle, content);
|
||||||
|
m_tags.Add(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(TextWriter output)
|
||||||
|
{
|
||||||
|
WriteHead(output);
|
||||||
|
foreach (YAMLDocument doc in m_documents)
|
||||||
|
{
|
||||||
|
WriteDocument(doc);
|
||||||
|
}
|
||||||
|
WriteTail(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteHead(TextWriter output)
|
||||||
|
{
|
||||||
|
m_emitter = new Emitter(output, IsFormatKeys);
|
||||||
|
m_isWriteSeparator = false;
|
||||||
|
|
||||||
|
if (IsWriteVersion)
|
||||||
|
{
|
||||||
|
m_emitter.WriteMeta(MetaType.YAML, Version.ToString());
|
||||||
|
m_isWriteSeparator = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsWriteDefaultTag)
|
||||||
|
{
|
||||||
|
m_emitter.WriteMeta(MetaType.TAG, DefaultTag.ToHeaderString());
|
||||||
|
m_isWriteSeparator = true;
|
||||||
|
}
|
||||||
|
foreach (YAMLTag tag in m_tags)
|
||||||
|
{
|
||||||
|
m_emitter.WriteMeta(MetaType.TAG, tag.ToHeaderString());
|
||||||
|
m_isWriteSeparator = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteDocument(YAMLDocument doc)
|
||||||
|
{
|
||||||
|
doc.Emit(m_emitter, m_isWriteSeparator);
|
||||||
|
m_isWriteSeparator = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteTail(TextWriter output)
|
||||||
|
{
|
||||||
|
output.Write('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Version Version { get; } = new Version(1, 1);
|
||||||
|
|
||||||
|
public const string DefaultTagHandle = "!u!";
|
||||||
|
public const string DefaultTagContent = "tag:unity3d.com,2011:";
|
||||||
|
|
||||||
|
public readonly YAMLTag DefaultTag = new YAMLTag(DefaultTagHandle, DefaultTagContent);
|
||||||
|
|
||||||
|
public bool IsWriteVersion { get; set; } = true;
|
||||||
|
public bool IsWriteDefaultTag { get; set; } = true;
|
||||||
|
public bool IsFormatKeys { get; set; }
|
||||||
|
|
||||||
|
private readonly HashSet<YAMLDocument> m_documents = new HashSet<YAMLDocument>();
|
||||||
|
private readonly List<YAMLTag> m_tags = new List<YAMLTag>();
|
||||||
|
|
||||||
|
private Emitter m_emitter;
|
||||||
|
private bool m_isWriteSeparator;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
AssetStudio/YAML/Utils/Extensions/ArrayYAMLExtensions.cs
Normal file
25
AssetStudio/YAML/Utils/Extensions/ArrayYAMLExtensions.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class ArrayYAMLExtensions
|
||||||
|
{
|
||||||
|
public static YAMLNode ExportYAML(this byte[] _this)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Length * 2);
|
||||||
|
for (int i = 0; i < _this.Length; i++)
|
||||||
|
{
|
||||||
|
sb.AppendHex(_this[i]);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T>(this T[][] _this, int[] version)
|
||||||
|
where T : IYAMLExportable
|
||||||
|
{
|
||||||
|
return ((IEnumerable<IEnumerable<T>>)_this).ExportYAML(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
AssetStudio/YAML/Utils/Extensions/BitConverterExtensions.cs
Normal file
107
AssetStudio/YAML/Utils/Extensions/BitConverterExtensions.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class BitConverterExtensions
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
private struct FloatUIntUnion
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public uint Int;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public float Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint ToUInt32(float value)
|
||||||
|
{
|
||||||
|
return new FloatUIntUnion { Float = value }.Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong ToUInt64(double value)
|
||||||
|
{
|
||||||
|
return unchecked((ulong)BitConverter.DoubleToInt64Bits(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static float ToSingle(uint value)
|
||||||
|
{
|
||||||
|
return new FloatUIntUnion { Int = value }.Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static double ToDouble(ulong value)
|
||||||
|
{
|
||||||
|
return BitConverter.Int64BitsToDouble(unchecked((long)value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void GetBytes(ushort value, byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
buffer[offset + 0] = unchecked((byte)(value >> 0));
|
||||||
|
buffer[offset + 1] = unchecked((byte)(value >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetBytes(uint value, byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
buffer[offset + 0] = unchecked((byte)(value >> 0));
|
||||||
|
buffer[offset + 1] = unchecked((byte)(value >> 8));
|
||||||
|
buffer[offset + 2] = unchecked((byte)(value >> 16));
|
||||||
|
buffer[offset + 3] = unchecked((byte)(value >> 24));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static short Swap(short value)
|
||||||
|
{
|
||||||
|
return unchecked((short)(Swap(unchecked((ushort)value))));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ushort Swap(ushort value)
|
||||||
|
{
|
||||||
|
return unchecked((ushort)(value >> 8 | value << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Swap(int value)
|
||||||
|
{
|
||||||
|
return unchecked((int)(Swap(unchecked((uint)value))));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Swap(uint value)
|
||||||
|
{
|
||||||
|
value = value >> 16 | value << 16;
|
||||||
|
return ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static long Swap(long value)
|
||||||
|
{
|
||||||
|
return unchecked((long)(Swap(unchecked((ulong)value))));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Swap(ulong value)
|
||||||
|
{
|
||||||
|
value = value >> 32 | value << 32;
|
||||||
|
value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16);
|
||||||
|
return ((value & 0xFF00FF00FF00FF00) >> 8) | ((value & 0x00FF00FF00FF00FF) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetDigitsCount(uint value)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
while (value != 0)
|
||||||
|
{
|
||||||
|
value /= 10;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
AssetStudio/YAML/Utils/Extensions/EmitterExtensions.cs
Normal file
82
AssetStudio/YAML/Utils/Extensions/EmitterExtensions.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
internal static class EmitterExtensions
|
||||||
|
{
|
||||||
|
public static Emitter WriteHex(this Emitter _this, byte value)
|
||||||
|
{
|
||||||
|
_this.Write(HexAlphabet[value >> 4]);
|
||||||
|
_this.Write(HexAlphabet[value & 0xF]);
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Emitter WriteHex(this Emitter _this, ushort value)
|
||||||
|
{
|
||||||
|
_this.Write(HexAlphabet[(value >> 4) & 0xF]);
|
||||||
|
_this.Write(HexAlphabet[(value >> 0) & 0xF]);
|
||||||
|
_this.Write(HexAlphabet[(value >> 12) & 0xF]);
|
||||||
|
_this.Write(HexAlphabet[(value >> 8) & 0xF]);
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Emitter WriteHex(this Emitter _this, short value)
|
||||||
|
{
|
||||||
|
return WriteHex(_this, unchecked((ushort)value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Emitter WriteHex(this Emitter _this, uint value)
|
||||||
|
{
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 4) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 0) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 12) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 8) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 20) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 16) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 28) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 24) & 0xF)]);
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Emitter WriteHex(this Emitter _this, int value)
|
||||||
|
{
|
||||||
|
return WriteHex(_this, unchecked((uint)value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Emitter WriteHex(this Emitter _this, ulong value)
|
||||||
|
{
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 4) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 0) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 12) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 8) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 20) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 16) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 28) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 24) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 36) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 32) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 44) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 40) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 52) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 48) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 60) & 0xF)]);
|
||||||
|
_this.Write(HexAlphabet[unchecked((int)(value >> 56) & 0xF)]);
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Emitter WriteHex(this Emitter _this, long value)
|
||||||
|
{
|
||||||
|
return WriteHex(_this, unchecked((ulong)value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Emitter WriteHex(this Emitter _this, float value)
|
||||||
|
{
|
||||||
|
return WriteHex(_this, BitConverterExtensions.ToUInt32(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Emitter WriteHex(this Emitter _this, double value)
|
||||||
|
{
|
||||||
|
return WriteHex(_this, BitConverterExtensions.ToUInt64(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly string HexAlphabet = "0123456789ABCDEF";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class IDictionaryExportYAMLExtensions
|
||||||
|
{
|
||||||
|
public static YAMLNode ExportYAML<T>(this IReadOnlyDictionary<int, T> _this, int[] version)
|
||||||
|
where T : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
map.Add(kvp.Key, kvp.Value.ExportYAML(version));
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T>(this IReadOnlyDictionary<string, T> _this, int[] version)
|
||||||
|
where T : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
map.Add(kvp.Key, kvp.Value.ExportYAML(version));
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T1, T2>(this IReadOnlyDictionary<Tuple<T1, long>, T2> _this, int[] version)
|
||||||
|
where T1 : IYAMLExportable
|
||||||
|
where T2 : IYAMLExportable
|
||||||
|
{
|
||||||
|
// TODO: test
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode kvpMap = new YAMLMappingNode();
|
||||||
|
YAMLMappingNode keyMap = new YAMLMappingNode();
|
||||||
|
keyMap.Add("first", kvp.Key.Item1.ExportYAML(version));
|
||||||
|
keyMap.Add("second", kvp.Key.Item2);
|
||||||
|
kvpMap.Add("first", keyMap);
|
||||||
|
kvpMap.Add("second", kvp.Value.ExportYAML(version));
|
||||||
|
node.Add(kvpMap);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T>(this IReadOnlyDictionary<T, int> _this, int[] version)
|
||||||
|
where T : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
YAMLNode key = kvp.Key.ExportYAML(version);
|
||||||
|
if (key.NodeType == YAMLNodeType.Scalar)
|
||||||
|
{
|
||||||
|
map.Add(key, kvp.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
map.Add("first", key);
|
||||||
|
map.Add("second", kvp.Value);
|
||||||
|
}
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T>(this IReadOnlyDictionary<T, float> _this, int[] version)
|
||||||
|
where T : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
YAMLNode key = kvp.Key.ExportYAML(version);
|
||||||
|
if (key.NodeType == YAMLNodeType.Scalar)
|
||||||
|
{
|
||||||
|
map.Add(key, kvp.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
map.Add("first", key);
|
||||||
|
map.Add("second", kvp.Value);
|
||||||
|
}
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T1, T2>(this IReadOnlyDictionary<T1, T2> _this, int[] version)
|
||||||
|
where T1 : IYAMLExportable
|
||||||
|
where T2 : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
YAMLNode key = kvp.Key.ExportYAML(version);
|
||||||
|
if (key.NodeType == YAMLNodeType.Scalar)
|
||||||
|
{
|
||||||
|
map.Add(key, kvp.Value.ExportYAML(version));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
map.Add("first", key);
|
||||||
|
map.Add("second", kvp.Value.ExportYAML(version));
|
||||||
|
}
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T1, T2>(this IReadOnlyDictionary<T1, T2[]> _this, int[] version)
|
||||||
|
where T1 : IYAMLExportable
|
||||||
|
where T2 : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
YAMLNode key = kvp.Key.ExportYAML(version);
|
||||||
|
if (key.NodeType == YAMLNodeType.Scalar)
|
||||||
|
{
|
||||||
|
map.Add(key, kvp.Value.ExportYAML(version));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
map.Add("first", key);
|
||||||
|
map.Add("second", kvp.Value.ExportYAML(version));
|
||||||
|
}
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
105
AssetStudio/YAML/Utils/Extensions/IDictionaryYAMLExtensions.cs
Normal file
105
AssetStudio/YAML/Utils/Extensions/IDictionaryYAMLExtensions.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class IDictionaryYAMLExtensions
|
||||||
|
{
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyDictionary<uint, string> _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode node = new YAMLMappingNode();
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
node.Add(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyDictionary<long, string> _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode node = new YAMLMappingNode();
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
node.Add(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyDictionary<string, string> _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode node = new YAMLMappingNode();
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
node.Add(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyDictionary<string, int> _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode node = new YAMLMappingNode();
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
node.Add(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyDictionary<string, float> _this)
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
map.Add(kvp.Key, kvp.Value);
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyDictionary<Tuple<ushort, ushort>, float> _this)
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode keyNode = new YAMLMappingNode();
|
||||||
|
keyNode.Add(kvp.Key.Item1, kvp.Key.Item2);
|
||||||
|
YAMLMappingNode kvpMap = new YAMLMappingNode();
|
||||||
|
kvpMap.Add("first", keyNode);
|
||||||
|
kvpMap.Add("second", kvp.Value);
|
||||||
|
node.Add(kvpMap);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyDictionary<Tuple<int, long>, string> _this)
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode keyNode = new YAMLMappingNode();
|
||||||
|
keyNode.Add(kvp.Key.Item1, kvp.Key.Item2);
|
||||||
|
YAMLMappingNode kvpMap = new YAMLMappingNode();
|
||||||
|
kvpMap.Add("first", keyNode);
|
||||||
|
kvpMap.Add("second", kvp.Value);
|
||||||
|
node.Add(kvpMap);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T>(this IReadOnlyDictionary<Tuple<T, long>, string> _this, Func<T, int> converter)
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.BlockCurve);
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode keyNode = new YAMLMappingNode();
|
||||||
|
keyNode.Add(converter(kvp.Key.Item1), kvp.Key.Item2);
|
||||||
|
YAMLMappingNode kvpMap = new YAMLMappingNode();
|
||||||
|
kvpMap.Add("first", keyNode);
|
||||||
|
kvpMap.Add("second", kvp.Value);
|
||||||
|
node.Add(kvpMap);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
273
AssetStudio/YAML/Utils/Extensions/IEnumerableYAMLExtensions.cs
Normal file
273
AssetStudio/YAML/Utils/Extensions/IEnumerableYAMLExtensions.cs
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class IEnumerableYAMLExtensions
|
||||||
|
{
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<bool> _this)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (bool value in _this)
|
||||||
|
{
|
||||||
|
byte bvalue = unchecked((byte)(value ? 1 : 0));
|
||||||
|
sb.AppendHex(bvalue);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<char> _this)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (char value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex((ushort)value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<byte> _this)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (byte value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<ushort> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (ushort value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (ushort value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<short> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (short value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (short value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<uint> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (uint value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (uint value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<int> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (int value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (int value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<ulong> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (ulong value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (ulong value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<long> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (long value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (long value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<float> _this)
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (float value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<double> _this)
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (double value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<string> _this)
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (string value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IEnumerable<IEnumerable<string>> _this)
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (IEnumerable<string> export in _this)
|
||||||
|
{
|
||||||
|
node.Add(export.ExportYAML());
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T>(this IEnumerable<T> _this, int[] version)
|
||||||
|
where T : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (T export in _this)
|
||||||
|
{
|
||||||
|
node.Add(export.ExportYAML(version));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T>(this IEnumerable<IEnumerable<T>> _this, int[] version)
|
||||||
|
where T : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (IEnumerable<T> export in _this)
|
||||||
|
{
|
||||||
|
node.Add(export.ExportYAML(version));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T>(this IEnumerable<Tuple<string, T>> _this, int[] version)
|
||||||
|
where T : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode();
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
map.Add(kvp.Item1, kvp.Item2.ExportYAML(version));
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T1, T2>(this IEnumerable<Tuple<T1, T2>> _this, Func<T1, int> converter, int[] version)
|
||||||
|
where T2 : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode();
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
map.Add(converter(kvp.Item1), kvp.Item2.ExportYAML(version));
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML<T>(this IEnumerable<KeyValuePair<string, T>> _this, int[] version)
|
||||||
|
where T : IYAMLExportable
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode();
|
||||||
|
foreach (var kvp in _this)
|
||||||
|
{
|
||||||
|
YAMLMappingNode map = new YAMLMappingNode();
|
||||||
|
map.Add(kvp.Key, kvp.Value.ExportYAML(version));
|
||||||
|
node.Add(map);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
171
AssetStudio/YAML/Utils/Extensions/IListYAMLExtensions.cs
Normal file
171
AssetStudio/YAML/Utils/Extensions/IListYAMLExtensions.cs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class IListYAMLExtensions
|
||||||
|
{
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyList<bool> _this)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Count * 2);
|
||||||
|
foreach (bool value in _this)
|
||||||
|
{
|
||||||
|
byte bvalue = unchecked((byte)(value ? 1 : 0));
|
||||||
|
sb.AppendHex(bvalue);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyList<char> _this)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Count * 4);
|
||||||
|
foreach (char value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex((ushort)value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyList<byte> _this)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Count * 2);
|
||||||
|
foreach (byte value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyList<ushort> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Count * 4);
|
||||||
|
foreach (ushort value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (ushort value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyList<short> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Count * 4);
|
||||||
|
foreach (short value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (short value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyList<uint> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Count * 8);
|
||||||
|
foreach (uint value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (uint value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyList<int> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Count * 8);
|
||||||
|
foreach (int value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (int value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyList<ulong> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Count * 16);
|
||||||
|
foreach (ulong value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (ulong value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLNode ExportYAML(this IReadOnlyList<long> _this, bool isRaw)
|
||||||
|
{
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(_this.Count * 16);
|
||||||
|
foreach (long value in _this)
|
||||||
|
{
|
||||||
|
sb.AppendHex(value);
|
||||||
|
}
|
||||||
|
return new YAMLScalarNode(sb.ToString(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YAMLSequenceNode node = new YAMLSequenceNode(SequenceStyle.Block);
|
||||||
|
foreach (long value in _this)
|
||||||
|
{
|
||||||
|
node.Add(value);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
AssetStudio/YAML/Utils/Extensions/PrimitiveExtensions.cs
Normal file
79
AssetStudio/YAML/Utils/Extensions/PrimitiveExtensions.cs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class PrimitiveExtensions
|
||||||
|
{
|
||||||
|
public static int ParseDigit(this char _this)
|
||||||
|
{
|
||||||
|
return _this - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToHexString(this byte _this)
|
||||||
|
{
|
||||||
|
return _this.ToString("x2");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToHexString(this short _this)
|
||||||
|
{
|
||||||
|
ushort value = unchecked((ushort)_this);
|
||||||
|
return ToHexString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToHexString(this ushort _this)
|
||||||
|
{
|
||||||
|
ushort reverse = unchecked((ushort)(((0xFF00 & _this) >> 8) | ((0x00FF & _this) << 8)));
|
||||||
|
return reverse.ToString("x4");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToHexString(this int _this)
|
||||||
|
{
|
||||||
|
uint value = unchecked((uint)_this);
|
||||||
|
return ToHexString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToHexString(this uint _this)
|
||||||
|
{
|
||||||
|
uint reverse = ((0xFF000000 & _this) >> 24) | ((0x00FF0000 & _this) >> 8) | ((0x0000FF00 & _this) << 8) | ((0x000000FF & _this) << 24);
|
||||||
|
return reverse.ToString("x8");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToHexString(this long _this)
|
||||||
|
{
|
||||||
|
ulong value = unchecked((ulong)_this);
|
||||||
|
return ToHexString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToHexString(this ulong _this)
|
||||||
|
{
|
||||||
|
ulong reverse = (_this & 0x00000000000000FFUL) << 56 | (_this & 0x000000000000FF00UL) << 40 |
|
||||||
|
(_this & 0x0000000000FF0000UL) << 24 | (_this & 0x00000000FF000000UL) << 8 |
|
||||||
|
(_this & 0x000000FF00000000UL) >> 8 | (_this & 0x0000FF0000000000UL) >> 24 |
|
||||||
|
(_this & 0x00FF000000000000UL) >> 40 | (_this & 0xFF00000000000000UL) >> 56;
|
||||||
|
return reverse.ToString("x16");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToHexString(this float _this)
|
||||||
|
{
|
||||||
|
uint value = BitConverterExtensions.ToUInt32(_this);
|
||||||
|
return ToHexString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToHexString(this double _this)
|
||||||
|
{
|
||||||
|
ulong value = BitConverterExtensions.ToUInt64(_this);
|
||||||
|
return ToHexString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ToClosestInt(this long _this)
|
||||||
|
{
|
||||||
|
if (_this > int.MaxValue)
|
||||||
|
{
|
||||||
|
return int.MaxValue;
|
||||||
|
}
|
||||||
|
if (_this < int.MinValue)
|
||||||
|
{
|
||||||
|
return int.MinValue;
|
||||||
|
}
|
||||||
|
return unchecked((int)_this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
AssetStudio/YAML/Utils/Extensions/StringBuilderExtensions.cs
Normal file
87
AssetStudio/YAML/Utils/Extensions/StringBuilderExtensions.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class StringBuilderExtensions
|
||||||
|
{
|
||||||
|
static StringBuilderExtensions()
|
||||||
|
{
|
||||||
|
for (int i = 0; i <= byte.MaxValue; i++)
|
||||||
|
{
|
||||||
|
ByteHexRepresentations[i] = i.ToString("x2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendHex(this StringBuilder _this, byte value)
|
||||||
|
{
|
||||||
|
_this.Append(ByteHexRepresentations[value]);
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendHex(this StringBuilder _this, ushort value)
|
||||||
|
{
|
||||||
|
_this.Append(ByteHexRepresentations[(value >> 0) & 0xFF]);
|
||||||
|
_this.Append(ByteHexRepresentations[(value >> 8) & 0xFF]);
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendHex(this StringBuilder _this, short value)
|
||||||
|
{
|
||||||
|
return AppendHex(_this, unchecked((ushort)value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendHex(this StringBuilder _this, uint value)
|
||||||
|
{
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 0) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 8) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 16) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 24) & 0xFF)]);
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendHex(this StringBuilder _this, int value)
|
||||||
|
{
|
||||||
|
return AppendHex(_this, unchecked((uint)value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendHex(this StringBuilder _this, ulong value)
|
||||||
|
{
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 0) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 8) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 16) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 24) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 32) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 40) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 48) & 0xFF)]);
|
||||||
|
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 56) & 0xFF)]);
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendHex(this StringBuilder _this, long value)
|
||||||
|
{
|
||||||
|
return AppendHex(_this, unchecked((ulong)value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendHex(this StringBuilder _this, float value)
|
||||||
|
{
|
||||||
|
return AppendHex(_this, BitConverterExtensions.ToUInt32(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendHex(this StringBuilder _this, double value)
|
||||||
|
{
|
||||||
|
return AppendHex(_this, BitConverterExtensions.ToUInt64(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringBuilder AppendIndent(this StringBuilder _this, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
_this.Append('\t');
|
||||||
|
}
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly string HexAlphabet = "0123456789abcdef";
|
||||||
|
public static readonly string[] ByteHexRepresentations = new string[256];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class YAMLMappingNodeExtensions
|
||||||
|
{
|
||||||
|
public static void AddSerializedVersion(this YAMLMappingNode _this, int version)
|
||||||
|
{
|
||||||
|
if(version > 1)
|
||||||
|
{
|
||||||
|
_this.Add(SerializedVersionName, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ForceAddSerializedVersion(this YAMLMappingNode _this, int version)
|
||||||
|
{
|
||||||
|
if (version > 0)
|
||||||
|
{
|
||||||
|
_this.Add(SerializedVersionName, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InsertSerializedVersion(this YAMLMappingNode _this, int version)
|
||||||
|
{
|
||||||
|
if(version > 1)
|
||||||
|
{
|
||||||
|
_this.InsertBegin(SerializedVersionName, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public const string SerializedVersionName = "serializedVersion";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -316,6 +316,16 @@ namespace AssetStudioCLI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool ExportAnimationClip(AssetItem item, string exportPath)
|
||||||
|
{
|
||||||
|
if (!TryExportFile(exportPath, item, ".anim", out var exportFullPath))
|
||||||
|
return false;
|
||||||
|
var m_AnimationClip = (AnimationClip)item.Asset;
|
||||||
|
var str = m_AnimationClip.Convert();
|
||||||
|
File.WriteAllText(exportFullPath, str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
|
public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
|
||||||
{
|
{
|
||||||
var exportFullPath = Path.Combine(exportPath, item.Text, item.Text + ".fbx");
|
var exportFullPath = Path.Combine(exportPath, item.Text, item.Text + ".fbx");
|
||||||
@@ -415,7 +425,7 @@ namespace AssetStudioCLI
|
|||||||
case ClassIDType.Animator:
|
case ClassIDType.Animator:
|
||||||
return ExportAnimator(item, exportPath);
|
return ExportAnimator(item, exportPath);
|
||||||
case ClassIDType.AnimationClip:
|
case ClassIDType.AnimationClip:
|
||||||
return false;
|
return ExportAnimationClip(item, exportPath);
|
||||||
case ClassIDType.MiHoYoBinData:
|
case ClassIDType.MiHoYoBinData:
|
||||||
return ExportMiHoYoBinData(item, exportPath);
|
return ExportMiHoYoBinData(item, exportPath);
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -78,6 +78,17 @@
|
|||||||
</ContentWithTargetPath>
|
</ContentWithTargetPath>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ContentWithTargetPath Include="Libraries\x86\acldb.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<TargetPath>x86\acldb.dll</TargetPath>
|
||||||
|
</ContentWithTargetPath>
|
||||||
|
<ContentWithTargetPath Include="Libraries\x64\acldb.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<TargetPath>x64\acldb.dll</TargetPath>
|
||||||
|
</ContentWithTargetPath>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="OpenTK" Version="4.8.0" />
|
<PackageReference Include="OpenTK" Version="4.8.0" />
|
||||||
|
|||||||
@@ -835,8 +835,8 @@ namespace AssetStudioGUI
|
|||||||
//StatusStripUpdate("Can be exported to FBX file.");
|
//StatusStripUpdate("Can be exported to FBX file.");
|
||||||
PreviewAnimator(m_Animator);
|
PreviewAnimator(m_Animator);
|
||||||
break;
|
break;
|
||||||
case AnimationClip _:
|
case AnimationClip m_AnimationClip:
|
||||||
StatusStripUpdate("Can be exported with Animator or Objects");
|
PreviewAnimationClip(m_AnimationClip);
|
||||||
break;
|
break;
|
||||||
case MiHoYoBinData m_MiHoYoBinData:
|
case MiHoYoBinData m_MiHoYoBinData:
|
||||||
PreviewText(m_MiHoYoBinData.AsString);
|
PreviewText(m_MiHoYoBinData.AsString);
|
||||||
@@ -1289,6 +1289,12 @@ namespace AssetStudioGUI
|
|||||||
PreviewModel(model);
|
PreviewModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PreviewAnimationClip(AnimationClip clip)
|
||||||
|
{
|
||||||
|
var str = clip.Convert();
|
||||||
|
PreviewText(str.Replace("\n", "\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
private void PreviewModel(ModelConverter model)
|
private void PreviewModel(ModelConverter model)
|
||||||
{
|
{
|
||||||
if (model.MeshList.Count > 0)
|
if (model.MeshList.Count > 0)
|
||||||
|
|||||||
@@ -315,6 +315,15 @@ namespace AssetStudioGUI
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
public static bool ExportAnimationClip(AssetItem item, string exportPath)
|
||||||
|
{
|
||||||
|
if (!TryExportFile(exportPath, item, ".anim", out var exportFullPath))
|
||||||
|
return false;
|
||||||
|
var m_AnimationClip = (AnimationClip)item.Asset;
|
||||||
|
var str = m_AnimationClip.Convert();
|
||||||
|
File.WriteAllText(exportFullPath, str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
|
public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
|
||||||
{
|
{
|
||||||
@@ -427,7 +436,7 @@ namespace AssetStudioGUI
|
|||||||
case ClassIDType.Animator:
|
case ClassIDType.Animator:
|
||||||
return ExportAnimator(item, exportPath);
|
return ExportAnimator(item, exportPath);
|
||||||
case ClassIDType.AnimationClip:
|
case ClassIDType.AnimationClip:
|
||||||
return false;
|
return ExportAnimationClip(item, exportPath);
|
||||||
case ClassIDType.MiHoYoBinData:
|
case ClassIDType.MiHoYoBinData:
|
||||||
return ExportMiHoYoBinData(item, exportPath);
|
return ExportMiHoYoBinData(item, exportPath);
|
||||||
default:
|
default:
|
||||||
|
|||||||
BIN
AssetStudioGUI/Libraries/x64/acldb.dll
Normal file
BIN
AssetStudioGUI/Libraries/x64/acldb.dll
Normal file
Binary file not shown.
BIN
AssetStudioGUI/Libraries/x86/acldb.dll
Normal file
BIN
AssetStudioGUI/Libraries/x86/acldb.dll
Normal file
Binary file not shown.
@@ -74,4 +74,48 @@ namespace ACLLibs
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class DBACL
|
||||||
|
{
|
||||||
|
private const string DLL_NAME = "acldb";
|
||||||
|
static DBACL()
|
||||||
|
{
|
||||||
|
DllLoader.PreloadDll(DLL_NAME);
|
||||||
|
}
|
||||||
|
public static void DecompressTracks(byte[] data, byte[] db, out float[] values, out float[] times)
|
||||||
|
{
|
||||||
|
var decompressedClip = new DecompressedClip();
|
||||||
|
|
||||||
|
var dataPtr = Marshal.AllocHGlobal(data.Length + 8);
|
||||||
|
var dataAligned = new IntPtr(16 * (((long)dataPtr + 15) / 16));
|
||||||
|
Marshal.Copy(data, 0, dataPtr, data.Length);
|
||||||
|
|
||||||
|
var dbPtr = Marshal.AllocHGlobal(db.Length + 8);
|
||||||
|
var dbAligned = new IntPtr(16 * (((long)dbPtr + 15) / 16));
|
||||||
|
Marshal.Copy(db, 0, dbAligned, db.Length);
|
||||||
|
|
||||||
|
DecompressTracks(dataAligned, dbAligned, ref decompressedClip);
|
||||||
|
|
||||||
|
Marshal.FreeHGlobal(dataPtr);
|
||||||
|
Marshal.FreeHGlobal(dbPtr);
|
||||||
|
|
||||||
|
values = new float[decompressedClip.ValuesCount];
|
||||||
|
Marshal.Copy(decompressedClip.Values, values, 0, decompressedClip.ValuesCount);
|
||||||
|
|
||||||
|
times = new float[decompressedClip.TimesCount];
|
||||||
|
Marshal.Copy(decompressedClip.Times, times, 0, decompressedClip.TimesCount);
|
||||||
|
|
||||||
|
Dispose(ref decompressedClip);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region importfunctions
|
||||||
|
|
||||||
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern void DecompressTracks(nint data, nint db, ref DecompressedClip decompressedClip);
|
||||||
|
|
||||||
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern void Dispose(ref DecompressedClip decompressedClip);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,23 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public static class ACLExtensions
|
public static class ACLExtensions
|
||||||
{
|
{
|
||||||
public static void Process(this ACLClip m_ACLClip, out float[] values, out float[] times) => ACL.DecompressAll(m_ACLClip.m_ClipData, out values, out times);
|
public static void Process(this ACLClip m_ACLClip, Game game, out float[] values, out float[] times)
|
||||||
public static void ProcessSR(this ACLClip m_ACLClip, out float[] values, out float[] times) => SRACL.DecompressAll(m_ACLClip.m_ClipData, out values, out times);
|
{
|
||||||
|
if (game.Type.IsSRGroup())
|
||||||
|
{
|
||||||
|
SRACL.DecompressAll(m_ACLClip.m_ClipData, out values, out times);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!m_ACLClip.m_DatabaseData.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
DBACL.DecompressTracks(m_ACLClip.m_ClipData, m_ACLClip.m_DatabaseData, out values, out times);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ACL.DecompressAll(m_ACLClip.m_ClipData, out values, out times);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -899,7 +899,7 @@ namespace AssetStudio
|
|||||||
var aclCount = m_ACLClip.m_CurveCount;
|
var aclCount = m_ACLClip.m_CurveCount;
|
||||||
if (!m_ACLClip.m_ClipData.IsNullOrEmpty() && !Game.Type.IsSRGroup())
|
if (!m_ACLClip.m_ClipData.IsNullOrEmpty() && !Game.Type.IsSRGroup())
|
||||||
{
|
{
|
||||||
m_ACLClip.Process(out var values, out var times);
|
m_ACLClip.Process(Game, out var values, out var times);
|
||||||
for (int frameIndex = 0; frameIndex < times.Length; frameIndex++)
|
for (int frameIndex = 0; frameIndex < times.Length; frameIndex++)
|
||||||
{
|
{
|
||||||
var time = times[frameIndex];
|
var time = times[frameIndex];
|
||||||
@@ -940,7 +940,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
if (!m_ACLClip.m_ClipData.IsNullOrEmpty() && Game.Type.IsSRGroup())
|
if (!m_ACLClip.m_ClipData.IsNullOrEmpty() && Game.Type.IsSRGroup())
|
||||||
{
|
{
|
||||||
m_ACLClip.ProcessSR(out var values, out var times);
|
m_ACLClip.Process(Game, out var values, out var times);
|
||||||
for (int frameIndex = 0; frameIndex < times.Length; frameIndex++)
|
for (int frameIndex = 0; frameIndex < times.Length; frameIndex++)
|
||||||
{
|
{
|
||||||
var time = times[frameIndex];
|
var time = times[frameIndex];
|
||||||
|
|||||||
538
AssetStudioUtility/YAML/AnimationClipConverter.cs
Normal file
538
AssetStudioUtility/YAML/AnimationClipConverter.cs
Normal file
@@ -0,0 +1,538 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using SevenZip;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public class AnimationClipConverter
|
||||||
|
{
|
||||||
|
public static readonly Regex UnknownPathRegex = new Regex($@"^{UnknownPathPrefix}[0-9]{{1,10}}$", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private const string UnknownPathPrefix = "path_";
|
||||||
|
private const string MissedPropertyPrefix = "missed_";
|
||||||
|
private const string ScriptPropertyPrefix = "script_";
|
||||||
|
private const string TypeTreePropertyPrefix = "typetree_";
|
||||||
|
|
||||||
|
private readonly Game game;
|
||||||
|
private readonly AnimationClip animationClip;
|
||||||
|
private readonly CustomCurveResolver m_customCurveResolver;
|
||||||
|
|
||||||
|
private readonly Dictionary<Vector3Curve, List<Keyframe<Vector3>>> m_translations = new Dictionary<Vector3Curve, List<Keyframe<Vector3>>>();
|
||||||
|
private readonly Dictionary<QuaternionCurve, List<Keyframe<Quaternion>>> m_rotations = new Dictionary<QuaternionCurve, List<Keyframe<Quaternion>>>();
|
||||||
|
private readonly Dictionary<Vector3Curve, List<Keyframe<Vector3>>> m_scales = new Dictionary<Vector3Curve, List<Keyframe<Vector3>>>();
|
||||||
|
private readonly Dictionary<Vector3Curve, List<Keyframe<Vector3>>> m_eulers = new Dictionary<Vector3Curve, List<Keyframe<Vector3>>>();
|
||||||
|
private readonly Dictionary<FloatCurve, List<Keyframe<Float>>> m_floats = new Dictionary<FloatCurve, List<Keyframe<Float>>>();
|
||||||
|
private readonly Dictionary<PPtrCurve, List<PPtrKeyframe>> m_pptrs = new Dictionary<PPtrCurve, List<PPtrKeyframe>>();
|
||||||
|
|
||||||
|
public Vector3Curve[] Translations { get; private set; }
|
||||||
|
public QuaternionCurve[] Rotations { get; private set; }
|
||||||
|
public Vector3Curve[] Scales { get; private set; }
|
||||||
|
public Vector3Curve[] Eulers { get; private set; }
|
||||||
|
public FloatCurve[] Floats { get; private set; }
|
||||||
|
public PPtrCurve[] PPtrs { get; private set; }
|
||||||
|
|
||||||
|
public AnimationClipConverter(AnimationClip clip)
|
||||||
|
{
|
||||||
|
game = clip.assetsFile.game;
|
||||||
|
animationClip = clip;
|
||||||
|
m_customCurveResolver = new CustomCurveResolver(animationClip);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AnimationClipConverter Process(AnimationClip clip)
|
||||||
|
{
|
||||||
|
var converter = new AnimationClipConverter(clip);
|
||||||
|
converter.ProcessInner();
|
||||||
|
return converter;
|
||||||
|
}
|
||||||
|
private void ProcessInner()
|
||||||
|
{
|
||||||
|
var m_Clip = animationClip.m_MuscleClip.m_Clip;
|
||||||
|
var bindings = animationClip.m_ClipBindingConstant;
|
||||||
|
var tos = animationClip.FindTOS();
|
||||||
|
|
||||||
|
var streamedFrames = m_Clip.m_StreamedClip.ReadData();
|
||||||
|
var lastDenseFrame = m_Clip.m_DenseClip.m_FrameCount / m_Clip.m_DenseClip.m_SampleRate;
|
||||||
|
var lastSampleFrame = streamedFrames.Count > 1 ? streamedFrames[streamedFrames.Count - 2].time : 0.0f;
|
||||||
|
var lastFrame = Math.Max(lastDenseFrame, lastSampleFrame);
|
||||||
|
|
||||||
|
if (!m_Clip.m_ACLClip.m_ClipData.IsNullOrEmpty() && !game.Type.IsSRGroup())
|
||||||
|
{
|
||||||
|
var lastACLFrame = ProcessACLClip(m_Clip, bindings, tos);
|
||||||
|
lastFrame = Math.Max(lastFrame, lastACLFrame);
|
||||||
|
animationClip.m_Compressed = false;
|
||||||
|
}
|
||||||
|
ProcessStreams(streamedFrames, bindings, tos, m_Clip.m_DenseClip.m_SampleRate);
|
||||||
|
ProcessDenses(m_Clip, bindings, tos);
|
||||||
|
if (!m_Clip.m_ACLClip.m_ClipData.IsNullOrEmpty() && game.Type.IsSRGroup())
|
||||||
|
{
|
||||||
|
var lastACLFrame = ProcessACLClip(m_Clip, bindings, tos);
|
||||||
|
lastFrame = Math.Max(lastFrame, lastACLFrame);
|
||||||
|
animationClip.m_Compressed = false;
|
||||||
|
}
|
||||||
|
if (m_Clip.m_ConstantClip != null)
|
||||||
|
{
|
||||||
|
ProcessConstant(m_Clip, bindings, tos, lastFrame);
|
||||||
|
}
|
||||||
|
CreateCurves();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateCurves()
|
||||||
|
{
|
||||||
|
m_translations.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||||
|
Translations = m_translations.Keys.ToArray();
|
||||||
|
m_rotations.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||||
|
Rotations = m_rotations.Keys.ToArray();
|
||||||
|
m_scales.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||||
|
Scales = m_scales.Keys.ToArray();
|
||||||
|
m_eulers.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||||
|
Eulers = m_eulers.Keys.ToArray();
|
||||||
|
m_floats.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||||
|
Floats = m_floats.Keys.ToArray();
|
||||||
|
m_pptrs.AsEnumerable().ToList().ForEach(x => x.Key.curve.AddRange(x.Value));
|
||||||
|
PPtrs = m_pptrs.Keys.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessStreams(List<StreamedClip.StreamedFrame> streamFrames, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos, float sampleRate)
|
||||||
|
{
|
||||||
|
var curveValues = new float[4];
|
||||||
|
var inSlopeValues = new float[4];
|
||||||
|
var outSlopeValues = new float[4];
|
||||||
|
var interval = 1.0f / sampleRate;
|
||||||
|
|
||||||
|
// first (index [0]) stream frame is for slope calculation for the first real frame (index [1])
|
||||||
|
// last one (index [count - 1]) is +Infinity
|
||||||
|
// it is made for slope processing, but we don't need them
|
||||||
|
for (var frameIndex = 1; frameIndex < streamFrames.Count - 1; frameIndex++)
|
||||||
|
{
|
||||||
|
var frame = streamFrames[frameIndex];
|
||||||
|
for (var curveIndex = 0; curveIndex < frame.keyList.Length;)
|
||||||
|
{
|
||||||
|
var curve = frame.keyList[curveIndex];
|
||||||
|
var index = curve.index;
|
||||||
|
if (!game.Type.IsSRGroup())
|
||||||
|
index += (int)animationClip.m_MuscleClip.m_Clip.m_ACLClip.m_CurveCount;
|
||||||
|
var binding = bindings.FindBinding(index);
|
||||||
|
|
||||||
|
var path = GetCurvePath(tos, binding.path);
|
||||||
|
if (binding.typeID == ClassIDType.Transform)
|
||||||
|
{
|
||||||
|
GetPreviousFrame(streamFrames, curve.index, frameIndex, out var prevFrameIndex, out var prevCurveIndex);
|
||||||
|
var dimension = binding.GetDimension();
|
||||||
|
for (int key = 0; key < dimension; key++)
|
||||||
|
{
|
||||||
|
var keyCurve = frame.keyList[curveIndex];
|
||||||
|
var prevFrame = streamFrames[prevFrameIndex];
|
||||||
|
var prevKeyCurve = prevFrame.keyList[prevCurveIndex + key];
|
||||||
|
var deltaTime = frame.time - prevFrame.time;
|
||||||
|
curveValues[key] = keyCurve.value;
|
||||||
|
inSlopeValues[key] = prevKeyCurve.CalculateNextInSlope(deltaTime, keyCurve);
|
||||||
|
outSlopeValues[key] = keyCurve.outSlope;
|
||||||
|
curveIndex = GetNextCurve(frame, curveIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddTransformCurve(frame.time, binding.attribute, curveValues, inSlopeValues, outSlopeValues, 0, path);
|
||||||
|
}
|
||||||
|
else if ((BindingCustomType)binding.customType == BindingCustomType.None)
|
||||||
|
{
|
||||||
|
AddDefaultCurve(binding, path, frame.time, frame.keyList[curveIndex].value);
|
||||||
|
curveIndex = GetNextCurve(frame, curveIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddCustomCurve(bindings, binding, path, frame.time, frame.keyList[curveIndex].value);
|
||||||
|
curveIndex = GetNextCurve(frame, curveIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessDenses(Clip clip, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos)
|
||||||
|
{
|
||||||
|
var dense = clip.m_DenseClip;
|
||||||
|
var streamCount = clip.m_StreamedClip.curveCount;
|
||||||
|
var slopeValues = new float[4]; // no slopes - 0 values
|
||||||
|
for (var frameIndex = 0; frameIndex < dense.m_FrameCount; frameIndex++)
|
||||||
|
{
|
||||||
|
var time = frameIndex / dense.m_SampleRate;
|
||||||
|
var frameOffset = frameIndex * (int)dense.m_CurveCount;
|
||||||
|
for (var curveIndex = 0; curveIndex < dense.m_CurveCount;)
|
||||||
|
{
|
||||||
|
var index = (int)streamCount + curveIndex;
|
||||||
|
if (!game.Type.IsSRGroup())
|
||||||
|
index += (int)clip.m_ACLClip.m_CurveCount;
|
||||||
|
var binding = bindings.FindBinding(index);
|
||||||
|
var path = GetCurvePath(tos, binding.path);
|
||||||
|
var framePosition = frameOffset + curveIndex;
|
||||||
|
if (binding.typeID == ClassIDType.Transform)
|
||||||
|
{
|
||||||
|
AddTransformCurve(time, binding.attribute, dense.m_SampleArray, slopeValues, slopeValues, framePosition, path);
|
||||||
|
curveIndex += binding.GetDimension();
|
||||||
|
}
|
||||||
|
else if ((BindingCustomType)binding.customType == BindingCustomType.None)
|
||||||
|
{
|
||||||
|
AddDefaultCurve(binding, path, time, dense.m_SampleArray[framePosition]);
|
||||||
|
curveIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddCustomCurve(bindings, binding, path, time, dense.m_SampleArray[framePosition]);
|
||||||
|
curveIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private float ProcessACLClip(Clip clip, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos)
|
||||||
|
{
|
||||||
|
var acl = clip.m_ACLClip;
|
||||||
|
acl.Process(game, out var values, out var times);
|
||||||
|
float[] slopeValues = new float[4]; // no slopes - 0 values
|
||||||
|
|
||||||
|
int frameCount = times.Length;
|
||||||
|
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
|
||||||
|
{
|
||||||
|
float time = times[frameIndex];
|
||||||
|
int frameOffset = frameIndex * (int)acl.m_CurveCount;
|
||||||
|
for (int curveIndex = 0; curveIndex < acl.m_CurveCount;)
|
||||||
|
{
|
||||||
|
var index = curveIndex;
|
||||||
|
if (game.Type.IsSRGroup())
|
||||||
|
index += (int)(clip.m_DenseClip.m_CurveCount + clip.m_StreamedClip.curveCount);
|
||||||
|
GenericBinding binding = bindings.FindBinding(index);
|
||||||
|
string path = GetCurvePath(tos, binding.path);
|
||||||
|
int framePosition = frameOffset + curveIndex;
|
||||||
|
if (binding.typeID == ClassIDType.Transform)
|
||||||
|
{
|
||||||
|
AddTransformCurve(time, binding.attribute, values, slopeValues, slopeValues, framePosition, path);
|
||||||
|
curveIndex += binding.GetDimension();
|
||||||
|
}
|
||||||
|
else if ((BindingCustomType)binding.customType == BindingCustomType.None)
|
||||||
|
{
|
||||||
|
AddDefaultCurve(binding, path, time, values[framePosition]);
|
||||||
|
curveIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddCustomCurve(bindings, binding, path, time, values[framePosition]);
|
||||||
|
curveIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return times[frameCount - 1];
|
||||||
|
}
|
||||||
|
private void ProcessConstant(Clip clip, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos, float lastFrame)
|
||||||
|
{
|
||||||
|
var constant = clip.m_ConstantClip;
|
||||||
|
var streamCount = clip.m_StreamedClip.curveCount;
|
||||||
|
var denseCount = clip.m_DenseClip.m_CurveCount;
|
||||||
|
var slopeValues = new float[4]; // no slopes - 0 values
|
||||||
|
|
||||||
|
// only first and last frames
|
||||||
|
var time = 0.0f;
|
||||||
|
for (var i = 0; i < 2; i++, time += lastFrame)
|
||||||
|
{
|
||||||
|
for (var curveIndex = 0; curveIndex < constant.data.Length;)
|
||||||
|
{
|
||||||
|
var index = (int)(streamCount + denseCount + curveIndex);
|
||||||
|
if (!clip.m_ACLClip.m_ClipData.IsNullOrEmpty())
|
||||||
|
index += (int)clip.m_ACLClip.m_CurveCount;
|
||||||
|
GenericBinding binding = bindings.FindBinding(index);
|
||||||
|
string path = GetCurvePath(tos, binding.path);
|
||||||
|
if (binding.typeID == ClassIDType.Transform)
|
||||||
|
{
|
||||||
|
AddTransformCurve(time, binding.attribute, constant.data, slopeValues, slopeValues, curveIndex, path);
|
||||||
|
curveIndex += binding.GetDimension();
|
||||||
|
}
|
||||||
|
else if ((BindingCustomType)binding.customType == BindingCustomType.None)
|
||||||
|
{
|
||||||
|
AddDefaultCurve(binding, path, time, constant.data[curveIndex]);
|
||||||
|
curveIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddCustomCurve(bindings, binding, path, time, constant.data[curveIndex]);
|
||||||
|
curveIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddCustomCurve(AnimationClipBindingConstant bindings, GenericBinding binding, string path, float time, float value)
|
||||||
|
{
|
||||||
|
switch ((BindingCustomType)binding.customType)
|
||||||
|
{
|
||||||
|
case BindingCustomType.AnimatorMuscle:
|
||||||
|
AddAnimatorMuscleCurve(binding, time, value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
string attribute = m_customCurveResolver.ToAttributeName((BindingCustomType)binding.customType, binding.attribute, path);
|
||||||
|
if (binding.isPPtrCurve == 0x01)
|
||||||
|
{
|
||||||
|
PPtrCurve curve = new PPtrCurve(path, attribute, binding.typeID, binding.script.Cast<MonoScript>());
|
||||||
|
AddPPtrKeyframe(curve, bindings, time, (int)value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FloatCurve curve = new FloatCurve(path, attribute, binding.typeID, binding.script.Cast<MonoScript>());
|
||||||
|
AddFloatKeyframe(curve, time, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddTransformCurve(float time, uint transType, float[] curveValues,
|
||||||
|
float[] inSlopeValues, float[] outSlopeValues, int offset, string path)
|
||||||
|
{
|
||||||
|
switch (transType)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
var curve = new Vector3Curve(path);
|
||||||
|
if (!m_translations.TryGetValue(curve, out List<Keyframe<Vector3>> transCurve))
|
||||||
|
{
|
||||||
|
transCurve = new List<Keyframe<Vector3>>();
|
||||||
|
m_translations.Add(curve, transCurve);
|
||||||
|
}
|
||||||
|
|
||||||
|
float x = curveValues[offset + 0];
|
||||||
|
float y = curveValues[offset + 1];
|
||||||
|
float z = curveValues[offset + 2];
|
||||||
|
|
||||||
|
float inX = inSlopeValues[0];
|
||||||
|
float inY = inSlopeValues[1];
|
||||||
|
float inZ = inSlopeValues[2];
|
||||||
|
|
||||||
|
float outX = outSlopeValues[0];
|
||||||
|
float outY = outSlopeValues[1];
|
||||||
|
float outZ = outSlopeValues[2];
|
||||||
|
|
||||||
|
Vector3 value = new Vector3(x, y, z);
|
||||||
|
Vector3 inSlope = new Vector3(inX, inY, inZ);
|
||||||
|
Vector3 outSlope = new Vector3(outX, outY, outZ);
|
||||||
|
Keyframe<Vector3> transKey = new Keyframe<Vector3>(time, value, inSlope, outSlope, AnimationClipExtensions.DefaultVector3Weight);
|
||||||
|
transCurve.Add(transKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
var curve = new QuaternionCurve(path);
|
||||||
|
if (!m_rotations.TryGetValue(curve, out List<Keyframe<Quaternion>> rotCurve))
|
||||||
|
{
|
||||||
|
rotCurve = new List<Keyframe<Quaternion>>();
|
||||||
|
m_rotations.Add(curve, rotCurve);
|
||||||
|
}
|
||||||
|
|
||||||
|
float x = curveValues[offset + 0];
|
||||||
|
float y = curveValues[offset + 1];
|
||||||
|
float z = curveValues[offset + 2];
|
||||||
|
float w = curveValues[offset + 3];
|
||||||
|
|
||||||
|
float inX = inSlopeValues[0];
|
||||||
|
float inY = inSlopeValues[1];
|
||||||
|
float inZ = inSlopeValues[2];
|
||||||
|
float inW = inSlopeValues[3];
|
||||||
|
|
||||||
|
float outX = outSlopeValues[0];
|
||||||
|
float outY = outSlopeValues[1];
|
||||||
|
float outZ = outSlopeValues[2];
|
||||||
|
float outW = outSlopeValues[3];
|
||||||
|
|
||||||
|
Quaternion value = new Quaternion(x, y, z, w);
|
||||||
|
Quaternion inSlope = new Quaternion(inX, inY, inZ, inW);
|
||||||
|
Quaternion outSlope = new Quaternion(outX, outY, outZ, outW);
|
||||||
|
Keyframe<Quaternion> rotKey = new Keyframe<Quaternion>(time, value, inSlope, outSlope, AnimationClipExtensions.DefaultQuaternionWeight);
|
||||||
|
rotCurve.Add(rotKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
var curve = new Vector3Curve(path);
|
||||||
|
if (!m_scales.TryGetValue(curve, out List<Keyframe<Vector3>> scaleCurve))
|
||||||
|
{
|
||||||
|
scaleCurve = new List<Keyframe<Vector3>>();
|
||||||
|
m_scales.Add(curve, scaleCurve);
|
||||||
|
}
|
||||||
|
|
||||||
|
float x = curveValues[offset + 0];
|
||||||
|
float y = curveValues[offset + 1];
|
||||||
|
float z = curveValues[offset + 2];
|
||||||
|
|
||||||
|
float inX = inSlopeValues[0];
|
||||||
|
float inY = inSlopeValues[1];
|
||||||
|
float inZ = inSlopeValues[2];
|
||||||
|
|
||||||
|
float outX = outSlopeValues[0];
|
||||||
|
float outY = outSlopeValues[1];
|
||||||
|
float outZ = outSlopeValues[2];
|
||||||
|
|
||||||
|
Vector3 value = new Vector3(x, y, z);
|
||||||
|
Vector3 inSlope = new Vector3(inX, inY, inZ);
|
||||||
|
Vector3 outSlope = new Vector3(outX, outY, outZ);
|
||||||
|
Keyframe<Vector3> scaleKey = new Keyframe<Vector3>(time, value, inSlope, outSlope, AnimationClipExtensions.DefaultVector3Weight);
|
||||||
|
scaleCurve.Add(scaleKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
var curve = new Vector3Curve(path);
|
||||||
|
if (!m_eulers.TryGetValue(curve, out List<Keyframe<Vector3>> eulerCurve))
|
||||||
|
{
|
||||||
|
eulerCurve = new List<Keyframe<Vector3>>();
|
||||||
|
m_eulers.Add(curve, eulerCurve);
|
||||||
|
}
|
||||||
|
|
||||||
|
float x = curveValues[offset + 0];
|
||||||
|
float y = curveValues[offset + 1];
|
||||||
|
float z = curveValues[offset + 2];
|
||||||
|
|
||||||
|
float inX = inSlopeValues[0];
|
||||||
|
float inY = inSlopeValues[1];
|
||||||
|
float inZ = inSlopeValues[2];
|
||||||
|
|
||||||
|
float outX = outSlopeValues[0];
|
||||||
|
float outY = outSlopeValues[1];
|
||||||
|
float outZ = outSlopeValues[2];
|
||||||
|
|
||||||
|
Vector3 value = new Vector3(x, y, z);
|
||||||
|
Vector3 inSlope = new Vector3(inX, inY, inZ);
|
||||||
|
Vector3 outSlope = new Vector3(outX, outY, outZ);
|
||||||
|
Keyframe<Vector3> eulerKey = new Keyframe<Vector3>(time, value, inSlope, outSlope, AnimationClipExtensions.DefaultVector3Weight);
|
||||||
|
eulerCurve.Add(eulerKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(transType.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddDefaultCurve(GenericBinding binding, string path, float time, float value)
|
||||||
|
{
|
||||||
|
switch (binding.typeID)
|
||||||
|
{
|
||||||
|
case ClassIDType.GameObject:
|
||||||
|
{
|
||||||
|
AddGameObjectCurve(binding, path, time, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ClassIDType.MonoBehaviour:
|
||||||
|
{
|
||||||
|
AddScriptCurve(binding, path, time, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
AddEngineCurve(binding, path, time, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddGameObjectCurve(GenericBinding binding, string path, float time, float value)
|
||||||
|
{
|
||||||
|
if (binding.attribute == CRC.CalculateDigestAscii("m_IsActive"))
|
||||||
|
{
|
||||||
|
FloatCurve curve = new FloatCurve(path, "m_IsActive", ClassIDType.GameObject, new PPtr<MonoScript>(0, 0, null));
|
||||||
|
AddFloatKeyframe(curve, time, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// that means that dev exported animation clip with missing component
|
||||||
|
FloatCurve curve = new FloatCurve(path, MissedPropertyPrefix + binding.attribute, ClassIDType.GameObject, new PPtr<MonoScript>(0, 0, null));
|
||||||
|
AddFloatKeyframe(curve, time, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddScriptCurve(GenericBinding binding, string path, float time, float value)
|
||||||
|
{
|
||||||
|
#warning TODO:
|
||||||
|
FloatCurve curve = new FloatCurve(path, ScriptPropertyPrefix + binding.attribute, ClassIDType.MonoBehaviour, binding.script.Cast<MonoScript>());
|
||||||
|
AddFloatKeyframe(curve, time, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddEngineCurve(GenericBinding binding, string path, float time, float value)
|
||||||
|
{
|
||||||
|
#warning TODO:
|
||||||
|
FloatCurve curve = new FloatCurve(path, TypeTreePropertyPrefix + binding.attribute, binding.typeID, new PPtr<MonoScript>(0, 0, null));
|
||||||
|
AddFloatKeyframe(curve, time, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddAnimatorMuscleCurve(GenericBinding binding, float time, float value)
|
||||||
|
{
|
||||||
|
FloatCurve curve = new FloatCurve(string.Empty, binding.GetHumanoidMuscle().ToAttributeString(), ClassIDType.Animator, new PPtr<MonoScript>(0, 0, null));
|
||||||
|
AddFloatKeyframe(curve, time, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddFloatKeyframe(FloatCurve curve, float time, float value)
|
||||||
|
{
|
||||||
|
if (!m_floats.TryGetValue(curve, out List<Keyframe<Float>> floatCurve))
|
||||||
|
{
|
||||||
|
floatCurve = new List<Keyframe<Float>>();
|
||||||
|
m_floats.Add(curve, floatCurve);
|
||||||
|
}
|
||||||
|
|
||||||
|
Keyframe<Float> floatKey = new Keyframe<Float>(time, value, default, default, AnimationClipExtensions.DefaultFloatWeight);
|
||||||
|
floatCurve.Add(floatKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddPPtrKeyframe(PPtrCurve curve, AnimationClipBindingConstant bindings, float time, int index)
|
||||||
|
{
|
||||||
|
if (!m_pptrs.TryGetValue(curve, out List<PPtrKeyframe> pptrCurve))
|
||||||
|
{
|
||||||
|
pptrCurve = new List<PPtrKeyframe>();
|
||||||
|
m_pptrs.Add(curve, pptrCurve);
|
||||||
|
AddPPtrKeyframe(curve, bindings, 0.0f, index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
PPtr<Object> value = bindings.pptrCurveMapping[index];
|
||||||
|
PPtrKeyframe pptrKey = new PPtrKeyframe(time, value);
|
||||||
|
pptrCurve.Add(pptrKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetPreviousFrame(List<StreamedClip.StreamedFrame> streamFrames, int curveID, int currentFrame, out int frameIndex, out int curveIndex)
|
||||||
|
{
|
||||||
|
for (frameIndex = currentFrame - 1; frameIndex >= 0; frameIndex--)
|
||||||
|
{
|
||||||
|
var frame = streamFrames[frameIndex];
|
||||||
|
for (curveIndex = 0; curveIndex < frame.keyList.Length; curveIndex++)
|
||||||
|
{
|
||||||
|
var curve = frame.keyList[curveIndex];
|
||||||
|
if (curve.index == curveID)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception($"There is no curve with index {curveID} in any of previous frames");
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetNextCurve(StreamedClip.StreamedFrame frame, int currentCurve)
|
||||||
|
{
|
||||||
|
var curve = frame.keyList[currentCurve];
|
||||||
|
int i = currentCurve + 1;
|
||||||
|
for (; i < frame.keyList.Length; i++)
|
||||||
|
{
|
||||||
|
if (frame.keyList[i].index != curve.index)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetCurvePath(Dictionary<uint, string> tos, uint hash)
|
||||||
|
{
|
||||||
|
if (tos.TryGetValue(hash, out string path))
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return UnknownPathPrefix + hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
335
AssetStudioUtility/YAML/AnimationClipExtensions.cs
Normal file
335
AssetStudioUtility/YAML/AnimationClipExtensions.cs
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using SevenZip;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class AnimationClipExtensions
|
||||||
|
{
|
||||||
|
public static float DefaultFloatWeight => 1.0f / 3.0f;
|
||||||
|
public static Vector3 DefaultVector3Weight => new Vector3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f);
|
||||||
|
public static Quaternion DefaultQuaternionWeight => new Quaternion(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f);
|
||||||
|
|
||||||
|
#region AnimationClip
|
||||||
|
public static IEnumerable<GameObject> FindRoots(this AnimationClip clip)
|
||||||
|
{
|
||||||
|
foreach (var asset in clip.assetsFile.assetsManager.assetsFileList.SelectMany(x => x.Objects))
|
||||||
|
{
|
||||||
|
switch (asset.type)
|
||||||
|
{
|
||||||
|
case ClassIDType.Animator:
|
||||||
|
Animator animator = (Animator)asset;
|
||||||
|
if (clip.IsAnimatorContainsClip(animator))
|
||||||
|
{
|
||||||
|
if (animator.m_GameObject.TryGet(out var go))
|
||||||
|
{
|
||||||
|
yield return go;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ClassIDType.Animation:
|
||||||
|
Animation animation = (Animation)asset;
|
||||||
|
if (clip.IsAnimationContainsClip(animation))
|
||||||
|
{
|
||||||
|
if (animation.m_GameObject.TryGet(out var go))
|
||||||
|
{
|
||||||
|
yield return go;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
public static Dictionary<uint, string> FindTOS(this AnimationClip clip)
|
||||||
|
{
|
||||||
|
var tos = new Dictionary<uint, string>() { { 0, string.Empty } };
|
||||||
|
foreach (var asset in clip.assetsFile.assetsManager.assetsFileList.SelectMany(x => x.Objects).OrderBy(x => x.type).ToArray())
|
||||||
|
{
|
||||||
|
switch (asset.type)
|
||||||
|
{
|
||||||
|
case ClassIDType.Avatar:
|
||||||
|
var avatar = asset as Avatar;
|
||||||
|
if (clip.AddAvatarTOS(avatar, tos))
|
||||||
|
{
|
||||||
|
return tos;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ClassIDType.Animator:
|
||||||
|
var animator = asset as Animator;
|
||||||
|
if (clip.IsAnimatorContainsClip(animator))
|
||||||
|
{
|
||||||
|
if (clip.AddAnimatorTOS(animator, tos))
|
||||||
|
{
|
||||||
|
return tos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ClassIDType.Animation:
|
||||||
|
var animation = asset as Animation;
|
||||||
|
if (clip.IsAnimationContainsClip(animation))
|
||||||
|
{
|
||||||
|
if (clip.AddAnimationTOS(animation, tos))
|
||||||
|
{
|
||||||
|
return tos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tos;
|
||||||
|
}
|
||||||
|
private static bool AddAvatarTOS(this AnimationClip clip, Avatar avatar, Dictionary<uint, string> tos)
|
||||||
|
{
|
||||||
|
return clip.AddTOS(avatar.m_TOS.ToDictionary(x => x.Key, x => x.Value), tos);
|
||||||
|
}
|
||||||
|
private static bool AddAnimatorTOS(this AnimationClip clip, Animator animator, Dictionary<uint, string> tos)
|
||||||
|
{
|
||||||
|
if (animator.m_Avatar.TryGet(out var avatar))
|
||||||
|
{
|
||||||
|
if (clip.AddAvatarTOS(avatar, tos))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<uint, string> animatorTOS = animator.BuildTOS();
|
||||||
|
return clip.AddTOS(animatorTOS, tos);
|
||||||
|
}
|
||||||
|
private static bool AddAnimationTOS(this AnimationClip clip, Animation animation, Dictionary<uint, string> tos)
|
||||||
|
{
|
||||||
|
if (animation.m_GameObject.TryGet(out var go))
|
||||||
|
{
|
||||||
|
Dictionary<uint, string> animationTOS = go.BuildTOS();
|
||||||
|
return clip.AddTOS(animationTOS, tos);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private static bool AddTOS(this AnimationClip clip, Dictionary<uint, string> src, Dictionary<uint, string> dest)
|
||||||
|
{
|
||||||
|
int tosCount = clip.m_ClipBindingConstant.genericBindings.Length;
|
||||||
|
for (int i = 0; i < tosCount; i++)
|
||||||
|
{
|
||||||
|
ref GenericBinding binding = ref clip.m_ClipBindingConstant.genericBindings[i];
|
||||||
|
if (src.TryGetValue(binding.path, out string path))
|
||||||
|
{
|
||||||
|
dest[binding.path] = path;
|
||||||
|
if (dest.Count == tosCount)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private static bool IsAnimationContainsClip(this AnimationClip clip, Animation animation)
|
||||||
|
{
|
||||||
|
return animation.IsContainsAnimationClip(clip);
|
||||||
|
}
|
||||||
|
private static bool IsAnimatorContainsClip(this AnimationClip clip, Animator animator)
|
||||||
|
{
|
||||||
|
if (animator.m_Controller.TryGet(out var runtime))
|
||||||
|
{
|
||||||
|
return runtime.IsContainsAnimationClip(clip);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static string Convert(this AnimationClip clip)
|
||||||
|
{
|
||||||
|
var converter = AnimationClipConverter.Process(clip);
|
||||||
|
clip.m_RotationCurves = converter.Rotations.Union(clip.m_RotationCurves).ToArray();
|
||||||
|
clip.m_EulerCurves = converter.Eulers.Union(clip.m_EulerCurves).ToArray();
|
||||||
|
clip.m_PositionCurves = converter.Translations.Union(clip.m_PositionCurves).ToArray();
|
||||||
|
clip.m_ScaleCurves = converter.Scales.Union(clip.m_ScaleCurves).ToArray();
|
||||||
|
clip.m_FloatCurves = converter.Floats.Union(clip.m_FloatCurves).ToArray();
|
||||||
|
clip.m_PPtrCurves = converter.PPtrs.Union(clip.m_PPtrCurves).ToArray();
|
||||||
|
return ConvertSerializedAnimationClip(clip);
|
||||||
|
}
|
||||||
|
public static string ConvertSerializedAnimationClip(AnimationClip animationClip)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
using (var stringWriter = new StringWriter(sb))
|
||||||
|
{
|
||||||
|
YAMLWriter writer = new YAMLWriter();
|
||||||
|
YAMLDocument doc = ExportYAMLDocument(animationClip);
|
||||||
|
writer.AddDocument(doc);
|
||||||
|
writer.Write(stringWriter);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YAMLDocument ExportYAMLDocument(AnimationClip animationClip)
|
||||||
|
{
|
||||||
|
var document = new YAMLDocument();
|
||||||
|
var root = document.CreateMappingRoot();
|
||||||
|
root.Tag = ((int)ClassIDType.AnimationClip).ToString();
|
||||||
|
root.Anchor = ((int)ClassIDType.AnimationClip * 100000).ToString();
|
||||||
|
var node = animationClip.ExportYAML(animationClip.version);
|
||||||
|
root.Add(ClassIDType.AnimationClip.ToString(), node);
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
public static YAMLMappingNode ExportYAML(this AnimationClip clip, int[] version)
|
||||||
|
{
|
||||||
|
var node = new YAMLMappingNode();
|
||||||
|
node.Add(nameof(clip.m_Name), clip.m_Name);
|
||||||
|
node.AddSerializedVersion(ToSerializedVersion(version));
|
||||||
|
node.Add(nameof(clip.m_Legacy), clip.m_Legacy);
|
||||||
|
node.Add(nameof(clip.m_Compressed), clip.m_Compressed);
|
||||||
|
node.Add(nameof(clip.m_UseHighQualityCurve), clip.m_UseHighQualityCurve);
|
||||||
|
node.Add(nameof(clip.m_RotationCurves), clip.m_RotationCurves.ExportYAML(version));
|
||||||
|
node.Add(nameof(clip.m_CompressedRotationCurves), clip.m_CompressedRotationCurves.ExportYAML(version));
|
||||||
|
node.Add(nameof(clip.m_EulerCurves), clip.m_EulerCurves.ExportYAML(version));
|
||||||
|
node.Add(nameof(clip.m_PositionCurves), clip.m_PositionCurves.ExportYAML(version));
|
||||||
|
node.Add(nameof(clip.m_ScaleCurves), clip.m_ScaleCurves.ExportYAML(version));
|
||||||
|
node.Add(nameof(clip.m_FloatCurves), clip.m_FloatCurves.ExportYAML(version));
|
||||||
|
node.Add(nameof(clip.m_PPtrCurves), clip.m_PPtrCurves.ExportYAML(version));
|
||||||
|
node.Add(nameof(clip.m_SampleRate), clip.m_SampleRate);
|
||||||
|
node.Add(nameof(clip.m_WrapMode), clip.m_WrapMode);
|
||||||
|
node.Add(nameof(clip.m_Bounds), clip.m_Bounds.ExportYAML(version));
|
||||||
|
node.Add(nameof(clip.m_ClipBindingConstant), clip.m_ClipBindingConstant.ExportYAML(version));
|
||||||
|
node.Add("m_AnimationClipSettings", clip.m_MuscleClip.ExportYAML(version));
|
||||||
|
node.Add(nameof(clip.m_Events), clip.m_Events.ExportYAML(version));
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ToSerializedVersion(int[] version)
|
||||||
|
{
|
||||||
|
if (version[0] >= 5)
|
||||||
|
{
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3))
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6))
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Others
|
||||||
|
private static bool IsContainsAnimationClip(this Animation animation, AnimationClip clip)
|
||||||
|
{
|
||||||
|
foreach (PPtr<AnimationClip> ptr in animation.m_Animations)
|
||||||
|
{
|
||||||
|
if (ptr.TryGet(out var animationClip) && animationClip.Equals(clip))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<uint, string> BuildTOS(this Animator animator)
|
||||||
|
{
|
||||||
|
if (animator.version[0] > 4 || (animator.version[0] == 4 && animator.version[1] >= 3))
|
||||||
|
{
|
||||||
|
if (animator.m_HasTransformHierarchy)
|
||||||
|
{
|
||||||
|
if (animator.m_GameObject.TryGet(out var go))
|
||||||
|
{
|
||||||
|
return go.BuildTOS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Dictionary<uint, string>() { { 0, string.Empty } };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (animator.m_GameObject.TryGet(out var go))
|
||||||
|
{
|
||||||
|
return go.BuildTOS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static Dictionary<uint, string> BuildTOS(this GameObject gameObject)
|
||||||
|
{
|
||||||
|
Dictionary<uint, string> tos = new Dictionary<uint, string>() { { 0, string.Empty } };
|
||||||
|
gameObject.BuildTOS(string.Empty, tos);
|
||||||
|
return tos;
|
||||||
|
}
|
||||||
|
private static void BuildTOS(this GameObject parent, string parentPath, Dictionary<uint, string> tos)
|
||||||
|
{
|
||||||
|
Transform transform = parent.m_Transform;
|
||||||
|
foreach (PPtr<Transform> childPtr in transform.m_Children)
|
||||||
|
{
|
||||||
|
if (childPtr.TryGet(out var childTransform))
|
||||||
|
{
|
||||||
|
if (childTransform.m_GameObject.TryGet(out var child))
|
||||||
|
{
|
||||||
|
string path = parentPath != string.Empty ? parentPath + '/' + child.m_Name : child.m_Name;
|
||||||
|
var pathHash = CRC.CalculateDigestUTF8(path);
|
||||||
|
tos[pathHash] = path;
|
||||||
|
BuildTOS(child, path, tos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static bool IsContainsAnimationClip(this RuntimeAnimatorController runtimeAnimatorController, AnimationClip clip)
|
||||||
|
{
|
||||||
|
if (runtimeAnimatorController is AnimatorController animatorController)
|
||||||
|
{
|
||||||
|
foreach (PPtr<AnimationClip> ptr in animatorController.m_AnimationClips)
|
||||||
|
{
|
||||||
|
if (ptr.TryGet(out var animationClip) && animationClip.Equals(clip))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public static int GetDimension(this GenericBinding binding)
|
||||||
|
{
|
||||||
|
return binding.attribute == 2 ? 4 : 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HumanoidMuscleType GetHumanoidMuscle(this GenericBinding binding)
|
||||||
|
{
|
||||||
|
return ((HumanoidMuscleType)binding.attribute).Update(binding.version);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BindingCustomType : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Transform = 4,
|
||||||
|
AnimatorMuscle = 8,
|
||||||
|
|
||||||
|
BlendShape = 20,
|
||||||
|
Renderer = 21,
|
||||||
|
RendererMaterial = 22,
|
||||||
|
SpriteRenderer = 23,
|
||||||
|
MonoBehaviour = 24,
|
||||||
|
Light = 25,
|
||||||
|
RendererShadows = 26,
|
||||||
|
ParticleSystem = 27,
|
||||||
|
RectTransform = 28,
|
||||||
|
LineRenderer = 29,
|
||||||
|
TrailRenderer = 30,
|
||||||
|
PositionConstraint = 31,
|
||||||
|
RotationConstraint = 32,
|
||||||
|
ScaleConstraint = 33,
|
||||||
|
AimConstraint = 34,
|
||||||
|
ParentConstraint = 35,
|
||||||
|
LookAtConstraint = 36,
|
||||||
|
Camera = 37,
|
||||||
|
}
|
||||||
|
}
|
||||||
672
AssetStudioUtility/YAML/CustomCurveResolver.cs
Normal file
672
AssetStudioUtility/YAML/CustomCurveResolver.cs
Normal file
@@ -0,0 +1,672 @@
|
|||||||
|
using System;
|
||||||
|
using SevenZip;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public sealed class CustomCurveResolver
|
||||||
|
{
|
||||||
|
public CustomCurveResolver(AnimationClip clip)
|
||||||
|
{
|
||||||
|
if (clip == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(clip));
|
||||||
|
}
|
||||||
|
m_clip = clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToAttributeName(BindingCustomType type, uint attribute, string path)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case BindingCustomType.BlendShape:
|
||||||
|
{
|
||||||
|
const string Prefix = "blendShape.";
|
||||||
|
if (AnimationClipConverter.UnknownPathRegex.IsMatch(path))
|
||||||
|
{
|
||||||
|
return Prefix + attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (GameObject root in Roots)
|
||||||
|
{
|
||||||
|
var rootTransform = root.m_Transform;
|
||||||
|
var child = rootTransform.FindChild(path);
|
||||||
|
if (child == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SkinnedMeshRenderer skin = null;
|
||||||
|
if (child.m_GameObject.TryGet(out var go))
|
||||||
|
{
|
||||||
|
skin = go.m_SkinnedMeshRenderer;
|
||||||
|
}
|
||||||
|
if (skin == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!skin.m_Mesh.TryGet(out var mesh))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
string shapeName = mesh.FindBlendShapeNameByCRC(attribute);
|
||||||
|
if (shapeName == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Prefix + shapeName;
|
||||||
|
}
|
||||||
|
return Prefix + attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BindingCustomType.Renderer:
|
||||||
|
return "m_Materials." + CommonString.StringBuffer[0x31] + "." + CommonString.StringBuffer[0x6A] + $"[{attribute}]";
|
||||||
|
|
||||||
|
case BindingCustomType.RendererMaterial:
|
||||||
|
{
|
||||||
|
const string Prefix = "material.";
|
||||||
|
if (AnimationClipConverter.UnknownPathRegex.IsMatch(path))
|
||||||
|
{
|
||||||
|
return Prefix + attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (GameObject root in Roots)
|
||||||
|
{
|
||||||
|
Transform rootTransform = root.m_Transform;
|
||||||
|
Transform child = rootTransform.FindChild(path);
|
||||||
|
if (child == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint crc28 = attribute & 0xFFFFFFF;
|
||||||
|
Renderer renderer = null;
|
||||||
|
if (child.m_GameObject.TryGet(out var go))
|
||||||
|
{
|
||||||
|
renderer = (Renderer)go.m_SkinnedMeshRenderer ?? go.m_MeshRenderer;
|
||||||
|
}
|
||||||
|
if (renderer == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
string property = renderer.FindMaterialPropertyNameByCRC28(crc28);
|
||||||
|
if (property == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((attribute & 0x80000000) != 0)
|
||||||
|
{
|
||||||
|
return Prefix + property;
|
||||||
|
}
|
||||||
|
char subProperty;
|
||||||
|
uint subPropIndex = attribute >> 28 & 3;
|
||||||
|
bool isRgba = (attribute & 0x40000000) != 0;
|
||||||
|
switch (subPropIndex)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
subProperty = isRgba ? 'r' : 'x';
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
subProperty = isRgba ? 'g' : 'y';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
subProperty = isRgba ? 'b' : 'z';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
subProperty = isRgba ? 'a' : 'w';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Prefix + property + "." + subProperty;
|
||||||
|
}
|
||||||
|
return Prefix + attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BindingCustomType.SpriteRenderer:
|
||||||
|
{
|
||||||
|
if (attribute == 0)
|
||||||
|
{
|
||||||
|
return "m_Sprite";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
case BindingCustomType.MonoBehaviour:
|
||||||
|
{
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_Enabled"))
|
||||||
|
{
|
||||||
|
return "m_Enabled";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
case BindingCustomType.Light:
|
||||||
|
{
|
||||||
|
string ColorR = "m_Color.r";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ColorR))
|
||||||
|
{
|
||||||
|
return ColorR;
|
||||||
|
}
|
||||||
|
string ColorG = "m_Color.g";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ColorG))
|
||||||
|
{
|
||||||
|
return ColorG;
|
||||||
|
}
|
||||||
|
string ColorB = "m_Color.b";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ColorB))
|
||||||
|
{
|
||||||
|
return ColorB;
|
||||||
|
}
|
||||||
|
string ColorA = "m_Color.a";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ColorA))
|
||||||
|
{
|
||||||
|
return ColorA;
|
||||||
|
}
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_CookieSize"))
|
||||||
|
{
|
||||||
|
return "m_CookieSize";
|
||||||
|
}
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_DrawHalo"))
|
||||||
|
{
|
||||||
|
return "m_DrawHalo";
|
||||||
|
}
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_Intensity"))
|
||||||
|
{
|
||||||
|
return "m_Intensity";
|
||||||
|
}
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_Range"))
|
||||||
|
{
|
||||||
|
return "m_Range";
|
||||||
|
}
|
||||||
|
const string ShadowsStrength = "m_Shadows.m_Strength";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ShadowsStrength))
|
||||||
|
{
|
||||||
|
return ShadowsStrength;
|
||||||
|
}
|
||||||
|
const string ShadowsBias = "m_Shadows.m_Bias";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ShadowsBias))
|
||||||
|
{
|
||||||
|
return ShadowsBias;
|
||||||
|
}
|
||||||
|
const string ShadowsNormalBias = "m_Shadows.m_NormalBias";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ShadowsNormalBias))
|
||||||
|
{
|
||||||
|
return ShadowsNormalBias;
|
||||||
|
}
|
||||||
|
const string ShadowsNearPlane = "m_Shadows.m_NearPlane";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ShadowsNearPlane))
|
||||||
|
{
|
||||||
|
return ShadowsNearPlane;
|
||||||
|
}
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_SpotAngle"))
|
||||||
|
{
|
||||||
|
return "m_SpotAngle";
|
||||||
|
}
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_ColorTemperature"))
|
||||||
|
{
|
||||||
|
return "m_ColorTemperature";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
case BindingCustomType.RendererShadows:
|
||||||
|
{
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_ReceiveShadows"))
|
||||||
|
{
|
||||||
|
return "m_ReceiveShadows";
|
||||||
|
}
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_SortingOrder"))
|
||||||
|
{
|
||||||
|
return "m_SortingOrder";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
#warning TODO:
|
||||||
|
case BindingCustomType.ParticleSystem:
|
||||||
|
return "ParticleSystem_" + attribute;
|
||||||
|
/*{
|
||||||
|
// TODO: ordinal propertyName
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {_this}");*/
|
||||||
|
|
||||||
|
case BindingCustomType.RectTransform:
|
||||||
|
{
|
||||||
|
string LocalPositionZ = "m_LocalPosition.z";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(LocalPositionZ))
|
||||||
|
{
|
||||||
|
return LocalPositionZ;
|
||||||
|
}
|
||||||
|
string AnchoredPositionX = "m_AnchoredPosition.x";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(AnchoredPositionX))
|
||||||
|
{
|
||||||
|
return AnchoredPositionX;
|
||||||
|
}
|
||||||
|
string AnchoredPositionY = "m_AnchoredPosition.y";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(AnchoredPositionY))
|
||||||
|
{
|
||||||
|
return AnchoredPositionY;
|
||||||
|
}
|
||||||
|
string AnchorMinX = "m_AnchorMin.x";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(AnchorMinX))
|
||||||
|
{
|
||||||
|
return AnchorMinX;
|
||||||
|
}
|
||||||
|
string AnchorMinY = "m_AnchorMin.y";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(AnchorMinY))
|
||||||
|
{
|
||||||
|
return AnchorMinY;
|
||||||
|
}
|
||||||
|
string AnchorMaxX = "m_AnchorMax.x";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(AnchorMaxX))
|
||||||
|
{
|
||||||
|
return AnchorMaxX;
|
||||||
|
}
|
||||||
|
string AnchorMaxY = "m_AnchorMax.y";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(AnchorMaxY))
|
||||||
|
{
|
||||||
|
return AnchorMaxY;
|
||||||
|
}
|
||||||
|
string SizeDeltaX = "m_SizeDelta.x";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(SizeDeltaX))
|
||||||
|
{
|
||||||
|
return SizeDeltaX;
|
||||||
|
}
|
||||||
|
string SizeDeltaY = "m_SizeDelta.y";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(SizeDeltaY))
|
||||||
|
{
|
||||||
|
return SizeDeltaY;
|
||||||
|
}
|
||||||
|
string PivotX = "m_Pivot.x";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(PivotX))
|
||||||
|
{
|
||||||
|
return PivotX;
|
||||||
|
}
|
||||||
|
string PivotY = "m_Pivot.y";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(PivotY))
|
||||||
|
{
|
||||||
|
return PivotY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
#warning TODO:
|
||||||
|
case BindingCustomType.LineRenderer:
|
||||||
|
{
|
||||||
|
const string ParametersWidthMultiplier = "m_Parameters" + "." + "widthMultiplier";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ParametersWidthMultiplier))
|
||||||
|
{
|
||||||
|
return ParametersWidthMultiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: old versions animate all properties as custom curves
|
||||||
|
return "LineRenderer_" + attribute;
|
||||||
|
|
||||||
|
#warning TODO:
|
||||||
|
case BindingCustomType.TrailRenderer:
|
||||||
|
{
|
||||||
|
const string ParametersWidthMultiplier = "m_Parameters" + "." + "widthMultiplier";
|
||||||
|
if (attribute == CRC.CalculateDigestAscii(ParametersWidthMultiplier))
|
||||||
|
{
|
||||||
|
return ParametersWidthMultiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: old versions animate all properties as custom curves
|
||||||
|
return "TrailRenderer_" + attribute;
|
||||||
|
|
||||||
|
#warning TODO:
|
||||||
|
case BindingCustomType.PositionConstraint:
|
||||||
|
{
|
||||||
|
uint property = attribute & 0xF;
|
||||||
|
switch (property)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "m_RestTranslation.x";
|
||||||
|
case 1:
|
||||||
|
return "m_RestTranslation.y";
|
||||||
|
case 2:
|
||||||
|
return "m_RestTranslation.z";
|
||||||
|
case 3:
|
||||||
|
return "m_Weight";
|
||||||
|
case 4:
|
||||||
|
return "m_TranslationOffset.x";
|
||||||
|
case 5:
|
||||||
|
return "m_TranslationOffset.y";
|
||||||
|
case 6:
|
||||||
|
return "m_TranslationOffset.z";
|
||||||
|
case 7:
|
||||||
|
return "m_AffectTranslationX";
|
||||||
|
case 8:
|
||||||
|
return "m_AffectTranslationY";
|
||||||
|
case 9:
|
||||||
|
return "m_AffectTranslationZ";
|
||||||
|
case 10:
|
||||||
|
return "m_Active";
|
||||||
|
case 11:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||||
|
case 12:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
#warning TODO:
|
||||||
|
case BindingCustomType.RotationConstraint:
|
||||||
|
{
|
||||||
|
uint property = attribute & 0xF;
|
||||||
|
switch (property)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "m_RestRotation.x";
|
||||||
|
case 1:
|
||||||
|
return "m_RestRotation.y";
|
||||||
|
case 2:
|
||||||
|
return "m_RestRotation.z";
|
||||||
|
case 3:
|
||||||
|
return "m_Weight";
|
||||||
|
case 4:
|
||||||
|
return "m_RotationOffset.x";
|
||||||
|
case 5:
|
||||||
|
return "m_RotationOffset.y";
|
||||||
|
case 6:
|
||||||
|
return "m_RotationOffset.z";
|
||||||
|
case 7:
|
||||||
|
return "m_AffectRotationX";
|
||||||
|
case 8:
|
||||||
|
return "m_AffectRotationY";
|
||||||
|
case 9:
|
||||||
|
return "m_AffectRotationZ";
|
||||||
|
case 10:
|
||||||
|
return "m_Active";
|
||||||
|
case 11:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||||
|
case 12:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
#warning TODO:
|
||||||
|
case BindingCustomType.ScaleConstraint:
|
||||||
|
{
|
||||||
|
uint property = attribute & 0xF;
|
||||||
|
switch (property)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "m_ScaleAtRest.x";
|
||||||
|
case 1:
|
||||||
|
return "m_ScaleAtRest.y";
|
||||||
|
case 2:
|
||||||
|
return "m_ScaleAtRest.z";
|
||||||
|
case 3:
|
||||||
|
return "m_Weight";
|
||||||
|
case 4:
|
||||||
|
return "m_ScalingOffset.x";
|
||||||
|
case 5:
|
||||||
|
return "m_ScalingOffset.y";
|
||||||
|
case 6:
|
||||||
|
return "m_ScalingOffset.z";
|
||||||
|
case 7:
|
||||||
|
return "m_AffectScalingX";
|
||||||
|
case 8:
|
||||||
|
return "m_AffectScalingY";
|
||||||
|
case 9:
|
||||||
|
return "m_AffectScalingZ";
|
||||||
|
case 10:
|
||||||
|
return "m_Active";
|
||||||
|
case 11:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||||
|
case 12:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
#warning TODO:
|
||||||
|
case BindingCustomType.AimConstraint:
|
||||||
|
{
|
||||||
|
uint property = attribute & 0xF;
|
||||||
|
switch (property)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "m_Weight";
|
||||||
|
case 1:
|
||||||
|
return "m_AffectRotationX";
|
||||||
|
case 2:
|
||||||
|
return "m_AffectRotationY";
|
||||||
|
case 3:
|
||||||
|
return "m_AffectRotationZ";
|
||||||
|
case 4:
|
||||||
|
return "m_Active";
|
||||||
|
case 5:
|
||||||
|
return "m_WorldUpObject";
|
||||||
|
case 6:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||||
|
case 7:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
#warning TODO:
|
||||||
|
case BindingCustomType.ParentConstraint:
|
||||||
|
{
|
||||||
|
uint property = attribute & 0xF;
|
||||||
|
switch (property)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "m_Weight";
|
||||||
|
case 1:
|
||||||
|
return "m_AffectTranslationX";
|
||||||
|
case 2:
|
||||||
|
return "m_AffectTranslationY";
|
||||||
|
case 3:
|
||||||
|
return "m_AffectTranslationZ";
|
||||||
|
case 4:
|
||||||
|
return "m_AffectRotationX";
|
||||||
|
case 5:
|
||||||
|
return "m_AffectRotationY";
|
||||||
|
case 6:
|
||||||
|
return "m_AffectRotationZ";
|
||||||
|
case 7:
|
||||||
|
return "m_Active";
|
||||||
|
case 8:
|
||||||
|
return $"m_TranslationOffsets.Array.data[{attribute >> 8}].x";
|
||||||
|
case 9:
|
||||||
|
return $"m_TranslationOffsets.Array.data[{attribute >> 8}].y";
|
||||||
|
case 10:
|
||||||
|
return $"m_TranslationOffsets.Array.data[{attribute >> 8}].z";
|
||||||
|
case 11:
|
||||||
|
return $"m_RotationOffsets.Array.data[{attribute >> 8}].x";
|
||||||
|
case 12:
|
||||||
|
return $"m_RotationOffsets.Array.data[{attribute >> 8}].y";
|
||||||
|
case 13:
|
||||||
|
return $"m_RotationOffsets.Array.data[{attribute >> 8}].z";
|
||||||
|
case 14:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||||
|
case 15:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
#warning TODO:
|
||||||
|
case BindingCustomType.LookAtConstraint:
|
||||||
|
{
|
||||||
|
uint property = attribute & 0xF;
|
||||||
|
switch (property)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "m_Weight";
|
||||||
|
case 1:
|
||||||
|
return "m_Active";
|
||||||
|
case 2:
|
||||||
|
return "m_WorldUpObject";
|
||||||
|
case 3:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||||
|
case 4:
|
||||||
|
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||||
|
case 5:
|
||||||
|
return "m_Roll";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
case BindingCustomType.Camera:
|
||||||
|
{
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("field of view"))
|
||||||
|
{
|
||||||
|
return "field of view";
|
||||||
|
}
|
||||||
|
if (attribute == CRC.CalculateDigestAscii("m_FocalLength"))
|
||||||
|
{
|
||||||
|
return "m_FocalLength";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(type.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private GameObject[] Roots
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!m_rootInited)
|
||||||
|
{
|
||||||
|
m_roots = m_clip.FindRoots().ToArray();
|
||||||
|
m_rootInited = true;
|
||||||
|
}
|
||||||
|
return m_roots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly AnimationClip m_clip = null;
|
||||||
|
|
||||||
|
private GameObject[] m_roots = null;
|
||||||
|
private bool m_rootInited = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CustomCurveResolverExtensions
|
||||||
|
{
|
||||||
|
public static Transform FindChild(this Transform transform, string path)
|
||||||
|
{
|
||||||
|
if (path.Length == 0)
|
||||||
|
{
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
return transform.FindChild(path, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Transform FindChild(this Transform transform, string path, int startIndex)
|
||||||
|
{
|
||||||
|
int separatorIndex = path.IndexOf('/', startIndex);
|
||||||
|
string childName = separatorIndex == -1 ?
|
||||||
|
path.Substring(startIndex, path.Length - startIndex) :
|
||||||
|
path.Substring(startIndex, separatorIndex - startIndex);
|
||||||
|
|
||||||
|
foreach (PPtr<Transform> childPtr in transform.m_Children)
|
||||||
|
{
|
||||||
|
if (childPtr.TryGet(out var child))
|
||||||
|
{
|
||||||
|
if (child.m_GameObject.TryGet(out var childGO) && childGO.m_Name == childName)
|
||||||
|
{
|
||||||
|
return separatorIndex == -1 ? child : child.FindChild(path, separatorIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FindBlendShapeNameByCRC(this Mesh mesh, uint crc)
|
||||||
|
{
|
||||||
|
if (mesh.version[0] > 4 || (mesh.version[0] == 4 && mesh.version[1] >= 3))
|
||||||
|
{
|
||||||
|
return mesh.m_Shapes.FindShapeNameByCRC(crc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var blendShape in mesh.m_Shapes.shapes)
|
||||||
|
{
|
||||||
|
if (CRC.VerifyDigestUTF8(blendShape.name, crc))
|
||||||
|
{
|
||||||
|
return blendShape.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FindShapeNameByCRC(this BlendShapeData blendShapeData, uint crc)
|
||||||
|
{
|
||||||
|
foreach (var blendChannel in blendShapeData.channels)
|
||||||
|
{
|
||||||
|
if (blendChannel.nameHash == crc)
|
||||||
|
{
|
||||||
|
return blendChannel.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FindMaterialPropertyNameByCRC28(this Renderer renderer, uint crc)
|
||||||
|
{
|
||||||
|
foreach (PPtr<Material> materialPtr in renderer.m_Materials)
|
||||||
|
{
|
||||||
|
if (!materialPtr.TryGet(out var material))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
string property = material.FindPropertyNameByCRC28(crc);
|
||||||
|
if (property == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FindPropertyNameByCRC28(this Material material, uint crc)
|
||||||
|
{
|
||||||
|
foreach (var property in material.m_SavedProperties.m_TexEnvs.Keys)
|
||||||
|
{
|
||||||
|
string hdrName = $"{property}_HDR";
|
||||||
|
if (CRC.Verify28DigestUTF8(hdrName, crc))
|
||||||
|
{
|
||||||
|
return hdrName;
|
||||||
|
}
|
||||||
|
string stName = $"{property}_ST";
|
||||||
|
if (CRC.Verify28DigestUTF8(stName, crc))
|
||||||
|
{
|
||||||
|
return stName;
|
||||||
|
}
|
||||||
|
string texelName = $"{property}_TexelSize";
|
||||||
|
if (CRC.Verify28DigestUTF8(texelName, crc))
|
||||||
|
{
|
||||||
|
return texelName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var property in material.m_SavedProperties.m_Floats.Keys)
|
||||||
|
{
|
||||||
|
if (CRC.Verify28DigestUTF8(property, crc))
|
||||||
|
{
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var property in material.m_SavedProperties.m_Colors.Keys)
|
||||||
|
{
|
||||||
|
if (CRC.Verify28DigestUTF8(property, crc))
|
||||||
|
{
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
648
AssetStudioUtility/YAML/MuscleHelper.cs
Normal file
648
AssetStudioUtility/YAML/MuscleHelper.cs
Normal file
@@ -0,0 +1,648 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public enum HumanoidMuscleType
|
||||||
|
{
|
||||||
|
Motion = 0,
|
||||||
|
Root = Motion + 7,
|
||||||
|
Limbs = Root + 7,
|
||||||
|
Muscles = Limbs + LimbType.Last * 7,
|
||||||
|
Fingers = Muscles + MuscleType.Last,
|
||||||
|
TDoFBones = Fingers + ArmType.Last * FingerType.Last * FingerDoFType.Last,
|
||||||
|
|
||||||
|
Last = TDoFBones + TDoFBoneType.Last * 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AnimationMuscleTypeExtensions
|
||||||
|
{
|
||||||
|
public static HumanoidMuscleType Update(this HumanoidMuscleType _this, int[] version)
|
||||||
|
{
|
||||||
|
if (_this < HumanoidMuscleType.Muscles)
|
||||||
|
{
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MuscleType muscle = (MuscleType)(_this - HumanoidMuscleType.Muscles);
|
||||||
|
MuscleType fixedMuscle = muscle.Update(version);
|
||||||
|
_this = HumanoidMuscleType.Muscles + (int)fixedMuscle;
|
||||||
|
if (_this < HumanoidMuscleType.TDoFBones)
|
||||||
|
{
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TDoFBoneType tdof = (TDoFBoneType)(_this - HumanoidMuscleType.TDoFBones);
|
||||||
|
TDoFBoneType fixedTdof = tdof.Update(version);
|
||||||
|
_this = HumanoidMuscleType.TDoFBones + (int)fixedTdof;
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToAttributeString(this HumanoidMuscleType _this)
|
||||||
|
{
|
||||||
|
if (_this < HumanoidMuscleType.Root)
|
||||||
|
{
|
||||||
|
int delta = _this - HumanoidMuscleType.Motion;
|
||||||
|
return nameof(HumanoidMuscleType.Motion) + GetTransformPostfix(delta % 7);
|
||||||
|
}
|
||||||
|
if (_this < HumanoidMuscleType.Limbs)
|
||||||
|
{
|
||||||
|
int delta = _this - HumanoidMuscleType.Root;
|
||||||
|
return nameof(HumanoidMuscleType.Root) + GetTransformPostfix(delta % 7);
|
||||||
|
}
|
||||||
|
if (_this < HumanoidMuscleType.Muscles)
|
||||||
|
{
|
||||||
|
int delta = _this - HumanoidMuscleType.Limbs;
|
||||||
|
LimbType limb = (LimbType)(delta / 7);
|
||||||
|
return limb.ToBoneType().ToAttributeString() + GetTransformPostfix(delta % 7);
|
||||||
|
}
|
||||||
|
if (_this < HumanoidMuscleType.Fingers)
|
||||||
|
{
|
||||||
|
int delta = _this - HumanoidMuscleType.Muscles;
|
||||||
|
MuscleType muscle = (MuscleType)delta;
|
||||||
|
return muscle.ToAttributeString();
|
||||||
|
}
|
||||||
|
if (_this < HumanoidMuscleType.TDoFBones)
|
||||||
|
{
|
||||||
|
const int armSize = (int)FingerType.Last * (int)FingerDoFType.Last;
|
||||||
|
const int dofSize = (int)FingerDoFType.Last;
|
||||||
|
int delta = _this - HumanoidMuscleType.Fingers;
|
||||||
|
ArmType arm = (ArmType)(delta / armSize);
|
||||||
|
delta = delta % armSize;
|
||||||
|
FingerType finger = (FingerType)(delta / dofSize);
|
||||||
|
delta = delta % dofSize;
|
||||||
|
FingerDoFType dof = (FingerDoFType)delta;
|
||||||
|
return $"{arm.ToBoneType().ToAttributeString()}.{finger.ToAttributeString()}.{dof.ToAttributeString()}";
|
||||||
|
}
|
||||||
|
if (_this < HumanoidMuscleType.Last)
|
||||||
|
{
|
||||||
|
int delta = _this - HumanoidMuscleType.TDoFBones;
|
||||||
|
TDoFBoneType tdof = (TDoFBoneType)(delta / 3);
|
||||||
|
return $"{tdof.ToBoneType().ToAttributeString()}{GetTDoFTransformPostfix(delta % 3)}";
|
||||||
|
}
|
||||||
|
throw new ArgumentException(_this.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetTransformPostfix(int index)
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "T.x";
|
||||||
|
case 1:
|
||||||
|
return "T.y";
|
||||||
|
case 2:
|
||||||
|
return "T.z";
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return "Q.x";
|
||||||
|
case 4:
|
||||||
|
return "Q.y";
|
||||||
|
case 5:
|
||||||
|
return "Q.z";
|
||||||
|
case 6:
|
||||||
|
return "Q.w";
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(index.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetTDoFTransformPostfix(int index)
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "TDOF.x";
|
||||||
|
case 1:
|
||||||
|
return "TDOF.y";
|
||||||
|
case 2:
|
||||||
|
return "TDOF.z";
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(index.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LimbType
|
||||||
|
{
|
||||||
|
LeftFoot = 0,
|
||||||
|
RightFoot = 1,
|
||||||
|
LeftHand = 2,
|
||||||
|
RightHand = 3,
|
||||||
|
|
||||||
|
Last,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LimbTypeExtensions
|
||||||
|
{
|
||||||
|
public static BoneType ToBoneType(this LimbType _this)
|
||||||
|
{
|
||||||
|
switch (_this)
|
||||||
|
{
|
||||||
|
case LimbType.LeftFoot:
|
||||||
|
return BoneType.LeftFoot;
|
||||||
|
case LimbType.RightFoot:
|
||||||
|
return BoneType.RightFoot;
|
||||||
|
case LimbType.LeftHand:
|
||||||
|
return BoneType.LeftHand;
|
||||||
|
case LimbType.RightHand:
|
||||||
|
return BoneType.RightHand;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(_this.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MuscleType
|
||||||
|
{
|
||||||
|
SpineFrontBack = 0,
|
||||||
|
SpineLeftRight = 1,
|
||||||
|
SpineTwistLeftRight = 2,
|
||||||
|
ChestFrontBack = 3,
|
||||||
|
ChestLeftRight = 4,
|
||||||
|
ChestTwistLeftRight = 5,
|
||||||
|
UpperchestFrontBack = 6,
|
||||||
|
UpperchestLeftRight = 7,
|
||||||
|
UpperchestTwisLeftRight = 8,
|
||||||
|
NeckNodDownUp = 9,
|
||||||
|
NeckTiltLeftRight = 10,
|
||||||
|
NeckTurnLeftRight = 11,
|
||||||
|
HeadNodDownUp = 12,
|
||||||
|
HeadTiltLeftRight = 13,
|
||||||
|
HeadTurnLeftRight = 14,
|
||||||
|
LeftEyeDownUp = 15,
|
||||||
|
LeftEyeInOut = 16,
|
||||||
|
RightEyeDownUp = 17,
|
||||||
|
RightEyeInOut = 18,
|
||||||
|
JawClose = 19,
|
||||||
|
JawLeftRight = 20,
|
||||||
|
LeftUpperLegFrontBack = 21,
|
||||||
|
LeftUpperLegInOut = 22,
|
||||||
|
LeftUpperLegTwistInOut = 23,
|
||||||
|
LeftLowerLegStretch = 24,
|
||||||
|
LeftLowerLegTwistInOut = 25,
|
||||||
|
LeftFootUpDown = 26,
|
||||||
|
LeftFootTwistInOut = 27,
|
||||||
|
LeftToesUpDown = 28,
|
||||||
|
RightUpperLegFrontBack = 29,
|
||||||
|
RightUpperLegInOut = 30,
|
||||||
|
RightUpperLegTwistInOut = 31,
|
||||||
|
RightLowerLegStretch = 32,
|
||||||
|
RightLowerLegTwistInOut = 33,
|
||||||
|
RightFootUpDown = 34,
|
||||||
|
RightFootTwistInOut = 35,
|
||||||
|
RightToesUpDown = 36,
|
||||||
|
LeftShoulderDownUp = 37,
|
||||||
|
LeftShoulderFrontBack = 38,
|
||||||
|
LeftArmDownUp = 39,
|
||||||
|
LeftArmFrontBack = 40,
|
||||||
|
LeftArmTwistInOut = 41,
|
||||||
|
LeftForearmStretch = 42,
|
||||||
|
LeftForearmTwistInOut = 43,
|
||||||
|
LeftHandDownUp = 44,
|
||||||
|
LeftHandInOut = 45,
|
||||||
|
RightShoulderDownUp = 46,
|
||||||
|
RightShoulderFrontBack = 47,
|
||||||
|
RightArmDownUp = 48,
|
||||||
|
RightArmFrontBack = 49,
|
||||||
|
RightArmTwistInOut = 50,
|
||||||
|
RightForearmStretch = 51,
|
||||||
|
RightForearmTwistInOut = 52,
|
||||||
|
RightHandDownUp = 53,
|
||||||
|
RightHandInOut = 54,
|
||||||
|
|
||||||
|
Last,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MuscleTypeExtensions
|
||||||
|
{
|
||||||
|
public static MuscleType Update(this MuscleType _this, int[] version)
|
||||||
|
{
|
||||||
|
if (!(version[0] > 5 || (version[0] == 5 && version[1] >= 6)))
|
||||||
|
{
|
||||||
|
if (_this >= MuscleType.UpperchestFrontBack)
|
||||||
|
{
|
||||||
|
_this += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToAttributeString(this MuscleType _this)
|
||||||
|
{
|
||||||
|
switch (_this)
|
||||||
|
{
|
||||||
|
case MuscleType.SpineFrontBack:
|
||||||
|
return "Spine Front-Back";
|
||||||
|
case MuscleType.SpineLeftRight:
|
||||||
|
return "Spine Left-Right";
|
||||||
|
case MuscleType.SpineTwistLeftRight:
|
||||||
|
return "Spine Twist Left-Right";
|
||||||
|
case MuscleType.ChestFrontBack:
|
||||||
|
return "Chest Front-Back";
|
||||||
|
case MuscleType.ChestLeftRight:
|
||||||
|
return "Chest Left-Right";
|
||||||
|
case MuscleType.ChestTwistLeftRight:
|
||||||
|
return "Chest Twist Left-Right";
|
||||||
|
case MuscleType.UpperchestFrontBack:
|
||||||
|
return "UpperChest Front-Back";
|
||||||
|
case MuscleType.UpperchestLeftRight:
|
||||||
|
return "UpperChest Left-Right";
|
||||||
|
case MuscleType.UpperchestTwisLeftRight:
|
||||||
|
return "UpperChest Twist Left-Right";
|
||||||
|
case MuscleType.NeckNodDownUp:
|
||||||
|
return "Neck Nod Down-Up";
|
||||||
|
case MuscleType.NeckTiltLeftRight:
|
||||||
|
return "Neck Tilt Left-Right";
|
||||||
|
case MuscleType.NeckTurnLeftRight:
|
||||||
|
return "Neck Turn Left-Right";
|
||||||
|
case MuscleType.HeadNodDownUp:
|
||||||
|
return "Head Nod Down-Up";
|
||||||
|
case MuscleType.HeadTiltLeftRight:
|
||||||
|
return "Head Tilt Left-Right";
|
||||||
|
case MuscleType.HeadTurnLeftRight:
|
||||||
|
return "Head Turn Left-Right";
|
||||||
|
case MuscleType.LeftEyeDownUp:
|
||||||
|
return "Left Eye Down-Up";
|
||||||
|
case MuscleType.LeftEyeInOut:
|
||||||
|
return "Left Eye In-Out";
|
||||||
|
case MuscleType.RightEyeDownUp:
|
||||||
|
return "Right Eye Down-Up";
|
||||||
|
case MuscleType.RightEyeInOut:
|
||||||
|
return "Right Eye In-Out";
|
||||||
|
case MuscleType.JawClose:
|
||||||
|
return "Jaw Close";
|
||||||
|
case MuscleType.JawLeftRight:
|
||||||
|
return "Jaw Left-Right";
|
||||||
|
case MuscleType.LeftUpperLegFrontBack:
|
||||||
|
return "Left Upper Leg Front-Back";
|
||||||
|
case MuscleType.LeftUpperLegInOut:
|
||||||
|
return "Left Upper Leg In-Out";
|
||||||
|
case MuscleType.LeftUpperLegTwistInOut:
|
||||||
|
return "Left Upper Leg Twist In-Out";
|
||||||
|
case MuscleType.LeftLowerLegStretch:
|
||||||
|
return "Left Lower Leg Stretch";
|
||||||
|
case MuscleType.LeftLowerLegTwistInOut:
|
||||||
|
return "Left Lower Leg Twist In-Out";
|
||||||
|
case MuscleType.LeftFootUpDown:
|
||||||
|
return "Left Foot Up-Down";
|
||||||
|
case MuscleType.LeftFootTwistInOut:
|
||||||
|
return "Left Foot Twist In-Out";
|
||||||
|
case MuscleType.LeftToesUpDown:
|
||||||
|
return "Left Toes Up-Down";
|
||||||
|
case MuscleType.RightUpperLegFrontBack:
|
||||||
|
return "Right Upper Leg Front-Back";
|
||||||
|
case MuscleType.RightUpperLegInOut:
|
||||||
|
return "Right Upper Leg In-Out";
|
||||||
|
case MuscleType.RightUpperLegTwistInOut:
|
||||||
|
return "Right Upper Leg Twist In-Out";
|
||||||
|
case MuscleType.RightLowerLegStretch:
|
||||||
|
return "Right Lower Leg Stretch";
|
||||||
|
case MuscleType.RightLowerLegTwistInOut:
|
||||||
|
return "Right Lower Leg Twist In-Out";
|
||||||
|
case MuscleType.RightFootUpDown:
|
||||||
|
return "Right Foot Up-Down";
|
||||||
|
case MuscleType.RightFootTwistInOut:
|
||||||
|
return "Right Foot Twist In-Out";
|
||||||
|
case MuscleType.RightToesUpDown:
|
||||||
|
return "Right Toes Up-Down";
|
||||||
|
case MuscleType.LeftShoulderDownUp:
|
||||||
|
return "Left Shoulder Down-Up";
|
||||||
|
case MuscleType.LeftShoulderFrontBack:
|
||||||
|
return "Left Shoulder Front-Back";
|
||||||
|
case MuscleType.LeftArmDownUp:
|
||||||
|
return "Left Arm Down-Up";
|
||||||
|
case MuscleType.LeftArmFrontBack:
|
||||||
|
return "Left Arm Front-Back";
|
||||||
|
case MuscleType.LeftArmTwistInOut:
|
||||||
|
return "Left Arm Twist In-Out";
|
||||||
|
case MuscleType.LeftForearmStretch:
|
||||||
|
return "Left Forearm Stretch";
|
||||||
|
case MuscleType.LeftForearmTwistInOut:
|
||||||
|
return "Left Forearm Twist In-Out";
|
||||||
|
case MuscleType.LeftHandDownUp:
|
||||||
|
return "Left Hand Down-Up";
|
||||||
|
case MuscleType.LeftHandInOut:
|
||||||
|
return "Left Hand In-Out";
|
||||||
|
case MuscleType.RightShoulderDownUp:
|
||||||
|
return "Right Shoulder Down-Up";
|
||||||
|
case MuscleType.RightShoulderFrontBack:
|
||||||
|
return "Right Shoulder Front-Back";
|
||||||
|
case MuscleType.RightArmDownUp:
|
||||||
|
return "Right Arm Down-Up";
|
||||||
|
case MuscleType.RightArmFrontBack:
|
||||||
|
return "Right Arm Front-Back";
|
||||||
|
case MuscleType.RightArmTwistInOut:
|
||||||
|
return "Right Arm Twist In-Out";
|
||||||
|
case MuscleType.RightForearmStretch:
|
||||||
|
return "Right Forearm Stretch";
|
||||||
|
case MuscleType.RightForearmTwistInOut:
|
||||||
|
return "Right Forearm Twist In-Out";
|
||||||
|
case MuscleType.RightHandDownUp:
|
||||||
|
return "Right Hand Down-Up";
|
||||||
|
case MuscleType.RightHandInOut:
|
||||||
|
return "Right Hand In-Out";
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(_this.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BoneType
|
||||||
|
{
|
||||||
|
Hips = 0,
|
||||||
|
LeftUpperLeg = 1,
|
||||||
|
RightUpperLeg = 2,
|
||||||
|
LeftLowerLeg = 3,
|
||||||
|
RightLowerLeg = 4,
|
||||||
|
LeftFoot = 5,
|
||||||
|
RightFoot = 6,
|
||||||
|
Spine = 7,
|
||||||
|
Chest = 8,
|
||||||
|
UpperChest = 9,
|
||||||
|
Neck = 10,
|
||||||
|
Head = 11,
|
||||||
|
LeftShoulder = 12,
|
||||||
|
RightShoulder = 13,
|
||||||
|
LeftUpperArm = 14,
|
||||||
|
RightUpperArm = 15,
|
||||||
|
LeftLowerArm = 16,
|
||||||
|
RightLowerArm = 17,
|
||||||
|
LeftHand = 18,
|
||||||
|
RightHand = 19,
|
||||||
|
LeftToes = 20,
|
||||||
|
RightToes = 21,
|
||||||
|
LeftEye = 22,
|
||||||
|
RightEye = 23,
|
||||||
|
Jaw = 24,
|
||||||
|
|
||||||
|
Last,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BoneTypeExtensions
|
||||||
|
{
|
||||||
|
public static BoneType Update(this BoneType _this, int[] version)
|
||||||
|
{
|
||||||
|
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6))
|
||||||
|
{
|
||||||
|
if (_this >= BoneType.UpperChest)
|
||||||
|
{
|
||||||
|
_this++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToAttributeString(this BoneType _this)
|
||||||
|
{
|
||||||
|
if (_this < BoneType.Last)
|
||||||
|
{
|
||||||
|
return _this.ToString();
|
||||||
|
}
|
||||||
|
throw new ArgumentException(_this.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TransformType
|
||||||
|
{
|
||||||
|
Translation = 1,
|
||||||
|
Rotation = 2,
|
||||||
|
Scaling = 3,
|
||||||
|
EulerRotation = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BindingTypeExtensions
|
||||||
|
{
|
||||||
|
public static bool IsValid(this TransformType _this)
|
||||||
|
{
|
||||||
|
return _this >= TransformType.Translation && _this <= TransformType.EulerRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetDimension(this TransformType _this)
|
||||||
|
{
|
||||||
|
switch (_this)
|
||||||
|
{
|
||||||
|
case TransformType.Translation:
|
||||||
|
case TransformType.Scaling:
|
||||||
|
case TransformType.EulerRotation:
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
case TransformType.Rotation:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Binding type {_this} is not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ArmType
|
||||||
|
{
|
||||||
|
LeftHand = 0,
|
||||||
|
RightHand = 1,
|
||||||
|
|
||||||
|
Last,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ArmTypeExtensions
|
||||||
|
{
|
||||||
|
public static BoneType ToBoneType(this ArmType _this)
|
||||||
|
{
|
||||||
|
switch (_this)
|
||||||
|
{
|
||||||
|
case ArmType.LeftHand:
|
||||||
|
return BoneType.LeftHand;
|
||||||
|
case ArmType.RightHand:
|
||||||
|
return BoneType.RightHand;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(_this.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FingerType
|
||||||
|
{
|
||||||
|
Thumb = 0,
|
||||||
|
Index = 1,
|
||||||
|
Middle = 2,
|
||||||
|
Ring = 3,
|
||||||
|
Little = 4,
|
||||||
|
|
||||||
|
Last,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FingerTypeExtensions
|
||||||
|
{
|
||||||
|
public static string ToAttributeString(this FingerType _this)
|
||||||
|
{
|
||||||
|
if (_this < FingerType.Last)
|
||||||
|
{
|
||||||
|
return _this.ToString();
|
||||||
|
}
|
||||||
|
throw new ArgumentException(_this.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FingerDoFType
|
||||||
|
{
|
||||||
|
_1Stretched = 0,
|
||||||
|
Spread = 1,
|
||||||
|
_2Stretched = 2,
|
||||||
|
_3Stretched = 3,
|
||||||
|
|
||||||
|
Last,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FingerDoFTypeExtensions
|
||||||
|
{
|
||||||
|
public static string ToAttributeString(this FingerDoFType _this)
|
||||||
|
{
|
||||||
|
switch (_this)
|
||||||
|
{
|
||||||
|
case FingerDoFType._1Stretched:
|
||||||
|
return "1 Stretched";
|
||||||
|
case FingerDoFType.Spread:
|
||||||
|
return "Spread";
|
||||||
|
case FingerDoFType._2Stretched:
|
||||||
|
return "2 Stretched";
|
||||||
|
case FingerDoFType._3Stretched:
|
||||||
|
return "3 Stretched";
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(_this.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public enum TDoFBoneType
|
||||||
|
{
|
||||||
|
Spine = 0,
|
||||||
|
Chest = 1,
|
||||||
|
UpperChest = 2,
|
||||||
|
Neck = 3,
|
||||||
|
Head = 4,
|
||||||
|
LeftUpperLeg = 5,
|
||||||
|
LeftLowerLeg = 6,
|
||||||
|
LeftFoot = 7,
|
||||||
|
LeftToes = 8,
|
||||||
|
RightUpperLeg = 9,
|
||||||
|
RightLowerLeg = 10,
|
||||||
|
RightFoot = 11,
|
||||||
|
RightToes = 12,
|
||||||
|
LeftShoulder = 13,
|
||||||
|
LeftUpperArm = 14,
|
||||||
|
LeftLowerArm = 15,
|
||||||
|
LeftHand = 16,
|
||||||
|
RightShoulder = 17,
|
||||||
|
RightUpperArm = 18,
|
||||||
|
RightLowerArm = 19,
|
||||||
|
RightHand = 20,
|
||||||
|
|
||||||
|
Last,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TDoFBoneTypeExtensions
|
||||||
|
{
|
||||||
|
public static TDoFBoneType Update(this TDoFBoneType _this, int[] version)
|
||||||
|
{
|
||||||
|
if (!(version[0] > 5 || (version[0] == 5 && version[1] >= 6)))
|
||||||
|
{
|
||||||
|
if (_this >= TDoFBoneType.UpperChest)
|
||||||
|
{
|
||||||
|
_this++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||||
|
{
|
||||||
|
if (_this >= TDoFBoneType.Head)
|
||||||
|
{
|
||||||
|
_this++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||||
|
{
|
||||||
|
if (_this >= TDoFBoneType.LeftLowerLeg)
|
||||||
|
{
|
||||||
|
_this += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||||
|
{
|
||||||
|
if (_this >= TDoFBoneType.RightLowerLeg)
|
||||||
|
{
|
||||||
|
_this += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||||
|
{
|
||||||
|
if (_this >= TDoFBoneType.LeftUpperArm)
|
||||||
|
{
|
||||||
|
_this += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||||
|
{
|
||||||
|
if (_this >= TDoFBoneType.RightUpperArm)
|
||||||
|
{
|
||||||
|
_this += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoneType ToBoneType(this TDoFBoneType _this)
|
||||||
|
{
|
||||||
|
switch (_this)
|
||||||
|
{
|
||||||
|
case TDoFBoneType.Spine:
|
||||||
|
return BoneType.Spine;
|
||||||
|
case TDoFBoneType.Chest:
|
||||||
|
return BoneType.Chest;
|
||||||
|
case TDoFBoneType.UpperChest:
|
||||||
|
return BoneType.UpperChest;
|
||||||
|
case TDoFBoneType.Neck:
|
||||||
|
return BoneType.Neck;
|
||||||
|
case TDoFBoneType.Head:
|
||||||
|
return BoneType.Head;
|
||||||
|
case TDoFBoneType.LeftUpperLeg:
|
||||||
|
return BoneType.LeftUpperLeg;
|
||||||
|
case TDoFBoneType.LeftLowerLeg:
|
||||||
|
return BoneType.LeftLowerLeg;
|
||||||
|
case TDoFBoneType.LeftFoot:
|
||||||
|
return BoneType.LeftFoot;
|
||||||
|
case TDoFBoneType.LeftToes:
|
||||||
|
return BoneType.LeftToes;
|
||||||
|
case TDoFBoneType.RightUpperLeg:
|
||||||
|
return BoneType.RightUpperLeg;
|
||||||
|
case TDoFBoneType.RightLowerLeg:
|
||||||
|
return BoneType.RightLowerLeg;
|
||||||
|
case TDoFBoneType.RightFoot:
|
||||||
|
return BoneType.RightFoot;
|
||||||
|
case TDoFBoneType.RightToes:
|
||||||
|
return BoneType.RightToes;
|
||||||
|
case TDoFBoneType.LeftShoulder:
|
||||||
|
return BoneType.LeftShoulder;
|
||||||
|
case TDoFBoneType.LeftUpperArm:
|
||||||
|
return BoneType.LeftUpperArm;
|
||||||
|
case TDoFBoneType.LeftLowerArm:
|
||||||
|
return BoneType.LeftLowerArm;
|
||||||
|
case TDoFBoneType.LeftHand:
|
||||||
|
return BoneType.LeftHand;
|
||||||
|
case TDoFBoneType.RightShoulder:
|
||||||
|
return BoneType.RightShoulder;
|
||||||
|
case TDoFBoneType.RightUpperArm:
|
||||||
|
return BoneType.RightUpperArm;
|
||||||
|
case TDoFBoneType.RightLowerArm:
|
||||||
|
return BoneType.RightLowerArm;
|
||||||
|
case TDoFBoneType.RightHand:
|
||||||
|
return BoneType.RightHand;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(_this.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user