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