541 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			541 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | 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(); | |||
|  |     } | |||
|  | } |