bevy/crates/bevy_app/src/schedule_runner.rs

138 lines
4.8 KiB
Rust
Raw Normal View History

2020-07-17 01:47:51 +00:00
use super::{App, AppBuilder};
use crate::{app::AppExit, event::Events, plugin::Plugin, ManualEventReader};
use bevy_utils::{Duration, Instant};
#[cfg(target_arch = "wasm32")]
use std::{cell::RefCell, rc::Rc};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::{prelude::*, JsCast};
2020-03-30 18:52:33 +00:00
/// Determines the method used to run an [App]'s `Schedule`
2020-03-30 18:52:33 +00:00
#[derive(Copy, Clone, Debug)]
pub enum RunMode {
2020-04-04 19:43:16 +00:00
Loop { wait: Option<Duration> },
2020-03-30 18:52:33 +00:00
Once,
}
impl Default for RunMode {
fn default() -> Self {
2020-04-04 19:43:16 +00:00
RunMode::Loop { wait: None }
2020-03-30 18:52:33 +00:00
}
}
#[derive(Copy, Clone, Default)]
pub struct ScheduleRunnerSettings {
2020-03-30 18:52:33 +00:00
pub run_mode: RunMode,
}
impl ScheduleRunnerSettings {
2020-05-01 20:12:47 +00:00
pub fn run_once() -> Self {
ScheduleRunnerSettings {
2020-05-01 20:12:47 +00:00
run_mode: RunMode::Once,
}
}
pub fn run_loop(wait_duration: Duration) -> Self {
ScheduleRunnerSettings {
2020-05-06 01:44:32 +00:00
run_mode: RunMode::Loop {
wait: Some(wait_duration),
},
2020-05-01 20:12:47 +00:00
}
}
}
/// Configures an App to run its [Schedule](bevy_ecs::Schedule) according to a given [RunMode]
#[derive(Default)]
pub struct ScheduleRunnerPlugin {}
2020-08-08 03:22:17 +00:00
impl Plugin for ScheduleRunnerPlugin {
2020-04-06 03:19:02 +00:00
fn build(&self, app: &mut AppBuilder) {
let settings = app
.resources_mut()
.get_or_insert_with(ScheduleRunnerSettings::default)
.to_owned();
2020-04-19 19:13:04 +00:00
app.set_runner(move |mut app: App| {
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
match settings.run_mode {
2020-04-19 19:13:04 +00:00
RunMode::Once => {
app.update();
2020-04-06 03:19:02 +00:00
}
RunMode::Loop { wait } => {
let mut tick = move |app: &mut App,
wait: Option<Duration>|
-> Result<Option<Duration>, AppExit> {
let start_time = Instant::now();
if let Some(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() {
if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last()
{
return Err(exit.clone());
}
2020-04-19 19:13:04 +00:00
}
app.update();
2020-05-03 07:21:32 +00:00
if let Some(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() {
if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last()
{
return Err(exit.clone());
}
2020-05-03 07:21:32 +00:00
}
let end_time = Instant::now();
if let Some(wait) = wait {
let exe_time = end_time - start_time;
if exe_time < wait {
return Ok(Some(wait - exe_time));
}
}
Ok(None)
};
#[cfg(not(target_arch = "wasm32"))]
{
while let Ok(delay) = tick(&mut app, wait) {
if let Some(delay) = delay {
std::thread::sleep(delay);
}
}
2020-04-19 19:13:04 +00:00
}
#[cfg(target_arch = "wasm32")]
{
fn set_timeout(f: &Closure<dyn FnMut()>, dur: Duration) {
web_sys::window()
.unwrap()
.set_timeout_with_callback_and_timeout_and_arguments_0(
f.as_ref().unchecked_ref(),
dur.as_millis() as i32,
)
.expect("Should register `setTimeout`.");
}
let asap = Duration::from_millis(1);
let mut rc = Rc::new(app);
let f = Rc::new(RefCell::new(None));
let g = f.clone();
let c = move || {
let mut app = Rc::get_mut(&mut rc).unwrap();
let delay = tick(&mut app, wait);
match delay {
Ok(delay) => {
set_timeout(f.borrow().as_ref().unwrap(), delay.unwrap_or(asap))
}
Err(_) => {}
}
};
*g.borrow_mut() = Some(Closure::wrap(Box::new(c) as Box<dyn FnMut()>));
set_timeout(g.borrow().as_ref().unwrap(), asap);
};
}
2020-03-30 18:52:33 +00:00
}
2020-04-06 03:19:02 +00:00
});
2020-03-30 18:52:33 +00:00
}
}