Fix triggering constructor & destructor callbacks when attaching/detaching ecs components

This commit is contained in:
Nikita Lisitsa 2025-03-06 18:20:08 +03:00
parent 42260d4d7d
commit e5811b61a0
5 changed files with 42 additions and 20 deletions

View file

@ -479,6 +479,9 @@ namespace psemek::ecs
for (auto const & uuid : attached_uuid_set)
uuids.push_back(uuid);
if (archetype_changed)
data->table->trigger_destructors(*this, data->row, attached_uuid_set, {});
auto table = table_container_.get(uuids);
if (!table)
@ -508,7 +511,7 @@ namespace psemek::ecs
((accessor.get<std::remove_cvref_t<Components>>() = std::forward<Components>(components)), ...);
if (archetype_changed)
table->trigger_constructors(*this, data->row, attached_uuid_set);
table->trigger_constructors(*this, data->row, attached_uuid_set, {});
attached_uuid_set.clear();
uuids.clear();
@ -530,10 +533,9 @@ namespace psemek::ecs
auto * data = entity_list_.get_entities().begin() + entity.id;
for (auto const & column : data->table->columns())
{
if (detached_uuid_set.contains(column->uuid()))
detached_uuid_set.insert(column->uuid());
else
uuids.push_back(column->uuid());
auto const column_uuid = column->uuid();
if (!detached_uuid_set.contains(column_uuid))
uuids.push_back(column_uuid);
}
bool const archetype_changed = sizeof...(Components) > 0;
@ -541,7 +543,7 @@ namespace psemek::ecs
auto table = table_container_.get(uuids);
if (archetype_changed)
data->table->trigger_destructors(*this, data->row, detached_uuid_set);
data->table->trigger_destructors(*this, data->row, {}, detached_uuid_set);
// Destructors could lead to reallocation of entity list
data = entity_list_.get_entities().begin() + entity.id;
@ -568,6 +570,9 @@ namespace psemek::ecs
data->row = new_row;
}
if (archetype_changed)
table->trigger_constructors(*this, data->row, {}, detached_uuid_set);
detached_uuid_set.clear();
uuids.clear();
detached_uuid_set.clear();
@ -664,9 +669,12 @@ namespace psemek::ecs
auto id = next_constructor_id_++;
auto constructor_factory = [function = std::move(function)](std::vector<std::uint32_t> const & column_indices) -> detail::table_callback {
return [function, column_indices](container & container, detail::table & table, std::uint32_t row, util::hash_set<util::uuid> const & attached_components, bool force){
return [function, column_indices](container & container, detail::table & table, std::uint32_t row, util::hash_set<util::uuid> const & attached_components, util::hash_set<util::uuid> const & detached_components, bool force){
bool const invoke = force || (detail::contains_helper<Components>::contains(attached_components) || ...);
bool const invoke = force
|| (detail::contains_helper<Components>::contains(attached_components) || ...)
|| (detail::contains_helper<Components>::contains_without(detached_components) || ...)
;
if (!invoke)
return;
@ -699,9 +707,11 @@ namespace psemek::ecs
auto id = next_destructor_id_++;
auto destructor_factory = [function = std::move(function)](std::vector<std::uint32_t> const & column_indices) -> detail::table_callback {
return [function, column_indices](container & container, detail::table & table, std::uint32_t row, util::hash_set<util::uuid> const & detached_components, bool force){
bool const invoke = force || (detail::contains_helper<Components>::contains(detached_components) || ...);
return [function, column_indices](container & container, detail::table & table, std::uint32_t row, util::hash_set<util::uuid> const & attached_components, util::hash_set<util::uuid> const & detached_components, bool force){
bool const invoke = force
|| (detail::contains_helper<Components>::contains_without(attached_components) || ...)
|| (detail::contains_helper<Components>::contains(detached_components) || ...)
;
if (!invoke)
return;

View file

@ -16,7 +16,7 @@ namespace psemek::ecs
struct table;
using table_callback = util::function<void(container &, table &, std::uint32_t, util::hash_set<util::uuid> const &, bool)>;
using table_callback = util::function<void(container &, table &, std::uint32_t, util::hash_set<util::uuid> const &, util::hash_set<util::uuid> const &, bool)>;
struct ordered_table_callback
{

View file

@ -74,10 +74,10 @@ namespace psemek::ecs::detail
void add_destructor(ordered_table_callback callback);
void trigger_constructors(container & container, std::uint32_t row);
void trigger_constructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & attached_components);
void trigger_constructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & attached_components, util::hash_set<util::uuid> const & detached_components);
void trigger_destructors(container & container, std::uint32_t row);
void trigger_destructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & detached_components);
void trigger_destructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & attached_components, util::hash_set<util::uuid> const & detached_components);
std::size_t memory_usage() const;

View file

@ -87,6 +87,12 @@ namespace psemek::ecs::detail
{
return container.contains(Component::uuid());
}
template <typename Container>
static bool contains_without(Container const &)
{
return false;
}
};
template <typename Component>
@ -97,6 +103,12 @@ namespace psemek::ecs::detail
{
return false;
}
template <typename Container>
static bool contains_without(Container const & container)
{
return container.contains(Component::uuid());
}
};
}

View file

@ -161,25 +161,25 @@ namespace psemek::ecs::detail
void table::trigger_constructors(container & container, std::uint32_t row)
{
for (auto const & callback : *constructors_)
callback.callback(container, *this, row, column_uuid_set_, true);
callback.callback(container, *this, row, column_uuid_set_, {}, true);
}
void table::trigger_constructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & attached_components)
void table::trigger_constructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & attached_components, util::hash_set<util::uuid> const & detached_components)
{
for (auto const & callback : *constructors_)
callback.callback(container, *this, row, attached_components, false);
callback.callback(container, *this, row, attached_components, detached_components, false);
}
void table::trigger_destructors(container & container, std::uint32_t row)
{
for (auto const & callback : *destructors_)
callback.callback(container, *this, row, column_uuid_set_, true);
callback.callback(container, *this, row, {}, column_uuid_set_, true);
}
void table::trigger_destructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & detached_components)
void table::trigger_destructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & attached_components, util::hash_set<util::uuid> const & detached_components)
{
for (auto const & callback : *destructors_)
callback.callback(container, *this, row, detached_components, false);
callback.callback(container, *this, row, attached_components, detached_components, false);
}
std::size_t table::memory_usage() const