From 05d6c60b56be03ddd0b2164584dc31899b5b7854 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 15 Mar 2025 17:15:45 +0200 Subject: [PATCH] Add utilities for keeping track of entities with specific components --- source/game/archetype.h | 147 ++++++++++++++++++++++++++++++++++++++++ source/game/handle.h | 3 + 2 files changed, 150 insertions(+) create mode 100644 source/game/archetype.h diff --git a/source/game/archetype.h b/source/game/archetype.h new file mode 100644 index 0000000..f6fef8c --- /dev/null +++ b/source/game/archetype.h @@ -0,0 +1,147 @@ +#ifndef MSP_GAME_ARCHETYPE_H_ +#define MSP_GAME_ARCHETYPE_H_ + +#include +#include +#include +#include "eventobserver.h" +#include "events.h" +#include "handle.h" + +namespace Msp::Game { + +template + requires (std::is_same_v::Class, typename PointerToMemberTraits::Class> && ...) +struct CommonClassOfMembers +{ + using Type = typename PointerToMemberTraits::Class; +}; + +template +struct ArchetypeComponents +{ + using Wrapper = typename CommonClassOfMembers::Type; + + template + static void dispatch(const F &, Handle); + + static bool all_null(const Wrapper &); +}; + + +template +concept ValidArchetype = + std::is_same_v && + requires(T t) { { t.entity } -> std::convertible_to>; }; + + +template + requires ValidArchetype +class ArchetypeMonitor +{ +private: + EventObserver &event_observer; + std::vector &entities; + std::function changed_callback; + +public: + ArchetypeMonitor(EventObserver &, std::vector &); + + void set_changed_callback(std::function); + +private: + void component_created(const Events::ComponentCreated &); + void component_destroyed(const Events::ComponentDestroyed &); + + T &get_or_create_wrapper(Handle); +}; + + +template +template +void ArchetypeComponents::dispatch(const F &func, Handle comp) +{ + if(auto cast_comp = dynamic_handle_cast::Type::element_type>(comp)) + func(cast_comp, first); + else if constexpr(sizeof...(rest)>0) + ArchetypeComponents::dispatch(func, comp); +} + +template +bool ArchetypeComponents::all_null(const Wrapper &wrapper) +{ + return (!(wrapper.*first) && ... && !(wrapper.*rest)); +} + + +template + requires ValidArchetype +ArchetypeMonitor::ArchetypeMonitor(EventObserver &o, std::vector &v): + event_observer(o), + entities(v) +{ + event_observer.observe([this](auto &e){ component_created(e); }); + event_observer.observe([this](auto &e){ component_destroyed(e); }); +} + +template + requires ValidArchetype +void ArchetypeMonitor::set_changed_callback(std::function cb) +{ + changed_callback = cb; +} + +template + requires ValidArchetype +void ArchetypeMonitor::component_created(const Events::ComponentCreated &event) +{ + T::Components::dispatch([this](Handle comp, Handle T::*member){ + Handle entity = comp->get_entity(); + T &wrapper = get_or_create_wrapper(entity); + wrapper.*member = comp; + + if(changed_callback) + changed_callback(wrapper); + }, event.component); +} + +template + requires ValidArchetype +void ArchetypeMonitor::component_destroyed(const Events::ComponentDestroyed &event) +{ + T::Components::dispatch([this](Handle comp, Handle T::*member){ + Handle entity = comp->get_entity(); + auto i = lower_bound_member(entities, entity, &T::entity); + if(i!=entities.end() && i->entity==entity) + { + (*i).*member = nullptr; + if(changed_callback) + changed_callback(*i); + } + + if(T::Components::all_null(*i)) + entities.erase(i); + }, event.component); +} + +template + requires ValidArchetype +T &ArchetypeMonitor::get_or_create_wrapper(Handle entity) +{ + auto i = lower_bound_member(entities, entity, &T::entity); + if(i!=entities.end() && i->entity==entity) + return *i; + + if constexpr(std::is_constructible_v>) + return *entities.emplace(i, entity); + else + { + auto &e = entities.emplace(i); + e.entity = entity; + return e; + } +} + +} // namespace Msp::Game + +#endif diff --git a/source/game/handle.h b/source/game/handle.h index 183fc41..73d4d11 100644 --- a/source/game/handle.h +++ b/source/game/handle.h @@ -18,6 +18,9 @@ class Handle template friend class Handle; +public: + using element_type = T; + protected: T *ptr = nullptr; -- 2.45.2