bevy_app/app.rs
1use crate::{
2 First, Main, MainSchedulePlugin, PlaceholderPlugin, Plugin, Plugins, PluginsState, SubApp,
3 SubApps,
4};
5pub use bevy_derive::AppLabel;
6use bevy_ecs::{
7 event::{event_update_system, ManualEventReader},
8 intern::Interned,
9 prelude::*,
10 schedule::{ScheduleBuildSettings, ScheduleLabel},
11 system::{IntoObserverSystem, SystemId},
12};
13#[cfg(feature = "trace")]
14use bevy_utils::tracing::info_span;
15use bevy_utils::{tracing::debug, HashMap};
16use std::{
17 fmt::Debug,
18 process::{ExitCode, Termination},
19};
20use std::{
21 num::NonZeroU8,
22 panic::{catch_unwind, resume_unwind, AssertUnwindSafe},
23};
24use thiserror::Error;
25
26bevy_ecs::define_label!(
27 /// A strongly-typed class of labels used to identify an [`App`].
28 AppLabel,
29 APP_LABEL_INTERNER
30);
31
32pub use bevy_ecs::label::DynEq;
33
34/// A shorthand for `Interned<dyn AppLabel>`.
35pub type InternedAppLabel = Interned<dyn AppLabel>;
36
37#[derive(Debug, Error)]
38pub(crate) enum AppError {
39 #[error("duplicate plugin {plugin_name:?}")]
40 DuplicatePlugin { plugin_name: String },
41}
42
43#[allow(clippy::needless_doctest_main)]
44/// [`App`] is the primary API for writing user applications. It automates the setup of a
45/// [standard lifecycle](Main) and provides interface glue for [plugins](`Plugin`).
46///
47/// A single [`App`] can contain multiple [`SubApp`] instances, but [`App`] methods only affect
48/// the "main" one. To access a particular [`SubApp`], use [`get_sub_app`](App::get_sub_app)
49/// or [`get_sub_app_mut`](App::get_sub_app_mut).
50///
51///
52/// # Examples
53///
54/// Here is a simple "Hello World" Bevy app:
55///
56/// ```
57/// # use bevy_app::prelude::*;
58/// # use bevy_ecs::prelude::*;
59/// #
60/// fn main() {
61/// App::new()
62/// .add_systems(Update, hello_world_system)
63/// .run();
64/// }
65///
66/// fn hello_world_system() {
67/// println!("hello world");
68/// }
69/// ```
70pub struct App {
71 pub(crate) sub_apps: SubApps,
72 /// The function that will manage the app's lifecycle.
73 ///
74 /// Bevy provides the [`WinitPlugin`] and [`ScheduleRunnerPlugin`] for windowed and headless
75 /// applications, respectively.
76 ///
77 /// [`WinitPlugin`]: https://docs.rs/bevy/latest/bevy/winit/struct.WinitPlugin.html
78 /// [`ScheduleRunnerPlugin`]: https://docs.rs/bevy/latest/bevy/app/struct.ScheduleRunnerPlugin.html
79 pub(crate) runner: RunnerFn,
80}
81
82impl Debug for App {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(f, "App {{ sub_apps: ")?;
85 f.debug_map()
86 .entries(self.sub_apps.sub_apps.iter())
87 .finish()?;
88 write!(f, "}}")
89 }
90}
91
92impl Default for App {
93 fn default() -> Self {
94 let mut app = App::empty();
95 app.sub_apps.main.update_schedule = Some(Main.intern());
96
97 #[cfg(feature = "bevy_reflect")]
98 app.init_resource::<AppTypeRegistry>();
99 app.add_plugins(MainSchedulePlugin);
100 app.add_systems(
101 First,
102 event_update_system
103 .in_set(bevy_ecs::event::EventUpdates)
104 .run_if(bevy_ecs::event::event_update_condition),
105 );
106 app.add_event::<AppExit>();
107
108 app
109 }
110}
111
112impl App {
113 /// Creates a new [`App`] with some default structure to enable core engine features.
114 /// This is the preferred constructor for most use cases.
115 pub fn new() -> App {
116 App::default()
117 }
118
119 /// Creates a new empty [`App`] with minimal default configuration.
120 ///
121 /// Use this constructor if you want to customize scheduling, exit handling, cleanup, etc.
122 pub fn empty() -> App {
123 Self {
124 sub_apps: SubApps {
125 main: SubApp::new(),
126 sub_apps: HashMap::new(),
127 },
128 runner: Box::new(run_once),
129 }
130 }
131
132 /// Runs the default schedules of all sub-apps (starting with the "main" app) once.
133 pub fn update(&mut self) {
134 if self.is_building_plugins() {
135 panic!("App::update() was called while a plugin was building.");
136 }
137
138 self.sub_apps.update();
139 }
140
141 /// Runs the [`App`] by calling its [runner](Self::set_runner).
142 ///
143 /// This will (re)build the [`App`] first. For general usage, see the example on the item
144 /// level documentation.
145 ///
146 /// # Caveats
147 ///
148 /// Calls to [`App::run()`] will never return on iOS and Web.
149 ///
150 /// Headless apps can generally expect this method to return control to the caller when
151 /// it completes, but that is not the case for windowed apps. Windowed apps are typically
152 /// driven by an event loop and some platforms expect the program to terminate when the
153 /// event loop ends.
154 ///
155 /// By default, *Bevy* uses the `winit` crate for window creation.
156 ///
157 /// # Panics
158 ///
159 /// Panics if not all plugins have been built.
160 pub fn run(&mut self) -> AppExit {
161 #[cfg(feature = "trace")]
162 let _bevy_app_run_span = info_span!("bevy_app").entered();
163 if self.is_building_plugins() {
164 panic!("App::run() was called while a plugin was building.");
165 }
166
167 let runner = std::mem::replace(&mut self.runner, Box::new(run_once));
168 let app = std::mem::replace(self, App::empty());
169 (runner)(app)
170 }
171
172 /// Sets the function that will be called when the app is run.
173 ///
174 /// The runner function `f` is called only once by [`App::run`]. If the
175 /// presence of a main loop in the app is desired, it is the responsibility of the runner
176 /// function to provide it.
177 ///
178 /// The runner function is usually not set manually, but by Bevy integrated plugins
179 /// (e.g. `WinitPlugin`).
180 ///
181 /// # Examples
182 ///
183 /// ```
184 /// # use bevy_app::prelude::*;
185 /// #
186 /// fn my_runner(mut app: App) -> AppExit {
187 /// loop {
188 /// println!("In main loop");
189 /// app.update();
190 /// if let Some(exit) = app.should_exit() {
191 /// return exit;
192 /// }
193 /// }
194 /// }
195 ///
196 /// App::new()
197 /// .set_runner(my_runner);
198 /// ```
199 pub fn set_runner(&mut self, f: impl FnOnce(App) -> AppExit + 'static) -> &mut Self {
200 self.runner = Box::new(f);
201 self
202 }
203
204 /// Returns the state of all plugins. This is usually called by the event loop, but can be
205 /// useful for situations where you want to use [`App::update`].
206 // TODO: &mut self -> &self
207 #[inline]
208 pub fn plugins_state(&mut self) -> PluginsState {
209 let mut overall_plugins_state = match self.main_mut().plugins_state {
210 PluginsState::Adding => {
211 let mut state = PluginsState::Ready;
212 let plugins = std::mem::take(&mut self.main_mut().plugin_registry);
213 for plugin in &plugins {
214 // plugins installed to main need to see all sub-apps
215 if !plugin.ready(self) {
216 state = PluginsState::Adding;
217 break;
218 }
219 }
220 self.main_mut().plugin_registry = plugins;
221 state
222 }
223 state => state,
224 };
225
226 // overall state is the earliest state of any sub-app
227 self.sub_apps.iter_mut().skip(1).for_each(|s| {
228 overall_plugins_state = overall_plugins_state.min(s.plugins_state());
229 });
230
231 overall_plugins_state
232 }
233
234 /// Runs [`Plugin::finish`] for each plugin. This is usually called by the event loop once all
235 /// plugins are ready, but can be useful for situations where you want to use [`App::update`].
236 pub fn finish(&mut self) {
237 // plugins installed to main should see all sub-apps
238 let plugins = std::mem::take(&mut self.main_mut().plugin_registry);
239 for plugin in &plugins {
240 plugin.finish(self);
241 }
242 let main = self.main_mut();
243 main.plugin_registry = plugins;
244 main.plugins_state = PluginsState::Finished;
245 self.sub_apps.iter_mut().skip(1).for_each(|s| s.finish());
246 }
247
248 /// Runs [`Plugin::cleanup`] for each plugin. This is usually called by the event loop after
249 /// [`App::finish`], but can be useful for situations where you want to use [`App::update`].
250 pub fn cleanup(&mut self) {
251 // plugins installed to main should see all sub-apps
252 let plugins = std::mem::take(&mut self.main_mut().plugin_registry);
253 for plugin in &plugins {
254 plugin.cleanup(self);
255 }
256 let main = self.main_mut();
257 main.plugin_registry = plugins;
258 main.plugins_state = PluginsState::Cleaned;
259 self.sub_apps.iter_mut().skip(1).for_each(|s| s.cleanup());
260 }
261
262 /// Returns `true` if any of the sub-apps are building plugins.
263 pub(crate) fn is_building_plugins(&self) -> bool {
264 self.sub_apps.iter().any(|s| s.is_building_plugins())
265 }
266
267 /// Adds one or more systems to the given schedule in this app's [`Schedules`].
268 ///
269 /// # Examples
270 ///
271 /// ```
272 /// # use bevy_app::prelude::*;
273 /// # use bevy_ecs::prelude::*;
274 /// #
275 /// # let mut app = App::new();
276 /// # fn system_a() {}
277 /// # fn system_b() {}
278 /// # fn system_c() {}
279 /// # fn should_run() -> bool { true }
280 /// #
281 /// app.add_systems(Update, (system_a, system_b, system_c));
282 /// app.add_systems(Update, (system_a, system_b).run_if(should_run));
283 /// ```
284 pub fn add_systems<M>(
285 &mut self,
286 schedule: impl ScheduleLabel,
287 systems: impl IntoSystemConfigs<M>,
288 ) -> &mut Self {
289 self.main_mut().add_systems(schedule, systems);
290 self
291 }
292
293 /// Registers a system and returns a [`SystemId`] so it can later be called by [`World::run_system`].
294 ///
295 /// It's possible to register the same systems more than once, they'll be stored separately.
296 ///
297 /// This is different from adding systems to a [`Schedule`] with [`App::add_systems`],
298 /// because the [`SystemId`] that is returned can be used anywhere in the [`World`] to run the associated system.
299 /// This allows for running systems in a push-based fashion.
300 /// Using a [`Schedule`] is still preferred for most cases
301 /// due to its better performance and ability to run non-conflicting systems simultaneously.
302 pub fn register_system<I: 'static, O: 'static, M, S: IntoSystem<I, O, M> + 'static>(
303 &mut self,
304 system: S,
305 ) -> SystemId<I, O> {
306 self.main_mut().register_system(system)
307 }
308
309 /// Configures a collection of system sets in the provided schedule, adding any sets that do not exist.
310 #[track_caller]
311 pub fn configure_sets(
312 &mut self,
313 schedule: impl ScheduleLabel,
314 sets: impl IntoSystemSetConfigs,
315 ) -> &mut Self {
316 self.main_mut().configure_sets(schedule, sets);
317 self
318 }
319
320 /// Initializes `T` event handling by inserting an event queue resource ([`Events::<T>`])
321 /// and scheduling an [`event_update_system`] in [`First`](crate::First).
322 ///
323 /// See [`Events`] for information on how to define events.
324 ///
325 /// # Examples
326 ///
327 /// ```
328 /// # use bevy_app::prelude::*;
329 /// # use bevy_ecs::prelude::*;
330 /// #
331 /// # #[derive(Event)]
332 /// # struct MyEvent;
333 /// # let mut app = App::new();
334 /// #
335 /// app.add_event::<MyEvent>();
336 /// ```
337 pub fn add_event<T>(&mut self) -> &mut Self
338 where
339 T: Event,
340 {
341 self.main_mut().add_event::<T>();
342 self
343 }
344
345 /// Inserts the [`Resource`] into the app, overwriting any existing resource of the same type.
346 ///
347 /// There is also an [`init_resource`](Self::init_resource) for resources that have
348 /// [`Default`] or [`FromWorld`] implementations.
349 ///
350 /// # Examples
351 ///
352 /// ```
353 /// # use bevy_app::prelude::*;
354 /// # use bevy_ecs::prelude::*;
355 /// #
356 /// #[derive(Resource)]
357 /// struct MyCounter {
358 /// counter: usize,
359 /// }
360 ///
361 /// App::new()
362 /// .insert_resource(MyCounter { counter: 0 });
363 /// ```
364 pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
365 self.main_mut().insert_resource(resource);
366 self
367 }
368
369 /// Inserts the [`Resource`], initialized with its default value, into the app,
370 /// if there is no existing instance of `R`.
371 ///
372 /// `R` must implement [`FromWorld`].
373 /// If `R` implements [`Default`], [`FromWorld`] will be automatically implemented and
374 /// initialize the [`Resource`] with [`Default::default`].
375 ///
376 /// # Examples
377 ///
378 /// ```
379 /// # use bevy_app::prelude::*;
380 /// # use bevy_ecs::prelude::*;
381 /// #
382 /// #[derive(Resource)]
383 /// struct MyCounter {
384 /// counter: usize,
385 /// }
386 ///
387 /// impl Default for MyCounter {
388 /// fn default() -> MyCounter {
389 /// MyCounter {
390 /// counter: 100
391 /// }
392 /// }
393 /// }
394 ///
395 /// App::new()
396 /// .init_resource::<MyCounter>();
397 /// ```
398 pub fn init_resource<R: Resource + FromWorld>(&mut self) -> &mut Self {
399 self.main_mut().init_resource::<R>();
400 self
401 }
402
403 /// Inserts the [`!Send`](Send) resource into the app, overwriting any existing resource
404 /// of the same type.
405 ///
406 /// There is also an [`init_non_send_resource`](Self::init_non_send_resource) for
407 /// resources that implement [`Default`]
408 ///
409 /// # Examples
410 ///
411 /// ```
412 /// # use bevy_app::prelude::*;
413 /// # use bevy_ecs::prelude::*;
414 /// #
415 /// struct MyCounter {
416 /// counter: usize,
417 /// }
418 ///
419 /// App::new()
420 /// .insert_non_send_resource(MyCounter { counter: 0 });
421 /// ```
422 pub fn insert_non_send_resource<R: 'static>(&mut self, resource: R) -> &mut Self {
423 self.world_mut().insert_non_send_resource(resource);
424 self
425 }
426
427 /// Inserts the [`!Send`](Send) resource into the app if there is no existing instance of `R`.
428 ///
429 /// `R` must implement [`FromWorld`].
430 /// If `R` implements [`Default`], [`FromWorld`] will be automatically implemented and
431 /// initialize the [`Resource`] with [`Default::default`].
432 pub fn init_non_send_resource<R: 'static + FromWorld>(&mut self) -> &mut Self {
433 self.world_mut().init_non_send_resource::<R>();
434 self
435 }
436
437 pub(crate) fn add_boxed_plugin(
438 &mut self,
439 plugin: Box<dyn Plugin>,
440 ) -> Result<&mut Self, AppError> {
441 debug!("added plugin: {}", plugin.name());
442 if plugin.is_unique() && self.main_mut().plugin_names.contains(plugin.name()) {
443 Err(AppError::DuplicatePlugin {
444 plugin_name: plugin.name().to_string(),
445 })?;
446 }
447
448 // Reserve position in the plugin registry. If the plugin adds more plugins,
449 // they'll all end up in insertion order.
450 let index = self.main().plugin_registry.len();
451 self.main_mut()
452 .plugin_registry
453 .push(Box::new(PlaceholderPlugin));
454
455 self.main_mut().plugin_build_depth += 1;
456 let result = catch_unwind(AssertUnwindSafe(|| plugin.build(self)));
457 self.main_mut()
458 .plugin_names
459 .insert(plugin.name().to_string());
460 self.main_mut().plugin_build_depth -= 1;
461
462 if let Err(payload) = result {
463 resume_unwind(payload);
464 }
465
466 self.main_mut().plugin_registry[index] = plugin;
467 Ok(self)
468 }
469
470 /// Returns `true` if the [`Plugin`] has already been added.
471 pub fn is_plugin_added<T>(&self) -> bool
472 where
473 T: Plugin,
474 {
475 self.main().is_plugin_added::<T>()
476 }
477
478 /// Returns a vector of references to all plugins of type `T` that have been added.
479 ///
480 /// This can be used to read the settings of any existing plugins.
481 /// This vector will be empty if no plugins of that type have been added.
482 /// If multiple copies of the same plugin are added to the [`App`], they will be listed in insertion order in this vector.
483 ///
484 /// ```
485 /// # use bevy_app::prelude::*;
486 /// # #[derive(Default)]
487 /// # struct ImagePlugin {
488 /// # default_sampler: bool,
489 /// # }
490 /// # impl Plugin for ImagePlugin {
491 /// # fn build(&self, app: &mut App) {}
492 /// # }
493 /// # let mut app = App::new();
494 /// # app.add_plugins(ImagePlugin::default());
495 /// let default_sampler = app.get_added_plugins::<ImagePlugin>()[0].default_sampler;
496 /// ```
497 pub fn get_added_plugins<T>(&self) -> Vec<&T>
498 where
499 T: Plugin,
500 {
501 self.main().get_added_plugins::<T>()
502 }
503
504 /// Installs a [`Plugin`] collection.
505 ///
506 /// Bevy prioritizes modularity as a core principle. **All** engine features are implemented
507 /// as plugins, even the complex ones like rendering.
508 ///
509 /// [`Plugin`]s can be grouped into a set by using a [`PluginGroup`].
510 ///
511 /// There are built-in [`PluginGroup`]s that provide core engine functionality.
512 /// The [`PluginGroup`]s available by default are `DefaultPlugins` and `MinimalPlugins`.
513 ///
514 /// To customize the plugins in the group (reorder, disable a plugin, add a new plugin
515 /// before / after another plugin), call [`build()`](super::PluginGroup::build) on the group,
516 /// which will convert it to a [`PluginGroupBuilder`](crate::PluginGroupBuilder).
517 ///
518 /// You can also specify a group of [`Plugin`]s by using a tuple over [`Plugin`]s and
519 /// [`PluginGroup`]s. See [`Plugins`] for more details.
520 ///
521 /// ## Examples
522 /// ```
523 /// # use bevy_app::{prelude::*, PluginGroupBuilder, NoopPluginGroup as MinimalPlugins};
524 /// #
525 /// # // Dummies created to avoid using `bevy_log`,
526 /// # // which pulls in too many dependencies and breaks rust-analyzer
527 /// # pub struct LogPlugin;
528 /// # impl Plugin for LogPlugin {
529 /// # fn build(&self, app: &mut App) {}
530 /// # }
531 /// App::new()
532 /// .add_plugins(MinimalPlugins);
533 /// App::new()
534 /// .add_plugins((MinimalPlugins, LogPlugin));
535 /// ```
536 ///
537 /// # Panics
538 ///
539 /// Panics if one of the plugins had already been added to the application.
540 ///
541 /// [`PluginGroup`]:super::PluginGroup
542 #[track_caller]
543 pub fn add_plugins<M>(&mut self, plugins: impl Plugins<M>) -> &mut Self {
544 if matches!(
545 self.plugins_state(),
546 PluginsState::Cleaned | PluginsState::Finished
547 ) {
548 panic!(
549 "Plugins cannot be added after App::cleanup() or App::finish() has been called."
550 );
551 }
552 plugins.add_to_app(self);
553 self
554 }
555
556 /// Registers the type `T` in the [`TypeRegistry`](bevy_reflect::TypeRegistry) resource,
557 /// adding reflect data as specified in the [`Reflect`](bevy_reflect::Reflect) derive:
558 /// ```ignore (No serde "derive" feature)
559 /// #[derive(Component, Serialize, Deserialize, Reflect)]
560 /// #[reflect(Component, Serialize, Deserialize)] // will register ReflectComponent, ReflectSerialize, ReflectDeserialize
561 /// ```
562 ///
563 /// See [`bevy_reflect::TypeRegistry::register`] for more information.
564 #[cfg(feature = "bevy_reflect")]
565 pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
566 self.main_mut().register_type::<T>();
567 self
568 }
569
570 /// Associates type data `D` with type `T` in the [`TypeRegistry`](bevy_reflect::TypeRegistry) resource.
571 ///
572 /// Most of the time [`register_type`](Self::register_type) can be used instead to register a
573 /// type you derived [`Reflect`](bevy_reflect::Reflect) for. However, in cases where you want to
574 /// add a piece of type data that was not included in the list of `#[reflect(...)]` type data in
575 /// the derive, or where the type is generic and cannot register e.g. `ReflectSerialize`
576 /// unconditionally without knowing the specific type parameters, this method can be used to
577 /// insert additional type data.
578 ///
579 /// # Example
580 /// ```
581 /// use bevy_app::App;
582 /// use bevy_reflect::{ReflectSerialize, ReflectDeserialize};
583 ///
584 /// App::new()
585 /// .register_type::<Option<String>>()
586 /// .register_type_data::<Option<String>, ReflectSerialize>()
587 /// .register_type_data::<Option<String>, ReflectDeserialize>();
588 /// ```
589 ///
590 /// See [`bevy_reflect::TypeRegistry::register_type_data`].
591 #[cfg(feature = "bevy_reflect")]
592 pub fn register_type_data<
593 T: bevy_reflect::Reflect + bevy_reflect::TypePath,
594 D: bevy_reflect::TypeData + bevy_reflect::FromType<T>,
595 >(
596 &mut self,
597 ) -> &mut Self {
598 self.main_mut().register_type_data::<T, D>();
599 self
600 }
601
602 /// Returns a reference to the [`World`].
603 pub fn world(&self) -> &World {
604 self.main().world()
605 }
606
607 /// Returns a mutable reference to the [`World`].
608 pub fn world_mut(&mut self) -> &mut World {
609 self.main_mut().world_mut()
610 }
611
612 /// Returns a reference to the main [`SubApp`].
613 pub fn main(&self) -> &SubApp {
614 &self.sub_apps.main
615 }
616
617 /// Returns a mutable reference to the main [`SubApp`].
618 pub fn main_mut(&mut self) -> &mut SubApp {
619 &mut self.sub_apps.main
620 }
621
622 /// Returns a reference to the [`SubApp`] with the given label.
623 ///
624 /// # Panics
625 ///
626 /// Panics if the [`SubApp`] doesn't exist.
627 pub fn sub_app(&self, label: impl AppLabel) -> &SubApp {
628 let str = label.intern();
629 self.get_sub_app(label).unwrap_or_else(|| {
630 panic!("No sub-app with label '{:?}' exists.", str);
631 })
632 }
633
634 /// Returns a reference to the [`SubApp`] with the given label.
635 ///
636 /// # Panics
637 ///
638 /// Panics if the [`SubApp`] doesn't exist.
639 pub fn sub_app_mut(&mut self, label: impl AppLabel) -> &mut SubApp {
640 let str = label.intern();
641 self.get_sub_app_mut(label).unwrap_or_else(|| {
642 panic!("No sub-app with label '{:?}' exists.", str);
643 })
644 }
645
646 /// Returns a reference to the [`SubApp`] with the given label, if it exists.
647 pub fn get_sub_app(&self, label: impl AppLabel) -> Option<&SubApp> {
648 self.sub_apps.sub_apps.get(&label.intern())
649 }
650
651 /// Returns a mutable reference to the [`SubApp`] with the given label, if it exists.
652 pub fn get_sub_app_mut(&mut self, label: impl AppLabel) -> Option<&mut SubApp> {
653 self.sub_apps.sub_apps.get_mut(&label.intern())
654 }
655
656 /// Inserts a [`SubApp`] with the given label.
657 pub fn insert_sub_app(&mut self, label: impl AppLabel, sub_app: SubApp) {
658 self.sub_apps.sub_apps.insert(label.intern(), sub_app);
659 }
660
661 /// Removes the [`SubApp`] with the given label, if it exists.
662 pub fn remove_sub_app(&mut self, label: impl AppLabel) -> Option<SubApp> {
663 self.sub_apps.sub_apps.remove(&label.intern())
664 }
665
666 /// Extract data from the main world into the [`SubApp`] with the given label and perform an update if it exists.
667 pub fn update_sub_app_by_label(&mut self, label: impl AppLabel) {
668 self.sub_apps.update_subapp_by_label(label);
669 }
670
671 /// Inserts a new `schedule` under the provided `label`, overwriting any existing
672 /// schedule with the same label.
673 pub fn add_schedule(&mut self, schedule: Schedule) -> &mut Self {
674 self.main_mut().add_schedule(schedule);
675 self
676 }
677
678 /// Initializes an empty `schedule` under the provided `label`, if it does not exist.
679 ///
680 /// See [`add_schedule`](Self::add_schedule) to insert an existing schedule.
681 pub fn init_schedule(&mut self, label: impl ScheduleLabel) -> &mut Self {
682 self.main_mut().init_schedule(label);
683 self
684 }
685
686 /// Returns a reference to the [`Schedule`] with the provided `label` if it exists.
687 pub fn get_schedule(&self, label: impl ScheduleLabel) -> Option<&Schedule> {
688 self.main().get_schedule(label)
689 }
690
691 /// Returns a mutable reference to the [`Schedule`] with the provided `label` if it exists.
692 pub fn get_schedule_mut(&mut self, label: impl ScheduleLabel) -> Option<&mut Schedule> {
693 self.main_mut().get_schedule_mut(label)
694 }
695
696 /// Runs function `f` with the [`Schedule`] associated with `label`.
697 ///
698 /// **Note:** This will create the schedule if it does not already exist.
699 pub fn edit_schedule(
700 &mut self,
701 label: impl ScheduleLabel,
702 f: impl FnMut(&mut Schedule),
703 ) -> &mut Self {
704 self.main_mut().edit_schedule(label, f);
705 self
706 }
707
708 /// Applies the provided [`ScheduleBuildSettings`] to all schedules.
709 pub fn configure_schedules(
710 &mut self,
711 schedule_build_settings: ScheduleBuildSettings,
712 ) -> &mut Self {
713 self.main_mut().configure_schedules(schedule_build_settings);
714 self
715 }
716
717 /// When doing [ambiguity checking](ScheduleBuildSettings) this
718 /// ignores systems that are ambiguous on [`Component`] T.
719 ///
720 /// This settings only applies to the main world. To apply this to other worlds call the
721 /// [corresponding method](World::allow_ambiguous_component) on World
722 ///
723 /// ## Example
724 ///
725 /// ```
726 /// # use bevy_app::prelude::*;
727 /// # use bevy_ecs::prelude::*;
728 /// # use bevy_ecs::schedule::{LogLevel, ScheduleBuildSettings};
729 /// # use bevy_utils::default;
730 ///
731 /// #[derive(Component)]
732 /// struct A;
733 ///
734 /// // these systems are ambiguous on A
735 /// fn system_1(_: Query<&mut A>) {}
736 /// fn system_2(_: Query<&A>) {}
737 ///
738 /// let mut app = App::new();
739 /// app.configure_schedules(ScheduleBuildSettings {
740 /// ambiguity_detection: LogLevel::Error,
741 /// ..default()
742 /// });
743 ///
744 /// app.add_systems(Update, ( system_1, system_2 ));
745 /// app.allow_ambiguous_component::<A>();
746 ///
747 /// // running the app does not error.
748 /// app.update();
749 /// ```
750 pub fn allow_ambiguous_component<T: Component>(&mut self) -> &mut Self {
751 self.main_mut().allow_ambiguous_component::<T>();
752 self
753 }
754
755 /// When doing [ambiguity checking](ScheduleBuildSettings) this
756 /// ignores systems that are ambiguous on [`Resource`] T.
757 ///
758 /// This settings only applies to the main world. To apply this to other worlds call the
759 /// [corresponding method](World::allow_ambiguous_resource) on World
760 ///
761 /// ## Example
762 ///
763 /// ```
764 /// # use bevy_app::prelude::*;
765 /// # use bevy_ecs::prelude::*;
766 /// # use bevy_ecs::schedule::{LogLevel, ScheduleBuildSettings};
767 /// # use bevy_utils::default;
768 ///
769 /// #[derive(Resource)]
770 /// struct R;
771 ///
772 /// // these systems are ambiguous on R
773 /// fn system_1(_: ResMut<R>) {}
774 /// fn system_2(_: Res<R>) {}
775 ///
776 /// let mut app = App::new();
777 /// app.configure_schedules(ScheduleBuildSettings {
778 /// ambiguity_detection: LogLevel::Error,
779 /// ..default()
780 /// });
781 /// app.insert_resource(R);
782 ///
783 /// app.add_systems(Update, ( system_1, system_2 ));
784 /// app.allow_ambiguous_resource::<R>();
785 ///
786 /// // running the app does not error.
787 /// app.update();
788 /// ```
789 pub fn allow_ambiguous_resource<T: Resource>(&mut self) -> &mut Self {
790 self.main_mut().allow_ambiguous_resource::<T>();
791 self
792 }
793
794 /// Suppress warnings and errors that would result from systems in these sets having ambiguities
795 /// (conflicting access but indeterminate order) with systems in `set`.
796 ///
797 /// When possible, do this directly in the `.add_systems(Update, a.ambiguous_with(b))` call.
798 /// However, sometimes two independent plugins `A` and `B` are reported as ambiguous, which you
799 /// can only suppress as the consumer of both.
800 #[track_caller]
801 pub fn ignore_ambiguity<M1, M2, S1, S2>(
802 &mut self,
803 schedule: impl ScheduleLabel,
804 a: S1,
805 b: S2,
806 ) -> &mut Self
807 where
808 S1: IntoSystemSet<M1>,
809 S2: IntoSystemSet<M2>,
810 {
811 self.main_mut().ignore_ambiguity(schedule, a, b);
812 self
813 }
814
815 /// Attempts to determine if an [`AppExit`] was raised since the last update.
816 ///
817 /// Will attempt to return the first [`Error`](AppExit::Error) it encounters.
818 /// This should be called after every [`update()`](App::update) otherwise you risk
819 /// dropping possible [`AppExit`] events.
820 pub fn should_exit(&self) -> Option<AppExit> {
821 let mut reader = ManualEventReader::default();
822
823 let events = self.world().get_resource::<Events<AppExit>>()?;
824 let mut events = reader.read(events);
825
826 if events.len() != 0 {
827 return Some(
828 events
829 .find(|exit| exit.is_error())
830 .cloned()
831 .unwrap_or(AppExit::Success),
832 );
833 }
834
835 None
836 }
837
838 /// Spawns an [`Observer`] entity, which will watch for and respond to the given event.
839 pub fn observe<E: Event, B: Bundle, M>(
840 &mut self,
841 observer: impl IntoObserverSystem<E, B, M>,
842 ) -> &mut Self {
843 self.world_mut().observe(observer);
844 self
845 }
846}
847
848type RunnerFn = Box<dyn FnOnce(App) -> AppExit>;
849
850fn run_once(mut app: App) -> AppExit {
851 while app.plugins_state() == PluginsState::Adding {
852 #[cfg(not(target_arch = "wasm32"))]
853 bevy_tasks::tick_global_task_pools_on_main_thread();
854 }
855 app.finish();
856 app.cleanup();
857
858 app.update();
859
860 app.should_exit().unwrap_or(AppExit::Success)
861}
862
863/// An event that indicates the [`App`] should exit. If one or more of these are present at the end of an update,
864/// the [runner](App::set_runner) will end and ([maybe](App::run)) return control to the caller.
865///
866/// This event can be used to detect when an exit is requested. Make sure that systems listening
867/// for this event run before the current update ends.
868///
869/// # Portability
870/// 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
871/// (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#))
872/// we only allow error codes between 1 and [255](u8::MAX).
873#[derive(Event, Debug, Clone, Default, PartialEq, Eq)]
874pub enum AppExit {
875 /// [`App`] exited without any problems.
876 #[default]
877 Success,
878 /// The [`App`] experienced an unhandleable error.
879 /// Holds the exit code we expect our app to return.
880 Error(NonZeroU8),
881}
882
883impl AppExit {
884 /// Creates a [`AppExit::Error`] with a error code of 1.
885 #[must_use]
886 pub const fn error() -> Self {
887 Self::Error(NonZeroU8::MIN)
888 }
889
890 /// Returns `true` if `self` is a [`AppExit::Success`].
891 #[must_use]
892 pub const fn is_success(&self) -> bool {
893 matches!(self, AppExit::Success)
894 }
895
896 /// Returns `true` if `self` is a [`AppExit::Error`].
897 #[must_use]
898 pub const fn is_error(&self) -> bool {
899 matches!(self, AppExit::Error(_))
900 }
901
902 /// Creates a [`AppExit`] from a code.
903 ///
904 /// When `code` is 0 a [`AppExit::Success`] is constructed otherwise a
905 /// [`AppExit::Error`] is constructed.
906 #[must_use]
907 pub const fn from_code(code: u8) -> Self {
908 match NonZeroU8::new(code) {
909 Some(code) => Self::Error(code),
910 None => Self::Success,
911 }
912 }
913}
914
915impl From<u8> for AppExit {
916 #[must_use]
917 fn from(value: u8) -> Self {
918 Self::from_code(value)
919 }
920}
921
922impl Termination for AppExit {
923 fn report(self) -> std::process::ExitCode {
924 match self {
925 AppExit::Success => ExitCode::SUCCESS,
926 // We leave logging an error to our users
927 AppExit::Error(value) => ExitCode::from(value.get()),
928 }
929 }
930}
931
932#[cfg(test)]
933mod tests {
934 use std::{iter, marker::PhantomData, mem, sync::Mutex};
935
936 use bevy_ecs::{
937 change_detection::{DetectChanges, ResMut},
938 component::Component,
939 entity::Entity,
940 event::{Event, EventWriter, Events},
941 query::With,
942 removal_detection::RemovedComponents,
943 schedule::{IntoSystemConfigs, ScheduleLabel},
944 system::{Commands, Query, Resource},
945 world::{FromWorld, World},
946 };
947
948 use crate::{App, AppExit, Plugin, SubApp, Update};
949
950 struct PluginA;
951 impl Plugin for PluginA {
952 fn build(&self, _app: &mut App) {}
953 }
954 struct PluginB;
955 impl Plugin for PluginB {
956 fn build(&self, _app: &mut App) {}
957 }
958 struct PluginC<T>(T);
959 impl<T: Send + Sync + 'static> Plugin for PluginC<T> {
960 fn build(&self, _app: &mut App) {}
961 }
962 struct PluginD;
963 impl Plugin for PluginD {
964 fn build(&self, _app: &mut App) {}
965 fn is_unique(&self) -> bool {
966 false
967 }
968 }
969
970 struct PluginE;
971
972 impl Plugin for PluginE {
973 fn build(&self, _app: &mut App) {}
974
975 fn finish(&self, app: &mut App) {
976 if app.is_plugin_added::<PluginA>() {
977 panic!("cannot run if PluginA is already registered");
978 }
979 }
980 }
981
982 #[test]
983 fn can_add_two_plugins() {
984 App::new().add_plugins((PluginA, PluginB));
985 }
986
987 #[test]
988 #[should_panic]
989 fn cant_add_twice_the_same_plugin() {
990 App::new().add_plugins((PluginA, PluginA));
991 }
992
993 #[test]
994 fn can_add_twice_the_same_plugin_with_different_type_param() {
995 App::new().add_plugins((PluginC(0), PluginC(true)));
996 }
997
998 #[test]
999 fn can_add_twice_the_same_plugin_not_unique() {
1000 App::new().add_plugins((PluginD, PluginD));
1001 }
1002
1003 #[test]
1004 #[should_panic]
1005 fn cant_call_app_run_from_plugin_build() {
1006 struct PluginRun;
1007 struct InnerPlugin;
1008 impl Plugin for InnerPlugin {
1009 fn build(&self, _: &mut App) {}
1010 }
1011 impl Plugin for PluginRun {
1012 fn build(&self, app: &mut App) {
1013 app.add_plugins(InnerPlugin).run();
1014 }
1015 }
1016 App::new().add_plugins(PluginRun);
1017 }
1018
1019 #[derive(ScheduleLabel, Hash, Clone, PartialEq, Eq, Debug)]
1020 struct EnterMainMenu;
1021
1022 fn bar(mut commands: Commands) {
1023 commands.spawn_empty();
1024 }
1025
1026 fn foo(mut commands: Commands) {
1027 commands.spawn_empty();
1028 }
1029
1030 #[test]
1031 fn add_systems_should_create_schedule_if_it_does_not_exist() {
1032 let mut app = App::new();
1033 app.add_systems(EnterMainMenu, (foo, bar));
1034
1035 app.world_mut().run_schedule(EnterMainMenu);
1036 assert_eq!(app.world().entities().len(), 2);
1037 }
1038
1039 #[test]
1040 #[should_panic]
1041 fn test_is_plugin_added_works_during_finish() {
1042 let mut app = App::new();
1043 app.add_plugins(PluginA);
1044 app.add_plugins(PluginE);
1045 app.finish();
1046 }
1047
1048 #[test]
1049 fn test_derive_app_label() {
1050 use super::AppLabel;
1051 use crate::{self as bevy_app};
1052
1053 #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1054 struct UnitLabel;
1055
1056 #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1057 struct TupleLabel(u32, u32);
1058
1059 #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1060 struct StructLabel {
1061 a: u32,
1062 b: u32,
1063 }
1064
1065 #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1066 struct EmptyTupleLabel();
1067
1068 #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1069 struct EmptyStructLabel {}
1070
1071 #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1072 enum EnumLabel {
1073 #[default]
1074 Unit,
1075 Tuple(u32, u32),
1076 Struct {
1077 a: u32,
1078 b: u32,
1079 },
1080 }
1081
1082 #[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1083 struct GenericLabel<T>(PhantomData<T>);
1084
1085 assert_eq!(UnitLabel.intern(), UnitLabel.intern());
1086 assert_eq!(EnumLabel::Unit.intern(), EnumLabel::Unit.intern());
1087 assert_ne!(UnitLabel.intern(), EnumLabel::Unit.intern());
1088 assert_ne!(UnitLabel.intern(), TupleLabel(0, 0).intern());
1089 assert_ne!(EnumLabel::Unit.intern(), EnumLabel::Tuple(0, 0).intern());
1090
1091 assert_eq!(TupleLabel(0, 0).intern(), TupleLabel(0, 0).intern());
1092 assert_eq!(
1093 EnumLabel::Tuple(0, 0).intern(),
1094 EnumLabel::Tuple(0, 0).intern()
1095 );
1096 assert_ne!(TupleLabel(0, 0).intern(), TupleLabel(0, 1).intern());
1097 assert_ne!(
1098 EnumLabel::Tuple(0, 0).intern(),
1099 EnumLabel::Tuple(0, 1).intern()
1100 );
1101 assert_ne!(TupleLabel(0, 0).intern(), EnumLabel::Tuple(0, 0).intern());
1102 assert_ne!(
1103 TupleLabel(0, 0).intern(),
1104 StructLabel { a: 0, b: 0 }.intern()
1105 );
1106 assert_ne!(
1107 EnumLabel::Tuple(0, 0).intern(),
1108 EnumLabel::Struct { a: 0, b: 0 }.intern()
1109 );
1110
1111 assert_eq!(
1112 StructLabel { a: 0, b: 0 }.intern(),
1113 StructLabel { a: 0, b: 0 }.intern()
1114 );
1115 assert_eq!(
1116 EnumLabel::Struct { a: 0, b: 0 }.intern(),
1117 EnumLabel::Struct { a: 0, b: 0 }.intern()
1118 );
1119 assert_ne!(
1120 StructLabel { a: 0, b: 0 }.intern(),
1121 StructLabel { a: 0, b: 1 }.intern()
1122 );
1123 assert_ne!(
1124 EnumLabel::Struct { a: 0, b: 0 }.intern(),
1125 EnumLabel::Struct { a: 0, b: 1 }.intern()
1126 );
1127 assert_ne!(
1128 StructLabel { a: 0, b: 0 }.intern(),
1129 EnumLabel::Struct { a: 0, b: 0 }.intern()
1130 );
1131 assert_ne!(
1132 StructLabel { a: 0, b: 0 }.intern(),
1133 EnumLabel::Struct { a: 0, b: 0 }.intern()
1134 );
1135 assert_ne!(StructLabel { a: 0, b: 0 }.intern(), UnitLabel.intern(),);
1136 assert_ne!(
1137 EnumLabel::Struct { a: 0, b: 0 }.intern(),
1138 EnumLabel::Unit.intern()
1139 );
1140
1141 assert_eq!(
1142 GenericLabel::<u32>(PhantomData).intern(),
1143 GenericLabel::<u32>(PhantomData).intern()
1144 );
1145 assert_ne!(
1146 GenericLabel::<u32>(PhantomData).intern(),
1147 GenericLabel::<u64>(PhantomData).intern()
1148 );
1149 }
1150
1151 #[test]
1152 fn test_update_clears_trackers_once() {
1153 #[derive(Component, Copy, Clone)]
1154 struct Foo;
1155
1156 let mut app = App::new();
1157 app.world_mut().spawn_batch(iter::repeat(Foo).take(5));
1158
1159 fn despawn_one_foo(mut commands: Commands, foos: Query<Entity, With<Foo>>) {
1160 if let Some(e) = foos.iter().next() {
1161 commands.entity(e).despawn();
1162 };
1163 }
1164 fn check_despawns(mut removed_foos: RemovedComponents<Foo>) {
1165 let mut despawn_count = 0;
1166 for _ in removed_foos.read() {
1167 despawn_count += 1;
1168 }
1169
1170 assert_eq!(despawn_count, 2);
1171 }
1172
1173 app.add_systems(Update, despawn_one_foo);
1174 app.update(); // Frame 0
1175 app.update(); // Frame 1
1176 app.add_systems(Update, check_despawns.after(despawn_one_foo));
1177 app.update(); // Should see despawns from frames 1 & 2, but not frame 0
1178 }
1179
1180 #[test]
1181 fn test_extract_sees_changes() {
1182 use super::AppLabel;
1183 use crate::{self as bevy_app};
1184
1185 #[derive(AppLabel, Clone, Copy, Hash, PartialEq, Eq, Debug)]
1186 struct MySubApp;
1187
1188 #[derive(Resource)]
1189 struct Foo(usize);
1190
1191 let mut app = App::new();
1192 app.world_mut().insert_resource(Foo(0));
1193 app.add_systems(Update, |mut foo: ResMut<Foo>| {
1194 foo.0 += 1;
1195 });
1196
1197 let mut sub_app = SubApp::new();
1198 sub_app.set_extract(|main_world, _sub_world| {
1199 assert!(main_world.get_resource_ref::<Foo>().unwrap().is_changed());
1200 });
1201
1202 app.insert_sub_app(MySubApp, sub_app);
1203
1204 app.update();
1205 }
1206
1207 #[test]
1208 fn runner_returns_correct_exit_code() {
1209 fn raise_exits(mut exits: EventWriter<AppExit>) {
1210 // Exit codes chosen by a fair dice roll.
1211 // Unlikely to overlap with default values.
1212 exits.send(AppExit::Success);
1213 exits.send(AppExit::from_code(4));
1214 exits.send(AppExit::from_code(73));
1215 }
1216
1217 let exit = App::new().add_systems(Update, raise_exits).run();
1218
1219 assert_eq!(exit, AppExit::from_code(4));
1220 }
1221
1222 /// Custom runners should be in charge of when `app::update` gets called as they may need to
1223 /// coordinate some state.
1224 /// bug: <https://github.com/bevyengine/bevy/issues/10385>
1225 /// fix: <https://github.com/bevyengine/bevy/pull/10389>
1226 #[test]
1227 fn regression_test_10385() {
1228 use super::{Res, Resource};
1229 use crate::PreUpdate;
1230
1231 #[derive(Resource)]
1232 struct MyState {}
1233
1234 fn my_runner(mut app: App) -> AppExit {
1235 let my_state = MyState {};
1236 app.world_mut().insert_resource(my_state);
1237
1238 for _ in 0..5 {
1239 app.update();
1240 }
1241
1242 AppExit::Success
1243 }
1244
1245 fn my_system(_: Res<MyState>) {
1246 // access state during app update
1247 }
1248
1249 // Should not panic due to missing resource
1250 App::new()
1251 .set_runner(my_runner)
1252 .add_systems(PreUpdate, my_system)
1253 .run();
1254 }
1255
1256 #[test]
1257 fn app_exit_size() {
1258 // There wont be many of them so the size isn't a issue but
1259 // it's nice they're so small let's keep it that way.
1260 assert_eq!(mem::size_of::<AppExit>(), mem::size_of::<u8>());
1261 }
1262
1263 #[test]
1264 fn initializing_resources_from_world() {
1265 #[derive(Resource)]
1266 struct TestResource;
1267 impl FromWorld for TestResource {
1268 fn from_world(_world: &mut World) -> Self {
1269 TestResource
1270 }
1271 }
1272
1273 #[derive(Resource)]
1274 struct NonSendTestResource {
1275 _marker: PhantomData<Mutex<()>>,
1276 }
1277 impl FromWorld for NonSendTestResource {
1278 fn from_world(_world: &mut World) -> Self {
1279 NonSendTestResource {
1280 _marker: PhantomData,
1281 }
1282 }
1283 }
1284
1285 App::new()
1286 .init_non_send_resource::<NonSendTestResource>()
1287 .init_resource::<TestResource>();
1288 }
1289
1290 #[test]
1291 /// Plugin should not be considered inserted while it's being built
1292 ///
1293 /// bug: <https://github.com/bevyengine/bevy/issues/13815>
1294 fn plugin_should_not_be_added_during_build_time() {
1295 pub struct Foo;
1296
1297 impl Plugin for Foo {
1298 fn build(&self, app: &mut App) {
1299 assert!(!app.is_plugin_added::<Self>());
1300 }
1301 }
1302
1303 App::new().add_plugins(Foo);
1304 }
1305 #[test]
1306 fn events_should_be_updated_once_per_update() {
1307 #[derive(Event, Clone)]
1308 struct TestEvent;
1309
1310 let mut app = App::new();
1311 app.add_event::<TestEvent>();
1312
1313 // Starts empty
1314 let test_events = app.world().resource::<Events<TestEvent>>();
1315 assert_eq!(test_events.len(), 0);
1316 assert_eq!(test_events.iter_current_update_events().count(), 0);
1317 app.update();
1318
1319 // Sending one event
1320 app.world_mut().send_event(TestEvent);
1321
1322 let test_events = app.world().resource::<Events<TestEvent>>();
1323 assert_eq!(test_events.len(), 1);
1324 assert_eq!(test_events.iter_current_update_events().count(), 1);
1325 app.update();
1326
1327 // Sending two events on the next frame
1328 app.world_mut().send_event(TestEvent);
1329 app.world_mut().send_event(TestEvent);
1330
1331 let test_events = app.world().resource::<Events<TestEvent>>();
1332 assert_eq!(test_events.len(), 3); // Events are double-buffered, so we see 1 + 2 = 3
1333 assert_eq!(test_events.iter_current_update_events().count(), 2);
1334 app.update();
1335
1336 // Sending zero events
1337 let test_events = app.world().resource::<Events<TestEvent>>();
1338 assert_eq!(test_events.len(), 2); // Events are double-buffered, so we see 2 + 0 = 2
1339 assert_eq!(test_events.iter_current_update_events().count(), 0);
1340 }
1341}