Support ecs species behaviors

This commit is contained in:
Nikita Lisitsa 2022-10-29 14:46:06 +03:00
parent 9489c1caef
commit 07804bdeda

View file

@ -106,6 +106,14 @@ namespace psemek::util
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...);
}
template <typename Behavior, typename ... Args>
void apply_species(Behavior & behavior, Args const & ... args)
{
if (!check_forbidden(behavior, 0))
return;
apply_species_impl(behavior, static_cast<typename Behavior::component_types *>(nullptr), std::make_index_sequence<std::tuple_size_v<typename Behavior::component_types>>{}, 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 <typename Behavior, typename ... Components, std::size_t ... Is, typename ... Args>
void apply_species_impl(Behavior & behavior, std::tuple<Components...> *, std::index_sequence<Is...>, Args const & ... args)
{
std::tuple<Components * ...> cptrs;
((std::get<Is>(cptrs) = get_species_component<Components>()), ...);
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, Components & ..., typename Behavior::context const &, Args const & ...>)
{
behavior(*ptrs..., ctx, args...);
}
else
{
behavior(*ptrs..., args...);
}
};
std::apply(visit, cptrs);
}
};
template <typename ... Components>
@ -516,6 +557,23 @@ namespace psemek::util
void begin(species_handle, Components const & ...) {}
};
template <typename ... Components>
struct species_behavior
{
using component_types = std::tuple<Components...>;
using component_ptrs = std::tuple<Components *...>;
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 <typename Behavior, typename ... Args>
void apply(Behavior && behavior, entity_handle entity, Args const & ... args);
template <typename Behavior, typename ... Args>
void apply_species(Behavior && behavior, Args const & ... args);
template <typename Behavior, typename ... Args>
void apply_species(Behavior && behavior, species_handle species, Args const & ... args);
template <typename Event, typename Processor>
void register_processor(Processor && processor);
@ -613,12 +677,21 @@ namespace psemek::util
template <typename Event, typename Behavior>
void register_behavior(Behavior && behavior, species_handle species);
template <typename Event, typename Behavior>
void register_species_behavior(Behavior && behavior);
template <typename Event, typename Behavior>
void register_species_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_species_constructor(Behavior && behavior);
template <typename Behavior>
void register_destructor(Behavior && behavior);
@ -633,22 +706,26 @@ namespace psemek::util
std::unordered_map<std::type_index, std::vector<util::function<void(void const *)>>> event_subscribers_;
std::vector<util::function<void(species_handle)>> species_constructors_;
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::unordered_map<ecs_detail::species_handle, std::vector<util::function<void(entity_handle)>>> private_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_;
std::unordered_map<ecs_detail::species_handle, std::vector<util::function<void(entity_handle)>>> private_destructors_;
};
template <typename ... Components>
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<ecs_detail::sparse_species_impl<Components...>>(this, std::move(name), result, std::move(components)...));
species_.push_back(std::make_unique<ecs_detail::sparse_species_impl<Components...>>(this, std::move(name), result.value, std::move(components)...));
else
species_.push_back(std::make_unique<ecs_detail::packed_species_impl<Components...>>(this, std::move(name), result, std::move(components)...));
return {result};
species_.push_back(std::make_unique<ecs_detail::packed_species_impl<Components...>>(this, std::move(name), result.value, std::move(components)...));
for (auto const & ctor : species_constructors_)
ctor(result);
return result;
}
template <typename ... Components>
@ -658,7 +735,7 @@ namespace psemek::util
((get<Components>(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 <typename Behavior, typename ... Args>
void ecs::apply_species(Behavior && behavior, Args const & ... args)
{
for (auto & s : species_)
s->apply_species(behavior, args...);
}
template <typename Behavior, typename ... Args>
void ecs::apply_species(Behavior && behavior, species_handle species, Args const & ... args)
{
species_[species.value]->apply_species(behavior, args...);
}
template <typename Event, typename Processor>
void ecs::register_processor(Processor && processor)
{
@ -785,6 +875,22 @@ namespace psemek::util
});
}
template <typename Event, typename Behavior>
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 const *>(event));
});
}
template <typename Event, typename Behavior>
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 const *>(event));
});
}
template <typename Behavior>
void ecs::register_constructor(Behavior && behavior)
{
@ -796,11 +902,19 @@ namespace psemek::util
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 {
private_constructors_[species.value].push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable {
apply(behavior, entity);
});
}
template <typename Behavior>
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 <typename Behavior>
void ecs::register_destructor(Behavior && behavior)
{
@ -812,7 +926,7 @@ namespace psemek::util
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 {
private_destructors_[species.value].push_back([this, behavior = std::move(behavior)](entity_handle entity) mutable {
apply(behavior, entity);
});
}