Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_app/src/app.rs
6595 views
1
use crate::{
2
First, Main, MainSchedulePlugin, PlaceholderPlugin, Plugin, Plugins, PluginsState, SubApp,
3
SubApps,
4
};
5
use alloc::{
6
boxed::Box,
7
string::{String, ToString},
8
vec::Vec,
9
};
10
pub use bevy_derive::AppLabel;
11
use bevy_ecs::{
12
component::RequiredComponentsError,
13
error::{DefaultErrorHandler, ErrorHandler},
14
event::{event_update_system, EventCursor},
15
intern::Interned,
16
prelude::*,
17
schedule::{InternedSystemSet, ScheduleBuildSettings, ScheduleLabel},
18
system::{IntoObserverSystem, ScheduleSystem, SystemId, SystemInput},
19
};
20
use bevy_platform::collections::HashMap;
21
use core::{fmt::Debug, num::NonZero, panic::AssertUnwindSafe};
22
use log::debug;
23
24
#[cfg(feature = "trace")]
25
use tracing::info_span;
26
27
#[cfg(feature = "std")]
28
use std::{
29
panic::{catch_unwind, resume_unwind},
30
process::{ExitCode, Termination},
31
};
32
33
bevy_ecs::define_label!(
34
/// A strongly-typed class of labels used to identify an [`App`].
35
#[diagnostic::on_unimplemented(
36
note = "consider annotating `{Self}` with `#[derive(AppLabel)]`"
37
)]
38
AppLabel,
39
APP_LABEL_INTERNER
40
);
41
42
pub use bevy_ecs::label::DynEq;
43
44
/// A shorthand for `Interned<dyn AppLabel>`.
45
pub type InternedAppLabel = Interned<dyn AppLabel>;
46
47
#[derive(Debug, thiserror::Error)]
48
pub(crate) enum AppError {
49
#[error("duplicate plugin {plugin_name:?}")]
50
DuplicatePlugin { plugin_name: String },
51
}
52
53
/// [`App`] is the primary API for writing user applications. It automates the setup of a
54
/// [standard lifecycle](Main) and provides interface glue for [plugins](`Plugin`).
55
///
56
/// A single [`App`] can contain multiple [`SubApp`] instances, but [`App`] methods only affect
57
/// the "main" one. To access a particular [`SubApp`], use [`get_sub_app`](App::get_sub_app)
58
/// or [`get_sub_app_mut`](App::get_sub_app_mut).
59
///
60
///
61
/// # Examples
62
///
63
/// Here is a simple "Hello World" Bevy app:
64
///
65
/// ```
66
/// # use bevy_app::prelude::*;
67
/// # use bevy_ecs::prelude::*;
68
/// #
69
/// fn main() {
70
/// App::new()
71
/// .add_systems(Update, hello_world_system)
72
/// .run();
73
/// }
74
///
75
/// fn hello_world_system() {
76
/// println!("hello world");
77
/// }
78
/// ```
79
pub struct App {
80
pub(crate) sub_apps: SubApps,
81
/// The function that will manage the app's lifecycle.
82
///
83
/// Bevy provides the [`WinitPlugin`] and [`ScheduleRunnerPlugin`] for windowed and headless
84
/// applications, respectively.
85
///
86
/// [`WinitPlugin`]: https://docs.rs/bevy/latest/bevy/winit/struct.WinitPlugin.html
87
/// [`ScheduleRunnerPlugin`]: https://docs.rs/bevy/latest/bevy/app/struct.ScheduleRunnerPlugin.html
88
pub(crate) runner: RunnerFn,
89
default_error_handler: Option<ErrorHandler>,
90
}
91
92
impl Debug for App {
93
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
94
write!(f, "App {{ sub_apps: ")?;
95
f.debug_map()
96
.entries(self.sub_apps.sub_apps.iter())
97
.finish()?;
98
write!(f, "}}")
99
}
100
}
101
102
impl Default for App {
103
fn default() -> Self {
104
let mut app = App::empty();
105
app.sub_apps.main.update_schedule = Some(Main.intern());
106
107
#[cfg(feature = "bevy_reflect")]
108
{
109
#[cfg(not(feature = "reflect_auto_register"))]
110
app.init_resource::<AppTypeRegistry>();
111
112
#[cfg(feature = "reflect_auto_register")]
113
app.insert_resource(AppTypeRegistry::new_with_derived_types());
114
}
115
116
#[cfg(feature = "reflect_functions")]
117
app.init_resource::<AppFunctionRegistry>();
118
119
app.add_plugins(MainSchedulePlugin);
120
app.add_systems(
121
First,
122
event_update_system
123
.in_set(bevy_ecs::event::EventUpdateSystems)
124
.run_if(bevy_ecs::event::event_update_condition),
125
);
126
app.add_event::<AppExit>();
127
128
app
129
}
130
}
131
132
impl App {
133
/// Creates a new [`App`] with some default structure to enable core engine features.
134
/// This is the preferred constructor for most use cases.
135
pub fn new() -> App {
136
App::default()
137
}
138
139
/// Creates a new empty [`App`] with minimal default configuration.
140
///
141
/// Use this constructor if you want to customize scheduling, exit handling, cleanup, etc.
142
pub fn empty() -> App {
143
Self {
144
sub_apps: SubApps {
145
main: SubApp::new(),
146
sub_apps: HashMap::default(),
147
},
148
runner: Box::new(run_once),
149
default_error_handler: None,
150
}
151
}
152
153
/// Runs the default schedules of all sub-apps (starting with the "main" app) once.
154
pub fn update(&mut self) {
155
if self.is_building_plugins() {
156
panic!("App::update() was called while a plugin was building.");
157
}
158
159
self.sub_apps.update();
160
}
161
162
/// Runs the [`App`] by calling its [runner](Self::set_runner).
163
///
164
/// This will (re)build the [`App`] first. For general usage, see the example on the item
165
/// level documentation.
166
///
167
/// # Caveats
168
///
169
/// Calls to [`App::run()`] will never return on iOS and Web.
170
///
171
/// Headless apps can generally expect this method to return control to the caller when
172
/// it completes, but that is not the case for windowed apps. Windowed apps are typically
173
/// driven by an event loop and some platforms expect the program to terminate when the
174
/// event loop ends.
175
///
176
/// By default, *Bevy* uses the `winit` crate for window creation.
177
///
178
/// # Panics
179
///
180
/// Panics if not all plugins have been built.
181
pub fn run(&mut self) -> AppExit {
182
#[cfg(feature = "trace")]
183
let _bevy_app_run_span = info_span!("bevy_app").entered();
184
if self.is_building_plugins() {
185
panic!("App::run() was called while a plugin was building.");
186
}
187
188
let runner = core::mem::replace(&mut self.runner, Box::new(run_once));
189
let app = core::mem::replace(self, App::empty());
190
(runner)(app)
191
}
192
193
/// Sets the function that will be called when the app is run.
194
///
195
/// The runner function `f` is called only once by [`App::run`]. If the
196
/// presence of a main loop in the app is desired, it is the responsibility of the runner
197
/// function to provide it.
198
///
199
/// The runner function is usually not set manually, but by Bevy integrated plugins
200
/// (e.g. `WinitPlugin`).
201
///
202
/// # Examples
203
///
204
/// ```
205
/// # use bevy_app::prelude::*;
206
/// #
207
/// fn my_runner(mut app: App) -> AppExit {
208
/// loop {
209
/// println!("In main loop");
210
/// app.update();
211
/// if let Some(exit) = app.should_exit() {
212
/// return exit;
213
/// }
214
/// }
215
/// }
216
///
217
/// App::new()
218
/// .set_runner(my_runner);
219
/// ```
220
pub fn set_runner(&mut self, f: impl FnOnce(App) -> AppExit + 'static) -> &mut Self {
221
self.runner = Box::new(f);
222
self
223
}
224
225
/// Returns the state of all plugins. This is usually called by the event loop, but can be
226
/// useful for situations where you want to use [`App::update`].
227
// TODO: &mut self -> &self
228
#[inline]
229
pub fn plugins_state(&mut self) -> PluginsState {
230
let mut overall_plugins_state = match self.main_mut().plugins_state {
231
PluginsState::Adding => {
232
let mut state = PluginsState::Ready;
233
let plugins = core::mem::take(&mut self.main_mut().plugin_registry);
234
for plugin in &plugins {
235
// plugins installed to main need to see all sub-apps
236
if !plugin.ready(self) {
237
state = PluginsState::Adding;
238
break;
239
}
240
}
241
self.main_mut().plugin_registry = plugins;
242
state
243
}
244
state => state,
245
};
246
247
// overall state is the earliest state of any sub-app
248
self.sub_apps.iter_mut().skip(1).for_each(|s| {
249
overall_plugins_state = overall_plugins_state.min(s.plugins_state());
250
});
251
252
overall_plugins_state
253
}
254
255
/// Runs [`Plugin::finish`] for each plugin. This is usually called by the event loop once all
256
/// plugins are ready, but can be useful for situations where you want to use [`App::update`].
257
pub fn finish(&mut self) {
258
#[cfg(feature = "trace")]
259
let _finish_span = info_span!("plugin finish").entered();
260
// plugins installed to main should see all sub-apps
261
// do hokey pokey with a boxed zst plugin (doesn't allocate)
262
let mut hokeypokey: Box<dyn Plugin> = Box::new(HokeyPokey);
263
for i in 0..self.main().plugin_registry.len() {
264
core::mem::swap(&mut self.main_mut().plugin_registry[i], &mut hokeypokey);
265
#[cfg(feature = "trace")]
266
let _plugin_finish_span =
267
info_span!("plugin finish", plugin = hokeypokey.name()).entered();
268
hokeypokey.finish(self);
269
core::mem::swap(&mut self.main_mut().plugin_registry[i], &mut hokeypokey);
270
}
271
self.main_mut().plugins_state = PluginsState::Finished;
272
self.sub_apps.iter_mut().skip(1).for_each(SubApp::finish);
273
}
274
275
/// Runs [`Plugin::cleanup`] for each plugin. This is usually called by the event loop after
276
/// [`App::finish`], but can be useful for situations where you want to use [`App::update`].
277
pub fn cleanup(&mut self) {
278
#[cfg(feature = "trace")]
279
let _cleanup_span = info_span!("plugin cleanup").entered();
280
// plugins installed to main should see all sub-apps
281
// do hokey pokey with a boxed zst plugin (doesn't allocate)
282
let mut hokeypokey: Box<dyn Plugin> = Box::new(HokeyPokey);
283
for i in 0..self.main().plugin_registry.len() {
284
core::mem::swap(&mut self.main_mut().plugin_registry[i], &mut hokeypokey);
285
#[cfg(feature = "trace")]
286
let _plugin_cleanup_span =
287
info_span!("plugin cleanup", plugin = hokeypokey.name()).entered();
288
hokeypokey.cleanup(self);
289
core::mem::swap(&mut self.main_mut().plugin_registry[i], &mut hokeypokey);
290
}
291
self.main_mut().plugins_state = PluginsState::Cleaned;
292
self.sub_apps.iter_mut().skip(1).for_each(SubApp::cleanup);
293
}
294
295
/// Returns `true` if any of the sub-apps are building plugins.
296
pub(crate) fn is_building_plugins(&self) -> bool {
297
self.sub_apps.iter().any(SubApp::is_building_plugins)
298
}
299
300
/// Adds one or more systems to the given schedule in this app's [`Schedules`].
301
///
302
/// # Examples
303
///
304
/// ```
305
/// # use bevy_app::prelude::*;
306
/// # use bevy_ecs::prelude::*;
307
/// #
308
/// # let mut app = App::new();
309
/// # fn system_a() {}
310
/// # fn system_b() {}
311
/// # fn system_c() {}
312
/// # fn should_run() -> bool { true }
313
/// #
314
/// app.add_systems(Update, (system_a, system_b, system_c));
315
/// app.add_systems(Update, (system_a, system_b).run_if(should_run));
316
/// ```
317
pub fn add_systems<M>(
318
&mut self,
319
schedule: impl ScheduleLabel,
320
systems: impl IntoScheduleConfigs<ScheduleSystem, M>,
321
) -> &mut Self {
322
self.main_mut().add_systems(schedule, systems);
323
self
324
}
325
326
/// Registers a system and returns a [`SystemId`] so it can later be called by [`World::run_system`].
327
///
328
/// It's possible to register the same systems more than once, they'll be stored separately.
329
///
330
/// This is different from adding systems to a [`Schedule`] with [`App::add_systems`],
331
/// because the [`SystemId`] that is returned can be used anywhere in the [`World`] to run the associated system.
332
/// This allows for running systems in a push-based fashion.
333
/// Using a [`Schedule`] is still preferred for most cases
334
/// due to its better performance and ability to run non-conflicting systems simultaneously.
335
pub fn register_system<I, O, M>(
336
&mut self,
337
system: impl IntoSystem<I, O, M> + 'static,
338
) -> SystemId<I, O>
339
where
340
I: SystemInput + 'static,
341
O: 'static,
342
{
343
self.main_mut().register_system(system)
344
}
345
346
/// Configures a collection of system sets in the provided schedule, adding any sets that do not exist.
347
#[track_caller]
348
pub fn configure_sets<M>(
349
&mut self,
350
schedule: impl ScheduleLabel,
351
sets: impl IntoScheduleConfigs<InternedSystemSet, M>,
352
) -> &mut Self {
353
self.main_mut().configure_sets(schedule, sets);
354
self
355
}
356
357
/// Initializes [`BufferedEvent`] handling for `T` by inserting an event queue resource ([`Events::<T>`])
358
/// and scheduling an [`event_update_system`] in [`First`].
359
///
360
/// See [`Events`] for information on how to define events.
361
///
362
/// # Examples
363
///
364
/// ```
365
/// # use bevy_app::prelude::*;
366
/// # use bevy_ecs::prelude::*;
367
/// #
368
/// # #[derive(BufferedEvent)]
369
/// # struct MyEvent;
370
/// # let mut app = App::new();
371
/// #
372
/// app.add_event::<MyEvent>();
373
/// ```
374
pub fn add_event<T>(&mut self) -> &mut Self
375
where
376
T: BufferedEvent,
377
{
378
self.main_mut().add_event::<T>();
379
self
380
}
381
382
/// Inserts the [`Resource`] into the app, overwriting any existing resource of the same type.
383
///
384
/// There is also an [`init_resource`](Self::init_resource) for resources that have
385
/// [`Default`] or [`FromWorld`] implementations.
386
///
387
/// # Examples
388
///
389
/// ```
390
/// # use bevy_app::prelude::*;
391
/// # use bevy_ecs::prelude::*;
392
/// #
393
/// #[derive(Resource)]
394
/// struct MyCounter {
395
/// counter: usize,
396
/// }
397
///
398
/// App::new()
399
/// .insert_resource(MyCounter { counter: 0 });
400
/// ```
401
pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
402
self.main_mut().insert_resource(resource);
403
self
404
}
405
406
/// Inserts the [`Resource`], initialized with its default value, into the app,
407
/// if there is no existing instance of `R`.
408
///
409
/// `R` must implement [`FromWorld`].
410
/// If `R` implements [`Default`], [`FromWorld`] will be automatically implemented and
411
/// initialize the [`Resource`] with [`Default::default`].
412
///
413
/// # Examples
414
///
415
/// ```
416
/// # use bevy_app::prelude::*;
417
/// # use bevy_ecs::prelude::*;
418
/// #
419
/// #[derive(Resource)]
420
/// struct MyCounter {
421
/// counter: usize,
422
/// }
423
///
424
/// impl Default for MyCounter {
425
/// fn default() -> MyCounter {
426
/// MyCounter {
427
/// counter: 100
428
/// }
429
/// }
430
/// }
431
///
432
/// App::new()
433
/// .init_resource::<MyCounter>();
434
/// ```
435
pub fn init_resource<R: Resource + FromWorld>(&mut self) -> &mut Self {
436
self.main_mut().init_resource::<R>();
437
self
438
}
439
440
/// Inserts the [`!Send`](Send) resource into the app, overwriting any existing resource
441
/// of the same type.
442
///
443
/// There is also an [`init_non_send_resource`](Self::init_non_send_resource) for
444
/// resources that implement [`Default`]
445
///
446
/// # Examples
447
///
448
/// ```
449
/// # use bevy_app::prelude::*;
450
/// # use bevy_ecs::prelude::*;
451
/// #
452
/// struct MyCounter {
453
/// counter: usize,
454
/// }
455
///
456
/// App::new()
457
/// .insert_non_send_resource(MyCounter { counter: 0 });
458
/// ```
459
pub fn insert_non_send_resource<R: 'static>(&mut self, resource: R) -> &mut Self {
460
self.world_mut().insert_non_send_resource(resource);
461
self
462
}
463
464
/// Inserts the [`!Send`](Send) resource into the app if there is no existing instance of `R`.
465
///
466
/// `R` must implement [`FromWorld`].
467
/// If `R` implements [`Default`], [`FromWorld`] will be automatically implemented and
468
/// initialize the [`Resource`] with [`Default::default`].
469
pub fn init_non_send_resource<R: 'static + FromWorld>(&mut self) -> &mut Self {
470
self.world_mut().init_non_send_resource::<R>();
471
self
472
}
473
474
pub(crate) fn add_boxed_plugin(
475
&mut self,
476
plugin: Box<dyn Plugin>,
477
) -> Result<&mut Self, AppError> {
478
debug!("added plugin: {}", plugin.name());
479
if plugin.is_unique() && self.main_mut().plugin_names.contains(plugin.name()) {
480
Err(AppError::DuplicatePlugin {
481
plugin_name: plugin.name().to_string(),
482
})?;
483
}
484
485
// Reserve position in the plugin registry. If the plugin adds more plugins,
486
// they'll all end up in insertion order.
487
let index = self.main().plugin_registry.len();
488
self.main_mut()
489
.plugin_registry
490
.push(Box::new(PlaceholderPlugin));
491
492
self.main_mut().plugin_build_depth += 1;
493
494
#[cfg(feature = "trace")]
495
let _plugin_build_span = info_span!("plugin build", plugin = plugin.name()).entered();
496
497
let f = AssertUnwindSafe(|| plugin.build(self));
498
499
#[cfg(feature = "std")]
500
let result = catch_unwind(f);
501
502
#[cfg(not(feature = "std"))]
503
f();
504
505
self.main_mut()
506
.plugin_names
507
.insert(plugin.name().to_string());
508
self.main_mut().plugin_build_depth -= 1;
509
510
#[cfg(feature = "std")]
511
if let Err(payload) = result {
512
resume_unwind(payload);
513
}
514
515
self.main_mut().plugin_registry[index] = plugin;
516
Ok(self)
517
}
518
519
/// Returns `true` if the [`Plugin`] has already been added.
520
pub fn is_plugin_added<T>(&self) -> bool
521
where
522
T: Plugin,
523
{
524
self.main().is_plugin_added::<T>()
525
}
526
527
/// Returns a vector of references to all plugins of type `T` that have been added.
528
///
529
/// This can be used to read the settings of any existing plugins.
530
/// This vector will be empty if no plugins of that type have been added.
531
/// If multiple copies of the same plugin are added to the [`App`], they will be listed in insertion order in this vector.
532
///
533
/// ```
534
/// # use bevy_app::prelude::*;
535
/// # #[derive(Default)]
536
/// # struct ImagePlugin {
537
/// # default_sampler: bool,
538
/// # }
539
/// # impl Plugin for ImagePlugin {
540
/// # fn build(&self, app: &mut App) {}
541
/// # }
542
/// # let mut app = App::new();
543
/// # app.add_plugins(ImagePlugin::default());
544
/// let default_sampler = app.get_added_plugins::<ImagePlugin>()[0].default_sampler;
545
/// ```
546
pub fn get_added_plugins<T>(&self) -> Vec<&T>
547
where
548
T: Plugin,
549
{
550
self.main().get_added_plugins::<T>()
551
}
552
553
/// Installs a [`Plugin`] collection.
554
///
555
/// Bevy prioritizes modularity as a core principle. **All** engine features are implemented
556
/// as plugins, even the complex ones like rendering.
557
///
558
/// [`Plugin`]s can be grouped into a set by using a [`PluginGroup`].
559
///
560
/// There are built-in [`PluginGroup`]s that provide core engine functionality.
561
/// The [`PluginGroup`]s available by default are `DefaultPlugins` and `MinimalPlugins`.
562
///
563
/// To customize the plugins in the group (reorder, disable a plugin, add a new plugin
564
/// before / after another plugin), call [`build()`](super::PluginGroup::build) on the group,
565
/// which will convert it to a [`PluginGroupBuilder`](crate::PluginGroupBuilder).
566
///
567
/// You can also specify a group of [`Plugin`]s by using a tuple over [`Plugin`]s and
568
/// [`PluginGroup`]s. See [`Plugins`] for more details.
569
///
570
/// ## Examples
571
/// ```
572
/// # use bevy_app::{prelude::*, PluginGroupBuilder, NoopPluginGroup as MinimalPlugins};
573
/// #
574
/// # // Dummies created to avoid using `bevy_log`,
575
/// # // which pulls in too many dependencies and breaks rust-analyzer
576
/// # pub struct LogPlugin;
577
/// # impl Plugin for LogPlugin {
578
/// # fn build(&self, app: &mut App) {}
579
/// # }
580
/// App::new()
581
/// .add_plugins(MinimalPlugins);
582
/// App::new()
583
/// .add_plugins((MinimalPlugins, LogPlugin));
584
/// ```
585
///
586
/// # Panics
587
///
588
/// Panics if one of the plugins had already been added to the application.
589
///
590
/// [`PluginGroup`]:super::PluginGroup
591
#[track_caller]
592
pub fn add_plugins<M>(&mut self, plugins: impl Plugins<M>) -> &mut Self {
593
if matches!(
594
self.plugins_state(),
595
PluginsState::Cleaned | PluginsState::Finished
596
) {
597
panic!(
598
"Plugins cannot be added after App::cleanup() or App::finish() has been called."
599
);
600
}
601
plugins.add_to_app(self);
602
self
603
}
604
605
/// Registers the type `T` in the [`AppTypeRegistry`] resource,
606
/// adding reflect data as specified in the [`Reflect`](bevy_reflect::Reflect) derive:
607
/// ```ignore (No serde "derive" feature)
608
/// #[derive(Component, Serialize, Deserialize, Reflect)]
609
/// #[reflect(Component, Serialize, Deserialize)] // will register ReflectComponent, ReflectSerialize, ReflectDeserialize
610
/// ```
611
///
612
/// See [`bevy_reflect::TypeRegistry::register`] for more information.
613
#[cfg(feature = "bevy_reflect")]
614
pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
615
self.main_mut().register_type::<T>();
616
self
617
}
618
619
/// Associates type data `D` with type `T` in the [`AppTypeRegistry`] resource.
620
///
621
/// Most of the time [`register_type`](Self::register_type) can be used instead to register a
622
/// type you derived [`Reflect`](bevy_reflect::Reflect) for. However, in cases where you want to
623
/// add a piece of type data that was not included in the list of `#[reflect(...)]` type data in
624
/// the derive, or where the type is generic and cannot register e.g. `ReflectSerialize`
625
/// unconditionally without knowing the specific type parameters, this method can be used to
626
/// insert additional type data.
627
///
628
/// # Example
629
/// ```
630
/// use bevy_app::App;
631
/// use bevy_reflect::{ReflectSerialize, ReflectDeserialize};
632
///
633
/// App::new()
634
/// .register_type::<Option<String>>()
635
/// .register_type_data::<Option<String>, ReflectSerialize>()
636
/// .register_type_data::<Option<String>, ReflectDeserialize>();
637
/// ```
638
///
639
/// See [`bevy_reflect::TypeRegistry::register_type_data`].
640
#[cfg(feature = "bevy_reflect")]
641
pub fn register_type_data<
642
T: bevy_reflect::Reflect + bevy_reflect::TypePath,
643
D: bevy_reflect::TypeData + bevy_reflect::FromType<T>,
644
>(
645
&mut self,
646
) -> &mut Self {
647
self.main_mut().register_type_data::<T, D>();
648
self
649
}
650
651
/// Registers the given function into the [`AppFunctionRegistry`] resource.
652
///
653
/// The given function will internally be stored as a [`DynamicFunction`]
654
/// and mapped according to its [name].
655
///
656
/// Because the function must have a name,
657
/// anonymous functions (e.g. `|a: i32, b: i32| { a + b }`) and closures must instead
658
/// be registered using [`register_function_with_name`] or converted to a [`DynamicFunction`]
659
/// and named using [`DynamicFunction::with_name`].
660
/// Failure to do so will result in a panic.
661
///
662
/// Only types that implement [`IntoFunction`] may be registered via this method.
663
///
664
/// See [`FunctionRegistry::register`] for more information.
665
///
666
/// # Panics
667
///
668
/// Panics if a function has already been registered with the given name
669
/// or if the function is missing a name (such as when it is an anonymous function).
670
///
671
/// # Examples
672
///
673
/// ```
674
/// use bevy_app::App;
675
///
676
/// fn add(a: i32, b: i32) -> i32 {
677
/// a + b
678
/// }
679
///
680
/// App::new().register_function(add);
681
/// ```
682
///
683
/// Functions cannot be registered more than once.
684
///
685
/// ```should_panic
686
/// use bevy_app::App;
687
///
688
/// fn add(a: i32, b: i32) -> i32 {
689
/// a + b
690
/// }
691
///
692
/// App::new()
693
/// .register_function(add)
694
/// // Panic! A function has already been registered with the name "my_function"
695
/// .register_function(add);
696
/// ```
697
///
698
/// Anonymous functions and closures should be registered using [`register_function_with_name`] or given a name using [`DynamicFunction::with_name`].
699
///
700
/// ```should_panic
701
/// use bevy_app::App;
702
///
703
/// // Panic! Anonymous functions cannot be registered using `register_function`
704
/// App::new().register_function(|a: i32, b: i32| a + b);
705
/// ```
706
///
707
/// [`register_function_with_name`]: Self::register_function_with_name
708
/// [`DynamicFunction`]: bevy_reflect::func::DynamicFunction
709
/// [name]: bevy_reflect::func::FunctionInfo::name
710
/// [`DynamicFunction::with_name`]: bevy_reflect::func::DynamicFunction::with_name
711
/// [`IntoFunction`]: bevy_reflect::func::IntoFunction
712
/// [`FunctionRegistry::register`]: bevy_reflect::func::FunctionRegistry::register
713
#[cfg(feature = "reflect_functions")]
714
pub fn register_function<F, Marker>(&mut self, function: F) -> &mut Self
715
where
716
F: bevy_reflect::func::IntoFunction<'static, Marker> + 'static,
717
{
718
self.main_mut().register_function(function);
719
self
720
}
721
722
/// Registers the given function or closure into the [`AppFunctionRegistry`] resource using the given name.
723
///
724
/// To avoid conflicts, it's recommended to use a unique name for the function.
725
/// This can be achieved by "namespacing" the function with a unique identifier,
726
/// such as the name of your crate.
727
///
728
/// For example, to register a function, `add`, from a crate, `my_crate`,
729
/// you could use the name, `"my_crate::add"`.
730
///
731
/// Another approach could be to use the [type name] of the function,
732
/// however, it should be noted that anonymous functions do _not_ have unique type names.
733
///
734
/// For named functions (e.g. `fn add(a: i32, b: i32) -> i32 { a + b }`) where a custom name is not needed,
735
/// it's recommended to use [`register_function`] instead as the generated name is guaranteed to be unique.
736
///
737
/// Only types that implement [`IntoFunction`] may be registered via this method.
738
///
739
/// See [`FunctionRegistry::register_with_name`] for more information.
740
///
741
/// # Panics
742
///
743
/// Panics if a function has already been registered with the given name.
744
///
745
/// # Examples
746
///
747
/// ```
748
/// use bevy_app::App;
749
///
750
/// fn mul(a: i32, b: i32) -> i32 {
751
/// a * b
752
/// }
753
///
754
/// let div = |a: i32, b: i32| a / b;
755
///
756
/// App::new()
757
/// // Registering an anonymous function with a unique name
758
/// .register_function_with_name("my_crate::add", |a: i32, b: i32| {
759
/// a + b
760
/// })
761
/// // Registering an existing function with its type name
762
/// .register_function_with_name(std::any::type_name_of_val(&mul), mul)
763
/// // Registering an existing function with a custom name
764
/// .register_function_with_name("my_crate::mul", mul)
765
/// // Be careful not to register anonymous functions with their type name.
766
/// // This code works but registers the function with a non-unique name like `foo::bar::{{closure}}`
767
/// .register_function_with_name(std::any::type_name_of_val(&div), div);
768
/// ```
769
///
770
/// Names must be unique.
771
///
772
/// ```should_panic
773
/// use bevy_app::App;
774
///
775
/// fn one() {}
776
/// fn two() {}
777
///
778
/// App::new()
779
/// .register_function_with_name("my_function", one)
780
/// // Panic! A function has already been registered with the name "my_function"
781
/// .register_function_with_name("my_function", two);
782
/// ```
783
///
784
/// [type name]: std::any::type_name
785
/// [`register_function`]: Self::register_function
786
/// [`IntoFunction`]: bevy_reflect::func::IntoFunction
787
/// [`FunctionRegistry::register_with_name`]: bevy_reflect::func::FunctionRegistry::register_with_name
788
#[cfg(feature = "reflect_functions")]
789
pub fn register_function_with_name<F, Marker>(
790
&mut self,
791
name: impl Into<alloc::borrow::Cow<'static, str>>,
792
function: F,
793
) -> &mut Self
794
where
795
F: bevy_reflect::func::IntoFunction<'static, Marker> + 'static,
796
{
797
self.main_mut().register_function_with_name(name, function);
798
self
799
}
800
801
/// Registers the given component `R` as a [required component] for `T`.
802
///
803
/// When `T` is added to an entity, `R` and its own required components will also be added
804
/// if `R` was not already provided. The [`Default`] `constructor` will be used for the creation of `R`.
805
/// If a custom constructor is desired, use [`App::register_required_components_with`] instead.
806
///
807
/// For the non-panicking version, see [`App::try_register_required_components`].
808
///
809
/// Note that requirements must currently be registered before `T` is inserted into the world
810
/// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future.
811
///
812
/// [required component]: Component#required-components
813
///
814
/// # Panics
815
///
816
/// Panics if `R` is already a directly required component for `T`, or if `T` has ever been added
817
/// on an entity before the registration.
818
///
819
/// Indirect requirements through other components are allowed. In those cases, any existing requirements
820
/// will only be overwritten if the new requirement is more specific.
821
///
822
/// # Example
823
///
824
/// ```
825
/// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup};
826
/// # use bevy_ecs::prelude::*;
827
/// #[derive(Component)]
828
/// struct A;
829
///
830
/// #[derive(Component, Default, PartialEq, Eq, Debug)]
831
/// struct B(usize);
832
///
833
/// #[derive(Component, Default, PartialEq, Eq, Debug)]
834
/// struct C(u32);
835
///
836
/// # let mut app = App::new();
837
/// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup);
838
/// // Register B as required by A and C as required by B.
839
/// app.register_required_components::<A, B>();
840
/// app.register_required_components::<B, C>();
841
///
842
/// fn setup(mut commands: Commands) {
843
/// // This will implicitly also insert B and C with their Default constructors.
844
/// commands.spawn(A);
845
/// }
846
///
847
/// fn validate(query: Option<Single<(&A, &B, &C)>>) {
848
/// let (a, b, c) = query.unwrap().into_inner();
849
/// assert_eq!(b, &B(0));
850
/// assert_eq!(c, &C(0));
851
/// }
852
/// # app.update();
853
/// ```
854
pub fn register_required_components<T: Component, R: Component + Default>(
855
&mut self,
856
) -> &mut Self {
857
self.world_mut().register_required_components::<T, R>();
858
self
859
}
860
861
/// Registers the given component `R` as a [required component] for `T`.
862
///
863
/// When `T` is added to an entity, `R` and its own required components will also be added
864
/// if `R` was not already provided. The given `constructor` will be used for the creation of `R`.
865
/// If a [`Default`] constructor is desired, use [`App::register_required_components`] instead.
866
///
867
/// For the non-panicking version, see [`App::try_register_required_components_with`].
868
///
869
/// Note that requirements must currently be registered before `T` is inserted into the world
870
/// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future.
871
///
872
/// [required component]: Component#required-components
873
///
874
/// # Panics
875
///
876
/// Panics if `R` is already a directly required component for `T`, or if `T` has ever been added
877
/// on an entity before the registration.
878
///
879
/// Indirect requirements through other components are allowed. In those cases, any existing requirements
880
/// will only be overwritten if the new requirement is more specific.
881
///
882
/// # Example
883
///
884
/// ```
885
/// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup};
886
/// # use bevy_ecs::prelude::*;
887
/// #[derive(Component)]
888
/// struct A;
889
///
890
/// #[derive(Component, Default, PartialEq, Eq, Debug)]
891
/// struct B(usize);
892
///
893
/// #[derive(Component, Default, PartialEq, Eq, Debug)]
894
/// struct C(u32);
895
///
896
/// # let mut app = App::new();
897
/// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup);
898
/// // Register B and C as required by A and C as required by B.
899
/// // A requiring C directly will overwrite the indirect requirement through B.
900
/// app.register_required_components::<A, B>();
901
/// app.register_required_components_with::<B, C>(|| C(1));
902
/// app.register_required_components_with::<A, C>(|| C(2));
903
///
904
/// fn setup(mut commands: Commands) {
905
/// // This will implicitly also insert B with its Default constructor and C
906
/// // with the custom constructor defined by A.
907
/// commands.spawn(A);
908
/// }
909
///
910
/// fn validate(query: Option<Single<(&A, &B, &C)>>) {
911
/// let (a, b, c) = query.unwrap().into_inner();
912
/// assert_eq!(b, &B(0));
913
/// assert_eq!(c, &C(2));
914
/// }
915
/// # app.update();
916
/// ```
917
pub fn register_required_components_with<T: Component, R: Component>(
918
&mut self,
919
constructor: fn() -> R,
920
) -> &mut Self {
921
self.world_mut()
922
.register_required_components_with::<T, R>(constructor);
923
self
924
}
925
926
/// Tries to register the given component `R` as a [required component] for `T`.
927
///
928
/// When `T` is added to an entity, `R` and its own required components will also be added
929
/// if `R` was not already provided. The [`Default`] `constructor` will be used for the creation of `R`.
930
/// If a custom constructor is desired, use [`App::register_required_components_with`] instead.
931
///
932
/// For the panicking version, see [`App::register_required_components`].
933
///
934
/// Note that requirements must currently be registered before `T` is inserted into the world
935
/// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future.
936
///
937
/// [required component]: Component#required-components
938
///
939
/// # Errors
940
///
941
/// Returns a [`RequiredComponentsError`] if `R` is already a directly required component for `T`, or if `T` has ever been added
942
/// on an entity before the registration.
943
///
944
/// Indirect requirements through other components are allowed. In those cases, any existing requirements
945
/// will only be overwritten if the new requirement is more specific.
946
///
947
/// # Example
948
///
949
/// ```
950
/// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup};
951
/// # use bevy_ecs::prelude::*;
952
/// #[derive(Component)]
953
/// struct A;
954
///
955
/// #[derive(Component, Default, PartialEq, Eq, Debug)]
956
/// struct B(usize);
957
///
958
/// #[derive(Component, Default, PartialEq, Eq, Debug)]
959
/// struct C(u32);
960
///
961
/// # let mut app = App::new();
962
/// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup);
963
/// // Register B as required by A and C as required by B.
964
/// app.register_required_components::<A, B>();
965
/// app.register_required_components::<B, C>();
966
///
967
/// // Duplicate registration! This will fail.
968
/// assert!(app.try_register_required_components::<A, B>().is_err());
969
///
970
/// fn setup(mut commands: Commands) {
971
/// // This will implicitly also insert B and C with their Default constructors.
972
/// commands.spawn(A);
973
/// }
974
///
975
/// fn validate(query: Option<Single<(&A, &B, &C)>>) {
976
/// let (a, b, c) = query.unwrap().into_inner();
977
/// assert_eq!(b, &B(0));
978
/// assert_eq!(c, &C(0));
979
/// }
980
/// # app.update();
981
/// ```
982
pub fn try_register_required_components<T: Component, R: Component + Default>(
983
&mut self,
984
) -> Result<(), RequiredComponentsError> {
985
self.world_mut().try_register_required_components::<T, R>()
986
}
987
988
/// Tries to register the given component `R` as a [required component] for `T`.
989
///
990
/// When `T` is added to an entity, `R` and its own required components will also be added
991
/// if `R` was not already provided. The given `constructor` will be used for the creation of `R`.
992
/// If a [`Default`] constructor is desired, use [`App::register_required_components`] instead.
993
///
994
/// For the panicking version, see [`App::register_required_components_with`].
995
///
996
/// Note that requirements must currently be registered before `T` is inserted into the world
997
/// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future.
998
///
999
/// [required component]: Component#required-components
1000
///
1001
/// # Errors
1002
///
1003
/// Returns a [`RequiredComponentsError`] if `R` is already a directly required component for `T`, or if `T` has ever been added
1004
/// on an entity before the registration.
1005
///
1006
/// Indirect requirements through other components are allowed. In those cases, any existing requirements
1007
/// will only be overwritten if the new requirement is more specific.
1008
///
1009
/// # Example
1010
///
1011
/// ```
1012
/// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup};
1013
/// # use bevy_ecs::prelude::*;
1014
/// #[derive(Component)]
1015
/// struct A;
1016
///
1017
/// #[derive(Component, Default, PartialEq, Eq, Debug)]
1018
/// struct B(usize);
1019
///
1020
/// #[derive(Component, Default, PartialEq, Eq, Debug)]
1021
/// struct C(u32);
1022
///
1023
/// # let mut app = App::new();
1024
/// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup);
1025
/// // Register B and C as required by A and C as required by B.
1026
/// // A requiring C directly will overwrite the indirect requirement through B.
1027
/// app.register_required_components::<A, B>();
1028
/// app.register_required_components_with::<B, C>(|| C(1));
1029
/// app.register_required_components_with::<A, C>(|| C(2));
1030
///
1031
/// // Duplicate registration! Even if the constructors were different, this would fail.
1032
/// assert!(app.try_register_required_components_with::<B, C>(|| C(1)).is_err());
1033
///
1034
/// fn setup(mut commands: Commands) {
1035
/// // This will implicitly also insert B with its Default constructor and C
1036
/// // with the custom constructor defined by A.
1037
/// commands.spawn(A);
1038
/// }
1039
///
1040
/// fn validate(query: Option<Single<(&A, &B, &C)>>) {
1041
/// let (a, b, c) = query.unwrap().into_inner();
1042
/// assert_eq!(b, &B(0));
1043
/// assert_eq!(c, &C(2));
1044
/// }
1045
/// # app.update();
1046
/// ```
1047
pub fn try_register_required_components_with<T: Component, R: Component>(
1048
&mut self,
1049
constructor: fn() -> R,
1050
) -> Result<(), RequiredComponentsError> {
1051
self.world_mut()
1052
.try_register_required_components_with::<T, R>(constructor)
1053
}
1054
1055
/// Registers a component type as "disabling",
1056
/// using [default query filters](bevy_ecs::entity_disabling::DefaultQueryFilters) to exclude entities with the component from queries.
1057
///
1058
/// # Warning
1059
///
1060
/// As discussed in the [module docs](bevy_ecs::entity_disabling), this can have performance implications,
1061
/// as well as create interoperability issues, and should be used with caution.
1062
pub fn register_disabling_component<C: Component>(&mut self) {
1063
self.world_mut().register_disabling_component::<C>();
1064
}
1065
1066
/// Returns a reference to the main [`SubApp`]'s [`World`]. This is the same as calling
1067
/// [`app.main().world()`].
1068
///
1069
/// [`app.main().world()`]: SubApp::world
1070
pub fn world(&self) -> &World {
1071
self.main().world()
1072
}
1073
1074
/// Returns a mutable reference to the main [`SubApp`]'s [`World`]. This is the same as calling
1075
/// [`app.main_mut().world_mut()`].
1076
///
1077
/// [`app.main_mut().world_mut()`]: SubApp::world_mut
1078
pub fn world_mut(&mut self) -> &mut World {
1079
self.main_mut().world_mut()
1080
}
1081
1082
/// Returns a reference to the main [`SubApp`].
1083
pub fn main(&self) -> &SubApp {
1084
&self.sub_apps.main
1085
}
1086
1087
/// Returns a mutable reference to the main [`SubApp`].
1088
pub fn main_mut(&mut self) -> &mut SubApp {
1089
&mut self.sub_apps.main
1090
}
1091
1092
/// Returns a reference to the [`SubApps`] collection.
1093
pub fn sub_apps(&self) -> &SubApps {
1094
&self.sub_apps
1095
}
1096
1097
/// Returns a mutable reference to the [`SubApps`] collection.
1098
pub fn sub_apps_mut(&mut self) -> &mut SubApps {
1099
&mut self.sub_apps
1100
}
1101
1102
/// Returns a reference to the [`SubApp`] with the given label.
1103
///
1104
/// # Panics
1105
///
1106
/// Panics if the [`SubApp`] doesn't exist.
1107
pub fn sub_app(&self, label: impl AppLabel) -> &SubApp {
1108
let str = label.intern();
1109
self.get_sub_app(label).unwrap_or_else(|| {
1110
panic!("No sub-app with label '{:?}' exists.", str);
1111
})
1112
}
1113
1114
/// Returns a reference to the [`SubApp`] with the given label.
1115
///
1116
/// # Panics
1117
///
1118
/// Panics if the [`SubApp`] doesn't exist.
1119
pub fn sub_app_mut(&mut self, label: impl AppLabel) -> &mut SubApp {
1120
let str = label.intern();
1121
self.get_sub_app_mut(label).unwrap_or_else(|| {
1122
panic!("No sub-app with label '{:?}' exists.", str);
1123
})
1124
}
1125
1126
/// Returns a reference to the [`SubApp`] with the given label, if it exists.
1127
pub fn get_sub_app(&self, label: impl AppLabel) -> Option<&SubApp> {
1128
self.sub_apps.sub_apps.get(&label.intern())
1129
}
1130
1131
/// Returns a mutable reference to the [`SubApp`] with the given label, if it exists.
1132
pub fn get_sub_app_mut(&mut self, label: impl AppLabel) -> Option<&mut SubApp> {
1133
self.sub_apps.sub_apps.get_mut(&label.intern())
1134
}
1135
1136
/// Inserts a [`SubApp`] with the given label.
1137
pub fn insert_sub_app(&mut self, label: impl AppLabel, mut sub_app: SubApp) {
1138
if let Some(handler) = self.default_error_handler {
1139
sub_app
1140
.world_mut()
1141
.get_resource_or_insert_with(|| DefaultErrorHandler(handler));
1142
}
1143
self.sub_apps.sub_apps.insert(label.intern(), sub_app);
1144
}
1145
1146
/// Removes the [`SubApp`] with the given label, if it exists.
1147
pub fn remove_sub_app(&mut self, label: impl AppLabel) -> Option<SubApp> {
1148
self.sub_apps.sub_apps.remove(&label.intern())
1149
}
1150
1151
/// Extract data from the main world into the [`SubApp`] with the given label and perform an update if it exists.
1152
pub fn update_sub_app_by_label(&mut self, label: impl AppLabel) {
1153
self.sub_apps.update_subapp_by_label(label);
1154
}
1155
1156
/// Inserts a new `schedule` under the provided `label`, overwriting any existing
1157
/// schedule with the same label.
1158
pub fn add_schedule(&mut self, schedule: Schedule) -> &mut Self {
1159
self.main_mut().add_schedule(schedule);
1160
self
1161
}
1162
1163
/// Initializes an empty `schedule` under the provided `label`, if it does not exist.
1164
///
1165
/// See [`add_schedule`](Self::add_schedule) to insert an existing schedule.
1166
pub fn init_schedule(&mut self, label: impl ScheduleLabel) -> &mut Self {
1167
self.main_mut().init_schedule(label);
1168
self
1169
}
1170
1171
/// Returns a reference to the [`Schedule`] with the provided `label` if it exists.
1172
pub fn get_schedule(&self, label: impl ScheduleLabel) -> Option<&Schedule> {
1173
self.main().get_schedule(label)
1174
}
1175
1176
/// Returns a mutable reference to the [`Schedule`] with the provided `label` if it exists.
1177
pub fn get_schedule_mut(&mut self, label: impl ScheduleLabel) -> Option<&mut Schedule> {
1178
self.main_mut().get_schedule_mut(label)
1179
}
1180
1181
/// Runs function `f` with the [`Schedule`] associated with `label`.
1182
///
1183
/// **Note:** This will create the schedule if it does not already exist.
1184
pub fn edit_schedule(
1185
&mut self,
1186
label: impl ScheduleLabel,
1187
f: impl FnMut(&mut Schedule),
1188
) -> &mut Self {
1189
self.main_mut().edit_schedule(label, f);
1190
self
1191
}
1192
1193
/// Applies the provided [`ScheduleBuildSettings`] to all schedules.
1194
pub fn configure_schedules(
1195
&mut self,
1196
schedule_build_settings: ScheduleBuildSettings,
1197
) -> &mut Self {
1198
self.main_mut().configure_schedules(schedule_build_settings);
1199
self
1200
}
1201
1202
/// When doing [ambiguity checking](ScheduleBuildSettings) this
1203
/// ignores systems that are ambiguous on [`Component`] T.
1204
///
1205
/// This settings only applies to the main world. To apply this to other worlds call the
1206
/// [corresponding method](World::allow_ambiguous_component) on World
1207
///
1208
/// ## Example
1209
///
1210
/// ```
1211
/// # use bevy_app::prelude::*;
1212
/// # use bevy_ecs::prelude::*;
1213
/// # use bevy_ecs::schedule::{LogLevel, ScheduleBuildSettings};
1214
/// # use bevy_utils::default;
1215
///
1216
/// #[derive(Component)]
1217
/// struct A;
1218
///
1219
/// // these systems are ambiguous on A
1220
/// fn system_1(_: Query<&mut A>) {}
1221
/// fn system_2(_: Query<&A>) {}
1222
///
1223
/// let mut app = App::new();
1224
/// app.configure_schedules(ScheduleBuildSettings {
1225
/// ambiguity_detection: LogLevel::Error,
1226
/// ..default()
1227
/// });
1228
///
1229
/// app.add_systems(Update, ( system_1, system_2 ));
1230
/// app.allow_ambiguous_component::<A>();
1231
///
1232
/// // running the app does not error.
1233
/// app.update();
1234
/// ```
1235
pub fn allow_ambiguous_component<T: Component>(&mut self) -> &mut Self {
1236
self.main_mut().allow_ambiguous_component::<T>();
1237
self
1238
}
1239
1240
/// When doing [ambiguity checking](ScheduleBuildSettings) this
1241
/// ignores systems that are ambiguous on [`Resource`] T.
1242
///
1243
/// This settings only applies to the main world. To apply this to other worlds call the
1244
/// [corresponding method](World::allow_ambiguous_resource) on World
1245
///
1246
/// ## Example
1247
///
1248
/// ```
1249
/// # use bevy_app::prelude::*;
1250
/// # use bevy_ecs::prelude::*;
1251
/// # use bevy_ecs::schedule::{LogLevel, ScheduleBuildSettings};
1252
/// # use bevy_utils::default;
1253
///
1254
/// #[derive(Resource)]
1255
/// struct R;
1256
///
1257
/// // these systems are ambiguous on R
1258
/// fn system_1(_: ResMut<R>) {}
1259
/// fn system_2(_: Res<R>) {}
1260
///
1261
/// let mut app = App::new();
1262
/// app.configure_schedules(ScheduleBuildSettings {
1263
/// ambiguity_detection: LogLevel::Error,
1264
/// ..default()
1265
/// });
1266
/// app.insert_resource(R);
1267
///
1268
/// app.add_systems(Update, ( system_1, system_2 ));
1269
/// app.allow_ambiguous_resource::<R>();
1270
///
1271
/// // running the app does not error.
1272
/// app.update();
1273
/// ```
1274
pub fn allow_ambiguous_resource<T: Resource>(&mut self) -> &mut Self {
1275
self.main_mut().allow_ambiguous_resource::<T>();
1276
self
1277
}
1278
1279
/// Suppress warnings and errors that would result from systems in these sets having ambiguities
1280
/// (conflicting access but indeterminate order) with systems in `set`.
1281
///
1282
/// When possible, do this directly in the `.add_systems(Update, a.ambiguous_with(b))` call.
1283
/// However, sometimes two independent plugins `A` and `B` are reported as ambiguous, which you
1284
/// can only suppress as the consumer of both.
1285
#[track_caller]
1286
pub fn ignore_ambiguity<M1, M2, S1, S2>(
1287
&mut self,
1288
schedule: impl ScheduleLabel,
1289
a: S1,
1290
b: S2,
1291
) -> &mut Self
1292
where
1293
S1: IntoSystemSet<M1>,
1294
S2: IntoSystemSet<M2>,
1295
{
1296
self.main_mut().ignore_ambiguity(schedule, a, b);
1297
self
1298
}
1299
1300
/// Attempts to determine if an [`AppExit`] was raised since the last update.
1301
///
1302
/// Will attempt to return the first [`Error`](AppExit::Error) it encounters.
1303
/// This should be called after every [`update()`](App::update) otherwise you risk
1304
/// dropping possible [`AppExit`] events.
1305
pub fn should_exit(&self) -> Option<AppExit> {
1306
let mut reader = EventCursor::default();
1307
1308
let events = self.world().get_resource::<Events<AppExit>>()?;
1309
let mut events = reader.read(events);
1310
1311
if events.len() != 0 {
1312
return Some(
1313
events
1314
.find(|exit| exit.is_error())
1315
.cloned()
1316
.unwrap_or(AppExit::Success),
1317
);
1318
}
1319
1320
None
1321
}
1322
1323
/// Spawns an [`Observer`] entity, which will watch for and respond to the given event.
1324
///
1325
/// `observer` can be any system whose first parameter is [`On`].
1326
///
1327
/// # Examples
1328
///
1329
/// ```rust
1330
/// # use bevy_app::prelude::*;
1331
/// # use bevy_ecs::prelude::*;
1332
/// # use bevy_utils::default;
1333
/// #
1334
/// # let mut app = App::new();
1335
/// #
1336
/// # #[derive(Event)]
1337
/// # struct Party {
1338
/// # friends_allowed: bool,
1339
/// # };
1340
/// #
1341
/// # #[derive(EntityEvent)]
1342
/// # struct Invite;
1343
/// #
1344
/// # #[derive(Component)]
1345
/// # struct Friend;
1346
/// #
1347
///
1348
/// app.add_observer(|event: On<Party>, friends: Query<Entity, With<Friend>>, mut commands: Commands| {
1349
/// if event.friends_allowed {
1350
/// for friend in friends.iter() {
1351
/// commands.trigger_targets(Invite, friend);
1352
/// }
1353
/// }
1354
/// });
1355
/// ```
1356
pub fn add_observer<E: Event, B: Bundle, M>(
1357
&mut self,
1358
observer: impl IntoObserverSystem<E, B, M>,
1359
) -> &mut Self {
1360
self.world_mut().add_observer(observer);
1361
self
1362
}
1363
1364
/// Gets the error handler to set for new supapps.
1365
///
1366
/// Note that the error handler of existing subapps may differ.
1367
pub fn get_error_handler(&self) -> Option<ErrorHandler> {
1368
self.default_error_handler
1369
}
1370
1371
/// Set the [default error handler] for the all subapps (including the main one and future ones)
1372
/// that do not have one.
1373
///
1374
/// May only be called once and should be set by the application, not by libraries.
1375
///
1376
/// The handler will be called when an error is produced and not otherwise handled.
1377
///
1378
/// # Panics
1379
/// Panics if called multiple times.
1380
///
1381
/// # Example
1382
/// ```
1383
/// # use bevy_app::*;
1384
/// # use bevy_ecs::error::warn;
1385
/// # fn MyPlugins(_: &mut App) {}
1386
/// App::new()
1387
/// .set_error_handler(warn)
1388
/// .add_plugins(MyPlugins)
1389
/// .run();
1390
/// ```
1391
///
1392
/// [default error handler]: bevy_ecs::error::DefaultErrorHandler
1393
pub fn set_error_handler(&mut self, handler: ErrorHandler) -> &mut Self {
1394
assert!(
1395
self.default_error_handler.is_none(),
1396
"`set_error_handler` called multiple times on same `App`"
1397
);
1398
self.default_error_handler = Some(handler);
1399
for sub_app in self.sub_apps.iter_mut() {
1400
sub_app
1401
.world_mut()
1402
.get_resource_or_insert_with(|| DefaultErrorHandler(handler));
1403
}
1404
self
1405
}
1406
}
1407
1408
// Used for doing hokey pokey in finish and cleanup
1409
pub(crate) struct HokeyPokey;
1410
impl Plugin for HokeyPokey {
1411
fn build(&self, _: &mut App) {}
1412
}
1413
1414
type RunnerFn = Box<dyn FnOnce(App) -> AppExit>;
1415
1416
fn run_once(mut app: App) -> AppExit {
1417
while app.plugins_state() == PluginsState::Adding {
1418
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
1419
bevy_tasks::tick_global_task_pools_on_main_thread();
1420
}
1421
app.finish();
1422
app.cleanup();
1423
1424
app.update();
1425
1426
app.should_exit().unwrap_or(AppExit::Success)
1427
}
1428
1429
/// A [`BufferedEvent`] that indicates the [`App`] should exit. If one or more of these are present at the end of an update,
1430
/// the [runner](App::set_runner) will end and ([maybe](App::run)) return control to the caller.
1431
///
1432
/// This event can be used to detect when an exit is requested. Make sure that systems listening
1433
/// for this event run before the current update ends.
1434
///
1435
/// # Portability
1436
/// 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
1437
/// (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#))
1438
/// we only allow error codes between 1 and [255](u8::MAX).
1439
#[derive(BufferedEvent, Debug, Clone, Default, PartialEq, Eq)]
1440
pub enum AppExit {
1441
/// [`App`] exited without any problems.
1442
#[default]
1443
Success,
1444
/// The [`App`] experienced an unhandleable error.
1445
/// Holds the exit code we expect our app to return.
1446
Error(NonZero<u8>),
1447
}
1448
1449
impl AppExit {
1450
/// Creates a [`AppExit::Error`] with an error code of 1.
1451
#[must_use]
1452
pub const fn error() -> Self {
1453
Self::Error(NonZero::<u8>::MIN)
1454
}
1455
1456
/// Returns `true` if `self` is a [`AppExit::Success`].
1457
#[must_use]
1458
pub const fn is_success(&self) -> bool {
1459
matches!(self, AppExit::Success)
1460
}
1461
1462
/// Returns `true` if `self` is a [`AppExit::Error`].
1463
#[must_use]
1464
pub const fn is_error(&self) -> bool {
1465
matches!(self, AppExit::Error(_))
1466
}
1467
1468
/// Creates a [`AppExit`] from a code.
1469
///
1470
/// When `code` is 0 a [`AppExit::Success`] is constructed otherwise a
1471
/// [`AppExit::Error`] is constructed.
1472
#[must_use]
1473
pub const fn from_code(code: u8) -> Self {
1474
match NonZero::<u8>::new(code) {
1475
Some(code) => Self::Error(code),
1476
None => Self::Success,
1477
}
1478
}
1479
}
1480
1481
impl From<u8> for AppExit {
1482
fn from(value: u8) -> Self {
1483
Self::from_code(value)
1484
}
1485
}
1486
1487
#[cfg(feature = "std")]
1488
impl Termination for AppExit {
1489
fn report(self) -> ExitCode {
1490
match self {
1491
AppExit::Success => ExitCode::SUCCESS,
1492
// We leave logging an error to our users
1493
AppExit::Error(value) => ExitCode::from(value.get()),
1494
}
1495
}
1496
}
1497
1498
#[cfg(test)]
1499
mod tests {
1500
use core::marker::PhantomData;
1501
use std::sync::Mutex;
1502
1503
use bevy_ecs::{
1504
change_detection::{DetectChanges, ResMut},
1505
component::Component,
1506
entity::Entity,
1507
event::{BufferedEvent, EventWriter, Events},
1508
lifecycle::RemovedComponents,
1509
query::With,
1510
resource::Resource,
1511
schedule::{IntoScheduleConfigs, ScheduleLabel},
1512
system::{Commands, Query},
1513
world::{FromWorld, World},
1514
};
1515
1516
use crate::{App, AppExit, Plugin, SubApp, Update};
1517
1518
struct PluginA;
1519
impl Plugin for PluginA {
1520
fn build(&self, _app: &mut App) {}
1521
}
1522
struct PluginB;
1523
impl Plugin for PluginB {
1524
fn build(&self, _app: &mut App) {}
1525
}
1526
struct PluginC<T>(T);
1527
impl<T: Send + Sync + 'static> Plugin for PluginC<T> {
1528
fn build(&self, _app: &mut App) {}
1529
}
1530
struct PluginD;
1531
impl Plugin for PluginD {
1532
fn build(&self, _app: &mut App) {}
1533
fn is_unique(&self) -> bool {
1534
false
1535
}
1536
}
1537
1538
struct PluginE;
1539
1540
impl Plugin for PluginE {
1541
fn build(&self, _app: &mut App) {}
1542
1543
fn finish(&self, app: &mut App) {
1544
if app.is_plugin_added::<PluginA>() {
1545
panic!("cannot run if PluginA is already registered");
1546
}
1547
}
1548
}
1549
1550
struct PluginF;
1551
1552
impl Plugin for PluginF {
1553
fn build(&self, _app: &mut App) {}
1554
1555
fn finish(&self, app: &mut App) {
1556
// Ensure other plugins are available during finish
1557
assert_eq!(
1558
app.is_plugin_added::<PluginA>(),
1559
!app.get_added_plugins::<PluginA>().is_empty(),
1560
);
1561
}
1562
1563
fn cleanup(&self, app: &mut App) {
1564
// Ensure other plugins are available during finish
1565
assert_eq!(
1566
app.is_plugin_added::<PluginA>(),
1567
!app.get_added_plugins::<PluginA>().is_empty(),
1568
);
1569
}
1570
}
1571
1572
struct PluginG;
1573
1574
impl Plugin for PluginG {
1575
fn build(&self, _app: &mut App) {}
1576
1577
fn finish(&self, app: &mut App) {
1578
app.add_plugins(PluginB);
1579
}
1580
}
1581
1582
#[test]
1583
fn can_add_two_plugins() {
1584
App::new().add_plugins((PluginA, PluginB));
1585
}
1586
1587
#[test]
1588
#[should_panic]
1589
fn cant_add_twice_the_same_plugin() {
1590
App::new().add_plugins((PluginA, PluginA));
1591
}
1592
1593
#[test]
1594
fn can_add_twice_the_same_plugin_with_different_type_param() {
1595
App::new().add_plugins((PluginC(0), PluginC(true)));
1596
}
1597
1598
#[test]
1599
fn can_add_twice_the_same_plugin_not_unique() {
1600
App::new().add_plugins((PluginD, PluginD));
1601
}
1602
1603
#[test]
1604
#[should_panic]
1605
fn cant_call_app_run_from_plugin_build() {
1606
struct PluginRun;
1607
struct InnerPlugin;
1608
impl Plugin for InnerPlugin {
1609
fn build(&self, _: &mut App) {}
1610
}
1611
impl Plugin for PluginRun {
1612
fn build(&self, app: &mut App) {
1613
app.add_plugins(InnerPlugin).run();
1614
}
1615
}
1616
App::new().add_plugins(PluginRun);
1617
}
1618
1619
#[derive(ScheduleLabel, Hash, Clone, PartialEq, Eq, Debug)]
1620
struct EnterMainMenu;
1621
1622
#[derive(Component)]
1623
struct A;
1624
1625
fn bar(mut commands: Commands) {
1626
commands.spawn(A);
1627
}
1628
1629
fn foo(mut commands: Commands) {
1630
commands.spawn(A);
1631
}
1632
1633
#[test]
1634
fn add_systems_should_create_schedule_if_it_does_not_exist() {
1635
let mut app = App::new();
1636
app.add_systems(EnterMainMenu, (foo, bar));
1637
1638
app.world_mut().run_schedule(EnterMainMenu);
1639
assert_eq!(app.world_mut().query::<&A>().query(app.world()).count(), 2);
1640
}
1641
1642
#[test]
1643
#[should_panic]
1644
fn test_is_plugin_added_works_during_finish() {
1645
let mut app = App::new();
1646
app.add_plugins(PluginA);
1647
app.add_plugins(PluginE);
1648
app.finish();
1649
}
1650
1651
#[test]
1652
fn test_get_added_plugins_works_during_finish_and_cleanup() {
1653
let mut app = App::new();
1654
app.add_plugins(PluginA);
1655
app.add_plugins(PluginF);
1656
app.finish();
1657
}
1658
1659
#[test]
1660
fn test_adding_plugin_works_during_finish() {
1661
let mut app = App::new();
1662
app.add_plugins(PluginA);
1663
app.add_plugins(PluginG);
1664
app.finish();
1665
assert_eq!(
1666
app.main().plugin_registry[0].name(),
1667
"bevy_app::main_schedule::MainSchedulePlugin"
1668
);
1669
assert_eq!(
1670
app.main().plugin_registry[1].name(),
1671
"bevy_app::app::tests::PluginA"
1672
);
1673
assert_eq!(
1674
app.main().plugin_registry[2].name(),
1675
"bevy_app::app::tests::PluginG"
1676
);
1677
// PluginG adds PluginB during finish
1678
assert_eq!(
1679
app.main().plugin_registry[3].name(),
1680
"bevy_app::app::tests::PluginB"
1681
);
1682
}
1683
1684
#[test]
1685
fn test_derive_app_label() {
1686
use super::AppLabel;
1687
1688
#[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1689
struct UnitLabel;
1690
1691
#[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1692
struct TupleLabel(u32, u32);
1693
1694
#[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1695
struct StructLabel {
1696
a: u32,
1697
b: u32,
1698
}
1699
1700
#[expect(
1701
dead_code,
1702
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
1703
)]
1704
#[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1705
struct EmptyTupleLabel();
1706
1707
#[expect(
1708
dead_code,
1709
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
1710
)]
1711
#[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1712
struct EmptyStructLabel {}
1713
1714
#[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1715
enum EnumLabel {
1716
#[default]
1717
Unit,
1718
Tuple(u32, u32),
1719
Struct {
1720
a: u32,
1721
b: u32,
1722
},
1723
}
1724
1725
#[derive(AppLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1726
struct GenericLabel<T>(PhantomData<T>);
1727
1728
assert_eq!(UnitLabel.intern(), UnitLabel.intern());
1729
assert_eq!(EnumLabel::Unit.intern(), EnumLabel::Unit.intern());
1730
assert_ne!(UnitLabel.intern(), EnumLabel::Unit.intern());
1731
assert_ne!(UnitLabel.intern(), TupleLabel(0, 0).intern());
1732
assert_ne!(EnumLabel::Unit.intern(), EnumLabel::Tuple(0, 0).intern());
1733
1734
assert_eq!(TupleLabel(0, 0).intern(), TupleLabel(0, 0).intern());
1735
assert_eq!(
1736
EnumLabel::Tuple(0, 0).intern(),
1737
EnumLabel::Tuple(0, 0).intern()
1738
);
1739
assert_ne!(TupleLabel(0, 0).intern(), TupleLabel(0, 1).intern());
1740
assert_ne!(
1741
EnumLabel::Tuple(0, 0).intern(),
1742
EnumLabel::Tuple(0, 1).intern()
1743
);
1744
assert_ne!(TupleLabel(0, 0).intern(), EnumLabel::Tuple(0, 0).intern());
1745
assert_ne!(
1746
TupleLabel(0, 0).intern(),
1747
StructLabel { a: 0, b: 0 }.intern()
1748
);
1749
assert_ne!(
1750
EnumLabel::Tuple(0, 0).intern(),
1751
EnumLabel::Struct { a: 0, b: 0 }.intern()
1752
);
1753
1754
assert_eq!(
1755
StructLabel { a: 0, b: 0 }.intern(),
1756
StructLabel { a: 0, b: 0 }.intern()
1757
);
1758
assert_eq!(
1759
EnumLabel::Struct { a: 0, b: 0 }.intern(),
1760
EnumLabel::Struct { a: 0, b: 0 }.intern()
1761
);
1762
assert_ne!(
1763
StructLabel { a: 0, b: 0 }.intern(),
1764
StructLabel { a: 0, b: 1 }.intern()
1765
);
1766
assert_ne!(
1767
EnumLabel::Struct { a: 0, b: 0 }.intern(),
1768
EnumLabel::Struct { a: 0, b: 1 }.intern()
1769
);
1770
assert_ne!(
1771
StructLabel { a: 0, b: 0 }.intern(),
1772
EnumLabel::Struct { a: 0, b: 0 }.intern()
1773
);
1774
assert_ne!(
1775
StructLabel { a: 0, b: 0 }.intern(),
1776
EnumLabel::Struct { a: 0, b: 0 }.intern()
1777
);
1778
assert_ne!(StructLabel { a: 0, b: 0 }.intern(), UnitLabel.intern(),);
1779
assert_ne!(
1780
EnumLabel::Struct { a: 0, b: 0 }.intern(),
1781
EnumLabel::Unit.intern()
1782
);
1783
1784
assert_eq!(
1785
GenericLabel::<u32>(PhantomData).intern(),
1786
GenericLabel::<u32>(PhantomData).intern()
1787
);
1788
assert_ne!(
1789
GenericLabel::<u32>(PhantomData).intern(),
1790
GenericLabel::<u64>(PhantomData).intern()
1791
);
1792
}
1793
1794
#[test]
1795
fn test_update_clears_trackers_once() {
1796
#[derive(Component, Copy, Clone)]
1797
struct Foo;
1798
1799
let mut app = App::new();
1800
app.world_mut().spawn_batch(core::iter::repeat_n(Foo, 5));
1801
1802
fn despawn_one_foo(mut commands: Commands, foos: Query<Entity, With<Foo>>) {
1803
if let Some(e) = foos.iter().next() {
1804
commands.entity(e).despawn();
1805
};
1806
}
1807
fn check_despawns(mut removed_foos: RemovedComponents<Foo>) {
1808
let mut despawn_count = 0;
1809
for _ in removed_foos.read() {
1810
despawn_count += 1;
1811
}
1812
1813
assert_eq!(despawn_count, 2);
1814
}
1815
1816
app.add_systems(Update, despawn_one_foo);
1817
app.update(); // Frame 0
1818
app.update(); // Frame 1
1819
app.add_systems(Update, check_despawns.after(despawn_one_foo));
1820
app.update(); // Should see despawns from frames 1 & 2, but not frame 0
1821
}
1822
1823
#[test]
1824
fn test_extract_sees_changes() {
1825
use super::AppLabel;
1826
1827
#[derive(AppLabel, Clone, Copy, Hash, PartialEq, Eq, Debug)]
1828
struct MySubApp;
1829
1830
#[derive(Resource)]
1831
struct Foo(usize);
1832
1833
let mut app = App::new();
1834
app.world_mut().insert_resource(Foo(0));
1835
app.add_systems(Update, |mut foo: ResMut<Foo>| {
1836
foo.0 += 1;
1837
});
1838
1839
let mut sub_app = SubApp::new();
1840
sub_app.set_extract(|main_world, _sub_world| {
1841
assert!(main_world.get_resource_ref::<Foo>().unwrap().is_changed());
1842
});
1843
1844
app.insert_sub_app(MySubApp, sub_app);
1845
1846
app.update();
1847
}
1848
1849
#[test]
1850
fn runner_returns_correct_exit_code() {
1851
fn raise_exits(mut exits: EventWriter<AppExit>) {
1852
// Exit codes chosen by a fair dice roll.
1853
// Unlikely to overlap with default values.
1854
exits.write(AppExit::Success);
1855
exits.write(AppExit::from_code(4));
1856
exits.write(AppExit::from_code(73));
1857
}
1858
1859
let exit = App::new().add_systems(Update, raise_exits).run();
1860
1861
assert_eq!(exit, AppExit::from_code(4));
1862
}
1863
1864
/// Custom runners should be in charge of when `app::update` gets called as they may need to
1865
/// coordinate some state.
1866
/// bug: <https://github.com/bevyengine/bevy/issues/10385>
1867
/// fix: <https://github.com/bevyengine/bevy/pull/10389>
1868
#[test]
1869
fn regression_test_10385() {
1870
use super::{Res, Resource};
1871
use crate::PreUpdate;
1872
1873
#[derive(Resource)]
1874
struct MyState {}
1875
1876
fn my_runner(mut app: App) -> AppExit {
1877
let my_state = MyState {};
1878
app.world_mut().insert_resource(my_state);
1879
1880
for _ in 0..5 {
1881
app.update();
1882
}
1883
1884
AppExit::Success
1885
}
1886
1887
fn my_system(_: Res<MyState>) {
1888
// access state during app update
1889
}
1890
1891
// Should not panic due to missing resource
1892
App::new()
1893
.set_runner(my_runner)
1894
.add_systems(PreUpdate, my_system)
1895
.run();
1896
}
1897
1898
#[test]
1899
fn app_exit_size() {
1900
// There wont be many of them so the size isn't an issue but
1901
// it's nice they're so small let's keep it that way.
1902
assert_eq!(size_of::<AppExit>(), size_of::<u8>());
1903
}
1904
1905
#[test]
1906
fn initializing_resources_from_world() {
1907
#[derive(Resource)]
1908
struct TestResource;
1909
impl FromWorld for TestResource {
1910
fn from_world(_world: &mut World) -> Self {
1911
TestResource
1912
}
1913
}
1914
1915
#[derive(Resource)]
1916
struct NonSendTestResource {
1917
_marker: PhantomData<Mutex<()>>,
1918
}
1919
impl FromWorld for NonSendTestResource {
1920
fn from_world(_world: &mut World) -> Self {
1921
NonSendTestResource {
1922
_marker: PhantomData,
1923
}
1924
}
1925
}
1926
1927
App::new()
1928
.init_non_send_resource::<NonSendTestResource>()
1929
.init_resource::<TestResource>();
1930
}
1931
1932
#[test]
1933
/// Plugin should not be considered inserted while it's being built
1934
///
1935
/// bug: <https://github.com/bevyengine/bevy/issues/13815>
1936
fn plugin_should_not_be_added_during_build_time() {
1937
pub struct Foo;
1938
1939
impl Plugin for Foo {
1940
fn build(&self, app: &mut App) {
1941
assert!(!app.is_plugin_added::<Self>());
1942
}
1943
}
1944
1945
App::new().add_plugins(Foo);
1946
}
1947
#[test]
1948
fn events_should_be_updated_once_per_update() {
1949
#[derive(BufferedEvent, Clone)]
1950
struct TestEvent;
1951
1952
let mut app = App::new();
1953
app.add_event::<TestEvent>();
1954
1955
// Starts empty
1956
let test_events = app.world().resource::<Events<TestEvent>>();
1957
assert_eq!(test_events.len(), 0);
1958
assert_eq!(test_events.iter_current_update_events().count(), 0);
1959
app.update();
1960
1961
// Sending one event
1962
app.world_mut().write_event(TestEvent);
1963
1964
let test_events = app.world().resource::<Events<TestEvent>>();
1965
assert_eq!(test_events.len(), 1);
1966
assert_eq!(test_events.iter_current_update_events().count(), 1);
1967
app.update();
1968
1969
// Sending two events on the next frame
1970
app.world_mut().write_event(TestEvent);
1971
app.world_mut().write_event(TestEvent);
1972
1973
let test_events = app.world().resource::<Events<TestEvent>>();
1974
assert_eq!(test_events.len(), 3); // Events are double-buffered, so we see 1 + 2 = 3
1975
assert_eq!(test_events.iter_current_update_events().count(), 2);
1976
app.update();
1977
1978
// Sending zero events
1979
let test_events = app.world().resource::<Events<TestEvent>>();
1980
assert_eq!(test_events.len(), 2); // Events are double-buffered, so we see 2 + 0 = 2
1981
assert_eq!(test_events.iter_current_update_events().count(), 0);
1982
}
1983
}
1984
1985