Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/observer/distributed_storage.rs
9358 views
1
//! Information about observers that is stored on the entities themselves.
2
//!
3
//! This allows for easier cleanup, better inspection, and more flexible querying.
4
//!
5
//! Each observer is associated with an entity, defined by the [`Observer`] component.
6
//! The [`Observer`] component contains the system that will be run when the observer is triggered,
7
//! and the [`ObserverDescriptor`] which contains information about what the observer is observing.
8
//!
9
//! When we watch entities, we add the [`ObservedBy`] component to those entities,
10
//! which links back to the observer entity.
11
12
use core::any::Any;
13
14
use core::marker::PhantomData;
15
16
use crate::{
17
component::{ComponentCloneBehavior, ComponentId, Mutable, StorageType},
18
error::{ErrorContext, ErrorHandler},
19
event::EventKey,
20
lifecycle::{ComponentHook, HookContext},
21
observer::{
22
condition::{ObserverCondition, ObserverWithCondition, ObserverWithConditionMarker},
23
observer_system_runner, ObserverRunner,
24
},
25
prelude::*,
26
system::{IntoObserverSystem, ObserverSystem},
27
world::DeferredWorld,
28
};
29
use alloc::boxed::Box;
30
use alloc::vec::Vec;
31
use bevy_utils::prelude::DebugName;
32
33
#[cfg(feature = "bevy_reflect")]
34
use crate::prelude::ReflectComponent;
35
36
/// An [`Observer`] system. Add this [`Component`] to an [`Entity`] to turn it into an "observer".
37
///
38
/// Observers watch for a "trigger" of a specific [`Event`]. An event can be triggered on the [`World`]
39
/// by calling [`World::trigger`]. It can also be queued up as a [`Command`] using [`Commands::trigger`].
40
///
41
/// When a [`World`] triggers an [`Event`], it will immediately run every [`Observer`] that watches for that [`Event`].
42
///
43
/// # Usage
44
///
45
/// The simplest usage of the observer pattern looks like this:
46
///
47
/// ```
48
/// # use bevy_ecs::prelude::*;
49
/// # let mut world = World::default();
50
/// #[derive(Event)]
51
/// struct Speak {
52
/// message: String,
53
/// }
54
///
55
/// world.add_observer(|event: On<Speak>| {
56
/// println!("{}", event.message);
57
/// });
58
///
59
/// world.trigger(Speak {
60
/// message: "Hello!".into(),
61
/// });
62
/// ```
63
///
64
/// Notice that we used [`World::add_observer`]. This is just a shorthand for spawning an [`Entity`] with an [`Observer`] manually:
65
///
66
/// ```
67
/// # use bevy_ecs::prelude::*;
68
/// # let mut world = World::default();
69
/// # #[derive(Event)]
70
/// # struct Speak;
71
/// // These are functionally the same:
72
/// world.add_observer(|event: On<Speak>| {});
73
/// world.spawn(Observer::new(|event: On<Speak>| {}));
74
/// ```
75
///
76
/// Observers are a specialized [`System`] called an [`ObserverSystem`]. The first parameter must be [`On`], which provides access
77
/// to the [`Event`], the [`Trigger`], and some additional execution context.
78
///
79
/// Because they are systems, they can access arbitrary [`World`] data by adding [`SystemParam`]s:
80
///
81
/// ```
82
/// # use bevy_ecs::prelude::*;
83
/// # let mut world = World::default();
84
/// # #[derive(Event)]
85
/// # struct PrintNames;
86
/// # #[derive(Component, Debug)]
87
/// # struct Name;
88
/// world.add_observer(|event: On<PrintNames>, names: Query<&Name>| {
89
/// for name in &names {
90
/// println!("{name:?}");
91
/// }
92
/// });
93
/// ```
94
///
95
/// You can also add [`Commands`], which means you can spawn new entities, insert new components, etc:
96
///
97
/// ```
98
/// # use bevy_ecs::prelude::*;
99
/// # let mut world = World::default();
100
/// # #[derive(Event)]
101
/// # struct SpawnThing;
102
/// # #[derive(Component, Debug)]
103
/// # struct Thing;
104
/// world.add_observer(|event: On<SpawnThing>, mut commands: Commands| {
105
/// commands.spawn(Thing);
106
/// });
107
/// ```
108
///
109
/// Observers can also trigger new events:
110
///
111
/// ```
112
/// # use bevy_ecs::prelude::*;
113
/// # let mut world = World::default();
114
/// # #[derive(Event)]
115
/// # struct A;
116
/// # #[derive(Event)]
117
/// # struct B;
118
/// world.add_observer(|event: On<A>, mut commands: Commands| {
119
/// commands.trigger(B);
120
/// });
121
/// ```
122
///
123
/// When the commands are flushed (including these "nested triggers") they will be
124
/// recursively evaluated until there are no commands left, meaning nested triggers all
125
/// evaluate at the same time!
126
///
127
/// ## Event [`Trigger`] behavior
128
///
129
/// Each [`Event`] defines a [`Trigger`] behavior, which determines _which_ observers will run for the given [`Event`] and _how_ they will be run.
130
///
131
/// [`Event`] by default (when derived) uses [`GlobalTrigger`](crate::event::GlobalTrigger). When it is triggered any [`Observer`] watching for it will be run.
132
///
133
/// ## Event sub-types
134
///
135
/// There are some built-in specialized [`Event`] types with custom [`Trigger`] logic:
136
///
137
/// - [`EntityEvent`] / [`EntityTrigger`](crate::event::EntityTrigger): An [`Event`] that targets a _specific_ entity. This also has opt-in support for
138
/// "event bubbling" behavior. See [`EntityEvent`] for details.
139
/// - [`EntityComponentsTrigger`](crate::event::EntityComponentsTrigger): An [`Event`] that targets an entity _and_ one or more components on that entity.
140
/// This is used for [component lifecycle events](crate::lifecycle).
141
///
142
/// You can also define your own!
143
///
144
/// ## Observer execution timing
145
///
146
/// Observers triggered via [`World::trigger`] are evaluated immediately, as are all commands they queue up.
147
///
148
/// Observers triggered via [`Commands::trigger`] are evaluated at the next sync point in the ECS schedule, just like any other [`Command`].
149
///
150
/// To control the relative ordering of observer trigger commands sent from different systems,
151
/// order the systems in the schedule relative to each other.
152
///
153
/// Currently, Bevy does not provide [a way to specify the relative ordering of observers](https://github.com/bevyengine/bevy/issues/14890)
154
/// watching for the same event. Their ordering is considered to be arbitrary. It is recommended to make no
155
/// assumptions about their execution order.
156
///
157
/// Commands sent by observers are [currently not immediately applied](https://github.com/bevyengine/bevy/issues/19569).
158
/// Instead, all queued observers will run, and then all of the commands from those observers will be applied.
159
///
160
/// ## [`ObservedBy`]
161
///
162
/// When entities are observed, they will receive an [`ObservedBy`] component,
163
/// which will be updated to track the observers that are currently observing them.
164
///
165
/// ## Manual [`Observer`] target configuration
166
///
167
/// You can manually control the targets that an observer is watching by calling builder methods like [`Observer::with_entity`]
168
/// _before_ inserting the [`Observer`] component.
169
///
170
/// In general, it is better to use the [`EntityWorldMut::observe`] or [`EntityCommands::observe`] methods,
171
/// which spawns a new observer, and configures it to watch the entity it is called on.
172
///
173
/// ## Cleaning up observers
174
///
175
/// If an [`EntityEvent`] [`Observer`] targets specific entities, and all of those entities are despawned, the [`Observer`] entity will also be despawned.
176
/// This protects against observer "garbage" building up over time.
177
///
178
/// ## Component lifecycle events: Observers vs Hooks
179
///
180
/// It is important to note that observers, just like [hooks](crate::lifecycle::ComponentHooks),
181
/// can watch for and respond to [lifecycle](crate::lifecycle) events.
182
/// Unlike hooks, observers are not treated as an "innate" part of component behavior:
183
/// they can be added or removed at runtime, and multiple observers
184
/// can be registered for the same lifecycle event for the same component.
185
///
186
/// The ordering of hooks versus observers differs based on the lifecycle event in question:
187
///
188
/// - when adding components, hooks are evaluated first, then observers
189
/// - when removing components, observers are evaluated first, then hooks
190
///
191
/// This allows hooks to act as constructors and destructors for components,
192
/// as they always have the first and final say in the component's lifecycle.
193
///
194
/// ## Observer re-targeting
195
///
196
/// Currently, [observers cannot be retargeted after spawning](https://github.com/bevyengine/bevy/issues/19587):
197
/// despawn and respawn an observer as a workaround.
198
///
199
/// ## Internal observer cache
200
///
201
/// For more efficient observer triggering, Observers make use of the internal [`CachedObservers`](crate::observer::CachedObservers) storage.
202
/// In general, this is an implementation detail developers don't need to worry about, but it can be used when implementing custom [`Trigger`](crate::event::Trigger)
203
/// types, or to add "dynamic" observers for cases like scripting / modding.
204
///
205
/// [`SystemParam`]: crate::system::SystemParam
206
/// [`Trigger`]: crate::event::Trigger
207
pub struct Observer {
208
hook_on_add: ComponentHook,
209
pub(crate) error_handler: Option<ErrorHandler>,
210
pub(crate) system: Box<dyn AnyNamedSystem>,
211
pub(crate) descriptor: ObserverDescriptor,
212
pub(crate) last_trigger_id: u32,
213
pub(crate) despawned_watched_entities: u32,
214
pub(crate) runner: ObserverRunner,
215
pub(crate) conditions: Vec<ObserverCondition>,
216
}
217
218
impl Observer {
219
/// Creates a new [`Observer`], which defaults to a "global" observer. This means it will run _whenever_ an event of type `E` is triggered.
220
///
221
/// # Panics
222
///
223
/// Panics if the given system is an exclusive system.
224
pub fn new<E: Event, B: Bundle, M, I: IntoObserverSystem<E, B, M>>(system: I) -> Self {
225
let system = Box::new(IntoObserverSystem::into_system(system));
226
assert!(
227
!system.is_exclusive(),
228
concat!(
229
"Exclusive system `{}` may not be used as observer.\n",
230
"Instead of `&mut World`, use either `DeferredWorld` if you do not need structural changes, or `Commands` if you do."
231
),
232
system.name()
233
);
234
Self {
235
system,
236
descriptor: Default::default(),
237
hook_on_add: hook_on_add::<E, B, I::System>,
238
error_handler: None,
239
runner: observer_system_runner::<E, B, I::System>,
240
despawned_watched_entities: 0,
241
last_trigger_id: 0,
242
conditions: Vec::new(),
243
}
244
}
245
246
/// Creates a new [`Observer`] with custom runner, this is mostly used for dynamic event observers
247
pub fn with_dynamic_runner(runner: ObserverRunner) -> Self {
248
Self {
249
system: Box::new(IntoSystem::into_system(|| {})),
250
descriptor: Default::default(),
251
hook_on_add: |mut world, hook_context| {
252
let default_error_handler = world.default_error_handler();
253
world.commands().queue(move |world: &mut World| {
254
let entity = hook_context.entity;
255
let mut conditions = {
256
let Some(mut observe) = world.get_mut::<Observer>(entity) else {
257
return;
258
};
259
if observe.descriptor.event_keys.is_empty() {
260
return;
261
}
262
if observe.error_handler.is_none() {
263
observe.error_handler = Some(default_error_handler);
264
}
265
core::mem::take(&mut observe.conditions)
266
};
267
for condition in &mut conditions {
268
condition.initialize(world);
269
}
270
if let Some(mut observe) = world.get_mut::<Observer>(entity) {
271
observe.conditions = conditions;
272
}
273
world.register_observer(entity);
274
});
275
},
276
error_handler: None,
277
runner,
278
despawned_watched_entities: 0,
279
last_trigger_id: 0,
280
conditions: Vec::new(),
281
}
282
}
283
284
/// Observes the given `entity` (in addition to any entity already being observed).
285
/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is the given `entity`.
286
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
287
pub fn with_entity(mut self, entity: Entity) -> Self {
288
self.watch_entity(entity);
289
self
290
}
291
292
/// Observes the given `entities` (in addition to any entity already being observed).
293
/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is any of the `entities`.
294
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
295
pub fn with_entities<I: IntoIterator<Item = Entity>>(mut self, entities: I) -> Self {
296
self.watch_entities(entities);
297
self
298
}
299
300
/// Observes the given `entity` (in addition to any entity already being observed).
301
/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is the given `entity`.
302
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
303
pub fn watch_entity(&mut self, entity: Entity) {
304
self.descriptor.entities.push(entity);
305
}
306
307
/// Observes the given `entity` (in addition to any entity already being observed).
308
/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is any of the `entities`.
309
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
310
pub fn watch_entities<I: IntoIterator<Item = Entity>>(&mut self, entities: I) {
311
self.descriptor.entities.extend(entities);
312
}
313
314
/// Observes the given `component`. This will cause the [`Observer`] to run whenever the [`Event`] has
315
/// an [`EntityComponentsTrigger`](crate::event::EntityComponentsTrigger) that targets the given `component`.
316
pub fn with_component(mut self, component: ComponentId) -> Self {
317
self.descriptor.components.push(component);
318
self
319
}
320
321
/// Observes the given `components`. This will cause the [`Observer`] to run whenever the [`Event`] has
322
/// an [`EntityComponentsTrigger`](crate::event::EntityComponentsTrigger) that targets any of the `components`.
323
pub fn with_components<I: IntoIterator<Item = ComponentId>>(mut self, components: I) -> Self {
324
self.descriptor.components.extend(components);
325
self
326
}
327
328
/// Observes the given `event_key`. This will cause the [`Observer`] to run whenever an event with the given [`EventKey`]
329
/// is triggered.
330
/// # Safety
331
/// The type of the `event_key` [`EventKey`] _must_ match the actual value
332
/// of the event passed into the observer system.
333
pub unsafe fn with_event_key(mut self, event_key: EventKey) -> Self {
334
self.descriptor.event_keys.push(event_key);
335
self
336
}
337
338
/// Sets the error handler to use for this observer.
339
///
340
/// See the [`error` module-level documentation](crate::error) for more information.
341
pub fn with_error_handler(mut self, error_handler: fn(BevyError, ErrorContext)) -> Self {
342
self.error_handler = Some(error_handler);
343
self
344
}
345
346
/// Adds a run condition to this observer.
347
///
348
/// The observer will only run if all conditions return `true` (AND semantics).
349
/// Multiple conditions can be added by chaining `run_if` calls.
350
pub fn run_if<M>(mut self, condition: impl SystemCondition<M>) -> Self {
351
self.conditions.push(ObserverCondition::new(condition));
352
self
353
}
354
355
/// Returns the [`ObserverDescriptor`] for this [`Observer`].
356
pub fn descriptor(&self) -> &ObserverDescriptor {
357
&self.descriptor
358
}
359
360
/// Returns the name of the [`Observer`]'s system .
361
pub fn system_name(&self) -> DebugName {
362
self.system.system_name()
363
}
364
}
365
366
impl Component for Observer {
367
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
368
type Mutability = Mutable;
369
fn on_add() -> Option<ComponentHook> {
370
Some(|world, context| {
371
let Some(observe) = world.get::<Self>(context.entity) else {
372
return;
373
};
374
let hook = observe.hook_on_add;
375
hook(world, context);
376
})
377
}
378
fn on_remove() -> Option<ComponentHook> {
379
Some(|mut world, HookContext { entity, .. }| {
380
let descriptor = core::mem::take(
381
&mut world
382
.entity_mut(entity)
383
.get_mut::<Self>()
384
.unwrap()
385
.as_mut()
386
.descriptor,
387
);
388
world.commands().queue(move |world: &mut World| {
389
world.unregister_observer(entity, descriptor);
390
});
391
})
392
}
393
}
394
395
/// Store information about what an [`Observer`] observes.
396
///
397
/// This information is stored inside of the [`Observer`] component,
398
#[derive(Default, Clone)]
399
pub struct ObserverDescriptor {
400
/// The event keys the observer is watching.
401
pub(super) event_keys: Vec<EventKey>,
402
403
/// The components the observer is watching.
404
pub(super) components: Vec<ComponentId>,
405
406
/// The entities the observer is watching.
407
pub(super) entities: Vec<Entity>,
408
}
409
410
impl ObserverDescriptor {
411
/// Add the given `event_keys` to the descriptor.
412
/// # Safety
413
/// The type of each [`EventKey`] in `event_keys` _must_ match the actual value
414
/// of the event passed into the observer.
415
pub unsafe fn with_event_keys(mut self, event_keys: Vec<EventKey>) -> Self {
416
self.event_keys = event_keys;
417
self
418
}
419
420
/// Add the given `components` to the descriptor.
421
pub fn with_components(mut self, components: Vec<ComponentId>) -> Self {
422
self.components = components;
423
self
424
}
425
426
/// Add the given `entities` to the descriptor.
427
pub fn with_entities(mut self, entities: Vec<Entity>) -> Self {
428
self.entities = entities;
429
self
430
}
431
432
/// Returns the `event_keys` that the observer is watching.
433
pub fn event_keys(&self) -> &[EventKey] {
434
&self.event_keys
435
}
436
437
/// Returns the `components` that the observer is watching.
438
pub fn components(&self) -> &[ComponentId] {
439
&self.components
440
}
441
442
/// Returns the `entities` that the observer is watching.
443
pub fn entities(&self) -> &[Entity] {
444
&self.entities
445
}
446
}
447
448
/// A [`ComponentHook`] used by [`Observer`] to handle its [`on-add`](`crate::lifecycle::ComponentHooks::on_add`).
449
///
450
/// This function exists separate from [`Observer`] to allow [`Observer`] to have its type parameters
451
/// erased.
452
///
453
/// The type parameters of this function _must_ match those used to create the [`Observer`].
454
/// As such, it is recommended to only use this function within the [`Observer::new`] method to
455
/// ensure type parameters match.
456
fn hook_on_add<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
457
mut world: DeferredWorld<'_>,
458
HookContext { entity, .. }: HookContext,
459
) {
460
world.commands().queue(move |world: &mut World| {
461
let event_key = world.register_event_key::<E>();
462
let components = B::component_ids(&mut world.components_registrator());
463
464
let system_ptr: *mut dyn ObserverSystem<E, B> = {
465
let Some(mut observer) = world.get_mut::<Observer>(entity) else {
466
return;
467
};
468
observer.descriptor.event_keys.push(event_key);
469
observer.descriptor.components.extend(components);
470
471
let system: &mut dyn Any = observer.system.as_mut();
472
system.downcast_mut::<S>().unwrap() as *mut dyn ObserverSystem<E, B>
473
};
474
475
// SAFETY: World reference is exclusive and initialize does not touch system, so references do not alias
476
unsafe {
477
(*system_ptr).initialize(world);
478
}
479
480
let mut conditions = {
481
let Some(mut observer) = world.get_mut::<Observer>(entity) else {
482
return;
483
};
484
core::mem::take(&mut observer.conditions)
485
};
486
487
for condition in &mut conditions {
488
condition.initialize(world);
489
}
490
491
if let Some(mut observer) = world.get_mut::<Observer>(entity) {
492
observer.conditions = conditions;
493
}
494
495
world.register_observer(entity);
496
});
497
}
498
499
/// Tracks a list of entity observers for the [`Entity`] [`ObservedBy`] is added to.
500
#[derive(Default, Debug)]
501
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
502
#[cfg_attr(feature = "bevy_reflect", reflect(Component, Debug))]
503
pub struct ObservedBy(pub(crate) Vec<Entity>);
504
505
impl ObservedBy {
506
/// Provides a read-only reference to the list of entities observing this entity.
507
pub fn get(&self) -> &[Entity] {
508
&self.0
509
}
510
}
511
512
impl Component for ObservedBy {
513
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
514
type Mutability = Mutable;
515
516
fn on_remove() -> Option<ComponentHook> {
517
Some(|mut world, HookContext { entity, .. }| {
518
let observed_by = {
519
let mut component = world.get_mut::<ObservedBy>(entity).unwrap();
520
core::mem::take(&mut component.0)
521
};
522
for e in observed_by {
523
let (total_entities, despawned_watched_entities) = {
524
let Ok(mut entity_mut) = world.get_entity_mut(e) else {
525
continue;
526
};
527
let Some(mut state) = entity_mut.get_mut::<Observer>() else {
528
continue;
529
};
530
state.despawned_watched_entities += 1;
531
(
532
state.descriptor.entities.len(),
533
state.despawned_watched_entities as usize,
534
)
535
};
536
537
// Despawn Observer if it has no more active sources.
538
if total_entities == despawned_watched_entities {
539
world.commands().entity(e).despawn();
540
}
541
}
542
})
543
}
544
545
fn clone_behavior() -> ComponentCloneBehavior {
546
ComponentCloneBehavior::Ignore
547
}
548
}
549
550
pub(crate) trait AnyNamedSystem: Any + Send + Sync + 'static {
551
fn system_name(&self) -> DebugName;
552
}
553
554
impl<T: Any + System> AnyNamedSystem for T {
555
fn system_name(&self) -> DebugName {
556
self.name()
557
}
558
}
559
560
/// Trait for types that can be converted into an [`Observer`].
561
pub trait IntoObserver<Marker>: Send + 'static {
562
/// Converts this type into an [`Observer`].
563
fn into_observer(self) -> Observer;
564
}
565
566
impl IntoObserver<()> for Observer {
567
fn into_observer(self) -> Observer {
568
self
569
}
570
}
571
572
impl<E: Event, B: Bundle, M, T: IntoObserverSystem<E, B, M>> IntoObserver<(E, B, M)> for T {
573
fn into_observer(self) -> Observer {
574
Observer::new(self)
575
}
576
}
577
578
impl<E: Event, B: Bundle, M: 'static, S: IntoObserverSystem<E, B, M>>
579
IntoObserver<ObserverWithConditionMarker> for ObserverWithCondition<E, B, M, S>
580
{
581
fn into_observer(self) -> Observer {
582
let (system, conditions) = self.take_conditions();
583
let mut observer = Observer::new(system);
584
observer.conditions = conditions;
585
observer
586
}
587
}
588
589
/// Trait for types that can be converted into an entity-targeting [`Observer`].
590
///
591
/// This trait enforces that the event type implements [`EntityEvent`].
592
#[diagnostic::on_unimplemented(
593
message = "`{Self}` cannot be used as an entity observer",
594
note = "entity observers require the event type to implement `EntityEvent`"
595
)]
596
pub trait IntoEntityObserver<Marker>: Send + 'static {
597
/// Converts this type into an [`Observer`] that watches the given entity.
598
fn into_observer_for_entity(self, entity: Entity) -> Observer;
599
}
600
601
impl<E: EntityEvent, B: Bundle, M, T: IntoObserverSystem<E, B, M>> IntoEntityObserver<(E, B, M)>
602
for T
603
{
604
fn into_observer_for_entity(self, entity: Entity) -> Observer {
605
Observer::new(self).with_entity(entity)
606
}
607
}
608
609
impl<E: EntityEvent, B: Bundle, M: 'static, S: IntoObserverSystem<E, B, M>>
610
IntoEntityObserver<ObserverWithConditionMarker> for ObserverWithCondition<E, B, M, S>
611
{
612
fn into_observer_for_entity(self, entity: Entity) -> Observer {
613
let (system, conditions) = self.take_conditions();
614
let mut observer = Observer::new(system);
615
observer.conditions = conditions;
616
observer.with_entity(entity)
617
}
618
}
619
620
/// Extension trait for adding run conditions to observer systems.
621
pub trait ObserverSystemExt<E: Event, B: Bundle, M>: IntoObserverSystem<E, B, M> + Sized {
622
/// Adds a run condition to this observer system.
623
///
624
/// The observer will only run if the condition returns `true`.
625
/// Multiple conditions can be chained (AND semantics).
626
fn run_if<C, CM>(self, condition: C) -> ObserverWithCondition<E, B, M, Self>
627
where
628
C: SystemCondition<CM>,
629
{
630
ObserverWithCondition {
631
system: self,
632
conditions: alloc::vec![Box::new(IntoSystem::into_system(condition))],
633
_marker: PhantomData,
634
}
635
}
636
}
637
638
impl<E: Event, B: Bundle, M, T: IntoObserverSystem<E, B, M>> ObserverSystemExt<E, B, M> for T {}
639
640