Support registering components in ecs::container
This commit is contained in:
parent
3b5e649a31
commit
bda4a156e7
2 changed files with 60 additions and 1 deletions
|
|
@ -7,6 +7,7 @@
|
|||
#include <psemek/ecs/detail/all_different_types.hpp>
|
||||
#include <psemek/ecs/detail/component_uuid_helper.hpp>
|
||||
#include <psemek/ecs/detail/without.hpp>
|
||||
#include <psemek/ecs/detail/component_registry.hpp>
|
||||
#include <psemek/ecs/accessor.hpp>
|
||||
#include <psemek/ecs/exceptions.hpp>
|
||||
#include <psemek/util/range.hpp>
|
||||
|
|
@ -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 <typename Component>
|
||||
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<util::uuid> uuid_helper_;
|
||||
util::hash_set<util::uuid> uuid_set_helper_;
|
||||
|
|
@ -375,11 +392,19 @@ namespace psemek::ecs
|
|||
void remove_row(detail::table & table, std::uint32_t row, util::span<detail::entity_data> entities);
|
||||
};
|
||||
|
||||
template <typename Component>
|
||||
void container::register_component()
|
||||
{
|
||||
component_registry_.register_component<Component>();
|
||||
}
|
||||
|
||||
template <typename ... Components>
|
||||
handle container::create(Components && ... components)
|
||||
{
|
||||
static_assert(detail::all_different_types_v<std::remove_cvref_t<Components>...>, "all component types must be different");
|
||||
|
||||
(register_component<Components>(), ...);
|
||||
|
||||
detail::component_uuid_helper<std::remove_cvref_t<Components>...> uuids;
|
||||
|
||||
auto table = table_container_.get(uuids.get());
|
||||
|
|
@ -410,6 +435,8 @@ namespace psemek::ecs
|
|||
{
|
||||
static_assert(detail::all_different_types_v<std::remove_cvref_t<Components>...>, "all component types must be different");
|
||||
|
||||
(register_component<Components>(), ...);
|
||||
|
||||
auto & data = entity_list_.get_entities()[entity.id];
|
||||
for (auto const & column : data.table->columns())
|
||||
uuid_helper_.push_back(column->uuid());
|
||||
|
|
|
|||
32
libs/ecs/include/psemek/ecs/detail/component_registry.hpp
Normal file
32
libs/ecs/include/psemek/ecs/detail/component_registry.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <psemek/ecs/detail/column.hpp>
|
||||
#include <psemek/util/uuid.hpp>
|
||||
#include <psemek/util/hash_table.hpp>
|
||||
#include <psemek/util/function.hpp>
|
||||
|
||||
namespace psemek::ecs::detail
|
||||
{
|
||||
|
||||
struct component_registry
|
||||
{
|
||||
template <typename Component>
|
||||
void register_component()
|
||||
{
|
||||
column_factories_.insert({Component::uuid(), []{
|
||||
return std::make_unique<column_impl<Component>>();
|
||||
}});
|
||||
}
|
||||
|
||||
std::unique_ptr<column> 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<util::uuid, util::function<std::unique_ptr<column>()>> column_factories_;
|
||||
};
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue