Implement ecs constructors & destructors

This commit is contained in:
Nikita Lisitsa 2022-10-28 23:36:04 +03:00
parent 55c3266343
commit 20401bee45

View file

@ -95,6 +95,14 @@ namespace psemek::util
apply_impl(behavior, static_cast<typename Behavior::component_types *>(nullptr), std::make_index_sequence<std::tuple_size_v<typename Behavior::component_types>>{}, args...); apply_impl(behavior, static_cast<typename Behavior::component_types *>(nullptr), std::make_index_sequence<std::tuple_size_v<typename Behavior::component_types>>{}, args...);
} }
template <typename Behavior, typename ... Args>
void apply_single(Behavior & behavior, entity_id entity, Args const & ... args)
{
if (!check_forbidden(behavior, 0))
return;
apply_single_impl(behavior, entity, static_cast<typename Behavior::component_types *>(nullptr), std::make_index_sequence<std::tuple_size_v<typename Behavior::component_types>>{}, args...);
}
virtual ~species_base() {} virtual ~species_base() {}
virtual entity_id const * get_free_list() const = 0; virtual entity_id const * get_free_list() const = 0;
@ -202,6 +210,44 @@ namespace psemek::util
} }
} }
} }
template <typename Behavior, typename ... Components, std::size_t ... Is, typename ... Args>
void apply_single_impl(Behavior & behavior, entity_id entity, std::tuple<Components...> *, std::index_sequence<Is...>, Args const & ... args)
{
std::tuple<typename Components::data * ...> cptrs;
((std::get<Is>(cptrs) = get_entity_component<Components>()), ...);
auto all_nonzero = [](auto * ... ptrs)
{
return ((ptrs != nullptr) && ...);
};
if (!std::apply(all_nonzero, cptrs))
return;
((std::get<Is>(cptrs) += entity), ...);
typename Behavior::context ctx;
((std::get<Components *>(ctx.components) = get_species_component<Components>()), ...);
behavior.begin({id_}, *std::get<Components *>(ctx.components)...);
auto visit = [&](auto * ... ptrs)
{
if constexpr (std::is_invocable_v<Behavior, typename Components::data & ..., typename Behavior::context const &, Args const & ...>)
{
behavior(*ptrs..., ctx, args...);
}
else
{
behavior(*ptrs..., args...);
}
};
std::apply(visit, cptrs);
}
}; };
template <typename ... Components> template <typename ... Components>
@ -539,6 +585,9 @@ namespace psemek::util
template <typename Behavior, typename ... Args> template <typename Behavior, typename ... Args>
void apply(Behavior && behavior, species_handle species, Args const & ... args); void apply(Behavior && behavior, species_handle species, Args const & ... args);
template <typename Behavior, typename ... Args>
void apply(Behavior && behavior, entity_handle entity, Args const & ... args);
template <typename Event, typename Processor> template <typename Event, typename Processor>
void register_processor(Processor && processor); void register_processor(Processor && processor);
@ -548,6 +597,18 @@ namespace psemek::util
template <typename Event, typename Behavior> template <typename Event, typename Behavior>
void register_behavior(Behavior && behavior, species_handle species); void register_behavior(Behavior && behavior, species_handle species);
template <typename Behavior>
void register_constructor(Behavior && behavior);
template <typename Behavior>
void register_constructor(Behavior && behavior, species_handle species);
template <typename Behavior>
void register_destructor(Behavior && behavior);
template <typename Behavior>
void register_destructor(Behavior && behavior, species_handle species);
template <typename Event> template <typename Event>
void event(Event const & event); void event(Event const & event);
@ -555,6 +616,12 @@ namespace psemek::util
std::vector<std::unique_ptr<ecs_detail::species_base>> species_; std::vector<std::unique_ptr<ecs_detail::species_base>> species_;
std::unordered_map<std::type_index, std::vector<util::function<void(void const *)>>> event_subscribers_; std::unordered_map<std::type_index, std::vector<util::function<void(void const *)>>> event_subscribers_;
std::vector<util::function<void(entity_handle)>> constructors_;
std::unordered_map<ecs_detail::species_handle, std::vector<util::function<void(entity_handle)>>> species_constructors_;
std::vector<util::function<void(entity_handle)>> destructors_;
std::unordered_map<ecs_detail::species_handle, std::vector<util::function<void(entity_handle)>>> species_destructors_;
}; };
template <typename ... Components> template <typename ... Components>
@ -570,7 +637,12 @@ namespace psemek::util
inline ecs::entity_handle ecs::add_entity(species_handle species) inline ecs::entity_handle ecs::add_entity(species_handle species)
{ {
return {species_[species.value]->add_entity()}; entity_handle entity{species_[species.value]->add_entity()};
for (auto const & ctor : constructors_)
ctor(entity);
for (auto const & ctor : species_constructors_[species.value])
ctor(entity);
return entity;
} }
inline ecs_detail::entity_id ecs::entity_count(species_handle species) const inline ecs_detail::entity_id ecs::entity_count(species_handle species) const
@ -580,6 +652,10 @@ namespace psemek::util
inline void ecs::remove_entity(entity_handle entity) inline void ecs::remove_entity(entity_handle entity)
{ {
for (auto const & dtor : destructors_)
dtor(entity);
for (auto const & dtor : species_destructors_[ecs_detail::unpack(entity.value).species])
dtor(entity);
species_[ecs_detail::unpack(entity.value).species]->remove_entity(entity.value); species_[ecs_detail::unpack(entity.value).species]->remove_entity(entity.value);
} }
@ -660,6 +736,13 @@ namespace psemek::util
species_[species.value]->apply(behavior, args...); species_[species.value]->apply(behavior, args...);
} }
template <typename Behavior, typename ... Args>
void ecs::apply(Behavior && behavior, entity_handle entity, Args const & ... args)
{
auto id = ecs_detail::unpack(entity.value);
species_[id.species]->apply_single(behavior, id.entity, args...);
}
template <typename Event, typename Processor> template <typename Event, typename Processor>
void ecs::register_processor(Processor && processor) void ecs::register_processor(Processor && processor)
{ {
@ -684,6 +767,38 @@ namespace psemek::util
}); });
} }
template <typename Behavior>
void ecs::register_constructor(Behavior && behavior)
{
constructors_.push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable {
apply(behavior, entity);
});
}
template <typename Behavior>
void ecs::register_constructor(Behavior && behavior, species_handle species)
{
species_constructors_[species.value].push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable {
apply(behavior, entity);
});
}
template <typename Behavior>
void ecs::register_destructor(Behavior && behavior)
{
destructors_.push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable {
apply(behavior, entity);
});
}
template <typename Behavior>
void ecs::register_destructor(Behavior && behavior, species_handle species)
{
species_destructors_[species.value].push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable {
apply(behavior, entity);
});
}
template <typename Event> template <typename Event>
void ecs::event(Event const & event) void ecs::event(Event const & event)
{ {