]> git.tdb.fi Git - libs/game.git/blob - source/game/stage.cpp
Schedule systems based on their declared dependencies
[libs/game.git] / source / game / stage.cpp
1 #include "stage.h"
2 #include <msp/debug/demangle.h>
3 #include <msp/strings/format.h>
4 #include "accessguard.h"
5 #include "camera.h"
6 #include "root.h"
7 #include "system.h"
8
9 using namespace std;
10
11 namespace Msp::Game {
12
13 Stage::Stage(Reflection::Reflector &f, DataFile::Collection &r):
14         reflector(f),
15         resources(r),
16         event_source(event_bus),
17         event_observer(event_bus),
18         root(std::make_unique<Root>(*this)),
19         scheduler(reflector)
20 {
21         event_observer.observe<Events::ComponentCreated>([this](auto &e){
22                 if(!active_camera)
23                         if(Handle<Camera> camera = dynamic_handle_cast<Camera>(e.component))
24                                 set_active_camera(camera);
25         });
26 }
27
28 // Hide unique_ptr destructors from the header
29 Stage::~Stage()
30 { }
31
32 void Stage::remove_system(System &s)
33 {
34         scheduler.remove_system(s);
35         erase_if(systems, [&s](auto &p){ return p.get()==&s; });
36         pending_reschedule = true;
37 }
38
39 void Stage::set_active_camera(Handle<Camera> c)
40 {
41         active_camera = c;
42         event_source.emit<Events::CameraChanged>(active_camera);
43 }
44
45 void Stage::synthesize_initial_events(EventObserver &target_observer)
46 {
47         synthesize_initial_events(Handle<Entity>::from_object(root.get()), target_observer);
48         if(active_camera)
49                 event_source.emit_to<Events::CameraChanged>(target_observer, active_camera);
50 }
51
52 void Stage::synthesize_initial_events(Handle<Entity> entity, EventObserver &target_observer)
53 {
54         for(Handle<Component> c: entity->get_components())
55                 event_source.emit_to<Events::ComponentCreated>(target_observer, c);
56         for(Handle<Entity> e: entity->get_children())
57                 synthesize_initial_events(e, target_observer);
58         event_source.emit_to<Events::EntityCreated>(target_observer, entity);
59 }
60
61 void Stage::tick(Time::TimeDelta dt)
62 {
63         if(pending_reschedule)
64         {
65                 scheduler.schedule();
66                 pending_reschedule = false;
67         }
68
69         {
70 #ifdef DEBUG
71                 AccessGuard::BlockForScope _block;
72 #endif
73                 for(const SystemScheduler::Group &g: scheduler.get_groups())
74                         for(System *s: g.systems)
75                         {
76                                 System::Activator act(*s);
77                                 try
78                                 {
79                                         s->tick(dt);
80                                 }
81                                 catch(const invalid_access &exc)
82                                 {
83                                         throw invalid_access(format("%s by %s", exc.what(), Debug::demangle(typeid(*s).name())));
84                                 }
85                         }
86         }
87
88         for(const auto &s: systems)
89                 s->deferred_tick();
90 }
91
92 } // namespace Msp::Game