diff --git a/Editor/Source/Editor/Windows/ProjectSettings/ProjectSettingsWindow.cpp b/Editor/Source/Editor/Windows/ProjectSettings/ProjectSettingsWindow.cpp index 89d2e991..db784af0 100644 --- a/Editor/Source/Editor/Windows/ProjectSettings/ProjectSettingsWindow.cpp +++ b/Editor/Source/Editor/Windows/ProjectSettings/ProjectSettingsWindow.cpp @@ -212,7 +212,7 @@ ProjectSettingsModuleWindow::ProjectSettingsModuleWindow(const std::string& inMo void ProjectSettingsModuleWindow::Draw() { - auto meta = entt::resolve(entt::hashed_string(Name.c_str())); + auto meta = entt::resolve(entt::hashed_string(("class " + Name).c_str())); auto instance = ModuleDB::Get().GetBaseImpl(Name).instance; for (auto [id, data] : meta.data()) { diff --git a/Nuake/Source/Nuake/Modules/ModuleDB.cpp b/Nuake/Source/Nuake/Modules/ModuleDB.cpp index f2329fbd..53f588f2 100644 --- a/Nuake/Source/Nuake/Modules/ModuleDB.cpp +++ b/Nuake/Source/Nuake/Modules/ModuleDB.cpp @@ -12,7 +12,7 @@ json ModuleDB::GenerateModuleAPI() json moduleData; moduleData["Name"] = name; - auto meta = entt::resolve(entt::hashed_string(name.c_str())); + auto meta = entt::resolve(entt::hashed_string(("class " + name).c_str())); int j = 0; for (auto [id, func] : meta.func()) diff --git a/Nuake/Source/Nuake/Modules/ModuleDB.h b/Nuake/Source/Nuake/Modules/ModuleDB.h index ffac004e..32bde48a 100644 --- a/Nuake/Source/Nuake/Modules/ModuleDB.h +++ b/Nuake/Source/Nuake/Modules/ModuleDB.h @@ -8,6 +8,7 @@ #include "Nuake/Core/GameState.h" #include "Nuake/Core/MulticastDelegate.h" #include "Nuake/Core/Object/Object.h" +#include "Nuake/Core/String.h" #include "Nuake/Scene/Scene.h" #include "Nuake/Scene/SceneSystems.h" @@ -110,7 +111,6 @@ class moduleName : public ModuleInstance \ { \ public: \ std::string Description = "No Description"; \ - entt::meta_factory ModuleFactory = entt::meta(); \ TypeNameMap TypeNames; \ \ std::map> FuncArgNames; \ @@ -205,22 +205,24 @@ namespace Nuake T& RegisterModule() { T* newInstance = new T(); + std::string unmangledName = Nuake::String::Split(typeid(T).name(), ' ')[1]; newInstance->instance = entt::resolve().construct(); - Modules[typeid(T).name()] = (ModuleInstance*)newInstance; - return *(T*)std::any_cast(Modules[typeid(T).name()]); + Modules[unmangledName] = (ModuleInstance*)newInstance; + return *(T*)std::any_cast(Modules[unmangledName]); } template T& GetModule() { const std::string_view typeName = typeid(T).name(); - if (!Modules.contains(typeName)) + std::string unmangledName = Nuake::String::Split(typeName)[1]; + if (!Modules.contains(unmangledName)) { assert(false && "Module not found."); return; } - return *(T*)std::any_cast(Modules[typeName]); + return *(T*)std::any_cast(Modules[unmangledName]); } ModuleInstance& GetBaseImpl(const std::string& moduleName) diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp index f21f6089..70500f0b 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp @@ -217,7 +217,7 @@ void VkRenderer::SelectGPU() std::string errMessage = "No GPU found who supports the required Vulkan extension: " + std::string(extension); errMessage += "\nConsider updating drivers."; Logger::Log(errMessage, "vulkan", CRITICAL); - OS::ShowMessageBox("Vulkan Error", errMessage); + //OS::ShowMessageBox("Vulkan Error", errMessage); } } diff --git a/NuakeNet/Source/Generated/AudioModule.cs b/NuakeNet/Source/Generated/AudioModule.cs new file mode 100644 index 00000000..1b7e24f4 --- /dev/null +++ b/NuakeNet/Source/Generated/AudioModule.cs @@ -0,0 +1,21 @@ +using System; +namespace Nuake +{ + public static class AudioModule + { + public static void SetVolume(float volume) + { + unsafe + { + Internals.AudioModuleSetVolumeICall(volume); + } + } + public static void SetMuted(bool muted) + { + unsafe + { + Internals.AudioModuleSetMutedICall(muted); + } + } + } +} diff --git a/NuakeNet/Source/Generated/ExampleModule.cs b/NuakeNet/Source/Generated/ExampleModule.cs new file mode 100644 index 00000000..2dc0a1ed --- /dev/null +++ b/NuakeNet/Source/Generated/ExampleModule.cs @@ -0,0 +1,21 @@ +using System; +namespace Nuake +{ + public static class ExampleModule + { + public static void ExampleFunction() + { + unsafe + { + Internals.ExampleModuleExampleFunctionICall(); + } + } + public static void ExampleModuleLog(string hi) + { + unsafe + { + Internals.ExampleModuleExampleModuleLogICall(hi); + } + } + } +} diff --git a/NuakeNet/Source/Generated/Internals.cs b/NuakeNet/Source/Generated/Internals.cs new file mode 100644 index 00000000..f55f2aaf --- /dev/null +++ b/NuakeNet/Source/Generated/Internals.cs @@ -0,0 +1,12 @@ +using Coral.Managed.Interop; +public class Internals +{ + // AudioModule + public static unsafe delegate* AudioModuleSetVolumeICall; + public static unsafe delegate* AudioModuleSetMutedICall; + + // ExampleModule + public static unsafe delegate* ExampleModuleExampleFunctionICall; + public static unsafe delegate* ExampleModuleExampleModuleLogICall; + +} diff --git a/NuakeNetGenerator/Source/Generator.cs b/NuakeNetGenerator/Source/Generator.cs new file mode 100644 index 00000000..18226c9d --- /dev/null +++ b/NuakeNetGenerator/Source/Generator.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +struct Arg +{ + public string Name { get; set; } + public string Type { get; set; } +} + +struct Function +{ + public string Name { get; set; } + public int NumArgs { get; set; } + public Arg[] Args { get; set; } + public string ReturnType { get; set; } +} + +struct Module +{ + public string Name { get; set; } + public Function[] Functions { get; set; } +} + +struct Bindings +{ + public Module[] Modules { get; set; } +} + +class Generator +{ + static string ConvertTypes(string type) + { + return type switch + { + "float" => "float", + "int" => "int", + "bool" => "bool", + "void" => "void", + "char" => "byte", + "string" => "NativeString" + }; + } + + static string GenerateInternals(Bindings bindings) + { + string generatedInternals = string.Empty; + + generatedInternals += "using Coral.Managed.Interop;\n"; + generatedInternals += "public class Internals\n"; + generatedInternals += "{\n"; + + foreach (var module in bindings.Modules) + { + generatedInternals += $" // {module.Name}\n"; + foreach (var function in module.Functions) + { + generatedInternals += $" public static unsafe delegate*<"; + + if (function.NumArgs > 0) + { + generatedInternals += $"{string.Join(", ", function.Args.Select(a => ConvertTypes(a.Type)))},"; + } + + generatedInternals += $"{function.ReturnType}>{module.Name}{function.Name}ICall;\n"; + } + + generatedInternals += "\n"; + } + + generatedInternals += "}\n"; + + return generatedInternals; + } + + static string GenerateModuleAPI(Module module) + { + string moduleApi = string.Empty; + moduleApi += "using System;\n"; + moduleApi += "namespace Nuake\n"; + moduleApi += "{\n"; + moduleApi += " public static class " + module.Name + "\n"; + moduleApi += " {\n"; + + foreach (Function func in module.Functions) + { + moduleApi += " public static " + func.ReturnType + " " + func.Name + "("; + if (func.NumArgs > 0) + { + moduleApi += string.Join(", ", func.Args.Select(a => a.Type + " " + a.Name)); + } + moduleApi += ")\n"; + moduleApi += " {\n"; + moduleApi += " unsafe\n"; + moduleApi += " {\n"; + if (func.ReturnType != "void") + { + moduleApi += $" return "; + } + moduleApi += $" Internals.{module.Name}{func.Name}ICall("; + if (func.NumArgs > 0) + { + moduleApi += string.Join(", ", func.Args.Select(a => a.Name)); + } + + moduleApi += ");\n"; + + moduleApi += " }\n"; + moduleApi += " }\n"; + + } + moduleApi += " }\n"; + moduleApi += "}\n"; + return moduleApi; + } + + struct FileToWrite + { + public string FileName { get; set; } + public string Content { get; set; } + } + + static void Main() + { + // Read file bindings.json + string json = File.ReadAllText("../../../../Editor/Build/Debug/Binaries/bindings.json"); + + // parse the json + Bindings bindings = System.Text.Json.JsonSerializer.Deserialize(json); + + List filesToWrite = new List(); + + string internals = GenerateInternals(bindings); + filesToWrite.Add(new FileToWrite + { + FileName = "Internals.cs", + Content = internals + }); + + Console.WriteLine("Generated Internals:\n"); + Console.WriteLine(internals); + + foreach (var module in bindings.Modules) + { + string fileName = module.Name + ".cs"; + Console.WriteLine("Generated " + fileName); + string api = GenerateModuleAPI(module); + Console.WriteLine(api); + + filesToWrite.Add(new FileToWrite + { + FileName = fileName, + Content = api + }); + } + + // WriteFiles + foreach (var module in filesToWrite) + { + string filePath = Path.Combine("../../../../NuakeNet/Source/Generated", module.FileName); + File.WriteAllText(filePath, module.Content); + Console.WriteLine($"Wrote {module.FileName} to {filePath}"); + } + } +} + + + + diff --git a/NuakeNetGenerator/premake5.lua b/NuakeNetGenerator/premake5.lua new file mode 100644 index 00000000..80d75d89 --- /dev/null +++ b/NuakeNetGenerator/premake5.lua @@ -0,0 +1,22 @@ +project "NuakeNetGenerator" + language "C#" + dotnetframework "net8.0" + kind "ConsoleApp" + clr "Unsafe" + + targetdir (binaryOutputDir) + objdir (intBinaryOutputDir) + debugdir (binaryOutputDir) + + -- Don't specify architecture here. (see https://github.com/premake/premake-core/issues/1758) + vsprops { + AppendTargetFrameworkToOutputPath = "false", + Nullable = "enable", + CopyLocalLockFileAssemblies = "true", + EnableDynamicLoading = "true" + } + + files + { + "Source/**.cs" + } diff --git a/premake5.lua b/premake5.lua index 942211ac..ca7b904a 100644 --- a/premake5.lua +++ b/premake5.lua @@ -83,4 +83,5 @@ include "Nuake/premake5.lua" include "Editor/premake5.lua" include "Runtime/premake5.lua" include "NuakeNet/premake5.lua" +include "NuakeNetGenerator/premake5.lua" include "EditorNet/premake5.lua"