308 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			308 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 
								 | 
							
								using System;
							 | 
						|||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						|||
| 
								 | 
							
								using EpicGames.Core;
							 | 
						|||
| 
								 | 
							
								using EpicGames.UHT.Types;
							 | 
						|||
| 
								 | 
							
								using UnrealSharpScriptGenerator.PropertyTranslators;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								namespace UnrealSharpScriptGenerator.Utilities;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								public enum ENameType
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    Parameter,
							 | 
						|||
| 
								 | 
							
								    Property,
							 | 
						|||
| 
								 | 
							
								    Struct,
							 | 
						|||
| 
								 | 
							
								    Function
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								public static class NameMapper
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    private static readonly List<string> ReservedKeywords = new()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue",
							 | 
						|||
| 
								 | 
							
								        "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", 
							 | 
						|||
| 
								 | 
							
								        "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock",
							 | 
						|||
| 
								 | 
							
								        "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", "private", "protected", "public", 
							 | 
						|||
| 
								 | 
							
								        "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", 
							 | 
						|||
| 
								 | 
							
								        "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual",
							 | 
						|||
| 
								 | 
							
								        "void", "volatile", "while", "System"
							 | 
						|||
| 
								 | 
							
								    };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    public static string GetParameterName(this UhtProperty property)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        string scriptName = ScriptifyName(property.GetScriptName(), ENameType.Parameter);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (property.Outer is not UhtFunction function)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            return scriptName;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        foreach (UhtProperty exportedProperty in function.Properties)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            if (exportedProperty.HasAllFlags(EPropertyFlags.ReturnParm))
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                continue;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            
							 | 
						|||
| 
								 | 
							
								            if (exportedProperty != property && scriptName == ScriptifyName(exportedProperty.GetScriptName(), ENameType.Parameter))
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                return PascalToCamelCase(exportedProperty.SourceName);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        return scriptName;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    public static string GetPropertyName(this UhtProperty property)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        string propertyName = ScriptifyName(property.GetScriptName(), ENameType.Property);
							 | 
						|||
| 
								 | 
							
								        if (property.Outer!.SourceName == propertyName || IsAKeyword(propertyName))
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            propertyName = $"K2_{propertyName}";
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return TryResolveConflictingName(property, propertyName);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    public static string GetStructName(this UhtType type)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (type.EngineType is UhtEngineType.Interface or UhtEngineType.NativeInterface || type == Program.Factory.Session.UInterface)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            return "I" + type.EngineName;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        if (type is UhtClass uhtClass && uhtClass.IsChildOf(Program.BlueprintFunctionLibrary))
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            return type.GetScriptName();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        return type.SourceName;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    public static string ExportGetAssemblyName(this UhtType type)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        string structName = type.GetStructName();
							 | 
						|||
| 
								 | 
							
								        return $"typeof({structName}).GetAssemblyName()";
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    public static string GetFullManagedName(this UhtType type)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return $"{type.GetNamespace()}.{type.GetStructName()}";
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    static readonly string[] MetadataKeys = { "ScriptName", "ScriptMethod", "DisplayName" };
							 | 
						|||
| 
								 | 
							
								    public static string GetScriptName(this UhtType type)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        bool OnlyContainsLetters(string str)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            foreach (char c in str)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (!char.IsLetter(c) && !char.IsWhiteSpace(c))
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    return false;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            return true;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        foreach (var key in MetadataKeys)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            string value = type.GetMetadata(key);
							 | 
						|||
| 
								 | 
							
								            
							 | 
						|||
| 
								 | 
							
								            if (string.IsNullOrEmpty(value) || !OnlyContainsLetters(value))
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                continue;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            
							 | 
						|||
| 
								 | 
							
								            // Try remove whitespace from the value
							 | 
						|||
| 
								 | 
							
								            value = value.Replace(" ", "");
							 | 
						|||
| 
								 | 
							
								            return value;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        return type.SourceName;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    public static string GetNamespace(this UhtType typeObj)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        UhtType outer = typeObj;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        string packageShortName = "";
							 | 
						|||
| 
								 | 
							
								        if (outer is UhtPackage package)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            packageShortName = package.GetShortName();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        else
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            while (outer.Outer != null)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                outer = outer.Outer;
							 | 
						|||
| 
								 | 
							
								            
							 | 
						|||
| 
								 | 
							
								                if (outer is UhtPackage header)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    packageShortName = header.Package.GetShortName();
							 | 
						|||
