306 lines
10 KiB
C#
306 lines
10 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using EpicGames.Core;
|
|||
|
|
using EpicGames.UHT.Types;
|
|||
|
|
using UnrealSharpScriptGenerator.Exporters;
|
|||
|
|
using UnrealSharpScriptGenerator.PropertyTranslators;
|
|||
|
|
|
|||
|
|
namespace UnrealSharpScriptGenerator.Utilities;
|
|||
|
|
|
|||
|
|
public static class FunctionUtilities
|
|||
|
|
{
|
|||
|
|
public static bool HasAnyFlags(this UhtFunction function, EFunctionFlags flags)
|
|||
|
|
{
|
|||
|
|
return (function.FunctionFlags & flags) != 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool HasAllFlags(this UhtFunction function, EFunctionFlags flags)
|
|||
|
|
{
|
|||
|
|
return (function.FunctionFlags & flags) == flags;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool IsInterfaceFunction(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
if (function.Outer is not UhtClass classOwner)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (classOwner.HasAnyFlags(EClassFlags.Interface))
|
|||
|
|
{
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
string sourceName;
|
|||
|
|
if (function.SourceName.EndsWith("_Implementation"))
|
|||
|
|
{
|
|||
|
|
sourceName = function.SourceName.Substring(0, function.SourceName.Length - 15);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
sourceName = function.SourceName;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UhtClass? currentClass = classOwner;
|
|||
|
|
while (currentClass != null)
|
|||
|
|
{
|
|||
|
|
foreach (UhtClass currentInterface in currentClass.GetInterfaces())
|
|||
|
|
{
|
|||
|
|
UhtClass? interfaceClass = currentInterface.GetInterfaceAlternateClass();
|
|||
|
|
if (interfaceClass != null && interfaceClass.FindFunctionByName(sourceName) != null)
|
|||
|
|
{
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
currentClass = currentClass.Super as UhtClass;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool HasOutParams(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
// Multicast delegates can have out params, but the UFunction flag isn't set.
|
|||
|
|
foreach (UhtProperty param in function.Properties)
|
|||
|
|
{
|
|||
|
|
if (param.HasAnyFlags(EPropertyFlags.OutParm))
|
|||
|
|
{
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool HasParametersOrReturnValue(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
return function.HasParameters || function.ReturnProperty != null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static string GetNativeFunctionName(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
return $"{function.SourceName}_NativeFunction";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool HasSameSignature(this UhtFunction function, UhtFunction otherFunction)
|
|||
|
|
{
|
|||
|
|
if (function.Children.Count != otherFunction.Children.Count)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int i = 0; i < function.Children.Count; i++)
|
|||
|
|
{
|
|||
|
|
UhtProperty param = (UhtProperty) function.Children[i];
|
|||
|
|
UhtProperty otherParam = (UhtProperty) otherFunction.Children[i];
|
|||
|
|
if (!param.IsSameType(otherParam))
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool IsAutocast(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
if (!function.FunctionFlags.HasAllFlags(EFunctionFlags.Static) || function.ReturnProperty == null || function.Children.Count != 2)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (function.Properties.First() is not UhtStructProperty)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// These will be interfaces in C#, which implicit conversion doesn't work for.
|
|||
|
|
// TODO: Support these in the future.
|
|||
|
|
UhtProperty returnProperty = function.ReturnProperty!;
|
|||
|
|
if (returnProperty is UhtArrayProperty or UhtSetProperty or UhtMapProperty)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (function.HasMetadata("BlueprintAutocast"))
|
|||
|
|
{
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
string sourceName = function.SourceName;
|
|||
|
|
return sourceName.StartsWith("Conv_", StringComparison.OrdinalIgnoreCase) || sourceName.StartsWith("To");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static string GetBlueprintAutocastName(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
int toTypeIndex = function.SourceName.IndexOf("Conv_", StringComparison.Ordinal);
|
|||
|
|
return toTypeIndex == -1 ? function.SourceName : function.SourceName.Substring(toTypeIndex + 5);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static bool IsBlueprintAccessor(this UhtFunction function, string accessorType, Func<UhtProperty, UhtFunction?> getBlueprintAccessor)
|
|||
|
|
{
|
|||
|
|
if (function.Properties.Count() != 1 )
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (function.HasMetadata(accessorType))
|
|||
|
|
{
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (function.Outer is not UhtClass classObj)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
foreach (UhtProperty property in classObj.Properties)
|
|||
|
|
{
|
|||
|
|
if (function != getBlueprintAccessor(property)! || !function.VerifyBlueprintAccessor(property))
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool VerifyBlueprintAccessor(this UhtFunction function, UhtProperty property)
|
|||
|
|
{
|
|||
|
|
if (!function.Properties.Any() || function.Properties.Count() != 1)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UhtProperty firstProperty = function.Properties.First();
|
|||
|
|
return firstProperty.IsSameType(property);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool IsNativeAccessor(this UhtFunction function, GetterSetterMode accessorType)
|
|||
|
|
{
|
|||
|
|
UhtClass classObj = (function.Outer as UhtClass)!;
|
|||
|
|
foreach (UhtProperty property in classObj.Properties)
|
|||
|
|
{
|
|||
|
|
if (accessorType + property.EngineName == function.SourceName)
|
|||
|
|
{
|
|||
|
|
switch (accessorType)
|
|||
|
|
{
|
|||
|
|
case GetterSetterMode.Get:
|
|||
|
|
return property.HasNativeGetter();
|
|||
|
|
case GetterSetterMode.Set:
|
|||
|
|
return property.HasNativeSetter();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool IsAnyGetter(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
if (function.Properties.Count() != 1)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return function.IsBlueprintAccessor("BlueprintGetter", property => property.GetBlueprintGetter())
|
|||
|
|
|| function.IsNativeAccessor(GetterSetterMode.Get);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool IsAnySetter(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
if (function.Properties.Count() != 1)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return function.IsBlueprintAccessor("BlueprintSetter", property => property.GetBlueprintSetter())
|
|||
|
|
|| function.IsNativeAccessor(GetterSetterMode.Set);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool HasGenericTypeSupport(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
if (!function.HasMetadata("DeterminesOutputType")) return false;
|
|||
|
|
|
|||
|
|
var propertyDOTEngineName = function.GetMetadata("DeterminesOutputType");
|
|||
|
|
|
|||
|
|
var propertyDeterminingOutputType = function.Properties
|
|||
|
|
.Where(p => p.EngineName == propertyDOTEngineName)
|
|||
|
|
.FirstOrDefault();
|
|||
|
|
|
|||
|
|
if (propertyDeterminingOutputType == null) return false;
|
|||
|
|
|
|||
|
|
PropertyTranslator dotParamTranslator = PropertyTranslatorManager.GetTranslator(propertyDeterminingOutputType)!;
|
|||
|
|
if (!dotParamTranslator.CanSupportGenericType(propertyDeterminingOutputType)) return false;
|
|||
|
|
|
|||
|
|
if (function.HasMetadata("DynamicOutputParam"))
|
|||
|
|
{
|
|||
|
|
var propertyDynamicOutputParam = function.Properties
|
|||
|
|
.Where(p => p.EngineName == function.GetMetadata("DynamicOutputParam"))
|
|||
|
|
.FirstOrDefault();
|
|||
|
|
|
|||
|
|
if (propertyDynamicOutputParam == null) return false;
|
|||
|
|
|
|||
|
|
if (propertyDeterminingOutputType!.GetGenericManagedType() != propertyDynamicOutputParam.GetGenericManagedType()) return false;
|
|||
|
|
|
|||
|
|
PropertyTranslator dopParamTranslator = PropertyTranslatorManager.GetTranslator(propertyDynamicOutputParam)!;
|
|||
|
|
return dopParamTranslator.CanSupportGenericType(propertyDynamicOutputParam);
|
|||
|
|
}
|
|||
|
|
else if (function.HasReturnProperty)
|
|||
|
|
{
|
|||
|
|
PropertyTranslator returnParamTranslator = PropertyTranslatorManager.GetTranslator(function.ReturnProperty!)!;
|
|||
|
|
return returnParamTranslator.CanSupportGenericType(function.ReturnProperty!);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static string GetGenericTypeConstraint(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
if (!function.HasMetadata("DeterminesOutputType")) return string.Empty;
|
|||
|
|
|
|||
|
|
var propertyDeterminingOutputType = function.Properties
|
|||
|
|
.Where(p => p.EngineName == function.GetMetadata("DeterminesOutputType"))
|
|||
|
|
.FirstOrDefault();
|
|||
|
|
|
|||
|
|
return propertyDeterminingOutputType?.GetGenericManagedType() ?? string.Empty;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool HasCustomStructParamSupport(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
if (!function.HasMetadata("CustomStructureParam")) return false;
|
|||
|
|
|
|||
|
|
var customStructParams = function.GetCustomStructParams();
|
|||
|
|
return customStructParams.All(customParamName =>
|
|||
|
|
function.Properties.Count(param => param.EngineName == customParamName) == 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static List<string> GetCustomStructParams(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
if (!function.HasMetadata("CustomStructureParam")) return new List<string>();
|
|||
|
|
|
|||
|
|
return function.GetMetadata("CustomStructureParam").Split(",").ToList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static int GetCustomStructParamCount(this UhtFunction function) => function.GetCustomStructParams().Count;
|
|||
|
|
|
|||
|
|
public static List<string> GetCustomStructParamTypes(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
if (!function.HasMetadata("CustomStructureParam")) return new List<string>();
|
|||
|
|
int paramCount = function.GetCustomStructParamCount();
|
|||
|
|
if (paramCount == 1) return new List<string> { "CSP" };
|
|||
|
|
return Enumerable.Range(0, paramCount).ToList().ConvertAll(i => $"CSP{i}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool IsBlueprintNativeEvent(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
return function.HasAllFlags(EFunctionFlags.BlueprintEvent | EFunctionFlags.Native);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool IsBlueprintImplementableEvent(this UhtFunction function)
|
|||
|
|
{
|
|||
|
|
return function.HasAllFlags(EFunctionFlags.BlueprintEvent) && !function.HasAllFlags(EFunctionFlags.Native);
|
|||
|
|
}
|
|||
|
|
}
|