mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
add SchedulePlans
This commit is contained in:
parent
1471cc84c5
commit
683a70d8e7
9 changed files with 268 additions and 110 deletions
|
@ -26,7 +26,7 @@ impl Default for App {
|
|||
|
||||
impl App {
|
||||
pub fn build() -> AppBuilder {
|
||||
AppBuilder::new()
|
||||
AppBuilder::default()
|
||||
}
|
||||
|
||||
pub fn update(&mut self) {
|
||||
|
|
|
@ -1,32 +1,39 @@
|
|||
use crate::{
|
||||
default_stage,
|
||||
plugin::{load_plugin, AppPlugin},
|
||||
system_stage, App, Events,
|
||||
schedule_plan::SchedulePlan,
|
||||
App, Events,
|
||||
};
|
||||
|
||||
use legion::prelude::{Resources, Runnable, Schedulable, Schedule, Universe, World};
|
||||
use std::collections::HashMap;
|
||||
use legion::prelude::{Resources, Runnable, Schedulable, Universe, World};
|
||||
|
||||
static APP_MISSING_MESSAGE: &str = "This AppBuilder no longer has an App. Check to see if you already called run(). A call to app_builder.run() consumes the AppBuilder's App.";
|
||||
|
||||
pub struct AppBuilder {
|
||||
app: Option<App>,
|
||||
pub setup_systems: Vec<Box<dyn Schedulable>>,
|
||||
// TODO: these separate lists will produce incorrect ordering
|
||||
pub system_stages: HashMap<String, Vec<Box<dyn Schedulable>>>,
|
||||
pub runnable_stages: HashMap<String, Vec<Box<dyn Runnable>>>,
|
||||
pub thread_local_stages: HashMap<String, Vec<Box<dyn FnMut(&mut World, &mut Resources)>>>,
|
||||
pub stage_order: Vec<String>,
|
||||
schedule_plan: SchedulePlan,
|
||||
startup_schedule_plan: SchedulePlan,
|
||||
}
|
||||
|
||||
impl Default for AppBuilder {
|
||||
fn default() -> Self {
|
||||
let mut app_builder = AppBuilder {
|
||||
app: Some(App::default()),
|
||||
schedule_plan: SchedulePlan::default(),
|
||||
startup_schedule_plan: SchedulePlan::default(),
|
||||
};
|
||||
|
||||
app_builder.add_default_stages();
|
||||
app_builder
|
||||
}
|
||||
}
|
||||
|
||||
impl AppBuilder {
|
||||
pub fn new() -> Self {
|
||||
pub fn empty() -> AppBuilder {
|
||||
AppBuilder {
|
||||
app: Some(App::default()),
|
||||
setup_systems: Vec::new(),
|
||||
system_stages: HashMap::new(),
|
||||
runnable_stages: HashMap::new(),
|
||||
thread_local_stages: HashMap::new(),
|
||||
stage_order: Vec::new(),
|
||||
schedule_plan: SchedulePlan::default(),
|
||||
startup_schedule_plan: SchedulePlan::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,53 +69,21 @@ impl AppBuilder {
|
|||
&mut self.app_mut().resources
|
||||
}
|
||||
|
||||
pub fn build_and_run_startup_schedule(&mut self) -> &mut Self {
|
||||
let mut startup_schedule = self.startup_schedule_plan.build();
|
||||
let app = self.app_mut();
|
||||
startup_schedule.execute(&mut app.world, &mut app.resources);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build_schedule(&mut self) -> &mut Self {
|
||||
let mut setup_schedule_builder = Schedule::builder();
|
||||
for setup_system in self.setup_systems.drain(..) {
|
||||
setup_schedule_builder = setup_schedule_builder.add_system(setup_system);
|
||||
}
|
||||
|
||||
let mut setup_schedule = setup_schedule_builder.build();
|
||||
let app = self.app_mut();
|
||||
setup_schedule.execute(&mut app.world, &mut app.resources);
|
||||
|
||||
let mut schedule_builder = Schedule::builder();
|
||||
for stage_name in self.stage_order.iter() {
|
||||
if let Some((_name, stage_systems)) = self.system_stages.remove_entry(stage_name) {
|
||||
for system in stage_systems {
|
||||
schedule_builder = schedule_builder.add_system(system);
|
||||
}
|
||||
|
||||
schedule_builder = schedule_builder.flush();
|
||||
}
|
||||
|
||||
if let Some((_name, stage_runnables)) = self.runnable_stages.remove_entry(stage_name) {
|
||||
for system in stage_runnables {
|
||||
schedule_builder = schedule_builder.add_thread_local(system);
|
||||
}
|
||||
|
||||
schedule_builder = schedule_builder.flush();
|
||||
}
|
||||
|
||||
if let Some((_name, stage_thread_locals)) =
|
||||
self.thread_local_stages.remove_entry(stage_name)
|
||||
{
|
||||
for system in stage_thread_locals {
|
||||
schedule_builder = schedule_builder.add_thread_local_fn(system);
|
||||
}
|
||||
|
||||
schedule_builder = schedule_builder.flush();
|
||||
}
|
||||
}
|
||||
|
||||
let app = self.app_mut();
|
||||
app.schedule = Some(schedule_builder.build());
|
||||
|
||||
self.app_mut().schedule = Some(self.schedule_plan.build());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
self.build_schedule();
|
||||
self.build_and_run_startup_schedule();
|
||||
self.app.take().unwrap().run();
|
||||
}
|
||||
|
||||
|
@ -123,15 +98,54 @@ impl AppBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn add_system(&mut self, system: Box<dyn Schedulable>) -> &mut Self {
|
||||
self.add_system_to_stage(system_stage::UPDATE, system)
|
||||
pub fn add_stage(&mut self, stage_name: &str) -> &mut Self {
|
||||
self.schedule_plan.add_stage(stage_name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_setup_system(&mut self, system: Box<dyn Schedulable>) -> &mut Self {
|
||||
self.setup_systems.push(system);
|
||||
pub fn add_stage_after(&mut self, target: &str, stage_name: &str) -> &mut Self {
|
||||
self.schedule_plan.add_stage_after(target, stage_name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_stage_before(&mut self, target: &str, stage_name: &str) -> &mut Self {
|
||||
self.schedule_plan.add_stage_before(target, stage_name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_startup_stage(&mut self, stage_name: &str) -> &mut Self {
|
||||
self.startup_schedule_plan.add_stage(stage_name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_system(&mut self, system: Box<dyn Schedulable>) -> &mut Self {
|
||||
self.add_system_to_stage(default_stage::UPDATE, system)
|
||||
}
|
||||
|
||||
pub fn add_startup_system_to_stage(
|
||||
&mut self,
|
||||
stage_name: &str,
|
||||
system: Box<dyn Schedulable>,
|
||||
) -> &mut Self {
|
||||
self.startup_schedule_plan
|
||||
.add_system_to_stage(stage_name, system);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_startup_system(&mut self, system: Box<dyn Schedulable>) -> &mut Self {
|
||||
self.startup_schedule_plan
|
||||
.add_system_to_stage(default_stage::STARTUP, system);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_default_stages(&mut self) -> &mut Self {
|
||||
self.add_startup_stage(default_stage::STARTUP)
|
||||
.add_stage(default_stage::FIRST)
|
||||
.add_stage(default_stage::EVENT_UPDATE)
|
||||
.add_stage(default_stage::UPDATE)
|
||||
.add_stage(default_stage::LAST)
|
||||
}
|
||||
|
||||
pub fn build_system<F>(&mut self, build: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&mut Resources) -> Box<dyn Schedulable>,
|
||||
|
@ -145,49 +159,27 @@ impl AppBuilder {
|
|||
stage_name: &str,
|
||||
system: Box<dyn Schedulable>,
|
||||
) -> &mut Self {
|
||||
if let None = self.system_stages.get(stage_name) {
|
||||
self.system_stages
|
||||
.insert(stage_name.to_string(), Vec::new());
|
||||
self.stage_order.push(stage_name.to_string());
|
||||
}
|
||||
|
||||
let stages = self.system_stages.get_mut(stage_name).unwrap();
|
||||
stages.push(system);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_runnable_to_stage(
|
||||
&mut self,
|
||||
stage_name: &str,
|
||||
system: Box<dyn Runnable>,
|
||||
) -> &mut Self {
|
||||
if let None = self.runnable_stages.get(stage_name) {
|
||||
self.runnable_stages
|
||||
.insert(stage_name.to_string(), Vec::new());
|
||||
self.stage_order.push(stage_name.to_string());
|
||||
}
|
||||
|
||||
let stages = self.runnable_stages.get_mut(stage_name).unwrap();
|
||||
stages.push(system);
|
||||
|
||||
self.schedule_plan.add_system_to_stage(stage_name, system);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_thread_local_to_stage(
|
||||
&mut self,
|
||||
stage_name: &str,
|
||||
f: impl FnMut(&mut World, &mut Resources) + 'static,
|
||||
system: Box<dyn Runnable>,
|
||||
) -> &mut Self {
|
||||
if let None = self.thread_local_stages.get(stage_name) {
|
||||
self.thread_local_stages
|
||||
.insert(stage_name.to_string(), Vec::new());
|
||||
// TODO: this is so broken
|
||||
self.stage_order.push(stage_name.to_string());
|
||||
self.schedule_plan
|
||||
.add_thread_local_to_stage(stage_name, system);
|
||||
self
|
||||
}
|
||||
|
||||
let thread_local_stages = self.thread_local_stages.get_mut(stage_name).unwrap();
|
||||
thread_local_stages.push(Box::new(f));
|
||||
pub fn add_thread_local_fn_to_stage(
|
||||
&mut self,
|
||||
stage_name: &str,
|
||||
f: impl FnMut(&mut World, &mut Resources) + 'static,
|
||||
) -> &mut Self {
|
||||
self.schedule_plan
|
||||
.add_thread_local_fn_to_stage(stage_name, f);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -197,7 +189,7 @@ impl AppBuilder {
|
|||
{
|
||||
self.add_resource(Events::<T>::default())
|
||||
.add_system_to_stage(
|
||||
system_stage::EVENT_UPDATE,
|
||||
default_stage::EVENT_UPDATE,
|
||||
Events::<T>::build_update_system(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// TODO: move me
|
||||
pub const STARTUP: &str = "startup";
|
||||
|
||||
pub const FIRST: &str = "first";
|
||||
pub const EVENT_UPDATE: &str = "event_update";
|
||||
pub const UPDATE: &str = "update";
|
||||
pub const RENDER: &str = "render";
|
||||
pub const LAST: &str = "last";
|
|
@ -2,8 +2,9 @@ mod app;
|
|||
mod app_builder;
|
||||
mod event;
|
||||
mod plugin;
|
||||
pub mod schedule_plan;
|
||||
pub mod schedule_runner;
|
||||
pub mod system_stage;
|
||||
pub mod default_stage;
|
||||
|
||||
pub use app::*;
|
||||
pub use app_builder::*;
|
||||
|
|
163
bevy_app/src/schedule_plan.rs
Normal file
163
bevy_app/src/schedule_plan.rs
Normal file
|
@ -0,0 +1,163 @@
|
|||
use legion::prelude::*;
|
||||
use std::{cmp::Ordering, collections::HashMap};
|
||||
|
||||
enum System {
|
||||
Schedulable(Box<dyn Schedulable>),
|
||||
ThreadLocal(Box<dyn Runnable>),
|
||||
ThreadLocalFn(Box<dyn FnMut(&mut World, &mut Resources)>),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SchedulePlan {
|
||||
stages: HashMap<String, Vec<System>>,
|
||||
stage_order: Vec<String>,
|
||||
}
|
||||
|
||||
impl SchedulePlan {
|
||||
pub fn build(&mut self) -> Schedule {
|
||||
let mut schedule_builder = Schedule::builder();
|
||||
|
||||
for stage in self.stage_order.drain(..) {
|
||||
if let Some((_, mut systems)) = self.stages.remove_entry(&stage) {
|
||||
let system_count = systems.len();
|
||||
for system in systems.drain(..) {
|
||||
match system {
|
||||
System::Schedulable(schedulable) => {
|
||||
schedule_builder = schedule_builder.add_system(schedulable);
|
||||
}
|
||||
System::ThreadLocal(runnable) => {
|
||||
schedule_builder = schedule_builder.add_thread_local(runnable);
|
||||
}
|
||||
System::ThreadLocalFn(thread_local) => {
|
||||
schedule_builder = schedule_builder.add_thread_local_fn(thread_local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if system_count > 0 {
|
||||
schedule_builder = schedule_builder.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schedule_builder.build()
|
||||
}
|
||||
|
||||
pub fn add_stage(&mut self, stage: &str) {
|
||||
if let Some(_) = self.stages.get(stage) {
|
||||
panic!("Stage already exists: {}", stage);
|
||||
} else {
|
||||
self.stages.insert(stage.to_string(), Vec::new());
|
||||
self.stage_order.push(stage.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_stage_after(&mut self, target: &str, stage: &str) {
|
||||
if let Some(_) = self.stages.get(stage) {
|
||||
panic!("Stage already exists: {}", stage);
|
||||
}
|
||||
|
||||
let target_index = self
|
||||
.stage_order
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_i, stage)| stage.as_str() == target)
|
||||
.map(|(i, _)| i)
|
||||
.unwrap_or_else(|| panic!("Target stage does not exist: {}", target));
|
||||
|
||||
self.stages.insert(stage.to_string(), Vec::new());
|
||||
self.stage_order.insert(target_index + 1, stage.to_string());
|
||||
}
|
||||
|
||||
pub fn add_stage_before(&mut self, target: &str, stage: &str) {
|
||||
if let Some(_) = self.stages.get(stage) {
|
||||
panic!("Stage already exists: {}", stage);
|
||||
}
|
||||
|
||||
let target_index = self
|
||||
.stage_order
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_i, stage)| stage.as_str() == target)
|
||||
.map(|(i, _)| i)
|
||||
.unwrap_or_else(|| panic!("Target stage does not exist: {}", target));
|
||||
|
||||
self.stages.insert(stage.to_string(), Vec::new());
|
||||
self.stage_order.insert(target_index, stage.to_string());
|
||||
}
|
||||
|
||||
pub fn add_system_to_stage(
|
||||
&mut self,
|
||||
stage_name: &str,
|
||||
system: Box<dyn Schedulable>,
|
||||
) -> &mut Self {
|
||||
let system = System::Schedulable(system);
|
||||
let systems = self
|
||||
.stages
|
||||
.get_mut(stage_name)
|
||||
.unwrap_or_else(|| panic!("Stage does not exist: {}", stage_name));
|
||||
systems.push(system);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_thread_local_to_stage(
|
||||
&mut self,
|
||||
stage_name: &str,
|
||||
runnable: Box<dyn Runnable>,
|
||||
) -> &mut Self {
|
||||
let system = System::ThreadLocal(runnable);
|
||||
let systems = self
|
||||
.stages
|
||||
.get_mut(stage_name)
|
||||
.unwrap_or_else(|| panic!("Stage does not exist: {}", stage_name));
|
||||
systems.push(system);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_thread_local_fn_to_stage(
|
||||
&mut self,
|
||||
stage_name: &str,
|
||||
f: impl FnMut(&mut World, &mut Resources) + 'static,
|
||||
) -> &mut Self {
|
||||
let system = System::ThreadLocalFn(Box::new(f));
|
||||
let systems = self
|
||||
.stages
|
||||
.get_mut(stage_name)
|
||||
.unwrap_or_else(|| panic!("Stage does not exist: {}", stage_name));
|
||||
systems.push(system);
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// working around the famous "rust float ordering" problem
|
||||
#[derive(PartialOrd)]
|
||||
struct FloatOrd(f32);
|
||||
|
||||
impl Ord for FloatOrd {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.0.partial_cmp(&other.0).unwrap_or_else(|| {
|
||||
if self.0.is_nan() && !other.0.is_nan() {
|
||||
Ordering::Less
|
||||
} else if !self.0.is_nan() && other.0.is_nan() {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FloatOrd {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.0.is_nan() && other.0.is_nan() {
|
||||
true
|
||||
} else {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for FloatOrd {}
|
|
@ -1,7 +1,7 @@
|
|||
pub mod bytes;
|
||||
pub mod time;
|
||||
|
||||
use bevy_app::{system_stage, AppBuilder, AppPlugin};
|
||||
use bevy_app::{default_stage, AppBuilder, AppPlugin};
|
||||
use bevy_transform::transform_system_bundle;
|
||||
use time::{start_timer_system, stop_timer_system};
|
||||
|
||||
|
@ -15,7 +15,7 @@ impl AppPlugin for CorePlugin {
|
|||
}
|
||||
|
||||
app.add_resource(time::Time::new())
|
||||
.add_system_to_stage(system_stage::FIRST, start_timer_system())
|
||||
.add_system_to_stage(system_stage::LAST, stop_timer_system());
|
||||
.add_system_to_stage(default_stage::FIRST, start_timer_system())
|
||||
.add_system_to_stage(default_stage::LAST, stop_timer_system());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,11 +48,13 @@ use self::{
|
|||
},
|
||||
};
|
||||
|
||||
use bevy_app::{AppBuilder, AppPlugin, GetEventReader};
|
||||
use bevy_app::{AppBuilder, AppPlugin, GetEventReader, default_stage};
|
||||
use bevy_transform::prelude::LocalToWorld;
|
||||
use bevy_asset::AssetStorage;
|
||||
use bevy_window::WindowResized;
|
||||
|
||||
pub static RENDER_STAGE: &str = "render";
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RenderPlugin;
|
||||
|
||||
|
@ -94,6 +96,7 @@ impl AppPlugin for RenderPlugin {
|
|||
asset_batchers.batch_types2::<Mesh, StandardMaterial>();
|
||||
app
|
||||
.add_system(build_entity_render_resource_assignments_system())
|
||||
.add_stage_after(default_stage::UPDATE, RENDER_STAGE)
|
||||
.add_resource(RenderGraph::default())
|
||||
.add_resource(AssetStorage::<Mesh>::new())
|
||||
.add_resource(AssetStorage::<Texture>::new())
|
||||
|
|
|
@ -7,8 +7,8 @@ pub use wgpu_render_pass::*;
|
|||
pub use wgpu_renderer::*;
|
||||
pub use wgpu_resources::*;
|
||||
|
||||
use bevy_app::{AppPlugin, system_stage, AppBuilder, Events};
|
||||
use bevy_render::renderer::Renderer;
|
||||
use bevy_app::{AppPlugin, AppBuilder, Events};
|
||||
use bevy_render::{renderer::Renderer, RENDER_STAGE};
|
||||
use bevy_window::{WindowCreated, WindowResized};
|
||||
use legion::prelude::*;
|
||||
|
||||
|
@ -18,7 +18,7 @@ pub struct WgpuRendererPlugin;
|
|||
impl AppPlugin for WgpuRendererPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
let render_system = wgpu_render_system(app.resources());
|
||||
app.add_thread_local_to_stage(system_stage::RENDER, render_system);
|
||||
app.add_thread_local_fn_to_stage(RENDER_STAGE, render_system);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,11 @@ use bevy::prelude::*;
|
|||
fn main() {
|
||||
App::build()
|
||||
.add_default_plugins()
|
||||
.add_setup_system(setup_system())
|
||||
.add_startup_system(startup_system())
|
||||
.run();
|
||||
}
|
||||
|
||||
pub fn setup_system() -> Box<dyn Schedulable> {
|
||||
pub fn startup_system() -> Box<dyn Schedulable> {
|
||||
SystemBuilder::new("setup")
|
||||
.write_resource::<AssetStorage<Mesh>>()
|
||||
.write_resource::<AssetStorage<StandardMaterial>>()
|
Loading…
Reference in a new issue