146 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using Mono.Cecil;
 | 
						|
using Mono.Cecil.Cil;
 | 
						|
using Mono.Cecil.Rocks;
 | 
						|
using UnrealSharpWeaver.MetaData;
 | 
						|
 | 
						|
namespace UnrealSharpWeaver.Utilities;
 | 
						|
 | 
						|
public static class MethodUtilities
 | 
						|
{
 | 
						|
    public static readonly EFunctionFlags RpcFlags = EFunctionFlags.NetServer | EFunctionFlags.NetClient | EFunctionFlags.NetMulticast;
 | 
						|
    public static readonly string UFunctionAttribute = "UFunctionAttribute";
 | 
						|
    
 | 
						|
    /// <param name="name">name the method copy will have</param>
 | 
						|
    /// <param name="method">original method</param>
 | 
						|
    /// <param name="addMethod">Add the method copy to the declaring type. this allows to use the original sources to be matched to the copy.</param>
 | 
						|
    /// <param name="copyMetadataToken"></param>
 | 
						|
    /// <returns>new instance of as copy of the original</returns>
 | 
						|
    public static MethodDefinition CopyMethod(string name, MethodDefinition method, bool addMethod = true, bool copyMetadataToken = true)
 | 
						|
    {
 | 
						|
        MethodDefinition newMethod = new MethodDefinition(name, method.Attributes, method.ReturnType)
 | 
						|
        {
 | 
						|
            HasThis = true,
 | 
						|
            ExplicitThis = method.ExplicitThis,
 | 
						|
            CallingConvention = method.CallingConvention,
 | 
						|
            Body = method.Body
 | 
						|
        };
 | 
						|
 | 
						|
        if (copyMetadataToken)
 | 
						|
        {
 | 
						|
            newMethod.MetadataToken = method.MetadataToken;
 | 
						|
        }
 | 
						|
 | 
						|
        foreach (ParameterDefinition parameter in method.Parameters)
 | 
						|
        {
 | 
						|
            TypeReference importedType = parameter.ParameterType.ImportType();
 | 
						|
            newMethod.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes, importedType));
 | 
						|
        }
 | 
						|
        
 | 
						|
        if (addMethod)
 | 
						|
        {
 | 
						|
            method.DeclaringType.Methods.Add(newMethod);
 | 
						|
        }
 | 
						|
 | 
						|
        return newMethod;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static VariableDefinition AddLocalVariable(this MethodDefinition method, TypeReference typeReference)
 | 
						|
    {
 | 
						|
        var variable = new VariableDefinition(typeReference);
 | 
						|
        method.Body.Variables.Add(variable);
 | 
						|
        method.Body.InitLocals = true;
 | 
						|
        return variable;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static void FinalizeMethod(this MethodDefinition method)
 | 
						|
    {
 | 
						|
        method.Body.GetILProcessor().Emit(OpCodes.Ret);
 | 
						|
        OptimizeMethod(method);
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static bool MethodIsCompilerGenerated(this ICustomAttributeProvider method)
 | 
						|
    {
 | 
						|
        return method.CustomAttributes.FindAttributeByType("System.Runtime.CompilerServices", "CompilerGeneratedAttribute") != null;
 | 
						|
    }
 | 
						|
 | 
						|
    public static EFunctionFlags GetFunctionFlags(this MethodDefinition method)
 | 
						|
    {
 | 
						|
        EFunctionFlags flags = (EFunctionFlags) BaseMetaData.GetFlags(method, "FunctionFlagsMapAttribute");
 | 
						|
 | 
						|
        if (method.IsPublic)
 | 
						|
        {
 | 
						|
            flags |= EFunctionFlags.Public;
 | 
						|
        }
 | 
						|
        else if (method.IsFamily)
 | 
						|
        {
 | 
						|
            flags |= EFunctionFlags.Protected;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            flags |= EFunctionFlags.Private;
 | 
						|
        }
 | 
						|
 | 
						|
        if (method.IsStatic)
 | 
						|
        {
 | 
						|
            flags |= EFunctionFlags.Static;
 | 
						|
        }
 | 
						|
        
 | 
						|
        if (flags.HasAnyFlags(RpcFlags))
 | 
						|
        {
 | 
						|
            flags |= EFunctionFlags.Net;
 | 
						|
            
 | 
						|
            if (!method.ReturnsVoid())
 | 
						|
            {
 | 
						|
                throw new InvalidUnrealFunctionException(method, "RPCs can't have return values.");
 | 
						|
            }
 | 
						|
            
 | 
						|
            if (flags.HasFlag(EFunctionFlags.BlueprintNativeEvent))
 | 
						|
            {
 | 
						|
                throw new InvalidUnrealFunctionException(method, "BlueprintEvents methods cannot be replicated!");
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        // This represents both BlueprintNativeEvent and BlueprintImplementableEvent
 | 
						|
        if (flags.HasFlag(EFunctionFlags.BlueprintNativeEvent))
 | 
						|
        {
 | 
						|
            flags |= EFunctionFlags.Event;
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Native is needed to bind the function pointer of the UFunction to our own invoke in UE.
 | 
						|
        return flags | EFunctionFlags.Native;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static void OptimizeMethod(this MethodDefinition method)
 | 
						|
    {
 | 
						|
        if (method.Body.CodeSize == 0)
 | 
						|
        {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        
 | 
						|
        method.Body.Optimize();
 | 
						|
        method.Body.SimplifyMacros();
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static void RemoveReturnInstruction(this MethodDefinition method)
 | 
						|
    {
 | 
						|
        if (method.Body.Instructions.Count > 0 && method.Body.Instructions[^1].OpCode == OpCodes.Ret)
 | 
						|
        {
 | 
						|
            method.Body.Instructions.RemoveAt(method.Body.Instructions.Count - 1);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static CustomAttribute? GetUFunction(this MethodDefinition function)
 | 
						|
    {
 | 
						|
        return function.CustomAttributes.FindAttributeByType(WeaverImporter.UnrealSharpAttributesNamespace, UFunctionAttribute);
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static bool IsUFunction(this MethodDefinition method)
 | 
						|
    {
 | 
						|
        return GetUFunction(method) != null;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static MethodReference ImportMethod(this MethodReference method)
 | 
						|
    {
 | 
						|
        return WeaverImporter.Instance.CurrentWeavingAssembly.MainModule.ImportReference(method);
 | 
						|
    }
 | 
						|
} |