mirror of
https://github.com/AssetRipper/AssetRipper.git
synced 2025-12-11 20:15:29 +01:00
109 lines
4.5 KiB
C#
109 lines
4.5 KiB
C#
using AssetRipper.AssemblyDumper.AST;
|
|
using AssetRipper.AssemblyDumper.InjectedTypes;
|
|
using AssetRipper.AssemblyDumper.Methods;
|
|
using AssetRipper.Assets;
|
|
using AssetRipper.Assets.Metadata;
|
|
using System.Collections;
|
|
|
|
namespace AssetRipper.AssemblyDumper.Passes;
|
|
|
|
public static partial class Pass103_FillDependencyMethods
|
|
{
|
|
public static void DoPass()
|
|
{
|
|
TypeDefinition injectedBaseType = SharedState.Instance.InjectHelperType(typeof(FetchDependenciesEnumerableBase));
|
|
FieldDefinition currentField = injectedBaseType.Fields.First(t => t.Name == "_current");
|
|
MethodDefinition baseConstructor = injectedBaseType.GetDefaultConstructor();
|
|
|
|
ITypeDefOrRef commonPPtrTypeRef = SharedState.Instance.Importer.ImportType(typeof(PPtr));
|
|
ITypeDefOrRef ienumerableRef = SharedState.Instance.Importer.ImportType(typeof(IEnumerable<>));
|
|
ITypeDefOrRef valueTupleRef = SharedState.Instance.Importer.ImportType(typeof(ValueTuple<,>));
|
|
GenericInstanceTypeSignature tupleGenericInstance = valueTupleRef.MakeGenericInstanceType(SharedState.Instance.Importer.String, commonPPtrTypeRef.ToTypeSignature());
|
|
IMethodDescriptor emptyEnumerableMethod = SharedState.Instance.Importer.ImportMethod(typeof(Enumerable), m => m.Name == nameof(Enumerable.Empty))
|
|
.MakeGenericInstanceMethod(tupleGenericInstance);
|
|
GenericInstanceTypeSignature returnType = ienumerableRef.MakeGenericInstanceType(tupleGenericInstance);
|
|
foreach (ClassGroupBase group in SharedState.Instance.AllGroups)
|
|
{
|
|
foreach (GeneratedClassInstance instance in group.Instances)
|
|
{
|
|
TypeNode rootNode = new(instance);
|
|
|
|
bool anyPPtrs = rootNode.AnyPPtrs;
|
|
if (!anyPPtrs && group is SubclassGroup)
|
|
{
|
|
//No need to generate a duplicate of the method in UnityAssetBase
|
|
continue;
|
|
}
|
|
|
|
MethodDefinition method = instance.Type.AddMethod(nameof(UnityAssetBase.FetchDependencies), Pass063_CreateEmptyMethods.OverrideMethodAttributes, returnType);
|
|
CilInstructionCollection instructions = method.GetInstructions();
|
|
if (anyPPtrs)
|
|
{
|
|
MethodDefinition enumerableConstructor = MakeEnumerableType(injectedBaseType, currentField, baseConstructor, instance, rootNode);
|
|
instructions.Add(CilOpCodes.Ldarg_0);
|
|
instructions.Add(CilOpCodes.Newobj, enumerableConstructor);
|
|
instructions.Add(CilOpCodes.Ret);
|
|
}
|
|
else
|
|
{
|
|
instructions.Add(CilOpCodes.Call, emptyEnumerableMethod);
|
|
instructions.Add(CilOpCodes.Ret);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static MethodDefinition MakeEnumerableType(TypeDefinition injectedBaseType, FieldDefinition currentField, MethodDefinition baseConstructor, GeneratedClassInstance instance, TypeNode rootNode)
|
|
{
|
|
TypeDefinition enumerableType = new(
|
|
null,
|
|
"FetchDependenciesEnumerable",
|
|
TypeAttributes.NestedPrivate | TypeAttributes.Sealed,
|
|
injectedBaseType);
|
|
instance.Type.NestedTypes.Add(enumerableType);
|
|
|
|
FieldDefinition thisField = enumerableType.AddField("_this", instance.Type.ToTypeSignature(), false, Visibility.Private);
|
|
thisField.IsInitOnly = true;
|
|
|
|
MethodDefinition enumerableConstructor = enumerableType.AddEmptyConstructor();
|
|
enumerableConstructor.AddParameter(instance.Type.ToTypeSignature(), "_this");
|
|
{
|
|
CilInstructionCollection instructions = enumerableConstructor.GetInstructions();
|
|
instructions.Add(CilOpCodes.Ldarg_0);
|
|
instructions.Add(CilOpCodes.Call, baseConstructor);
|
|
instructions.Add(CilOpCodes.Ldarg_0);
|
|
instructions.Add(CilOpCodes.Ldarg_1);
|
|
instructions.Add(CilOpCodes.Stfld, thisField);
|
|
instructions.Add(CilOpCodes.Ret);
|
|
}
|
|
|
|
// CreateNew
|
|
{
|
|
MethodDefinition createNewMethod = enumerableType.AddMethod("CreateNew", MethodAttributes.FamilyAndAssembly | MethodAttributes.Virtual | MethodAttributes.HideBySig, enumerableType.ToTypeSignature());
|
|
{
|
|
CilInstructionCollection instructions = createNewMethod.GetInstructions();
|
|
instructions.Add(CilOpCodes.Ldarg_0);
|
|
instructions.Add(CilOpCodes.Ldfld, thisField);
|
|
instructions.Add(CilOpCodes.Newobj, enumerableConstructor);
|
|
instructions.Add(CilOpCodes.Ret);
|
|
}
|
|
}
|
|
|
|
// MoveNext
|
|
{
|
|
MethodDefinition moveNextMethod = enumerableType.AddMethod(nameof(IEnumerator.MoveNext), MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, SharedState.Instance.Importer.Boolean);
|
|
DependencyMethodContext context = new()
|
|
{
|
|
Processor = moveNextMethod.GetInstructions(),
|
|
Type = enumerableType,
|
|
CurrentField = currentField,
|
|
ThisField = thisField,
|
|
};
|
|
TypeNodeHelper.ApplyAsRoot(rootNode, context);
|
|
context.Processor.OptimizeMacros();
|
|
}
|
|
|
|
return enumerableConstructor;
|
|
}
|
|
}
|