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);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 |