mirror of
https://github.com/AssetRipper/AssetRipper.git
synced 2025-12-11 20:15:29 +01:00
143 lines
6.5 KiB
C#
143 lines
6.5 KiB
C#
using AssetRipper.AssemblyDumper.Documentation;
|
|
using AssetRipper.AssemblyDumper.InjectedTypes;
|
|
using AssetRipper.AssemblyDumper.Methods;
|
|
using AssetRipper.AssemblyDumper.Types;
|
|
using AssetRipper.Assets;
|
|
|
|
namespace AssetRipper.AssemblyDumper.Passes;
|
|
|
|
/// <summary>
|
|
/// Adds to the IMonoBehaviour and IScriptedImporter interfaces. Also fixes the read and yaml methods
|
|
/// </summary>
|
|
public static class Pass501_MonoBehaviourImplementation
|
|
{
|
|
public static void DoPass()
|
|
{
|
|
TypeDefinition monoBehaviourHelperType = SharedState.Instance.InjectHelperType(typeof(MonoBehaviourHelper));
|
|
TypeSignature propertyType = SharedState.Instance.Importer.ImportTypeSignature<IUnityAssetBase>();
|
|
|
|
//MonoBehaviour
|
|
ApplyChangesToGroup(SharedState.Instance.ClassGroups[114], monoBehaviourHelperType, propertyType);
|
|
|
|
//ScriptedImporter
|
|
ApplyChangesToGroup(SharedState.Instance.ClassGroups[2089858483], monoBehaviourHelperType, propertyType);
|
|
}
|
|
|
|
private static void ApplyChangesToGroup(ClassGroup group, TypeDefinition monoBehaviourHelperType, TypeSignature propertyType)
|
|
{
|
|
const string propertyName = "Structure";
|
|
const string fieldName = "m_" + propertyName;
|
|
|
|
PropertyDefinition interfaceProperty = group.Interface.AddFullProperty(propertyName, InterfaceUtils.InterfacePropertyDeclaration, propertyType)
|
|
.AddNullableAttributesForMaybeNull();
|
|
|
|
foreach (GeneratedClassInstance instance in group.Instances)
|
|
{
|
|
FieldDefinition structureField = instance.Type.AddField(fieldName, propertyType, visibility: Visibility.Internal);
|
|
structureField
|
|
.AddNullableAttributesForMaybeNull()
|
|
.AddDebuggerBrowsableNeverAttribute();
|
|
|
|
PropertyDefinition property = instance.Type.ImplementFullProperty(propertyName, InterfaceUtils.InterfacePropertyImplementation, null, structureField)
|
|
.AddNullableAttributesForMaybeNull();
|
|
|
|
DocumentationHandler.AddPropertyDefinitionLine(property, "The custom structure of this asset, based on the instance fields of its MonoScript.");
|
|
|
|
instance.Type.AddWalkStructure(structureField, monoBehaviourHelperType, "Editor");
|
|
instance.Type.AddWalkStructure(structureField, monoBehaviourHelperType, "Release");
|
|
instance.Type.AddWalkStructure(structureField, monoBehaviourHelperType, "Standard");
|
|
|
|
instance.Type.AddStructureFetchDependencies(structureField, monoBehaviourHelperType);
|
|
|
|
instance.Type.AddStructureReset(structureField, monoBehaviourHelperType);
|
|
|
|
instance.Type.AddStructureCopyValues(structureField, interfaceProperty, monoBehaviourHelperType);
|
|
}
|
|
}
|
|
|
|
private static void AddWalkStructure(this TypeDefinition type, FieldDefinition field, TypeDefinition monoBehaviourHelperType, string walkType)
|
|
{
|
|
string targetMethodName = walkType switch
|
|
{
|
|
"Editor" => nameof(UnityAssetBase.WalkEditor),
|
|
"Release" => nameof(UnityAssetBase.WalkRelease),
|
|
"Standard" => nameof(UnityAssetBase.WalkStandard),
|
|
_ => throw new ArgumentException(null, nameof(walkType)),
|
|
};
|
|
|
|
MethodDefinition method = type.Methods.Single(m => m.Name == targetMethodName);
|
|
|
|
string injectedMethodName = walkType switch
|
|
{
|
|
"Editor" => nameof(MonoBehaviourHelper.MaybeWalkStructureEditor),
|
|
"Release" => nameof(MonoBehaviourHelper.MaybeWalkStructureRelease),
|
|
"Standard" => nameof(MonoBehaviourHelper.MaybeWalkStructureStandard),
|
|
_ => throw new ArgumentException(null, nameof(walkType)),
|
|
};
|
|
|
|
IMethodDefOrRef walkStructureMethod = monoBehaviourHelperType.Methods.Single(m => m.Name == injectedMethodName);
|
|
|
|
CilInstructionCollection instructions = method.CilMethodBody!.Instructions;
|
|
|
|
int insertIndex = FindLastNop(instructions) + 1;
|
|
|
|
//Insert the opcodes in reverse order, so that we don't have to adjust the insert index.
|
|
instructions.Insert(insertIndex, CilOpCodes.Call, walkStructureMethod);
|
|
instructions.Insert(insertIndex, CilOpCodes.Ldarg_1);//walker
|
|
instructions.Insert(insertIndex, CilOpCodes.Ldfld, field);//the structure field
|
|
instructions.Insert(insertIndex, CilOpCodes.Ldarg_0);//this
|
|
instructions.Insert(insertIndex, CilOpCodes.Ldarg_0);//this
|
|
|
|
static int FindLastNop(CilInstructionCollection instructions)
|
|
{
|
|
for (int i = instructions.Count - 1; i >= 0; i--)
|
|
{
|
|
if (instructions[i].OpCode == CilOpCodes.Nop)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
throw new Exception("No nop found");
|
|
}
|
|
}
|
|
|
|
private static void AddStructureFetchDependencies(this TypeDefinition type, FieldDefinition field, TypeDefinition monoBehaviourHelperType)
|
|
{
|
|
MethodDefinition method = type.Methods.Single(m => m.Name == nameof(UnityAssetBase.FetchDependencies));
|
|
IMethodDefOrRef fetchDependenciesMethod = monoBehaviourHelperType.Methods.Single(m => m.Name == nameof(MonoBehaviourHelper.MaybeAppendStructureDependencies));
|
|
CilInstructionCollection instructions = method.CilMethodBody!.Instructions;
|
|
instructions.Pop(); //pop the return value
|
|
instructions.Add(CilOpCodes.Ldarg_0);//this
|
|
instructions.Add(CilOpCodes.Ldfld, field);//the structure field
|
|
instructions.Add(CilOpCodes.Call, fetchDependenciesMethod);
|
|
instructions.Add(CilOpCodes.Ret);
|
|
}
|
|
|
|
private static void AddStructureReset(this TypeDefinition type, FieldDefinition field, TypeDefinition monoBehaviourHelperType)
|
|
{
|
|
MethodDefinition method = type.Methods.Single(m => m.Name == nameof(UnityAssetBase.Reset));
|
|
IMethodDefOrRef resetMethod = monoBehaviourHelperType.Methods.Single(m => m.Name == nameof(MonoBehaviourHelper.ResetStructure));
|
|
CilInstructionCollection instructions = method.CilMethodBody!.Instructions;
|
|
instructions.Pop(); //pop the return value
|
|
instructions.Add(CilOpCodes.Ldarg_0);//this
|
|
instructions.Add(CilOpCodes.Ldfld, field);//the structure field
|
|
instructions.Add(CilOpCodes.Call, resetMethod);
|
|
instructions.Add(CilOpCodes.Ret);
|
|
}
|
|
|
|
private static void AddStructureCopyValues(this TypeDefinition type, FieldDefinition field, PropertyDefinition interfaceProperty, TypeDefinition monoBehaviourHelperType)
|
|
{
|
|
MethodDefinition method = type.Methods.Single(m => m.Name == nameof(UnityAssetBase.CopyValues) && m.IsFinal && m.Parameters.Count == 2);
|
|
IMethodDefOrRef copyValuesMethod = monoBehaviourHelperType.Methods.Single(m => m.Name == nameof(MonoBehaviourHelper.CopyStructureValues));
|
|
CilInstructionCollection instructions = method.CilMethodBody!.Instructions;
|
|
instructions.Pop(); //pop the return value
|
|
instructions.Add(CilOpCodes.Ldarg_0);//this
|
|
instructions.Add(CilOpCodes.Ldflda, field);//the structure field
|
|
instructions.Add(CilOpCodes.Ldarg_1);//source
|
|
instructions.Add(CilOpCodes.Callvirt, interfaceProperty.GetMethod!);//the Structure property
|
|
instructions.Add(CilOpCodes.Ldarg_2);//converter
|
|
instructions.Add(CilOpCodes.Call, copyValuesMethod);
|
|
instructions.Add(CilOpCodes.Ret);
|
|
}
|
|
}
|