| 
								 | 
							
								                    break;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        if (string.IsNullOrEmpty(packageShortName))
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            throw new Exception($"Failed to find package name for {typeObj}");
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        return $"UnrealSharp.{packageShortName}";
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    public static string GetFunctionName(this UhtFunction function)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        string functionName = function.GetScriptName();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (function.HasAnyFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate))
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            functionName = DelegateBasePropertyTranslator.GetDelegateName(function);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        if (functionName.StartsWith("K2_") || functionName.StartsWith("BP_"))
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            functionName = functionName.Substring(3);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (function.IsInterfaceFunction() && functionName.EndsWith("_Implementation"))
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            functionName = functionName.Substring(0, functionName.Length - 15);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (function.Outer is not UhtClass)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            return functionName;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        functionName = TryResolveConflictingName(function, functionName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        return functionName;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    public static string TryResolveConflictingName(UhtType type, string scriptName)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        UhtType outer = type.Outer!;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        bool IsConflictingWithChild(List<UhtType> children)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            foreach (UhtType child in children)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (child == type)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    continue;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            
							 | 
						|||
| 
								 | 
							
								                if (child is UhtProperty property)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    if (scriptName == ScriptifyName(property.GetScriptName(), ENameType.Property))
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        return true;
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            
							 | 
						|||
| 
								 | 
							
								                if (child is UhtFunction function)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    if (scriptName == ScriptifyName(function.GetScriptName(), ENameType.Function))
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        return true;
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            return false;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        bool isConflicting = IsConflictingWithChild(outer.Children);
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        if (!isConflicting && outer is UhtClass outerClass)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            List<UhtClass> classInterfaces = outerClass.GetInterfaces();
							 | 
						|||
| 
								 | 
							
								            foreach (UhtClass classInterface in classInterfaces)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (classInterface.AlternateObject is not UhtClass interfaceClass)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    continue;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                UhtFunction? function = interfaceClass.FindFunctionByName(scriptName, (uhtFunction, s) => uhtFunction.GetFunctionName() == s);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                if (function != null && type is UhtFunction typeAsFunction)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    if (function.HasSameSignature(typeAsFunction))
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        continue;
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                    
							 | 
						|||
| 
								 | 
							
								                    isConflicting = true;
							 | 
						|||
| 
								 | 
							
								                    break;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        return isConflicting ? type.EngineName : scriptName;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    public static string ScriptifyName(string engineName, ENameType nameType)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        string strippedName = engineName;
							 | 
						|||
| 
								 | 
							
								        switch (nameType)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            case ENameType.Parameter:
							 | 
						|||
| 
								 | 
							
								                strippedName = StripPropertyPrefix(strippedName);
							 | 
						|||
| 
								 | 
							
								                strippedName = PascalToCamelCase(strippedName);
							 | 
						|||
| 
								 | 
							
								                break;
							 | 
						|||
| 
								 | 
							
								            case ENameType.Property:
							 | 
						|||
| 
								 | 
							
								                strippedName = StripPropertyPrefix(strippedName);
							 | 
						|||
| 
								 | 
							
								                break;
							 | 
						|||
| 
								 | 
							
								            case ENameType.Struct:
							 | 
						|||
| 
								 | 
							
								                break;
							 | 
						|||
| 
								 | 
							
								            case ENameType.Function:
							 | 
						|||
| 
								 | 
							
								                break;
							 | 
						|||
| 
								 | 
							
								            default:
							 | 
						|||
| 
								 | 
							
								                throw new ArgumentOutOfRangeException(nameof(nameType), nameType, null);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        return EscapeKeywords(strippedName);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    public static string StripPropertyPrefix(string inName)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        int nameOffset = 0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        while (true)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            // Strip the "b" prefix from bool names
							 | 
						|||
| 
								 | 
							
								            if (inName.Length - nameOffset >= 2 && inName[nameOffset] == 'b' && char.IsUpper(inName[nameOffset + 1]))
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                nameOffset += 1;
							 | 
						|||
| 
								 | 
							
								                continue;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            // Strip the "In" prefix from names
							 | 
						|||
| 
								 | 
							
								            if (inName.Length - nameOffset >= 3 && inName[nameOffset] == 'I' && inName[nameOffset + 1] == 'n' && char.IsUpper(inName[nameOffset + 2]))
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                nameOffset += 2;
							 | 
						|||
| 
								 | 
							
								                continue;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            break;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        return nameOffset != 0 ? inName.Substring(nameOffset) : inName;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    public static string EscapeKeywords(string name)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return IsAKeyword(name) || char.IsDigit(name[0]) ? $"_{name}" : name;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    private static bool IsAKeyword(string name)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return ReservedKeywords.Contains(name);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    private static string PascalToCamelCase(string name)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return char.ToLowerInvariant(name[0]) + name.Substring(1);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 |