diff --git a/headers/ecs.hpp/ecs.hpp b/headers/ecs.hpp/ecs.hpp index 4305a36..198de46 100644 --- a/headers/ecs.hpp/ecs.hpp +++ b/headers/ecs.hpp/ecs.hpp @@ -39,7 +39,12 @@ namespace ecs_hpp class prototype; - template < typename Event > + template < typename E > + class after; + template < typename E > + class before; + + template < typename... Es > class system; class feature; class registry; @@ -1236,6 +1241,27 @@ namespace ecs_hpp void swap(prototype& l, prototype& r) noexcept; } +// ----------------------------------------------------------------------------- +// +// triggers +// +// ----------------------------------------------------------------------------- + +namespace ecs_hpp +{ + template < typename E > + class after { + public: + const E& event; + }; + + template < typename E > + class before { + public: + const E& event; + }; +} + // ----------------------------------------------------------------------------- // // system @@ -1244,20 +1270,23 @@ namespace ecs_hpp namespace ecs_hpp { - namespace detail - { - class system_base { - public: - virtual ~system_base() = default; - }; - } - - template < typename Event > - class system : public detail::system_base { + template <> + class system<> { public: - using event_type = Event; - virtual void process(registry& owner, const Event& event) = 0; + virtual ~system() = default; }; + + template < typename E > + class system + : public virtual system<> { + public: + virtual void process(registry& owner, const E& event) = 0; + }; + + template < typename E, typename... Es> + class system + : public system + , public system {}; } // ----------------------------------------------------------------------------- @@ -1278,21 +1307,26 @@ namespace ecs_hpp feature(feature&&) noexcept = default; feature& operator=(feature&&) noexcept = default; - feature& enable() noexcept; - feature& disable() noexcept; + feature& enable() & noexcept; + feature&& enable() && noexcept; + + feature& disable() & noexcept; + feature&& disable() && noexcept; bool is_enabled() const noexcept; bool is_disabled() const noexcept; template < typename T, typename... Args > - feature& add_system(Args&&... args); + feature& add_system(Args&&... args) &; + template < typename T, typename... Args > + feature&& add_system(Args&&... args) &&; + template < typename Event > feature& process_event(registry& owner, const Event& event); private: bool disabled_{false}; - mutable detail::incremental_locker base_systems_locker_; - using system_uptr = std::unique_ptr; - std::vector> base_systems_; + std::vector>> systems_; + mutable detail::incremental_locker systems_locker_; }; } @@ -1556,49 +1590,43 @@ namespace ecs_hpp namespace ecs_hpp { - // - // traits - // + namespace detail + { + template < typename T > + struct is_option + : std::false_type {}; - template < typename T > - struct option { - static constexpr bool instance = false; - }; + template < typename T > + struct is_option> + : std::true_type {}; - template < typename T > - struct option> { - static constexpr bool instance = true; - }; + template < typename... Ts > + struct is_option> + : std::true_type {}; - template < typename... Ts > - struct option> { - static constexpr bool instance = true; - }; + template < typename... Ts > + struct is_option> + : std::true_type {}; - template < typename... Ts > - struct option> { - static constexpr bool instance = true; - }; + template < typename T > + struct is_option> + : std::true_type {}; - template < typename T > - struct option> { - static constexpr bool instance = true; - }; + template < typename... Ts > + struct is_option> + : std::true_type {}; - template < typename... Ts > - struct option> { - static constexpr bool instance = true; - }; + template < typename... Ts > + struct is_option> + : std::true_type {}; - template < typename... Ts > - struct option> { - static constexpr bool instance = true; - }; + template <> + struct is_option + : std::true_type {}; - template <> - struct option { - static constexpr bool instance = true; - }; + template < typename T > + inline constexpr bool is_option_v = is_option::value; + } // // options @@ -1693,21 +1721,21 @@ namespace ecs_hpp // template < typename A - , typename = std::enable_if_t::instance>> + , typename = std::enable_if_t> > option_neg> operator!(A&& a) { return {std::forward(a)}; } template < typename A, typename B - , typename = std::enable_if_t::instance> - , typename = std::enable_if_t::instance> > + , typename = std::enable_if_t> + , typename = std::enable_if_t> > option_conj, std::decay_t> operator&&(A&& a, B&& b) { return {std::forward(a), std::forward(b)}; } template < typename A, typename B - , typename = std::enable_if_t::instance> - , typename = std::enable_if_t::instance> > + , typename = std::enable_if_t> + , typename = std::enable_if_t> > option_disj, std::decay_t> operator||(A&& a, B&& b) { return {std::forward(a), std::forward(b)}; } @@ -2358,16 +2386,26 @@ namespace ecs_hpp namespace ecs_hpp { - inline feature& feature::enable() noexcept { + inline feature& feature::enable() & noexcept { disabled_ = false; return *this; } - inline feature& feature::disable() noexcept { + inline feature&& feature::enable() && noexcept { + enable(); + return std::move(*this); + } + + inline feature& feature::disable() & noexcept { disabled_ = true; return *this; } + inline feature&& feature::disable() && noexcept { + disable(); + return std::move(*this); + } + inline bool feature::is_enabled() const noexcept { return !disabled_; } @@ -2377,24 +2415,35 @@ namespace ecs_hpp } template < typename T, typename... Args > - feature& feature::add_system(Args&&... args) { - assert(!base_systems_locker_.is_locked()); - base_systems_.push_back({ - detail::type_family::id(), - std::make_unique(std::forward(args)...)}); + feature& feature::add_system(Args&&... args) & { + assert(!systems_locker_.is_locked()); + systems_.push_back(std::make_unique(std::forward(args)...)); return *this; } + template < typename T, typename... Args > + feature&& feature::add_system(Args&&... args) && { + add_system(std::forward(args)...); + return std::move(*this); + } + template < typename Event > feature& feature::process_event(registry& owner, const Event& event) { - const auto event_id = detail::type_family::id(); - detail::incremental_lock_guard lock(base_systems_locker_); - for ( const auto& [system_event_id, base_system] : base_systems_ ) { - if ( event_id == system_event_id ) { - auto system_ptr = static_cast*>(base_system.get()); - system_ptr->process(owner, event); + detail::incremental_lock_guard lock(systems_locker_); + + const auto fire_event = [this, &owner](const auto& event){ + for ( const auto& base_system : systems_ ) { + using system_type = system>; + if ( auto event_system = dynamic_cast(base_system.get()) ) { + event_system->process(owner, event); + } } - } + }; + + fire_event(before{event}); + fire_event(event); + fire_event(after{event}); + return *this; } } diff --git a/untests/ecs_tests.cpp b/untests/ecs_tests.cpp index 7757e83..bd13427 100644 --- a/untests/ecs_tests.cpp +++ b/untests/ecs_tests.cpp @@ -1536,20 +1536,22 @@ TEST_CASE("registry") { }; struct physics_evt { - update_evt parent_evt{}; + update_evt parent{}; }; - class gravity_system : public ecs::system { + struct clear_velocity_evt { + }; + + class gravity_system : public ecs::system> { public: gravity_system(int g) : g_(g) {} - void process(ecs::registry& owner, const physics_evt& evt) override { - owner.for_each_component< - velocity_c - >([this, &evt](ecs::entity, velocity_c& v) { - v.x += g_ * evt.parent_evt.dt; - v.y += g_ * evt.parent_evt.dt; + void process(ecs::registry& owner, const ecs::before& before) override { + owner.for_each_component( + [this, &evt = before.event](ecs::entity, velocity_c& v) { + v.x += g_ * evt.parent.dt; + v.y += g_ * evt.parent.dt; }, !ecs::exists{}); } private: @@ -1559,20 +1561,24 @@ TEST_CASE("registry") { class movement_system : public ecs::system { public: void process(ecs::registry& owner, const physics_evt& evt) override { - owner.for_joined_components([&evt]( - ecs::entity, position_c& p, const velocity_c& v) - { - p.x += v.x * evt.parent_evt.dt; - p.y += v.y * evt.parent_evt.dt; + owner.for_joined_components( + [&evt](ecs::entity, position_c& p, const velocity_c& v) { + p.x += v.x * evt.parent.dt; + p.y += v.y * evt.parent.dt; }, !ecs::exists{}); } }; - class physics_system : public ecs::system { + class physics_system : public ecs::system { public: void process(ecs::registry& owner, const update_evt& evt) override { owner.process_event(physics_evt{evt}); } + + void process(ecs::registry& owner, const clear_velocity_evt& evt) override { + (void)evt; + owner.remove_all_components(); + } }; ecs::registry w; @@ -1590,6 +1596,12 @@ TEST_CASE("registry") { REQUIRE(e.get_component().x == 1 + (3 + 9 * 2) * 2); REQUIRE(e.get_component().y == 2 + (4 + 9 * 2) * 2); + + REQUIRE(w.component_count() == 1); + + w.process_event(clear_velocity_evt{}); + + REQUIRE(w.component_count() == 0); } SECTION("fillers") { struct component_n {