ECS destructors wip

This commit is contained in:
Nikita Lisitsa 2023-12-18 12:45:42 +03:00
parent 028b4e1296
commit a85e72a5b6
7 changed files with 79 additions and 3 deletions

View file

@ -336,7 +336,6 @@ namespace psemek::ecs
* detaches components), the behavior is undefined
* @warning If the destructor destroys the entity recursively, the behavior is undefined
*/
// TODO: implement
template <typename ... Components, typename Function>
void destructor(Function && function);
@ -631,4 +630,30 @@ namespace psemek::ecs
callback_caches_.push_back(cache);
}
template <typename ... Components, typename Function>
void container::destructor(Function && function)
{
static_assert(detail::all_different_types_v<std::remove_const_t<Components>...>, "all component types must be different");
using invocable_type = typename detail::filter_with<detail::invocable, std::tuple<Components ...>, Function>::type;
static_assert(invocable_type::value, "function is not invocable with these components");
query_cache cache = this->cache<Components...>();
cache->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){
typename detail::filter_with<detail::static_apply_helper, std::tuple<Components ...>>::type apply_helper(container, table.entity_handles());
for (std::size_t i = 0; i < apply_helper.column_count; ++i)
apply_helper.pointers[i] = table.columns()[column_indices[i]]->data();
apply_helper.advance(row);
apply_helper.apply(function);
};
};
callback_caches_.push_back(cache);
}
}

View file

@ -24,6 +24,7 @@ namespace psemek::ecs::detail
std::vector<query_cache_entry> entries;
util::function<table_callback(std::vector<std::uint32_t> const &)> constructor_factory;
util::function<table_callback(std::vector<std::uint32_t> const &)> destructor_factory;
void add(table * table);
};

View file

@ -73,8 +73,10 @@ namespace psemek::ecs::detail
std::vector<std::type_index> const & non_copyable_components() const;
void add_constructor(table_callback callback);
void add_destructor(table_callback callback);
void trigger_constructors(container & container, std::uint32_t row);
void trigger_destructors(container & container, std::uint32_t row);
protected:
std::size_t hash_;
@ -90,6 +92,7 @@ namespace psemek::ecs::detail
std::vector<std::type_index> non_copyable_components_;
std::shared_ptr<std::vector<table_callback>> constructors_;
std::shared_ptr<std::vector<table_callback>> destructors_;
};
}

View file

@ -78,6 +78,8 @@ namespace psemek::ecs
auto & data = entities[entity.id];
auto & iteration_data = data.table->get_iteration_data();
data.table->trigger_destructors(*this, data.row);
if (!iteration_data || iteration_data->current_row < data.row)
remove_row(*data.table, data.row, entities);
else

View file

@ -14,6 +14,9 @@ namespace psemek::ecs::detail
if (constructor_factory)
table->add_constructor(constructor_factory(entry.columns_indices));
if (destructor_factory)
table->add_destructor(destructor_factory(entry.columns_indices));
}
}

View file

@ -21,6 +21,7 @@ namespace psemek::ecs::detail
columns_ = std::move(columns);
constructors_ = std::make_shared<std::vector<table_callback>>();
destructors_ = std::make_shared<std::vector<table_callback>>();
}
std::optional<std::size_t> table::column_index(util::uuid const & uuid) const
@ -108,6 +109,7 @@ namespace psemek::ecs::detail
auto result = std::make_unique<table>(std::move(columns));
result->constructors_ = constructors_;
result->destructors_ = destructors_;
return result;
}
@ -146,12 +148,21 @@ namespace psemek::ecs::detail
constructors_->push_back(std::move(callback));
}
void table::add_destructor(table_callback callback)
{
destructors_->push_back(std::move(callback));
}
void table::trigger_constructors(container & container, std::uint32_t row)
{
for (auto const & callback : *constructors_)
{
callback(container, *this, row);
}
}
void table::trigger_destructors(container & container, std::uint32_t row)
{
for (auto const & callback : *destructors_)
callback(container, *this, row);
}
}

View file

@ -52,3 +52,34 @@ test_case(ecs_callback_constructor_create)
container.create(component_1{40}, component_2{200});
expect_equal(value, 40);
}
test_case(ecs_callback_destructor_destroy)
{
container container;
int value = 0;
container.destructor<component_1>([&value](component_1 const & c1){
value = c1.value;
});
auto h1 = container.create(component_1{10});
auto h2 = container.create(component_1{20});
auto h3 = container.create(component_2{100});
auto h4 = container.create();
auto h5 = container.create(component_1{30});
auto h6 = container.create(component_1{40}, component_2{200});
expect_equal(value, 0);
container.destroy(h1);
expect_equal(value, 10);
container.destroy(h2);
expect_equal(value, 20);
container.destroy(h3);
expect_equal(value, 20);
container.destroy(h4);
expect_equal(value, 20);
container.destroy(h5);
expect_equal(value, 30);
container.destroy(h6);
expect_equal(value, 40);
}