]> git.tdb.fi Git - libs/game.git/blobdiff - source/game/system.h
Implement base support for buffered components
[libs/game.git] / source / game / system.h
index 3b379178c1b6e27972cd60f9bfa31441bafbebe2..3d62c06276553821694651c0c5f15020845cc083 100644 (file)
@@ -3,16 +3,51 @@
 
 #include <functional>
 #include <msp/time/timedelta.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
+       };
+
+       struct Dependency
+       {
+               DependencyFlags flags = NO_DEPENDENCY;
+               const Reflection::ClassBase &type;
+               void (*prepare)(Stage &) = nullptr;
+               void (*commit)(Stage &) = nullptr;
+
+               Dependency(const Reflection::ClassBase &t): type(t) { }
+       };
+
+       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<std::function<void()>> deferred_queue;
+       std::vector<Dependency> dependencies;
+
+       static thread_local System *active;
 
        System(Stage &s): stage(s) { }
 public:
@@ -20,7 +55,14 @@ public:
 
        Stage &get_stage() const { return stage; }
 
+protected:
+       template<typename T>
+       void declare_dependency(DependencyFlags);
+
+public:
+       void begin_tick();
        virtual void tick(Time::TimeDelta) = 0;
+       void end_tick();
        virtual void deferred_tick();
 
 protected:
@@ -28,6 +70,29 @@ protected:
        void defer(F &&f) { deferred_queue.emplace_back(std::forward<F>(f)); }
 };
 
+
+template<typename T>
+inline void System::declare_dependency(DependencyFlags flags)
+{
+       if(!std::is_base_of_v<Component, T>)
+               throw std::invalid_argument("System::declare_dependency");
+
+       const Reflection::ClassBase &type = stage.get_reflector().get_or_create_class<T>();
+       auto i = find_if(dependencies, [&type](const Dependency &d){ return &d.type==&type; });
+
+       if(i!=dependencies.end())
+               flags = static_cast<DependencyFlags>(flags|i->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(); })
+               if(flags&WRITE)
+               {
+                       dep.prepare = +[](Stage &s){ s.iterate_objects<T>([](T &c){ c.prepare_tick(); }); };
+                       dep.commit = +[](Stage &s){ s.iterate_objects<T>([](T &c){ c.commit_tick(); }); };
+               }
+}
+
 } // namespace Msp::Game
 
 #endif