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_set(&mut self, system_set: SystemSet) -> &mut Self { self.add_startup_system_set_to_stage(StartupStage::Startup, system_set) } 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 } pub fn add_startup_system_set_to_stage( &mut self, stage_label: impl StageLabel, system_set: SystemSet, ) -> &mut Self { self.app .schedule .stage(CoreStage::Startup, |schedule: &mut Schedule| { schedule.add_system_set_to_stage(stage_label, system_set) }); 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 } }