Refactor ecs::entity_container & add documentation
This commit is contained in:
parent
c1991cbb57
commit
82682c0317
2 changed files with 116 additions and 79 deletions
|
|
@ -15,93 +15,37 @@ namespace psemek::ecs
|
||||||
|
|
||||||
struct entity_container
|
struct entity_container
|
||||||
{
|
{
|
||||||
|
// Create an entity with the specified components
|
||||||
|
// NB: equivalent to create() followed by a
|
||||||
|
// series of attach() calls, but faster
|
||||||
template <typename ... Components>
|
template <typename ... Components>
|
||||||
entity_handle create(Components && ... components)
|
entity_handle create(Components && ... components);
|
||||||
{
|
|
||||||
detail::component_uuid_holder<Components...> uuids;
|
|
||||||
detail::component_mask mask = component_index_.make_component_mask(uuids.get());
|
|
||||||
|
|
||||||
auto insert_result = table_container_.insert<Components...>(mask, uuids.get());
|
// Check if an entity handle refers to an active entity
|
||||||
auto table = insert_result.first;
|
// UB if the handle wasn't obtained by a create() call
|
||||||
bool created = insert_result.second;
|
bool alive(entity_handle const & entity) const;
|
||||||
|
|
||||||
if (created)
|
// Destroy an entity
|
||||||
{
|
// UB if the handle wasn't obtained by a create() call
|
||||||
query_cache_container_.apply([table](detail::query_cache & cache){
|
// or if the entity was already destroyed
|
||||||
cache.add(table);
|
void destroy(entity_handle const & entity);
|
||||||
}, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto id = entity_list_.create(table, table->row_count());
|
// Get an entity accessor for an entity
|
||||||
entity_handle handle{id, entity_list_.get_entities()[id].epoch};
|
// UB if the handle wasn't obtained by a create() call
|
||||||
[[maybe_unused]] entity_accessor accessor = get(handle);
|
// or if the entity isn't active
|
||||||
|
entity_accessor get(entity_handle const & entity);
|
||||||
table->push_row(id);
|
|
||||||
((accessor.get<Components>() = std::move(components)), ...);
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool alive(entity_handle const & entity) const
|
|
||||||
{
|
|
||||||
return entity_list_.get_entities()[entity.id].epoch == entity.epoch;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy(entity_handle const & entity)
|
|
||||||
{
|
|
||||||
// Swap with the last row in that table
|
|
||||||
auto entities = entity_list_.get_entities();
|
|
||||||
auto & data = entities[entity.id];
|
|
||||||
auto table_entity_ids = data.table->get_entity_ids();
|
|
||||||
data.table->swap_rows(data.row, table_entity_ids.size() - 1);
|
|
||||||
data.table->pop_row();
|
|
||||||
auto swap_id = table_entity_ids[data.row];
|
|
||||||
auto & swap_data = entities[swap_id];
|
|
||||||
swap_data.row = data.row;
|
|
||||||
entity_list_.destroy(entity.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Create a query cache that can be used for the
|
||||||
|
// apply() call to speed it up
|
||||||
template <typename ... Components>
|
template <typename ... Components>
|
||||||
query_cache cache()
|
query_cache cache();
|
||||||
{
|
|
||||||
detail::component_uuid_holder<Components...> uuids;
|
|
||||||
detail::component_mask mask = component_index_.make_component_mask(uuids.get());
|
|
||||||
|
|
||||||
auto result = query_cache_container_.create(mask, uuids.get());
|
|
||||||
|
|
||||||
table_container_.apply([&](detail::table & table){
|
|
||||||
result->add(&table);
|
|
||||||
}, mask);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Apply a function to all entities having the specified
|
||||||
|
// components. The function signature is void(entity_handle, components...)
|
||||||
|
// An optional query cache can be supplied to speed up the call
|
||||||
|
// UB if the cache wasn't created with the exact same component sequence
|
||||||
template <typename ... Components, typename Function>
|
template <typename ... Components, typename Function>
|
||||||
void apply(Function && function, query_cache cache = {})
|
void apply(Function && function, query_cache cache = {});
|
||||||
{
|
|
||||||
if (!cache)
|
|
||||||
cache = this->cache<Components...>();
|
|
||||||
|
|
||||||
for (auto const & entry : cache->tables)
|
|
||||||
{
|
|
||||||
detail::static_apply_helper<Components...> apply_helper(entry.table->get_entity_ids(), entity_list_.get_entities());
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < sizeof...(Components); ++i)
|
|
||||||
apply_helper.pointers[i] = entry.table->get_component_pointers()[entry.column_ids[i]];
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < apply_helper.size(); ++i)
|
|
||||||
{
|
|
||||||
apply_helper.apply(function);
|
|
||||||
apply_helper.advance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entity_accessor get(entity_handle const & entity)
|
|
||||||
{
|
|
||||||
auto const & data = entity_list_.get_entities()[entity.id];
|
|
||||||
return {data.table, data.row};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
detail::entity_list entity_list_;
|
detail::entity_list entity_list_;
|
||||||
|
|
@ -110,4 +54,66 @@ namespace psemek::ecs
|
||||||
detail::query_cache_container query_cache_container_;
|
detail::query_cache_container query_cache_container_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename ... Components>
|
||||||
|
entity_handle entity_container::create(Components && ... components)
|
||||||
|
{
|
||||||
|
detail::component_uuid_holder<Components...> uuids;
|
||||||
|
detail::component_mask mask = component_index_.make_component_mask(uuids.get());
|
||||||
|
|
||||||
|
auto insert_result = table_container_.insert<Components...>(mask, uuids.get());
|
||||||
|
auto table = insert_result.first;
|
||||||
|
bool created = insert_result.second;
|
||||||
|
|
||||||
|
if (created)
|
||||||
|
{
|
||||||
|
query_cache_container_.apply([table](detail::query_cache & cache){
|
||||||
|
cache.add(table);
|
||||||
|
}, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto id = entity_list_.create(table, table->row_count());
|
||||||
|
entity_handle handle{id, entity_list_.get_entities()[id].epoch};
|
||||||
|
[[maybe_unused]] entity_accessor accessor = get(handle);
|
||||||
|
|
||||||
|
table->push_row(id);
|
||||||
|
((accessor.get<Components>() = std::move(components)), ...);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ... Components>
|
||||||
|
query_cache entity_container::cache()
|
||||||
|
{
|
||||||
|
detail::component_uuid_holder<Components...> uuids;
|
||||||
|
detail::component_mask mask = component_index_.make_component_mask(uuids.get());
|
||||||
|
|
||||||
|
auto result = query_cache_container_.create(mask, uuids.get());
|
||||||
|
|
||||||
|
table_container_.apply([&](detail::table & table){
|
||||||
|
result->add(&table);
|
||||||
|
}, mask);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ... Components, typename Function>
|
||||||
|
void entity_container::apply(Function && function, query_cache cache)
|
||||||
|
{
|
||||||
|
if (!cache)
|
||||||
|
cache = this->cache<Components...>();
|
||||||
|
|
||||||
|
for (auto const & entry : cache->tables)
|
||||||
|
{
|
||||||
|
detail::static_apply_helper<Components...> apply_helper(entry.table->get_entity_ids(), entity_list_.get_entities());
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < sizeof...(Components); ++i)
|
||||||
|
apply_helper.pointers[i] = entry.table->get_component_pointers()[entry.column_ids[i]];
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < apply_helper.size(); ++i)
|
||||||
|
{
|
||||||
|
apply_helper.apply(function);
|
||||||
|
apply_helper.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
libs/ecs/source/entity_container.cpp
Normal file
31
libs/ecs/source/entity_container.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#include <psemek/ecs/entity_container.hpp>
|
||||||
|
|
||||||
|
namespace psemek::ecs
|
||||||
|
{
|
||||||
|
|
||||||
|
bool entity_container::alive(entity_handle const & entity) const
|
||||||
|
{
|
||||||
|
return entity_list_.get_entities()[entity.id].epoch == entity.epoch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_container::destroy(entity_handle const & entity)
|
||||||
|
{
|
||||||
|
// Swap with the last row in that table
|
||||||
|
auto entities = entity_list_.get_entities();
|
||||||
|
auto & data = entities[entity.id];
|
||||||
|
auto table_entity_ids = data.table->get_entity_ids();
|
||||||
|
data.table->swap_rows(data.row, table_entity_ids.size() - 1);
|
||||||
|
data.table->pop_row();
|
||||||
|
auto swap_id = table_entity_ids[data.row];
|
||||||
|
auto & swap_data = entities[swap_id];
|
||||||
|
swap_data.row = data.row;
|
||||||
|
entity_list_.destroy(entity.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_accessor entity_container::get(entity_handle const & entity)
|
||||||
|
{
|
||||||
|
auto const & data = entity_list_.get_entities()[entity.id];
|
||||||
|
return {data.table, data.row};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue