mirror of
https://github.com/antopilo/Nuake.git
synced 2026-09-15 20:08:54 +03:00
Module reflection system
This commit is contained in:
@@ -2,12 +2,59 @@
|
||||
#include "AudioSceneSystem.h"
|
||||
|
||||
#include "Nuake/Scene/SceneSystems.h"
|
||||
#include "Nuake/Modules/ModuleDB.h"
|
||||
#include <Nuake/Core/Logger.h>
|
||||
|
||||
void PlayAudio(int id, float volume)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void StopAudio()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NUAKEMODULE(AudioModule)
|
||||
void AudioModule_Startup()
|
||||
{
|
||||
using namespace Nuake;
|
||||
|
||||
SceneSystemDB::Get().RegisterSceneSystem<AudioModule::AudioSystem>();
|
||||
auto& module = ModuleDB::Get().RegisterModule<AudioModule>();
|
||||
module.Description = "Core audio module.";
|
||||
|
||||
module.BindFunction<PlayAudio>("PlayAudio", "id", "volume");
|
||||
module.BindFunction<StopAudio>("StopAudio");
|
||||
|
||||
Logger::Log("AudioModule exposed API:", "Module", VERBOSE);
|
||||
|
||||
auto reflection = module.Resolve();
|
||||
for (auto [id, func] : reflection.func())
|
||||
{
|
||||
const std::string_view returnType = func.ret().info().name();
|
||||
const std::string_view funcName = module.GetTypeName(id);
|
||||
|
||||
std::string msg = std::string(returnType) + " " + std::string(funcName) + "(";
|
||||
auto argNames = module.GetFuncArgNames(id);
|
||||
std::vector<std::string_view> args;
|
||||
for (int i = 0; i < func.arity(); i++)
|
||||
{
|
||||
const std::string argType = std::string(func.arg(i).info().name());
|
||||
args.push_back(argType);
|
||||
|
||||
msg += argType + " " + argNames[i];
|
||||
|
||||
if (i < func.arity() - 1)
|
||||
{
|
||||
msg += ", ";
|
||||
}
|
||||
}
|
||||
msg += ")";
|
||||
|
||||
Logger::Log(msg, "", VERBOSE);
|
||||
}
|
||||
|
||||
SceneSystemDB::Get().RegisterSceneSystem<Audio::AudioSystem>();
|
||||
}
|
||||
|
||||
void AudioModule_Shutdown()
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <future>
|
||||
|
||||
namespace AudioModule
|
||||
namespace Audio
|
||||
{
|
||||
using namespace Nuake;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "Nuake/Scene/Systems/System.h"
|
||||
|
||||
namespace AudioModule
|
||||
namespace Audio
|
||||
{
|
||||
using namespace Nuake;
|
||||
|
||||
|
||||
@@ -1,7 +1,83 @@
|
||||
#include "ExampleModule.h"
|
||||
|
||||
#include "Nuake/Modules/ModuleDB.h"
|
||||
|
||||
#include "Nuake/Core/Logger.h"
|
||||
|
||||
#include "Nuake/Resource/Serializer/ComponentSerializer.h"
|
||||
#include "Nuake/Scene/Components/AudioEmitterComponent.h"
|
||||
#include "Nuake/Scene/Components/LightComponent.h"
|
||||
#include "Nuake/Scene/Components/Component.h"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
#include "Thirdparty/entt/src/entt/meta/meta.hpp"
|
||||
#include "Thirdparty/entt/src/entt/core/hashed_string.hpp"
|
||||
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
class MyModuleComponent : public Component
|
||||
{
|
||||
NUAKECOMPONENT(MyModuleComponent, "My custom component")
|
||||
|
||||
static void InitializeComponentClass()
|
||||
{
|
||||
BindComponentField<&MyModuleComponent::MyFloat>("MyFloat", "My Float");
|
||||
}
|
||||
|
||||
public:
|
||||
float MyFloat = 1.0f;
|
||||
};
|
||||
}
|
||||
|
||||
void ExampleFunction() { }
|
||||
|
||||
void ExampleModuleLog(const std::string& hi)
|
||||
{
|
||||
Nuake::Logger::Log(hi, "ExampleModule", Nuake::VERBOSE);
|
||||
}
|
||||
|
||||
NUAKEMODULE(ExampleModule)
|
||||
void ExampleModule_Startup()
|
||||
{
|
||||
using namespace Nuake;
|
||||
|
||||
auto& module = ModuleDB::Get().RegisterModule<ExampleModule>();
|
||||
module.Description = "This is an example module";
|
||||
|
||||
// This is to expose functions to the rest of the engine
|
||||
module.BindFunction<ExampleFunction>("ExampleFunction");
|
||||
module.BindFunction<ExampleModuleLog>("ExampleModuleLog", "hi");
|
||||
|
||||
Logger::Log("ExampleModule exposed API:", "Module", VERBOSE);
|
||||
|
||||
auto reflection = module.Resolve();
|
||||
for (auto [id, func] : reflection.func())
|
||||
{
|
||||
const std::string_view returnType = func.ret().info().name();
|
||||
const std::string_view funcName = module.GetTypeName(id);
|
||||
|
||||
std::string msg = std::string(returnType) + " " + std::string(funcName) + "(";
|
||||
|
||||
auto argNames = module.GetFuncArgNames(id);
|
||||
std::vector<std::string_view> args;
|
||||
for (int i = 0; i < func.arity(); i++)
|
||||
{
|
||||
const std::string argType = std::string(func.arg(i).info().name());
|
||||
args.push_back(argType);
|
||||
|
||||
msg += argType + " " + argNames[i];
|
||||
|
||||
if (i < func.arity() - 1)
|
||||
{
|
||||
msg += ", ";
|
||||
}
|
||||
}
|
||||
msg += ")";
|
||||
|
||||
Logger::Log(msg, "", VERBOSE);
|
||||
}
|
||||
|
||||
// This is where you would initialize your module
|
||||
// This function is called when the engine starts up
|
||||
|
||||
@@ -10,8 +86,27 @@ void ExampleModule_Startup()
|
||||
|
||||
// You can register custom asset bakers to support custom formats
|
||||
// Example: See Assimp Module for reference
|
||||
using namespace Nuake;
|
||||
MyModuleComponent::InternalInitializeClass();
|
||||
|
||||
AudioEmitterComponent component;
|
||||
LightComponent lightComponent;
|
||||
|
||||
ComponentSerializer serializer;
|
||||
|
||||
json jsonData = serializer.Serialize(component);
|
||||
json jsonDataOG = component.Serialize();
|
||||
//Logger::Log("Serialized reflected component: " + jsonData.dump(4), "ExampleModule", VERBOSE);
|
||||
//Logger::Log("Serialized original component: " + jsonDataOG.dump(4), "ExampleModule", VERBOSE);
|
||||
|
||||
jsonData = serializer.Serialize(lightComponent);
|
||||
jsonDataOG = lightComponent.Serialize();
|
||||
//Logger::Log("Serialized reflected component: " + jsonData.dump(4), "ExampleModule", VERBOSE);
|
||||
//Logger::Log("Serialized original component: " + jsonDataOG.dump(4), "ExampleModule", VERBOSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ExampleModule_Shutdown()
|
||||
{
|
||||
|
||||
|
||||
100
Nuake/Source/Nuake/Modules/ModuleDB.h
Normal file
100
Nuake/Source/Nuake/Modules/ModuleDB.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <any>
|
||||
#include <vector>
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
#define NUAKEMODULE(name) \
|
||||
using TypeNameMap = std::map<entt::id_type, std::string>; \
|
||||
\
|
||||
struct name \
|
||||
{ \
|
||||
const std::string Name = #name; \
|
||||
std::string Description = "No Description"; \
|
||||
entt::meta_factory<name> ModuleFactory = entt::meta<name>(); \
|
||||
TypeNameMap TypeNames; \
|
||||
\
|
||||
std::map<entt::id_type, std::vector<std::string>> FuncArgNames; \
|
||||
\
|
||||
template<auto T, typename... Args> \
|
||||
inline name& BindFunction(const std::string& name, Args... argNames) \
|
||||
{ \
|
||||
entt::id_type typeId = entt::hashed_string(name.c_str()); \
|
||||
TypeNames[typeId] = name; \
|
||||
FuncArgNames[typeId] = { argNames ... }; \
|
||||
ModuleFactory.func<T>(typeId); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
auto Resolve() \
|
||||
{ \
|
||||
return entt::resolve<name>(); \
|
||||
} \
|
||||
\
|
||||
std::vector<std::string> GetFuncArgNames(entt::id_type id) \
|
||||
{ \
|
||||
return FuncArgNames[id]; \
|
||||
} \
|
||||
\
|
||||
std::vector<std::string> GetAllFuncNames() \
|
||||
{\
|
||||
std::vector<std::string> names; \
|
||||
names.reserve(TypeNames.size()); \
|
||||
for (const auto& [_, name] : TypeNames) \
|
||||
{ \
|
||||
names.push_back(name);\
|
||||
}\
|
||||
return names;\
|
||||
}\
|
||||
\
|
||||
std::string_view GetTypeName(entt::id_type id) \
|
||||
{ \
|
||||
if (TypeNames.contains(id)) \
|
||||
{ \
|
||||
return TypeNames[id]; \
|
||||
} \
|
||||
return "Unknown"; \
|
||||
}\
|
||||
};
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
// This is a singleton that knows about every modules and their public API
|
||||
class ModuleDB
|
||||
{
|
||||
public:
|
||||
ModuleDB() = default;
|
||||
~ModuleDB() = default;
|
||||
|
||||
static ModuleDB& Get()
|
||||
{
|
||||
static ModuleDB instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& RegisterModule()
|
||||
{
|
||||
Modules[typeid(T).name()] = T();
|
||||
return std::any_cast<T&>(Modules[typeid(T).name()]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& GetModule()
|
||||
{
|
||||
const std::string_view typeName = typeid(T).name();
|
||||
if (!Modules.contains(typeName))
|
||||
{
|
||||
assert(false && "Module not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
return std::any_cast<T>(Modules[typeName]);
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, std::any> Modules;
|
||||
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user