X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgame%2Fsystem.h;h=09ee157a6953916522702cf0543ac75872f8ac78;hb=e4f03880d49bdbe0c7269be0f40f23b197bcea77;hp=3b379178c1b6e27972cd60f9bfa31441bafbebe2;hpb=c7177adc21993307482b2c18dc4db6a03361586d;p=libs%2Fgame.git diff --git a/source/game/system.h b/source/game/system.h index 3b37917..09ee157 100644 --- a/source/game/system.h +++ b/source/game/system.h @@ -3,16 +3,65 @@ #include #include +#include "accessguard.h" +#include "component.h" +#include "reflection.h" +#include "stage.h" namespace Msp::Game { -class Stage; - class System { +public: + enum DependencyFlags + { + NO_DEPENDENCY = 0, + READ_OLD = 1, + READ_FRESH = 3, + WRITE = 4, + UPDATE = READ_OLD | WRITE, + CHAINED_UPDATE = READ_FRESH | WRITE, + DATA_MASK = 7, + RUN_BEFORE = 8, + RUN_AFTER = 16, + ORDER_MASK = 24 + }; + + class Dependency + { + friend class System; + + private: + DependencyFlags flags = NO_DEPENDENCY; + const Reflection::ClassBase &type; + void (*prepare)(Stage &) = nullptr; + void (*commit)(Stage &) = nullptr; + void (*unblock)(DependencyFlags) = nullptr; + void (*block)(DependencyFlags) = nullptr; + + public: + Dependency(const Reflection::ClassBase &t): type(t) { } + + DependencyFlags get_flags() const { return flags; } + const Reflection::ClassBase &get_type() const { return type; } + }; + + class Activator: public NonCopyable + { + private: + System &system; + + public: + Activator(System &s): system(s) { system.begin_tick(); } + ~Activator() { system.end_tick(); } + }; + protected: Stage &stage; std::vector> deferred_queue; + std::vector dependencies; + + static thread_local System *active; System(Stage &s): stage(s) { } public: @@ -20,7 +69,16 @@ public: Stage &get_stage() const { return stage; } +protected: + template + void declare_dependency(DependencyFlags); + +public: + const std::vector &get_dependencies() const { return dependencies; } + + void begin_tick(); virtual void tick(Time::TimeDelta) = 0; + void end_tick(); virtual void deferred_tick(); protected: @@ -28,6 +86,45 @@ protected: void defer(F &&f) { deferred_queue.emplace_back(std::forward(f)); } }; + +template +inline void System::declare_dependency(DependencyFlags flags) +{ + if((flags&DATA_MASK) && !std::is_base_of_v) + throw std::invalid_argument("System::declare_dependency"); + if((flags&ORDER_MASK) && !std::is_base_of_v) + throw std::invalid_argument("System::declare_dependency"); + + const Reflection::ClassBase &type = stage.get_reflector().get_or_create_class(); + auto i = find_if(dependencies, [&type](const Dependency &d){ return &d.type==&type; }); + + if(i!=dependencies.end()) + flags = static_cast(flags|i->flags); + if((flags&RUN_BEFORE) && (flags&RUN_AFTER)) + throw std::logic_error("conflicting order flags"); + + Dependency &dep = (i!=dependencies.end() ? *i : dependencies.emplace_back(type)); + dep.flags = flags; + if constexpr(requires(T &c) { typename T::Data; c.prepare_tick(); c.commit_tick(); }) + { +#ifdef DEBUG + dep.unblock = +[](DependencyFlags f){ + if(f&READ_OLD) AccessGuard::get_instance().unblock>(); + if(f&WRITE) AccessGuard::get_instance().unblock>(); + }; + dep.block = +[](DependencyFlags f){ + if(f&READ_OLD) AccessGuard::get_instance().block>(); + if(f&WRITE) AccessGuard::get_instance().block>(); + }; +#endif + if(flags&WRITE) + { + dep.prepare = +[](Stage &s){ s.iterate_objects([](T &c){ c.prepare_tick(); }); }; + dep.commit = +[](Stage &s){ s.iterate_objects([](T &c){ c.commit_tick(); }); }; + } + } +} + } // namespace Msp::Game #endif