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