#include <string>
#include <vector>
#include <msp/core/noncopyable.h>
+#include <msp/debug/demangle.h>
namespace Msp::Game {
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
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
#define MSP_GAME_COMPONENT_H_
#include <msp/time/timedelta.h>
+#include "accessguard.h"
#include "handle.h"
namespace Msp::Game {
BufferedComponent(Handle<Entity> e): Component(e) { }
- const T &read() const { return data[read_index]; }
+ const T &read() const;
T &write();
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];
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;
#include <functional>
#include <msp/time/timedelta.h>
+#include "accessguard.h"
#include "component.h"
#include "reflection.h"
#include "stage.h"
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) { }
};
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