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