use crate::{ First, Main, MainSchedulePlugin, PlaceholderPlugin, Plugin, Plugins, PluginsState, SubApp, SubApps, }; pub use bevy_derive::AppLabel; use bevy_ecs::{ component::RequiredComponentsError, event::{event_update_system, EventCursor}, intern::Interned, prelude::*, schedule::{ScheduleBuildSettings, ScheduleLabel}, system::{IntoObserverSystem, SystemId, SystemInput}, }; #[cfg(feature = "trace")] use bevy_utils::tracing::info_span; use bevy_utils::{tracing::debug, HashMap}; use core::{fmt::Debug, num::NonZero, panic::AssertUnwindSafe}; use derive_more::derive::{Display, Error}; use std::{ panic::{catch_unwind, resume_unwind}, process::{ExitCode, Termination}, }; bevy_ecs::define_label!( /// A strongly-typed class of labels used to identify an [`App`]. AppLabel, APP_LABEL_INTERNER ); pub use bevy_ecs::label::DynEq; /// A shorthand for `Interned`. pub type InternedAppLabel = Interned; #[derive(Debug, Error, Display)] pub(crate) enum AppError { #[display("duplicate plugin {plugin_name:?}")] DuplicatePlugin { plugin_name: String }, } /// [`App`] is the primary API for writing user applications. It automates the setup of a /// [standard lifecycle](Main) and provides interface glue for [plugins](`Plugin`). /// /// A single [`App`] can contain multiple [`SubApp`] instances, but [`App`] methods only affect /// the "main" one. To access a particular [`SubApp`], use [`get_sub_app`](App::get_sub_app) /// or [`get_sub_app_mut`](App::get_sub_app_mut). /// /// /// # Examples /// /// Here is a simple "Hello World" Bevy app: /// /// ``` /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # /// fn main() { /// App::new() /// .add_systems(Update, hello_world_system) /// .run(); /// } /// /// fn hello_world_system() { /// println!("hello world"); /// } /// ``` pub struct App { pub(crate) sub_apps: SubApps, /// The function that will manage the app's lifecycle. /// /// Bevy provides the [`WinitPlugin`] and [`ScheduleRunnerPlugin`] for windowed and headless /// applications, respectively. /// /// [`WinitPlugin`]: https://docs.rs/bevy/latest/bevy/winit/struct.WinitPlugin.html /// [`ScheduleRunnerPlugin`]: https://docs.rs/bevy/latest/bevy/app/struct.ScheduleRunnerPlugin.html pub(crate) runner: RunnerFn, } impl Debug for App { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "App {{ sub_apps: ")?; f.debug_map() .entries(self.sub_apps.sub_apps.iter()) .finish()?; write!(f, "}}") } } impl Default for App { fn default() -> Self { let mut app = App::empty(); app.sub_apps.main.update_schedule = Some(Main.intern()); #[cfg(feature = "bevy_reflect")] app.init_resource::(); #[cfg(feature = "reflect_functions")] app.init_resource::(); app.add_plugins(MainSchedulePlugin); app.add_systems( First, event_update_system .in_set(bevy_ecs::event::EventUpdates) .run_if(bevy_ecs::event::event_update_condition), ); app.add_event::(); app } } impl App { /// Creates a new [`App`] with some default structure to enable core engine features. /// This is the preferred constructor for most use cases. pub fn new() -> App { App::default() } /// Creates a new empty [`App`] with minimal default configuration. /// /// Use this constructor if you want to customize scheduling, exit handling, cleanup, etc. pub fn empty() -> App { Self { sub_apps: SubApps { main: SubApp::new(), sub_apps: HashMap::new(), }, runner: Box::new(run_once), } } /// Runs the default schedules of all sub-apps (starting with the "main" app) once. pub fn update(&mut self) { if self.is_building_plugins() { panic!("App::update() was called while a plugin was building."); } self.sub_apps.update(); } /// Runs the [`App`] by calling its [runner](Self::set_runner). /// /// This will (re)build the [`App`] first. For general usage, see the example on the item /// level documentation. /// /// # Caveats /// /// Calls to [`App::run()`] will never return on iOS and Web. /// /// Headless apps can generally expect this method to return control to the caller when /// it completes, but that is not the case for windowed apps. Windowed apps are typically /// driven by an event loop and some platforms expect the program to terminate when the /// event loop ends. /// /// By default, *Bevy* uses the `winit` crate for window creation. /// /// # Panics /// /// Panics if not all plugins have been built. pub fn run(&mut self) -> AppExit { #[cfg(feature = "trace")] let _bevy_app_run_span = info_span!("bevy_app").entered(); if self.is_building_plugins() { panic!("App::run() was called while a plugin was building."); } let runner = core::mem::replace(&mut self.runner, Box::new(run_once)); let app = core::mem::replace(self, App::empty()); (runner)(app) } /// Sets the function that will be called when the app is run. /// /// The runner function `f` is called only once by [`App::run`]. If the /// presence of a main loop in the app is desired, it is the responsibility of the runner /// function to provide it. /// /// The runner function is usually not set manually, but by Bevy integrated plugins /// (e.g. `WinitPlugin`). /// /// # Examples /// /// ``` /// # use bevy_app::prelude::*; /// # /// fn my_runner(mut app: App) -> AppExit { /// loop { /// println!("In main loop"); /// app.update(); /// if let Some(exit) = app.should_exit() { /// return exit; /// } /// } /// } /// /// App::new() /// .set_runner(my_runner); /// ``` pub fn set_runner(&mut self, f: impl FnOnce(App) -> AppExit + 'static) -> &mut Self { self.runner = Box::new(f); self } /// Returns the state of all plugins. This is usually called by the event loop, but can be /// useful for situations where you want to use [`App::update`]. // TODO: &mut self -> &self #[inline] pub fn plugins_state(&mut self) -> PluginsState { let mut overall_plugins_state = match self.main_mut().plugins_state { PluginsState::Adding => { let mut state = PluginsState::Ready; let plugins = core::mem::take(&mut self.main_mut().plugin_registry); for plugin in &plugins { // plugins installed to main need to see all sub-apps if !plugin.ready(self) { state = PluginsState::Adding; break; } } self.main_mut().plugin_registry = plugins; state } state => state, }; // overall state is the earliest state of any sub-app self.sub_apps.iter_mut().skip(1).for_each(|s| { overall_plugins_state = overall_plugins_state.min(s.plugins_state()); }); overall_plugins_state } /// Runs [`Plugin::finish`] for each plugin. This is usually called by the event loop once all /// plugins are ready, but can be useful for situations where you want to use [`App::update`]. pub fn finish(&mut self) { // plugins installed to main should see all sub-apps let plugins = core::mem::take(&mut self.main_mut().plugin_registry); for plugin in &plugins { plugin.finish(self); } let main = self.main_mut(); main.plugin_registry = plugins; main.plugins_state = PluginsState::Finished; self.sub_apps.iter_mut().skip(1).for_each(SubApp::finish); } /// Runs [`Plugin::cleanup`] for each plugin. This is usually called by the event loop after /// [`App::finish`], but can be useful for situations where you want to use [`App::update`]. pub fn cleanup(&mut self) { // plugins installed to main should see all sub-apps let plugins = core::mem::take(&mut self.main_mut().plugin_registry); for plugin in &plugins { plugin.cleanup(self); } let main = self.main_mut(); main.plugin_registry = plugins; main.plugins_state = PluginsState::Cleaned; self.sub_apps.iter_mut().skip(1).for_each(SubApp::cleanup); } /// Returns `true` if any of the sub-apps are building plugins. pub(crate) fn is_building_plugins(&self) -> bool { self.sub_apps.iter().any(SubApp::is_building_plugins) } /// Adds one or more systems to the given schedule in this app's [`Schedules`]. /// /// # Examples /// /// ``` /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # /// # let mut app = App::new(); /// # fn system_a() {} /// # fn system_b() {} /// # fn system_c() {} /// # fn should_run() -> bool { true } /// # /// app.add_systems(Update, (system_a, system_b, system_c)); /// app.add_systems(Update, (system_a, system_b).run_if(should_run)); /// ``` pub fn add_systems( &mut self, schedule: impl ScheduleLabel, systems: impl IntoSystemConfigs, ) -> &mut Self { self.main_mut().add_systems(schedule, systems); self } /// Registers a system and returns a [`SystemId`] so it can later be called by [`World::run_system`]. /// /// It's possible to register the same systems more than once, they'll be stored separately. /// /// This is different from adding systems to a [`Schedule`] with [`App::add_systems`], /// because the [`SystemId`] that is returned can be used anywhere in the [`World`] to run the associated system. /// This allows for running systems in a push-based fashion. /// Using a [`Schedule`] is still preferred for most cases /// due to its better performance and ability to run non-conflicting systems simultaneously. pub fn register_system( &mut self, system: impl IntoSystem + 'static, ) -> SystemId where I: SystemInput + 'static, O: 'static, { self.main_mut().register_system(system) } /// Configures a collection of system sets in the provided schedule, adding any sets that do not exist. #[track_caller] pub fn configure_sets( &mut self, schedule: impl ScheduleLabel, sets: impl IntoSystemSetConfigs, ) -> &mut Self { self.main_mut().configure_sets(schedule, sets); self } /// Initializes `T` event handling by inserting an event queue resource ([`Events::`]) /// and scheduling an [`event_update_system`] in [`First`]. /// /// See [`Events`] for information on how to define events. /// /// # Examples /// /// ``` /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # /// # #[derive(Event)] /// # struct MyEvent; /// # let mut app = App::new(); /// # /// app.add_event::(); /// ``` pub fn add_event(&mut self) -> &mut Self where T: Event, { self.main_mut().add_event::(); self } /// Inserts the [`Resource`] into the app, overwriting any existing resource of the same type. /// /// There is also an [`init_resource`](Self::init_resource) for resources that have /// [`Default`] or [`FromWorld`] implementations. /// /// # Examples /// /// ``` /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # /// #[derive(Resource)] /// struct MyCounter { /// counter: usize, /// } /// /// App::new() /// .insert_resource(MyCounter { counter: 0 }); /// ``` pub fn insert_resource(&mut self, resource: R) -> &mut Self { self.main_mut().insert_resource(resource); self } /// Inserts the [`Resource`], initialized with its default value, into the app, /// if there is no existing instance of `R`. /// /// `R` must implement [`FromWorld`]. /// If `R` implements [`Default`], [`FromWorld`] will be automatically implemented and /// initialize the [`Resource`] with [`Default::default`]. /// /// # Examples /// /// ``` /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # /// #[derive(Resource)] /// 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 { self.main_mut().init_resource::(); self } /// Inserts the [`!Send`](Send) resource into the app, overwriting any existing resource /// of the same type. /// /// There is also an [`init_non_send_resource`](Self::init_non_send_resource) for /// resources that implement [`Default`] /// /// # Examples /// /// ``` /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # /// struct MyCounter { /// counter: usize, /// } /// /// App::new() /// .insert_non_send_resource(MyCounter { counter: 0 }); /// ``` pub fn insert_non_send_resource(&mut self, resource: R) -> &mut Self { self.world_mut().insert_non_send_resource(resource); self } /// Inserts the [`!Send`](Send) resource into the app if there is no existing instance of `R`. /// /// `R` must implement [`FromWorld`]. /// If `R` implements [`Default`], [`FromWorld`] will be automatically implemented and /// initialize the [`Resource`] with [`Default::default`]. pub fn init_non_send_resource(&mut self) -> &mut Self { self.world_mut().init_non_send_resource::(); self } pub(crate) fn add_boxed_plugin( &mut self, plugin: Box, ) -> Result<&mut Self, AppError> { debug!("added plugin: {}", plugin.name()); if plugin.is_unique() && self.main_mut().plugin_names.contains(plugin.name()) { Err(AppError::DuplicatePlugin { plugin_name: plugin.name().to_string(), })?; } // Reserve position in the plugin registry. If the plugin adds more plugins, // they'll all end up in insertion order. let index = self.main().plugin_registry.len(); self.main_mut() .plugin_registry .push(Box::new(PlaceholderPlugin)); self.main_mut().plugin_build_depth += 1; let result = catch_unwind(AssertUnwindSafe(|| plugin.build(self))); self.main_mut() .plugin_names .insert(plugin.name().to_string()); self.main_mut().plugin_build_depth -= 1; if let Err(payload) = result { resume_unwind(payload); } self.main_mut().plugin_registry[index] = plugin; Ok(self) } /// Returns `true` if the [`Plugin`] has already been added. pub fn is_plugin_added(&self) -> bool where T: Plugin, { self.main().is_plugin_added::() } /// Returns a vector of references to all plugins of type `T` that have been added. /// /// This can be used to read the settings of any existing plugins. /// This vector will be empty if no plugins of that type have been added. /// If multiple copies of the same plugin are added to the [`App`], they will be listed in insertion order in this vector. /// /// ``` /// # use bevy_app::prelude::*; /// # #[derive(Default)] /// # struct ImagePlugin { /// # default_sampler: bool, /// # } /// # impl Plugin for ImagePlugin { /// # fn build(&self, app: &mut App) {} /// # } /// # let mut app = App::new(); /// # app.add_plugins(ImagePlugin::default()); /// let default_sampler = app.get_added_plugins::()[0].default_sampler; /// ``` pub fn get_added_plugins(&self) -> Vec<&T> where T: Plugin, { self.main().get_added_plugins::() } /// Installs a [`Plugin`] collection. /// /// Bevy prioritizes modularity as a core principle. **All** engine features are implemented /// as plugins, even the complex ones like rendering. /// /// [`Plugin`]s can be grouped into a set by using a [`PluginGroup`]. /// /// There are built-in [`PluginGroup`]s that provide core engine functionality. /// The [`PluginGroup`]s available by default are `DefaultPlugins` and `MinimalPlugins`. /// /// To customize the plugins in the group (reorder, disable a plugin, add a new plugin /// before / after another plugin), call [`build()`](super::PluginGroup::build) on the group, /// which will convert it to a [`PluginGroupBuilder`](crate::PluginGroupBuilder). /// /// You can also specify a group of [`Plugin`]s by using a tuple over [`Plugin`]s and /// [`PluginGroup`]s. See [`Plugins`] for more details. /// /// ## Examples /// ``` /// # use bevy_app::{prelude::*, PluginGroupBuilder, NoopPluginGroup as MinimalPlugins}; /// # /// # // Dummies created to avoid using `bevy_log`, /// # // which pulls in too many dependencies and breaks rust-analyzer /// # pub struct LogPlugin; /// # impl Plugin for LogPlugin { /// # fn build(&self, app: &mut App) {} /// # } /// App::new() /// .add_plugins(MinimalPlugins); /// App::new() /// .add_plugins((MinimalPlugins, LogPlugin)); /// ``` /// /// # Panics /// /// Panics if one of the plugins had already been added to the application. /// /// [`PluginGroup`]:super::PluginGroup #[track_caller] pub fn add_plugins(&mut self, plugins: impl Plugins) -> &mut Self { if matches!( self.plugins_state(), PluginsState::Cleaned | PluginsState::Finished ) { panic!( "Plugins cannot be added after App::cleanup() or App::finish() has been called." ); } plugins.add_to_app(self); self } /// Registers the type `T` in the [`AppTypeRegistry`] resource, /// adding reflect data as specified in the [`Reflect`](bevy_reflect::Reflect) derive: /// ```ignore (No serde "derive" feature) /// #[derive(Component, Serialize, Deserialize, Reflect)] /// #[reflect(Component, Serialize, Deserialize)] // will register ReflectComponent, ReflectSerialize, ReflectDeserialize /// ``` /// /// See [`bevy_reflect::TypeRegistry::register`] for more information. #[cfg(feature = "bevy_reflect")] pub fn register_type(&mut self) -> &mut Self { self.main_mut().register_type::(); self } /// Associates type data `D` with type `T` in the [`AppTypeRegistry`] resource. /// /// Most of the time [`register_type`](Self::register_type) can be used instead to register a /// type you derived [`Reflect`](bevy_reflect::Reflect) for. However, in cases where you want to /// add a piece of type data that was not included in the list of `#[reflect(...)]` type data in /// the derive, or where the type is generic and cannot register e.g. `ReflectSerialize` /// unconditionally without knowing the specific type parameters, this method can be used to /// insert additional type data. /// /// # Example /// ``` /// use bevy_app::App; /// use bevy_reflect::{ReflectSerialize, ReflectDeserialize}; /// /// App::new() /// .register_type::>() /// .register_type_data::, ReflectSerialize>() /// .register_type_data::, ReflectDeserialize>(); /// ``` /// /// See [`bevy_reflect::TypeRegistry::register_type_data`]. #[cfg(feature = "bevy_reflect")] pub fn register_type_data< T: bevy_reflect::Reflect + bevy_reflect::TypePath, D: bevy_reflect::TypeData + bevy_reflect::FromType, >( &mut self, ) -> &mut Self { self.main_mut().register_type_data::(); self } /// Registers the given function into the [`AppFunctionRegistry`] resource. /// /// The given function will internally be stored as a [`DynamicFunction`] /// and mapped according to its [name]. /// /// Because the function must have a name, /// anonymous functions (e.g. `|a: i32, b: i32| { a + b }`) and closures must instead /// be registered using [`register_function_with_name`] or converted to a [`DynamicFunction`] /// and named using [`DynamicFunction::with_name`]. /// Failure to do so will result in a panic. /// /// Only types that implement [`IntoFunction`] may be registered via this method. /// /// See [`FunctionRegistry::register`] for more information. /// /// # Panics /// /// Panics if a function has already been registered with the given name /// or if the function is missing a name (such as when it is an anonymous function). /// /// # Examples /// /// ``` /// use bevy_app::App; /// /// fn add(a: i32, b: i32) -> i32 { /// a + b /// } /// /// App::new().register_function(add); /// ``` /// /// Functions cannot be registered more than once. /// /// ```should_panic /// use bevy_app::App; /// /// fn add(a: i32, b: i32) -> i32 { /// a + b /// } /// /// App::new() /// .register_function(add) /// // Panic! A function has already been registered with the name "my_function" /// .register_function(add); /// ``` /// /// Anonymous functions and closures should be registered using [`register_function_with_name`] or given a name using [`DynamicFunction::with_name`]. /// /// ```should_panic /// use bevy_app::App; /// /// // Panic! Anonymous functions cannot be registered using `register_function` /// App::new().register_function(|a: i32, b: i32| a + b); /// ``` /// /// [`register_function_with_name`]: Self::register_function_with_name /// [`DynamicFunction`]: bevy_reflect::func::DynamicFunction /// [name]: bevy_reflect::func::FunctionInfo::name /// [`DynamicFunction::with_name`]: bevy_reflect::func::DynamicFunction::with_name /// [`IntoFunction`]: bevy_reflect::func::IntoFunction /// [`FunctionRegistry::register`]: bevy_reflect::func::FunctionRegistry::register #[cfg(feature = "reflect_functions")] pub fn register_function(&mut self, function: F) -> &mut Self where F: bevy_reflect::func::IntoFunction<'static, Marker> + 'static, { self.main_mut().register_function(function); self } /// Registers the given function or closure into the [`AppFunctionRegistry`] resource using the given name. /// /// To avoid conflicts, it's recommended to use a unique name for the function. /// This can be achieved by "namespacing" the function with a unique identifier, /// such as the name of your crate. /// /// For example, to register a function, `add`, from a crate, `my_crate`, /// you could use the name, `"my_crate::add"`. /// /// Another approach could be to use the [type name] of the function, /// however, it should be noted that anonymous functions do _not_ have unique type names. /// /// For named functions (e.g. `fn add(a: i32, b: i32) -> i32 { a + b }`) where a custom name is not needed, /// it's recommended to use [`register_function`] instead as the generated name is guaranteed to be unique. /// /// Only types that implement [`IntoFunction`] may be registered via this method. /// /// See [`FunctionRegistry::register_with_name`] for more information. /// /// # Panics /// /// Panics if a function has already been registered with the given name. /// /// # Examples /// /// ``` /// use bevy_app::App; /// /// fn mul(a: i32, b: i32) -> i32 { /// a * b /// } /// /// let div = |a: i32, b: i32| a / b; /// /// App::new() /// // Registering an anonymous function with a unique name /// .register_function_with_name("my_crate::add", |a: i32, b: i32| { /// a + b /// }) /// // Registering an existing function with its type name /// .register_function_with_name(std::any::type_name_of_val(&mul), mul) /// // Registering an existing function with a custom name /// .register_function_with_name("my_crate::mul", mul) /// // Be careful not to register anonymous functions with their type name. /// // This code works but registers the function with a non-unique name like `foo::bar::{{closure}}` /// .register_function_with_name(std::any::type_name_of_val(&div), div); /// ``` /// /// Names must be unique. /// /// ```should_panic /// use bevy_app::App; /// /// fn one() {} /// fn two() {} /// /// App::new() /// .register_function_with_name("my_function", one) /// // Panic! A function has already been registered with the name "my_function" /// .register_function_with_name("my_function", two); /// ``` /// /// [type name]: std::any::type_name /// [`register_function`]: Self::register_function /// [`IntoFunction`]: bevy_reflect::func::IntoFunction /// [`FunctionRegistry::register_with_name`]: bevy_reflect::func::FunctionRegistry::register_with_name #[cfg(feature = "reflect_functions")] pub fn register_function_with_name( &mut self, name: impl Into>, function: F, ) -> &mut Self where F: bevy_reflect::func::IntoFunction<'static, Marker> + 'static, { self.main_mut().register_function_with_name(name, function); self } /// Registers the given component `R` as a [required component] for `T`. /// /// When `T` is added to an entity, `R` and its own required components will also be added /// if `R` was not already provided. The [`Default`] `constructor` will be used for the creation of `R`. /// If a custom constructor is desired, use [`App::register_required_components_with`] instead. /// /// For the non-panicking version, see [`App::try_register_required_components`]. /// /// Note that requirements must currently be registered before `T` is inserted into the world /// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future. /// /// [required component]: Component#required-components /// /// # Panics /// /// Panics if `R` is already a directly required component for `T`, or if `T` has ever been added /// on an entity before the registration. /// /// Indirect requirements through other components are allowed. In those cases, any existing requirements /// will only be overwritten if the new requirement is more specific. /// /// # Example /// /// ``` /// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup}; /// # use bevy_ecs::prelude::*; /// #[derive(Component)] /// struct A; /// /// #[derive(Component, Default, PartialEq, Eq, Debug)] /// struct B(usize); /// /// #[derive(Component, Default, PartialEq, Eq, Debug)] /// struct C(u32); /// /// # let mut app = App::new(); /// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup); /// // Register B as required by A and C as required by B. /// app.register_required_components::(); /// app.register_required_components::(); /// /// fn setup(mut commands: Commands) { /// // This will implicitly also insert B and C with their Default constructors. /// commands.spawn(A); /// } /// /// fn validate(query: Option>) { /// let (a, b, c) = query.unwrap().into_inner(); /// assert_eq!(b, &B(0)); /// assert_eq!(c, &C(0)); /// } /// # app.update(); /// ``` pub fn register_required_components( &mut self, ) -> &mut Self { self.world_mut().register_required_components::(); self } /// Registers the given component `R` as a [required component] for `T`. /// /// When `T` is added to an entity, `R` and its own required components will also be added /// if `R` was not already provided. The given `constructor` will be used for the creation of `R`. /// If a [`Default`] constructor is desired, use [`App::register_required_components`] instead. /// /// For the non-panicking version, see [`App::try_register_required_components_with`]. /// /// Note that requirements must currently be registered before `T` is inserted into the world /// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future. /// /// [required component]: Component#required-components /// /// # Panics /// /// Panics if `R` is already a directly required component for `T`, or if `T` has ever been added /// on an entity before the registration. /// /// Indirect requirements through other components are allowed. In those cases, any existing requirements /// will only be overwritten if the new requirement is more specific. /// /// # Example /// /// ``` /// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup}; /// # use bevy_ecs::prelude::*; /// #[derive(Component)] /// struct A; /// /// #[derive(Component, Default, PartialEq, Eq, Debug)] /// struct B(usize); /// /// #[derive(Component, Default, PartialEq, Eq, Debug)] /// struct C(u32); /// /// # let mut app = App::new(); /// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup); /// // Register B and C as required by A and C as required by B. /// // A requiring C directly will overwrite the indirect requirement through B. /// app.register_required_components::(); /// app.register_required_components_with::(|| C(1)); /// app.register_required_components_with::(|| C(2)); /// /// fn setup(mut commands: Commands) { /// // This will implicitly also insert B with its Default constructor and C /// // with the custom constructor defined by A. /// commands.spawn(A); /// } /// /// fn validate(query: Option>) { /// let (a, b, c) = query.unwrap().into_inner(); /// assert_eq!(b, &B(0)); /// assert_eq!(c, &C(2)); /// } /// # app.update(); /// ``` pub fn register_required_components_with( &mut self, constructor: fn() -> R, ) -> &mut Self { self.world_mut() .register_required_components_with::(constructor); self } /// Tries to register the given component `R` as a [required component] for `T`. /// /// When `T` is added to an entity, `R` and its own required components will also be added /// if `R` was not already provided. The [`Default`] `constructor` will be used for the creation of `R`. /// If a custom constructor is desired, use [`App::register_required_components_with`] instead. /// /// For the panicking version, see [`App::register_required_components`]. /// /// Note that requirements must currently be registered before `T` is inserted into the world /// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future. /// /// [required component]: Component#required-components /// /// # Errors /// /// Returns a [`RequiredComponentsError`] if `R` is already a directly required component for `T`, or if `T` has ever been added /// on an entity before the registration. /// /// Indirect requirements through other components are allowed. In those cases, any existing requirements /// will only be overwritten if the new requirement is more specific. /// /// # Example /// /// ``` /// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup}; /// # use bevy_ecs::prelude::*; /// #[derive(Component)] /// struct A; /// /// #[derive(Component, Default, PartialEq, Eq, Debug)] /// struct B(usize); /// /// #[derive(Component, Default, PartialEq, Eq, Debug)] /// struct C(u32); /// /// # let mut app = App::new(); /// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup); /// // Register B as required by A and C as required by B. /// app.register_required_components::(); /// app.register_required_components::(); /// /// // Duplicate registration! This will fail. /// assert!(app.try_register_required_components::().is_err()); /// /// fn setup(mut commands: Commands) { /// // This will implicitly also insert B and C with their Default constructors. /// commands.spawn(A); /// } /// /// fn validate(query: Option>) { /// let (a, b, c) = query.unwrap().into_inner(); /// assert_eq!(b, &B(0)); /// assert_eq!(c, &C(0)); /// } /// # app.update(); /// ``` pub fn try_register_required_components( &mut self, ) -> Result<(), RequiredComponentsError> { self.world_mut().try_register_required_components::() } /// Tries to register the given component `R` as a [required component] for `T`. /// /// When `T` is added to an entity, `R` and its own required components will also be added /// if `R` was not already provided. The given `constructor` will be used for the creation of `R`. /// If a [`Default`] constructor is desired, use [`App::register_required_components`] instead. /// /// For the panicking version, see [`App::register_required_components_with`]. /// /// Note that requirements must currently be registered before `T` is inserted into the world /// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future. /// /// [required component]: Component#required-components /// /// # Errors /// /// Returns a [`RequiredComponentsError`] if `R` is already a directly required component for `T`, or if `T` has ever been added /// on an entity before the registration. /// /// Indirect requirements through other components are allowed. In those cases, any existing requirements /// will only be overwritten if the new requirement is more specific. /// /// # Example /// /// ``` /// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup}; /// # use bevy_ecs::prelude::*; /// #[derive(Component)] /// struct A; /// /// #[derive(Component, Default, PartialEq, Eq, Debug)] /// struct B(usize); /// /// #[derive(Component, Default, PartialEq, Eq, Debug)] /// struct C(u32); /// /// # let mut app = App::new(); /// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup); /// // Register B and C as required by A and C as required by B. /// // A requiring C directly will overwrite the indirect requirement through B. /// app.register_required_components::(); /// app.register_required_components_with::(|| C(1)); /// app.register_required_components_with::(|| C(2)); /// /// // Duplicate registration! Even if the constructors were different, this would fail. /// assert!(app.try_register_required_components_with::(|| C(1)).is_err()); /// /// fn setup(mut commands: Commands) { /// // This will implicitly also insert B with its Default constructor and C /// // with the custom constructor defined by A. /// commands.spawn(A); /// } /// /// fn validate(query: Option>) { /// let (a, b, c) = query.unwrap().into_inner(); /// assert_eq!(b, &B(0)); /// assert_eq!(c, &C(2)); /// } /// # app.update(); /// ``` pub fn try_register_required_components_with( &mut self, constructor: fn() -> R, ) -> Result<(), RequiredComponentsError> { self.world_mut() .try_register_required_components_with::(constructor) } /// Returns a reference to the main [`SubApp`]'s [`World`]. This is the same as calling /// [`app.main().world()`]. /// /// [`app.main().world()`]: SubApp::world pub fn world(&self) -> &World { self.main().world() } /// Returns a mutable reference to the main [`SubApp`]'s [`World`]. This is the same as calling /// [`app.main_mut().world_mut()`]. /// /// [`app.main_mut().world_mut()`]: SubApp::world_mut pub fn world_mut(&mut self) -> &mut World { self.main_mut().world_mut() } /// Returns a reference to the main [`SubApp`]. pub fn main(&self) -> &SubApp { &self.sub_apps.main } /// Returns a mutable reference to the main [`SubApp`]. pub fn main_mut(&mut self) -> &mut SubApp { &mut self.sub_apps.main } /// Returns a reference to the [`SubApp`] with the given label. /// /// # Panics /// /// Panics if the [`SubApp`] doesn't exist. pub fn sub_app(&self, label: impl AppLabel) -> &SubApp { let str = label.intern(); self.get_sub_app(label).unwrap_or_else(|| { panic!("No sub-app with label '{:?}' exists.", str); }) } /// Returns a reference to the [`SubApp`] with the given label. /// /// # Panics /// /// Panics if the [`SubApp`] doesn't exist. pub fn sub_app_mut(&mut self, label: impl AppLabel) -> &mut SubApp { let str = label.intern(); self.get_sub_app_mut(label).unwrap_or_else(|| { panic!("No sub-app with label '{:?}' exists.", str); }) } /// Returns a reference to the [`SubApp`] with the given label, if it exists. pub fn get_sub_app(&self, label: impl AppLabel) -> Option<&SubApp> { self.sub_apps.sub_apps.get(&label.intern()) } /// Returns a mutable reference to the [`SubApp`] with the given label, if it exists. pub fn get_sub_app_mut(&mut self, label: impl AppLabel) -> Option<&mut SubApp> { self.sub_apps.sub_apps.get_mut(&label.intern()) } /// Inserts a [`SubApp`] with the given label. pub fn insert_sub_app(&mut self, label: impl AppLabel, sub_app: SubApp) { self.sub_apps.sub_apps.insert(label.intern(), sub_app); } /// Removes the [`SubApp`] with the given label, if it exists. pub fn remove_sub_app(&mut self, label: impl AppLabel) -> Option { self.sub_apps.sub_apps.remove(&label.intern()) } /// Extract data from the main world into the [`SubApp`] with the given label and perform an update if it exists. pub fn update_sub_app_by_label(&mut self, label: impl AppLabel) { self.sub_apps.update_subapp_by_label(label); } /// Inserts a new `schedule` under the provided `label`, overwriting any existing /// schedule with the same label. pub fn add_schedule(&mut self, schedule: Schedule) -> &mut Self { self.main_mut().add_schedule(schedule); self } /// Initializes an empty `schedule` under the provided `label`, if it does not exist. /// /// See [`add_schedule`](Self::add_schedule) to insert an existing schedule. pub fn init_schedule(&mut self, label: impl ScheduleLabel) -> &mut Self { self.main_mut().init_schedule(label); self } /// Returns a reference to the [`Schedule`] with the provided `label` if it exists. pub fn get_schedule(&self, label: impl ScheduleLabel) -> Option<&Schedule> { self.main().get_schedule(label) } /// Returns a mutable reference to the [`Schedule`] with the provided `label` if it exists. pub fn get_schedule_mut(&mut self, label: impl ScheduleLabel) -> Option<&mut Schedule> { self.main_mut().get_schedule_mut(label) } /// Runs function `f` with the [`Schedule`] associated with `label`. /// /// **Note:** This will create the schedule if it does not already exist. pub fn edit_schedule( &mut self, label: impl ScheduleLabel, f: impl FnMut(&mut Schedule), ) -> &mut Self { self.main_mut().edit_schedule(label, f); self } /// Applies the provided [`ScheduleBuildSettings`] to all schedules. pub fn configure_schedules( &mut self, schedule_build_settings: ScheduleBuildSettings, ) -> &mut Self { self.main_mut().configure_schedules(schedule_build_settings); self } /// When doing [ambiguity checking](ScheduleBuildSettings) this /// ignores systems that are ambiguous on [`Component`] T. /// /// This settings only applies to the main world. To apply this to other worlds call the /// [corresponding method](World::allow_ambiguous_component) on World /// /// ## Example /// /// ``` /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::schedule::{LogLevel, ScheduleBuildSettings}; /// # use bevy_utils::default; /// /// #[derive(Component)] /// struct A; /// /// // these systems are ambiguous on A /// fn system_1(_: Query<&mut A>) {} /// fn system_2(_: Query<&A>) {} /// /// let mut app = App::new(); /// app.configure_schedules(ScheduleBuildSettings { /// ambiguity_detection: LogLevel::Error, /// ..default() /// }); /// /// app.add_systems(Update, ( system_1, system_2 )); /// app.allow_ambiguous_component::(); /// /// // running the app does not error. /// app.update(); /// ``` pub fn allow_ambiguous_component(&mut self) -> &mut Self { self.main_mut().allow_ambiguous_component::(); self } /// When doing [ambiguity checking](ScheduleBuildSettings) this /// ignores systems that are ambiguous on [`Resource`] T. /// /// This settings only applies to the main world. To apply this to other worlds call the /// [corresponding method](World::allow_ambiguous_resource) on World /// /// ## Example /// /// ``` /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::schedule::{LogLevel, ScheduleBuildSettings}; /// # use bevy_utils::default; /// /// #[derive(Resource)] /// struct R; /// /// // these systems are ambiguous on R /// fn system_1(_: ResMut) {} /// fn system_2(_: Res) {} /// /// let mut app = App::new(); /// app.configure_schedules(ScheduleBuildSettings { /// ambiguity_detection: LogLevel::Error, /// ..default() /// }); /// app.insert_resource(R); /// /// app.add_systems(Update, ( system_1, system_2 )); /// app.allow_ambiguous_resource::(); /// /// // running the app does not error. /// app.update(); /// ``` pub fn allow_ambiguous_resource(&mut self) -> &mut Self { self.main_mut().allow_ambiguous_resource::(); self } /// Suppress warnings and errors that would result from systems in these sets having ambiguities /// (conflicting access but indeterminate order) with systems in `set`. /// /// When possible, do this directly in the `.add_systems(Update, a.ambiguous_with(b))` call. /// However, sometimes two independent plugins `A` and `B` are reported as ambiguous, which you /// can only suppress as the consumer of both. #[track_caller] pub fn ignore_ambiguity( &mut self, schedule: impl ScheduleLabel, a: S1, b: S2, ) -> &mut Self where S1: IntoSystemSet, S2: IntoSystemSet, { self.main_mut().ignore_ambiguity(schedule, a, b); self } /// Attempts to determine if an [`AppExit`] was raised since the last update. /// /// Will attempt to return the first [`Error`](AppExit::Error) it encounters. /// This should be called after every [`update()`](App::update) otherwise you risk /// dropping possible [`AppExit`] events. pub fn should_exit(&self) -> Option { let mut reader = EventCursor::default(); let events = self.world().get_resource::>()?; let mut events = reader.read(events); if events.len() != 0 { return Some( events .find(|exit| exit.is_error()) .cloned() .unwrap_or(AppExit::Success), ); } None } /// Spawns an [`Observer`] entity, which will watch for and respond to the given event. /// /// # Examples /// /// ```rust /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # use bevy_utils::default; /// # /// # let mut app = App::new(); /// # /// # #[derive(Event)] /// # struct Party { /// # friends_allowed: bool, /// # }; /// # /// # #[derive(Event)] /// # struct Invite; /// # /// # #[derive(Component)] /// # struct Friend; /// # /// // An observer system can be any system where the first parameter is a trigger /// app.add_observer(|trigger: Trigger, friends: Query>, mut commands: Commands| { /// if trigger.event().friends_allowed { /// for friend in friends.iter() { /// commands.trigger_targets(Invite, friend); /// } /// } /// }); /// ``` pub fn add_observer( &mut self, observer: impl IntoObserverSystem, ) -> &mut Self { self.world_mut().add_observer(observer); self } } type RunnerFn = Box AppExit>; fn run_once(mut app: App) -> AppExit { while app.plugins_state() == PluginsState::Adding { #[cfg(not(target_arch = "wasm32"))] bevy_tasks::tick_global_task_pools_on_main_thread(); } app.finish(); app.cleanup(); app.update(); app.should_exit().unwrap_or(AppExit::Success) } /// An event that indicates the [`App`] should exit. If one or more of these are present at the end of an update, /// the [runner](App::set_runner) will end and ([maybe](App::run)) return control to the caller. /// /// This event can be used to detect when an exit is requested. Make sure that systems listening /// for this event run before the current update ends. /// /// # Portability /// This type is roughly meant to map to a standard definition of a process exit code (0 means success, not 0 means error). Due to portability concerns /// (see [`ExitCode`](https://doc.rust-lang.org/std/process/struct.ExitCode.html) and [`process::exit`](https://doc.rust-lang.org/std/process/fn.exit.html#)) /// we only allow error codes between 1 and [255](u8::MAX). #[derive(Event, Debug, Clone, Default, PartialEq, Eq)] pub enum AppExit { /// [`App`] exited without any problems. #[default] Success, /// The [`App`] experienced an unhandleable error. /// Holds the exit code we expect our app to return. Error(NonZero), } impl AppExit { /// Creates a [`AppExit::Error`] with a error code of 1. #[must_use] pub const fn error() -> Self { Self::Error(NonZero::::MIN) } /// Returns `true` if `self` is a [`AppExit::Success`]. #[must_use] pub const fn is_success(&self) -> bool { matches!(self, AppExit::Success) } /// Returns `true` if `self` is a [`AppExit::Error`]. #[must_use] pub const fn is_error(&self) -> bool { matches!(self, AppExit::Error(_)) } /// Creates a [`AppExit`] from a code. /// /// When `code` is 0 a [`AppExit::Success`] is constructed otherwise a /// [`AppExit::Error`] is constructed. #[must_use] pub const fn from_code(code: u8) -> Self { match NonZero::::new(code) { Some(code) => Self::Error(code), None => Self::Success, } } } impl From for AppExit { #[must_use] fn from(value: u8) -> Self { Self::from_code(value) } } impl Termination for AppExit { fn report(self) -> ExitCode { match self { AppExit::Success => ExitCode::SUCCESS, // We leave logging an error to our users AppExit::Error(value) => ExitCode::from(value.get()), } } } #[cfg(test)] mod tests { use core::{iter, marker::PhantomData}; use std::sync::Mutex; use bevy_ecs::{ change_detection::{DetectChanges, ResMut}, component::Component, entity::Entity, event::{Event, EventWriter, Events}, query::With, removal_detection::RemovedComponents, schedule::{IntoSystemConfigs, ScheduleLabel}, system::{Commands, Query, Resource}, world::{FromWorld, World}, }; use crate::{App, AppExit, Plugin, SubApp, Update}; struct PluginA; impl Plugin for PluginA { fn build(&self, _app: &mut App) {} } struct PluginB; impl Plugin for PluginB { fn build(&self, _app: &mut App) {} } struct PluginC(T); impl Plugin for PluginC { fn build(&self, _app: &mut App) {} } struct PluginD; impl Plugin for PluginD { fn build(&self, _app: &mut App) {} fn is_unique(&self) -> bool { false } } struct PluginE; impl Plugin for PluginE { fn build(&self, _app: &mut App) {} fn finish(&self, app: &mut App) { if app.is_plugin_added::() { panic!("cannot run if PluginA is already registered"); } } } #[test] fn can_add_two_plugins() { App::new().add_plugins((PluginA, PluginB)); } #[test] #[should_panic] fn cant_add_twice_the_same_plugin() { App::new().add_plugins((PluginA, PluginA)); } #[test] fn can_add_twice_the_same_plugin_with_different_type_param() { App::new().add_plugins((PluginC(0), PluginC(true))); } #[test] fn can_add_twice_the_same_plugin_not_unique() { App::new().add_plugins((PluginD, PluginD)); } #[test] #[should_panic] fn cant_call_app_run_from_plugin_build() { struct PluginRun; struct InnerPlugin; impl Plugin for InnerPlugin { fn build(&self, _: &mut App) {} } impl Plugin for PluginRun { fn build(&self, app: &mut App) { app.add_plugins(InnerPlugin).run(); } } App::new().add_plugins(PluginRun); } #[derive(ScheduleLabel, Hash, Clone, PartialEq, Eq, Debug)] struct EnterMainMenu; fn bar(mut commands: Commands) { commands.spawn_empty(); } fn foo(mut commands: Commands) { commands.spawn_empty(); } #[test] fn add_systems_should_create_schedule_if_it_does_not_exist() { let mut app = App::new(); app.add_systems(EnterMainMenu, (foo, bar)); app.world_mut().run_schedule(EnterMainMenu); assert_eq!(app.world().entities().len(), 2); } #[test] #[should_panic] fn test_is_plugin_added_works_during_finish() { let mut app = App::new(); app.add_plugins(PluginA); app.add_plugins(PluginE); app.finish(); } #[test] fn test_derive_app_label() { use super::AppLabel; use crate::{self as bevy_app}; #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] struct UnitLabel; #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] struct TupleLabel(u32, u32); #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] struct StructLabel { a: u32, b: u32, } #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] struct EmptyTupleLabel(); #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] struct EmptyStructLabel {} #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] enum EnumLabel { #[default] Unit, Tuple(u32, u32), Struct { a: u32, b: u32, }, } #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] struct GenericLabel(PhantomData); assert_eq!(UnitLabel.intern(), UnitLabel.intern()); assert_eq!(EnumLabel::Unit.intern(), EnumLabel::Unit.intern()); assert_ne!(UnitLabel.intern(), EnumLabel::Unit.intern()); assert_ne!(UnitLabel.intern(), TupleLabel(0, 0).intern()); assert_ne!(EnumLabel::Unit.intern(), EnumLabel::Tuple(0, 0).intern()); assert_eq!(TupleLabel(0, 0).intern(), TupleLabel(0, 0).intern()); assert_eq!( EnumLabel::Tuple(0, 0).intern(), EnumLabel::Tuple(0, 0).intern() ); assert_ne!(TupleLabel(0, 0).intern(), TupleLabel(0, 1).intern()); assert_ne!( EnumLabel::Tuple(0, 0).intern(), EnumLabel::Tuple(0, 1).intern() ); assert_ne!(TupleLabel(0, 0).intern(), EnumLabel::Tuple(0, 0).intern()); assert_ne!( TupleLabel(0, 0).intern(), StructLabel { a: 0, b: 0 }.intern() ); assert_ne!( EnumLabel::Tuple(0, 0).intern(), EnumLabel::Struct { a: 0, b: 0 }.intern() ); assert_eq!( StructLabel { a: 0, b: 0 }.intern(), StructLabel { a: 0, b: 0 }.intern() ); assert_eq!( EnumLabel::Struct { a: 0, b: 0 }.intern(), EnumLabel::Struct { a: 0, b: 0 }.intern() ); assert_ne!( StructLabel { a: 0, b: 0 }.intern(), StructLabel { a: 0, b: 1 }.intern() ); assert_ne!( EnumLabel::Struct { a: 0, b: 0 }.intern(), EnumLabel::Struct { a: 0, b: 1 }.intern() ); assert_ne!( StructLabel { a: 0, b: 0 }.intern(), EnumLabel::Struct { a: 0, b: 0 }.intern() ); assert_ne!( StructLabel { a: 0, b: 0 }.intern(), EnumLabel::Struct { a: 0, b: 0 }.intern() ); assert_ne!(StructLabel { a: 0, b: 0 }.intern(), UnitLabel.intern(),); assert_ne!( EnumLabel::Struct { a: 0, b: 0 }.intern(), EnumLabel::Unit.intern() ); assert_eq!( GenericLabel::(PhantomData).intern(), GenericLabel::(PhantomData).intern() ); assert_ne!( GenericLabel::(PhantomData).intern(), GenericLabel::(PhantomData).intern() ); } #[test] fn test_update_clears_trackers_once() { #[derive(Component, Copy, Clone)] struct Foo; let mut app = App::new(); app.world_mut().spawn_batch(iter::repeat(Foo).take(5)); fn despawn_one_foo(mut commands: Commands, foos: Query>) { if let Some(e) = foos.iter().next() { commands.entity(e).despawn(); }; } fn check_despawns(mut removed_foos: RemovedComponents) { let mut despawn_count = 0; for _ in removed_foos.read() { despawn_count += 1; } assert_eq!(despawn_count, 2); } app.add_systems(Update, despawn_one_foo); app.update(); // Frame 0 app.update(); // Frame 1 app.add_systems(Update, check_despawns.after(despawn_one_foo)); app.update(); // Should see despawns from frames 1 & 2, but not frame 0 } #[test] fn test_extract_sees_changes() { use super::AppLabel; use crate::{self as bevy_app}; #[derive(AppLabel, Clone, Copy, Hash, PartialEq, Eq, Debug)] struct MySubApp; #[derive(Resource)] struct Foo(usize); let mut app = App::new(); app.world_mut().insert_resource(Foo(0)); app.add_systems(Update, |mut foo: ResMut| { foo.0 += 1; }); let mut sub_app = SubApp::new(); sub_app.set_extract(|main_world, _sub_world| { assert!(main_world.get_resource_ref::().unwrap().is_changed()); }); app.insert_sub_app(MySubApp, sub_app); app.update(); } #[test] fn runner_returns_correct_exit_code() { fn raise_exits(mut exits: EventWriter) { // Exit codes chosen by a fair dice roll. // Unlikely to overlap with default values. exits.send(AppExit::Success); exits.send(AppExit::from_code(4)); exits.send(AppExit::from_code(73)); } let exit = App::new().add_systems(Update, raise_exits).run(); assert_eq!(exit, AppExit::from_code(4)); } /// Custom runners should be in charge of when `app::update` gets called as they may need to /// coordinate some state. /// bug: /// fix: #[test] fn regression_test_10385() { use super::{Res, Resource}; use crate::PreUpdate; #[derive(Resource)] struct MyState {} fn my_runner(mut app: App) -> AppExit { let my_state = MyState {}; app.world_mut().insert_resource(my_state); for _ in 0..5 { app.update(); } AppExit::Success } fn my_system(_: Res) { // access state during app update } // Should not panic due to missing resource App::new() .set_runner(my_runner) .add_systems(PreUpdate, my_system) .run(); } #[test] fn app_exit_size() { // There wont be many of them so the size isn't a issue but // it's nice they're so small let's keep it that way. assert_eq!(size_of::(), size_of::()); } #[test] fn initializing_resources_from_world() { #[derive(Resource)] struct TestResource; impl FromWorld for TestResource { fn from_world(_world: &mut World) -> Self { TestResource } } #[derive(Resource)] struct NonSendTestResource { _marker: PhantomData>, } impl FromWorld for NonSendTestResource { fn from_world(_world: &mut World) -> Self { NonSendTestResource { _marker: PhantomData, } } } App::new() .init_non_send_resource::() .init_resource::(); } #[test] /// Plugin should not be considered inserted while it's being built /// /// bug: fn plugin_should_not_be_added_during_build_time() { pub struct Foo; impl Plugin for Foo { fn build(&self, app: &mut App) { assert!(!app.is_plugin_added::()); } } App::new().add_plugins(Foo); } #[test] fn events_should_be_updated_once_per_update() { #[derive(Event, Clone)] struct TestEvent; let mut app = App::new(); app.add_event::(); // Starts empty let test_events = app.world().resource::>(); assert_eq!(test_events.len(), 0); assert_eq!(test_events.iter_current_update_events().count(), 0); app.update(); // Sending one event app.world_mut().send_event(TestEvent); let test_events = app.world().resource::>(); assert_eq!(test_events.len(), 1); assert_eq!(test_events.iter_current_update_events().count(), 1); app.update(); // Sending two events on the next frame app.world_mut().send_event(TestEvent); app.world_mut().send_event(TestEvent); let test_events = app.world().resource::>(); assert_eq!(test_events.len(), 3); // Events are double-buffered, so we see 1 + 2 = 3 assert_eq!(test_events.iter_current_update_events().count(), 2); app.update(); // Sending zero events let test_events = app.world().resource::>(); assert_eq!(test_events.len(), 2); // Events are double-buffered, so we see 2 + 0 = 2 assert_eq!(test_events.iter_current_update_events().count(), 0); } }