]> git.tdb.fi Git - libs/game.git/commitdiff
Rewrite System tick bracketing with a Transactor class
authorMikko Rasa <tdb@tdb.fi>
Sat, 22 Mar 2025 10:25:34 +0000 (12:25 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sat, 22 Mar 2025 10:25:34 +0000 (12:25 +0200)
This allows components to better customize their transactions.

source/game/component.h
source/game/stage.h
source/game/system.cpp
source/game/system.h
source/game/transactor.h [new file with mode: 0644]

index dbf5e17b838740513a14b40a039d17912baee080..8e46aa4cdccb7a3357c43d1123a39e65cb7dc94a 100644 (file)
@@ -5,6 +5,7 @@
 #include "accessguard.h"
 #include "handle.h"
 #include "mspgame_api.h"
+#include "transactor.h"
 
 namespace Msp::Game {
 
@@ -30,6 +31,7 @@ class BufferedComponent: public Component
 {
 public:
        using Data = T;
+       using Transactor = BasicTransactor<BufferedComponent<T>>;
        
 private:
        T data[2];
index 4fc4ad0b5e0b88bba6a0e119c3167c2bb38b2844..00b9047bcfa3021dc90d78ae61a1e9efde2ef640 100644 (file)
@@ -20,6 +20,7 @@ class Camera;
 class Root;
 class StagePlan;
 class System;
+class Transactor;
 
 class MSPGAME_API Stage
 {
@@ -44,6 +45,7 @@ private:
        std::unique_ptr<Root> root;
        std::unique_ptr<Content> content;
        std::vector<std::unique_ptr<System>> systems;
+       std::vector<std::unique_ptr<Transactor>> transactors;
        SystemScheduler scheduler;
        Handle<Camera> active_camera;
 
@@ -74,6 +76,9 @@ public:
        template<typename T>
        T *find_system() const;
 
+       template<typename T>
+       T &get_or_create_transactor();
+
        void set_active_camera(Handle<Camera>);
        Handle<Camera> get_active_camera() const { return active_camera; }
 
@@ -109,6 +114,16 @@ inline T *Stage::find_system() const
        return nullptr;
 }
 
+template<typename T>
+inline T &Stage::get_or_create_transactor()
+{
+       for(const auto &t: transactors)
+               if(T *tt = dynamic_cast<T *>(t.get()))
+                       return *tt;
+
+       return static_cast<T &>(*transactors.emplace_back(std::make_unique<T>(*this)));
+}
+
 } // namespace Msp::Game
 
 #endif
index ad81eac9fe935ccbcf83833ca1b833496be04840..1411a8de45da9bbb37066171e6aeb84b5539009f 100644 (file)
@@ -18,27 +18,15 @@ 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);
-       }
+               if(d.transactor)
+                       d.transactor->prepare(d.transact_mode);
 }
 
 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(d.transactor)
+                       d.transactor->commit(d.transact_mode);
 
        System *&active = get_active_ptr();
        if(active==this)
index 2882e8ceb7c1ae570c68aa4a9fc06a2a8bafef51..2cfe52a56a19852b633af7fba0df2584bcd5f5ec 100644 (file)
@@ -8,6 +8,7 @@
 #include "mspgame_api.h"
 #include "reflection.h"
 #include "stage.h"
+#include "transactor.h"
 
 namespace Msp::Game {
 
@@ -38,10 +39,8 @@ public:
        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;
+               Transactor *transactor = nullptr;
+               Transactor::Mode transact_mode = Transactor::NONE;
 
        public:
                Dependency(const Reflection::ClassBase &t): type(t) { }
@@ -116,23 +115,17 @@ inline void System::declare_dependency(DependencyFlags flags)
        dep.flags = flags;
        if constexpr(std::is_base_of_v<Component, T>)
        {
-               if constexpr(requires(T &c) { typename T::Data; c.prepare_tick(); c.commit_tick(); })
+               if constexpr(requires{ typename T::Transactor; })
                {
-#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|UNBUFFERED))==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(); }); };
-                       }
+                       dep.transactor = &stage.get_or_create_transactor<typename T::Transactor>();
+                       if((flags&UPDATE)==READ_OLD)
+                               dep.transact_mode = Transactor::READ;
+                       else if((flags&UPDATE)==WRITE)
+                               dep.transact_mode = Transactor::WRITE;
+                       else if((flags&UPDATE)==UPDATE)
+                               dep.transact_mode = Transactor::RDWR;
+                       else
+                               dep.transact_mode = Transactor::NONE;
                }
                else
                        dep.flags = static_cast<DependencyFlags>(dep.flags|UNBUFFERED);
diff --git a/source/game/transactor.h b/source/game/transactor.h
new file mode 100644 (file)
index 0000000..d502d7b
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef MSP_GAME_TRANSACTOR_H_
+#define MSP_GAME_TRANSACTOR_H_
+
+#include "accessguard.h"
+#include "mspgame_api.h"
+#include "stage.h"
+
+namespace Msp::Game {
+
+class MSPGAME_API Transactor
+{
+public:
+       enum Mode
+       {
+               NONE = 0,
+               READ = 1,
+               WRITE = 2,
+               RDWR = 3
+       };
+
+protected:
+       Stage &stage;
+
+       Transactor(Stage &s): stage(s) { }
+public:
+       virtual ~Transactor() = default;
+
+       virtual void prepare(Mode) = 0;
+       virtual void commit(Mode) = 0;
+};
+
+template<typename T>
+class BasicTransactor: public Transactor
+{
+public:
+       BasicTransactor(Stage &s): Transactor(s) { }
+
+       void prepare(Mode) override;
+       void commit(Mode) override;
+};
+
+template<typename T>
+void BasicTransactor<T>::prepare(Mode mode)
+{
+#ifdef DEBUG
+       if(mode&READ)
+               AccessGuard::get_instance().unblock<AccessGuard::Read<typename T::Data>>();
+       if(mode&WRITE)
+               AccessGuard::get_instance().unblock<AccessGuard::Write<typename T::Data>>();
+#endif
+
+       if(mode&WRITE)
+               stage.iterate_objects<T>([](T &c){ c.prepare_tick(); });
+}
+
+template<typename T>
+void BasicTransactor<T>::commit(Mode mode)
+{
+       if(mode&WRITE)
+               stage.iterate_objects<T>([](T &c){ c.commit_tick(); });
+
+#ifdef DEBUG
+       if(mode&READ)
+               AccessGuard::get_instance().block<AccessGuard::Read<typename T::Data>>();
+       if(mode&WRITE)
+               AccessGuard::get_instance().block<AccessGuard::Write<typename T::Data>>();
+#endif
+}
+
+} // namespace Msp::Game
+
+#endif