+
+template<typename T>
+inline void System::declare_dependency(DependencyFlags flags)
+{
+ 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>();
+ auto i = find_if(dependencies, [&type](const Dependency &d){ return &d.type==&type; });
+
+ 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(); }); };
+ }
+ }
+}
+