From bda4a156e745efda17903ea6666f1ea13cbc8343 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sun, 17 Dec 2023 15:44:38 +0300 Subject: [PATCH] Support registering components in ecs::container --- libs/ecs/include/psemek/ecs/container.hpp | 29 ++++++++++++++++- .../psemek/ecs/detail/component_registry.hpp | 32 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 libs/ecs/include/psemek/ecs/detail/component_registry.hpp diff --git a/libs/ecs/include/psemek/ecs/container.hpp b/libs/ecs/include/psemek/ecs/container.hpp index 89aa1e3e..bc5e44c6 100644 --- a/libs/ecs/include/psemek/ecs/container.hpp +++ b/libs/ecs/include/psemek/ecs/container.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,6 @@ namespace psemek::ecs // - Fully document which functions can be called from which callbacks // - Constructors & destructors implementation (const-only) // - Modification callbacks implementation (const-only) - // - Registering components // - Tables serialization // - Refactor query caches // - Index API @@ -32,6 +32,18 @@ namespace psemek::ecs struct container { + /** Register a component type within this container. This is used to properly deserialize + * a serialized container, otherwise it wouldn't know how to create entity tables from + * serialized data. + * + * Note that creating entities or attaching components to them automatically registers all + * referenced components. + * + * @tparam Component The component type to register + */ + template + void register_component(); + /** Create an entity with the specified components. It is faster to create an entity * with all the components at once than to create it with no components and `attach()` * them one-by-one. @@ -41,6 +53,8 @@ namespace psemek::ecs * If the entity is created during iteration (inside an `apply()` call), it is unspecified * whether the created entity will be visited by iteration or not. * + * This function automatically registers all the entity's component types by calling `register_component()`. + * * @param components The components to initialize the entity with * @return A unique handle to the created entity * @warning If any two of the passed component types are equal, the call fails with @@ -124,6 +138,8 @@ namespace psemek::ecs * For the purposes of `apply()` semantics, attaching behaves as if * the entity was destroyed and then recreated with the same handle. * + * This function automatically registers all the new component types by calling `register_component()`. + * * @param entity A handle to the entity to attach components to * @param components The components to attach to the entity * @pre The entity was previously obtained by a `create()` call and is `alive()` @@ -366,6 +382,7 @@ namespace psemek::ecs detail::entity_list entity_list_; detail::table_container table_container_; detail::query_cache_container query_cache_container_; + detail::component_registry component_registry_; std::vector uuid_helper_; util::hash_set uuid_set_helper_; @@ -375,11 +392,19 @@ namespace psemek::ecs void remove_row(detail::table & table, std::uint32_t row, util::span entities); }; + template + void container::register_component() + { + component_registry_.register_component(); + } + template handle container::create(Components && ... components) { static_assert(detail::all_different_types_v...>, "all component types must be different"); + (register_component(), ...); + detail::component_uuid_helper...> uuids; auto table = table_container_.get(uuids.get()); @@ -410,6 +435,8 @@ namespace psemek::ecs { static_assert(detail::all_different_types_v...>, "all component types must be different"); + (register_component(), ...); + auto & data = entity_list_.get_entities()[entity.id]; for (auto const & column : data.table->columns()) uuid_helper_.push_back(column->uuid()); diff --git a/libs/ecs/include/psemek/ecs/detail/component_registry.hpp b/libs/ecs/include/psemek/ecs/detail/component_registry.hpp new file mode 100644 index 00000000..49cc9fa1 --- /dev/null +++ b/libs/ecs/include/psemek/ecs/detail/component_registry.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include + +namespace psemek::ecs::detail +{ + + struct component_registry + { + template + void register_component() + { + column_factories_.insert({Component::uuid(), []{ + return std::make_unique>(); + }}); + } + + std::unique_ptr create_column(util::uuid const & uuid) const + { + if (auto it = column_factories_.find(uuid); it != column_factories_.end()) + return it->second(); + return nullptr; + } + + private: + util::hash_map()>> column_factories_; + }; + +}