diff --git a/bindings/lua/CMakeLists.txt b/bindings/lua/CMakeLists.txt index 7e06c036c..28d08abff 100644 --- a/bindings/lua/CMakeLists.txt +++ b/bindings/lua/CMakeLists.txt @@ -14,6 +14,7 @@ set(LUA_BINDINGS_SOURCE "src/plugin.cpp" "src/systems.cpp" "src/logging.cpp" + "src/depends.cpp" ) # ------------------------ Configure lua bindings target ------------------------- diff --git a/bindings/lua/samples/CMakeLists.txt b/bindings/lua/samples/CMakeLists.txt index 9412f0ff5..f8f0fa416 100644 --- a/bindings/lua/samples/CMakeLists.txt +++ b/bindings/lua/samples/CMakeLists.txt @@ -54,3 +54,4 @@ endfunction() make_sample(DIR "hello_world" ASSETS) make_sample(DIR "modules" ASSETS) make_sample(DIR "systems" ASSETS) +make_sample(DIR "depends" ASSETS) diff --git a/bindings/lua/samples/depends/main.cpp b/bindings/lua/samples/depends/main.cpp new file mode 100644 index 000000000..9925f97bd --- /dev/null +++ b/bindings/lua/samples/depends/main.cpp @@ -0,0 +1,24 @@ +#include + +#include +#include +#include + +using namespace cubos::engine; +using namespace cubos::bindings::lua; + +int main(int argc, char** argv) +{ + Cubos cubos{argc, argv}; + + cubos.plugin(settingsPlugin); + cubos.plugin(luaBindingsPlugin); + cubos.plugin(transformPlugin); + + cubos.startupSystem("configure Assets").before(settingsTag).call([](Settings& settings) { + settings.setString("scripts.lua.app.osPath", APP_SCRIPTS_PATH); + }); + + cubos.run(); + return 0; +} diff --git a/bindings/lua/samples/depends/scripts/depends.lua b/bindings/lua/samples/depends/scripts/depends.lua new file mode 100644 index 000000000..f5740f5a2 --- /dev/null +++ b/bindings/lua/samples/depends/scripts/depends.lua @@ -0,0 +1,8 @@ +transform = cubos.depends("cubos::engine::transformPlugin") + +for i, v in pairs(transform) do + cubos.info(i) +end + +cubos.info("Type of position:", transform.Position.__kind) +cubos.info("Type of childof:", transform.ChildOf.__kind) diff --git a/bindings/lua/src/cubos.cpp b/bindings/lua/src/cubos.cpp index 4eb70f61f..d872b5e37 100644 --- a/bindings/lua/src/cubos.cpp +++ b/bindings/lua/src/cubos.cpp @@ -8,6 +8,7 @@ #include "cubos.hpp" #include "systems.hpp" #include "logging.hpp" +#include "depends.hpp" using cubos::engine::Cubos; @@ -24,14 +25,35 @@ void cubos::bindings::lua::injectCubos(lua_State* state, Cubos* cubos) lua_settable(state, LUA_REGISTRYINDEX); lua_newtable(state); + + // Ecs pushFunction(state, "startupSystem", startupSystem); pushFunction(state, "system", system); + pushFunction(state, "depends", depends); + // Logging pushFunction(state, "info", logInfo); pushFunction(state, "warn", logWarn); pushFunction(state, "error", logError); lua_setglobal(state, "cubos"); + + + // Create metatables for types + luaL_newmetatable(state, "component"); + lua_pushstring(state, "Component"); + lua_setfield(state, -2, "__kind"); + lua_setfield(state, -1, "__index"); + + luaL_newmetatable(state, "resource"); + lua_pushstring(state, "Resource"); + lua_setfield(state, -2, "__kind"); + lua_setfield(state, -1, "__index"); + + luaL_newmetatable(state, "relation"); + lua_pushstring(state, "Relation"); + lua_setfield(state, -2, "__kind"); + lua_setfield(state, -1, "__index"); } Cubos* cubos::bindings::lua::getCubos(lua_State* state) diff --git a/bindings/lua/src/depends.cpp b/bindings/lua/src/depends.cpp new file mode 100644 index 000000000..21e446a00 --- /dev/null +++ b/bindings/lua/src/depends.cpp @@ -0,0 +1,107 @@ +#include "systems.hpp" + +#include "cubos.hpp" +#include "logging.hpp" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +using namespace cubos::core::ecs; +using namespace cubos::core::reflection; + + +static Plugin findPlugin(Cubos* cubos, const char* pluginName) { + for (auto& entry : cubos->installedPlugins()) + { + if (entry.second.name == pluginName) + { + return entry.first; + } + } + + return nullptr; +} + +static PluginInfo getPluginInfo(Cubos* cubos, Plugin plugin) { + return cubos->installedPlugins().at(plugin); +} + +/* + * Gets the contents of a plugin and its subplugins + */ +static void registerPlugin(Cubos* cubos, Plugin plugin, std::vector& pluginContent) +{ + PluginInfo pluginInfo = getPluginInfo(cubos, plugin); + + for (Plugin subplugin : pluginInfo.subPlugins) + { + registerPlugin(cubos, subplugin, pluginContent); + } + + for (auto& type : pluginInfo.types) + { + pluginContent.push_back(type); + } +} + +namespace cubos::bindings::lua { + int depends(lua_State *state) + { + Cubos* cubos = getCubos(state); + World* world = cubos->world(); + Types types = world->types(); + std::vector pluginContent; + + const char* pluginName = luaL_checkstring(state, 1); + Plugin plugin = findPlugin(cubos, pluginName); + + if (plugin == nullptr) + { + logLua(state, cubos::core::tel::Level::Error, "Unable to find plugin named " + std::string(pluginName)); + lua_pushnil(state); + return 1; + } + + registerPlugin(cubos, plugin, pluginContent); + + // The plugin is defined as a table with each type being a field. + // Each type is defined as a userdata with a metatable corresponding + // to its kind (Component/Resource/Relation). + lua_newtable(state); + + for (auto& type : pluginContent) + { + const Type** instance = (const Type**) lua_newuserdata(state, sizeof(Type*)); + *instance = type; + + DataTypeId id = types.id(*type); + + if (types.isComponent(id)) + { + luaL_getmetatable(state, "component"); + } + else if (types.isResource(id)) + { + luaL_getmetatable(state, "resource"); + } + else if (types.isRelation(id)) + { + luaL_getmetatable(state, "relation"); + } + + lua_setmetatable(state, -2); + lua_setfield(state, -2, type->shortName().c_str()); + } + + return 1; + } +} \ No newline at end of file diff --git a/bindings/lua/src/depends.hpp b/bindings/lua/src/depends.hpp new file mode 100644 index 000000000..97724bce4 --- /dev/null +++ b/bindings/lua/src/depends.hpp @@ -0,0 +1,21 @@ +/// @dir +/// @brief @ref lua-bindings-plugin plugin directory. + +/// @file +/// @brief Logging lua api. +/// @ingroup lua-bindings-plugin +#pragma once + +#include + +#include + +namespace cubos::bindings::lua +{ + /// @brief Lua api function that gets the components, resources and relations of a given plugin + // and its subplugins. + /// @param state The current lua state. + /// @ingroup lua-bindings-plugin + int depends(lua_State* state); + +} // namespace cubos::bindings::lua \ No newline at end of file diff --git a/bindings/lua/src/logging.cpp b/bindings/lua/src/logging.cpp index 228c33637..5c5bfb932 100644 --- a/bindings/lua/src/logging.cpp +++ b/bindings/lua/src/logging.cpp @@ -2,8 +2,10 @@ #include #include +#include -#include +#include +#include using namespace cubos::core::tel; @@ -64,42 +66,41 @@ static std::string formatArgs(lua_State *state) return str; } -static void log(lua_State* state, Level logLevel) +namespace cubos::bindings::lua { - std::string formattedArgs = formatArgs(state); - Logger::Location location; - lua_Debug debugInfo; - - if (lua_getstack(state, 1, &debugInfo)) + void logLua(lua_State* state, Level logLevel, std::string message) { - if (lua_getinfo(state, "nSl", &debugInfo)) + Logger::Location location; + lua_Debug debugInfo; + + if (lua_getstack(state, 1, &debugInfo)) { - location.function = debugInfo.name ? debugInfo.name : "undefined"; - location.file = debugInfo.short_src; - location.line = debugInfo.currentline; + if (lua_getinfo(state, "nSl", &debugInfo)) + { + location.function = debugInfo.name ? debugInfo.name : "undefined"; + location.file = debugInfo.short_src; + location.line = debugInfo.currentline; - Logger::write(logLevel, location, formattedArgs); + Logger::write(logLevel, location, std::move(message)); + } } } -} -namespace cubos::bindings::lua -{ int logInfo(lua_State* state) { - log(state, Level::Info); + logLua(state, Level::Info, formatArgs(state)); return 0; }; int logWarn(lua_State* state) { - log(state, Level::Warn); + logLua(state, Level::Warn, formatArgs(state)); return 0; }; int logError(lua_State* state) { - log(state, Level::Error); + logLua(state, Level::Error, formatArgs(state)); return 0; }; } // namespace cubos::bindings::lua diff --git a/bindings/lua/src/logging.hpp b/bindings/lua/src/logging.hpp index cb6cc1547..30ee6b137 100644 --- a/bindings/lua/src/logging.hpp +++ b/bindings/lua/src/logging.hpp @@ -7,11 +7,20 @@ #pragma once #include +#include +#include #include namespace cubos::bindings::lua { + /// @brief Logs a message showing lua specific info. + /// @param state The current lua state. + /// @param level Logging level. + /// @param message Message to print. + /// @ingroup lua-bindings-plugin + void logLua(lua_State* state, cubos::core::tel::Level level, std::string message); + /// @brief Lua api function to log information. /// @param state The current lua state. /// @ingroup lua-bindings-plugin diff --git a/bindings/lua/src/plugin.cpp b/bindings/lua/src/plugin.cpp index d16cd10f2..38df951b6 100644 --- a/bindings/lua/src/plugin.cpp +++ b/bindings/lua/src/plugin.cpp @@ -132,7 +132,7 @@ void cubos::bindings::lua::luaBindingsPlugin(Cubos& cubos) } (void)plugins; plugins.add([](Cubos& other) { - auto& state = other.world().resource(); + auto& state = other.world()->resource(); loadScripts(ScriptsMountPoint, state.luaState); }); } diff --git a/core/include/cubos/core/ecs/cubos.hpp b/core/include/cubos/core/ecs/cubos.hpp index 3b0d46f88..2eafb2911 100644 --- a/core/include/cubos/core/ecs/cubos.hpp +++ b/core/include/cubos/core/ecs/cubos.hpp @@ -17,6 +17,7 @@ #include #include #include +#include namespace cubos::core::ecs { @@ -65,6 +66,37 @@ namespace cubos::core::ecs std::vector value; ///< Command-line arguments. }; + /// @brief Stores information regarding a plugin. + struct PluginInfo + { + /// @brief How many plugins depend on this plugin. + int dependentCount{0}; + + /// @brief Plugins which this plugin depends on. + std::unordered_set dependencies; + + /// @brief Plugins which were added by this plugin. + std::unordered_set subPlugins; + + /// @brief Systems which were added by this plugin. + std::vector systems; + + /// @brief Conditions which were added by this plugin. + std::vector conditions; + + /// @brief Main tags which were added by this plugin. + std::vector tags; + + /// @brief Observers which were added by this plugin. + std::vector observers; + + /// @brief Types which were added by this plugin. + std::vector types; + + /// @brief Name of the plugin. + std::string name; + }; + /// @brief Represents the engine itself, and exposes the interface with which the game /// developer interacts with. Ties up all the different parts of the engine together. /// @ingroup core-ecs @@ -257,37 +289,13 @@ namespace cubos::core::ecs /// @brief Returns the ECS world used. /// @return The internal ECS world. - World& world(); + World* world(); - private: - /// @brief Stores information regarding a plugin. - struct PluginInfo - { - /// @brief How many plugins depend on this plugin. - int dependentCount{0}; - - /// @brief Plugins which this plugin depends on. - std::unordered_set dependencies; - - /// @brief Plugins which were added by this plugin. - std::unordered_set subPlugins; - - /// @brief Systems which were added by this plugin. - std::vector systems; - - /// @brief Conditions which were added by this plugin. - std::vector conditions; - - /// @brief Main tags which were added by this plugin. - std::vector tags; - - /// @brief Observers which were added by this plugin. - std::vector observers; - - /// @brief Name of the plugin. - std::string name; - }; + /// Returns installed plugins. + /// @return Installed plugins. + std::unordered_map installedPlugins(); + private: /// @brief Stores information regarding a tag. struct TagInfo { diff --git a/core/src/ecs/cubos.cpp b/core/src/ecs/cubos.cpp index c0234a288..31cc94be4 100644 --- a/core/src/ecs/cubos.cpp +++ b/core/src/ecs/cubos.cpp @@ -181,6 +181,14 @@ Cubos& Cubos::inject(Plugin target, Plugin plugin) Cubos& Cubos::uninitResource(const reflection::Type& type) { CUBOS_ASSERT(!mTypeToPlugin.contains(type), "Resource {} was already registered", type.name()); + + Plugin plugin = mPluginStack.back(); + if (mInjectedPlugins.contains(plugin)) + { + plugin = mInjectedPlugins.at(plugin); + } + + mInstalledPlugins.at(plugin).types.push_back(&type); mTypeToPlugin.insert(type, mPluginStack.back()); mWorld->registerResource(type); return *this; @@ -196,6 +204,14 @@ Cubos& Cubos::resource(memory::AnyValue value) Cubos& Cubos::component(const reflection::Type& type) { CUBOS_ASSERT(!mTypeToPlugin.contains(type), "Component {} was already registered", type.name()); + + Plugin plugin = mPluginStack.back(); + if (mInjectedPlugins.contains(plugin)) + { + plugin = mInjectedPlugins.at(plugin); + } + + mInstalledPlugins.at(plugin).types.push_back(&type); mTypeToPlugin.insert(type, mPluginStack.back()); mWorld->registerComponent(type); return *this; @@ -204,6 +220,14 @@ Cubos& Cubos::component(const reflection::Type& type) Cubos& Cubos::relation(const reflection::Type& type) { CUBOS_ASSERT(!mTypeToPlugin.contains(type), "Relation {} was already registered", type.name()); + + Plugin plugin = mPluginStack.back(); + if (mInjectedPlugins.contains(plugin)) + { + plugin = mInjectedPlugins.at(plugin); + } + + mInstalledPlugins.at(plugin).types.push_back(&type); mTypeToPlugin.insert(type, mPluginStack.back()); mWorld->registerRelation(type); return *this; @@ -452,9 +476,14 @@ bool Cubos::shouldQuit() const return mWorld->resource().value; } -cubos::core::ecs::World& Cubos::world() +cubos::core::ecs::World* Cubos::world() +{ + return mWorld; +} + +std::unordered_map Cubos::installedPlugins() { - return *mWorld; + return mInstalledPlugins; } bool Cubos::isRegistered(const reflection::Type& type) const