]> git.tdb.fi Git - libs/game.git/commitdiff
Enforce correct access to buffered components
authorMikko Rasa <tdb@tdb.fi>
Sun, 4 Dec 2022 20:13:56 +0000 (22:13 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sun, 4 Dec 2022 20:20:21 +0000 (22:20 +0200)
source/game/accessguard.h
source/game/component.h
source/game/system.cpp
source/game/system.h

index c64efe75bee9de0ae04427f3b3589b295b8d6fdd..26bbb4e0e99b3d7bb896c6376e7e1d22f9fae827 100644 (file)
@@ -6,6 +6,7 @@
 #include <string>
 #include <vector>
 #include <msp/core/noncopyable.h>
+#include <msp/debug/demangle.h>
 
 namespace Msp::Game {
 
@@ -21,6 +22,8 @@ class AccessGuard
 public:
        struct Create { static std::string describe() { return "create"; } };
        struct Destroy { static std::string describe() { return "destroy"; } };
+       template<typename T> struct Read { static std::string describe(); };
+       template<typename T> struct Write { static std::string describe(); };
 
        template<typename T = void>
        struct BlockForScope: NonCopyable
@@ -94,6 +97,19 @@ template<>
 inline void AccessGuard::unblock<void>()
 { unblock_all(); }
 
+
+template<typename T>
+inline std::string AccessGuard::Read<T>::describe()
+{
+       return "read "+Debug::demangle(typeid(T).name());
+}
+
+template<typename T>
+inline std::string AccessGuard::Write<T>::describe()
+{
+       return "write "+Debug::demangle(typeid(T).name());
+}
+
 } // namespace Msp::Game
 
 #endif
index 44927ffd2e73c640f9d8a609f4e4b66984633572..6406cb5743e3f417f0cb7f27a08c92e439aecef8 100644 (file)
@@ -2,6 +2,7 @@
 #define MSP_GAME_COMPONENT_H_
 
 #include <msp/time/timedelta.h>
+#include "accessguard.h"
 #include "handle.h"
 
 namespace Msp::Game {
@@ -34,7 +35,7 @@ protected:
 
        BufferedComponent(Handle<Entity> e): Component(e) { }
 
-       const T &read() const { return data[read_index]; }
+       const T &read() const;
        T &write();
 
 public:
@@ -42,9 +43,21 @@ public:
        virtual void commit_tick() { if(written) read_index = write_index; }
 };
 
+template<typename T>
+const T &BufferedComponent<T>::read() const
+{
+#ifdef DEBUG
+       AccessGuard::get_instance().check<AccessGuard::Read<T>>();
+#endif
+       return data[read_index];
+}
+
 template<typename T>
 T &BufferedComponent<T>::write()
 {
+#ifdef DEBUG
+       AccessGuard::get_instance().check<AccessGuard::Write<T>>();
+#endif
        if(!written && write_index!=read_index)
        {
                data[write_index] = data[read_index];
index 33157c3946990c6c64b25b1b8b6f0ee8782f35da..4c1f4fbba01fa46ecc8b39c9a9dcb80172925c6b 100644 (file)
@@ -13,15 +13,27 @@ void System::begin_tick()
        active = this;
 
        for(const Dependency &d: dependencies)
+       {
+#ifdef DEBUG
+               if(d.unblock)
+                       d.unblock(d.flags);
+#endif
                if(d.prepare)
                        d.prepare(stage);
+       }
 }
 
 void System::end_tick()
 {
        for(const Dependency &d: dependencies)
+       {
                if(d.commit)
                        d.commit(stage);
+#ifdef DEBUG
+               if(d.block)
+                       d.block(d.flags);
+#endif
+       }
 
        if(active==this)
                active = nullptr;
index 3d62c06276553821694651c0c5f15020845cc083..e3d71171c1e19aa8e31da854aa007737885774ce 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <functional>
 #include <msp/time/timedelta.h>
+#include "accessguard.h"
 #include "component.h"
 #include "reflection.h"
 #include "stage.h"
@@ -28,6 +29,8 @@ public:
                const Reflection::ClassBase &type;
                void (*prepare)(Stage &) = nullptr;
                void (*commit)(Stage &) = nullptr;
+               void (*unblock)(DependencyFlags) = nullptr;
+               void (*block)(DependencyFlags) = nullptr;
 
                Dependency(const Reflection::ClassBase &t): type(t) { }
        };
@@ -86,11 +89,23 @@ inline void System::declare_dependency(DependencyFlags 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