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 exportedFunctions = new(); List exportedOverrides = new(); Dictionary exportedGetterSetters = new(); Dictionary getSetOverrides = new(); ScriptGeneratorUtilities.GetExportedFunctions(classObj, exportedFunctions, exportedOverrides, exportedGetterSetters, getSetOverrides); List exportedProperties = new List(); Dictionary getSetBackedProperties = new(); ScriptGeneratorUtilities.GetExportedProperties(classObj, exportedProperties, getSetBackedProperties); List 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 exportedPropertyNames = new(); HashSet 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 exportedProperties, HashSet 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 getSetBackedProperties, HashSet exportedPropertyNames, HashSet exportedFunctionNames) { Dictionary exportedGetterSetters = new(); foreach (KeyValuePair 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 getSetBackedProperties, HashSet exportedPropertyNames, HashSet exportedFunctionNames) { foreach (KeyValuePair 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 exportedOverrides, HashSet exportedFunctionNames) { foreach (UhtFunction function in exportedOverrides) { FunctionExporter.ExportOverridableFunction(builder, function, exportedFunctionNames); exportedFunctionNames.Add(function.SourceName); } } static void ExportClassFunctions(UhtClass owner, GeneratorStringBuilder builder, List exportedFunctions, HashSet 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 exportedGetterSetters, HashSet exportedPropertyNames, HashSet exportedFunctionNames) { foreach (KeyValuePair 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); } } } }