Introduce util::ecs::behavior::context

This commit is contained in:
Nikita Lisitsa 2021-07-24 11:14:39 +03:00
parent bc7378456b
commit 02b29af95a

View file

@ -23,7 +23,12 @@ namespace psemek::util
struct species_base struct species_base
{ {
virtual std::string_view name() const = 0; species_base(std::string name, handle id)
: name_(std::move(name))
, id_(id)
{}
std::string_view name() const { return name_; }
virtual void * get_species_component(std::type_index component_type) = 0; virtual void * get_species_component(std::type_index component_type) = 0;
virtual void * get_entity_component(std::type_index component_type) = 0; virtual void * get_entity_component(std::type_index component_type) = 0;
@ -65,6 +70,9 @@ namespace psemek::util
private: private:
std::string name_;
handle id_;
template <typename Behavior, typename ... Components, std::size_t ... Is> template <typename Behavior, typename ... Components, std::size_t ... Is>
void apply_impl(Behavior & behavior, std::tuple<Components...> *, std::index_sequence<Is...>) void apply_impl(Behavior & behavior, std::tuple<Components...> *, std::index_sequence<Is...>)
{ {
@ -80,15 +88,16 @@ namespace psemek::util
if (!std::apply(all_nonzero, cptrs)) if (!std::apply(all_nonzero, cptrs))
return; return;
std::tuple<Components *...> cs; typename Behavior::context ctx;
ctx.species = id_;
((std::get<Components *>(cs) = get_species_component<Components>()), ...); ((std::get<Components *>(ctx.components) = get_species_component<Components>()), ...);
auto visit = [&](auto * ... ptrs) auto visit = [&](auto * ... ptrs)
{ {
if constexpr (std::is_invocable_v<Behavior, typename Components::data & ..., std::tuple<Components *...> const &>) if constexpr (std::is_invocable_v<Behavior, typename Components::data & ..., typename Behavior::context &>)
{ {
behavior(*ptrs..., cs); behavior(*ptrs..., ctx);
} }
else else
{ {
@ -108,7 +117,10 @@ namespace psemek::util
for (std::size_t i = 0; i < count; ++i) for (std::size_t i = 0; i < count; ++i)
{ {
if (*list == i) if (*list == i)
{
ctx.entity = i;
std::apply(visit, cptrs); std::apply(visit, cptrs);
}
std::apply(increment, cptrs); std::apply(increment, cptrs);
++list; ++list;
} }
@ -119,16 +131,11 @@ namespace psemek::util
struct species_impl struct species_impl
: species_base : species_base
{ {
species_impl(std::string name, Components && ... components) species_impl(std::string name, handle id, Components && ... components)
: name_(std::move(name)) : species_base(std::move(name), id)
, species_components_{std::move(components)...} , species_components_{std::move(components)...}
{} {}
std::string_view name() const override
{
return name_;
}
using species_base::get_species_component; using species_base::get_species_component;
using species_base::get_entity_component; using species_base::get_entity_component;
@ -170,7 +177,6 @@ namespace psemek::util
} }
private: private:
std::string name_;
std::tuple<Components...> species_components_; std::tuple<Components...> species_components_;
std::tuple<std::vector<typename Components::data>...> entity_components_; std::tuple<std::vector<typename Components::data>...> entity_components_;
std::vector<handle> list_; std::vector<handle> list_;
@ -220,12 +226,6 @@ namespace psemek::util
} }
}; };
template <typename Behavior>
using prepare_helper = decltype(std::declval<Behavior>().prepare());
template <typename Behavior>
using has_prepare = std::experimental::is_detected<prepare_helper, Behavior>;
} }
struct ecs struct ecs
@ -235,6 +235,20 @@ namespace psemek::util
{ {
using component_types = std::tuple<Components...>; using component_types = std::tuple<Components...>;
using component_ptrs = std::tuple<Components *...>; using component_ptrs = std::tuple<Components *...>;
struct context
{
ecs_detail::handle species;
ecs_detail::handle entity;
component_ptrs components;
template <typename Component>
Component & get() const
{
return *std::get<Component *>(components);
}
};
}; };
using handle = ecs_detail::handle; using handle = ecs_detail::handle;
@ -280,6 +294,9 @@ namespace psemek::util
template <typename Behavior> template <typename Behavior>
void apply(Behavior && behavior) const; void apply(Behavior && behavior) const;
template <typename Behavior>
void apply(Behavior && behavior, handle species) const;
private: private:
std::vector<std::unique_ptr<ecs_detail::species_base>> species_; std::vector<std::unique_ptr<ecs_detail::species_base>> species_;
}; };
@ -288,7 +305,7 @@ namespace psemek::util
ecs::handle ecs::register_species(std::string name, Components && ... components) ecs::handle ecs::register_species(std::string name, Components && ... components)
{ {
handle result = species_.size(); handle result = species_.size();
species_.push_back(std::make_unique<ecs_detail::species_impl<Components...>>(std::move(name), std::move(components)...)); species_.push_back(std::make_unique<ecs_detail::species_impl<Components...>>(std::move(name), result, std::move(components)...));
return result; return result;
} }
@ -372,13 +389,14 @@ namespace psemek::util
template <typename Behavior> template <typename Behavior>
void ecs::apply(Behavior && behavior) const void ecs::apply(Behavior && behavior) const
{ {
if constexpr (ecs_detail::has_prepare<Behavior>::value)
{
behavior.prepare();
}
for (auto & s : species_) for (auto & s : species_)
s->apply(behavior); s->apply(behavior);
} }
template <typename Behavior>
void ecs::apply(Behavior && behavior, handle species) const
{
species_[species]->apply(behavior);
}
} }