1use crate::{
2 plugin::Plugin,
3 resources::Resources,
4 system::{IntoSystem, System},
5};
6use std::collections::BTreeMap;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub enum SystemStage {
10 Startup,
11 AssetSync,
12 AssetSyncDeps,
13 PreUpdate,
14 Update,
15 PostUpdate,
16 PreRender,
17 Render,
18 PostRender,
19}
20
21pub type AppRunner = Box<dyn FnOnce(App)>;
22
23pub struct App {
24 pub(crate) world: hecs::World,
25 pub(crate) resources: Resources,
26 plugins: Vec<Box<dyn Plugin>>,
27 systems: BTreeMap<SystemStage, Vec<Box<dyn System>>>,
28 runner: Option<AppRunner>,
29}
30
31impl Default for App {
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37impl App {
38 pub fn new() -> Self {
39 let mut world = hecs::World::default();
40 let mut resources = Resources::new(&mut world);
41 resources.insert_resource(&mut world, ());
42
43 Self {
44 world: world,
45 resources: resources,
46 plugins: Vec::new(),
47 systems: BTreeMap::new(),
48 runner: Some(Box::new(|mut app| {
49 loop {
50 app.update();
51 }
52 })),
53 }
54 }
55
56 pub fn add_plugin(&mut self, plugin: impl Plugin) -> &mut Self {
57 self.plugins.push(Box::new(plugin));
58 self
59 }
60
61 pub fn add_resource(&mut self, res: impl hecs::Component) -> &mut Self {
62 self.resources.insert_resource(&mut self.world, res);
63 self
64 }
65
66 pub fn get_resource<'a, T: hecs::Component>(&'a self) -> hecs::Ref<'a, T> {
67 self.resources.get_resource(&self.world)
68 }
69
70 pub fn get_resource_mut<'a, T: hecs::Component>(&'a self) -> hecs::RefMut<'a, T> {
71 self.resources.get_resource_mut(&self.world)
72 }
73
74 pub fn try_insert_resource<T: hecs::Component>(&mut self, res: T) -> bool {
75 self.resources.try_insert(&mut self.world, res)
76 }
77
78 pub fn add_system<Marker>(
79 &mut self,
80 stage: SystemStage,
81 system: impl IntoSystem<Marker> + 'static,
82 ) -> &mut Self {
83 self.systems
84 .entry(stage)
85 .or_default()
86 .push(Box::new(system.into_system()));
87 self
88 }
89
90 pub fn build(&mut self) -> &mut Self {
91 while !self.plugins.is_empty() {
92 let plugins: Vec<_> = self.plugins.drain(..).collect();
93 for plugin in plugins {
94 plugin.build(self);
95 }
96 }
97
98 if let Some(systems) = self.systems.remove(&SystemStage::Startup) {
99 for mut system in systems {
100 system.run(&self.world, &self.resources);
101 }
102 self.resources.get_command_buffer().run_on(&mut self.world);
103 }
104 self
105 }
106
107 pub fn update(&mut self) {
108 for systems in self.systems.values_mut() {
109 for system in systems {
110 system.run(&self.world, &self.resources);
111 }
112 self.resources.get_command_buffer().run_on(&mut self.world);
113 }
114 }
115
116 pub fn set_runner<F>(&mut self, runner: F) -> &mut Self
117 where
118 F: FnOnce(App) + 'static,
119 {
120 self.runner = Some(Box::new(runner));
121 self
122 }
123
124 pub fn run(&mut self) {
125 let mut owned_app = std::mem::take(self);
126 let runner = owned_app.runner.take().expect("No runner found!");
127 runner(owned_app);
128 }
129}