| @ -0,0 +1,113 @@ | ||||
| using System.Collections.Concurrent; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading.Tasks; | ||||
| using EpicGames.UHT.Types; | ||||
| using UnrealSharpScriptGenerator.PropertyTranslators; | ||||
| using UnrealSharpScriptGenerator.Utilities; | ||||
|  | ||||
| namespace UnrealSharpScriptGenerator.Exporters; | ||||
|  | ||||
| public static class AutocastExporter  | ||||
| { | ||||
|     private static readonly ConcurrentDictionary<UhtStruct, List<UhtFunction>> ExportedAutocasts = new(); | ||||
|      | ||||
|     public static void AddAutocastFunction(UhtStruct conversionStruct, UhtFunction function) | ||||
|     { | ||||
|         if (!ExportedAutocasts.TryGetValue(conversionStruct, out List<UhtFunction>? value)) | ||||
|         { | ||||
|             value = new List<UhtFunction>(); | ||||
|             ExportedAutocasts[conversionStruct] = value; | ||||
|         } | ||||
|  | ||||
|         value!.Add(function); | ||||
|     } | ||||
|      | ||||
|     public static void StartExportingAutocastFunctions(List<Task> tasks) | ||||
|     { | ||||
|         foreach (KeyValuePair<UhtStruct, List<UhtFunction>> pair in ExportedAutocasts) | ||||
|         { | ||||
|             tasks.Add(Program.Factory.CreateTask(_ =>  | ||||
|             { | ||||
|                 ExportAutocast(pair.Key, pair.Value); | ||||
|             })!); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     static void ExportAutocast(UhtStruct conversionStruct, List<UhtFunction> functions) | ||||
|     { | ||||
|         GeneratorStringBuilder stringBuilder = new(); | ||||
|         stringBuilder.GenerateTypeSkeleton(conversionStruct); | ||||
|         stringBuilder.DeclareType(conversionStruct, "struct", conversionStruct.GetStructName()); | ||||
|  | ||||
|         string conversionStructName = conversionStruct.GetFullManagedName(); | ||||
|         HashSet<UhtFunction> exportedFunctions = new(); | ||||
|          | ||||
|         foreach (UhtFunction function in functions) | ||||
|         { | ||||
|             string returnType = PropertyTranslatorManager.GetTranslator(function.ReturnProperty!)!.GetManagedType(function.ReturnProperty!); | ||||
|             string functionCall = $"{function.Outer!.GetFullManagedName()}.{function.GetFunctionName()}"; | ||||
|              | ||||
|             if (SharesSignature(function, exportedFunctions) || ReturnValueIsSameAsParameter(function)) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             stringBuilder.AppendLine($"public static implicit operator {returnType}({conversionStructName} value) => {functionCall}(value);"); | ||||
|             exportedFunctions.Add(function); | ||||
|         } | ||||
|  | ||||
|         stringBuilder.CloseBrace(); | ||||
|  | ||||
|         string directory = FileExporter.GetDirectoryPath(conversionStruct.Package); | ||||
|         string fileName = $"{conversionStruct.EngineName}.Autocast"; | ||||
|         FileExporter.SaveGlueToDisk(conversionStruct.Package, directory, fileName, stringBuilder.ToString()); | ||||
|     } | ||||
|      | ||||
|     static bool SharesSignature(UhtFunction function, IEnumerable<UhtFunction> otherFunctions) | ||||
|     { | ||||
|         foreach (UhtFunction otherFunction in otherFunctions) | ||||
|         { | ||||
|             if (function == otherFunction) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             bool sharesSignature = true; | ||||
|             int parameterCount = function.Children.Count; | ||||
|             for (int i = 0; i < parameterCount; i++) | ||||
|             { | ||||
|                 UhtProperty parameter = (UhtProperty) function.Children[i]; | ||||
|                 UhtProperty otherParameter = (UhtProperty) otherFunction.Children[i]; | ||||
|  | ||||
|                 if (parameter.IsSameType(otherParameter)) | ||||
|                 { | ||||
|                     continue; | ||||
|                 } | ||||
|                      | ||||
|                 sharesSignature = false; | ||||
|                 break; | ||||
|             } | ||||
|                  | ||||
|             if (sharesSignature) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|          | ||||
|     static bool ReturnValueIsSameAsParameter(UhtFunction function) | ||||
|     { | ||||
|         UhtProperty returnProperty = function.ReturnProperty!; | ||||
|         foreach (UhtType uhtType in function.Children) | ||||
|         { | ||||
|             UhtProperty parameter = (UhtProperty) uhtType; | ||||
|              | ||||
|             if (parameter != returnProperty && parameter.IsSameType(returnProperty)) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,199 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using EpicGames.Core; | ||||
| using EpicGames.UHT.Types; | ||||
| using UnrealSharpScriptGenerator.PropertyTranslators; | ||||
| using UnrealSharpScriptGenerator.Tooltip; | ||||
| using UnrealSharpScriptGenerator.Utilities; | ||||
|  | ||||
| namespace UnrealSharpScriptGenerator.Exporters; | ||||
|  | ||||
| public static class ClassExporter | ||||
| { | ||||
|     public static void ExportClass(UhtClass classObj, bool isManualExport) | ||||
|     { | ||||
|         GeneratorStringBuilder stringBuilder = new(); | ||||
|  | ||||
|         string typeNameSpace = classObj.GetNamespace(); | ||||
|          | ||||
|         List<UhtFunction> exportedFunctions = new(); | ||||
|         List<UhtFunction> exportedOverrides = new(); | ||||
|         Dictionary<string, GetterSetterPair> exportedGetterSetters = new(); | ||||
|         Dictionary<string, GetterSetterPair> getSetOverrides = new(); | ||||
|          | ||||
|         ScriptGeneratorUtilities.GetExportedFunctions(classObj, exportedFunctions,  | ||||
|             exportedOverrides,  | ||||
|             exportedGetterSetters, getSetOverrides); | ||||
|          | ||||
|         List<UhtProperty> exportedProperties = new List<UhtProperty>(); | ||||
|         Dictionary<UhtProperty, GetterSetterPair> getSetBackedProperties = new(); | ||||
|         ScriptGeneratorUtilities.GetExportedProperties(classObj, exportedProperties, getSetBackedProperties); | ||||
|          | ||||
|         List<UhtClass> interfaces = classObj.GetInterfaces(); | ||||
|          | ||||
|         bool nullableEnabled = classObj.HasMetadata(UhtTypeUtilities.NullableEnable); | ||||
|         stringBuilder.GenerateTypeSkeleton(typeNameSpace, nullableEnabled: nullableEnabled); | ||||
|         stringBuilder.AppendTooltip(classObj); | ||||
|          | ||||
|         AttributeBuilder attributeBuilder = new AttributeBuilder(classObj); | ||||
|         if (classObj.ClassFlags.HasAnyFlags(EClassFlags.Abstract)) | ||||
|         { | ||||
|             attributeBuilder.AddArgument("ClassFlags.Abstract"); | ||||
|         } | ||||
|         attributeBuilder.AddGeneratedTypeAttribute(classObj); | ||||
|         attributeBuilder.Finish(); | ||||
|         stringBuilder.AppendLine(attributeBuilder.ToString()); | ||||
|  | ||||
|         string superClassName; | ||||
|         if (classObj.SuperClass != null) | ||||
|         { | ||||
|             superClassName = classObj.SuperClass.GetFullManagedName(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             superClassName = "UnrealSharp.Core.UnrealSharpObject"; | ||||
|         } | ||||
|          | ||||
|         stringBuilder.DeclareType(classObj, "class", classObj.GetStructName(), superClassName, nativeInterfaces: interfaces); | ||||
|          | ||||
|         // For manual exports we just want to generate attributes | ||||
|         if (!isManualExport) | ||||
|         {  | ||||
|             StaticConstructorUtilities.ExportStaticConstructor(stringBuilder, classObj,  | ||||
|                 exportedProperties,  | ||||
|                 exportedFunctions,  | ||||
|                 exportedGetterSetters, | ||||
|                 getSetBackedProperties, | ||||
|                 exportedOverrides); | ||||
|              | ||||
|             HashSet<string> exportedPropertyNames = new(); | ||||
|             HashSet<string> exportedFunctionNames = new(); | ||||
|             ExportClassProperties(stringBuilder, exportedProperties, exportedPropertyNames); | ||||
|             ExportGetSetProperties(stringBuilder, getSetBackedProperties, exportedPropertyNames, exportedFunctionNames); | ||||
|             ExportCustomProperties(stringBuilder, exportedGetterSetters, exportedPropertyNames, exportedFunctionNames); | ||||
|              | ||||
|             ExportClassFunctions(classObj, stringBuilder, exportedFunctions, exportedFunctionNames); | ||||
|             ExportGetSetOverrides(stringBuilder, getSetOverrides, exportedPropertyNames, exportedFunctionNames); | ||||
|             ExportOverrides(stringBuilder, exportedOverrides, exportedFunctionNames); | ||||
|             stringBuilder.AppendLine(); | ||||
|         } | ||||
|  | ||||
|         stringBuilder.CloseBrace(); | ||||
|          | ||||
|         FileExporter.SaveGlueToDisk(classObj, stringBuilder); | ||||
|     } | ||||
|  | ||||
|     static void ExportClassProperties(GeneratorStringBuilder generatorStringBuilder, List<UhtProperty> exportedProperties, HashSet<string> exportedPropertyNames) | ||||
|     { | ||||
|         foreach (UhtProperty property in exportedProperties) | ||||
|         { | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|             translator.ExportProperty(generatorStringBuilder, property); | ||||
|             exportedPropertyNames.Add(property.SourceName); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public static void ExportGetSetProperties(GeneratorStringBuilder builder,  | ||||
|                                               Dictionary<UhtProperty, GetterSetterPair> getSetBackedProperties,  | ||||
|                                               HashSet<string> exportedPropertyNames, | ||||
|                                               HashSet<string> exportedFunctionNames) | ||||
|     { | ||||
|         Dictionary<UhtFunction, FunctionExporter> exportedGetterSetters = new(); | ||||
|         foreach (KeyValuePair<UhtProperty, GetterSetterPair> pair in getSetBackedProperties) | ||||
|         { | ||||
|             UhtProperty property = pair.Key; | ||||
|             GetterSetterPair getterSetterPair = pair.Value; | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|             translator.ExportGetSetProperty(builder, getterSetterPair, property, exportedGetterSetters, exportedFunctionNames); | ||||
|              | ||||
|             exportedPropertyNames.Add(getterSetterPair.PropertyName); | ||||
|             foreach (UhtFunction function in getterSetterPair.Accessors) | ||||
|             { | ||||
|                 exportedFunctionNames.Add(function.SourceName); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static void ExportGetSetOverrides(GeneratorStringBuilder builder, Dictionary<string, GetterSetterPair> getSetBackedProperties,  | ||||
|                                               HashSet<string> exportedPropertyNames, HashSet<string> exportedFunctionNames) | ||||
|     { | ||||
|         foreach (KeyValuePair<string, GetterSetterPair> pair in getSetBackedProperties) | ||||
|         { | ||||
|             if (pair.Value.Property == null) | ||||
|             { | ||||
|                 throw new InvalidDataException($"Property '{pair.Value.PropertyName}' does not have a UProperty"); | ||||
|             } | ||||
|              | ||||
|             UhtFunction firstAccessor = pair.Value.Accessors.First(); | ||||
|             UhtProperty firstProperty = pair.Value.Property; | ||||
|             string propertyName = pair.Value.PropertyName; | ||||
|              | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(firstProperty)!; | ||||
|             builder.TryAddWithEditor(firstAccessor); | ||||
|             translator.ExportCustomProperty(builder, pair.Value, propertyName, firstProperty,  | ||||
|                 exportedPropertyNames.Contains(propertyName), exportedFunctionNames); | ||||
|             builder.TryEndWithEditor(firstAccessor); | ||||
|              | ||||
|             exportedPropertyNames.Add(propertyName); | ||||
|             foreach (UhtFunction function in pair.Value.Accessors) | ||||
|             { | ||||
|                 exportedFunctionNames.Add(function.SourceName); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     static void ExportOverrides(GeneratorStringBuilder builder, List<UhtFunction> exportedOverrides, HashSet<string> exportedFunctionNames) | ||||
|     { | ||||
|         foreach (UhtFunction function in exportedOverrides) | ||||
|         { | ||||
|             FunctionExporter.ExportOverridableFunction(builder, function, exportedFunctionNames); | ||||
|             exportedFunctionNames.Add(function.SourceName); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     static void ExportClassFunctions(UhtClass owner, GeneratorStringBuilder builder, List<UhtFunction> exportedFunctions, | ||||
|                                      HashSet<string> exportedFunctionNames) | ||||
|     { | ||||
|         bool isBlueprintFunctionLibrary = owner.IsChildOf(Program.BlueprintFunctionLibrary); | ||||
|         foreach (UhtFunction function in exportedFunctions) | ||||
|         { | ||||
|             if (function.HasAllFlags(EFunctionFlags.Static) && isBlueprintFunctionLibrary) | ||||
|             { | ||||
|                 FunctionExporter.TryAddExtensionMethod(function); | ||||
|             } | ||||
|              | ||||
|             FunctionExporter.ExportFunction(builder, function, FunctionType.Normal, exportedFunctionNames); | ||||
|             exportedFunctionNames.Add(function.SourceName); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void ExportCustomProperties(GeneratorStringBuilder builder,  | ||||
|                                               Dictionary<string, GetterSetterPair> exportedGetterSetters,  | ||||
|                                               HashSet<string> exportedPropertyNames, | ||||
|                                               HashSet<string> exportedFunctionNames) | ||||
|     { | ||||
|         foreach (KeyValuePair<string, GetterSetterPair> pair in exportedGetterSetters) | ||||
|         { | ||||
|             if (pair.Value.Property == null) | ||||
|             { | ||||
|                 throw new InvalidDataException($"Property '{pair.Value.PropertyName}' does not have a UProperty"); | ||||
|             } | ||||
|              | ||||
|             UhtFunction firstAccessor = pair.Value.Accessors.First(); | ||||
|             UhtProperty firstProperty = pair.Value.Property; | ||||
|             string propertyName = pair.Value.PropertyName; | ||||
|              | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(firstProperty)!; | ||||
|             builder.TryAddWithEditor(firstAccessor); | ||||
|             translator.ExportCustomProperty(builder, pair.Value, propertyName, firstProperty, exportedFunctionNames: exportedFunctionNames); | ||||
|             builder.TryEndWithEditor(firstAccessor); | ||||
|              | ||||
|             exportedPropertyNames.Add(propertyName); | ||||
|             foreach (UhtFunction function in pair.Value.Accessors) | ||||
|             { | ||||
|                 exportedFunctionNames.Add(function.SourceName); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,60 @@ | ||||
| using EpicGames.Core; | ||||
| using EpicGames.UHT.Types; | ||||
| using UnrealSharpScriptGenerator.PropertyTranslators; | ||||
| using UnrealSharpScriptGenerator.Utilities; | ||||
|  | ||||
| namespace UnrealSharpScriptGenerator.Exporters; | ||||
|  | ||||
| public static class DelegateExporter | ||||
| { | ||||
|     public static void ExportDelegate(UhtFunction function) | ||||
|     { | ||||
|         string delegateName = DelegateBasePropertyTranslator.GetDelegateName(function); | ||||
|         string delegateNamespace = function.GetNamespace(); | ||||
|          | ||||
|         GeneratorStringBuilder builder = new(); | ||||
|          | ||||
|         builder.GenerateTypeSkeleton(delegateNamespace); | ||||
|         builder.AppendLine(); | ||||
|          | ||||
|         string superClass; | ||||
|         if (function.HasAllFlags(EFunctionFlags.MulticastDelegate)) | ||||
|         { | ||||
|             superClass = $"MulticastDelegate<{delegateName}>"; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             superClass = $"Delegate<{delegateName}>"; | ||||
|         } | ||||
|          | ||||
|         FunctionExporter functionExporter = FunctionExporter.ExportDelegateSignature(builder, function, delegateName); | ||||
|          | ||||
|         builder.DeclareType(function, "class", $"U{delegateName}", superClass); | ||||
|          | ||||
|         FunctionExporter.ExportDelegateGlue(builder, functionExporter); | ||||
|          | ||||
|         builder.AppendLine("static public void InitializeUnrealDelegate(IntPtr nativeDelegateProperty)"); | ||||
|         builder.OpenBrace(); | ||||
|         ExportDelegateFunctionStaticConstruction(builder, function); | ||||
|         builder.CloseBrace(); | ||||
|         builder.CloseBrace(); | ||||
|          | ||||
|         FileExporter.SaveGlueToDisk(function, builder); | ||||
|     } | ||||
|  | ||||
|     private static void ExportDelegateFunctionStaticConstruction(GeneratorStringBuilder builder, UhtFunction function) | ||||
|     { | ||||
|         string delegateName = function.SourceName; | ||||
|         builder.AppendLine($"{delegateName}_NativeFunction = FMulticastDelegatePropertyExporter.CallGetSignatureFunction(nativeDelegateProperty);"); | ||||
|         if (function.HasParameters) | ||||
|         { | ||||
|             builder.AppendLine($"{delegateName}_ParamsSize = {ExporterCallbacks.UFunctionCallbacks}.CallGetNativeFunctionParamsSize({delegateName}_NativeFunction);"); | ||||
|         } | ||||
|          | ||||
|         foreach (UhtProperty parameter in function.Properties) | ||||
|         { | ||||
|             PropertyTranslator propertyTranslator = PropertyTranslatorManager.GetTranslator(parameter)!; | ||||
|             propertyTranslator.ExportParameterStaticConstructor(builder, parameter, function, parameter.SourceName, delegateName); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,64 @@ | ||||
| using System; | ||||
| using EpicGames.UHT.Types; | ||||
| using UnrealSharpScriptGenerator.Tooltip; | ||||
| using UnrealSharpScriptGenerator.Utilities; | ||||
|  | ||||
| namespace UnrealSharpScriptGenerator.Exporters; | ||||
|  | ||||
| public static class EnumExporter | ||||
| { | ||||
|     public static void ExportEnum(UhtEnum enumObj) | ||||
|     { | ||||
|         GeneratorStringBuilder stringBuilder = new GeneratorStringBuilder(); | ||||
|          | ||||
|         string moduleName = enumObj.GetNamespace(); | ||||
|          | ||||
|         stringBuilder.GenerateTypeSkeleton(moduleName); | ||||
|         stringBuilder.AppendTooltip(enumObj); | ||||
|          | ||||
|         AttributeBuilder attributeBuilder = new AttributeBuilder(enumObj); | ||||
|         attributeBuilder.AddGeneratedTypeAttribute(enumObj); | ||||
|         attributeBuilder.Finish(); | ||||
|          | ||||
|         stringBuilder.AppendLine(attributeBuilder.ToString()); | ||||
|          | ||||
|         string underlyingType = UnderlyingTypeToString(enumObj.UnderlyingType); | ||||
|         stringBuilder.DeclareType(enumObj, "enum", enumObj.GetStructName(), underlyingType, isPartial: false); | ||||
|          | ||||
|         int enumValuesCount = enumObj.EnumValues.Count; | ||||
|         for (int i = 0; i < enumValuesCount; i++) | ||||
|         { | ||||
|             UhtEnumValue enumValue = enumObj.EnumValues[i]; | ||||
|  | ||||
|             string toolTip = enumObj.GetMetadata("Tooltip", i); | ||||
|             stringBuilder.AppendTooltip(toolTip); | ||||
|              | ||||
|             string cleanValueName = ScriptGeneratorUtilities.GetCleanEnumValueName(enumObj, enumValue); | ||||
|             string value = enumValue.Value == -1 ? "," : $" = {enumValue.Value},"; | ||||
|              | ||||
|             stringBuilder.AppendLine($"{cleanValueName}{value}"); | ||||
|         } | ||||
|          | ||||
|         stringBuilder.CloseBrace(); | ||||
|         FileExporter.SaveGlueToDisk(enumObj, stringBuilder); | ||||
|     } | ||||
|      | ||||
|     public static string UnderlyingTypeToString(UhtEnumUnderlyingType underlyingType) | ||||
|     { | ||||
|         return underlyingType switch | ||||
|         { | ||||
|             UhtEnumUnderlyingType.Unspecified => "", | ||||
|             UhtEnumUnderlyingType.Uint8 => "byte", | ||||
|             UhtEnumUnderlyingType.Int8 => "sbyte", | ||||
|             UhtEnumUnderlyingType.Int16 => "short", | ||||
|             UhtEnumUnderlyingType.Int => "int", | ||||
|             UhtEnumUnderlyingType.Int32 => "int", | ||||
|             UhtEnumUnderlyingType.Int64 => "long", | ||||
|             UhtEnumUnderlyingType.Uint16 => "ushort", | ||||
|             UhtEnumUnderlyingType.Uint32 => "uint", | ||||
|             UhtEnumUnderlyingType.Uint64 => "ulong", | ||||
|             _ => throw new ArgumentOutOfRangeException(nameof(underlyingType), underlyingType, null) | ||||
|         }; | ||||
|          | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,56 @@ | ||||
| using System.Collections.Generic; | ||||
| using EpicGames.UHT.Types; | ||||
| using UnrealSharpScriptGenerator.Utilities; | ||||
|  | ||||
| namespace UnrealSharpScriptGenerator.Exporters; | ||||
|  | ||||
| public static class ExtensionsClassExporter | ||||
| { | ||||
|     public static void ExportExtensionsClass(UhtPackage package, List<ExtensionMethod> extensionMethods) | ||||
|     { | ||||
|         Dictionary<UhtType, List<ExtensionMethod>?> libraryToExtensionMethod = new(); | ||||
|          | ||||
|         foreach (ExtensionMethod extensionMethod in extensionMethods) | ||||
|         { | ||||
|             UhtType outerClass = extensionMethod.Function.Outer!; | ||||
|              | ||||
|             if (!libraryToExtensionMethod.TryGetValue(outerClass, out List<ExtensionMethod>? libraryExtensions)) | ||||
|             { | ||||
|                 libraryExtensions = new List<ExtensionMethod>(); | ||||
|                 libraryToExtensionMethod[outerClass] = libraryExtensions; | ||||
|             } | ||||
|              | ||||
|             libraryExtensions!.Add(extensionMethod); | ||||
|         } | ||||
|          | ||||
|         foreach (KeyValuePair<UhtType, List<ExtensionMethod>?> pair in libraryToExtensionMethod) | ||||
|         { | ||||
|             UhtType libraryClass = pair.Key; | ||||
|             List<ExtensionMethod>? libraryExtensions = pair.Value; | ||||
|             ExportLibrary(package, libraryClass, libraryExtensions!); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void ExportLibrary(UhtPackage package, UhtType libraryClass, List<ExtensionMethod> extensionMethods) | ||||
|     { | ||||
|         string typeNamespace = package.GetNamespace(); | ||||
|         string className = $"{libraryClass.EngineName}_Extensions"; | ||||
|          | ||||
|         GeneratorStringBuilder stringBuilder = new(); | ||||
|         stringBuilder.GenerateTypeSkeleton(typeNamespace); | ||||
|         stringBuilder.DeclareType(package, "static class", className, null, false); | ||||
|          | ||||
|         foreach (ExtensionMethod extensionMethod in extensionMethods) | ||||
|         { | ||||
|             FunctionExporter exporter = new FunctionExporter(extensionMethod); | ||||
|             exporter.Initialize(OverloadMode.AllowOverloads, EFunctionProtectionMode.UseUFunctionProtection, EBlueprintVisibility.Call); | ||||
|             exporter.ExportExtensionMethodOverloads(stringBuilder); | ||||
|             exporter.ExportExtensionMethod(stringBuilder); | ||||
|         } | ||||
|          | ||||
|         stringBuilder.CloseBrace(); | ||||
|          | ||||
|         string directory = FileExporter.GetDirectoryPath(package); | ||||
|         FileExporter.SaveGlueToDisk(package, directory, className, stringBuilder.ToString()); | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,73 @@ | ||||
| using EpicGames.Core; | ||||
| using EpicGames.UHT.Types; | ||||
| using UnrealSharpScriptGenerator.PropertyTranslators; | ||||
| using UnrealSharpScriptGenerator.Utilities; | ||||
|  | ||||
| namespace UnrealSharpScriptGenerator.Exporters; | ||||
|  | ||||
| public enum GetterSetterMode | ||||
| { | ||||
|     Get, | ||||
|     Set | ||||
| } | ||||
|  | ||||
| public class GetterSetterFunctionExporter : FunctionExporter | ||||
| { | ||||
|     private readonly UhtProperty _propertyGetterSetter; | ||||
|     private readonly GetterSetterMode _getterSetterMode; | ||||
|     private string _outParameterName; | ||||
|      | ||||
|     public static GetterSetterFunctionExporter Create(UhtFunction function,  | ||||
|         UhtProperty propertyGetterSetter,  | ||||
|         GetterSetterMode getterSetterMode,  | ||||
|         EFunctionProtectionMode protectionMode) | ||||
|     { | ||||
|         GetterSetterFunctionExporter exporter = new GetterSetterFunctionExporter(function, propertyGetterSetter, getterSetterMode); | ||||
|         exporter.Initialize(OverloadMode.SuppressOverloads, protectionMode, EBlueprintVisibility.GetterSetter); | ||||
|         return exporter; | ||||
|     } | ||||
|      | ||||
|     private GetterSetterFunctionExporter(UhtFunction function, UhtProperty propertyGetterSetter, GetterSetterMode getterSetterMode) : base(function) | ||||
|     { | ||||
|         _outParameterName = string.Empty; | ||||
|         _propertyGetterSetter = propertyGetterSetter; | ||||
|         _getterSetterMode = getterSetterMode; | ||||
|          | ||||
|         Initialize(OverloadMode.SuppressOverloads, EFunctionProtectionMode.OverrideWithInternal, EBlueprintVisibility.GetterSetter); | ||||
|     } | ||||
|  | ||||
|     protected override string GetParameterName(UhtProperty parameter) | ||||
|     { | ||||
|         return _getterSetterMode == GetterSetterMode.Get ? _propertyGetterSetter.GetParameterName() : "value"; | ||||
|     } | ||||
|  | ||||
|     protected override string MakeOutMarshalDestination(UhtProperty parameter, PropertyTranslator propertyTranslator, GeneratorStringBuilder builder) | ||||
|     { | ||||
|         _outParameterName = GetParameterName(parameter) + "_Out"; | ||||
|         builder.AppendLine($"{propertyTranslator.GetManagedType(parameter)} {_outParameterName};"); | ||||
|         return _outParameterName; | ||||
|     } | ||||
|  | ||||
|     protected override void ExportReturnStatement(GeneratorStringBuilder builder) | ||||
|     { | ||||
|         if (Function.ReturnProperty != null && Function.ReturnProperty.IsSameType(_propertyGetterSetter)) | ||||
|         { | ||||
|             string castOperation = _propertyGetterSetter.HasAllFlags(EPropertyFlags.BlueprintReadOnly)  | ||||
|                 ? $"({ReturnValueTranslator!.GetManagedType(_propertyGetterSetter)})" : string.Empty; | ||||
|             builder.AppendLine($"return {castOperation}returnValue;"); | ||||
|         } | ||||
|         else if (Function.ReturnProperty != null) | ||||
|         { | ||||
|             // Types differ (e.g., getter returns FText, property bound as string). Still return and rely on | ||||
|             // available implicit/user-defined conversions on the managed types (FText -> string, etc.). | ||||
|             builder.AppendLine("return returnValue;"); | ||||
|         } | ||||
|          | ||||
|         if (string.IsNullOrEmpty(_outParameterName)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|          | ||||
|         builder.AppendLine($"return {_outParameterName};"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,173 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using EpicGames.Core; | ||||
| using EpicGames.UHT.Types; | ||||
| using UnrealSharpScriptGenerator.PropertyTranslators; | ||||
| using UnrealSharpScriptGenerator.Tooltip; | ||||
| using UnrealSharpScriptGenerator.Utilities; | ||||
|  | ||||
| namespace UnrealSharpScriptGenerator.Exporters; | ||||
|  | ||||
| public static class InterfaceExporter | ||||
| { | ||||
|     public static void ExportInterface(UhtClass interfaceObj) | ||||
|     { | ||||
|         GeneratorStringBuilder stringBuilder = new(); | ||||
|          | ||||
|         bool nullableEnabled = interfaceObj.HasMetadata(UhtTypeUtilities.NullableEnable); | ||||
|         string interfaceName = interfaceObj.GetStructName(); | ||||
|         string typeNamespace = interfaceObj.GetNamespace(); | ||||
|          | ||||
|         stringBuilder.GenerateTypeSkeleton(typeNamespace, nullableEnabled: nullableEnabled); | ||||
|         stringBuilder.AppendTooltip(interfaceObj); | ||||
|          | ||||
|         AttributeBuilder attributeBuilder = new AttributeBuilder(interfaceObj); | ||||
|         attributeBuilder.AddGeneratedTypeAttribute(interfaceObj); | ||||
|         attributeBuilder.Finish(); | ||||
|          | ||||
|         stringBuilder.AppendLine(attributeBuilder.ToString()); | ||||
|         stringBuilder.DeclareType(interfaceObj, "interface", interfaceName); | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"static {interfaceName} Wrap(UnrealSharp.CoreUObject.UObject obj)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"return new {interfaceName}Wrapper(obj);"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|          | ||||
|         List<UhtFunction> exportedFunctions = new(); | ||||
|         List<UhtFunction> exportedOverrides = new(); | ||||
|         Dictionary<string, GetterSetterPair> exportedGetterSetters = new(); | ||||
|         Dictionary<string, GetterSetterPair> getSetOverrides = new(); | ||||
|  | ||||
|         if (interfaceObj.AlternateObject is UhtClass alternateObject) | ||||
|         { | ||||
|             ScriptGeneratorUtilities.GetExportedFunctions(alternateObject, exportedFunctions, exportedOverrides, exportedGetterSetters, getSetOverrides); | ||||
|         } | ||||
|          | ||||
|         ScriptGeneratorUtilities.GetExportedFunctions(interfaceObj, exportedFunctions, exportedOverrides, exportedGetterSetters, getSetOverrides); | ||||
|          | ||||
|         ExportInterfaceProperties(stringBuilder, exportedGetterSetters); | ||||
|         ExportInterfaceFunctions(stringBuilder, exportedFunctions); | ||||
|         ExportInterfaceFunctions(stringBuilder, exportedOverrides); | ||||
|          | ||||
|         stringBuilder.CloseBrace(); | ||||
|          | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"internal sealed class {interfaceName}Wrapper : {interfaceName}, UnrealSharp.CoreUObject.IScriptInterface"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine("public UnrealSharp.CoreUObject.UObject Object { get; }"); | ||||
|         stringBuilder.AppendLine("private IntPtr NativeObject => Object.NativeObject;"); | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"internal {interfaceName}Wrapper(UnrealSharp.CoreUObject.UObject obj)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine("Object = obj;"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|  | ||||
|         StaticConstructorUtilities.ExportStaticConstructor(stringBuilder, interfaceObj, | ||||
|             new List<UhtProperty>(), | ||||
|             exportedFunctions, | ||||
|             exportedGetterSetters, | ||||
|             new Dictionary<UhtProperty, GetterSetterPair>(), | ||||
|             exportedOverrides,  | ||||
|             false, interfaceName + "Wrapper"); | ||||
|          | ||||
|         ClassExporter.ExportCustomProperties(stringBuilder, exportedGetterSetters, [], []); | ||||
|         ExportWrapperFunctions(stringBuilder, exportedFunctions); | ||||
|         ExportWrapperFunctions(stringBuilder, exportedOverrides); | ||||
|          | ||||
|         stringBuilder.CloseBrace(); | ||||
|          | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public static class {interfaceName}Marshaller"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"public static void ToNative(IntPtr nativeBuffer, int arrayIndex, {interfaceName} obj)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"UnrealSharp.CoreUObject.ScriptInterfaceMarshaller<{interfaceName}>.ToNative(nativeBuffer, arrayIndex, obj);"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|         stringBuilder.AppendLine(); | ||||
|  | ||||
|         stringBuilder.AppendLine($"public static {interfaceName} FromNative(IntPtr nativeBuffer, int arrayIndex)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"return UnrealSharp.CoreUObject.ScriptInterfaceMarshaller<{interfaceName}>.FromNative(nativeBuffer, arrayIndex);"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|         stringBuilder.CloseBrace(); | ||||
|          | ||||
|         FileExporter.SaveGlueToDisk(interfaceObj, stringBuilder); | ||||
|     } | ||||
|  | ||||
|     static void ExportInterfaceProperties(GeneratorStringBuilder stringBuilder, | ||||
|                                           Dictionary<string, GetterSetterPair> exportedGetterSetters) | ||||
|     { | ||||
|         foreach (var (_, getterSetterPair) in exportedGetterSetters) | ||||
|         { | ||||
|             if (getterSetterPair.Property is null) | ||||
|             { | ||||
|                 throw new InvalidDataException("Properties should have a UProperty associated with them."); | ||||
|             } | ||||
|              | ||||
|             UhtFunction firstAccessor = getterSetterPair.Accessors.First(); | ||||
|             UhtProperty firstProperty = getterSetterPair.Property; | ||||
|             string propertyName = getterSetterPair.PropertyName; | ||||
|              | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(firstProperty)!; | ||||
|             stringBuilder.TryAddWithEditor(firstAccessor); | ||||
|             string protection = firstProperty.GetProtection(); | ||||
|             stringBuilder.AppendTooltip(firstProperty); | ||||
|          | ||||
|             string managedType = translator.GetManagedType(firstProperty); | ||||
|             stringBuilder.AppendLine($"{managedType} {propertyName}"); | ||||
|             stringBuilder.OpenBrace(); | ||||
|  | ||||
|             if (getterSetterPair.Getter is not null) | ||||
|             { | ||||
|                 AppendPropertyFunctionDeclaration(stringBuilder, getterSetterPair.Getter); | ||||
|                 stringBuilder.AppendLine("get;"); | ||||
|             } | ||||
|  | ||||
|             if (getterSetterPair.Setter is not null) | ||||
|             { | ||||
|                 AppendPropertyFunctionDeclaration(stringBuilder, getterSetterPair.Setter); | ||||
|                 stringBuilder.AppendLine("set;"); | ||||
|             } | ||||
|          | ||||
|             stringBuilder.CloseBrace(); | ||||
|             stringBuilder.TryEndWithEditor(firstAccessor); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static void AppendPropertyFunctionDeclaration(GeneratorStringBuilder stringBuilder, UhtFunction function) | ||||
|     { | ||||
|         AttributeBuilder attributeBuilder = new AttributeBuilder(function); | ||||
|          | ||||
|         if (function.FunctionFlags.HasAnyFlags(EFunctionFlags.BlueprintEvent)) | ||||
|         { | ||||
|             attributeBuilder.AddArgument("FunctionFlags.BlueprintEvent"); | ||||
|         } | ||||
|          | ||||
|         attributeBuilder.AddGeneratedTypeAttribute(function); | ||||
|         attributeBuilder.Finish(); | ||||
|          | ||||
|         stringBuilder.AppendLine(attributeBuilder.ToString()); | ||||
|     } | ||||
|      | ||||
|     static void ExportInterfaceFunctions(GeneratorStringBuilder stringBuilder, List<UhtFunction> exportedFunctions) | ||||
|     { | ||||
|         foreach (UhtFunction function in exportedFunctions) | ||||
|         { | ||||
|             FunctionExporter.ExportInterfaceFunction(stringBuilder, function); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     static void ExportWrapperFunctions(GeneratorStringBuilder stringBuilder, List<UhtFunction> exportedFunctions) | ||||
|     { | ||||
|         foreach (UhtFunction function in exportedFunctions) | ||||
|         { | ||||
|             FunctionType functionType = function.FunctionFlags.HasFlag(EFunctionFlags.BlueprintEvent)  | ||||
|                 ? FunctionType.BlueprintEvent  | ||||
|                 : FunctionType.Normal; | ||||
|              | ||||
|             FunctionExporter.ExportFunction(stringBuilder, function, functionType); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,167 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using EpicGames.Core; | ||||
| using EpicGames.UHT.Parsers; | ||||
| using EpicGames.UHT.Tables; | ||||
| using EpicGames.UHT.Tokenizer; | ||||
| using EpicGames.UHT.Types; | ||||
| using EpicGames.UHT.Utils; | ||||
| using UnrealSharpScriptGenerator.Utilities; | ||||
|  | ||||
| namespace UnrealSharpScriptGenerator.Exporters; | ||||
|  | ||||
| [UnrealHeaderTool] | ||||
| public static class NativeBindExporter | ||||
| { | ||||
|     private struct NativeBindMethod | ||||
|     { | ||||
|         public readonly string MethodName; | ||||
|      | ||||
|         public NativeBindMethod(string methodName) | ||||
|         { | ||||
|             MethodName = methodName; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private class NativeBindTypeInfo | ||||
|     { | ||||
|         public readonly UhtType Type; | ||||
|         public readonly List<NativeBindMethod> Methods; | ||||
|  | ||||
|         public NativeBindTypeInfo(UhtType type, List<NativeBindMethod> methods) | ||||
|         { | ||||
|             Type = type; | ||||
|             Methods = methods; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static readonly Dictionary<UhtHeaderFile, List<NativeBindTypeInfo>> NativeBindTypes = new(); | ||||
|  | ||||
|     [UhtExporter(Name = "UnrealSharpNativeGlue",  | ||||
|         Description = "Exports Native Glue",  | ||||
|         Options = UhtExporterOptions.Default,  | ||||
|         ModuleName = "UnrealSharpCore", CppFilters = new string [] { "*.unrealsharp.gen.cpp" })] | ||||
|     private static void Main(IUhtExportFactory factory) | ||||
|     { | ||||
|         ExportBindMethods(factory); | ||||
|     } | ||||
|      | ||||
|     [UhtKeyword(Extends = UhtTableNames.Default, Keyword = "UNREALSHARP_FUNCTION")] | ||||
|     private static UhtParseResult UNREALSHARP_FUNCTIONKeyword(UhtParsingScope topScope, UhtParsingScope actionScope, ref UhtToken token) | ||||
|     { | ||||
|         return ParseUnrealSharpBind(topScope, actionScope, ref token); | ||||
|     } | ||||
|      | ||||
|     [UhtSpecifier(Extends = UhtTableNames.Function, ValueType = UhtSpecifierValueType.Legacy)] | ||||
|     private static void ScriptCallableSpecifier(UhtSpecifierContext specifierContext) | ||||
|     { | ||||
|         UhtFunction function = (UhtFunction)specifierContext.Type; | ||||
|         function.MetaData.Add("ScriptCallable", ""); | ||||
|     } | ||||
|      | ||||
|     private static UhtParseResult ParseUnrealSharpBind(UhtParsingScope topScope, UhtParsingScope actionScope, ref UhtToken token) | ||||
|     { | ||||
|         UhtHeaderFile headerFile = topScope.ScopeType.HeaderFile; | ||||
|  | ||||
|         topScope.TokenReader.EnableRecording(); | ||||
|         topScope.TokenReader | ||||
|             .Require('(') | ||||
|             .Require(')') | ||||
|             .Require("static") | ||||
|             .ConsumeUntil('('); | ||||
|  | ||||
|         int recordedTokensCount = topScope.TokenReader.RecordedTokens.Count; | ||||
|         string methodName = topScope.TokenReader.RecordedTokens[recordedTokensCount - 2].Value.ToString(); | ||||
|         topScope.TokenReader.DisableRecording(); | ||||
|          | ||||
|         NativeBindMethod methodInfo = new(methodName); | ||||
|          | ||||
|         if (!NativeBindTypes.TryGetValue(headerFile, out List<NativeBindTypeInfo>? value)) | ||||
|         { | ||||
|             value = new List<NativeBindTypeInfo>(); | ||||
|             NativeBindTypes.Add(headerFile, value); | ||||
|         } | ||||
|  | ||||
|         UhtType type = topScope.ScopeType; | ||||
|          | ||||
|         NativeBindTypeInfo? nativeBindTypeInfo = null; | ||||
|         foreach (NativeBindTypeInfo bindTypeInfo in value) | ||||
|         { | ||||
|             if (bindTypeInfo.Type != type) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|              | ||||
|             nativeBindTypeInfo = bindTypeInfo; | ||||
|             break; | ||||
|         } | ||||
|          | ||||
|         if (nativeBindTypeInfo == null) | ||||
|         { | ||||
|             nativeBindTypeInfo = new NativeBindTypeInfo(type, new List<NativeBindMethod>()); | ||||
|             value.Add(nativeBindTypeInfo); | ||||
|         } | ||||
|          | ||||
|         nativeBindTypeInfo.Methods.Add(methodInfo); | ||||
|          | ||||
|         return UhtParseResult.Handled; | ||||
|     } | ||||
|      | ||||
|     public static void ExportBindMethods(IUhtExportFactory factory) | ||||
|     { | ||||
|         foreach (KeyValuePair<UhtHeaderFile, List<NativeBindTypeInfo>> bindMethod in NativeBindTypes) | ||||
|         { | ||||
|             UhtHeaderFile headerFile = bindMethod.Key; | ||||
|             List<NativeBindTypeInfo> containingTypesInHeader = bindMethod.Value; | ||||
|              | ||||
|             GeneratorStringBuilder builder = new(); | ||||
|             builder.AppendLine("#include \"UnrealSharpBinds.h\""); | ||||
|             builder.AppendLine($"#include \"{headerFile.FilePath}\""); | ||||
|             builder.AppendLine(); | ||||
|              | ||||
|             foreach (NativeBindTypeInfo containingType in containingTypesInHeader) | ||||
|             { | ||||
|                 UhtType topType = containingType.Type; | ||||
|                 List<NativeBindMethod> methods = containingType.Methods; | ||||
|                  | ||||
|                 string typeName = $"Z_Construct_U{topType.EngineClassName}_UnrealSharp_Binds_" + topType.SourceName; | ||||
|                 builder.Append($"struct {typeName}"); | ||||
|              | ||||
|                 builder.OpenBrace(); | ||||
|              | ||||
|                 foreach (NativeBindMethod method in methods) | ||||
|                 { | ||||
|                     builder.AppendLine($"static const FCSExportedFunction UnrealSharpBind_{method.MethodName};"); | ||||
|                 } | ||||
|              | ||||
|                 builder.CloseBrace(); | ||||
|                 builder.Append(";"); | ||||
|              | ||||
|                 foreach (NativeBindMethod method in methods) | ||||
|                 { | ||||
|                     string functionReference = $"{topType.SourceName}::{method.MethodName}"; | ||||
|                     builder.AppendLine($"const FCSExportedFunction {typeName}::UnrealSharpBind_{method.MethodName}"); | ||||
|                     builder.Append($" = FCSExportedFunction(\"{topType.EngineName}\", \"{method.MethodName}\", (void*)&{functionReference}, GetFunctionSize({functionReference}));"); | ||||
|                 } | ||||
|                  | ||||
|                 builder.AppendLine(); | ||||
|                 builder.AppendLine(); | ||||
|             } | ||||
|  | ||||
|             UHTManifest.Module manifestModule; | ||||
|             #if UE_5_5_OR_LATER | ||||
|             manifestModule = headerFile.Module.Module; | ||||
|             #else | ||||
|             manifestModule= headerFile.Package.GetModule(); | ||||
|             #endif | ||||
|              | ||||
|             string outputDirectory = manifestModule.OutputDirectory; | ||||
|             string fileName = headerFile.FileNameWithoutExtension + ".unrealsharp.gen.cpp"; | ||||
|             string filePath = Path.Combine(outputDirectory, fileName); | ||||
|              | ||||
|             factory.CommitOutput(filePath, builder.ToString()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,541 @@ | ||||
| using EpicGames.UHT.Types; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using UnrealSharpScriptGenerator.PropertyTranslators; | ||||
| using UnrealSharpScriptGenerator.Tooltip; | ||||
| using UnrealSharpScriptGenerator.Utilities; | ||||
|  | ||||
| namespace UnrealSharpScriptGenerator.Exporters; | ||||
|  | ||||
| public static class StructExporter | ||||
| { | ||||
|     public static void ExportStruct(UhtScriptStruct structObj, bool isManualExport) | ||||
|     { | ||||
|         GeneratorStringBuilder stringBuilder = new(); | ||||
|         List<UhtProperty> exportedProperties = new(); | ||||
|         Dictionary<UhtProperty, GetterSetterPair> getSetBackedProperties = new(); | ||||
|         List<UhtStruct> inheritanceHierarchy = new(); | ||||
|         UhtStruct? currentStruct = structObj; | ||||
|         while (currentStruct is not null) | ||||
|         { | ||||
|             inheritanceHierarchy.Add(currentStruct); | ||||
|             currentStruct = currentStruct.SuperStruct; | ||||
|         } | ||||
|  | ||||
|         inheritanceHierarchy.Reverse(); | ||||
|         foreach (UhtStruct inheritance in inheritanceHierarchy) | ||||
|         { | ||||
|             ScriptGeneratorUtilities.GetExportedProperties(inheritance, exportedProperties, getSetBackedProperties); | ||||
|         } | ||||
|          | ||||
|         // Check there are not properties with the same name, remove otherwise | ||||
|         List<string> propertyNames = new(); | ||||
|         for (int i = 0; i < exportedProperties.Count; i++) | ||||
|         { | ||||
|             UhtProperty property = exportedProperties[i]; | ||||
|             string scriptName = property.GetParameterName(); | ||||
|             if (propertyNames.Contains(scriptName)) | ||||
|             { | ||||
|                 exportedProperties.RemoveAt(i); | ||||
|                 i--; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 propertyNames.Add(scriptName); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         bool nullableEnabled = structObj.HasMetadata(UhtTypeUtilities.NullableEnable); | ||||
|         bool isRecordStruct = structObj.HasMetadata("RecordStruct"); | ||||
|         bool isReadOnly = structObj.HasMetadata("ReadOnly"); | ||||
|         bool useProperties = structObj.HasMetadata("UseProperties"); | ||||
|         bool isBlittable = structObj.IsStructBlittable(); | ||||
|         bool isCopyable = structObj.IsStructNativelyCopyable(); | ||||
|         bool isDestructible = structObj.IsStructNativelyDestructible(); | ||||
|         bool isEquatable = structObj.IsStructEquatable(exportedProperties); | ||||
|  | ||||
|         string typeNameSpace = structObj.GetNamespace(); | ||||
|         stringBuilder.GenerateTypeSkeleton(typeNameSpace, isBlittable, nullableEnabled); | ||||
|                  | ||||
|         stringBuilder.AppendTooltip(structObj); | ||||
|          | ||||
|         AttributeBuilder attributeBuilder = new AttributeBuilder(structObj); | ||||
|         if (isBlittable) | ||||
|         { | ||||
|             attributeBuilder.AddIsBlittableAttribute(); | ||||
|             attributeBuilder.AddStructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential); | ||||
|         } | ||||
|         attributeBuilder.AddGeneratedTypeAttribute(structObj); | ||||
|         attributeBuilder.Finish(); | ||||
|         stringBuilder.AppendLine(attributeBuilder.ToString()); | ||||
|  | ||||
|         string structName = structObj.GetStructName(); | ||||
|         List<string>? csInterfaces = null; | ||||
|  | ||||
|         if (isBlittable || !isManualExport)  | ||||
|         {  | ||||
|             csInterfaces = new List<string> { $"MarshalledStruct<{structName}>" }; | ||||
|              | ||||
|             if (isDestructible)  | ||||
|             { | ||||
|                 csInterfaces.Add("IDisposable"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (isEquatable) | ||||
|         { | ||||
|             // If null create the list and add the interface | ||||
|             (csInterfaces ??= new()).Add($"IEquatable<{structName}>"); | ||||
|         } | ||||
|  | ||||
|         stringBuilder.DeclareType(structObj, isRecordStruct ? "record struct" : "struct", structName, csInterfaces: csInterfaces,  | ||||
|             modifiers: isReadOnly ? " readonly" : null); | ||||
|  | ||||
|         if (isCopyable) | ||||
|         { | ||||
|             stringBuilder.AppendLine(isDestructible | ||||
|                 ? "private NativeStructHandle NativeHandle;" | ||||
|                 : "private byte[] Allocation;"); | ||||
|         } | ||||
|          | ||||
|         // For manual exports we just want to generate attributes | ||||
|         if (!isManualExport) | ||||
|         { | ||||
|             List<string> reservedNames = GetReservedNames(exportedProperties); | ||||
|  | ||||
|             ExportStructProperties(structObj, stringBuilder, exportedProperties, isBlittable, reservedNames, isReadOnly, useProperties); | ||||
|         } | ||||
|  | ||||
|         if (isBlittable) | ||||
|         { | ||||
|             StaticConstructorUtilities.ExportStaticConstructor(stringBuilder, structObj,  | ||||
|                 new List<UhtProperty>(),  | ||||
|                 new List<UhtFunction>(), | ||||
|                 new Dictionary<string, GetterSetterPair>(), | ||||
|                 new Dictionary<UhtProperty, GetterSetterPair>(), | ||||
|                 new List<UhtFunction>(),  | ||||
|                 true); | ||||
|             stringBuilder.AppendLine(); | ||||
|             stringBuilder.AppendLine($"public static {structName} FromNative(IntPtr buffer) => BlittableMarshaller<{structName}>.FromNative(buffer, 0);"); | ||||
|             stringBuilder.AppendLine(); | ||||
|             stringBuilder.AppendLine($"public void ToNative(IntPtr buffer) => BlittableMarshaller<{structName}>.ToNative(buffer, 0, this);"); | ||||
|         } | ||||
|         else if (!isManualExport) | ||||
|         { | ||||
|             stringBuilder.AppendLine(); | ||||
|             StaticConstructorUtilities.ExportStaticConstructor(stringBuilder, structObj, exportedProperties,  | ||||
|                 new List<UhtFunction>(),  | ||||
|                 new Dictionary<string, GetterSetterPair>(),  | ||||
|                 new Dictionary<UhtProperty, GetterSetterPair>(), | ||||
|                 new List<UhtFunction>()); | ||||
|              | ||||
|             stringBuilder.AppendLine(); | ||||
|             ExportMirrorStructMarshalling(stringBuilder, structObj, exportedProperties); | ||||
|  | ||||
|             if (isDestructible)  | ||||
|             { | ||||
|                 stringBuilder.AppendLine(); | ||||
|                 stringBuilder.AppendLine("public void Dispose()"); | ||||
|                 stringBuilder.OpenBrace(); | ||||
|                 stringBuilder.AppendLine("NativeHandle?.Dispose();"); | ||||
|                 stringBuilder.CloseBrace(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (isEquatable) | ||||
|         { | ||||
|             ExportStructEquality(structObj, structName, stringBuilder, exportedProperties); | ||||
|         } | ||||
|  | ||||
|         if (structObj.CanSupportArithmetic(exportedProperties)) | ||||
|         { | ||||
|             ExportStructArithmetic(structObj, structName, stringBuilder, exportedProperties); | ||||
|         } | ||||
|  | ||||
|         stringBuilder.CloseBrace(); | ||||
|  | ||||
|         if (!isBlittable && !isManualExport) | ||||
|         { | ||||
|             ExportStructMarshaller(stringBuilder, structObj); | ||||
|         } | ||||
|          | ||||
|          | ||||
|         FileExporter.SaveGlueToDisk(structObj, stringBuilder); | ||||
|     } | ||||
|  | ||||
|     public static void ExportStructEquality(UhtStruct structObj, string structName, GeneratorStringBuilder stringBuilder, List<UhtProperty> exportedProperties) | ||||
|     { | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public override bool Equals(object? obj)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"return obj is {structName} other && Equals(other);"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|          | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public bool Equals({structName} other)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         if (exportedProperties.Count == 0) | ||||
|         { | ||||
|             stringBuilder.AppendLine("return true;"); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             StringBuilder equalitySb = new StringBuilder(); | ||||
|             for (int i = 0; i < exportedProperties.Count; i++) | ||||
|             { | ||||
|                 UhtProperty property = exportedProperties[i]; | ||||
|                 string scriptName = property.GetPropertyName(); | ||||
|                 equalitySb.Append($"this.{scriptName} == other.{scriptName}"); | ||||
|                 if (i < exportedProperties.Count - 1) | ||||
|                 { | ||||
|                     equalitySb.Append(" && "); | ||||
|                 } | ||||
|             } | ||||
|             stringBuilder.AppendLine($"return {equalitySb};"); | ||||
|         } | ||||
|         stringBuilder.CloseBrace(); | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine("public override int GetHashCode()"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         if (exportedProperties.Count == 0) | ||||
|         { | ||||
|             stringBuilder.AppendLine("return 0;"); | ||||
|         } | ||||
|         // More accurate hashcode equality | ||||
|         else if (exportedProperties.Count <= 8) | ||||
|         { | ||||
|             StringBuilder hashSb = new StringBuilder(); | ||||
|             for (int i = 0; i < exportedProperties.Count; i++) | ||||
|             { | ||||
|                 UhtProperty property = exportedProperties[i]; | ||||
|                 string scriptName = property.GetPropertyName(); | ||||
|                 hashSb.Append($"{scriptName}"); | ||||
|                 if (i < exportedProperties.Count - 1) | ||||
|                 { | ||||
|                     hashSb.Append(", "); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             stringBuilder.AppendLine($"return HashCode.Combine({hashSb});"); | ||||
|         } | ||||
|         // Fallback to xor for more than 8 properties as HashCode.Combine only supports up to 8 parameters | ||||
|         else | ||||
|         { | ||||
|             StringBuilder hashSb = new StringBuilder(); | ||||
|             for (int i = 0; i < exportedProperties.Count; i++) | ||||
|             { | ||||
|                 UhtProperty property = exportedProperties[i]; | ||||
|                 string scriptName = property.GetPropertyName(); | ||||
|                 hashSb.Append($"{scriptName}.GetHashCode()"); | ||||
|                 if (i < exportedProperties.Count - 1) | ||||
|                 { | ||||
|                     hashSb.Append(" ^ "); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             stringBuilder.AppendLine($"return {hashSb};"); | ||||
|         } | ||||
|         stringBuilder.CloseBrace(); | ||||
|  | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public static bool operator ==({structName} left, {structName} right)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine("return left.Equals(right);"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|  | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public static bool operator !=({structName} left, {structName} right)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine("return !(left == right);"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|     } | ||||
|  | ||||
|     public static void ExportStructArithmetic(UhtStruct structObj, string structName, GeneratorStringBuilder stringBuilder, List<UhtProperty> exportedProperties) | ||||
|     { | ||||
|         // Addition operator | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public static {structName} operator +({structName} lhs, {structName} rhs)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"return new {structName}"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine(); | ||||
|         for (int i = 0; i < exportedProperties.Count; i++) | ||||
|         { | ||||
|             UhtProperty property = exportedProperties[i]; | ||||
|             string scriptName = property.GetPropertyName(); | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|  | ||||
|             translator.ExportPropertyArithmetic(stringBuilder, property, ArithmeticKind.Add); | ||||
|  | ||||
|             if (i < exportedProperties.Count - 1) | ||||
|             { | ||||
|                 stringBuilder.Append(", "); | ||||
|                 stringBuilder.AppendLine(); | ||||
|             } | ||||
|         } | ||||
|         stringBuilder.UnIndent(); | ||||
|         stringBuilder.AppendLine("};"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|  | ||||
|         // Subtraction operator | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public static {structName} operator -({structName} lhs, {structName} rhs)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"return new {structName}"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine(); | ||||
|         for (int i = 0; i < exportedProperties.Count; i++) | ||||
|         { | ||||
|             UhtProperty property = exportedProperties[i]; | ||||
|             string scriptName = property.GetPropertyName(); | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|  | ||||
|             translator.ExportPropertyArithmetic(stringBuilder, property, ArithmeticKind.Subtract); | ||||
|  | ||||
|             if (i < exportedProperties.Count - 1) | ||||
|             { | ||||
|                 stringBuilder.Append(", "); | ||||
|                 stringBuilder.AppendLine(); | ||||
|             } | ||||
|         } | ||||
|         stringBuilder.UnIndent(); | ||||
|         stringBuilder.AppendLine("};"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|  | ||||
|         // Multiplication operator | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public static {structName} operator *({structName} lhs, {structName} rhs)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"return new {structName}"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine(); | ||||
|         for (int i = 0; i < exportedProperties.Count; i++) | ||||
|         { | ||||
|             UhtProperty property = exportedProperties[i]; | ||||
|             string scriptName = property.GetPropertyName(); | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|  | ||||
|             translator.ExportPropertyArithmetic(stringBuilder, property, ArithmeticKind.Multiply); | ||||
|  | ||||
|             if (i < exportedProperties.Count - 1) | ||||
|             { | ||||
|                 stringBuilder.Append(", "); | ||||
|                 stringBuilder.AppendLine(); | ||||
|             } | ||||
|         } | ||||
|         stringBuilder.UnIndent(); | ||||
|         stringBuilder.AppendLine("};"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|  | ||||
|         // Division operator | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public static {structName} operator /({structName} lhs, {structName} rhs)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"return new {structName}"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine(); | ||||
|         for (int i = 0; i < exportedProperties.Count; i++) | ||||
|         { | ||||
|             UhtProperty property = exportedProperties[i]; | ||||
|             string scriptName = property.GetPropertyName(); | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|  | ||||
|             translator.ExportPropertyArithmetic(stringBuilder, property, ArithmeticKind.Divide); | ||||
|  | ||||
|             if (i < exportedProperties.Count - 1) | ||||
|             { | ||||
|                 stringBuilder.Append(", "); | ||||
|                 stringBuilder.AppendLine(); | ||||
|             } | ||||
|         } | ||||
|         stringBuilder.UnIndent(); | ||||
|         stringBuilder.AppendLine("};"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|  | ||||
|         // Modulo operator | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public static {structName} operator %({structName} lhs, {structName} rhs)"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine($"return new {structName}"); | ||||
|         stringBuilder.OpenBrace(); | ||||
|         stringBuilder.AppendLine(); | ||||
|         for (int i = 0; i < exportedProperties.Count; i++) | ||||
|         { | ||||
|             UhtProperty property = exportedProperties[i]; | ||||
|             string scriptName = property.GetPropertyName(); | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|  | ||||
|             translator.ExportPropertyArithmetic(stringBuilder, property, ArithmeticKind.Modulo); | ||||
|  | ||||
|             if (i < exportedProperties.Count - 1) | ||||
|             { | ||||
|                 stringBuilder.Append(", "); | ||||
|                 stringBuilder.AppendLine(); | ||||
|             } | ||||
|         } | ||||
|         stringBuilder.UnIndent(); | ||||
|         stringBuilder.AppendLine("};"); | ||||
|         stringBuilder.CloseBrace(); | ||||
|     } | ||||
| 	 | ||||
|     public static void ExportStructProperties(UhtStruct structObj, GeneratorStringBuilder stringBuilder, List<UhtProperty> exportedProperties, bool suppressOffsets, List<string> reservedNames, bool isReadOnly, bool useProperties) | ||||
|     { | ||||
|         foreach (UhtProperty property in exportedProperties) | ||||
|         { | ||||
|             PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|             translator.ExportMirrorProperty(structObj, stringBuilder, property, suppressOffsets, reservedNames, isReadOnly, useProperties); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public static List<string> GetReservedNames(List<UhtProperty> properties) | ||||
|     { | ||||
|         List<string> reservedNames = new(); | ||||
|         foreach (UhtProperty property in properties) | ||||
|         { | ||||
|             if (reservedNames.Contains(property.SourceName)) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|             reservedNames.Add(property.SourceName); | ||||
|         } | ||||
|         return reservedNames; | ||||
|     } | ||||
|  | ||||
|     public static void ExportStructMarshaller(GeneratorStringBuilder builder, UhtScriptStruct structObj) | ||||
|     { | ||||
|         string structName = structObj.GetStructName(); | ||||
|          | ||||
|         builder.AppendLine(); | ||||
|         builder.AppendLine($"public static class {structName}Marshaller"); | ||||
|         builder.OpenBrace(); | ||||
|          | ||||
|         builder.AppendLine($"public static {structName} FromNative(IntPtr nativeBuffer, int arrayIndex)"); | ||||
|         builder.OpenBrace(); | ||||
|         builder.AppendLine($"return new {structName}(nativeBuffer + (arrayIndex * GetNativeDataSize()));"); | ||||
|         builder.CloseBrace(); | ||||
|          | ||||
|         builder.AppendLine(); | ||||
|         builder.AppendLine($"public static void ToNative(IntPtr nativeBuffer, int arrayIndex, {structName} obj)"); | ||||
|         builder.OpenBrace(); | ||||
|         builder.AppendLine($"obj.ToNative(nativeBuffer + (arrayIndex * GetNativeDataSize()));"); | ||||
|         builder.CloseBrace(); | ||||
|  | ||||
|         builder.AppendLine(); | ||||
|         builder.AppendLine($"public static int GetNativeDataSize()"); | ||||
|         builder.OpenBrace(); | ||||
|         builder.AppendLine($"return {structName}.NativeDataSize;"); | ||||
|         builder.CloseBrace(); | ||||
|         builder.CloseBrace(); | ||||
|     } | ||||
|  | ||||
|     public static void ExportMirrorStructMarshalling(GeneratorStringBuilder builder, UhtScriptStruct structObj, List<UhtProperty> properties) | ||||
|     { | ||||
|         string structName = structObj.GetStructName(); | ||||
|         bool isCopyable = structObj.IsStructNativelyCopyable(); | ||||
|         bool isDestructible = structObj.IsStructNativelyDestructible(); | ||||
|         if (isCopyable) | ||||
|         { | ||||
|             builder.AppendLine(); | ||||
|             builder.AppendLine($"public {structName}()"); | ||||
|             builder.OpenBrace(); | ||||
|             builder.AppendLine(isDestructible | ||||
|                 ? "NativeHandle = new NativeStructHandle(NativeClassPtr);" | ||||
|                 : "Allocation = new byte[NativeDataSize];"); | ||||
|             builder.CloseBrace(); | ||||
|         } | ||||
|  | ||||
|         builder.AppendLine(); | ||||
|         builder.AppendLine("[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]"); | ||||
|         builder.AppendLine($"public {structName}(IntPtr InNativeStruct)"); | ||||
|         builder.OpenBrace(); | ||||
|         builder.BeginUnsafeBlock(); | ||||
|  | ||||
|         if (isCopyable) | ||||
|         { | ||||
|             if (isDestructible) | ||||
|             { | ||||
|                 builder.AppendLine("NativeHandle = new NativeStructHandle(NativeClassPtr);"); | ||||
|                 builder.AppendLine("fixed (NativeStructHandleData* StructDataPointer = &NativeHandle.Data)"); | ||||
|                 builder.OpenBrace(); | ||||
|                 builder.AppendLine($"IntPtr AllocationPointer = {ExporterCallbacks.UScriptStructCallbacks}.CallGetStructLocation(StructDataPointer, NativeClassPtr);"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 builder.AppendLine("Allocation = new byte[NativeDataSize];"); | ||||
|                 builder.AppendLine("fixed (byte* AllocationPointer = Allocation)"); | ||||
|                 builder.OpenBrace(); | ||||
|             } | ||||
|              | ||||
|             builder.AppendLine($"{ExporterCallbacks.UScriptStructCallbacks}.CallNativeCopy(NativeClassPtr, InNativeStruct, (nint) AllocationPointer);"); | ||||
|             builder.CloseBrace(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             foreach (UhtProperty property in properties) | ||||
|             { | ||||
|                 PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|                 string scriptName = property.GetPropertyName(); | ||||
|                 string assignmentOrReturn = $"{scriptName} ="; | ||||
|                 string offsetName = $"{property.SourceName}_Offset"; | ||||
|                 builder.TryAddWithEditor(property); | ||||
|                 translator.ExportFromNative(builder, property, property.SourceName, assignmentOrReturn, "InNativeStruct", offsetName, false, false); | ||||
|                 builder.TryEndWithEditor(property); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         builder.EndUnsafeBlock(); | ||||
|         builder.CloseBrace(); | ||||
|          | ||||
|         builder.AppendLine(); | ||||
|         builder.AppendLine($"public static {structName} FromNative(IntPtr buffer) => new {structName}(buffer);"); | ||||
|          | ||||
|         builder.AppendLine(); | ||||
|         builder.AppendLine("public void ToNative(IntPtr buffer)"); | ||||
|         builder.OpenBrace(); | ||||
|         builder.BeginUnsafeBlock(); | ||||
|          | ||||
|         if (structObj.IsStructNativelyCopyable()) | ||||
|         { | ||||
|             if (structObj.IsStructNativelyDestructible()) | ||||
|             { | ||||
|                 builder.AppendLine("if (NativeHandle is null)"); | ||||
|                 builder.OpenBrace(); | ||||
|                 builder.AppendLine("NativeHandle = new NativeStructHandle(NativeClassPtr);"); | ||||
|                 builder.CloseBrace(); | ||||
|                 builder.AppendLine(); | ||||
|                 builder.AppendLine("fixed (NativeStructHandleData* StructDataPointer = &NativeHandle.Data)"); | ||||
|                 builder.OpenBrace(); | ||||
|                 builder.AppendLine($"IntPtr AllocationPointer = {ExporterCallbacks.UScriptStructCallbacks}.CallGetStructLocation(StructDataPointer, NativeClassPtr);"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 builder.AppendLine("if (Allocation is null)"); | ||||
|                 builder.OpenBrace(); | ||||
|                 builder.AppendLine("Allocation = new byte[NativeDataSize];"); | ||||
|                 builder.AppendLine(); | ||||
|                 builder.CloseBrace(); | ||||
|                 builder.AppendLine("fixed (byte* AllocationPointer = Allocation)"); | ||||
|                 builder.OpenBrace(); | ||||
|             } | ||||
|              | ||||
|             builder.AppendLine($"{ExporterCallbacks.UScriptStructCallbacks}.CallNativeCopy(NativeClassPtr, (nint) AllocationPointer, buffer);"); | ||||
|             builder.CloseBrace(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             foreach (UhtProperty property in properties) | ||||
|             { | ||||
|                 PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; | ||||
|                 string scriptName = property.GetPropertyName(); | ||||
|                 string offsetName = $"{property.SourceName}_Offset"; | ||||
|                 builder.TryAddWithEditor(property); | ||||
|                 translator.ExportToNative(builder, property, property.SourceName, "buffer", offsetName, scriptName); | ||||
|                 builder.TryEndWithEditor(property); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         builder.EndUnsafeBlock(); | ||||
|         builder.CloseBrace(); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user