1270 lines
49 KiB
C#
1270 lines
49 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Data.Common;
|
|
using System.Linq;
|
|
using System.Reflection.Metadata;
|
|
using System.Reflection.Metadata.Ecma335;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading.Tasks;
|
|
using EpicGames.Core;
|
|
using EpicGames.UHT.Types;
|
|
using UnrealSharpScriptGenerator.PropertyTranslators;
|
|
using UnrealSharpScriptGenerator.Tooltip;
|
|
using UnrealSharpScriptGenerator.Utilities;
|
|
|
|
namespace UnrealSharpScriptGenerator.Exporters;
|
|
|
|
public enum EFunctionProtectionMode
|
|
{
|
|
UseUFunctionProtection,
|
|
OverrideWithInternal,
|
|
}
|
|
|
|
public struct ExtensionMethod
|
|
{
|
|
public UhtClass Class;
|
|
public UhtFunction Function;
|
|
public UhtProperty SelfParameter;
|
|
}
|
|
|
|
public enum FunctionType
|
|
{
|
|
Normal,
|
|
BlueprintEvent,
|
|
ExtensionOnAnotherClass,
|
|
InternalWhitelisted,
|
|
GetterSetter,
|
|
};
|
|
|
|
public enum OverloadMode
|
|
{
|
|
AllowOverloads,
|
|
SuppressOverloads,
|
|
};
|
|
|
|
public enum EBlueprintVisibility
|
|
{
|
|
Call,
|
|
Event,
|
|
GetterSetter,
|
|
Throwing
|
|
};
|
|
|
|
public struct FunctionOverload
|
|
{
|
|
public string ParamStringApiWithDefaults;
|
|
public string ParamsStringCall;
|
|
public string CSharpParamName;
|
|
public string CppDefaultValue;
|
|
public PropertyTranslator Translator;
|
|
public UhtProperty Parameter;
|
|
}
|
|
|
|
public class FunctionExporter
|
|
{
|
|
protected static readonly ConcurrentDictionary<UhtPackage, List<ExtensionMethod>> ExtensionMethods = new();
|
|
|
|
public UhtFunction Function { get; }
|
|
protected string _functionName = null!;
|
|
protected List<PropertyTranslator> _parameterTranslators = null!;
|
|
protected PropertyTranslator? ReturnValueTranslator => Function.ReturnProperty != null ? _parameterTranslators.Last() : null;
|
|
protected OverloadMode _overloadMode = OverloadMode.AllowOverloads;
|
|
protected EFunctionProtectionMode _protectionMode = EFunctionProtectionMode.UseUFunctionProtection;
|
|
protected EBlueprintVisibility _blueprintVisibility = EBlueprintVisibility.Call;
|
|
|
|
protected bool BlittableFunction;
|
|
|
|
public string Modifiers { get; private set; } = "";
|
|
|
|
protected bool BlueprintEvent => Function.HasAllFlags(EFunctionFlags.BlueprintEvent);
|
|
protected bool BlueprintNativeEvent => Function.IsBlueprintNativeEvent();
|
|
protected bool BlueprintImplementableEvent => Function.IsBlueprintImplementableEvent();
|
|
protected bool Throwing => _blueprintVisibility == EBlueprintVisibility.Throwing;
|
|
|
|
protected string _invokeFunction = "";
|
|
protected string _invokeFirstArgument = "";
|
|
|
|
protected string _customInvoke = "";
|
|
|
|
protected string _paramStringApiWithDefaults = "";
|
|
protected string _paramsStringCall = "";
|
|
|
|
protected bool _hasGenericTypeSupport = false;
|
|
protected bool _hasCustomStructParamSupport = false;
|
|
|
|
protected List<string> _customStructParamTypes = null!;
|
|
|
|
protected readonly UhtProperty? _selfParameter;
|
|
protected readonly UhtClass? _classBeingExtended;
|
|
|
|
protected readonly List<FunctionOverload> _overloads = new();
|
|
|
|
public string NativeFunctionIntPtr => $"{Function.SourceName}_NativeFunction";
|
|
public string InstanceFunctionPtr => $"{Function.SourceName}_InstanceFunction";
|
|
|
|
public FunctionExporter(ExtensionMethod extensionMethod)
|
|
{
|
|
_selfParameter = extensionMethod.SelfParameter;
|
|
Function = extensionMethod.Function;
|
|
_classBeingExtended = extensionMethod.Class;
|
|
}
|
|
|
|
public FunctionExporter(UhtFunction function)
|
|
{
|
|
Function = function;
|
|
}
|
|
|
|
string GetRefQualifier(UhtProperty parameter)
|
|
{
|
|
if (parameter.HasAllFlags(EPropertyFlags.ConstParm))
|
|
{
|
|
return "";
|
|
}
|
|
|
|
if (parameter.HasAllFlags(EPropertyFlags.ReferenceParm))
|
|
{
|
|
return "ref ";
|
|
}
|
|
|
|
if (parameter.HasAllFlags(EPropertyFlags.OutParm))
|
|
{
|
|
return "out ";
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
public void Initialize(OverloadMode overloadMode, EFunctionProtectionMode protectionMode, EBlueprintVisibility blueprintVisibility, bool withGenerics = false)
|
|
{
|
|
_functionName = protectionMode != EFunctionProtectionMode.OverrideWithInternal
|
|
? Function.GetFunctionName()
|
|
: Function.SourceName;
|
|
|
|
_overloadMode = overloadMode;
|
|
_protectionMode = protectionMode;
|
|
_blueprintVisibility = blueprintVisibility;
|
|
|
|
_parameterTranslators = new List<PropertyTranslator>(Function.Children.Count);
|
|
|
|
bool isBlittable = true;
|
|
foreach (UhtProperty parameter in Function.Properties)
|
|
{
|
|
PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(parameter)!;
|
|
_parameterTranslators.Add(translator);
|
|
|
|
if (!translator.IsBlittable && isBlittable)
|
|
{
|
|
isBlittable = false;
|
|
}
|
|
}
|
|
BlittableFunction = isBlittable;
|
|
|
|
_hasGenericTypeSupport = Function.HasGenericTypeSupport();
|
|
|
|
_hasCustomStructParamSupport = Function.HasCustomStructParamSupport();
|
|
|
|
DetermineProtectionMode();
|
|
_invokeFunction = DetermineInvokeFunction();
|
|
|
|
if (Function.HasAllFlags(EFunctionFlags.Static))
|
|
{
|
|
Modifiers += "static ";
|
|
_invokeFirstArgument = "NativeClassPtr";
|
|
}
|
|
else if (Function.HasAllFlags(EFunctionFlags.Delegate))
|
|
{
|
|
if (Function.HasParametersOrReturnValue())
|
|
{
|
|
_customInvoke = "ProcessDelegate(paramsBuffer);";
|
|
}
|
|
else
|
|
{
|
|
_customInvoke = "ProcessDelegate(IntPtr.Zero);";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (BlueprintEvent)
|
|
{
|
|
Modifiers += "virtual ";
|
|
}
|
|
|
|
if (Function.IsInterfaceFunction())
|
|
{
|
|
Modifiers = ScriptGeneratorUtilities.PublicKeyword;
|
|
}
|
|
|
|
_invokeFirstArgument = "NativeObject";
|
|
}
|
|
|
|
string paramString = "";
|
|
bool hasDefaultParameters = false;
|
|
|
|
if (_selfParameter != null)
|
|
{
|
|
PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(_selfParameter)!;
|
|
string paramType = _classBeingExtended != null
|
|
? _classBeingExtended.GetFullManagedName()
|
|
: translator.GetManagedType(_selfParameter);
|
|
|
|
paramString = $"this {paramType} {_selfParameter.GetParameterName()}, ";
|
|
_paramStringApiWithDefaults = paramString;
|
|
}
|
|
|
|
string paramsStringCallNative = "";
|
|
|
|
string paramsStringCallGenerics = "";
|
|
string paramStringApiWithDefaultsWithGenerics = "";
|
|
|
|
bool hasGenericClassParam = false;
|
|
|
|
_customStructParamTypes = Function.GetCustomStructParamTypes();
|
|
|
|
for (int i = 0; i < Function.Children.Count; i++)
|
|
{
|
|
UhtProperty parameter = (UhtProperty) Function.Children[i];
|
|
if (parameter.HasAllFlags(EPropertyFlags.ReturnParm))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
PropertyTranslator translator = _parameterTranslators[i];
|
|
|
|
string refQualifier = GetRefQualifier(parameter);
|
|
string parameterName = GetParameterName(parameter);
|
|
string parameterManagedType = translator.GetManagedType(parameter);
|
|
|
|
if (!translator.ShouldBeDeclaredAsParameter)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (_selfParameter == parameter)
|
|
{
|
|
if (string.IsNullOrEmpty(paramsStringCallGenerics))
|
|
{
|
|
paramsStringCallGenerics += refQualifier + parameterName;
|
|
}
|
|
else
|
|
{
|
|
paramsStringCallGenerics = $"{parameterName}, " + _paramsStringCall.Substring(0, _paramsStringCall.Length - 2);
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(_paramsStringCall))
|
|
{
|
|
_paramsStringCall += refQualifier + parameterName;
|
|
}
|
|
else
|
|
{
|
|
_paramsStringCall = $"{parameterName}, " + _paramsStringCall.Substring(0, _paramsStringCall.Length - 2);
|
|
}
|
|
paramsStringCallNative += parameterName;
|
|
}
|
|
else
|
|
{
|
|
string cppDefaultValue = translator.GetCppDefaultValue(Function, parameter);
|
|
bool isGenericClassParam = _hasGenericTypeSupport && parameter.IsGenericType() && !parameter.HasAnyFlags(EPropertyFlags.OutParm) && parameter is UhtClassProperty;
|
|
|
|
if (cppDefaultValue == "()" && parameter is UhtStructProperty structProperty)
|
|
{
|
|
_paramsStringCall += $"new {structProperty.ScriptStruct.GetFullManagedName()}()";
|
|
paramsStringCallGenerics += $"new {structProperty.ScriptStruct.GetFullManagedName()}()";
|
|
}
|
|
else if (isGenericClassParam)
|
|
{
|
|
_paramsStringCall += $"{refQualifier}{parameterName}";
|
|
paramsStringCallGenerics += $"typeof(DOT)";
|
|
|
|
hasGenericClassParam = true;
|
|
}
|
|
else
|
|
{
|
|
_paramsStringCall += $"{refQualifier}{parameterName}";
|
|
paramsStringCallGenerics += $"{refQualifier}{parameterName}";
|
|
}
|
|
|
|
paramsStringCallNative += $"{refQualifier}{parameterName}";
|
|
paramString += $"{refQualifier}{parameterManagedType} {parameterName}";
|
|
|
|
if (!isGenericClassParam)
|
|
{
|
|
paramStringApiWithDefaultsWithGenerics += $"{refQualifier}{parameterManagedType} {parameterName}";
|
|
}
|
|
|
|
if ((hasDefaultParameters || cppDefaultValue.Length > 0) && _overloadMode == OverloadMode.AllowOverloads)
|
|
{
|
|
hasDefaultParameters = true;
|
|
string csharpDefaultValue = "";
|
|
|
|
if (cppDefaultValue.Length == 0 || cppDefaultValue == "None")
|
|
{
|
|
csharpDefaultValue = translator.GetNullValue(parameter);
|
|
}
|
|
else if (translator.ExportDefaultParameter)
|
|
{
|
|
csharpDefaultValue = translator.ConvertCPPDefaultValue(cppDefaultValue, Function, parameter);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(csharpDefaultValue))
|
|
{
|
|
string defaultValue = $" = {csharpDefaultValue}";
|
|
_paramStringApiWithDefaults += $"{refQualifier}{parameterManagedType} {parameterName}{defaultValue}";
|
|
}
|
|
else
|
|
{
|
|
if (_paramStringApiWithDefaults.Length > 0)
|
|
{
|
|
_paramStringApiWithDefaults = _paramStringApiWithDefaults.Substring(0, _paramStringApiWithDefaults.Length - 2);
|
|
}
|
|
|
|
FunctionOverload overload = new FunctionOverload
|
|
{
|
|
ParamStringApiWithDefaults = _paramStringApiWithDefaults,
|
|
ParamsStringCall = _paramsStringCall,
|
|
CSharpParamName = parameterName,
|
|
CppDefaultValue = cppDefaultValue,
|
|
Translator = translator,
|
|
Parameter = parameter,
|
|
};
|
|
|
|
_overloads.Add(overload);
|
|
|
|
_paramStringApiWithDefaults = paramString;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_paramStringApiWithDefaults = paramString;
|
|
}
|
|
|
|
paramString += ", ";
|
|
_paramStringApiWithDefaults += ", ";
|
|
|
|
if (!isGenericClassParam)
|
|
{
|
|
paramStringApiWithDefaultsWithGenerics += ", ";
|
|
}
|
|
}
|
|
|
|
_paramsStringCall += ", ";
|
|
paramsStringCallGenerics += ", ";
|
|
paramsStringCallNative += ", ";
|
|
}
|
|
|
|
if (_selfParameter == null)
|
|
{
|
|
_paramsStringCall = paramsStringCallNative;
|
|
}
|
|
|
|
// remove last comma
|
|
if (_paramStringApiWithDefaults.Length > 0)
|
|
{
|
|
_paramStringApiWithDefaults = _paramStringApiWithDefaults.Substring(0, _paramStringApiWithDefaults.Length - 2);
|
|
}
|
|
|
|
if (_paramsStringCall.Length > 0)
|
|
{
|
|
_paramsStringCall = _paramsStringCall.Substring(0, _paramsStringCall.Length - 2);
|
|
}
|
|
|
|
if (paramsStringCallGenerics.Length > 0)
|
|
{
|
|
paramsStringCallGenerics = paramsStringCallGenerics[..^2];
|
|
}
|
|
|
|
if (paramStringApiWithDefaultsWithGenerics.Length > 0)
|
|
{
|
|
paramStringApiWithDefaultsWithGenerics = paramStringApiWithDefaultsWithGenerics[..^2];
|
|
}
|
|
|
|
if (hasGenericClassParam)
|
|
{
|
|
FunctionOverload overload = new FunctionOverload
|
|
{
|
|
ParamStringApiWithDefaults = paramStringApiWithDefaultsWithGenerics,
|
|
ParamsStringCall = paramsStringCallGenerics,
|
|
};
|
|
|
|
_overloads.Add(overload);
|
|
}
|
|
}
|
|
|
|
protected virtual string GetParameterName(UhtProperty parameter)
|
|
{
|
|
return parameter.GetParameterName();
|
|
}
|
|
|
|
public static void TryAddExtensionMethod(UhtFunction function)
|
|
{
|
|
if (!function.HasMetadata("ExtensionMethod") && !function.IsAutocast())
|
|
{
|
|
return;
|
|
}
|
|
|
|
UhtPackage package = function.Outer!.Package;
|
|
|
|
if (!ExtensionMethods.TryGetValue(package, out var extensionMethods))
|
|
{
|
|
extensionMethods = new List<ExtensionMethod>();
|
|
ExtensionMethods.TryAdd(package, extensionMethods);
|
|
}
|
|
|
|
UhtProperty firstParameter = (function.Children[0] as UhtProperty)!;
|
|
ExtensionMethod newExtensionMethod = new ExtensionMethod
|
|
{
|
|
Function = function,
|
|
SelfParameter = firstParameter,
|
|
};
|
|
|
|
if (firstParameter is UhtObjectPropertyBase objectSelfProperty)
|
|
{
|
|
newExtensionMethod.Class = objectSelfProperty.MetaClass!;
|
|
}
|
|
|
|
extensionMethods.Add(newExtensionMethod);
|
|
}
|
|
|
|
public static void StartExportingExtensionMethods(List<Task> tasks)
|
|
{
|
|
foreach (KeyValuePair<UhtPackage, List<ExtensionMethod>> extensionInfo in ExtensionMethods)
|
|
{
|
|
tasks.Add(Program.Factory.CreateTask(_ =>
|
|
{
|
|
ExtensionsClassExporter.ExportExtensionsClass(extensionInfo.Key, extensionInfo.Value);
|
|
})!);
|
|
}
|
|
}
|
|
|
|
public static FunctionExporter ExportFunction(GeneratorStringBuilder builder, UhtFunction function, FunctionType functionType, HashSet<string>? exportedFunctions = null)
|
|
{
|
|
EFunctionProtectionMode protectionMode = EFunctionProtectionMode.UseUFunctionProtection;
|
|
OverloadMode overloadMode = OverloadMode.AllowOverloads;
|
|
EBlueprintVisibility blueprintVisibility = EBlueprintVisibility.Call;
|
|
|
|
if (functionType == FunctionType.ExtensionOnAnotherClass)
|
|
{
|
|
protectionMode = EFunctionProtectionMode.OverrideWithInternal;
|
|
overloadMode = OverloadMode.SuppressOverloads;
|
|
}
|
|
else if (functionType == FunctionType.BlueprintEvent)
|
|
{
|
|
overloadMode = OverloadMode.SuppressOverloads;
|
|
blueprintVisibility = EBlueprintVisibility.Event;
|
|
}
|
|
else if (functionType == FunctionType.GetterSetter)
|
|
{
|
|
protectionMode = EFunctionProtectionMode.OverrideWithInternal;
|
|
overloadMode = OverloadMode.SuppressOverloads;
|
|
blueprintVisibility = EBlueprintVisibility.GetterSetter;
|
|
}
|
|
|
|
builder.TryAddWithEditor(function);
|
|
FunctionExporter exporter = new FunctionExporter(function);
|
|
exporter.Initialize(overloadMode, protectionMode, blueprintVisibility);
|
|
if (exportedFunctions is null || !exportedFunctions.Contains(function.SourceName))
|
|
{
|
|
exporter.ExportFunctionVariables(builder);
|
|
}
|
|
|
|
exporter.ExportOverloads(builder);
|
|
exporter.ExportFunction(builder);
|
|
|
|
builder.TryEndWithEditor(function);
|
|
|
|
return exporter;
|
|
}
|
|
|
|
public static void ExportOverridableFunction(GeneratorStringBuilder builder, UhtFunction function, HashSet<string>? exportedFunctions = null)
|
|
{
|
|
builder.TryAddWithEditor(function);
|
|
|
|
string paramsStringApi = "";
|
|
string paramsCallString = "";
|
|
string methodName = function.GetFunctionName();
|
|
|
|
foreach (UhtProperty parameter in function.Properties)
|
|
{
|
|
if (parameter.HasAllFlags(EPropertyFlags.ReturnParm))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string paramName = parameter.GetParameterName();
|
|
string paramType = PropertyTranslatorManager.GetTranslator(parameter)!.GetManagedType(parameter);
|
|
|
|
string refQualifier = "";
|
|
if (!parameter.HasAllFlags(EPropertyFlags.ConstParm))
|
|
{
|
|
if (parameter.HasAllFlags(EPropertyFlags.ReferenceParm))
|
|
{
|
|
refQualifier = "ref ";
|
|
}
|
|
else if (parameter.HasAllFlags(EPropertyFlags.OutParm))
|
|
{
|
|
refQualifier = "out ";
|
|
}
|
|
}
|
|
|
|
paramsStringApi += $"{refQualifier}{paramType} {paramName}, ";
|
|
paramsCallString += $"{refQualifier}{paramName}, ";
|
|
}
|
|
|
|
if (paramsStringApi.Length > 0)
|
|
{
|
|
paramsStringApi = paramsStringApi.Substring(0, paramsStringApi.Length - 2);
|
|
}
|
|
if (paramsCallString.Length > 0)
|
|
{
|
|
paramsCallString = paramsCallString.Substring(0, paramsCallString.Length - 2);
|
|
}
|
|
|
|
FunctionExporter exportFunction = ExportFunction(builder, function, FunctionType.BlueprintEvent, exportedFunctions);
|
|
|
|
string returnType = function.ReturnProperty != null
|
|
? PropertyTranslatorManager.GetTranslator(function.ReturnProperty)!.GetManagedType(function.ReturnProperty)
|
|
: "void";
|
|
|
|
builder.AppendLine("// Hide implementation function from Intellisense");
|
|
builder.AppendLine("[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]");
|
|
builder.AppendLine($"protected virtual {returnType} {methodName}_Implementation({paramsStringApi})");
|
|
|
|
builder.OpenBrace();
|
|
if (exportFunction.BlueprintNativeEvent)
|
|
{
|
|
exportFunction.ExportInvoke(builder);
|
|
}
|
|
else
|
|
{
|
|
exportFunction.ForEachParameter((translator, parameter) =>
|
|
{
|
|
if (!parameter.HasAllFlags(EPropertyFlags.OutParm) || parameter.HasAnyFlags(EPropertyFlags.ReturnParm | EPropertyFlags.ConstParm | EPropertyFlags.ReferenceParm))
|
|
{
|
|
return;
|
|
}
|
|
|
|
string paramName = parameter.GetParameterName();
|
|
string nullValue = translator.GetNullValue(parameter);
|
|
builder.AppendLine($"{paramName} = {nullValue};");
|
|
});
|
|
|
|
if (function.ReturnProperty != null)
|
|
{
|
|
PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(function.ReturnProperty)!;
|
|
string nullValue = translator.GetNullValue(function.ReturnProperty);
|
|
builder.AppendLine($"return {nullValue};");
|
|
}
|
|
}
|
|
builder.CloseBrace();
|
|
|
|
builder.AppendLine($"void Invoke_{function.EngineName}(IntPtr buffer, IntPtr returnBuffer)");
|
|
builder.OpenBrace();
|
|
builder.BeginUnsafeBlock();
|
|
|
|
string returnAssignment = "";
|
|
exportFunction.ForEachParameter((translator, parameter) =>
|
|
{
|
|
string paramType = translator.GetManagedType(parameter);
|
|
|
|
if (parameter.HasAllFlags(EPropertyFlags.ReturnParm))
|
|
{
|
|
returnAssignment = $"{paramType} returnValue = ";
|
|
}
|
|
else if (!parameter.HasAnyFlags(EPropertyFlags.ConstParm)
|
|
&& !parameter.HasAnyFlags(EPropertyFlags.ReferenceParm)
|
|
&& parameter.HasAnyFlags(EPropertyFlags.OutParm))
|
|
{
|
|
builder.AppendLine($"{paramType} {parameter.GetParameterName()} = default;");
|
|
}
|
|
else
|
|
{
|
|
string parameterName = parameter.GetParameterName();
|
|
string assignmentOrReturn = $"{paramType} {parameterName} = ";
|
|
string offsetName = parameter.GetOffsetVariableName();
|
|
|
|
translator.ExportFromNative(builder, parameter, parameter.SourceName, assignmentOrReturn, "buffer",
|
|
offsetName, false, false);
|
|
}
|
|
});
|
|
|
|
builder.AppendLine($"{returnAssignment}{methodName}_Implementation({paramsCallString});");
|
|
|
|
if (function.ReturnProperty != null)
|
|
{
|
|
PropertyTranslator translator = PropertyTranslatorManager.GetTranslator(function.ReturnProperty)!;
|
|
translator.ExportToNative(builder, function.ReturnProperty, function.ReturnProperty.SourceName, "returnBuffer", "0", "returnValue");
|
|
}
|
|
|
|
exportFunction.ForEachParameter((translator, parameter) =>
|
|
{
|
|
if (parameter.HasAnyFlags(EPropertyFlags.ReturnParm | EPropertyFlags.ConstParm) ||
|
|
!parameter.HasAnyFlags(EPropertyFlags.OutParm))
|
|
{
|
|
return;
|
|
}
|
|
|
|
translator.ExportToNative(builder, parameter, parameter.SourceName, "buffer", parameter.GetOffsetVariableName(), parameter.GetParameterName());
|
|
});
|
|
|
|
builder.EndUnsafeBlock();
|
|
builder.CloseBrace();
|
|
|
|
builder.TryEndWithEditor(function);
|
|
|
|
builder.AppendLine();
|
|
}
|
|
|
|
public static FunctionExporter ExportDelegateSignature(GeneratorStringBuilder builder, UhtFunction function, string delegateName)
|
|
{
|
|
FunctionExporter exporter = new FunctionExporter(function);
|
|
exporter.Initialize(OverloadMode.SuppressOverloads, EFunctionProtectionMode.UseUFunctionProtection, EBlueprintVisibility.Call);
|
|
|
|
AttributeBuilder attributeBuilder = new AttributeBuilder();
|
|
attributeBuilder.AddGeneratedTypeAttribute(function);
|
|
|
|
if (function.HasAllFlags(EFunctionFlags.MulticastDelegate))
|
|
{
|
|
attributeBuilder.AddAttribute("UMultiDelegate");
|
|
}
|
|
else
|
|
{
|
|
attributeBuilder.AddAttribute("USingleDelegate");
|
|
}
|
|
|
|
attributeBuilder.Finish();
|
|
builder.AppendLine(attributeBuilder.ToString());
|
|
|
|
builder.AppendLine($"public delegate void {delegateName}({exporter._paramStringApiWithDefaults});");
|
|
builder.AppendLine();
|
|
|
|
return exporter;
|
|
}
|
|
|
|
public static void ExportDelegateGlue(GeneratorStringBuilder builder, FunctionExporter exporter)
|
|
{
|
|
exporter.ExportFunctionVariables(builder);
|
|
builder.AppendLine();
|
|
|
|
builder.AppendLine($"protected void Invoker({exporter._paramStringApiWithDefaults})");
|
|
|
|
builder.OpenBrace();
|
|
exporter.ExportInvoke(builder);
|
|
builder.CloseBrace();
|
|
}
|
|
|
|
public static void ExportInterfaceFunction(GeneratorStringBuilder builder, UhtFunction function)
|
|
{
|
|
builder.TryAddWithEditor(function);
|
|
|
|
FunctionExporter exporter = new FunctionExporter(function);
|
|
exporter.Initialize(OverloadMode.SuppressOverloads, EFunctionProtectionMode.UseUFunctionProtection, EBlueprintVisibility.Call);
|
|
exporter.ExportSignature(builder, ScriptGeneratorUtilities.PublicKeyword);
|
|
builder.Append(";");
|
|
|
|
builder.TryEndWithEditor(function);
|
|
}
|
|
|
|
public void ForEachParameter(Action<PropertyTranslator, UhtProperty> action)
|
|
{
|
|
for (int i = 0; i < Function.Children.Count; i++)
|
|
{
|
|
UhtProperty parameter = (UhtProperty) Function.Children[i];
|
|
PropertyTranslator translator = _parameterTranslators[i];
|
|
action(translator, parameter);
|
|
}
|
|
}
|
|
|
|
public void ExportExtensionMethodOverloads(GeneratorStringBuilder builder)
|
|
{
|
|
foreach (FunctionOverload overload in _overloads)
|
|
{
|
|
builder.AppendLine();
|
|
ExportDeprecation(builder);
|
|
|
|
string returnType = "void";
|
|
string returnStatement = "";
|
|
if (Function.ReturnProperty != null)
|
|
{
|
|
returnType = ReturnValueTranslator!.GetManagedType(Function.ReturnProperty);
|
|
returnStatement = "return ";
|
|
}
|
|
|
|
List<string> genericTypes = new List<string>();
|
|
List<string> genericConstraints = new List<string>();
|
|
if (_hasGenericTypeSupport)
|
|
{
|
|
genericTypes.Add("DOT");
|
|
genericConstraints.Add(Function.GetGenericTypeConstraint());
|
|
}
|
|
|
|
if (_hasCustomStructParamSupport)
|
|
{
|
|
genericTypes.AddRange(_customStructParamTypes);
|
|
genericConstraints.AddRange(_customStructParamTypes.ConvertAll(paramType => $"MarshalledStruct<{paramType}>"));
|
|
}
|
|
|
|
string genericTypeString = string.Join(", ", genericTypes);
|
|
|
|
if (genericTypes.Count > 0)
|
|
{
|
|
PropertyTranslator translator = _parameterTranslators[0];
|
|
string paramType = _classBeingExtended != null
|
|
? _classBeingExtended.GetFullManagedName()
|
|
: translator.GetManagedType(_selfParameter!);
|
|
builder.AppendLine($"{Modifiers}{returnType} {_functionName}<{genericTypeString}>(this {paramType} {_selfParameter!.GetParameterName()}, {overload.ParamStringApiWithDefaults})");
|
|
builder.Indent();
|
|
foreach (var (genericType, constraint) in genericTypes.Zip(genericConstraints))
|
|
builder.AppendLine($"where {genericType} : {constraint}");
|
|
builder.UnIndent();
|
|
}
|
|
else
|
|
{
|
|
builder.AppendLine($"{Modifiers}{returnType} {_functionName}(this {overload.ParamStringApiWithDefaults})");
|
|
}
|
|
|
|
builder.OpenBrace();
|
|
overload.Translator?.ExportCppDefaultParameterAsLocalVariable(builder, overload.CSharpParamName, overload.CppDefaultValue, Function, overload.Parameter);
|
|
|
|
UhtClass functionOwner = (UhtClass) Function.Outer!;
|
|
string fullClassName = functionOwner.GetFullManagedName();
|
|
if (genericTypes.Count > 0)
|
|
{
|
|
builder.AppendLine($"{returnStatement}{fullClassName}.{_functionName}<{genericTypeString}>({overload.ParamsStringCall});");
|
|
}
|
|
else
|
|
{
|
|
builder.AppendLine($"{returnStatement}{fullClassName}.{_functionName}({overload.ParamsStringCall});");
|
|
}
|
|
builder.CloseBrace();
|
|
}
|
|
}
|
|
|
|
public void ExportExtensionMethod(GeneratorStringBuilder builder)
|
|
{
|
|
builder.AppendLine();
|
|
builder.AppendTooltip(Function);
|
|
ExportDeprecation(builder);
|
|
|
|
string returnManagedType = "void";
|
|
if (ReturnValueTranslator != null)
|
|
{
|
|
returnManagedType = ReturnValueTranslator.GetManagedType(Function.ReturnProperty!);
|
|
}
|
|
|
|
string functionNameToUse = Function.IsAutocast() ? Function.GetBlueprintAutocastName() : _functionName;
|
|
|
|
List<string> genericTypes = new List<string>();
|
|
List<string> genericConstraints = new List<string>();
|
|
if (_hasGenericTypeSupport)
|
|
{
|
|
genericTypes.Add("DOT");
|
|
genericConstraints.Add(Function.GetGenericTypeConstraint());
|
|
}
|
|
|
|
if (_hasCustomStructParamSupport)
|
|
{
|
|
genericTypes.AddRange(_customStructParamTypes);
|
|
genericConstraints.AddRange(_customStructParamTypes.ConvertAll(paramType => $"MarshalledStruct<{paramType}>"));
|
|
}
|
|
|
|
string genericTypeString = string.Join(", ", genericTypes);
|
|
|
|
if (genericTypes.Count > 0)
|
|
{
|
|
builder.AppendLine($"{Modifiers}{returnManagedType} {functionNameToUse}<{genericTypeString}>({_paramStringApiWithDefaults})");
|
|
builder.Indent();
|
|
foreach (var (genericType, constraint) in genericTypes.Zip(genericConstraints))
|
|
builder.AppendLine($"where {genericType} : {constraint}");
|
|
builder.UnIndent();
|
|
}
|
|
else
|
|
{
|
|
builder.AppendLine($"{Modifiers}{returnManagedType} {functionNameToUse}({_paramStringApiWithDefaults})");
|
|
}
|
|
|
|
builder.OpenBrace();
|
|
string returnStatement = Function.ReturnProperty != null ? "return " : "";
|
|
UhtClass functionOwner = (UhtClass) Function.Outer!;
|
|
|
|
string fullClassName = functionOwner.GetFullManagedName();
|
|
builder.AppendLine($"{returnStatement}{fullClassName}.{_functionName}({_paramsStringCall});");
|
|
builder.CloseBrace();
|
|
}
|
|
|
|
public void ExportFunctionVariables(GeneratorStringBuilder builder)
|
|
{
|
|
builder.AppendLine($"// {Function.SourceName}");
|
|
|
|
if (!BlueprintImplementableEvent)
|
|
{
|
|
builder.AppendLine($"static IntPtr {NativeFunctionIntPtr};");
|
|
}
|
|
|
|
if (BlueprintEvent)
|
|
{
|
|
builder.AppendLine($"IntPtr {InstanceFunctionPtr};");
|
|
}
|
|
|
|
if (Function.HasParametersOrReturnValue())
|
|
{
|
|
if (_hasCustomStructParamSupport)
|
|
{
|
|
string genericTypes = string.Join(", ", _customStructParamTypes);
|
|
builder.AppendLine($"static int {Function.SourceName}_NativeParamsSize;");
|
|
builder.AppendLine($"static int {Function.SourceName}_ParamsSize<{genericTypes}>()");
|
|
builder.Indent();
|
|
foreach (string genericType in _customStructParamTypes)
|
|
{
|
|
builder.AppendLine($"where {genericType}: MarshalledStruct<{genericType}>");
|
|
}
|
|
List<string> variableNames = new List<string>{$"{Function.SourceName}_NativeParamsSize"};
|
|
int customStructureParamIndex = 0;
|
|
ForEachParameter((translator, parameter) =>
|
|
{
|
|
if (!parameter.IsCustomStructureType()) return;
|
|
variableNames.Add($"{_customStructParamTypes[customStructureParamIndex]}.GetNativeDataSize()");
|
|
customStructureParamIndex++;
|
|
});
|
|
builder.AppendLine($"=> {string.Join(" + ", variableNames)};");
|
|
builder.UnIndent();
|
|
builder.AppendLine($"static IntPtr[] {Function.SourceName}_CustomStructureNativeProperties;");
|
|
}
|
|
else
|
|
{
|
|
builder.AppendLine($"static int {Function.SourceName}_ParamsSize;");
|
|
}
|
|
}
|
|
|
|
ForEachParameter((translator, parameter) =>
|
|
{
|
|
translator.ExportParameterVariables(builder, Function, Function.SourceName, parameter, parameter.SourceName);
|
|
});
|
|
}
|
|
|
|
void ExportOverloads(GeneratorStringBuilder builder)
|
|
{
|
|
foreach (FunctionOverload overload in _overloads)
|
|
{
|
|
builder.AppendLine();
|
|
ExportDeprecation(builder);
|
|
|
|
string returnType = "void";
|
|
string returnStatement = "";
|
|
if (Function.ReturnProperty != null)
|
|
{
|
|
returnType = ReturnValueTranslator!.GetManagedType(Function.ReturnProperty);
|
|
returnStatement = "return ";
|
|
}
|
|
|
|
List<string> genericTypes = new List<string>();
|
|
List<string> genericConstraints = new List<string>();
|
|
if (_hasGenericTypeSupport)
|
|
{
|
|
genericTypes.Add("DOT");
|
|
genericConstraints.Add(Function.GetGenericTypeConstraint());
|
|
}
|
|
|
|
if (_hasCustomStructParamSupport)
|
|
{
|
|
genericTypes.AddRange(_customStructParamTypes);
|
|
genericConstraints.AddRange(_customStructParamTypes.ConvertAll(paramType => $"MarshalledStruct<{paramType}>"));
|
|
}
|
|
|
|
string genericTypeString = string.Join(", ", genericTypes);
|
|
|
|
if (genericTypes.Count > 0)
|
|
{
|
|
builder.AppendLine($"{Modifiers}{returnType} {_functionName}<{genericTypeString}>({overload.ParamStringApiWithDefaults})");
|
|
builder.Indent();
|
|
foreach (var (genericType, constraint) in genericTypes.Zip(genericConstraints))
|
|
builder.AppendLine($"where {genericType} : {constraint}");
|
|
builder.UnIndent();
|
|
}
|
|
else
|
|
{
|
|
builder.AppendLine($"{Modifiers}{returnType} {_functionName}({overload.ParamStringApiWithDefaults})");
|
|
}
|
|
|
|
builder.OpenBrace();
|
|
overload.Translator?.ExportCppDefaultParameterAsLocalVariable(builder, overload.CSharpParamName, overload.CppDefaultValue, Function, overload.Parameter);
|
|
|
|
if (genericTypes.Count > 0)
|
|
{
|
|
builder.AppendLine($"{returnStatement}{_functionName}<{genericTypeString}>({overload.ParamsStringCall});");
|
|
}
|
|
else
|
|
{
|
|
builder.AppendLine($"{returnStatement}{_functionName}({overload.ParamsStringCall});");
|
|
}
|
|
builder.CloseBrace();
|
|
}
|
|
}
|
|
|
|
void ExportFunction(GeneratorStringBuilder builder)
|
|
{
|
|
builder.AppendLine();
|
|
ExportDeprecation(builder);
|
|
ExportSpecializationGetter(builder);
|
|
|
|
ExportSignature(builder, Modifiers);
|
|
|
|
builder.OpenBrace();
|
|
|
|
if (Throwing)
|
|
{
|
|
builder.AppendLine($"throw new InvalidOperationException(\"Function {Function.EngineName} cannot be called on a Blueprint-only implementer\");");
|
|
}
|
|
|
|
else if (BlueprintEvent)
|
|
{
|
|
builder.AppendLine($"if ({InstanceFunctionPtr} == IntPtr.Zero)");
|
|
builder.OpenBrace();
|
|
builder.AppendLine($"{InstanceFunctionPtr} = {ExporterCallbacks.UClassCallbacks}.CallGetNativeFunctionFromInstanceAndName(NativeObject, \"{Function.EngineName}\");");
|
|
builder.CloseBrace();
|
|
|
|
if (BlueprintImplementableEvent)
|
|
{
|
|
builder.AppendLine($"if (!{ExporterCallbacks.UFunctionCallbacks}.IsFunctionImplemented({InstanceFunctionPtr}))");
|
|
builder.OpenBrace();
|
|
builder.AppendLine($"throw new System.NotImplementedException(\"Tried calling {Function.Outer!.EngineName}.{_functionName} which is not implemented in C# or Blueprint!\");");
|
|
builder.CloseBrace();
|
|
}
|
|
|
|
ExportInvoke(builder, InstanceFunctionPtr);
|
|
}
|
|
else
|
|
{
|
|
ExportInvoke(builder);
|
|
}
|
|
|
|
builder.CloseBrace();
|
|
builder.AppendLine();
|
|
}
|
|
|
|
public void ExportInvoke(GeneratorStringBuilder builder, string functionPtr = "")
|
|
{
|
|
builder.BeginUnsafeBlock();
|
|
string nativeFunctionIntPtr = string.IsNullOrEmpty(functionPtr) ? NativeFunctionIntPtr : functionPtr;
|
|
|
|
if (!Function.HasParametersOrReturnValue())
|
|
{
|
|
if (string.IsNullOrEmpty(_customInvoke))
|
|
{
|
|
builder.AppendLine($"{_invokeFunction}({_invokeFirstArgument}, {nativeFunctionIntPtr}, {ScriptGeneratorUtilities.IntPtrZero}, {ScriptGeneratorUtilities.IntPtrZero});");
|
|
}
|
|
else
|
|
{
|
|
builder.AppendLine(_customInvoke);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_hasCustomStructParamSupport)
|
|
{
|
|
string genericTypes = string.Join(", ", _customStructParamTypes);
|
|
builder.AppendLine($"IntPtr Specialization = {Function.SourceName}_GetSpecialization<{genericTypes}>();");
|
|
builder.AppendStackAllocFunction($"{Function.SourceName}_ParamsSize<{genericTypes}>()",
|
|
"Specialization");
|
|
}
|
|
else
|
|
{
|
|
builder.AppendStackAllocFunction($"{Function.SourceName}_ParamsSize",
|
|
nativeFunctionIntPtr,
|
|
!BlittableFunction);
|
|
}
|
|
|
|
ForEachParameter((translator, parameter) =>
|
|
{
|
|
if (parameter.HasAllFlags(EPropertyFlags.ReturnParm))
|
|
{
|
|
return;
|
|
}
|
|
|
|
string propertyName = GetParameterName(parameter);
|
|
|
|
if (parameter.HasAllFlags(EPropertyFlags.ReferenceParm) || !parameter.HasAllFlags(EPropertyFlags.OutParm))
|
|
{
|
|
string offsetName = TryAddPrecedingCustomStructParams(parameter, parameter.GetOffsetVariableName());
|
|
translator.ExportToNative(builder, parameter, parameter.SourceName, "paramsBuffer", offsetName, propertyName);
|
|
}
|
|
});
|
|
|
|
builder.AppendLine();
|
|
|
|
if (string.IsNullOrEmpty(_customInvoke))
|
|
{
|
|
string invokedFunctionIntPtr = _hasCustomStructParamSupport ? "Specialization" : nativeFunctionIntPtr;
|
|
|
|
string returnValueAddressStr = Function.ReturnProperty != null
|
|
? $"paramsBuffer + {TryAddPrecedingCustomStructParams(Function.ReturnProperty, Function.ReturnProperty.GetOffsetVariableName())}"
|
|
: ScriptGeneratorUtilities.IntPtrZero;
|
|
|
|
builder.AppendLine($"{_invokeFunction}({_invokeFirstArgument}, {invokedFunctionIntPtr}, paramsBuffer, {returnValueAddressStr});");
|
|
}
|
|
else
|
|
{
|
|
builder.AppendLine(_customInvoke);
|
|
}
|
|
|
|
if (Function.ReturnProperty != null || Function.HasOutParams())
|
|
{
|
|
builder.AppendLine();
|
|
|
|
ForEachParameter((translator, parameter) =>
|
|
{
|
|
if (!parameter.HasAllFlags(EPropertyFlags.ReturnParm) &&
|
|
(parameter.HasAllFlags(EPropertyFlags.ConstParm) ||
|
|
!parameter.HasAllFlags(EPropertyFlags.OutParm)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
string marshalDestination;
|
|
if (parameter.HasAllFlags(EPropertyFlags.ReturnParm))
|
|
{
|
|
builder.AppendLine($"{ReturnValueTranslator!.GetManagedType(parameter)} returnValue;");
|
|
marshalDestination = "returnValue";
|
|
}
|
|
else
|
|
{
|
|
marshalDestination = MakeOutMarshalDestination(parameter, translator, builder);
|
|
}
|
|
|
|
string offsetName = TryAddPrecedingCustomStructParams(parameter, parameter.GetOffsetVariableName());
|
|
|
|
translator.ExportFromNative(builder,
|
|
parameter,
|
|
parameter.SourceName,
|
|
$"{marshalDestination} =",
|
|
"paramsBuffer",
|
|
offsetName,
|
|
true,
|
|
parameter.HasAllFlags(EPropertyFlags.ReferenceParm) &&
|
|
!parameter.HasAllFlags(EPropertyFlags.ReturnParm));
|
|
});
|
|
}
|
|
|
|
builder.AppendLine();
|
|
|
|
ForEachParameter((translator, parameter) =>
|
|
{
|
|
if (!parameter.HasAnyFlags(EPropertyFlags.ReturnParm | EPropertyFlags.OutParm))
|
|
{
|
|
translator.ExportCleanupMarshallingBuffer(builder, parameter, parameter.SourceName);
|
|
}
|
|
});
|
|
|
|
ExportReturnStatement(builder);
|
|
}
|
|
builder.EndUnsafeBlock();
|
|
}
|
|
|
|
protected virtual string MakeOutMarshalDestination(UhtProperty parameter, PropertyTranslator propertyTranslator, GeneratorStringBuilder builder)
|
|
{
|
|
return GetParameterName(parameter);
|
|
}
|
|
|
|
protected virtual void ExportReturnStatement(GeneratorStringBuilder builder)
|
|
{
|
|
if (Function.ReturnProperty != null)
|
|
{
|
|
builder.AppendLine("return returnValue;");
|
|
}
|
|
}
|
|
|
|
void ExportSignature(GeneratorStringBuilder builder, string protection)
|
|
{
|
|
builder.AppendTooltip(Function);
|
|
|
|
AttributeBuilder attributeBuilder = new AttributeBuilder(Function);
|
|
|
|
if (BlueprintEvent)
|
|
{
|
|
attributeBuilder.AddArgument("FunctionFlags.BlueprintEvent");
|
|
}
|
|
|
|
attributeBuilder.AddGeneratedTypeAttribute(Function);
|
|
|
|
if (_hasGenericTypeSupport)
|
|
{
|
|
if (Function.HasMetadata("DeterminesOutputType"))
|
|
{
|
|
attributeBuilder.AddAttribute("UMetaData");
|
|
attributeBuilder.AddArgument($"\"DeterminesOutputType\"");
|
|
attributeBuilder.AddArgument($"\"{Function.GetMetadata("DeterminesOutputType")}\"");
|
|
}
|
|
|
|
if (Function.HasMetadata("DynamicOutputParam"))
|
|
{
|
|
attributeBuilder.AddAttribute("UMetaData");
|
|
attributeBuilder.AddArgument($"\"DynamicOutputParam\"");
|
|
attributeBuilder.AddArgument($"\"{Function.GetMetadata("DynamicOutputParam")}\"");
|
|
}
|
|
}
|
|
|
|
if (_hasCustomStructParamSupport)
|
|
{
|
|
attributeBuilder.AddAttribute("UMetaData");
|
|
attributeBuilder.AddArgument($"\"CustomStructureParam\"");
|
|
attributeBuilder.AddArgument($"\"{Function.GetMetadata("CustomStructureParam")}\"");
|
|
}
|
|
|
|
attributeBuilder.Finish();
|
|
builder.AppendLine(attributeBuilder.ToString());
|
|
|
|
string returnType = Function.ReturnProperty != null
|
|
? ReturnValueTranslator!.GetManagedType(Function.ReturnProperty)
|
|
: "void";
|
|
|
|
List<string> genericTypes = new List<string>();
|
|
List<string> genericConstraints = new List<string>();
|
|
if (_hasGenericTypeSupport)
|
|
{
|
|
genericTypes.Add("DOT");
|
|
genericConstraints.Add(Function.GetGenericTypeConstraint());
|
|
}
|
|
|
|
if (_hasCustomStructParamSupport)
|
|
{
|
|
genericTypes.AddRange(_customStructParamTypes);
|
|
genericConstraints.AddRange(_customStructParamTypes.ConvertAll(paramType => $"MarshalledStruct<{paramType}>"));
|
|
}
|
|
|
|
if (genericTypes.Count > 0)
|
|
{
|
|
builder.AppendLine($"{protection}{returnType} {_functionName}<{string.Join(", ", genericTypes)}>({_paramStringApiWithDefaults})");
|
|
builder.Indent();
|
|
foreach (var (genericType, constraint) in genericTypes.Zip(genericConstraints))
|
|
builder.AppendLine($"where {genericType} : {constraint}");
|
|
builder.UnIndent();
|
|
}
|
|
else
|
|
{
|
|
builder.AppendLine($"{protection}{returnType} {_functionName}({_paramStringApiWithDefaults})");
|
|
}
|
|
}
|
|
|
|
|
|
void ExportDeprecation(GeneratorStringBuilder builder)
|
|
{
|
|
if (Function.HasMetadata("DeprecatedFunction"))
|
|
{
|
|
string deprecationMessage = Function.GetMetadata("DeprecationMessage");
|
|
if (deprecationMessage.Length == 0)
|
|
{
|
|
deprecationMessage = "This function is deprecated.";
|
|
}
|
|
else
|
|
{
|
|
// Remove nested quotes
|
|
deprecationMessage = deprecationMessage.Replace("\"", "");
|
|
}
|
|
builder.AppendLine($"[Obsolete(\"{Function.SourceName} is deprecated: {deprecationMessage}\")]");
|
|
}
|
|
}
|
|
|
|
void ExportSpecializationGetter(GeneratorStringBuilder builder)
|
|
{
|
|
if (_hasCustomStructParamSupport)
|
|
{
|
|
int customStructureParamCount = _customStructParamTypes.Count;
|
|
string dictionaryKey = customStructureParamCount == 1
|
|
? "IntPtr"
|
|
: $"({string.Join(", ", Enumerable.Repeat("IntPtr", customStructureParamCount))})";
|
|
builder.AppendLine($"static Dictionary<{dictionaryKey}, IntPtr> {Function.SourceName}_Specializations = new Dictionary<{dictionaryKey}, IntPtr>();");
|
|
builder.AppendLine($"static IntPtr {Function.SourceName}_GetSpecialization<{string.Join(", ", _customStructParamTypes)}>()");
|
|
builder.Indent();
|
|
foreach (string customStructParamType in _customStructParamTypes)
|
|
{
|
|
builder.AppendLine($"where {customStructParamType} : MarshalledStruct<{customStructParamType}>");
|
|
}
|
|
builder.UnIndent();
|
|
builder.OpenBrace();
|
|
builder.AppendLine("IntPtr specializationNativeFunction;");
|
|
List<string> nativeClassPtrs = _customStructParamTypes.ConvertAll(customStructParamType =>
|
|
$"{customStructParamType}.GetNativeClassPtr()");
|
|
string specializationKeyInitializer = nativeClassPtrs.Count == 1 ? nativeClassPtrs[0] : $"({string.Join(", ", nativeClassPtrs)})";
|
|
builder.AppendLine($"{dictionaryKey} specializationKey = {specializationKeyInitializer};");
|
|
builder.AppendLine($"if(!{Function.SourceName}_Specializations.TryGetValue(specializationKey, out specializationNativeFunction))");
|
|
builder.OpenBrace();
|
|
builder.BeginUnsafeBlock();
|
|
string customStructBufferInitializationList = customStructureParamCount == 1 ? "specializationKey" : string.Join(", ", Enumerable.Range(1, customStructureParamCount).ToList().ConvertAll(i => $"specializationKey.Item{i}"));
|
|
builder.AppendLine($"IntPtr* customStructBufferAllocation = stackalloc IntPtr[]{{{customStructBufferInitializationList}}};");
|
|
builder.AppendLine("IntPtr customStructBuffer = (IntPtr) customStructBufferAllocation;");
|
|
string nativeFunctionIntPtr = $"{Function.SourceName}_NativeFunction";
|
|
string customStructNativePropertiesIntPtr = $"{Function.SourceName}_CustomStructureNativeProperties";
|
|
builder.AppendLine($"fixed(nint* nativePropertyBuffer = {customStructNativePropertiesIntPtr})");
|
|
builder.OpenBrace();
|
|
builder.AppendLine($"specializationNativeFunction = {ExporterCallbacks.UFunctionCallbacks}.CallCreateNativeFunctionCustomStructSpecialization({nativeFunctionIntPtr}, (nint) nativePropertyBuffer, customStructBuffer);");
|
|
builder.CloseBrace();
|
|
builder.AppendLine($"{Function.SourceName}_Specializations.Add(specializationKey, specializationNativeFunction);");
|
|
builder.EndUnsafeBlock();
|
|
builder.CloseBrace();
|
|
builder.AppendLine("return specializationNativeFunction;");
|
|
builder.CloseBrace();
|
|
}
|
|
}
|
|
|
|
void DetermineProtectionMode()
|
|
{
|
|
switch (_protectionMode)
|
|
{
|
|
case EFunctionProtectionMode.UseUFunctionProtection:
|
|
if (Function.HasAnyFlags(EFunctionFlags.Public | EFunctionFlags.BlueprintCallable))
|
|
{
|
|
Modifiers = ScriptGeneratorUtilities.PublicKeyword;
|
|
}
|
|
else if (Function.HasAllFlags(EFunctionFlags.Protected) || Function.HasMetadata("BlueprintProtected"))
|
|
{
|
|
Modifiers = ScriptGeneratorUtilities.ProtectedKeyword;
|
|
}
|
|
else
|
|
{
|
|
Modifiers = ScriptGeneratorUtilities.PrivateKeyword;
|
|
}
|
|
break;
|
|
case EFunctionProtectionMode.OverrideWithInternal:
|
|
Modifiers = "internal ";
|
|
break;
|
|
}
|
|
}
|
|
|
|
string DetermineInvokeFunction()
|
|
{
|
|
string invokeFunction = ExporterCallbacks.UObjectCallbacks;
|
|
|
|
if (Function.HasAllFlags(EFunctionFlags.Static))
|
|
{
|
|
return invokeFunction + ".CallInvokeNativeStaticFunction";
|
|
}
|
|
|
|
if (Function.HasAllFlags(EFunctionFlags.Net))
|
|
{
|
|
return invokeFunction + ".CallInvokeNativeNetFunction";
|
|
}
|
|
|
|
if (Function.HasAllFlags(EFunctionFlags.HasOutParms) || Function.HasReturnProperty)
|
|
{
|
|
return invokeFunction + ".CallInvokeNativeFunctionOutParms";
|
|
}
|
|
|
|
return invokeFunction + ".CallInvokeNativeFunction";
|
|
}
|
|
|
|
public string TryAddPrecedingCustomStructParams(UhtProperty parameter, string name)
|
|
{
|
|
if (!_hasCustomStructParamSupport)
|
|
{
|
|
return name;
|
|
}
|
|
|
|
int precedingCustomStructParams = parameter.GetPrecedingCustomStructParams();
|
|
if (precedingCustomStructParams > 0)
|
|
{
|
|
return name + $"<{string.Join(", ", _customStructParamTypes.GetRange(0, precedingCustomStructParams))}>()";
|
|
}
|
|
|
|
return name;
|
|
}
|
|
}
|