1use std::{
6 any::{Any, TypeId},
7 collections::HashMap,
8};
9
10use magma_ecs::{
11 error::EventError,
12 rayon::iter::{IntoParallelRefIterator, ParallelIterator},
13 systems::{Systems, dispatcher::Dispatcher},
14};
15use module::Module;
16
17pub use magma_ecs;
18pub use magma_ecs::{World, entities, rayon, resources, systems};
19pub use schedule::AppSchedule;
20
21use crate::{
22 error::ScheduleError,
23 schedule::{PostUpdate, PreUpdate, Startup, Update},
24};
25
26pub mod error;
27pub mod module;
29pub mod schedule;
31
32type SystemSlice = &'static [(fn(&World), &'static str, &'static [&'static str])];
33
34pub struct App {
36 pub world: World,
37 runner: fn(App),
38 modules: Vec<TypeId>,
39 systems: HashMap<TypeId, (Systems, Dispatcher)>,
40 event_systems: HashMap<TypeId, (Systems, Dispatcher)>,
41}
42
43impl Default for App {
44 fn default() -> Self {
45 let mut app = Self {
46 world: Default::default(),
47 runner: default_runner,
48 modules: vec![],
49 systems: Default::default(),
50 event_systems: Default::default(),
51 };
52
53 app.register_schedule::<Startup>();
54 app.register_schedule::<PreUpdate>();
55 app.register_schedule::<Update>();
56 app.register_schedule::<PostUpdate>();
57
58 app
59 }
60}
61
62impl App {
63 pub fn new() -> Self {
65 Self::default()
66 }
67
68 pub fn add_module(&mut self, module: impl Module + 'static) {
90 let type_id = module.type_id();
91 if !self.modules.contains(&type_id) {
92 self.modules.push(type_id);
93 module.setup(self);
94 }
95 }
96
97 pub fn register_schedule<S: AppSchedule + 'static>(&mut self) {
99 self.systems.insert(TypeId::of::<S>(), Default::default());
100 }
101
102 pub fn run_schedule<S: AppSchedule + 'static>(&self) -> Result<(), ScheduleError> {
104 self.systems
105 .get(&TypeId::of::<S>())
106 .ok_or(ScheduleError::ScheduleNotRegistered)?
107 .1
108 .dispatch(&self.world);
109 Ok(())
110 }
111
112 pub fn add_systems<S: AppSchedule + 'static>(
134 &mut self,
135 systems: SystemSlice,
136 ) -> Result<(), ScheduleError> {
137 let schedule = self
138 .systems
139 .get_mut(&TypeId::of::<S>())
140 .ok_or(ScheduleError::ScheduleNotRegistered)?;
141 for (run, name, deps) in systems {
142 schedule.0.add(*run, name, deps);
143 }
144
145 schedule.1 = schedule.0.to_owned().build_dispatcher();
146 Ok(())
147 }
148
149 pub fn register_event<E: Any + Send + Sync + Clone>(&mut self) {
150 self.world.register_event::<E>();
151 self.event_systems
152 .insert(TypeId::of::<E>(), (Systems::new(), Dispatcher::default()));
153 }
154
155 pub fn add_event_systems<E: Any + Send + Sync + Clone>(
156 &mut self,
157 systems: SystemSlice,
158 ) -> Result<(), EventError> {
159 let event_systems = self
160 .event_systems
161 .get_mut(&TypeId::of::<E>())
162 .ok_or(EventError::EventNotRegistered)?;
163 for (run, name, deps) in systems {
164 event_systems.0.add(*run, name, deps);
165 }
166 event_systems.1 = event_systems.0.to_owned().build_dispatcher();
167 Ok(())
168 }
169
170 pub fn set_runner(&mut self, runner: fn(App)) {
172 self.runner = runner;
173 }
174
175 pub fn process_events(&self) {
177 let events = self.world.get_pending_events();
178 events.par_iter().for_each(|type_id| {
180 self.event_systems
181 .get(type_id)
182 .unwrap()
183 .1
184 .dispatch(&self.world);
185 });
186
187 self.world.clear_events();
188 }
189
190 pub fn run(self) {
192 (self.runner)(self);
193 }
194}
195
196fn default_runner(app: App) {
197 app.run_schedule::<Startup>().unwrap();
198 loop {
199 app.run_schedule::<PreUpdate>().unwrap();
200 app.run_schedule::<Update>().unwrap();
201 app.run_schedule::<PostUpdate>().unwrap();
202 app.process_events();
203 }
204}