This allows components to better customize their transactions.
#include "accessguard.h"
#include "handle.h"
#include "mspgame_api.h"
+#include "transactor.h"
namespace Msp::Game {
{
public:
using Data = T;
+ using Transactor = BasicTransactor<BufferedComponent<T>>;
private:
T data[2];
class Root;
class StagePlan;
class System;
+class Transactor;
class MSPGAME_API Stage
{
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;
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; }
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
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)
#include "mspgame_api.h"
#include "reflection.h"
#include "stage.h"
+#include "transactor.h"
namespace Msp::Game {
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) { }
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);
--- /dev/null
+#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