@ -0,0 +1,167 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user