From de5af0a5aa5a85dcb34b37f940e7b895da6591a1 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Tue, 12 May 2020 02:06:10 +0200 Subject: [PATCH] Streamlined library and reworked the way runtime components work --- ecs-lua/include/ecs-lua.h | 3 +- ecs-lua/src/ecs-lua.cpp | 175 ++++++++++++++++++++++++++------ ecs-serial/include/ecs-serial.h | 17 +--- ecs-serial/src/ecs-serial.cpp | 58 ++++------- ecs/include/ecs.h | 137 ++++++++++++++----------- ecs/src/ecs.cpp | 42 +++----- flint.yaml | 18 ++-- test/generated/ecs_components.h | 6 +- test/src/main.cpp | 121 +++++----------------- test/test.lua | 143 ++++++++++++++------------ test/test2.lua | 63 ++++++++---- 11 files changed, 424 insertions(+), 359 deletions(-) diff --git a/ecs-lua/include/ecs-lua.h b/ecs-lua/include/ecs-lua.h index bcdbed9..2251a9d 100644 --- a/ecs-lua/include/ecs-lua.h +++ b/ecs-lua/include/ecs-lua.h @@ -9,8 +9,7 @@ namespace ecs::lua { struct Wrapper : Component { // @todo Figure out a more elegant way - Wrapper(sol::table _table) : Component(ComponentID::id), table(_table) {} - Wrapper() : Component(ComponentID::id) {} + Wrapper() {} sol::table table; }; diff --git a/ecs-lua/src/ecs-lua.cpp b/ecs-lua/src/ecs-lua.cpp index 8881422..8d44e4c 100644 --- a/ecs-lua/src/ecs-lua.cpp +++ b/ecs-lua/src/ecs-lua.cpp @@ -2,6 +2,10 @@ #include "ecs.h" +#ifdef _OPTIONAL_ECS_SERIAL +#include "ecs-serial.h" +#endif + namespace sol { template<> struct is_container> : std::true_type {}; @@ -14,35 +18,159 @@ namespace ecs::lua { preload["ecs"] = [&lua] { sol::table ecs = lua.create_table(); + ecs.set_function("register", [&lua] (std::string name, sol::table table) { + size_t id = ComponentID::regist(name); + + std::unordered_map map; + + for (auto [skey, stype] : table) { + std::string key = skey.as(); + std::string type = stype.as(); + + if (!type.compare("string")) { + map.insert({key, sol::type::string}); + } else if (!type.compare("number")) { + map.insert({key, sol::type::number}); + } else if (!type.compare("boolean")) { + map.insert({key, sol::type::boolean}); + } + } + + #ifdef _OPTIONAL_ECS_SERIAL + auto serialize = [map, name] (std::ostream& os, ecs::Component* component) { + std::cout << "SERIALIZE: " << name << '\n'; + Wrapper* wrapper = (Wrapper*)component; + + // Write each of the entries + io::write(os, map.size()); + for (auto [key, type] : map) { + io::write(os, key); + switch (type) { + case sol::type::string: + io::write(os, wrapper->table.get(key)); + break; + + case sol::type::number: + io::write(os, wrapper->table.get(key)); + break; + + case sol::type::boolean: + io::write(os, wrapper->table.get(key)); + break; + + default: + break; + } + } + }; + + auto deserialize = [map] (std::istream& is, Component* component) { + std::cout << "DESERIALIZE\n"; + + Wrapper* wrapper = (Wrapper*)component; + + // Write each of the entries + size_t size = io::read(is); + for (size_t i = 0; i < size; ++i) { + std::string key = io::read(is); + const auto it = map.find(key); + sol::type type = it->second; + + std::cout << key << '\n'; + + switch (type) { + case sol::type::string: + std::cout << "STRING\n"; + wrapper->table[key] = io::read(is); + break; + + case sol::type::number: + std::cout << "NUMBER\n"; + wrapper->table[key] = io::read(is); + break; + + case sol::type::boolean: + std::cout << "BOOL\n"; + wrapper->table[key] = io::read(is); + break; + + default: + break; + } + } + }; + + auto create = [&lua, map] { + std::cout << "CREATE\n"; + Wrapper* wrapper = new Wrapper(); + wrapper->table = lua.create_table(); + + for (auto [key, type] : map) { + switch (type) { + case sol::type::string: + wrapper->table[key] = ""; + break; + + case sol::type::number: + wrapper->table[key] = 0; + break; + + case sol::type::boolean: + wrapper->table[key] = true; + break; + + default: + break; + } + } + + return wrapper; + }; + + ecs::serial::register_component_custom(id, serialize, deserialize, create); + #endif + + lua.set_function("_internal_to_" + name, [] (ecs::Component* component) { + return (Wrapper*)component; + }); + + sol::table component = lua.create_table(); + + component.set_function("new", sol::factories([&lua, id, map] (sol::table table) { + Wrapper* wrapper = new Wrapper(); + wrapper->table = lua.create_table(); + + for (auto [key, type] : map) { + wrapper->table[key] = table[key]; + } + + return std::make_pair(id, wrapper); + })); + + return component; + }); + ecs.new_usertype("Entity", "__tostring", [] (Entity* thiz) { return uuids::to_string(thiz->uuid); }, - "add_component", [] (Entity* thiz, Component* component, std::string name) { - return thiz->add_component(ComponentID::get_id({name})[0], component); + "add_component", [] (Entity* thiz, size_t id, Component* component) { + return thiz->add_component(id, component); }, "has_components", [] (Entity* thiz, sol::variadic_args args) { std::vector names; for (std::string name : args) { names.push_back(name); } - return thiz->has_components(ComponentID::get_id(names)); + return thiz->has_components(ComponentID::resolve(names)); }, "get_component", [&lua] (Entity* thiz, std::string name) -> sol::object { // Convert to the correct component type - Component* component = thiz->get_component(ComponentID::get_id({name})[0]); - if (!component->_runtime) { - // @todo Figure out a more elegant way to convert - auto f1 = lua["_internal_to_" + name]; - if (f1.valid()) { - return f1(component); - } - } else { - // @todo This call is not very fast... - auto f1 = lua["_internal_to_" + ComponentID::get_name(component->_id)]; - if (f1.valid()) { - return f1(component); - } + Component* component = thiz->get_component(ComponentID::resolve(name)); + // @todo Figure out a more elegant way to convert + auto f1 = lua["_internal_to_" + name]; + if (f1.valid()) { + return f1(component); } throw std::runtime_error("Unknown component"); } @@ -71,7 +199,7 @@ namespace ecs::lua { for (std::string name : args) { names.push_back(name); } - return thiz->view(ComponentID::get_id(names)); + return thiz->view(ComponentID::resolve(names)); } ); @@ -79,8 +207,7 @@ namespace ecs::lua { }; preload["ecs.Wrapper"] = [&lua] { - sol::table component = lua.create_table(); - component.new_usertype("Wrapper", + lua.new_usertype("Wrapper", "__index", [] (Wrapper* thiz, std::string key) { return thiz->table[key]; }, @@ -89,16 +216,6 @@ namespace ecs::lua { }, sol::base_classes, sol::bases() ); - - component.set_function("new", sol::factories([](std::string _name, sol::table _table) { - return std::make_pair(new Wrapper(_table), _name); - })); - - lua.set_function("_internal_to_Wrapper", [] (ecs::Component* component) { - return (Wrapper*)component; - }); - - return component; }; } } diff --git a/ecs-serial/include/ecs-serial.h b/ecs-serial/include/ecs-serial.h index 0de65f3..795a6b6 100644 --- a/ecs-serial/include/ecs-serial.h +++ b/ecs-serial/include/ecs-serial.h @@ -41,32 +41,25 @@ namespace ecs::serial { template void register_component(Args... args) { // Serialize component - auto func1 = [args...] (std::ostream& os, ecs::Component* component) { + auto serialize = [args...] (std::ostream& os, ecs::Component* component) { T* t = (T*)component; serialize_member(os, t, args...); }; // Deserialize component - auto func2 = [args...] (std::istream& is, ecs::Component* component) { + auto deserialize = [args...] (std::istream& is, ecs::Component* component) { T* t = (T*)component; deserialize_member(is, t, args...); }; - auto func3 = [] () -> Component* { + auto create = [] () -> Component* { return new T(); }; - internal::functions.insert({ComponentID::id, {func1, func2, func3}}); + internal::functions.insert({ComponentID::id, {serialize, deserialize, create}}); } - template - void register_component_custom(std::function func1, std::function func2) { - auto func3 = [] () -> Component* { - return new T(); - }; - - internal::functions.insert({ComponentID::id, {func1, func2, func3}}); - } + void register_component_custom(size_t id, std::function serialize, std::function deserialize, std::function create); void serialize(std::ostream& os, Entity* entity); void deserialize(std::istream& is, Manager& manager); diff --git a/ecs-serial/src/ecs-serial.cpp b/ecs-serial/src/ecs-serial.cpp index 2535bbe..c0c153c 100644 --- a/ecs-serial/src/ecs-serial.cpp +++ b/ecs-serial/src/ecs-serial.cpp @@ -12,6 +12,10 @@ namespace ecs::serial { std::unordered_map conversion; + void register_component_custom(size_t id, std::function serialize, std::function deserialize, std::function create) { + internal::functions.insert({id, {serialize, deserialize, create}}); + } + void serialize(std::ostream& os, Entity* entity) { auto uuid_data = reinterpret_cast(entity->uuid.as_bytes().data()); io::write>(os, std::vector(uuid_data, uuid_data + 16), false); @@ -19,28 +23,13 @@ namespace ecs::serial { auto components = entity->get_components(); io::write(os, components.size()); for (auto [id, component] : components) { - if (!component->_runtime) { - auto functions = internal::functions.find(id); - if (functions == internal::functions.end()) { - throw std::runtime_error("No known serializer for id"); - } - - io::write(os, id); - io::write(os, false); - std::get<0>(internal::functions[id])(os, component); - } else { - auto new_id = component->_id; - auto functions = internal::functions.find(new_id); - - if (functions == internal::functions.end()) { - throw std::runtime_error("No known serializer for id"); - } - - io::write(os, new_id); - io::write(os, true); - io::write(os, id); - std::get<0>(internal::functions[new_id])(os, component); + auto functions = internal::functions.find(id); + if (functions == internal::functions.end()) { + throw std::runtime_error("No known serializer for id"); } + + io::write(os, id); + std::get<0>(internal::functions[id])(os, component); } } @@ -60,12 +49,7 @@ namespace ecs::serial { size_t component_count = io::read(is); // std::cout << "Updating " << component_count << " components in entity: " << uuid << '\n'; for (size_t i = 0; i < component_count; ++i) { - size_t new_id = conversion[io::read(is)]; - bool runtime = io::read(is); - size_t id = new_id; - if (runtime) { - id = conversion[io::read(is)]; - } + size_t id = conversion[io::read(is)]; // @todo We also need to be able to remove components // Sending a component with length 0 -> remove component @@ -75,22 +59,14 @@ namespace ecs::serial { // @todo What if the function does not exist? if (entity->has_components({id})) { // Update the component - std::cout << "Updating component: " << id << " [" << ComponentID::get_name(id) << "]"; - if (new_id != id) { - std::cout << " (base: " << new_id << " [" << ComponentID::get_name(new_id) << "])"; - } - std::cout << '\n'; + std::cout << "Updating component: " << id << " [" << ComponentID::reverse_resolve(id) << "]\n"; Component* component = entity->get_component(id); // @note We do not have to check if this exists as the entity already has the component - std::get<1>(internal::functions[new_id])(is, component); + std::get<1>(internal::functions[id])(is, component); } else { // Add new component - std::cout << "Adding component: " << id << " [" << ComponentID::get_name(id) << "]"; - if (new_id != id) { - std::cout << " (base: " << new_id << " [" << ComponentID::get_name(new_id) << "])"; - } - std::cout << '\n'; - auto func = internal::functions.find(new_id); + std::cout << "Adding component: " << id << " [" << ComponentID::reverse_resolve(id) << "]\n"; + auto func = internal::functions.find(id); if (func == internal::functions.end()) { throw std::runtime_error("No known serializers for component"); } @@ -102,7 +78,7 @@ namespace ecs::serial { } void serialize_ids(std::ostream& os) { - auto& ids = ComponentID::_ids(); + auto& ids = ComponentID::get_map(); io::write(os, ids.size()); for (auto& [name, id] : ids) { @@ -117,7 +93,7 @@ namespace ecs::serial { std::string name = io::read(is); size_t id = io::read(is); - conversion[id] = ComponentID::get_id({name})[0]; + conversion[id] = ComponentID::resolve(name); } for (auto [remote_id, local_id] : conversion) { diff --git a/ecs/include/ecs.h b/ecs/include/ecs.h index d7a27f3..ac62cd3 100644 --- a/ecs/include/ecs.h +++ b/ecs/include/ecs.h @@ -4,68 +4,79 @@ #include #include #include - -#include -#if __has_include() - #include -#endif +#include +#include #include "uuid.h" namespace ecs { - template - std::string get_typename() { - #if __has_include() - std::string name = abi::__cxa_demangle(typeid(T).name(), 0, 0, 0); - #else - std::string name = typeid(T).name(); - // This is really janky - name = name.substr(name.find(' ')+1); - #endif - - auto index = name.find_last_of(':'); - if (index != std::string::npos) { - name = name.substr(index+1); - } - - return name; - } - + // @todo Redo the component id system to require registering the components + // This would hopefully clear up some of the jank related to this part of the codebase (No weird lookups) + // It would also make runtime generated / meta components much easier class ComponentID { private: - static size_t _id; + static size_t next_id; + static std::unordered_map _ids; public: - // This needs to be a function because otherwise it might not be initialized on time - static std::unordered_map& _ids(); - static std::vector get_id(std::vector names); + template + static size_t regist(std::string name) { + _ids.insert({name, id}); + // @todo Do some other register stuff + return id; + } - // @todo This is slow... - static std::string get_name(size_t id) { - for (auto it = _ids().begin(); it != _ids().end(); ++it) { - if (it->second == id) { - return it->first; - } - } - - throw std::runtime_error("ID does not exist"); + static size_t regist(std::string name) { + size_t id = next_id++; + _ids.insert({name, id}); + return id; } // This looks kind of ugly template - inline static const size_t id = get_id({get_typename()})[0]; + inline static const size_t id = next_id++; + + static size_t resolve(std::string name) { + auto it = _ids.find(name); + if (it == _ids.end()) { + return 0; + } + return it->second; + } + + static std::vector resolve(std::vector names) { + std::vector ids; + + for (const auto& name : names) { + ids.push_back(resolve(name)); + } + + return ids; + } + + static std::string reverse_resolve(size_t id) { + for (auto& [name, _id] : _ids) { + if (id == _id) { + return name; + } + } + + return ""; + } + + static const auto& get_map() { + return _ids; + } }; struct Component { - Component() : _runtime(false), _id(0) {} - - // @todo Would be nice if this worked with templates - Component(size_t id) : _runtime(true), _id(id) {} + Component() {} virtual ~Component() {} - - const bool _runtime; - const size_t _id; + // + // @todo Store parent entity and also make a vector for all components of this type + // that way we can do some nice stuff without having to search the entities + // For example we could loop over all sprite components and then draw them (using parent to find location) }; class Entity { @@ -73,52 +84,48 @@ namespace ecs { Entity(uuids::uuid _uuid) : uuid(_uuid) {} ~Entity(); + void add_component(size_t id, Component* component); + bool has_components(std::vector ids) const; + bool has_components(size_t id) const; + Component* get_component(size_t id) const; + template void add_component(Args... args) { size_t id = ComponentID::id; + std::cout << "ID: " << id << '\n'; + if (_components.find(id) != _components.end()) { throw std::runtime_error("Component already exists"); } + // @todo Also register the component to the manager _components[id] = new T(args...); } template bool has_components() const { std::vector ids = {ComponentID::id...}; - for (const auto& id : ids) { - if (_components.find(id) == _components.end()) { - return false; - } - } - return true; + return has_components(ids); } template T* get_component() const { size_t id = ComponentID::id; - auto it = _components.find(id); - if (it == _components.end()) { - throw std::runtime_error("Component does not exist"); - } - return (T*)it->second; + return (T*)get_component(id); } const std::unordered_map get_components() const { return _components; } - void add_component(size_t id, Component* component); - bool has_components(std::vector ids); - Component* get_component(size_t id); - const uuids::uuid uuid; private: std::unordered_map _components; + // @todo Store manager, this allows the entity to register components to the manager }; template @@ -183,6 +190,18 @@ namespace ecs { return View(entities); } + View<> view(size_t id) { + std::unordered_map entities; + + for (auto [uuid, entity] : _entities) { + if (entity->has_components(id)) { + entities.insert({uuid, entity}); + } + } + + return View<>(entities); + } + View<> view(std::vector ids) { std::unordered_map entities; diff --git a/ecs/src/ecs.cpp b/ecs/src/ecs.cpp index a23c1a1..93b569c 100644 --- a/ecs/src/ecs.cpp +++ b/ecs/src/ecs.cpp @@ -3,29 +3,8 @@ #include namespace ecs { - size_t ComponentID::_id; - // This needs to be a function because otherwise it might not be initialized on time - std::unordered_map& ComponentID::_ids() { - static std::unordered_map ids; - return ids; - }; - - std::vector ComponentID::get_id(std::vector names) { - std::vector ids; - - for (const auto& name : names) { - auto it = _ids().find(name); - if (it != _ids().end()) { - ids.push_back(it->second); - } else { - size_t id = _id++; - _ids()[name] = id; - ids.push_back(id); - } - } - - return ids; - } + size_t ComponentID::next_id = 1; + std::unordered_map ComponentID::_ids; Entity::~Entity() { // @todo This does not work... @@ -37,6 +16,9 @@ namespace ecs { } void Entity::add_component(size_t id, Component* component) { + if (id == 0) { + throw std::runtime_error("Unknown component!"); + } if (_components.find(id) != _components.end()) { throw std::runtime_error("Component already exists"); } @@ -44,7 +26,15 @@ namespace ecs { _components[id] = component; } - bool Entity::has_components(std::vector ids) { + bool Entity::has_components(size_t id) const { + if (_components.find(id) == _components.end()) { + return false; + } + + return true; + } + + bool Entity::has_components(std::vector ids) const { for (const auto& id : ids) { if (_components.find(id) == _components.end()) { return false; @@ -54,10 +44,10 @@ namespace ecs { return true; } - Component* Entity::get_component(size_t id) { + Component* Entity::get_component(size_t id) const { auto it = _components.find(id); if (it == _components.end()) { - throw std::runtime_error("Component does not exist"); + return nullptr; } return it->second; diff --git a/flint.yaml b/flint.yaml index bdfde20..d697296 100644 --- a/flint.yaml +++ b/flint.yaml @@ -37,19 +37,21 @@ targets: dependency: - stduuid + ecs_serial: + type: lib + path: ecs-serial + dependency: + - ecs + - io + ecs-lua: type: lib path: ecs-lua dependency: - ecs - sol2 - - ecs-serial: - type: lib - path: ecs-serial - dependency: - - ecs - - io + optional: + - ecs_serial test: type: exe @@ -59,5 +61,5 @@ targets: dependency: - ecs - ecs-lua - - ecs-serial + - ecs_serial diff --git a/test/generated/ecs_components.h b/test/generated/ecs_components.h index 917f446..19c9351 100644 --- a/test/generated/ecs_components.h +++ b/test/generated/ecs_components.h @@ -15,7 +15,7 @@ namespace generated { ); component.set_function("new", sol::factories([](float _x, float _y) { - return std::make_pair(new Position(_x, _y), "Position"); + return std::make_pair(ecs::ComponentID::id, new Position(_x, _y)); })); lua.set_function("_internal_to_Position", [] (ecs::Component* component) { @@ -33,7 +33,7 @@ namespace generated { ); component.set_function("new", sol::factories([](float _x, float _y) { - return std::make_pair(new Velocity(_x, _y), "Velocity"); + return std::make_pair(ecs::ComponentID::id, new Velocity(_x, _y)); })); lua.set_function("_internal_to_Velocity", [] (ecs::Component* component) { @@ -51,7 +51,7 @@ namespace generated { ); component.set_function("new", sol::factories([](std::string _name) { - return std::make_pair(new Meta(_name), "Meta"); + return std::make_pair(ecs::ComponentID::id, new Meta(_name)); })); lua.set_function("_internal_to_Meta", [] (ecs::Component* component) { diff --git a/test/src/main.cpp b/test/src/main.cpp index e74bd02..b9b24b5 100644 --- a/test/src/main.cpp +++ b/test/src/main.cpp @@ -38,6 +38,11 @@ int main(int argc, const char** argv) { return -1; } + ecs::ComponentID::regist("Wrapper"); + ecs::ComponentID::regist("Position"); + ecs::ComponentID::regist("Velocity"); + ecs::ComponentID::regist("Meta"); + sol::state lua(sol::c_call); lua.open_libraries(sol::lib::base, sol::lib::package); @@ -46,95 +51,6 @@ int main(int argc, const char** argv) { generated::init(lua); generated::init(); - // @todo I am pretty sure that iohelper actually has an api that allows us to write a custom (de)serializer - ecs::serial::register_component_custom( - [](std::ostream& os, ecs::Component* component) { - ecs::lua::Wrapper* wrapper = (ecs::lua::Wrapper*)component; - - // iohelper::write(os, wrapper->name); - - // #todo .size() does not work - size_t size = 0; - for (auto [a, b] : wrapper->table) { - size++; - } - io::write(os, size); - - for (auto [a, b] : wrapper->table) { - io::write(os, a.as()); - - sol::type type = b.get_type(); - io::write(os, (uint8_t)type); - switch (type) { - case sol::type::none: - case sol::type::nil: - break; - - case sol::type::string: - io::write(os, b.as()); - break; - - case sol::type::number: - // @todo These should be doubles instead of floats - io::write(os, b.as()); - break; - - case sol::type::boolean: - io::write(os, b.as()); - break; - - case sol::type::table: - // @todo Make this happen - break; - - // All other types are not supported - default: - throw std::runtime_error("Unsupported type in wrapped lua table"); - break; - } - } - }, - [&lua](std::istream& is, ecs::Component* component) { - ecs::lua::Wrapper* wrapper = (ecs::lua::Wrapper*)component; - // @todo Only do this if table is not created yet - wrapper->table = lua.create_table(); - - size_t size = io::read(is); - std::cout << "Size: " << size << '\n'; - for (size_t i = 0; i < size; ++i) { - std::string name = io::read(is); - - std::cout << "Name: " << name << '\n'; - - sol::type type = (sol::type)io::read(is); - switch (type) { - case sol::type::none: - break; - - case sol::type::nil: - break; - - case sol::type::string: - wrapper->table[name] = io::read(is); - break; - - case sol::type::number: - wrapper->table[name] = io::read(is); - break; - - case sol::type::boolean: - { - wrapper->table[name] = io::read(is); - break; - } - - default: - break; - } - } - } - ); - if (save) { ecs::Manager manager; @@ -147,6 +63,14 @@ int main(int argc, const char** argv) { lua.safe_script_file("test.lua"); + sol::protected_function init = lua["init"]; + std::cout << "Running init()\n"; + init(); + + sol::protected_function run = lua["run"]; + std::cout << "Running run()\n"; + run(); + std::cout << "Update position\n"; manager.view().for_each([](ecs::Entity*, Position* pos, Velocity* vel) { pos->x += vel->x; @@ -160,15 +84,15 @@ int main(int argc, const char** argv) { }); // These are really just an internal api that should not be used - for (auto [uuid, entity] : manager.view(ecs::ComponentID::get_id({"Random"}))) { - sol::table random = ((ecs::lua::Wrapper*)entity->get_component(ecs::ComponentID::get_id({"Random"})[0]))->table; + for (auto [uuid, entity] : manager.view(ecs::ComponentID::resolve("Random"))) { + sol::table random = ((ecs::lua::Wrapper*)entity->get_component(ecs::ComponentID::resolve("Random")))->table; random["a"] = 21; std::cout << random["a"].get() << '\n'; }; - for (auto [uuid, entity] : manager.view(ecs::ComponentID::get_id({"Random"}))) { - sol::table random = ((ecs::lua::Wrapper*)entity->get_component(ecs::ComponentID::get_id({"Random"})[0]))->table; + for (auto [uuid, entity] : manager.view(ecs::ComponentID::resolve("Random"))) { + sol::table random = ((ecs::lua::Wrapper*)entity->get_component(ecs::ComponentID::resolve("Random")))->table; std::cout << random["a"].get() << '\n'; }; @@ -214,6 +138,11 @@ int main(int argc, const char** argv) { { std::cout << "LOAD\n"; + lua.safe_script_file("test2.lua"); + sol::protected_function init = lua["init"]; + std::cout << "Running init()\n"; + init(); + // Load entities from disk as a test std::ifstream file("entities", std::ios::in); @@ -248,11 +177,13 @@ int main(int argc, const char** argv) { return manager; }); - lua.safe_script_file("test2.lua"); + sol::protected_function run = lua["run"]; + std::cout << "Running run()\n"; + run(); } } - for (auto [name, id] : ecs::ComponentID::_ids()) { + for (auto [name, id] : ecs::ComponentID::get_map()) { std::cout << name << ' ' << id << '\n'; } } diff --git a/test/test.lua b/test/test.lua index f85de21..ad636ee 100644 --- a/test/test.lua +++ b/test/test.lua @@ -1,87 +1,102 @@ local ecs = require "ecs" --- local test = require "ecs_test" local Position = require "ecs.Position" local Velocity = require "ecs.Velocity" local Meta = require "ecs.Meta" local Wrapper = require 'ecs.Wrapper' -manager = get_manager() -ent = manager:create_entity() -ent:add_component(Velocity.new(0.2, 0.3)) -ent:add_component(Position.new(1.9, 9.7)) -ent:add_component(Meta.new("Soldier")) +function init() + print("Registering components") -data = { - speed = 10, - something = "Hello, World!", - alive = true -} -ent:add_component(Wrapper.new("LuaData", data)) -ent:add_component(Wrapper.new("TestThing", { test = 1.23563 })) + LuaData = ecs.register("LuaData", { + speed = "number", + something = "string", + alive = "boolean" + }) + TestThing = ecs.register("TestThing", { + test = "string" + }) +end --- @todo Make this happen... --- stats = { --- hp = 100, --- magic = 30 --- } --- --- ent:add_component(ecs.Wrapper.new("Stats", stats)) -print(ent:has_components("Position", "Velocity")) -pos = ent:get_component("Position") -print("x: " .. pos.x) -print("y: " .. pos.y) -vel = ent:get_component("Velocity") -print("v_x: " .. vel.x) -print("v_y: " .. vel.y) +function run() + print("Running!") + manager = get_manager() + ent = manager:create_entity() + ent:add_component(Position.new(1.9, 9.7)) + ent:add_component(Velocity.new(0.2, 0.3)) + ent:add_component(Meta.new("Soldier")) -print("View test") -manager:view("Position", "Velocity"):for_each(function(ent) + ent:add_component(LuaData.new({ + speed = 10, + something = "Hello, World!", + alive = true + })) + ent:add_component(TestThing.new({ + test = "This is a test!" + })) + + -- @todo Make this happen... + -- stats = { + -- hp = 100, + -- magic = 30 + -- } + -- + -- ent:add_component(ecs.Wrapper.new("Stats", stats)) + + print(ent:has_components("Position", "Velocity")) pos = ent:get_component("Position") - vel = ent:get_component("Velocity") - - pos.x = pos.x + vel.x - pos.y = pos.y + vel.y - - print(ent) - print("x: " .. pos.x) print("y: " .. pos.y) - + vel = ent:get_component("Velocity") print("v_x: " .. vel.x) print("v_y: " .. vel.y) - if ent:has_components("Meta") then - meta = ent:get_component("Meta") - print("name: " .. meta.name) - end -end) + print("View test") + manager:view("Position", "Velocity"):for_each(function(ent) + pos = ent:get_component("Position") + vel = ent:get_component("Velocity") --- @todo Implement this --- for uuid,entity in pairs(view) do --- print "TEST" --- end + pos.x = pos.x + vel.x + pos.y = pos.y + vel.y -manager:view("LuaData"):for_each(function(ent) - d = ent:get_component("LuaData") + print(ent) - print(d.speed) - d.speed = 11 - print(d.speed) - print(data.speed) - data.speed = 20 - print(d.speed) - print(data.speed) + print("x: " .. pos.x) + print("y: " .. pos.y) - print(d.alive) - d.alive = false - print(d.alive) + print("v_x: " .. vel.x) + print("v_y: " .. vel.y) - print(d.something) -end) + if ent:has_components("Meta") then + meta = ent:get_component("Meta") + print("name: " .. meta.name) + end + end) -manager:view("TestThing"):for_each(function(ent) - t = ent:get_component("TestThing") + -- @todo Implement this + -- for uuid,entity in pairs(view) do + -- print "TEST" + -- end + + manager:view("LuaData"):for_each(function(ent) + d = ent:get_component("LuaData") - print(t.test) -end) + print("speed: " .. d.speed) + d.speed = 11 + print("speed: " .. d.speed) + + print("alive: ") print(d.alive) + d.alive = false + print("alive: ") print(d.alive) + + print("Something: " .. d.something) + end) + + manager:view("TestThing"):for_each(function(ent) + t = ent:get_component("TestThing") + + print("test: " .. t.test) + end) + + print("Done running!") +end diff --git a/test/test2.lua b/test/test2.lua index 178c54c..aeb1df4 100644 --- a/test/test2.lua +++ b/test/test2.lua @@ -1,26 +1,49 @@ -require "ecs" +local ecs = require "ecs" require "ecs.Wrapper" -manager = get_manager() +function init() + print("Registering components") -manager:view("TestThing"):for_each(function(ent) - data = ent:get_component("TestThing") - print("test: " .. data.test) -end) + LuaData = ecs.register("LuaData", { + speed = "number", + something = "string", + alive = "boolean" + }) + TestThing = ecs.register("TestThing", { + test = "string" + }) +end -manager:view("LuaData"):for_each(function(ent) - -- @todo It would be nice if this could somehow be passed in as function arg - data = ent:get_component("LuaData") - print("speed: " .. data.speed) - print("something: " .. data.something) - -- @todo You cannot concatenate bool to string - print("alive: ") - print(data.alive) -end) +function run() + print("Running!") --- @todo Allow this --- for i, v in pairs(manager:view("TestThing")) do --- print(i, v) --- end + manager = get_manager() -print(manager:has_entity("70bca3cf-33dd-40dc-8b0f-2e19aa0b4a17")) + print("AAA") + + manager:view("TestThing"):for_each(function(ent) + data = ent:get_component("TestThing") + print("test: " .. data.test) + end) + + + manager:view("LuaData"):for_each(function(ent) + -- @todo It would be nice if this could somehow be passed in as function arg + data = ent:get_component("LuaData") + print("speed: " .. data.speed) + print("something: " .. data.something) + -- @todo You cannot concatenate bool to string + print("alive: ") + print(data.alive) + end) + + -- @todo Allow this + -- for i, v in pairs(manager:view("TestThing")) do + -- print(i, v) + -- end + + print("Exists: ") + print(manager:has_entity("70bca3cf-33dd-40dc-8b0f-2e19aa0b4a17")) + + print("Done running!") +end