AssetRipper_AssetRipper/Source/AssetRipper.AssemblyDumper/Passes/Pass007_ExtractSubclasses.Injections.cs
2025-09-17 16:40:02 -07:00

478 lines
18 KiB
C#

using AssetRipper.AssemblyDumper.Utils;
using AssetRipper.IO.Files.SerializedFiles;
using System.Diagnostics;
namespace AssetRipper.AssemblyDumper.Passes;
internal static partial class Pass007_ExtractSubclasses
{
private static void DoCustomInjections()
{
InjectLayerMask();
InjectRectInt();
InjectRectOffset();
InjectAABBInt();
InjectGUIStyleState();
InjectGUIStyle();
InjectStreamedCurveKey();
InjectStreamedFrame();
}
private static void InjectLayerMask()
{
const string ClassName = "LayerMask";
VersionedList<UniversalClass> classList = new();
SharedState.Instance.SubclassInformation.Add(ClassName, classList);
UniversalNode releaseNode = MakeRootNode();
UniversalNode editorNode = MakeRootNode();
UniversalClass @class = new UniversalClass(releaseNode, editorNode);
classList.Add(SharedState.Instance.MinVersion, @class);
static UniversalNode MakeRootNode()
{
UniversalNode rootNode = new()
{
Name = "Base",
TypeName = ClassName,
Version = 2,//1 before 2.0.0
MetaFlag = TransferMetaFlags.NoTransferFlags,
};
rootNode.SubNodes.Add(new()
{
Name = "m_Bits",
TypeName = "UInt32",//UInt16 before 2.0.0
Version = 1,
MetaFlag = TransferMetaFlags.NoTransferFlags,
});
return rootNode;
}
}
private static void InjectRectInt()
{
const string ClassName = "RectInt";
VersionedList<UniversalClass> classList = new();
SharedState.Instance.SubclassInformation.Add(ClassName, classList);
UniversalNode releaseNode = MakeRootNode();
UniversalNode editorNode = MakeRootNode();
UniversalClass @class = new UniversalClass(releaseNode, editorNode);
classList.Add(SharedState.Instance.MinVersion, @class);
static UniversalNode MakeRootNode()
{
UniversalNode rootNode = CreateRootNode(ClassName, 2);
rootNode.SubNodes.Add(CreateInt32Node("m_X", "x"));
rootNode.SubNodes.Add(CreateInt32Node("m_Y", "y"));
rootNode.SubNodes.Add(CreateInt32Node("m_Width", "width"));
rootNode.SubNodes.Add(CreateInt32Node("m_Height", "height"));
return rootNode;
}
}
private static void InjectRectOffset()
{
const string ClassName = "RectOffset";
VersionedList<UniversalClass> classList = new();
SharedState.Instance.SubclassInformation.Add(ClassName, classList);
UniversalNode releaseNode = MakeRootNode();
UniversalNode editorNode = MakeRootNode();
UniversalClass @class = new UniversalClass(releaseNode, editorNode);
classList.Add(SharedState.Instance.MinVersion, @class);
static UniversalNode MakeRootNode()
{
UniversalNode rootNode = CreateRootNode(ClassName);
rootNode.SubNodes.Add(CreateInt32Node("m_Left"));
rootNode.SubNodes.Add(CreateInt32Node("m_Right"));
rootNode.SubNodes.Add(CreateInt32Node("m_Top"));
rootNode.SubNodes.Add(CreateInt32Node("m_Bottom"));
return rootNode;
}
}
private static void InjectAABBInt()
{
VersionedList<UniversalClass> vector3IntList = SharedState.Instance.SubclassInformation["Vector3Int"];
VersionedList<UniversalClass> classList = new();
const string ClassName = "AABBInt";
SharedState.Instance.SubclassInformation.Add(ClassName, classList);
foreach ((UnityVersion version, UniversalClass? vectorClass) in vector3IntList)
{
if (vectorClass is null)
{
classList.Add(version, null);
}
else
{
UniversalNode releaseNode;
{
releaseNode = new()
{
Name = "Base",
TypeName = ClassName,
Version = 1,
MetaFlag = TransferMetaFlags.NoTransferFlags,
};
UniversalNode centerNode = vectorClass.ReleaseRootNode!.DeepClone();
centerNode.Name = centerNode.OriginalName = "m_Center";
releaseNode.SubNodes.Add(centerNode);
UniversalNode extentNode = vectorClass.ReleaseRootNode!.DeepClone();
extentNode.Name = extentNode.OriginalName = "m_Extent";
releaseNode.SubNodes.Add(extentNode);
}
UniversalNode editorNode;
{
editorNode = new()
{
Name = "Base",
TypeName = ClassName,
Version = 1,
MetaFlag = TransferMetaFlags.NoTransferFlags,
};
UniversalNode centerNode = vectorClass.EditorRootNode!.DeepClone();
centerNode.Name = centerNode.OriginalName = "m_Center";
editorNode.SubNodes.Add(centerNode);
UniversalNode extentNode = vectorClass.EditorRootNode!.DeepClone();
extentNode.Name = extentNode.OriginalName = "m_Extent";
editorNode.SubNodes.Add(extentNode);
}
UniversalClass @class = new UniversalClass(releaseNode, editorNode);
classList.Add(version, @class);
}
}
}
private static void InjectGUIStyleState()
{
VersionedList<UniversalClass> pptrTexture2DList = SharedState.Instance.SubclassInformation["PPtr_Texture2D"];
VersionedList<UniversalClass> colorList = SharedState.Instance.SubclassInformation["ColorRGBAf"];
Debug.Assert(pptrTexture2DList.Count == 2);
Debug.Assert(colorList.Count == 1);
const string ClassName = "GUIStyleState";
VersionedList<UniversalClass> classList = new();
SharedState.Instance.SubclassInformation.Add(ClassName, classList);
(UnityVersion versionC, UniversalClass? colorClass) = colorList[0];
(UnityVersion versionP1, UniversalClass? pptrClass1) = pptrTexture2DList[0];
(UnityVersion versionP2, UniversalClass? pptrClass2) = pptrTexture2DList[1];
Debug.Assert(versionC == SharedState.Instance.MinVersion);
Debug.Assert(versionC == versionP1);
Debug.Assert(versionC < versionP2);
UniversalNode releaseRoot1 = CreateRootNode(ClassName);
releaseRoot1.SubNodes.Add(pptrClass1!.ReleaseRootNode!.DeepCloneAndChangeName("m_Background"));
releaseRoot1.SubNodes.Add(colorClass!.ReleaseRootNode!.DeepCloneAndChangeName("m_TextColor"));
UniversalNode editorRoot1 = CreateRootNode(ClassName);
editorRoot1.SubNodes.Add(pptrClass1!.EditorRootNode!.DeepCloneAndChangeName("m_Background"));
editorRoot1.SubNodes.Add(colorClass!.EditorRootNode!.DeepCloneAndChangeName("m_TextColor"));
classList.Add(versionC, new UniversalClass(releaseRoot1, editorRoot1));
UniversalNode releaseRoot2 = CreateRootNode(ClassName);
releaseRoot2.SubNodes.Add(pptrClass2!.ReleaseRootNode!.DeepCloneAndChangeName("m_Background"));
releaseRoot2.SubNodes.Add(colorClass!.ReleaseRootNode!.DeepCloneAndChangeName("m_TextColor"));
UniversalNode editorRoot2 = CreateRootNode(ClassName);
editorRoot2.SubNodes.Add(pptrClass2!.EditorRootNode!.DeepCloneAndChangeName("m_Background"));
editorRoot2.SubNodes.Add(colorClass!.EditorRootNode!.DeepCloneAndChangeName("m_TextColor"));
classList.Add(versionP2, new UniversalClass(releaseRoot2, editorRoot2));
UniversalNode releaseRoot3 = CreateRootNode(ClassName);
releaseRoot3.SubNodes.Add(pptrClass2!.ReleaseRootNode!.DeepCloneAndChangeName("m_Background"));
releaseRoot3.SubNodes.Add(colorClass!.ReleaseRootNode!.DeepCloneAndChangeName("m_TextColor"));
UniversalNode editorRoot3 = CreateRootNode(ClassName);
editorRoot3.SubNodes.Add(pptrClass2!.EditorRootNode!.DeepCloneAndChangeName("m_Background"));
editorRoot3.SubNodes.Add(CreateArrayNode("m_ScaledBackgrounds", pptrClass2!.EditorRootNode!.DeepClone(), false));
editorRoot3.SubNodes.Add(colorClass!.EditorRootNode!.DeepCloneAndChangeName("m_TextColor"));
classList.Add(new UnityVersion(5, 4, 0), new UniversalClass(releaseRoot3, editorRoot3));
UniversalNode releaseRoot4 = CreateRootNode(ClassName);
releaseRoot4.SubNodes.Add(pptrClass2!.ReleaseRootNode!.DeepCloneAndChangeName("m_Background"));
releaseRoot4.SubNodes.Add(colorClass!.ReleaseRootNode!.DeepCloneAndChangeName("m_TextColor"));
UniversalNode editorRoot4 = CreateRootNode(ClassName);
editorRoot4.SubNodes.Add(pptrClass2!.EditorRootNode!.DeepCloneAndChangeName("m_Background"));
editorRoot4.SubNodes.Add(CreateArrayNode("m_ScaledBackgrounds", pptrClass2!.EditorRootNode!.DeepClone(), true));
editorRoot4.SubNodes.Add(colorClass!.EditorRootNode!.DeepCloneAndChangeName("m_TextColor"));
classList.Add(ArrayAlignmentStartVersion, new UniversalClass(releaseRoot4, editorRoot4));
}
private static void InjectGUIStyle()
{
UnityVersion builtInVersion = new UnityVersion(4, 0, 0);
VersionedList<UniversalClass> pptrFontList = SharedState.Instance.SubclassInformation["PPtr_Font"];
VersionedList<UniversalClass> stateList = SharedState.Instance.SubclassInformation["GUIStyleState"];
UniversalNode stringTemplate = SharedState.Instance.ClassInformation[1][^1].Value!.ReleaseRootNode!.GetSubNodeByName("m_Name");
VersionedList<UniversalClass> rectOffsetList = SharedState.Instance.SubclassInformation["RectOffset"];
VersionedList<UniversalClass> vectorList = SharedState.Instance.SubclassInformation["Vector2f"];
Debug.Assert(pptrFontList.Count == 2);
Debug.Assert(stateList.Count == 4);
const string ClassName = "GUIStyle";
VersionedList<UniversalClass> classList = new();
SharedState.Instance.SubclassInformation.Add(ClassName, classList);
UnityVersion versionS1 = stateList[0].Key;
UnityVersion versionP1 = pptrFontList[0].Key;
Debug.Assert(versionS1 == versionP1);
Debug.Assert(versionS1 == SharedState.Instance.MinVersion);
Debug.Assert(versionS1 < builtInVersion);
UnityVersion versionP2 = pptrFontList[1].Key;
UnityVersion versionS2 = stateList[1].Key;
UnityVersion versionS3 = stateList[2].Key;
UnityVersion versionS4 = stateList[3].Key;
Debug.Assert(versionS2 == versionP2);
Debug.Assert(versionS2 > builtInVersion);
List<UnityVersion> versions = new()
{
versionS1,
builtInVersion,
versionS2,
versionS3,
versionS4,
};
foreach (UnityVersion version in versions)
{
UniversalNode releaseRoot = CreateRootNode(ClassName);
UniversalNode editorRoot = CreateRootNode(ClassName);
AddSubNodeClone(releaseRoot, editorRoot, stringTemplate, "m_Name");
AddSubNode(releaseRoot, editorRoot, stateList, version, "m_Normal");
AddSubNode(releaseRoot, editorRoot, stateList, version, "m_Hover");
AddSubNode(releaseRoot, editorRoot, stateList, version, "m_Active");
AddSubNode(releaseRoot, editorRoot, stateList, version, "m_Focused");
AddSubNode(releaseRoot, editorRoot, stateList, version, "m_OnNormal");
AddSubNode(releaseRoot, editorRoot, stateList, version, "m_OnHover");
AddSubNode(releaseRoot, editorRoot, stateList, version, "m_OnActive");
AddSubNode(releaseRoot, editorRoot, stateList, version, "m_OnFocused");
AddSubNode(releaseRoot, editorRoot, rectOffsetList, version, "m_Border");
if (IsBuiltinFormat(version))
{
AddSubNode(releaseRoot, editorRoot, rectOffsetList, version, "m_Margin");
AddSubNode(releaseRoot, editorRoot, rectOffsetList, version, "m_Padding");
}
else
{
AddSubNode(releaseRoot, editorRoot, rectOffsetList, version, "m_Padding");
AddSubNode(releaseRoot, editorRoot, rectOffsetList, version, "m_Margin");
}
AddSubNode(releaseRoot, editorRoot, rectOffsetList, version, "m_Overflow");
AddSubNode(releaseRoot, editorRoot, pptrFontList, version, "m_Font");
if (IsBuiltinFormat(version))
{
AddInt32SubNode(releaseRoot, editorRoot, "m_FontSize");
AddInt32SubNode(releaseRoot, editorRoot, "m_FontStyle");
AddInt32SubNode(releaseRoot, editorRoot, "m_Alignment");
AddBooleanSubNode(releaseRoot, editorRoot, "m_WordWrap", false);
AddBooleanSubNode(releaseRoot, editorRoot, "m_RichText", true);
AddInt32SubNode(releaseRoot, editorRoot, "m_TextClipping");
AddInt32SubNode(releaseRoot, editorRoot, "m_ImagePosition");
AddSubNode(releaseRoot, editorRoot, vectorList, version, "m_ContentOffset");
AddSingleSubNode(releaseRoot, editorRoot, "m_FixedWidth");
AddSingleSubNode(releaseRoot, editorRoot, "m_FixedHeight");
AddBooleanSubNode(releaseRoot, editorRoot, "m_StretchWidth", false);
AddBooleanSubNode(releaseRoot, editorRoot, "m_StretchHeight", true);
}
else
{
AddInt32SubNode(releaseRoot, editorRoot, "m_ImagePosition");
AddInt32SubNode(releaseRoot, editorRoot, "m_Alignment");
AddBooleanSubNode(releaseRoot, editorRoot, "m_WordWrap", true);
AddInt32SubNode(releaseRoot, editorRoot, "m_TextClipping");
AddSubNode(releaseRoot, editorRoot, vectorList, version, "m_ContentOffset");
AddSubNode(releaseRoot, editorRoot, vectorList, version, "m_ClipOffset");
AddSingleSubNode(releaseRoot, editorRoot, "m_FixedWidth");
AddSingleSubNode(releaseRoot, editorRoot, "m_FixedHeight");
if (HasFontSize(version))
{
AddInt32SubNode(releaseRoot, editorRoot, "m_FontSize");
AddInt32SubNode(releaseRoot, editorRoot, "m_FontStyle");
}
AddBooleanSubNode(releaseRoot, editorRoot, "m_StretchWidth", true);
AddBooleanSubNode(releaseRoot, editorRoot, "m_StretchHeight", true);
}
classList.Add(version, new UniversalClass(releaseRoot, editorRoot));
}
static void AddSubNodeClone(UniversalNode releaseRoot, UniversalNode editorRoot, UniversalNode sourceNode, string name)
{
releaseRoot.SubNodes.Add(sourceNode.DeepCloneAndChangeName(name));
editorRoot.SubNodes.Add(sourceNode.DeepCloneAndChangeName(name));
}
}
private static void InjectStreamedCurveKey()
{
VersionedList<UniversalClass> vectorList = SharedState.Instance.SubclassInformation["Vector3f"];
UnityVersion startVersion = vectorList[0].Key;
const string ClassName = "StreamedCurveKey";
VersionedList<UniversalClass> classList = new();
SharedState.Instance.SubclassInformation.Add(ClassName, classList);
UniversalNode releaseRoot = CreateRootNode(ClassName);
UniversalNode editorRoot = CreateRootNode(ClassName);
AddInt32SubNode(releaseRoot, editorRoot, "m_Index");
AddSubNode(releaseRoot, editorRoot, vectorList, startVersion, "m_Coefficient");
AddSingleSubNode(releaseRoot, editorRoot, "m_Value");
classList.Add(startVersion, new UniversalClass(releaseRoot, editorRoot));
}
private static void InjectStreamedFrame()
{
VersionedList<UniversalClass> curveKeyList = SharedState.Instance.SubclassInformation["StreamedCurveKey"];
const string ClassName = "StreamedFrame";
VersionedList<UniversalClass> classList = new();
SharedState.Instance.SubclassInformation.Add(ClassName, classList);
List<UnityVersion> versions = new()
{
curveKeyList[0].Key,
ArrayAlignmentStartVersion,
};
foreach (UnityVersion version in versions)
{
UniversalNode releaseRoot = CreateRootNode(ClassName);
UniversalNode editorRoot = CreateRootNode(ClassName);
AddSingleSubNode(releaseRoot, editorRoot, "m_Time");
releaseRoot.SubNodes.Add(CreateArrayNode("m_Curves", curveKeyList[0].Value!.ReleaseRootNode!.DeepClone(), version));
editorRoot.SubNodes.Add(CreateArrayNode("m_Curves", curveKeyList[0].Value!.EditorRootNode!.DeepClone(), version));
classList.Add(version, new UniversalClass(releaseRoot, editorRoot));
}
}
private static UniversalNode DeepCloneAndChangeName(this UniversalNode node, string name)
{
UniversalNode result = node.DeepClone();
result.OriginalName = result.Name = name;
return result;
}
private static UniversalNode CreateRootNode(string className, short version = 1)
{
return new()
{
Name = "Base",
TypeName = className,
Version = version,
MetaFlag = TransferMetaFlags.NoTransferFlags,
};
}
private static UniversalNode CreateInt32Node(string name)
{
return new()
{
Name = name,
TypeName = "SInt32",
Version = 1,
MetaFlag = TransferMetaFlags.NoTransferFlags,
};
}
private static UniversalNode CreateInt32Node(string name, string originalName)
{
UniversalNode result = CreateInt32Node(name);
result.OriginalName = originalName;
return result;
}
private static UniversalNode CreateSingleNode(string name)
{
return new()
{
Name = name,
TypeName = "float",
Version = 1,
MetaFlag = TransferMetaFlags.NoTransferFlags,
};
}
private static UniversalNode CreateBooleanNode(string name, bool align)
{
return new()
{
Name = name,
TypeName = "bool",
Version = 1,
MetaFlag = align ? TransferMetaFlags.AlignBytes : TransferMetaFlags.NoTransferFlags,
};
}
private static UniversalNode CreateArrayNode(string name, UniversalNode dataNode, bool align)
{
UniversalNode arrayNode = new()
{
Name = name,
TypeName = "Array",
Version = 1,
MetaFlag = align ? TransferMetaFlags.AlignBytes : TransferMetaFlags.NoTransferFlags,
};
arrayNode.SubNodes.Add(new()
{
Name = "size",
TypeName = "SInt32",
Version = 1,
MetaFlag = TransferMetaFlags.NoTransferFlags,
});
dataNode.Name = "m_Data";
dataNode.OriginalName = "data";
arrayNode.SubNodes.Add(dataNode);
return arrayNode;
}
private static UniversalNode CreateArrayNode(string name, UniversalNode dataNode, UnityVersion version)
{
return CreateArrayNode(name, dataNode, version >= ArrayAlignmentStartVersion);
}
private static void AddSubNode(UniversalNode releaseRoot, UniversalNode editorRoot, VersionedList<UniversalClass> sourceList, UnityVersion version, string name)
{
releaseRoot.SubNodes.Add(sourceList.GetItemForVersion(version)!.ReleaseRootNode!.DeepCloneAndChangeName(name));
editorRoot.SubNodes.Add(sourceList.GetItemForVersion(version)!.EditorRootNode!.DeepCloneAndChangeName(name));
}
private static void AddInt32SubNode(UniversalNode releaseRoot, UniversalNode editorRoot, string name)
{
releaseRoot.SubNodes.Add(CreateInt32Node(name));
editorRoot.SubNodes.Add(CreateInt32Node(name));
}
private static void AddSingleSubNode(UniversalNode releaseRoot, UniversalNode editorRoot, string name)
{
releaseRoot.SubNodes.Add(CreateSingleNode(name));
editorRoot.SubNodes.Add(CreateSingleNode(name));
}
private static void AddBooleanSubNode(UniversalNode releaseRoot, UniversalNode editorRoot, string name, bool align)
{
releaseRoot.SubNodes.Add(CreateBooleanNode(name, align));
editorRoot.SubNodes.Add(CreateBooleanNode(name, align));
}
/// <summary>
/// 4.0.0 and greater
/// GUIStyle became builtin serializable only in v4.0.0
/// </summary>
private static bool IsBuiltinFormat(UnityVersion version) => version.GreaterThanOrEquals(4);
/// <summary>
/// 3.0.0 and greater
/// </summary>
private static bool HasFontSize(UnityVersion version) => version.GreaterThanOrEquals(3);
private static UnityVersion ArrayAlignmentStartVersion { get; } = new UnityVersion(2017, 1);
}