167 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Diagnostics;
 | 
						|
using System.IO;
 | 
						|
using EpicGames.Core;
 | 
						|
using EpicGames.UHT.Parsers;
 | 
						|
using EpicGames.UHT.Tables;
 | 
						|
using EpicGames.UHT.Tokenizer;
 | 
						|
using EpicGames.UHT.Types;
 | 
						|
using EpicGames.UHT.Utils;
 | 
						|
using UnrealSharpScriptGenerator.Utilities;
 | 
						|
 | 
						|
namespace UnrealSharpScriptGenerator.Exporters;
 | 
						|
 | 
						|
[UnrealHeaderTool]
 | 
						|
public static class NativeBindExporter
 | 
						|
{
 | 
						|
    private struct NativeBindMethod
 | 
						|
    {
 | 
						|
        public readonly string MethodName;
 | 
						|
    
 | 
						|
        public NativeBindMethod(string methodName)
 | 
						|
        {
 | 
						|
            MethodName = methodName;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private class NativeBindTypeInfo
 | 
						|
    {
 | 
						|
        public readonly UhtType Type;
 | 
						|
        public readonly List<NativeBindMethod> Methods;
 | 
						|
 | 
						|
        public NativeBindTypeInfo(UhtType type, List<NativeBindMethod> methods)
 | 
						|
        {
 | 
						|
            Type = type;
 | 
						|
            Methods = methods;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private static readonly Dictionary<UhtHeaderFile, List<NativeBindTypeInfo>> NativeBindTypes = new();
 | 
						|
 | 
						|
    [UhtExporter(Name = "UnrealSharpNativeGlue", 
 | 
						|
        Description = "Exports Native Glue", 
 | 
						|
        Options = UhtExporterOptions.Default, 
 | 
						|
        ModuleName = "UnrealSharpCore", CppFilters = new string [] { "*.unrealsharp.gen.cpp" })]
 | 
						|
    private static void Main(IUhtExportFactory factory)
 | 
						|
    {
 | 
						|
        ExportBindMethods(factory);
 | 
						|
    }
 | 
						|
    
 | 
						|
    [UhtKeyword(Extends = UhtTableNames.Default, Keyword = "UNREALSHARP_FUNCTION")]
 | 
						|
    private static UhtParseResult UNREALSHARP_FUNCTIONKeyword(UhtParsingScope topScope, UhtParsingScope actionScope, ref UhtToken token)
 | 
						|
    {
 | 
						|
        return ParseUnrealSharpBind(topScope, actionScope, ref token);
 | 
						|
    }
 | 
						|
    
 | 
						|
    [UhtSpecifier(Extends = UhtTableNames.Function, ValueType = UhtSpecifierValueType.Legacy)]
 | 
						|
    private static void ScriptCallableSpecifier(UhtSpecifierContext specifierContext)
 | 
						|
    {
 | 
						|
        UhtFunction function = (UhtFunction)specifierContext.Type;
 | 
						|
        function.MetaData.Add("ScriptCallable", "");
 | 
						|
    }
 | 
						|
    
 | 
						|
    private static UhtParseResult ParseUnrealSharpBind(UhtParsingScope topScope, UhtParsingScope actionScope, ref UhtToken token)
 | 
						|
    {
 | 
						|
        UhtHeaderFile headerFile = topScope.ScopeType.HeaderFile;
 | 
						|
 | 
						|
        topScope.TokenReader.EnableRecording();
 | 
						|
        topScope.TokenReader
 | 
						|
            .Require('(')
 | 
						|
            .Require(')')
 | 
						|
            .Require("static")
 | 
						|
            .ConsumeUntil('(');
 | 
						|
 | 
						|
        int recordedTokensCount = topScope.TokenReader.RecordedTokens.Count;
 | 
						|
        string methodName = topScope.TokenReader.RecordedTokens[recordedTokensCount - 2].Value.ToString();
 | 
						|
        topScope.TokenReader.DisableRecording();
 | 
						|
        
 | 
						|
        NativeBindMethod methodInfo = new(methodName);
 | 
						|
        
 | 
						|
        if (!NativeBindTypes.TryGetValue(headerFile, out List<NativeBindTypeInfo>? value))
 | 
						|
        {
 | 
						|
            value = new List<NativeBindTypeInfo>();
 | 
						|
            NativeBindTypes.Add(headerFile, value);
 | 
						|
        }
 | 
						|
 | 
						|
        UhtType type = topScope.ScopeType;
 | 
						|
        
 | 
						|
        NativeBindTypeInfo? nativeBindTypeInfo = null;
 | 
						|
        foreach (NativeBindTypeInfo bindTypeInfo in value)
 | 
						|
        {
 | 
						|
            if (bindTypeInfo.Type != type)
 | 
						|
            {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            
 | 
						|
            nativeBindTypeInfo = bindTypeInfo;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        
 | 
						|
        if (nativeBindTypeInfo == null)
 | 
						|
        {
 | 
						|
            nativeBindTypeInfo = new NativeBindTypeInfo(type, new List<NativeBindMethod>());
 | 
						|
            value.Add(nativeBindTypeInfo);
 | 
						|
        }
 | 
						|
        
 | 
						|
        nativeBindTypeInfo.Methods.Add(methodInfo);
 | 
						|
        
 | 
						|
        return UhtParseResult.Handled;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static void ExportBindMethods(IUhtExportFactory factory)
 | 
						|
    {
 | 
						|
        foreach (KeyValuePair<UhtHeaderFile, List<NativeBindTypeInfo>> bindMethod in NativeBindTypes)
 | 
						|
        {
 | 
						|
            UhtHeaderFile headerFile = bindMethod.Key;
 | 
						|
            List<NativeBindTypeInfo> containingTypesInHeader = bindMethod.Value;
 | 
						|
            
 | 
						|
            GeneratorStringBuilder builder = new();
 | 
						|
            builder.AppendLine("#include \"UnrealSharpBinds.h\"");
 | 
						|
            builder.AppendLine($"#include \"{headerFile.FilePath}\"");
 | 
						|
            builder.AppendLine();
 | 
						|
            
 | 
						|
            foreach (NativeBindTypeInfo containingType in containingTypesInHeader)
 | 
						|
            {
 | 
						|
                UhtType topType = containingType.Type;
 | 
						|
                List<NativeBindMethod> methods = containingType.Methods;
 | 
						|
                
 | 
						|
                string typeName = $"Z_Construct_U{topType.EngineClassName}_UnrealSharp_Binds_" + topType.SourceName;
 | 
						|
                builder.Append($"struct {typeName}");
 | 
						|
            
 | 
						|
                builder.OpenBrace();
 | 
						|
            
 | 
						|
                foreach (NativeBindMethod method in methods)
 | 
						|
                {
 | 
						|
                    builder.AppendLine($"static const FCSExportedFunction UnrealSharpBind_{method.MethodName};");
 | 
						|
                }
 | 
						|
            
 | 
						|
                builder.CloseBrace();
 | 
						|
                builder.Append(";");
 | 
						|
            
 | 
						|
                foreach (NativeBindMethod method in methods)
 | 
						|
                {
 | 
						|
                    string functionReference = $"{topType.SourceName}::{method.MethodName}";
 | 
						|
                    builder.AppendLine($"const FCSExportedFunction {typeName}::UnrealSharpBind_{method.MethodName}");
 | 
						|
                    builder.Append($" = FCSExportedFunction(\"{topType.EngineName}\", \"{method.MethodName}\", (void*)&{functionReference}, GetFunctionSize({functionReference}));");
 | 
						|
                }
 | 
						|
                
 | 
						|
                builder.AppendLine();
 | 
						|
                builder.AppendLine();
 | 
						|
            }
 | 
						|
 | 
						|
            UHTManifest.Module manifestModule;
 | 
						|
            #if UE_5_5_OR_LATER
 | 
						|
            manifestModule = headerFile.Module.Module;
 | 
						|
            #else
 | 
						|
            manifestModule= headerFile.Package.GetModule();
 | 
						|
            #endif
 | 
						|
            
 | 
						|
            string outputDirectory = manifestModule.OutputDirectory;
 | 
						|
            string fileName = headerFile.FileNameWithoutExtension + ".unrealsharp.gen.cpp";
 | 
						|
            string filePath = Path.Combine(outputDirectory, fileName);
 | 
						|
            
 | 
						|
            factory.CommitOutput(filePath, builder.ToString());
 | 
						|
        }
 | 
						|
    }
 | 
						|
} |