Files
Nuake-custom/Nuake/Source/Nuake/Modules/ModuleDB.h
2025-04-03 21:27:15 -04:00

272 lines
8.3 KiB
C++

#pragma once
#include <string>
#include <any>
#include <map>
#include <vector>
#include "Nuake/Core/Logger.h"
#include "Nuake/Core/GameState.h"
#include "Nuake/Core/MulticastDelegate.h"
#include "Nuake/Core/Object/Object.h"
#include "Nuake/Scene/Scene.h"
#include "Nuake/Scene/SceneSystems.h"
#include <entt/entt.hpp>
class ModuleInstance
{
public:
entt::meta_any instance;
std::string Name;
entt::meta_type Resolve()
{
Nuake::Logger::Log("Resolved!" + Name, "ModuleReflection", Nuake::LOG_TYPE::VERBOSE); \
return entt::resolve(entt::hashed_string(Name.c_str()));
}
MulticastDelegate<Ref<Nuake::Scene>> OnSceneLoad;
MulticastDelegate<float> OnUpdate;
MulticastDelegate<float> OnFixedUpdate;
MulticastDelegate<Nuake::GameState> OnGameStateChanged;
};
class Class
{
protected:
static void InitializeClass() {}
static void (*GetInitializeClass(void))()
{
return &Class::InitializeClass;
}
public:
static std::string GetName(const entt::meta_type& componentMeta);
};
#define NUAKECLASS(klass) \
public: \
static std::string ClassName() \
{ \
static std::string className = #klass; \
return className; \
} \
\
static void (*GetInitializeClass())() \
{ \
return &klass::InitializeClass; \
} \
\
inline static auto ClassFactory = entt::meta<klass>(); \
static void InternalInitializeClass() \
{ \
static bool initialized = false; \
if (initialized) \
return; \
\
ClassFactory.type(entt::hashed_string(#klass)); \
ClassFactory.func<&klass::ClassName>(entt::hashed_string("ClassName")) \
.prop(Nuake::HashedName::DisplayName, #klass); \
if (klass::GetInitializeClass() != Class::GetInitializeClass()) \
{ \
GetInitializeClass()(); \
} \
\
initialized = true; \
} \
\
template<auto Data> \
static auto BindField(const char* varName, const char* displayName) \
{ \
return ClassFactory \
.data<Data>(entt::hashed_string(varName)) \
.prop(Nuake::HashedName::DisplayName, displayName); \
} \
\
template<auto Getter, auto Setter> \
static auto BindProperty(const char* varName, const char* displayName) \
{ \
return ClassFactory \
.data<Getter, Setter>(entt::hashed_string(varName)) \
.prop(Nuake::HashedName::DisplayName, displayName); \
} \
\
template<auto F, typename... Args> \
static void BindFunc(const char* funcName, Args... args) \
{ \
ClassFactory \
.func<F>(entt::hashed_string(funcName)) \
.prop(Nuake::HashedName::DisplayName, funcName) \
.prop(Nuake::HashedName::ArgsName, std::vector<std::string>({args...})); \
} \
\
#define NUAKEMODULE(moduleName) \
using TypeNameMap = std::map<entt::id_type, std::string>; \
\
class moduleName : public ModuleInstance \
{ \
public: \
std::string Description = "No Description"; \
entt::meta_factory<moduleName> ModuleFactory = entt::meta<moduleName>(); \
TypeNameMap TypeNames; \
\
std::map<entt::id_type, std::vector<std::string>> FuncArgNames; \
\
inline static auto ClassFactory = entt::meta<moduleName>(); \
template<auto T, typename... Args> \
static void BindFunction(const std::string& name, Args... argNames) \
{ \
entt::id_type typeId = entt::hashed_string(name.c_str()); \
ClassFactory.func<T>(typeId) \
.prop(Nuake::HashedName::DisplayName, name) \
.prop(Nuake::HashedName::ArgsName, std::vector<const char*>({argNames...})); \
} \
\
template<auto Func> \
static auto RegisterSetting(const char* settingName) \
{ \
return ClassFactory \
.data<Func>(entt::hashed_string(settingName)) \
.prop(Nuake::HashedName::DisplayName, settingName); \
} \
\
template<typename T> \
void RegisterComponent() \
{ \
Nuake::SceneSystemDB::Get().RegisterComponent<T>(); \
} \
\
template<typename T> \
void RegisterComponentSystem() \
{ \
Nuake::SceneSystemDB::Get().RegisterSceneSystem<T>(); \
} \
\
template<typename... Args> \
auto Invoke(const std::string& funcName, Args... args) \
{ \
auto reflection = Resolve(); \
for (auto [id, func] : reflection.func()) \
{ \
const std::string_view returnType = func.ret().info().name(); \
const std::string_view funcTypeName = GetTypeName(id); \
if (funcName == funcTypeName) \
{ \
return func.invoke(instance, args...); \
} \
} \
} \
\
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()
{
T* newInstance = new T();
newInstance->instance = entt::resolve<T>().construct();
Modules[typeid(T).name()] = (ModuleInstance*)newInstance;
return *(T*)std::any_cast<ModuleInstance*>(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 *(T*)std::any_cast<ModuleInstance*>(Modules[typeName]);
}
ModuleInstance& GetBaseImpl(const std::string& moduleName)
{
for (auto& [name, _] : Modules)
{
if (name == moduleName)
{
return *std::any_cast<ModuleInstance*>(Modules[name]);
}
}
assert(false && "Module not found.");
}
entt::meta_type GetModuleMeta(const std::string& moduleName)
{
for (auto& [name, _] : Modules)
{
if (name == moduleName)
{
return std::any_cast<ModuleInstance*>(Modules[name])->Resolve();
}
}
assert(false && "Module not found");
return entt::meta_type();
}
std::vector<std::string> GetModules()
{
std::vector<std::string> moduleNames;
moduleNames.reserve(Modules.size());
for(auto& [moduleName, _] : Modules)
{
moduleNames.push_back(moduleName);
}
return moduleNames;
}
json GenerateModuleAPI();
private:
std::map<std::string, std::any> Modules;
};
}