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 exportedFunctions = new(); List exportedOverrides = new(); Dictionary exportedGetterSetters = new(); Dictionary 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(), exportedFunctions, exportedGetterSetters, new Dictionary(), 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 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 exportedFunctions) { foreach (UhtFunction function in exportedFunctions) { FunctionExporter.ExportInterfaceFunction(stringBuilder, function); } } static void ExportWrapperFunctions(GeneratorStringBuilder stringBuilder, List exportedFunctions) { foreach (UhtFunction function in exportedFunctions) { FunctionType functionType = function.FunctionFlags.HasFlag(EFunctionFlags.BlueprintEvent) ? FunctionType.BlueprintEvent : FunctionType.Normal; FunctionExporter.ExportFunction(stringBuilder, function, functionType); } } }