#include "stage.h"
+#include <msp/debug/demangle.h>
+#include <msp/strings/format.h>
+#include "accessguard.h"
+#include "camera.h"
#include "root.h"
#include "system.h"
+using namespace std;
+
namespace Msp::Game {
-Stage::Stage(DataFile::Collection &r):
+Stage::Stage(Reflection::Reflector &f, DataFile::Collection &r):
+ reflector(f),
resources(r),
event_source(event_bus),
- root(std::make_unique<Root>(*this))
-{ }
+ event_observer(event_bus),
+ root(std::make_unique<Root>(*this)),
+ scheduler(reflector)
+{
+ event_observer.observe<Events::ComponentCreated>([this](auto &e){
+ if(!active_camera)
+ if(Handle<Camera> camera = dynamic_handle_cast<Camera>(e.component))
+ set_active_camera(camera);
+ });
+}
// Hide unique_ptr destructors from the header
Stage::~Stage()
{ }
+void Stage::remove_system(System &s)
+{
+ scheduler.remove_system(s);
+ erase_if(systems, [&s](auto &p){ return p.get()==&s; });
+ pending_reschedule = true;
+}
+
+void Stage::set_active_camera(Handle<Camera> c)
+{
+ active_camera = c;
+ event_source.emit<Events::CameraChanged>(active_camera);
+}
+
+void Stage::synthesize_initial_events(EventObserver &target_observer)
+{
+ synthesize_initial_events(Handle<Entity>::from_object(root.get()), target_observer);
+ if(active_camera)
+ event_source.emit_to<Events::CameraChanged>(target_observer, active_camera);
+}
+
+void Stage::synthesize_initial_events(Handle<Entity> entity, EventObserver &target_observer)
+{
+ for(Handle<Component> c: entity->get_components())
+ event_source.emit_to<Events::ComponentCreated>(target_observer, c);
+ for(Handle<Entity> e: entity->get_children())
+ synthesize_initial_events(e, target_observer);
+ event_source.emit_to<Events::EntityCreated>(target_observer, entity);
+}
+
void Stage::tick(Time::TimeDelta dt)
{
+ if(pending_reschedule)
+ {
+ scheduler.schedule();
+ pending_reschedule = false;
+ }
+
+ {
+#ifdef DEBUG
+ AccessGuard::BlockForScope _block;
+#endif
+ for(const SystemScheduler::Group &g: scheduler.get_groups())
+ for(System *s: g.systems)
+ {
+ System::Activator act(*s);
+ try
+ {
+ s->tick(dt);
+ }
+ catch(const invalid_access &exc)
+ {
+ throw invalid_access(format("%s by %s", exc.what(), Debug::demangle(typeid(*s).name())));
+ }
+ }
+ }
+
for(const auto &s: systems)
- s->tick(dt);
+ s->deferred_tick();
}
} // namespace Msp::Game