Skip to main content

pebble/
app.rs

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}