using System.Collections.Generic; using EpicGames.Core; using EpicGames.UHT.Types; using UnrealSharpScriptGenerator.PropertyTranslators; namespace UnrealSharpScriptGenerator.Utilities; public static class StaticConstructorUtilities { public static void ExportStaticConstructor(GeneratorStringBuilder generatorStringBuilder, UhtStruct structObj, List exportedProperties, List exportedFunctions, Dictionary exportedGetterSetters, Dictionary getSetBackedProperties, List overrides, bool isBlittable = false, string? customStaticConstructorName = null) { UhtClass? classObj = structObj as UhtClass; UhtScriptStruct? scriptStructObj = structObj as UhtScriptStruct; string structName = structObj.GetStructName(); if (classObj != null && exportedProperties.Count == 0 && exportedFunctions.Count == 0 && overrides.Count == 0 && exportedGetterSetters.Count == 0 && getSetBackedProperties.Count == 0) { return; } bool hasStaticFunctions = true; void CheckIfStaticFunction(UhtFunction function) { if (function.FunctionFlags.HasAnyFlags(EFunctionFlags.Static)) { hasStaticFunctions = true; } } foreach (UhtFunction function in exportedFunctions) { CheckIfStaticFunction(function); } foreach (GetterSetterPair pair in exportedGetterSetters.Values) { if (pair.Getter != null) { CheckIfStaticFunction(pair.Getter); } if (pair.Setter != null) { CheckIfStaticFunction(pair.Setter); } } string nativeClassPtrDeclaration = string.Empty; if (hasStaticFunctions) { generatorStringBuilder.AppendLine("static readonly IntPtr NativeClassPtr;"); } else { nativeClassPtrDeclaration = "IntPtr "; } if (scriptStructObj != null) { if(classObj == null) generatorStringBuilder.AppendLine("public static IntPtr GetNativeClassPtr() => NativeClassPtr;"); if (isBlittable) { generatorStringBuilder.AppendLine("public static int GetNativeDataSize()"); generatorStringBuilder.OpenBrace(); generatorStringBuilder.BeginUnsafeBlock(); generatorStringBuilder.AppendLine($"return sizeof({structName});"); generatorStringBuilder.EndUnsafeBlock(); generatorStringBuilder.CloseBrace(); } else { generatorStringBuilder.AppendLine("public static readonly int NativeDataSize;"); if (classObj == null) { generatorStringBuilder.AppendLine("public static int GetNativeDataSize() => NativeDataSize;"); } } } string staticCtorName = customStaticConstructorName != null ? customStaticConstructorName : structName; generatorStringBuilder.AppendLine($"static {staticCtorName}()"); generatorStringBuilder.OpenBrace(); string type = classObj != null ? "Class" : "Struct"; string engineName = structObj.EngineName; generatorStringBuilder.AppendLine($"{nativeClassPtrDeclaration}NativeClassPtr = {ExporterCallbacks.CoreUObjectCallbacks}.CallGetNative{type}FromName({structObj.ExportGetAssemblyName()}, \"{structObj.GetNamespace()}\", \"{engineName}\");"); ExportPropertiesStaticConstructor(generatorStringBuilder, exportedProperties); ExportGetSetBackedPropertyStaticConstructor(generatorStringBuilder, getSetBackedProperties); if (classObj != null) { foreach (KeyValuePair pair in exportedGetterSetters) { if (pair.Value.Getter != null) { ExportClassFunctionStaticConstructor(generatorStringBuilder, pair.Value.Getter); } if (pair.Value.Setter != null) { ExportClassFunctionStaticConstructor(generatorStringBuilder, pair.Value.Setter); } } ExportClassFunctionsStaticConstructor(generatorStringBuilder, exportedFunctions); ExportClassOverridesStaticConstructor(generatorStringBuilder, overrides); } else if (!isBlittable) generatorStringBuilder.AppendLine($"NativeDataSize = {ExporterCallbacks.UScriptStructCallbacks}.CallGetNativeStructSize(NativeClassPtr);"); generatorStringBuilder.CloseBrace(); } public static void ExportClassFunctionsStaticConstructor(GeneratorStringBuilder generatorStringBuilder, List exportedFunctions) { foreach (UhtFunction function in exportedFunctions) { ExportClassFunctionStaticConstructor(generatorStringBuilder, function); } } public static void ExportClassFunctionStaticConstructor(GeneratorStringBuilder generatorStringBuilder, UhtFunction function) { string functionName = function.SourceName; string nativeFunctionName = function.GetNativeFunctionName(); generatorStringBuilder.TryAddWithEditor(function); generatorStringBuilder.AppendLine($"{nativeFunctionName} = {ExporterCallbacks.UClassCallbacks}.CallGetNativeFunctionFromClassAndName(NativeClassPtr, \"{function.EngineName}\");"); if (function.HasParametersOrReturnValue()) { bool hasCustomStructParams = function.HasCustomStructParamSupport(); string variableName = hasCustomStructParams ? $"{functionName}_NativeParamsSize" : $"{functionName}_ParamsSize"; generatorStringBuilder.AppendLine($"{variableName} = {ExporterCallbacks.UFunctionCallbacks}.CallGetNativeFunctionParamsSize({functionName}_NativeFunction);"); foreach (UhtType parameter in function.Children) { if (parameter is not UhtProperty property) { continue; } PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; translator.ExportParameterStaticConstructor(generatorStringBuilder, property, function, property.SourceName, functionName); } if (hasCustomStructParams) { List customStructParams = function.GetCustomStructParams(); List initializerElements = customStructParams.ConvertAll(param => $"{ExporterCallbacks.FPropertyCallbacks}.CallGetNativePropertyFromName({nativeFunctionName}, \"{param}\")"); generatorStringBuilder.AppendLine($"{functionName}_CustomStructureNativeProperties = new IntPtr[]{{{string.Join(", ", initializerElements)}}};"); } } generatorStringBuilder.TryEndWithEditor(function); } public static void ExportClassOverridesStaticConstructor(GeneratorStringBuilder generatorStringBuilder, List overrides) { foreach (UhtFunction function in overrides) { generatorStringBuilder.TryAddWithEditor(function); string functionName = function.SourceName; string intPtrDeclaration = function.IsBlueprintImplementableEvent() ? "IntPtr " : ""; generatorStringBuilder.AppendLine($"{intPtrDeclaration}{functionName}_NativeFunction = {ExporterCallbacks.UClassCallbacks}.CallGetNativeFunctionFromClassAndName(NativeClassPtr, \"{function.EngineName}\");"); if (function.HasParametersOrReturnValue()) { generatorStringBuilder.AppendLine($"{functionName}_ParamsSize = {ExporterCallbacks.UFunctionCallbacks}.CallGetNativeFunctionParamsSize({functionName}_NativeFunction);"); foreach (UhtType parameter in function.Children) { if (parameter is not UhtProperty property) { continue; } PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; translator.ExportParameterStaticConstructor(generatorStringBuilder, property, function, property.SourceName, functionName); } } generatorStringBuilder.TryEndWithEditor(function); } } public static void ExportPropertiesStaticConstructor(GeneratorStringBuilder generatorStringBuilder, List exportedProperties) { foreach (UhtProperty property in exportedProperties) { ExportPropertyStaticConstructor(generatorStringBuilder, property); } } public static void ExportGetSetBackedPropertyStaticConstructor(GeneratorStringBuilder generatorStringBuilder, Dictionary getSetBackedProperties) { foreach (KeyValuePair pair in getSetBackedProperties) { ExportPropertyStaticConstructor(generatorStringBuilder, pair.Key); } } private static void ExportPropertyStaticConstructor(GeneratorStringBuilder generatorStringBuilder, UhtProperty property) { generatorStringBuilder.TryAddWithEditor(property); PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(property)!; translator.ExportPropertyStaticConstructor(generatorStringBuilder, property, property.SourceName); generatorStringBuilder.TryEndWithEditor(property); } }