before and after event triggers

This commit is contained in:
2019-10-18 19:41:15 +07:00
parent dcb62437ca
commit 7ad769cdfa
2 changed files with 148 additions and 87 deletions

View File

@@ -39,7 +39,12 @@ namespace ecs_hpp
class prototype; class prototype;
template < typename Event > template < typename E >
class after;
template < typename E >
class before;
template < typename... Es >
class system; class system;
class feature; class feature;
class registry; class registry;
@@ -1236,6 +1241,27 @@ namespace ecs_hpp
void swap(prototype& l, prototype& r) noexcept; 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 // system
@@ -1244,20 +1270,23 @@ namespace ecs_hpp
namespace ecs_hpp namespace ecs_hpp
{ {
namespace detail template <>
{ class system<> {
class system_base {
public:
virtual ~system_base() = default;
};
}
template < typename Event >
class system : public detail::system_base {
public: public:
using event_type = Event; virtual ~system() = default;
virtual void process(registry& owner, const Event& event) = 0;
}; };
template < typename E >
class system<E>
: public virtual system<> {
public:
virtual void process(registry& owner, const E& event) = 0;
};
template < typename E, typename... Es>
class system<E, Es...>
: public system<E>
, public system<Es...> {};
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -1278,21 +1307,26 @@ namespace ecs_hpp
feature(feature&&) noexcept = default; feature(feature&&) noexcept = default;
feature& operator=(feature&&) noexcept = default; feature& operator=(feature&&) noexcept = default;
feature& enable() noexcept; feature& enable() & noexcept;
feature& disable() noexcept; feature&& enable() && noexcept;
feature& disable() & noexcept;
feature&& disable() && noexcept;
bool is_enabled() const noexcept; bool is_enabled() const noexcept;
bool is_disabled() const noexcept; bool is_disabled() const noexcept;
template < typename T, typename... Args > 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 > template < typename Event >
feature& process_event(registry& owner, const Event& event); feature& process_event(registry& owner, const Event& event);
private: private:
bool disabled_{false}; bool disabled_{false};
mutable detail::incremental_locker base_systems_locker_; std::vector<std::unique_ptr<system<>>> systems_;
using system_uptr = std::unique_ptr<detail::system_base>; mutable detail::incremental_locker systems_locker_;
std::vector<std::pair<family_id, system_uptr>> base_systems_;
}; };
} }
@@ -1556,49 +1590,43 @@ namespace ecs_hpp
namespace ecs_hpp namespace ecs_hpp
{ {
// namespace detail
// traits {
// template < typename T >
struct is_option
: std::false_type {};
template < typename T > template < typename T >
struct option { struct is_option<exists<T>>
static constexpr bool instance = false; : std::true_type {};
};
template < typename T > template < typename... Ts >
struct option<exists<T>> { struct is_option<exists_any<Ts...>>
static constexpr bool instance = true; : std::true_type {};
};
template < typename... Ts > template < typename... Ts >
struct option<exists_any<Ts...>> { struct is_option<exists_all<Ts...>>
static constexpr bool instance = true; : std::true_type {};
};
template < typename... Ts > template < typename T >
struct option<exists_all<Ts...>> { struct is_option<option_neg<T>>
static constexpr bool instance = true; : std::true_type {};
};
template < typename T > template < typename... Ts >
struct option<option_neg<T>> { struct is_option<option_conj<Ts...>>
static constexpr bool instance = true; : std::true_type {};
};
template < typename... Ts > template < typename... Ts >
struct option<option_conj<Ts...>> { struct is_option<option_disj<Ts...>>
static constexpr bool instance = true; : std::true_type {};
};
template < typename... Ts > template <>
struct option<option_disj<Ts...>> { struct is_option<option_bool>
static constexpr bool instance = true; : std::true_type {};
};
template <> template < typename T >
struct option<option_bool> { inline constexpr bool is_option_v = is_option<T>::value;
static constexpr bool instance = true; }
};
// //
// options // options
@@ -1693,21 +1721,21 @@ namespace ecs_hpp
// //
template < typename A template < typename A
, typename = std::enable_if_t<option<A>::instance>> , typename = std::enable_if_t<detail::is_option_v<A>> >
option_neg<std::decay_t<A>> operator!(A&& a) { option_neg<std::decay_t<A>> operator!(A&& a) {
return {std::forward<A>(a)}; return {std::forward<A>(a)};
} }
template < typename A, typename B template < typename A, typename B
, typename = std::enable_if_t<option<A>::instance> , typename = std::enable_if_t<detail::is_option_v<A>>
, typename = std::enable_if_t<option<B>::instance> > , typename = std::enable_if_t<detail::is_option_v<B>> >
option_conj<std::decay_t<A>, std::decay_t<B>> operator&&(A&& a, B&& b) { option_conj<std::decay_t<A>, std::decay_t<B>> operator&&(A&& a, B&& b) {
return {std::forward<A>(a), std::forward<B>(b)}; return {std::forward<A>(a), std::forward<B>(b)};
} }
template < typename A, typename B template < typename A, typename B
, typename = std::enable_if_t<option<A>::instance> , typename = std::enable_if_t<detail::is_option_v<A>>
, typename = std::enable_if_t<option<B>::instance> > , typename = std::enable_if_t<detail::is_option_v<B>> >
option_disj<std::decay_t<A>, std::decay_t<B>> operator||(A&& a, B&& b) { option_disj<std::decay_t<A>, std::decay_t<B>> operator||(A&& a, B&& b) {
return {std::forward<A>(a), std::forward<B>(b)}; return {std::forward<A>(a), std::forward<B>(b)};
} }
@@ -2358,16 +2386,26 @@ namespace ecs_hpp
namespace ecs_hpp namespace ecs_hpp
{ {
inline feature& feature::enable() noexcept { inline feature& feature::enable() & noexcept {
disabled_ = false; disabled_ = false;
return *this; return *this;
} }
inline feature& feature::disable() noexcept { inline feature&& feature::enable() && noexcept {
enable();
return std::move(*this);
}
inline feature& feature::disable() & noexcept {
disabled_ = true; disabled_ = true;
return *this; return *this;
} }
inline feature&& feature::disable() && noexcept {
disable();
return std::move(*this);
}
inline bool feature::is_enabled() const noexcept { inline bool feature::is_enabled() const noexcept {
return !disabled_; return !disabled_;
} }
@@ -2377,24 +2415,35 @@ namespace ecs_hpp
} }
template < typename T, typename... Args > template < typename T, typename... Args >
feature& feature::add_system(Args&&... args) { feature& feature::add_system(Args&&... args) & {
assert(!base_systems_locker_.is_locked()); assert(!systems_locker_.is_locked());
base_systems_.push_back({ systems_.push_back(std::make_unique<T>(std::forward<Args>(args)...));
detail::type_family<typename T::event_type>::id(),
std::make_unique<T>(std::forward<Args>(args)...)});
return *this; return *this;
} }
template < typename T, typename... Args >
feature&& feature::add_system(Args&&... args) && {
add_system<T>(std::forward<Args>(args)...);
return std::move(*this);
}
template < typename Event > template < typename Event >
feature& feature::process_event(registry& owner, const Event& event) { feature& feature::process_event(registry& owner, const Event& event) {
const auto event_id = detail::type_family<Event>::id(); detail::incremental_lock_guard lock(systems_locker_);
detail::incremental_lock_guard lock(base_systems_locker_);
for ( const auto& [system_event_id, base_system] : base_systems_ ) { const auto fire_event = [this, &owner](const auto& event){
if ( event_id == system_event_id ) { for ( const auto& base_system : systems_ ) {
auto system_ptr = static_cast<system<Event>*>(base_system.get()); using system_type = system<std::decay_t<decltype(event)>>;
system_ptr->process(owner, event); if ( auto event_system = dynamic_cast<system_type*>(base_system.get()) ) {
event_system->process(owner, event);
}
} }
} };
fire_event(before<Event>{event});
fire_event(event);
fire_event(after<Event>{event});
return *this; return *this;
} }
} }

