Files
BusyRabbit/Plugins/UnrealSharp/Managed/UnrealSharpPrograms/UnrealSharpWeaver/Utilities/MethodUtilities.cs
wyatt 648386cd73 Lua向C#逻辑迁移 一期 #13
将整个插件代码上传
2025-10-26 21:48:39 +08:00

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