mirror of
https://github.com/BlackMATov/ecs.hpp.git
synced 2025-12-15 11:53:51 +07:00
before and after event triggers
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user