diff --git a/libs/util/include/psemek/util/ecs.hpp b/libs/util/include/psemek/util/ecs.hpp index 93ffbdc3..ba82cabc 100644 --- a/libs/util/include/psemek/util/ecs.hpp +++ b/libs/util/include/psemek/util/ecs.hpp @@ -106,6 +106,14 @@ namespace psemek::util apply_single_impl(behavior, entity, static_cast(nullptr), std::make_index_sequence>{}, args...); } + template + void apply_species(Behavior & behavior, Args const & ... args) + { + if (!check_forbidden(behavior, 0)) + return; + apply_species_impl(behavior, static_cast(nullptr), std::make_index_sequence>{}, args...); + } + virtual ~species_base() {} virtual entity_id const * get_free_list() const = 0; @@ -257,6 +265,39 @@ namespace psemek::util std::apply(visit, cptrs); } + + template + void apply_species_impl(Behavior & behavior, std::tuple *, std::index_sequence, Args const & ... args) + { + std::tuple cptrs; + + ((std::get(cptrs) = get_species_component()), ...); + + auto all_nonzero = [](auto * ... ptrs) + { + return ((ptrs != nullptr) && ...); + }; + + if (!std::apply(all_nonzero, cptrs)) + return; + + typename Behavior::context ctx{*ecs_}; + ctx.species.value = id_; + + auto visit = [&](auto * ... ptrs) + { + if constexpr (std::is_invocable_v) + { + behavior(*ptrs..., ctx, args...); + } + else + { + behavior(*ptrs..., args...); + } + }; + + std::apply(visit, cptrs); + } }; template @@ -516,6 +557,23 @@ namespace psemek::util void begin(species_handle, Components const & ...) {} }; + template + struct species_behavior + { + using component_types = std::tuple; + using component_ptrs = std::tuple; + + struct context + { + struct ecs & ecs; + species_handle species; + + context(struct ecs & ecs) + : ecs(ecs) + {} + }; + }; + struct species_iterator { species_iterator(ecs_detail::species_handle h) @@ -604,6 +662,12 @@ namespace psemek::util template void apply(Behavior && behavior, entity_handle entity, Args const & ... args); + template + void apply_species(Behavior && behavior, Args const & ... args); + + template + void apply_species(Behavior && behavior, species_handle species, Args const & ... args); + template void register_processor(Processor && processor); @@ -613,12 +677,21 @@ namespace psemek::util template void register_behavior(Behavior && behavior, species_handle species); + template + void register_species_behavior(Behavior && behavior); + + template + void register_species_behavior(Behavior && behavior, species_handle species); + template void register_constructor(Behavior && behavior); template void register_constructor(Behavior && behavior, species_handle species); + template + void register_species_constructor(Behavior && behavior); + template void register_destructor(Behavior && behavior); @@ -633,22 +706,26 @@ namespace psemek::util std::unordered_map>> event_subscribers_; + std::vector> species_constructors_; + std::vector> constructors_; - std::unordered_map>> species_constructors_; + std::unordered_map>> private_constructors_; std::vector> destructors_; - std::unordered_map>> species_destructors_; + std::unordered_map>> private_destructors_; }; template ecs::species_handle ecs::register_species(std::string name, policy p, Components && ... components) { - auto result = species_.size(); + species_handle result{species_.size()}; if (p == policy::sparse) - species_.push_back(std::make_unique>(this, std::move(name), result, std::move(components)...)); + species_.push_back(std::make_unique>(this, std::move(name), result.value, std::move(components)...)); else - species_.push_back(std::make_unique>(this, std::move(name), result, std::move(components)...)); - return {result}; + species_.push_back(std::make_unique>(this, std::move(name), result.value, std::move(components)...)); + for (auto const & ctor : species_constructors_) + ctor(result); + return result; } template @@ -658,7 +735,7 @@ namespace psemek::util ((get(entity) = std::move(components)), ...); for (auto const & ctor : constructors_) ctor(entity); - for (auto const & ctor : species_constructors_[species.value]) + for (auto const & ctor : private_constructors_[species.value]) ctor(entity); return entity; } @@ -672,7 +749,7 @@ namespace psemek::util { for (auto const & dtor : destructors_) dtor(entity); - for (auto const & dtor : species_destructors_[ecs_detail::unpack(entity.value).species]) + for (auto const & dtor : private_destructors_[ecs_detail::unpack(entity.value).species]) dtor(entity); species_[ecs_detail::unpack(entity.value).species]->remove_entity(entity.value); } @@ -761,6 +838,19 @@ namespace psemek::util species_[id.species]->apply_single(behavior, id.entity, args...); } + template + void ecs::apply_species(Behavior && behavior, Args const & ... args) + { + for (auto & s : species_) + s->apply_species(behavior, args...); + } + + template + void ecs::apply_species(Behavior && behavior, species_handle species, Args const & ... args) + { + species_[species.value]->apply_species(behavior, args...); + } + template void ecs::register_processor(Processor && processor) { @@ -785,6 +875,22 @@ namespace psemek::util }); } + template + void ecs::register_species_behavior(Behavior && behavior) + { + event_subscribers_[typeid(Event)].push_back([this, behavior = std::move(behavior)](void const * event) mutable { + apply_species(behavior, *static_cast(event)); + }); + } + + template + void ecs::register_species_behavior(Behavior && behavior, species_handle species) + { + event_subscribers_[typeid(Event)].push_back([this, species, behavior = std::move(behavior)](void const * event) mutable { + apply_species(behavior, species, *static_cast(event)); + }); + } + template void ecs::register_constructor(Behavior && behavior) { @@ -796,11 +902,19 @@ namespace psemek::util template void ecs::register_constructor(Behavior && behavior, species_handle species) { - species_constructors_[species.value].push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable { + private_constructors_[species.value].push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable { apply(behavior, entity); }); } + template + void ecs::register_species_constructor(Behavior && behavior) + { + species_constructors_.push_back([this, behavior = std::move(behavior)](species_handle species) mutable { + apply_species(behavior, species); + }); + } + template void ecs::register_destructor(Behavior && behavior) { @@ -812,7 +926,7 @@ namespace psemek::util template void ecs::register_destructor(Behavior && behavior, species_handle species) { - species_destructors_[species.value].push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable { + private_destructors_[species.value].push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable { apply(behavior, entity); }); }