| @ -0,0 +1,62 @@ | ||||
| using Mono.Cecil; | ||||
| using Mono.Cecil.Rocks; | ||||
|  | ||||
| namespace UnrealSharpWeaver.Utilities; | ||||
|  | ||||
| public static class AssemblyUtilities | ||||
| { | ||||
|     public static TypeReference? FindGenericType(this AssemblyDefinition assembly, string typeNamespace, string typeName, TypeReference[] typeParameters, bool bThrowOnException = true) | ||||
|     { | ||||
|         TypeReference? typeRef = FindType(assembly, typeName, typeNamespace, bThrowOnException); | ||||
|         return typeRef == null ? null : typeRef.Resolve().MakeGenericInstanceType(typeParameters).ImportType(); | ||||
|     } | ||||
|  | ||||
|     public static TypeReference? FindType(this AssemblyDefinition assembly, string typeName, string typeNamespace = "", bool throwOnException = true) | ||||
|     { | ||||
|         foreach (var module in assembly.Modules) | ||||
|         { | ||||
|             foreach (var type in module.GetAllTypes()) | ||||
|             { | ||||
|                 if ((typeNamespace.Length > 0 && type.Namespace != typeNamespace) || type.Name != typeName) | ||||
|                 { | ||||
|                     continue; | ||||
|                 } | ||||
|                  | ||||
|                 return type.ImportType(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (throwOnException) | ||||
|         { | ||||
|             throw new TypeAccessException($"Type \"{typeNamespace}.{typeName}\" not found in userAssembly {assembly.Name}"); | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|      | ||||
|     public static TypeDefinition CreateNewClass(this AssemblyDefinition assembly, string classNamespace, string className, TypeAttributes attributes, TypeReference? parentClass = null) | ||||
|     { | ||||
|         if (parentClass == null) | ||||
|         { | ||||
|             parentClass = assembly.MainModule.TypeSystem.Object; | ||||
|         } | ||||
|          | ||||
|         TypeDefinition newType = new TypeDefinition(classNamespace, className, attributes, parentClass); | ||||
|         assembly.MainModule.Types.Add(newType); | ||||
|         return newType; | ||||
|     } | ||||
|      | ||||
|     public static void ForEachAssembly(Func<AssemblyDefinition, bool> action) | ||||
|     { | ||||
|         List<AssemblyDefinition> assemblies = [WeaverImporter.Instance.UnrealSharpAssembly, WeaverImporter.Instance.UnrealSharpCoreAssembly]; | ||||
|         assemblies.AddRange(WeaverImporter.Instance.AllProjectAssemblies); | ||||
|          | ||||
|         foreach (AssemblyDefinition assembly in assemblies) | ||||
|         { | ||||
|             if (!action(assembly)) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,63 @@ | ||||
| using Mono.Cecil; | ||||
|  | ||||
| namespace UnrealSharpWeaver.Utilities; | ||||
|  | ||||
| public static class AttributeUtilities | ||||
| { | ||||
|     public static readonly string UMetaDataAttribute = "UMetaDataAttribute"; | ||||
|     public static readonly string MetaTagsNamespace = WeaverImporter.AttributeNamespace + ".MetaTags"; | ||||
|      | ||||
|     public static List<CustomAttribute> FindMetaDataAttributes(this IEnumerable<CustomAttribute> customAttributes) | ||||
|     { | ||||
|         return FindAttributesByType(customAttributes, WeaverImporter.AttributeNamespace, UMetaDataAttribute); | ||||
|     } | ||||
|  | ||||
|     public static List<CustomAttribute> FindMetaDataAttributesByNamespace(this IEnumerable<CustomAttribute> customAttributes) | ||||
|     { | ||||
|         return FindAttributesByNamespace(customAttributes, MetaTagsNamespace); | ||||
|     } | ||||
|  | ||||
|     public static CustomAttributeArgument? FindAttributeField(this CustomAttribute attribute, string fieldName) | ||||
|     { | ||||
|         foreach (var field in attribute.Fields)  | ||||
|         { | ||||
|             if (field.Name == fieldName)  | ||||
|             { | ||||
|                 return field.Argument; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|      | ||||
|     public static CustomAttribute? FindAttributeByType(this IEnumerable<CustomAttribute> customAttributes, string typeNamespace, string typeName) | ||||
|     { | ||||
|         List<CustomAttribute> attribs = FindAttributesByType(customAttributes, typeNamespace, typeName); | ||||
|         return attribs.Count == 0 ? null : attribs[0]; | ||||
|     } | ||||
|  | ||||
|     public static List<CustomAttribute> FindAttributesByType(this IEnumerable<CustomAttribute> customAttributes, string typeNamespace, string typeName) | ||||
|     { | ||||
|         List<CustomAttribute> attribs = new List<CustomAttribute>(); | ||||
|         foreach (CustomAttribute attrib in customAttributes) | ||||
|         { | ||||
|             if (attrib.AttributeType.Namespace == typeNamespace && attrib.AttributeType.Name == typeName) | ||||
|             { | ||||
|                 attribs.Add(attrib); | ||||
|             } | ||||
|         } | ||||
|         return attribs; | ||||
|     } | ||||
|  | ||||
|     public static List<CustomAttribute> FindAttributesByNamespace(this IEnumerable<CustomAttribute> customAttributes, string typeNamespace) | ||||
|     { | ||||
|         List<CustomAttribute> attribs = new List<CustomAttribute>(); | ||||
|         foreach (var attrib in customAttributes) | ||||
|         { | ||||
|             if (attrib.AttributeType.Namespace == typeNamespace) | ||||
|             { | ||||
|                 attribs.Add(attrib); | ||||
|             } | ||||
|         } | ||||
|         return attribs; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,34 @@ | ||||
| using Mono.Cecil; | ||||
|  | ||||
| namespace UnrealSharpWeaver.Utilities; | ||||
|  | ||||
| public static class DelegateUtilities | ||||
| { | ||||
|     public static MethodDefinition GetDelegateInvokeMethod(TypeDefinition typeDefinition) | ||||
|     { | ||||
|         foreach (MethodDefinition method in typeDefinition.Methods) | ||||
|         { | ||||
|             if (method.Name != "Invoke") | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|              | ||||
|             if (!method.ReturnsVoid()) | ||||
|             { | ||||
|                 throw new Exception($"{typeDefinition.FullName} is exposed to Unreal Engine, and must have a void return type."); | ||||
|             } | ||||
|              | ||||
|             return method; | ||||
|         } | ||||
|          | ||||
|         throw new Exception($"Delegate type {typeDefinition.FullName} does not have an Invoke method."); | ||||
|     } | ||||
|      | ||||
|     public static string GetUnrealDelegateName(TypeReference typeDefinition) | ||||
|     { | ||||
|         string functionName = typeDefinition.FullName; | ||||
|         functionName = functionName.Replace(".", "_"); | ||||
|         functionName += "__DelegateSignature"; | ||||
|         return functionName; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,9 @@ | ||||
| namespace UnrealSharpWeaver.Utilities; | ||||
|  | ||||
| public static class EnumUtilities | ||||
| { | ||||
|     public static bool HasAnyFlags(this Enum flags, Enum testFlags) | ||||
|     { | ||||
|         return (Convert.ToUInt64(flags) & Convert.ToUInt64(testFlags)) != 0; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,146 @@ | ||||
| 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); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,156 @@ | ||||
| using Mono.Cecil; | ||||
| using Mono.Cecil.Cil; | ||||
| using Mono.Cecil.Rocks; | ||||
|  | ||||
| namespace UnrealSharpWeaver.Utilities; | ||||
|  | ||||
| public static class ParameterUtilities | ||||
| { | ||||
|     public static Instruction CreateLoadInstructionOutParam(this ParameterDefinition param, PropertyType paramTypeCode) | ||||
|     { | ||||
|         while (true) | ||||
|         { | ||||
|             switch (paramTypeCode) | ||||
|             { | ||||
|                 case PropertyType.Enum: | ||||
|                     var param1 = param; | ||||
|                     param = null!; | ||||
|                     paramTypeCode = param1.ParameterType.Resolve().GetEnumUnderlyingType().GetPrimitiveTypeCode(); | ||||
|                     continue; | ||||
|  | ||||
|                 case PropertyType.Bool: | ||||
|                 case PropertyType.Int8: | ||||
|                 case PropertyType.Byte: | ||||
|                     return Instruction.Create(OpCodes.Ldind_I1); | ||||
|  | ||||
|                 case PropertyType.Int16: | ||||
|                 case PropertyType.UInt16: | ||||
|                     return Instruction.Create(OpCodes.Ldind_I2); | ||||
|  | ||||
|                 case PropertyType.Int: | ||||
|                 case PropertyType.UInt32: | ||||
|                     return Instruction.Create(OpCodes.Ldind_I4); | ||||
|  | ||||
|                 case PropertyType.Int64: | ||||
|                 case PropertyType.UInt64: | ||||
|                     return Instruction.Create(OpCodes.Ldind_I8); | ||||
|  | ||||
|                 case PropertyType.Float: | ||||
|                     return Instruction.Create(OpCodes.Ldind_R4); | ||||
|  | ||||
|                 case PropertyType.Double: | ||||
|                     return Instruction.Create(OpCodes.Ldind_R8); | ||||
|  | ||||
|                 case PropertyType.Struct: | ||||
|                     return Instruction.Create(OpCodes.Ldobj, param.ParameterType.GetElementType()); | ||||
|  | ||||
|                 case PropertyType.LazyObject: | ||||
|                 case PropertyType.WeakObject: | ||||
|                 case PropertyType.SoftClass: | ||||
|                 case PropertyType.SoftObject: | ||||
|                 case PropertyType.Class: | ||||
|                     return Instruction.Create(OpCodes.Ldobj, param.ParameterType.GetElementType()); | ||||
|  | ||||
|                 case PropertyType.Delegate: | ||||
|                 case PropertyType.MulticastInlineDelegate: | ||||
|                 case PropertyType.MulticastSparseDelegate: | ||||
|                     // Delegate/multicast delegates in C# are implemented as classes, use Ldind_Ref | ||||
|                     return Instruction.Create(OpCodes.Ldind_Ref); | ||||
|  | ||||
|                 case PropertyType.InternalManagedFixedSizeArray: | ||||
|                 case PropertyType.InternalNativeFixedSizeArray: | ||||
|                     throw new NotImplementedException(); // Fixed size arrays not supported as args | ||||
|  | ||||
|                 case PropertyType.Array: | ||||
|                 case PropertyType.Set: | ||||
|                 case PropertyType.Map: | ||||
|                     // Assumes this will be always be an object (IList, List, ISet, HashSet, IDictionary, Dictionary) | ||||
|                     return Instruction.Create(OpCodes.Ldind_Ref); | ||||
|  | ||||
|                 case PropertyType.Unknown: | ||||
|                 case PropertyType.Interface: | ||||
|                 case PropertyType.Object: | ||||
|                 case PropertyType.ObjectPtr: | ||||
|                 case PropertyType.String: | ||||
|                 case PropertyType.Name: | ||||
|                 case PropertyType.Text: | ||||
|                 case PropertyType.DefaultComponent: | ||||
|                 default: | ||||
|                     return Instruction.Create(OpCodes.Ldind_Ref); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static Instruction CreateSetInstructionOutParam(this ParameterDefinition param, PropertyType paramTypeCode) | ||||
|     { | ||||
|         while (true) | ||||
|         { | ||||
|             switch (paramTypeCode) | ||||
|             { | ||||
|                 case PropertyType.Enum: | ||||
|                     paramTypeCode = param.ParameterType.Resolve().GetEnumUnderlyingType().GetPrimitiveTypeCode(); | ||||
|                     continue; | ||||
|  | ||||
|                 case PropertyType.Bool: | ||||
|                 case PropertyType.Int8: | ||||
|                 case PropertyType.Byte: | ||||
|                     return Instruction.Create(OpCodes.Stind_I1); | ||||
|  | ||||
|                 case PropertyType.Int16: | ||||
|                 case PropertyType.UInt16: | ||||
|                     return Instruction.Create(OpCodes.Stind_I2); | ||||
|  | ||||
|                 case PropertyType.Int: | ||||
|                 case PropertyType.UInt32: | ||||
|                     return Instruction.Create(OpCodes.Stind_I4); | ||||
|  | ||||
|                 case PropertyType.Int64: | ||||
|                 case PropertyType.UInt64: | ||||
|                     return Instruction.Create(OpCodes.Stind_I8); | ||||
|  | ||||
|                 case PropertyType.Float: | ||||
|                     return Instruction.Create(OpCodes.Stind_R4); | ||||
|  | ||||
|                 case PropertyType.Double: | ||||
|                     return Instruction.Create(OpCodes.Stind_R8); | ||||
|  | ||||
|                 case PropertyType.Struct: | ||||
|                     return Instruction.Create(OpCodes.Stobj, param.ParameterType.GetElementType()); | ||||
|  | ||||
|                 case PropertyType.LazyObject: | ||||
|                 case PropertyType.WeakObject: | ||||
|                 case PropertyType.SoftClass: | ||||
|                 case PropertyType.SoftObject: | ||||
|                 case PropertyType.Class: | ||||
|                 case PropertyType.Name: | ||||
|                 case PropertyType.Text: | ||||
|                     return Instruction.Create(OpCodes.Stobj, param.ParameterType.GetElementType()); | ||||
|  | ||||
|                 case PropertyType.Delegate: | ||||
|                 case PropertyType.MulticastSparseDelegate: | ||||
|                 case PropertyType.MulticastInlineDelegate: | ||||
|                     // Delegate/multicast delegates in C# are implemented as classes, use Stind_Ref | ||||
|                     return Instruction.Create(OpCodes.Stind_Ref); | ||||
|  | ||||
|                 case PropertyType.InternalManagedFixedSizeArray: | ||||
|                 case PropertyType.InternalNativeFixedSizeArray: | ||||
|                     throw new NotImplementedException(); // Fixed size arrays not supported as args | ||||
|  | ||||
|                 case PropertyType.Array: | ||||
|                 case PropertyType.Set: | ||||
|                 case PropertyType.Map: | ||||
|                     // Assumes this will be always be an object (IList, List, ISet, HashSet, IDictionary, Dictionary) | ||||
|                     return Instruction.Create(OpCodes.Stind_Ref); | ||||
|  | ||||
|                 case PropertyType.Unknown: | ||||
|                 case PropertyType.Interface: | ||||
|                 case PropertyType.Object: | ||||
|                 case PropertyType.ObjectPtr: | ||||
|                 case PropertyType.String: | ||||
|                 case PropertyType.DefaultComponent: | ||||
|                 default: | ||||
|                     return Instruction.Create(OpCodes.Stind_Ref); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,24 @@ | ||||
| using Mono.Cecil; | ||||
| using Mono.Collections.Generic; | ||||
|  | ||||
| namespace UnrealSharpWeaver.Utilities; | ||||
|  | ||||
| public static class PropertyUtilities | ||||
| { | ||||
|     public static readonly string UPropertyAttribute = "UPropertyAttribute"; | ||||
|      | ||||
|     public static CustomAttribute? GetUProperty(Collection<CustomAttribute> attributes) | ||||
|     { | ||||
|         return attributes.FindAttributeByType(WeaverImporter.UnrealSharpAttributesNamespace, UPropertyAttribute); | ||||
|     } | ||||
|      | ||||
|     public static CustomAttribute? GetUProperty(this IMemberDefinition typeDefinition) | ||||
|     { | ||||
|         return typeDefinition.CustomAttributes.FindAttributeByType(WeaverImporter.UnrealSharpAttributesNamespace, UPropertyAttribute); | ||||
|     } | ||||
|      | ||||
|     public static bool IsUProperty(this IMemberDefinition property) | ||||
|     { | ||||
|         return GetUProperty(property.CustomAttributes) != null; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,656 @@ | ||||
| using System.Reflection.Metadata; | ||||
| using Mono.Cecil; | ||||
| using Mono.Cecil.Rocks; | ||||
| using Mono.Collections.Generic; | ||||
| using UnrealSharpWeaver.NativeTypes; | ||||
| using CustomAttribute = Mono.Cecil.CustomAttribute; | ||||
| using FieldDefinition = Mono.Cecil.FieldDefinition; | ||||
| using InterfaceImplementation = Mono.Cecil.InterfaceImplementation; | ||||
| using MethodDefinition = Mono.Cecil.MethodDefinition; | ||||
| using PropertyDefinition = Mono.Cecil.PropertyDefinition; | ||||
| using SequencePoint = Mono.Cecil.Cil.SequencePoint; | ||||
| using TypeDefinition = Mono.Cecil.TypeDefinition; | ||||
| using TypeReference = Mono.Cecil.TypeReference; | ||||
|  | ||||
| namespace UnrealSharpWeaver.Utilities; | ||||
|  | ||||
| public static class TypeDefinitionUtilities | ||||
| { | ||||
|     public static readonly string UClassCallbacks = "UClassExporter"; | ||||
|     public static readonly string UClassAttribute = "UClassAttribute"; | ||||
|      | ||||
|     public static readonly string UEnumAttribute = "UEnumAttribute"; | ||||
|     public static readonly string UStructAttribute = "UStructAttribute"; | ||||
|     public static readonly string UInterfaceAttribute = "UInterfaceAttribute"; | ||||
|     public static readonly string BlittableTypeAttribute = "BlittableTypeAttribute"; | ||||
|      | ||||
|     public static CustomAttribute? GetUClass(this IMemberDefinition definition) | ||||
|     { | ||||
|         return definition.CustomAttributes.FindAttributeByType(WeaverImporter.UnrealSharpAttributesNamespace, UClassAttribute); | ||||
|     } | ||||
|      | ||||
|     public static bool IsUClass(this IMemberDefinition definition) | ||||
|     { | ||||
|         return GetUClass(definition) != null; | ||||
|     } | ||||
|      | ||||
|     public static bool IsUInterface(this TypeDefinition typeDefinition) | ||||
|     { | ||||
|         return GetUInterface(typeDefinition) != null; | ||||
|     } | ||||
|      | ||||
|     public static bool IsUEnum(this TypeDefinition typeDefinition) | ||||
|     { | ||||
|         return GetUEnum(typeDefinition) != null; | ||||
|     } | ||||
|      | ||||
|     public static CustomAttribute? GetUStruct(this IMemberDefinition type) | ||||
|     { | ||||
|         return type.CustomAttributes.FindAttributeByType(WeaverImporter.UnrealSharpAttributesNamespace, UStructAttribute); | ||||
|     } | ||||
|      | ||||
|     public static bool IsUStruct(this IMemberDefinition definition) | ||||
|     { | ||||
|         return GetUStruct(definition) != null; | ||||
|     } | ||||
|      | ||||
|     public static string GetEngineName(this IMemberDefinition memberDefinition) | ||||
|     { | ||||
|         IMemberDefinition currentMemberIteration = memberDefinition; | ||||
|         while (currentMemberIteration != null) | ||||
|         { | ||||
|             CustomAttribute? genTypeAttribute = currentMemberIteration.CustomAttributes | ||||
|                 .FirstOrDefault(x => x.AttributeType.Name == WeaverImporter.GeneratedTypeAttribute); | ||||
|              | ||||
|             if (genTypeAttribute is not null) | ||||
|             { | ||||
|                 return (string) genTypeAttribute.ConstructorArguments[0].Value; | ||||
|             } | ||||
|  | ||||
|             if (memberDefinition.IsUClass() && memberDefinition.Name.StartsWith('U') || | ||||
|                 memberDefinition.IsUStruct() && memberDefinition.Name.StartsWith('F')) | ||||
|             { | ||||
|                 return memberDefinition.Name[1..]; | ||||
|             } | ||||
|              | ||||
|             if (currentMemberIteration is MethodDefinition { IsVirtual: true } virtualMethodDefinition) | ||||
|             { | ||||
|                 if (currentMemberIteration == virtualMethodDefinition.GetBaseMethod()) | ||||
|                 { | ||||
|                     break; | ||||
|                 } | ||||
|                  | ||||
|                 currentMemberIteration = virtualMethodDefinition.GetBaseMethod(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // Same name in engine as in managed code | ||||
|         return memberDefinition.Name; | ||||
|     } | ||||
|      | ||||
|     public static CustomAttribute? GetUEnum(this TypeDefinition type) | ||||
|     { | ||||
|         return type.CustomAttributes.FindAttributeByType(WeaverImporter.UnrealSharpAttributesNamespace, UEnumAttribute); | ||||
|     } | ||||
|      | ||||
|     public static CustomAttribute? GetBlittableType(this TypeDefinition type) | ||||
|     { | ||||
|         return type.CustomAttributes.FindAttributeByType(WeaverImporter.UnrealSharpCoreAttributesNamespace, BlittableTypeAttribute); | ||||
|     } | ||||
|      | ||||
|     public static bool IsUnmanagedType(this TypeReference typeRef) | ||||
|     { | ||||
|         var typeDef = typeRef.Resolve(); | ||||
|      | ||||
|         // Must be a value type | ||||
|         if (!typeDef.IsValueType) | ||||
|             return false; | ||||
|  | ||||
|         // Primitive types and enums are unmanaged | ||||
|         if (typeDef.IsPrimitive || typeDef.IsEnum) | ||||
|             return true; | ||||
|  | ||||
|         // For structs, recursively check all fields | ||||
|         return typeDef.Fields | ||||
|             .Where(f => !f.IsStatic) | ||||
|             .Select(f => f.FieldType.Resolve()) | ||||
|             .All(IsUnmanagedType); | ||||
|     } | ||||
|  | ||||
|      | ||||
|     public static CustomAttribute? GetUInterface(this TypeDefinition type) | ||||
|     { | ||||
|         return type.CustomAttributes.FindAttributeByType(WeaverImporter.UnrealSharpAttributesNamespace, UInterfaceAttribute); | ||||
|     } | ||||
|      | ||||
|     public static void AddGeneratedTypeAttribute(this TypeDefinition type) | ||||
|     { | ||||
|         CustomAttribute attribute = new CustomAttribute(WeaverImporter.Instance.GeneratedTypeCtor); | ||||
|         string typeName = type.Name.Substring(1); | ||||
|         string fullTypeName = type.Namespace + "." + typeName; | ||||
|         attribute.ConstructorArguments.Add(new CustomAttributeArgument(WeaverImporter.Instance.CurrentWeavingAssembly.MainModule.TypeSystem.String, typeName)); | ||||
|         attribute.ConstructorArguments.Add(new CustomAttributeArgument(WeaverImporter.Instance.CurrentWeavingAssembly.MainModule.TypeSystem.String, fullTypeName)); | ||||
|          | ||||
|         type.CustomAttributes.Add(attribute); | ||||
|     } | ||||
|      | ||||
|     public static PropertyDefinition? FindPropertyByName(this TypeDefinition classOuter, string propertyName) | ||||
|     { | ||||
|         foreach (var property in classOuter.Properties) | ||||
|         { | ||||
|             if (property.Name == propertyName) | ||||
|             { | ||||
|                 return property; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return default; | ||||
|     } | ||||
|      | ||||
|     public static bool IsChildOf(this TypeDefinition type, TypeDefinition parentType) | ||||
|     { | ||||
|         TypeDefinition? currentType = type; | ||||
|         while (currentType != null) | ||||
|         { | ||||
|             if (currentType == parentType) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|  | ||||
|             currentType = currentType.BaseType?.Resolve(); | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     public static TypeReference FindNestedType(this TypeDefinition typeDef, string typeName) | ||||
|     { | ||||
|         foreach (var nestedType in typeDef.NestedTypes) | ||||
|         { | ||||
|             if (nestedType.Name != typeName) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             return WeaverImporter.Instance.CurrentWeavingAssembly.MainModule.ImportReference(nestedType); | ||||
|         } | ||||
|          | ||||
|         throw new Exception($"{typeName} not found in {typeDef}."); | ||||
|     } | ||||
|      | ||||
|     public static MethodDefinition AddMethod(this TypeDefinition type, string name, TypeReference? returnType, MethodAttributes attributes = MethodAttributes.Private, params TypeReference[] parameterTypes) | ||||
|     { | ||||
|         returnType ??= WeaverImporter.Instance.CurrentWeavingAssembly.MainModule.TypeSystem.Void; | ||||
|          | ||||
|         var method = new MethodDefinition(name, attributes, returnType); | ||||
|          | ||||
|         foreach (var parameterType in parameterTypes) | ||||
|         { | ||||
|             method.Parameters.Add(new ParameterDefinition(parameterType)); | ||||
|         } | ||||
|         type.Methods.Add(method); | ||||
|         return method; | ||||
|     } | ||||
|      | ||||
|     public static MethodDefinition GetOrAddMethod(this TypeDefinition type, string name, TypeReference? returnType, MethodAttributes attributes = MethodAttributes.Private, params TypeReference[] parameterTypes) | ||||
|     { | ||||
|         returnType ??= WeaverImporter.Instance.CurrentWeavingAssembly.MainModule.TypeSystem.Void; | ||||
|       | ||||
|         var existingMethod = FindMethod(type, name, throwIfNotFound: false, parameterTypes); | ||||
|         if (existingMethod is not null) | ||||
|         { | ||||
|             return existingMethod.Resolve(); | ||||
|         } | ||||
|          | ||||
|         var method = new MethodDefinition(name, attributes, returnType); | ||||
|          | ||||
|         foreach (var parameterType in parameterTypes) | ||||
|         { | ||||
|             method.Parameters.Add(new ParameterDefinition(parameterType)); | ||||
|         } | ||||
|         type.Methods.Add(method); | ||||
|         return method; | ||||
|     } | ||||
|  | ||||
|     private static readonly MethodAttributes MethodAttributes = MethodAttributes.Public | MethodAttributes.Static; | ||||
|      | ||||
|     public static MethodDefinition AddToNativeMethod(this TypeDefinition type, TypeDefinition valueType, TypeReference[]? parameters = null) | ||||
|     { | ||||
|         if (parameters == null) | ||||
|         { | ||||
|             parameters = [WeaverImporter.Instance.IntPtrType, WeaverImporter.Instance.Int32TypeRef, valueType]; | ||||
|         } | ||||
|          | ||||
|         MethodDefinition toNativeMethod = type.AddMethod("ToNative", WeaverImporter.Instance.VoidTypeRef, MethodAttributes, parameters); | ||||
|         return toNativeMethod; | ||||
|     } | ||||
|      | ||||
|     public static MethodDefinition AddFromNativeMethod(this TypeDefinition type, TypeDefinition returnType, TypeReference[]? parameters = null) | ||||
|     { | ||||
|         if (parameters == null) | ||||
|         { | ||||
|             parameters = [WeaverImporter.Instance.IntPtrType, WeaverImporter.Instance.Int32TypeRef]; | ||||
|         } | ||||
|          | ||||
|         MethodDefinition fromNative = type.AddMethod("FromNative", returnType, MethodAttributes, parameters); | ||||
|         return fromNative; | ||||
|     } | ||||
|      | ||||
|     public static FieldDefinition AddField(this TypeDefinition type, string name, TypeReference typeReference, FieldAttributes attributes = 0) | ||||
|     { | ||||
|         if (attributes == 0) | ||||
|         { | ||||
|             attributes = FieldAttributes.Static | FieldAttributes.Private; | ||||
|         } | ||||
|          | ||||
|         var field = new FieldDefinition(name, attributes, typeReference); | ||||
|         type.Fields.Add(field); | ||||
|         return field; | ||||
|     } | ||||
|      | ||||
|     public static FieldReference FindField(this TypeDefinition typeDef, string fieldName) | ||||
|     { | ||||
|         foreach (var field in typeDef.Fields) | ||||
|         { | ||||
|             if (field.Name != fieldName) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             return WeaverImporter.Instance.CurrentWeavingAssembly.MainModule.ImportReference(field); | ||||
|         } | ||||
|          | ||||
|         throw new Exception($"{fieldName} not found in {typeDef}."); | ||||
|     } | ||||
|      | ||||
|     public static bool IsUObject(this TypeDefinition typeDefinition) | ||||
|     { | ||||
|         if (!typeDefinition.IsUClass()) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|          | ||||
|         while (typeDefinition != null) | ||||
|         { | ||||
|             if (typeDefinition.BaseType == null) | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
|              | ||||
|             if (typeDefinition == WeaverImporter.Instance.UObjectDefinition) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|  | ||||
|             typeDefinition = typeDefinition.BaseType.Resolve(); | ||||
|         } | ||||
|          | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     public static TypeReference ImportType(this TypeReference type) | ||||
|     { | ||||
|         return WeaverImporter.Instance.CurrentWeavingAssembly.MainModule.ImportReference(type); | ||||
|     } | ||||
|      | ||||
|     public static bool HasMethod(this TypeDefinition typeDef, string methodName, bool throwIfNotFound = true, params TypeReference[] parameterTypes) | ||||
|     { | ||||
|         return FindMethod(typeDef, methodName, throwIfNotFound, parameterTypes) != null; | ||||
|     } | ||||
|  | ||||
|     public static MethodReference? FindMethod(this TypeReference typeReference, string methodName, | ||||
|         bool throwIfNotFound = true, params TypeReference[] parameterTypes) | ||||
|     { | ||||
|         var method = FindMethod(typeReference.Resolve(), methodName, throwIfNotFound, parameterTypes); | ||||
|         if (method is null) return null; | ||||
|          | ||||
|         // If the declaring type is generic instance, we need to create a new method reference | ||||
|         if (typeReference is GenericInstanceType genericInstance) | ||||
|         { | ||||
|             // Create new method reference on the generic instance | ||||
|             var newMethod = new MethodReference(method.Name, method.ReturnType, genericInstance) | ||||
|             { | ||||
|                 HasThis = method.HasThis, | ||||
|                 ExplicitThis = method.ExplicitThis, | ||||
|                 CallingConvention = method.CallingConvention | ||||
|             }; | ||||
|  | ||||
|             // Copy the parameters | ||||
|             foreach (var parameter in method.Parameters) | ||||
|             { | ||||
|                 newMethod.Parameters.Add(new ParameterDefinition(parameter.ParameterType)); | ||||
|             } | ||||
|  | ||||
|             // If the method itself is generic, handle its generic parameters | ||||
|             if (method.HasGenericParameters) | ||||
|             { | ||||
|                 var genericInstanceMethod = new GenericInstanceMethod(newMethod); | ||||
|                 foreach (var genericParam in method.GenericParameters) | ||||
|                 { | ||||
|                     // Map the generic parameter to the concrete type from the declaring type | ||||
|                     var concreteType = genericInstance.GenericArguments[genericParam.Position]; | ||||
|                     genericInstanceMethod.GenericArguments.Add(concreteType); | ||||
|                 } | ||||
|                 return genericInstanceMethod; | ||||
|             } | ||||
|  | ||||
|             return newMethod; | ||||
|         } | ||||
|  | ||||
|         return method; | ||||
|     } | ||||
|  | ||||
|     public static MethodReference? FindMethod(this TypeDefinition typeDef, string methodName, bool throwIfNotFound = true, params TypeReference[] parameterTypes) | ||||
|     { | ||||
|         TypeDefinition? currentClass = typeDef; | ||||
|         while (currentClass != null) | ||||
|         { | ||||
|             MethodReference? method = FindOwnMethod(currentClass, methodName, throwIfNotFound: false, parameterTypes); | ||||
|             if (method != null) | ||||
|             { | ||||
|                 return method; | ||||
|             } | ||||
|  | ||||
|             currentClass = currentClass.BaseType?.Resolve(); | ||||
|         } | ||||
|  | ||||
|         if (throwIfNotFound) | ||||
|         { | ||||
|             throw new Exception("Couldn't find method " + methodName + " in " + typeDef + "."); | ||||
|         } | ||||
|  | ||||
|         return default; | ||||
|     } | ||||
|      | ||||
|     public static MethodReference? FindOwnMethod(TypeDefinition typeDef, string methodName, bool throwIfNotFound = true, params TypeReference[] parameterTypes) | ||||
|     { | ||||
|         foreach (var classMethod in typeDef.Methods) | ||||
|         { | ||||
|             if (classMethod.Name != methodName) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (parameterTypes.Length > 0 && classMethod.Parameters.Count != parameterTypes.Length) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             bool found = true; | ||||
|             for (int i = 0; i < parameterTypes.Length; i++) | ||||
|             { | ||||
|                 if (classMethod.Parameters[i].ParameterType.FullName != parameterTypes[i].FullName) | ||||
|                 { | ||||
|                     found = false; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (found) | ||||
|             { | ||||
|                 return classMethod.ImportMethod(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (throwIfNotFound) | ||||
|         { | ||||
|             throw new Exception("Couldn't find method " + methodName + " in " + typeDef + "."); | ||||
|         } | ||||
|  | ||||
|         return default; | ||||
|     } | ||||
|      | ||||
|     public static NativeDataType GetDataType(this TypeReference typeRef, string propertyName, Collection<CustomAttribute>? customAttributes) | ||||
|     { | ||||
|         int arrayDim = 1; | ||||
|         TypeDefinition typeDef = typeRef.Resolve(); | ||||
|         SequencePoint? sequencePoint = ErrorEmitter.GetSequencePointFromMemberDefinition(typeDef); | ||||
|  | ||||
|         if (customAttributes != null) | ||||
|         { | ||||
|             CustomAttribute? propertyAttribute = typeDef.GetUProperty(); | ||||
|              | ||||
|             if (propertyAttribute != null) | ||||
|             { | ||||
|                 CustomAttributeArgument? arrayDimArg = propertyAttribute.FindAttributeField("ArrayDim"); | ||||
|  | ||||
|                 if (typeRef is GenericInstanceType genericType && genericType.GetElementType().FullName == "UnrealSharp.FixedSizeArrayReadWrite`1") | ||||
|                 { | ||||
|                     if (arrayDimArg.HasValue) | ||||
|                     { | ||||
|                         arrayDim = (int) arrayDimArg.Value.Value; | ||||
|  | ||||
|                         // Unreal doesn't have a separate type for fixed arrays, so we just want to generate the inner UProperty type with an arrayDim. | ||||
|                         typeRef = genericType.GenericArguments[0]; | ||||
|                         typeDef = typeRef.Resolve(); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         throw new InvalidPropertyException(propertyName, sequencePoint, "Fixed array properties must specify an ArrayDim in their [UProperty] attribute"); | ||||
|                     } | ||||
|                 } | ||||
|                 else if (arrayDimArg.HasValue) | ||||
|                 { | ||||
|                     throw new InvalidPropertyException(propertyName, sequencePoint, "ArrayDim is only valid for FixedSizeArray properties."); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         switch (typeDef.FullName) | ||||
|         { | ||||
|             case "System.Double": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.Double); | ||||
|             case "System.Single": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.Float); | ||||
|  | ||||
|             case "System.SByte": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.Int8); | ||||
|             case "System.Int16": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.Int16); | ||||
|             case "System.Int32": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.Int); | ||||
|             case "System.Int64": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.Int64); | ||||
|  | ||||
|             case "System.Byte": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.Byte); | ||||
|             case "System.UInt16": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.UInt16); | ||||
|             case "System.UInt32": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.UInt32); | ||||
|             case "System.UInt64": | ||||
|                 return new NativeDataBuiltinType(typeRef, arrayDim, PropertyType.UInt64); | ||||
|  | ||||
|             case "System.Boolean": | ||||
|                 return new NativeDataBooleanType(typeRef, arrayDim); | ||||
|  | ||||
|             case "System.String": | ||||
|                 return new NativeDataStringType(typeRef, arrayDim); | ||||
|  | ||||
|             default: | ||||
|  | ||||
|                 if (typeRef.IsGenericInstance || typeRef.IsByReference) | ||||
|                 { | ||||
|                     GenericInstanceType? instanceType = null; | ||||
|                     if (typeRef is GenericInstanceType genericInstanceType) | ||||
|                     { | ||||
|                         instanceType = genericInstanceType; | ||||
|                     } | ||||
|                     if (typeRef is ByReferenceType byReferenceType) | ||||
|                     { | ||||
|                         instanceType = byReferenceType.ElementType as GenericInstanceType; | ||||
|                         typeRef = byReferenceType.ElementType; | ||||
|                     } | ||||
|  | ||||
|                     if (instanceType != null) | ||||
|                     { | ||||
|                         TypeReference[] genericArguments = instanceType.GenericArguments.ToArray(); | ||||
|                         string? genericTypeName = instanceType.ElementType.Name; | ||||
|                          | ||||
|                         if (genericTypeName.Contains("TArray`1") || genericTypeName.Contains("List`1")) | ||||
|                         { | ||||
|                             return new NativeDataArrayType(typeRef, arrayDim, genericArguments[0]); | ||||
|                         } | ||||
|  | ||||
|                         if (genericTypeName.Contains("TNativeArray`1") || genericTypeName.Contains("ReadOnlySpan`1")) | ||||
|                         { | ||||
|                             return new NativeDataNativeArrayType(typeRef, arrayDim, genericArguments[0]); | ||||
|                         } | ||||
|  | ||||
|                         if (genericTypeName.Contains("TMap`2") || genericTypeName.Contains("Dictionary`2")) | ||||
|                         { | ||||
|                             return new NativeDataMapType(typeRef, arrayDim, genericArguments[0], genericArguments[1]); | ||||
|                         } | ||||
|                          | ||||
|                         if (genericTypeName.Contains("TSet`1") || genericTypeName.Contains("HashSet`1")) | ||||
|                         { | ||||
|                             return new NativeDataSetType(typeRef, arrayDim, genericArguments[0]); | ||||
|                         } | ||||
|  | ||||
|                         if (genericTypeName.Contains("TSubclassOf`1")) | ||||
|                         { | ||||
|                             return new NativeDataClassType(typeRef, genericArguments[0], arrayDim); | ||||
|                         } | ||||
|  | ||||
|                         if (genericTypeName.Contains("TWeakObjectPtr`1")) | ||||
|                         { | ||||
|                             return new NativeDataWeakObjectType(typeRef, genericArguments[0], arrayDim); | ||||
|                         } | ||||
|  | ||||
|                         if (genericTypeName.Contains("TSoftObjectPtr`1")) | ||||
|                         { | ||||
|                             return new NativeDataSoftObjectType(typeRef, genericArguments[0], arrayDim); | ||||
|                         } | ||||
|  | ||||
|                         if (genericTypeName.Contains("TSoftClassPtr`1")) | ||||
|                         { | ||||
|                             return new NativeDataSoftClassType(typeRef, genericArguments[0], arrayDim); | ||||
|                         } | ||||
|  | ||||
|                         if (genericTypeName.Contains("TOptional`1")) | ||||
|                         { | ||||
|                             return new NativeDataOptionalType(typeRef, genericArguments[0], arrayDim); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (typeDef.IsEnum && typeDef.IsUEnum()) | ||||
|                 { | ||||
|                     CustomAttribute? enumAttribute = typeDef.GetUEnum(); | ||||
|                  | ||||
|                     if (enumAttribute == null) | ||||
|                     { | ||||
|                         throw new InvalidPropertyException(propertyName, sequencePoint, "Enum properties must use an UEnum enum: " + typeRef.FullName); | ||||
|                     } | ||||
|                  | ||||
|                     // TODO: This is just true for properties, not for function parameters they can be int. Need a good way to differentiate. | ||||
|                     // if (typeDef.GetEnumUnderlyingType().Resolve() != ByteTypeRef.Resolve()) | ||||
|                     // { | ||||
|                     //     throw new InvalidPropertyException(propertyName, sequencePoint, "Enum's exposed to Blueprints must have an underlying type of System.Byte: " + typeRef.FullName); | ||||
|                     // } | ||||
|  | ||||
|                     return new NativeDataEnumType(typeDef, arrayDim); | ||||
|                 } | ||||
|  | ||||
|                 if (typeDef.IsInterface && typeDef.IsUInterface()) | ||||
|                 { | ||||
|                     return new NativeDataInterfaceType(typeRef, typeDef.Name + "Marshaller"); | ||||
|                 } | ||||
|                  | ||||
|                 if (typeDef.FullName == "UnrealSharp.FText") | ||||
|                 { | ||||
|                     return new NativeDataTextType(typeDef); | ||||
|                 } | ||||
|                  | ||||
|                 if (typeDef.FullName == "UnrealSharp.FName") | ||||
|                 { | ||||
|                     return new NativeDataNameType(typeDef, arrayDim); | ||||
|                 } | ||||
|              | ||||
|                 if (typeDef.Name == "TMulticastDelegate`1") | ||||
|                 { | ||||
|                     return new NativeDataMulticastDelegate(typeRef); | ||||
|                 } | ||||
|              | ||||
|                 if (typeDef.Name == "TDelegate`1") | ||||
|                 { | ||||
|                     return new NativeDataDelegateType(typeRef); | ||||
|                 } | ||||
|              | ||||
|                 if (customAttributes != null && NativeDataDefaultComponent.IsDefaultComponent(customAttributes)) | ||||
|                 { | ||||
|                     return new NativeDataDefaultComponent(customAttributes, typeDef, arrayDim); | ||||
|                 } | ||||
|              | ||||
|                 TypeDefinition? superType = typeDef; | ||||
|                 while (superType != null && superType.FullName != "UnrealSharp.Core.UnrealSharpObject") | ||||
|                 { | ||||
|                     TypeReference superTypeRef = superType.BaseType; | ||||
|                     superType = superTypeRef != null ? superTypeRef.Resolve() : null; | ||||
|                 } | ||||
|  | ||||
|                 if (superType != null) | ||||
|                 { | ||||
|                     return new NativeDataObjectType(typeRef, typeDef, arrayDim); | ||||
|                 } | ||||
|  | ||||
|                 // See if this is a struct | ||||
|                 CustomAttribute? structAttribute = typeDef.GetUStruct(); | ||||
|                  | ||||
|                 if (structAttribute == null) | ||||
|                 { | ||||
|                     return typeDef.IsUnmanagedType() ? new NativeDataUnmanagedType(typeDef, arrayDim) : new NativeDataManagedObjectType(typeRef, arrayDim); | ||||
|                 } | ||||
|                  | ||||
|                 return typeDef.GetBlittableType() != null ? new NativeDataBlittableStructType(typeDef, arrayDim) : new NativeDataStructType(typeDef, "StructMarshaller`1", arrayDim); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public static string GetWrapperClassName(this TypeReference typeRef) | ||||
|     { | ||||
|         return typeRef.Name + "Wrapper"; | ||||
|     } | ||||
|      | ||||
|     public static string GetMarshallerClassName(this TypeReference typeRef) | ||||
|     { | ||||
|         return typeRef.Name + "Marshaller"; | ||||
|     } | ||||
|      | ||||
|     public static PropertyType GetPrimitiveTypeCode(this TypeReference type) | ||||
|     { | ||||
|         // Is there a better way to do this? The private member e_type on TypeReference has what we want | ||||
|         return type.FullName switch | ||||
|         { | ||||
|             "System.Byte" => PropertyType.Byte, | ||||
|             "System.SByte" => PropertyType.Int8, | ||||
|             "System.Int16" => PropertyType.Int16, | ||||
|             "System.UInt16" => PropertyType.UInt16, | ||||
|             "System.Int32" => PropertyType.Int, | ||||
|             "System.UInt32" => PropertyType.UInt32, | ||||
|             "System.Int64" => PropertyType.Int64, | ||||
|             "System.UInt64" => PropertyType.UInt64, | ||||
|             "System.Float" => PropertyType.Float, | ||||
|             "System.Double" => PropertyType.Double, | ||||
|             _ => throw new NotImplementedException() | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     public static GenericInstanceType AddMarshalledStructInterface(this TypeDefinition typeDefinition) | ||||
|     { | ||||
|         var marshalledStructRef = WeaverImporter.Instance.CurrentWeavingAssembly.MainModule.ImportReference( | ||||
|             WeaverImporter.Instance.MarshalledStructReference); | ||||
|         var instancedInterface = marshalledStructRef.MakeGenericInstanceType(typeDefinition); | ||||
|         ArgumentNullException.ThrowIfNull(instancedInterface); | ||||
|  | ||||
|         if (typeDefinition.Interfaces.All(i => i.InterfaceType.FullName != instancedInterface.FullName)) | ||||
|         { | ||||
|             typeDefinition.Interfaces.Add(new InterfaceImplementation(instancedInterface)); | ||||
|         } | ||||
|          | ||||
|         return instancedInterface; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user