diff --git a/Cargo.toml b/Cargo.toml index 9e8551ffc3daf..73e9066423646 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,15 +17,18 @@ repository = "https://github.com/bevyengine/bevy" [workspace] exclude = ["benches"] -members = ["crates/*", "examples/ios", "tools/ci"] +members = ["crates/*", "pipelined/*", "examples/ios", "tools/ci"] [features] default = [ "bevy_audio", "bevy_dynamic_plugin", "bevy_gilrs", - "bevy_gltf", + "bevy_gltf2", "bevy_wgpu", + "bevy_sprite2", + "bevy_render2", + "bevy_pbr2", "bevy_winit", "render", "png", @@ -48,6 +51,11 @@ bevy_gltf = ["bevy_internal/bevy_gltf"] bevy_wgpu = ["bevy_internal/bevy_wgpu"] bevy_winit = ["bevy_internal/bevy_winit"] +bevy_render2 = ["bevy_internal/bevy_render2"] +bevy_sprite2 = ["bevy_internal/bevy_sprite2"] +bevy_pbr2 = ["bevy_internal/bevy_pbr2"] +bevy_gltf2 = ["bevy_internal/bevy_gltf2"] + trace_chrome = ["bevy_internal/trace_chrome"] trace = ["bevy_internal/trace"] wgpu_trace = ["bevy_internal/wgpu_trace"] @@ -132,10 +140,22 @@ path = "examples/2d/texture_atlas.rs" name = "3d_scene" path = "examples/3d/3d_scene.rs" +[[example]] +name = "3d_scene_pipelined" +path = "examples/3d/3d_scene_pipelined.rs" + +[[example]] +name = "cornell_box_pipelined" +path = "examples/3d/cornell_box_pipelined.rs" + [[example]] name = "load_gltf" path = "examples/3d/load_gltf.rs" +[[example]] +name = "load_gltf_pipelined" +path = "examples/3d/load_gltf_pipelined.rs" + [[example]] name = "msaa" path = "examples/3d/msaa.rs" @@ -152,10 +172,18 @@ path = "examples/3d/parenting.rs" name = "pbr" path = "examples/3d/pbr.rs" +[[example]] +name = "pbr_pipelined" +path = "examples/3d/pbr_pipelined.rs" + [[example]] name = "render_to_texture" path = "examples/3d/render_to_texture.rs" +[[example]] +name = "shadow_biases_pipelined" +path = "examples/3d/shadow_biases_pipelined.rs" + [[example]] name = "spawner" path = "examples/3d/spawner.rs" @@ -164,6 +192,10 @@ path = "examples/3d/spawner.rs" name = "texture" path = "examples/3d/texture.rs" +[[example]] +name = "texture_pipelined" +path = "examples/3d/texture_pipelined.rs" + [[example]] name = "update_gltf_scene" path = "examples/3d/update_gltf_scene.rs" @@ -416,6 +448,10 @@ path = "examples/shader/shader_defs.rs" name = "bevymark" path = "examples/tools/bevymark.rs" +[[example]] +name = "bevymark_pipelined" +path = "examples/tools/bevymark_pipelined.rs" + # UI (User Interface) [[example]] name = "button" diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index d30303a4ac9bd..8a01e6b6631b7 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1,10 +1,17 @@ -use crate::app_builder::AppBuilder; +use crate::{CoreStage, Events, Plugin, PluginGroup, PluginGroupBuilder, StartupStage}; use bevy_ecs::{ - schedule::{Schedule, Stage}, + component::{Component, ComponentDescriptor}, + prelude::{FromWorld, IntoExclusiveSystem, IntoSystem}, + schedule::{ + RunOnce, Schedule, Stage, StageLabel, State, SystemDescriptor, SystemSet, SystemStage, + }, world::World, }; +use bevy_utils::tracing::debug; #[cfg(feature = "trace")] use bevy_utils::tracing::info_span; +use std::fmt::Debug; +use std::hash::Hash; #[allow(clippy::needless_doctest_main)] /// Containers of app logic and data @@ -20,7 +27,7 @@ use bevy_utils::tracing::info_span; /// # use bevy_ecs::prelude::*; /// /// fn main() { -/// App::build() +/// App::new() /// .add_system(hello_world_system.system()) /// .run(); /// } @@ -33,25 +40,45 @@ pub struct App { pub world: World, pub runner: Box, pub schedule: Schedule, + sub_apps: Vec, +} + +struct SubApp { + app: App, + runner: Box, } impl Default for App { fn default() -> Self { - Self { - world: Default::default(), - schedule: Default::default(), - runner: Box::new(run_once), + let mut app = App::empty(); + #[cfg(feature = "bevy_reflect")] + app.init_resource::(); + + app.add_default_stages() + .add_event::() + .add_system_to_stage(CoreStage::Last, World::clear_trackers.exclusive_system()); + + #[cfg(feature = "bevy_ci_testing")] + { + crate::ci_testing::setup_app(&mut app); } - } -} -fn run_once(mut app: App) { - app.update(); + app + } } impl App { - pub fn build() -> AppBuilder { - AppBuilder::default() + pub fn new() -> App { + App::default() + } + + pub fn empty() -> App { + Self { + world: Default::default(), + schedule: Default::default(), + runner: Box::new(run_once), + sub_apps: Vec::new(), + } } pub fn update(&mut self) { @@ -60,17 +87,507 @@ impl App { #[cfg(feature = "trace")] let _bevy_frame_update_guard = bevy_frame_update_span.enter(); self.schedule.run(&mut self.world); + for sub_app in self.sub_apps.iter_mut() { + (sub_app.runner)(&mut self.world, &mut sub_app.app); + } } - pub fn run(mut self) { + /// Start the application (through main runner) + /// + /// Runs the application main loop. + /// + /// Usually the main loop is handled by Bevy integrated plugins (`winit`), but + /// but one can also set the runner function through [`App::set_runner`]. + /// + /// ## Example + /// ``` + /// # use bevy_app::prelude::*; + /// # + /// App::new() + /// // all required plugin insertions, systems, etc inserted here + /// // finally, call: + /// .run(); + /// ``` + pub fn run(&mut self) { #[cfg(feature = "trace")] let bevy_app_run_span = info_span!("bevy_app"); #[cfg(feature = "trace")] let _bevy_app_run_guard = bevy_app_run_span.enter(); - let runner = std::mem::replace(&mut self.runner, Box::new(run_once)); - (runner)(self); + let mut app = std::mem::replace(self, App::empty()); + let runner = std::mem::replace(&mut app.runner, Box::new(run_once)); + (runner)(app); + } + + pub fn add_stage(&mut self, label: impl StageLabel, stage: S) -> &mut Self { + self.schedule.add_stage(label, stage); + self + } + + pub fn add_stage_after( + &mut self, + target: impl StageLabel, + label: impl StageLabel, + stage: S, + ) -> &mut Self { + self.schedule.add_stage_after(target, label, stage); + self + } + + pub fn add_stage_before( + &mut self, + target: impl StageLabel, + label: impl StageLabel, + stage: S, + ) -> &mut Self { + self.schedule.add_stage_before(target, label, stage); + self + } + + pub fn add_startup_stage(&mut self, label: impl StageLabel, stage: S) -> &mut Self { + self.schedule + .stage(CoreStage::Startup, |schedule: &mut Schedule| { + schedule.add_stage(label, stage) + }); + self + } + + pub fn add_startup_stage_after( + &mut self, + target: impl StageLabel, + label: impl StageLabel, + stage: S, + ) -> &mut Self { + self.schedule + .stage(CoreStage::Startup, |schedule: &mut Schedule| { + schedule.add_stage_after(target, label, stage) + }); + self + } + + pub fn add_startup_stage_before( + &mut self, + target: impl StageLabel, + label: impl StageLabel, + stage: S, + ) -> &mut Self { + self.schedule + .stage(CoreStage::Startup, |schedule: &mut Schedule| { + schedule.add_stage_before(target, label, stage) + }); + self + } + + pub fn stage &mut T>( + &mut self, + label: impl StageLabel, + func: F, + ) -> &mut Self { + self.schedule.stage(label, func); + self + } + + /// Adds a system that runs every time `app.update()` is called by the runner + /// + /// Systems are the main building block in the Bevy ECS app model. You can define + /// normal rust functions, and call `.system()` to make them be Bevy systems. + /// + /// System functions can have parameters, through which one can query and + /// mutate Bevy ECS states. + /// See [The Bevy Book](https://bevyengine.org/learn/book/introduction/) for more information. + /// + /// Systems are run in parallel, and the execution order is not deterministic. + /// If you want more fine-grained control for order, see [`App::add_system_to_stage`]. + /// + /// For adding a system that runs only at app startup, see [`App::add_startup_system`]. + /// + /// ## Example + /// ``` + /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; + /// # + /// fn my_system(_commands: Commands) { + /// println!("My system, triggered once per frame"); + /// } + /// + /// App::new() + /// .add_system(my_system.system()); + /// ``` + pub fn add_system(&mut self, system: impl Into) -> &mut Self { + self.add_system_to_stage(CoreStage::Update, system) + } + + pub fn add_system_set(&mut self, system_set: SystemSet) -> &mut Self { + self.add_system_set_to_stage(CoreStage::Update, system_set) + } + + pub fn add_system_to_stage( + &mut self, + stage_label: impl StageLabel, + system: impl Into, + ) -> &mut Self { + self.schedule.add_system_to_stage(stage_label, system); + self + } + + pub fn add_system_set_to_stage( + &mut self, + stage_label: impl StageLabel, + system_set: SystemSet, + ) -> &mut Self { + self.schedule + .add_system_set_to_stage(stage_label, system_set); + self } + + /// Adds a system that is run once at application startup + /// + /// Startup systems run exactly once BEFORE all other systems. These are generally used for + /// app initialization code (ex: adding entities and resources). + /// + /// * For adding a system that runs for every frame, see [`App::add_system`]. + /// * For adding a system to specific stage, see [`App::add_system_to_stage`]. + /// + /// ## Example + /// ``` + /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; + /// # + /// fn my_startup_system(_commands: Commands) { + /// println!("My startup system"); + /// } + /// + /// App::new() + /// .add_startup_system(my_startup_system.system()); + /// ``` + pub fn add_startup_system(&mut self, system: impl Into) -> &mut Self { + self.add_startup_system_to_stage(StartupStage::Startup, system) + } + + pub fn add_startup_system_to_stage( + &mut self, + stage_label: impl StageLabel, + system: impl Into, + ) -> &mut Self { + self.schedule + .stage(CoreStage::Startup, |schedule: &mut Schedule| { + schedule.add_system_to_stage(stage_label, system) + }); + self + } + + /// Adds a new [State] with the given `initial` value. + /// This inserts a new `State` resource and adds a new "driver" to [CoreStage::Update]. + /// Each stage that uses `State` for system run criteria needs a driver. If you need to use + /// your state in a different stage, consider using [Self::add_state_to_stage] or manually + /// adding [State::get_driver] to additional stages you need it in. + pub fn add_state(&mut self, initial: T) -> &mut Self + where + T: Component + Debug + Clone + Eq + Hash, + { + self.add_state_to_stage(CoreStage::Update, initial) + } + + /// Adds a new [State] with the given `initial` value. + /// This inserts a new `State` resource and adds a new "driver" to the given stage. + /// Each stage that uses `State` for system run criteria needs a driver. If you need to use + /// your state in more than one stage, consider manually adding [State::get_driver] to the + /// stages you need it in. + pub fn add_state_to_stage(&mut self, stage: impl StageLabel, initial: T) -> &mut Self + where + T: Component + Debug + Clone + Eq + Hash, + { + self.insert_resource(State::new(initial)) + .add_system_set_to_stage(stage, State::::get_driver()) + } + + pub fn add_default_stages(&mut self) -> &mut Self { + self.add_stage(CoreStage::First, SystemStage::parallel()) + .add_stage( + CoreStage::Startup, + Schedule::default() + .with_run_criteria(RunOnce::default()) + .with_stage(StartupStage::PreStartup, SystemStage::parallel()) + .with_stage(StartupStage::Startup, SystemStage::parallel()) + .with_stage(StartupStage::PostStartup, SystemStage::parallel()), + ) + .add_stage(CoreStage::PreUpdate, SystemStage::parallel()) + .add_stage(CoreStage::Update, SystemStage::parallel()) + .add_stage(CoreStage::PostUpdate, SystemStage::parallel()) + .add_stage(CoreStage::Last, SystemStage::parallel()) + } + + /// Setup the application to manage events of type `T`. + /// + /// This is done by adding a `Resource` of type `Events::`, + /// and inserting a `Events::::update_system` system into `CoreStage::First`. + pub fn add_event(&mut self) -> &mut Self + where + T: Component, + { + self.insert_resource(Events::::default()) + .add_system_to_stage(CoreStage::First, Events::::update_system.system()) + } + + /// Inserts a resource to the current [App] and overwrites any resource previously added of the same type. + /// + /// A resource in Bevy represents globally unique data. Resources must be added to Bevy Apps + /// before using them. This happens with [`App::insert_resource`]. + /// + /// See also `init_resource` for resources that implement `Default` or [`FromResources`]. + /// + /// ## Example + /// ``` + /// # use bevy_app::prelude::*; + /// # + /// struct MyCounter { + /// counter: usize, + /// } + /// + /// App::new() + /// .insert_resource(MyCounter { counter: 0 }); + /// ``` + pub fn insert_resource(&mut self, resource: T) -> &mut Self + where + T: Component, + { + self.world.insert_resource(resource); + self + } + + /// Inserts a non-send resource to the app + /// + /// You usually want to use `insert_resource`, but there are some special cases when a resource must + /// be non-send. + /// + /// ## Example + /// ``` + /// # use bevy_app::prelude::*; + /// # + /// struct MyCounter { + /// counter: usize, + /// } + /// + /// App::new() + /// .insert_non_send_resource(MyCounter { counter: 0 }); + /// ``` + pub fn insert_non_send_resource(&mut self, resource: T) -> &mut Self + where + T: 'static, + { + self.world.insert_non_send(resource); + self + } + + /// Initialize a resource in the current [App], if it does not exist yet + /// + /// Adds a resource that implements `Default` or [`FromResources`] trait. + /// If the resource already exists, `init_resource` does nothing. + /// + /// ## Example + /// ``` + /// # use bevy_app::prelude::*; + /// # + /// struct MyCounter { + /// counter: usize, + /// } + /// + /// impl Default for MyCounter { + /// fn default() -> MyCounter { + /// MyCounter { + /// counter: 100 + /// } + /// } + /// } + /// + /// App::new() + /// .init_resource::(); + /// ``` + pub fn init_resource(&mut self) -> &mut Self + where + R: FromWorld + Send + Sync + 'static, + { + // PERF: We could avoid double hashing here, since the `from_resources` call is guaranteed + // not to modify the map. However, we would need to be borrowing resources both + // mutably and immutably, so we would need to be extremely certain this is correct + if !self.world.contains_resource::() { + let resource = R::from_world(&mut self.world); + self.insert_resource(resource); + } + self + } + + pub fn init_non_send_resource(&mut self) -> &mut Self + where + R: FromWorld + 'static, + { + // See perf comment in init_resource + if self.world.get_non_send_resource::().is_none() { + let resource = R::from_world(&mut self.world); + self.world.insert_non_send(resource); + } + self + } + + /// Sets the main runner loop function for this Bevy App + /// + /// Usually the main loop is handled by Bevy integrated plugins ([`WinitPlugin`]), but + /// in some cases one might wish to implement their own main loop. + /// + /// This method sets the main loop function, overwriting a previous runner if any. + /// + /// ## Example + /// ``` + /// # use bevy_app::prelude::*; + /// # + /// fn my_runner(mut app: App) { + /// loop { + /// println!("In main loop"); + /// app.update(); + /// } + /// } + /// + /// App::new() + /// .set_runner(my_runner); + /// ``` + pub fn set_runner(&mut self, run_fn: impl Fn(App) + 'static) -> &mut Self { + self.runner = Box::new(run_fn); + self + } + + /// Adds a single plugin + /// + /// One of Bevy's core principles is modularity. All Bevy engine features are implemented + /// as plugins. This includes internal features like the renderer. + /// + /// Bevy also provides a few sets of default plugins. See [`App::add_plugins`]. + /// + /// ## Example + /// ``` + /// # use bevy_app::prelude::*; + /// # + /// App::new().add_plugin(bevy_log::LogPlugin::default()); + /// ``` + pub fn add_plugin(&mut self, plugin: T) -> &mut Self + where + T: Plugin, + { + debug!("added plugin: {}", plugin.name()); + plugin.build(self); + self + } + + /// Adds a group of plugins + /// + /// Bevy plugins can be grouped into a set of plugins. Bevy provides + /// built-in PluginGroups that provide core engine functionality. + /// + /// The plugin groups available by default are [`DefaultPlugins`] and [`MinimalPlugins`]. + /// + /// ## Example + /// ``` + /// # use bevy_app::{prelude::*, PluginGroupBuilder}; + /// # + /// # // Dummy created to avoid using bevy_internal, which pulls in to many dependencies. + /// # struct MinimalPlugins; + /// # impl PluginGroup for MinimalPlugins { + /// # fn build(&mut self, group: &mut PluginGroupBuilder){;} + /// # } + /// # + /// App::new() + /// .add_plugins(MinimalPlugins); + /// ``` + pub fn add_plugins(&mut self, mut group: T) -> &mut Self { + let mut plugin_group_builder = PluginGroupBuilder::default(); + group.build(&mut plugin_group_builder); + plugin_group_builder.finish(self); + self + } + + /// Adds a group of plugins with an initializer method + /// + /// Can be used to add a group of plugins, where the group is modified + /// before insertion into Bevy application. For example, you can add + /// extra plugins at a specific place in the plugin group, or deactivate + /// specific plugins while keeping the rest. + /// + /// ## Example + /// ``` + /// # use bevy_app::{prelude::*, PluginGroupBuilder}; + /// # + /// # // Dummies created to avoid using bevy_internal which pulls in to many dependencies. + /// # struct DefaultPlugins; + /// # impl PluginGroup for DefaultPlugins { + /// # fn build(&mut self, group: &mut PluginGroupBuilder){ + /// # group.add(bevy_log::LogPlugin::default()); + /// # } + /// # } + /// # + /// # struct MyOwnPlugin; + /// # impl Plugin for MyOwnPlugin { + /// # fn build(&self, app: &mut AppBuilder){;} + /// # } + /// # + /// App::new() + /// .add_plugins_with(DefaultPlugins, |group| { + /// group.add_before::(MyOwnPlugin) + /// }); + /// ``` + pub fn add_plugins_with(&mut self, mut group: T, func: F) -> &mut Self + where + T: PluginGroup, + F: FnOnce(&mut PluginGroupBuilder) -> &mut PluginGroupBuilder, + { + let mut plugin_group_builder = PluginGroupBuilder::default(); + group.build(&mut plugin_group_builder); + func(&mut plugin_group_builder); + plugin_group_builder.finish(self); + self + } + + /// Registers a new component using the given [ComponentDescriptor]. Components do not need to + /// be manually registered. This just provides a way to override default configuration. + /// Attempting to register a component with a type that has already been used by [World] + /// will result in an error. + /// + /// See [World::register_component] + pub fn register_component(&mut self, descriptor: ComponentDescriptor) -> &mut Self { + self.world.register_component(descriptor).unwrap(); + self + } + + #[cfg(feature = "bevy_reflect")] + pub fn register_type(&mut self) -> &mut Self { + { + let registry = self + .world + .get_resource_mut::() + .unwrap(); + registry.write().register::(); + } + self + } + + pub fn add_sub_app( + &mut self, + app: App, + f: impl Fn(&mut World, &mut App) + 'static, + ) -> &mut Self { + self.sub_apps.push(SubApp { + app, + runner: Box::new(f), + }); + self + } + + // TODO: use labels instead of indices + pub fn sub_app_mut(&mut self, index: usize) -> &mut App { + &mut self.sub_apps[index].app + } +} + +fn run_once(mut app: App) { + app.update(); } /// An event that indicates the app should exit. This will fully exit the app process. diff --git a/crates/bevy_app/src/app_builder.rs b/crates/bevy_app/src/app_builder.rs deleted file mode 100644 index 58a2dbdd87c22..0000000000000 --- a/crates/bevy_app/src/app_builder.rs +++ /dev/null @@ -1,539 +0,0 @@ -use crate::{ - app::{App, AppExit}, - plugin::Plugin, - CoreStage, PluginGroup, PluginGroupBuilder, StartupStage, -}; -use bevy_ecs::{ - component::{Component, ComponentDescriptor}, - event::Events, - schedule::{ - RunOnce, Schedule, Stage, StageLabel, State, SystemDescriptor, SystemSet, SystemStage, - }, - system::{IntoExclusiveSystem, IntoSystem}, - world::{FromWorld, World}, -}; -use bevy_utils::tracing::debug; -use std::{fmt::Debug, hash::Hash}; - -/// Configure [App]s using the builder pattern -pub struct AppBuilder { - pub app: App, -} - -impl Default for AppBuilder { - fn default() -> Self { - let mut app_builder = AppBuilder { - app: App::default(), - }; - - #[cfg(feature = "bevy_reflect")] - app_builder.init_resource::(); - - app_builder - .add_default_stages() - .add_event::() - .add_system_to_stage(CoreStage::Last, World::clear_trackers.exclusive_system()); - - #[cfg(feature = "bevy_ci_testing")] - { - crate::ci_testing::setup_app(&mut app_builder); - } - app_builder - } -} - -impl AppBuilder { - pub fn empty() -> AppBuilder { - AppBuilder { - app: App::default(), - } - } - - /// Start the application (through main runner) - /// - /// Runs the application main loop. - /// - /// Usually the main loop is handled by Bevy integrated plugins (`winit`), but - /// but one can also set the runner function through [`AppBuilder::set_runner`]. - /// - /// ## Example - /// ``` - /// # use bevy_app::prelude::*; - /// # - /// App::build() - /// // all required plugin insertions, systems, etc inserted here - /// // finally, call: - /// .run(); - /// ``` - pub fn run(&mut self) { - let app = std::mem::take(&mut self.app); - app.run(); - } - - pub fn world(&mut self) -> &World { - &self.app.world - } - - pub fn world_mut(&mut self) -> &mut World { - &mut self.app.world - } - - pub fn set_world(&mut self, world: World) -> &mut Self { - self.app.world = world; - self - } - - pub fn add_stage(&mut self, label: impl StageLabel, stage: S) -> &mut Self { - self.app.schedule.add_stage(label, stage); - self - } - - pub fn add_stage_after( - &mut self, - target: impl StageLabel, - label: impl StageLabel, - stage: S, - ) -> &mut Self { - self.app.schedule.add_stage_after(target, label, stage); - self - } - - pub fn add_stage_before( - &mut self, - target: impl StageLabel, - label: impl StageLabel, - stage: S, - ) -> &mut Self { - self.app.schedule.add_stage_before(target, label, stage); - self - } - - pub fn add_startup_stage(&mut self, label: impl StageLabel, stage: S) -> &mut Self { - self.app - .schedule - .stage(CoreStage::Startup, |schedule: &mut Schedule| { - schedule.add_stage(label, stage) - }); - self - } - - pub fn add_startup_stage_after( - &mut self, - target: impl StageLabel, - label: impl StageLabel, - stage: S, - ) -> &mut Self { - self.app - .schedule - .stage(CoreStage::Startup, |schedule: &mut Schedule| { - schedule.add_stage_after(target, label, stage) - }); - self - } - - pub fn add_startup_stage_before( - &mut self, - target: impl StageLabel, - label: impl StageLabel, - stage: S, - ) -> &mut Self { - self.app - .schedule - .stage(CoreStage::Startup, |schedule: &mut Schedule| { - schedule.add_stage_before(target, label, stage) - }); - self - } - - pub fn stage &mut T>( - &mut self, - label: impl StageLabel, - func: F, - ) -> &mut Self { - self.app.schedule.stage(label, func); - self - } - - /// Adds a system that runs every time `app.update()` is called by the runner - /// - /// Systems are the main building block in the Bevy ECS app model. You can define - /// normal rust functions, and call `.system()` to make them be Bevy systems. - /// - /// System functions can have parameters, through which one can query and - /// mutate Bevy ECS states. - /// See [The Bevy Book](https://bevyengine.org/learn/book/introduction/) for more information. - /// - /// Systems are run in parallel, and the execution order is not deterministic. - /// If you want more fine-grained control for order, see [`AppBuilder::add_system_to_stage`]. - /// - /// For adding a system that runs only at app startup, see [`AppBuilder::add_startup_system`]. - /// - /// ## Example - /// ``` - /// # use bevy_app::prelude::*; - /// # use bevy_ecs::prelude::*; - /// # - /// fn my_system(_commands: Commands) { - /// println!("My system, triggered once per frame"); - /// } - /// - /// App::build() - /// .add_system(my_system.system()); - /// ``` - pub fn add_system(&mut self, system: impl Into) -> &mut Self { - self.add_system_to_stage(CoreStage::Update, system) - } - - pub fn add_system_set(&mut self, system_set: SystemSet) -> &mut Self { - self.add_system_set_to_stage(CoreStage::Update, system_set) - } - - pub fn add_system_to_stage( - &mut self, - stage_label: impl StageLabel, - system: impl Into, - ) -> &mut Self { - self.app.schedule.add_system_to_stage(stage_label, system); - self - } - - pub fn add_system_set_to_stage( - &mut self, - stage_label: impl StageLabel, - system_set: SystemSet, - ) -> &mut Self { - self.app - .schedule - .add_system_set_to_stage(stage_label, system_set); - self - } - - /// Adds a system that is run once at application startup - /// - /// Startup systems run exactly once BEFORE all other systems. These are generally used for - /// app initialization code (ex: adding entities and resources). - /// - /// * For adding a system that runs for every frame, see [`AppBuilder::add_system`]. - /// * For adding a system to specific stage, see [`AppBuilder::add_system_to_stage`]. - /// - /// ## Example - /// ``` - /// # use bevy_app::prelude::*; - /// # use bevy_ecs::prelude::*; - /// # - /// fn my_startup_system(_commands: Commands) { - /// println!("My startup system"); - /// } - /// - /// App::build() - /// .add_startup_system(my_startup_system.system()); - /// ``` - pub fn add_startup_system(&mut self, system: impl Into) -> &mut Self { - self.add_startup_system_to_stage(StartupStage::Startup, system) - } - - pub fn add_startup_system_to_stage( - &mut self, - stage_label: impl StageLabel, - system: impl Into, - ) -> &mut Self { - self.app - .schedule - .stage(CoreStage::Startup, |schedule: &mut Schedule| { - schedule.add_system_to_stage(stage_label, system) - }); - self - } - - /// Adds a new [State] with the given `initial` value. - /// This inserts a new `State` resource and adds a new "driver" to [CoreStage::Update]. - /// Each stage that uses `State` for system run criteria needs a driver. If you need to use - /// your state in a different stage, consider using [Self::add_state_to_stage] or manually - /// adding [State::get_driver] to additional stages you need it in. - pub fn add_state(&mut self, initial: T) -> &mut Self - where - T: Component + Debug + Clone + Eq + Hash, - { - self.add_state_to_stage(CoreStage::Update, initial) - } - - /// Adds a new [State] with the given `initial` value. - /// This inserts a new `State` resource and adds a new "driver" to the given stage. - /// Each stage that uses `State` for system run criteria needs a driver. If you need to use - /// your state in more than one stage, consider manually adding [State::get_driver] to the - /// stages you need it in. - pub fn add_state_to_stage(&mut self, stage: impl StageLabel, initial: T) -> &mut Self - where - T: Component + Debug + Clone + Eq + Hash, - { - self.insert_resource(State::new(initial)) - .add_system_set_to_stage(stage, State::::get_driver()) - } - - pub fn add_default_stages(&mut self) -> &mut Self { - self.add_stage(CoreStage::First, SystemStage::parallel()) - .add_stage( - CoreStage::Startup, - Schedule::default() - .with_run_criteria(RunOnce::default()) - .with_stage(StartupStage::PreStartup, SystemStage::parallel()) - .with_stage(StartupStage::Startup, SystemStage::parallel()) - .with_stage(StartupStage::PostStartup, SystemStage::parallel()), - ) - .add_stage(CoreStage::PreUpdate, SystemStage::parallel()) - .add_stage(CoreStage::Update, SystemStage::parallel()) - .add_stage(CoreStage::PostUpdate, SystemStage::parallel()) - .add_stage(CoreStage::Last, SystemStage::parallel()) - } - - /// Setup the application to manage events of type `T`. - /// - /// This is done by adding a `Resource` of type `Events::`, - /// and inserting a `Events::::update_system` system into `CoreStage::First`. - pub fn add_event(&mut self) -> &mut Self - where - T: Component, - { - self.insert_resource(Events::::default()) - .add_system_to_stage(CoreStage::First, Events::::update_system.system()) - } - - /// Inserts a resource to the current [App] and overwrites any resource previously added of the same type. - /// - /// A resource in Bevy represents globally unique data. Resources must be added to Bevy Apps - /// before using them. This happens with [`AppBuilder::insert_resource`]. - /// - /// See also `init_resource` for resources that implement `Default` or [`FromResources`]. - /// - /// ## Example - /// ``` - /// # use bevy_app::prelude::*; - /// # - /// struct MyCounter { - /// counter: usize, - /// } - /// - /// App::build() - /// .insert_resource(MyCounter { counter: 0 }); - /// ``` - pub fn insert_resource(&mut self, resource: T) -> &mut Self - where - T: Component, - { - self.app.world.insert_resource(resource); - self - } - - /// Inserts a non-send resource to the app - /// - /// You usually want to use `insert_resource`, but there are some special cases when a resource must - /// be non-send. - /// - /// ## Example - /// ``` - /// # use bevy_app::prelude::*; - /// # - /// struct MyCounter { - /// counter: usize, - /// } - /// - /// App::build() - /// .insert_non_send_resource(MyCounter { counter: 0 }); - /// ``` - pub fn insert_non_send_resource(&mut self, resource: T) -> &mut Self - where - T: 'static, - { - self.app.world.insert_non_send(resource); - self - } - - /// Initialize a resource in the current [App], if it does not exist yet - /// - /// Adds a resource that implements `Default` or [`FromResources`] trait. - /// If the resource already exists, `init_resource` does nothing. - /// - /// ## Example - /// ``` - /// # use bevy_app::prelude::*; - /// # - /// struct MyCounter { - /// counter: usize, - /// } - /// - /// impl Default for MyCounter { - /// fn default() -> MyCounter { - /// MyCounter { - /// counter: 100 - /// } - /// } - /// } - /// - /// App::build() - /// .init_resource::(); - /// ``` - pub fn init_resource(&mut self) -> &mut Self - where - R: FromWorld + Send + Sync + 'static, - { - // PERF: We could avoid double hashing here, since the `from_resources` call is guaranteed - // not to modify the map. However, we would need to be borrowing resources both - // mutably and immutably, so we would need to be extremely certain this is correct - if !self.world_mut().contains_resource::() { - let resource = R::from_world(self.world_mut()); - self.insert_resource(resource); - } - self - } - - pub fn init_non_send_resource(&mut self) -> &mut Self - where - R: FromWorld + 'static, - { - // See perf comment in init_resource - if self.app.world.get_non_send_resource::().is_none() { - let resource = R::from_world(self.world_mut()); - self.app.world.insert_non_send(resource); - } - self - } - - /// Sets the main runner loop function for this Bevy App - /// - /// Usually the main loop is handled by Bevy integrated plugins ([`WinitPlugin`]), but - /// in some cases one might wish to implement their own main loop. - /// - /// This method sets the main loop function, overwriting a previous runner if any. - /// - /// ## Example - /// ``` - /// # use bevy_app::prelude::*; - /// # - /// fn my_runner(mut app: App) { - /// loop { - /// println!("In main loop"); - /// app.update(); - /// } - /// } - /// - /// App::build() - /// .set_runner(my_runner); - /// ``` - pub fn set_runner(&mut self, run_fn: impl Fn(App) + 'static) -> &mut Self { - self.app.runner = Box::new(run_fn); - self - } - - /// Adds a single plugin - /// - /// One of Bevy's core principles is modularity. All Bevy engine features are implemented - /// as plugins. This includes internal features like the renderer. - /// - /// Bevy also provides a few sets of default plugins. See [`AppBuilder::add_plugins`]. - /// - /// ## Example - /// ``` - /// # use bevy_app::prelude::*; - /// # - /// App::build().add_plugin(bevy_log::LogPlugin::default()); - /// ``` - pub fn add_plugin(&mut self, plugin: T) -> &mut Self - where - T: Plugin, - { - debug!("added plugin: {}", plugin.name()); - plugin.build(self); - self - } - - /// Adds a group of plugins - /// - /// Bevy plugins can be grouped into a set of plugins. Bevy provides - /// built-in PluginGroups that provide core engine functionality. - /// - /// The plugin groups available by default are [`DefaultPlugins`] and [`MinimalPlugins`]. - /// - /// ## Example - /// ``` - /// # use bevy_app::{prelude::*, PluginGroupBuilder}; - /// # - /// # // Dummy created to avoid using bevy_internal, which pulls in to many dependencies. - /// # struct MinimalPlugins; - /// # impl PluginGroup for MinimalPlugins { - /// # fn build(&mut self, group: &mut PluginGroupBuilder){;} - /// # } - /// # - /// App::build() - /// .add_plugins(MinimalPlugins); - /// ``` - pub fn add_plugins(&mut self, mut group: T) -> &mut Self { - let mut plugin_group_builder = PluginGroupBuilder::default(); - group.build(&mut plugin_group_builder); - plugin_group_builder.finish(self); - self - } - - /// Adds a group of plugins with an initializer method - /// - /// Can be used to add a group of plugins, where the group is modified - /// before insertion into Bevy application. For example, you can add - /// extra plugins at a specific place in the plugin group, or deactivate - /// specific plugins while keeping the rest. - /// - /// ## Example - /// ``` - /// # use bevy_app::{prelude::*, PluginGroupBuilder}; - /// # - /// # // Dummies created to avoid using bevy_internal which pulls in to many dependencies. - /// # struct DefaultPlugins; - /// # impl PluginGroup for DefaultPlugins { - /// # fn build(&mut self, group: &mut PluginGroupBuilder){ - /// # group.add(bevy_log::LogPlugin::default()); - /// # } - /// # } - /// # - /// # struct MyOwnPlugin; - /// # impl Plugin for MyOwnPlugin { - /// # fn build(&self, app: &mut AppBuilder){;} - /// # } - /// # - /// App::build() - /// .add_plugins_with(DefaultPlugins, |group| { - /// group.add_before::(MyOwnPlugin) - /// }); - /// ``` - pub fn add_plugins_with(&mut self, mut group: T, func: F) -> &mut Self - where - T: PluginGroup, - F: FnOnce(&mut PluginGroupBuilder) -> &mut PluginGroupBuilder, - { - let mut plugin_group_builder = PluginGroupBuilder::default(); - group.build(&mut plugin_group_builder); - func(&mut plugin_group_builder); - plugin_group_builder.finish(self); - self - } - - /// Registers a new component using the given [ComponentDescriptor]. Components do not need to - /// be manually registered. This just provides a way to override default configuration. - /// Attempting to register a component with a type that has already been used by [World] - /// will result in an error. - /// - /// See [World::register_component] - pub fn register_component(&mut self, descriptor: ComponentDescriptor) -> &mut Self { - self.world_mut().register_component(descriptor).unwrap(); - self - } - - #[cfg(feature = "bevy_reflect")] - pub fn register_type(&mut self) -> &mut Self { - { - let registry = self - .world_mut() - .get_resource_mut::() - .unwrap(); - registry.write().register::(); - } - self - } -} diff --git a/crates/bevy_app/src/ci_testing.rs b/crates/bevy_app/src/ci_testing.rs index 21e22bec04e9a..dc8865a166696 100644 --- a/crates/bevy_app/src/ci_testing.rs +++ b/crates/bevy_app/src/ci_testing.rs @@ -1,7 +1,6 @@ -use serde::Deserialize; - -use crate::{app::AppExit, AppBuilder}; +use crate::app::{App, AppExit}; use bevy_ecs::system::IntoSystem; +use serde::Deserialize; /// Configuration for automated testing on CI #[derive(Deserialize)] @@ -23,16 +22,15 @@ fn ci_testing_exit_after( *current_frame += 1; } -pub(crate) fn setup_app(app_builder: &mut AppBuilder) -> &mut AppBuilder { +pub(crate) fn setup_app(app: &mut App) -> &mut App { let filename = std::env::var("CI_TESTING_CONFIG").unwrap_or_else(|_| "ci_testing_config.ron".to_string()); let config: CiTestingConfig = ron::from_str( &std::fs::read_to_string(filename).expect("error reading CI testing configuration file"), ) .expect("error deserializing CI testing configuration file"); - app_builder - .insert_resource(config) + app.insert_resource(config) .add_system(ci_testing_exit_after.system()); - app_builder + app } diff --git a/crates/bevy_app/src/lib.rs b/crates/bevy_app/src/lib.rs index e5cd52fd6e7cf..7349ce86b1055 100644 --- a/crates/bevy_app/src/lib.rs +++ b/crates/bevy_app/src/lib.rs @@ -1,5 +1,4 @@ mod app; -mod app_builder; mod plugin; mod plugin_group; mod schedule_runner; @@ -8,7 +7,6 @@ mod schedule_runner; mod ci_testing; pub use app::*; -pub use app_builder::*; pub use bevy_derive::DynamicPlugin; pub use bevy_ecs::event::*; pub use plugin::*; @@ -17,10 +15,7 @@ pub use schedule_runner::*; pub mod prelude { #[doc(hidden)] - pub use crate::{ - app::App, app_builder::AppBuilder, CoreStage, DynamicPlugin, Plugin, PluginGroup, - StartupStage, - }; + pub use crate::{app::App, CoreStage, DynamicPlugin, Plugin, PluginGroup, StartupStage}; } use bevy_ecs::schedule::StageLabel; diff --git a/crates/bevy_app/src/plugin.rs b/crates/bevy_app/src/plugin.rs index ea5ef0021a4d9..38115af2ced49 100644 --- a/crates/bevy_app/src/plugin.rs +++ b/crates/bevy_app/src/plugin.rs @@ -1,12 +1,12 @@ -use crate::AppBuilder; +use crate::App; use std::any::Any; /// A collection of Bevy App logic and configuration /// -/// Plugins use [AppBuilder] to configure an [App](crate::App). When an [App](crate::App) registers +/// Plugins configure an [App](crate::App). When an [App](crate::App) registers /// a plugin, the plugin's [Plugin::build] function is run. pub trait Plugin: Any + Send + Sync { - fn build(&self, app: &mut AppBuilder); + fn build(&self, app: &mut App); fn name(&self) -> &str { std::any::type_name::() } diff --git a/crates/bevy_app/src/plugin_group.rs b/crates/bevy_app/src/plugin_group.rs index 074a2d3083cd2..6bb41483bba89 100644 --- a/crates/bevy_app/src/plugin_group.rs +++ b/crates/bevy_app/src/plugin_group.rs @@ -1,4 +1,4 @@ -use crate::{AppBuilder, Plugin}; +use crate::{App, Plugin}; use bevy_utils::{tracing::debug, HashMap}; use std::any::TypeId; @@ -96,7 +96,7 @@ impl PluginGroupBuilder { self } - pub fn finish(self, app: &mut AppBuilder) { + pub fn finish(self, app: &mut App) { for ty in self.order.iter() { if let Some(entry) = self.plugins.get(ty) { if entry.enabled { diff --git a/crates/bevy_app/src/schedule_runner.rs b/crates/bevy_app/src/schedule_runner.rs index 7b27cc43c8e32..9c80d237e6def 100644 --- a/crates/bevy_app/src/schedule_runner.rs +++ b/crates/bevy_app/src/schedule_runner.rs @@ -1,5 +1,8 @@ -use super::{App, AppBuilder}; -use crate::{app::AppExit, plugin::Plugin, ManualEventReader}; +use crate::{ + app::{App, AppExit}, + plugin::Plugin, + ManualEventReader, +}; use bevy_ecs::event::Events; use bevy_utils::{Duration, Instant}; @@ -48,9 +51,9 @@ impl ScheduleRunnerSettings { pub struct ScheduleRunnerPlugin {} impl Plugin for ScheduleRunnerPlugin { - fn build(&self, app: &mut AppBuilder) { + fn build(&self, app: &mut App) { let settings = app - .world_mut() + .world .get_resource_or_insert_with(ScheduleRunnerSettings::default) .to_owned(); app.set_runner(move |mut app: App| { diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 299be3e3b9530..34da94aa50f58 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -2,7 +2,7 @@ use crate::{ update_asset_storage_system, Asset, AssetLoader, AssetServer, AssetStage, Handle, HandleId, RefChange, }; -use bevy_app::{AppBuilder, EventWriter, Events}; +use bevy_app::{App, EventWriter, Events}; use bevy_ecs::{ system::{IntoSystem, ResMut}, world::FromWorld, @@ -206,13 +206,13 @@ pub trait AddAsset { T: AssetLoader; } -impl AddAsset for AppBuilder { +impl AddAsset for App { fn add_asset(&mut self) -> &mut Self where T: Asset, { let assets = { - let asset_server = self.world().get_resource::().unwrap(); + let asset_server = self.world.get_resource::().unwrap(); asset_server.register_asset_type::() }; @@ -233,7 +233,7 @@ impl AddAsset for AppBuilder { where T: AssetLoader + FromWorld, { - let result = T::from_world(self.world_mut()); + let result = T::from_world(&mut self.world); self.add_asset_loader(result) } @@ -241,7 +241,7 @@ impl AddAsset for AppBuilder { where T: AssetLoader, { - self.world_mut() + self.world .get_resource_mut::() .expect("AssetServer does not exist. Consider adding it as a resource.") .add_loader(loader); diff --git a/crates/bevy_asset/src/diagnostic/asset_count_diagnostics_plugin.rs b/crates/bevy_asset/src/diagnostic/asset_count_diagnostics_plugin.rs index 4dae5198d85b1..a915d8fe88ef6 100644 --- a/crates/bevy_asset/src/diagnostic/asset_count_diagnostics_plugin.rs +++ b/crates/bevy_asset/src/diagnostic/asset_count_diagnostics_plugin.rs @@ -17,7 +17,7 @@ impl Default for AssetCountDiagnosticsPlugin { } impl Plugin for AssetCountDiagnosticsPlugin { - fn build(&self, app: &mut AppBuilder) { + fn build(&self, app: &mut App) { app.add_startup_system(Self::setup_system.system()) .add_system(Self::diagnostic_system.system()); } diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index 62808e38a42c2..12a3149872d4f 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -26,7 +26,7 @@ pub use io::*; pub use loader::*; pub use path::*; -use bevy_app::{prelude::Plugin, AppBuilder}; +use bevy_app::{prelude::Plugin, App}; use bevy_ecs::{ schedule::{StageLabel, SystemStage}, system::IntoSystem, @@ -61,9 +61,9 @@ impl Default for AssetServerSettings { /// /// This is useful when providing a custom `AssetIo` instance that needs to /// delegate to the default `AssetIo` for the platform. -pub fn create_platform_default_asset_io(app: &mut AppBuilder) -> Box { +pub fn create_platform_default_asset_io(app: &mut App) -> Box { let settings = app - .world_mut() + .world .get_resource_or_insert_with(AssetServerSettings::default); #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))] @@ -77,10 +77,10 @@ pub fn create_platform_default_asset_io(app: &mut AppBuilder) -> Box().is_none() { + fn build(&self, app: &mut App) { + if app.world.get_resource::().is_none() { let task_pool = app - .world() + .world .get_resource::() .expect("`IoTaskPool` resource not found.") .0 diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index eb9f148460ed2..5f44d68f9f40b 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -20,7 +20,7 @@ use bevy_ecs::system::IntoExclusiveSystem; pub struct AudioPlugin; impl Plugin for AudioPlugin { - fn build(&self, app: &mut AppBuilder) { + fn build(&self, app: &mut App) { app.init_non_send_resource::>() .add_asset::() .init_resource::>() diff --git a/crates/bevy_core/src/lib.rs b/crates/bevy_core/src/lib.rs index 75fd87adb5ebb..50ab218cd61f1 100644 --- a/crates/bevy_core/src/lib.rs +++ b/crates/bevy_core/src/lib.rs @@ -38,13 +38,13 @@ pub enum CoreSystem { } impl Plugin for CorePlugin { - fn build(&self, app: &mut AppBuilder) { + fn build(&self, app: &mut App) { // Setup the default bevy task pools - app.world_mut() + app.world .get_resource::() .cloned() .unwrap_or_else(DefaultTaskPoolOptions::default) - .create_default_pools(app.world_mut()); + .create_default_pools(&mut app.world); app.init_resource::