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