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); | ||
|  |     } | ||
|  | } |