View File

@@ -1536,20 +1536,22 @@ TEST_CASE("registry") {
}; };
struct physics_evt { struct physics_evt {
update_evt parent_evt{}; update_evt parent{};
}; };
class gravity_system : public ecs::system<physics_evt> { struct clear_velocity_evt {
};
class gravity_system : public ecs::system<ecs::before<physics_evt>> {
public: public:
gravity_system(int g) gravity_system(int g)
: g_(g) {} : g_(g) {}
void process(ecs::registry& owner, const physics_evt& evt) override { void process(ecs::registry& owner, const ecs::before<physics_evt>& before) override {
owner.for_each_component< owner.for_each_component<velocity_c>(
velocity_c [this, &evt = before.event](ecs::entity, velocity_c& v) {
>([this, &evt](ecs::entity, velocity_c& v) { v.x += g_ * evt.parent.dt;
v.x += g_ * evt.parent_evt.dt; v.y += g_ * evt.parent.dt;
v.y += g_ * evt.parent_evt.dt;
}, !ecs::exists<disabled_c>{}); }, !ecs::exists<disabled_c>{});
} }
private: private:
@@ -1559,20 +1561,24 @@ TEST_CASE("registry") {
class movement_system : public ecs::system<physics_evt> { class movement_system : public ecs::system<physics_evt> {
public: public:
void process(ecs::registry& owner, const physics_evt& evt) override { void process(ecs::registry& owner, const physics_evt& evt) override {
owner.for_joined_components<position_c, velocity_c>([&evt]( owner.for_joined_components<position_c, velocity_c>(
ecs::entity, position_c& p, const velocity_c& v) [&evt](ecs::entity, position_c& p, const velocity_c& v) {
{ p.x += v.x * evt.parent.dt;
p.x += v.x * evt.parent_evt.dt; p.y += v.y * evt.parent.dt;
p.y += v.y * evt.parent_evt.dt;
}, !ecs::exists<disabled_c>{}); }, !ecs::exists<disabled_c>{});
} }
}; };
class physics_system : public ecs::system<update_evt> { class physics_system : public ecs::system<update_evt, clear_velocity_evt> {
public: public:
void process(ecs::registry& owner, const update_evt& evt) override { void process(ecs::registry& owner, const update_evt& evt) override {
owner.process_event(physics_evt{evt}); owner.process_event(physics_evt{evt});
} }
void process(ecs::registry& owner, const clear_velocity_evt& evt) override {
(void)evt;
owner.remove_all_components<velocity_c>();
}
}; };
ecs::registry w; ecs::registry w;
@@ -1590,6 +1596,12 @@ TEST_CASE("registry") {
REQUIRE(e.get_component<position_c>().x == 1 + (3 + 9 * 2) * 2); REQUIRE(e.get_component<position_c>().x == 1 + (3 + 9 * 2) * 2);
REQUIRE(e.get_component<position_c>().y == 2 + (4 + 9 * 2) * 2); REQUIRE(e.get_component<position_c>().y == 2 + (4 + 9 * 2) * 2);
REQUIRE(w.component_count<velocity_c>() == 1);
w.process_event(clear_velocity_evt{});
REQUIRE(w.component_count<velocity_c>() == 0);
} }
SECTION("fillers") { SECTION("fillers") {
struct component_n { struct component_n {