]> git.tdb.fi Git - libs/game.git/blobdiff - source/game/system.h
Decorate things which constitute the public API of the library
[libs/game.git] / source / game / system.h
index 3d62c06276553821694651c0c5f15020845cc083..4d39e301762d2981ce629c8ce51676a1370fe810 100644 (file)
@@ -3,13 +3,15 @@
 
 #include <functional>
 #include <msp/time/timedelta.h>
+#include "accessguard.h"
 #include "component.h"
+#include "mspgame_api.h"
 #include "reflection.h"
 #include "stage.h"
 
 namespace Msp::Game {
 
-class System
+class MSPGAME_API System
 {
 public:
        enum DependencyFlags
@@ -19,17 +21,30 @@ public:
                READ_FRESH = 3,
                WRITE = 4,
                UPDATE = READ_OLD | WRITE,
-               CHAINED_UPDATE = READ_FRESH | WRITE
+               CHAINED_UPDATE = READ_FRESH | WRITE,
+               DATA_MASK = 7,
+               RUN_BEFORE = 8,
+               RUN_AFTER = 16,
+               ORDER_MASK = 24
        };
 
-       struct Dependency
+       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
@@ -60,6 +75,8 @@ protected:
        void declare_dependency(DependencyFlags);
 
 public:
+       const std::vector<Dependency> &get_dependencies() const { return dependencies; }
+
        void begin_tick();
        virtual void tick(Time::TimeDelta) = 0;
        void end_tick();
@@ -74,7 +91,9 @@ protected:
 template<typename T>
 inline void System::declare_dependency(DependencyFlags flags)
 {
-       if(!std::is_base_of_v<Component, T>)
+       if((flags&DATA_MASK) && !std::is_base_of_v<Component, T>)
+               throw std::invalid_argument("System::declare_dependency");
+       if((flags&ORDER_MASK) && !std::is_base_of_v<System, T>)
                throw std::invalid_argument("System::declare_dependency");
 
        const Reflection::ClassBase &type = stage.get_reflector().get_or_create_class<T>();
@@ -82,15 +101,29 @@ inline void System::declare_dependency(DependencyFlags flags)
 
        if(i!=dependencies.end())
                flags = static_cast<DependencyFlags>(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<AccessGuard::Read<typename T::Data>>();
+                       if(f&WRITE) AccessGuard::get_instance().unblock<AccessGuard::Write<typename T::Data>>();
+               };
+               dep.block = +[](DependencyFlags f){
+                       if(f&READ_OLD) AccessGuard::get_instance().block<AccessGuard::Read<typename T::Data>>();
+                       if(f&WRITE) AccessGuard::get_instance().block<AccessGuard::Write<typename T::Data>>();
+               };
+#endif
                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