1- //! Types for creating and storing [`Observer`]s
1+ //! Observers are a push-based tool for responding to [`Event`]s.
2+ //!
3+ //! ## Observer targeting
4+ //!
5+ //! Observers can be "global", listening for events that are both targeted at and not targeted at any specific entity,
6+ //! or they can be "entity-specific", listening for events that are targeted at specific entities.
7+ //!
8+ //! They can also be further refined by listening to events targeted at specific components
9+ //! (instead of using a generic event type), as is done with the [`OnAdd`] family of lifecycle events.
10+ //!
11+ //! When entities are observed, they will receive an [`ObservedBy`] component,
12+ //! which will be updated to track the observers that are currently observing them.
13+ //!
14+ //! Currently, [observers cannot be retargeted after spawning](https://github.com/bevyengine/bevy/issues/19587):
15+ //! despawn and respawn an observer as a workaround.
16+ //!
17+ //! ## Writing observers
18+ //!
19+ //! Observers are systems which implement [`IntoObserverSystem`] that listen for [`Event`]s matching their
20+ //! type and target(s).
21+ //! To write observer systems, use the [`Trigger`] system parameter as the first parameter of your system.
22+ //! This parameter provides access to the specific event that triggered the observer,
23+ //! as well as the entity that the event was targeted at, if any.
24+ //!
25+ //! Observers can request other data from the world,
26+ //! such as via a [`Query`] or [`Res`]. Commonly, you might want to verify that
27+ //! the entity that the observable event is targeting has a specific component,
28+ //! or meets some other condition.
29+ //! [`Query::get`] or [`Query::contains`] on the [`Trigger::target`] entity
30+ //! is a good way to do this.
31+ //!
32+ //! [`Commands`] can also be used inside of observers.
33+ //! This can be particularly useful for triggering other observers!
34+ //!
35+ //! ## Spawning observers
36+ //!
37+ //! Observers can be spawned via [`World::add_observer`], or the equivalent app method.
38+ //! This will cause an entity with the [`Observer`] component to be created,
39+ //! which will then run the observer system whenever the event it is watching is triggered.
40+ //!
41+ //! You can control the targets that an observer is watching by calling [`Observer::watch_entity`]
42+ //! once the entity is spawned, or by manually spawning an entity with the [`Observer`] component
43+ //! configured with the desired targets.
44+ //!
45+ //! Observers are fundamentally defined as "entities which have the [`Observer`] component"
46+ //! allowing you to add it manually to existing entities.
47+ //! At first, this seems convenient, but only one observer can be added to an entity at a time,
48+ //! regardless of the event it responds to: like always, components are unique.
49+ //!
50+ //! Instead, a better way to achieve a similar aim is to
51+ //! use the [`EntityWorldMut::observe`] / [`EntityCommands::observe`] method,
52+ //! which spawns a new observer, and configures it to watch the entity it is called on.
53+ //! Unfortunately, observers defined in this way
54+ //! [currently cannot be spawned as part of bundles](https://github.com/bevyengine/bevy/issues/14204).
55+ //!
56+ //! ## Triggering observers
57+ //!
58+ //! Observers are most commonly triggered by [`Commands`],
59+ //! via [`Commands::trigger`] (for untargeted events) or [`Commands::trigger_targets`] (for targeted events).
60+ //! Like usual, equivalent methods are available on [`World`], allowing you to reduce overhead when working with exclusive world access.
61+ //!
62+ //! If your observer is configured to watch for a specific component or set of components instead,
63+ //! you can pass in [`ComponentId`]s into [`Commands::trigger_targets`] by using the [`TriggerTargets`] trait.
64+ //! As discussed in the [`Trigger`] documentation, this use case is rare, and is currently only used
65+ //! for [lifecycle](crate::lifecycle) events, which are automatically emitted.
66+ //!
67+ //! ## Observer bubbling
68+ //!
69+ //! When events are targeted at an entity, they can optionally bubble to other targets,
70+ //! typically up to parents in an entity hierarchy.
71+ //!
72+ //! This behavior is controlled via [`Event::Traversal`] and [`Event::AUTO_PROPAGATE`],
73+ //! with the details of the propagation path specified by the [`Traversal`](crate::traversal::Traversal) trait.
74+ //!
75+ //! When auto-propagation is enabled, propagaion must be manually stopped to prevent the event from
76+ //! continuing to other targets.
77+ //! This can be done using the [`Trigger::propagate`] method on the [`Trigger`] system parameter inside of your observer.
78+ //!
79+ //! ## Observer timing
80+ //!
81+ //! Observers are triggered via [`Commands`], which imply that they are evaluated at the next sync point in the ECS schedule.
82+ //! Accordingly, they have full access to the world, and are evaluated sequentially, in the order that the commands were sent.
83+ //!
84+ //! To control the relative ordering of observers sent from different systems,
85+ //! order the systems in the schedule relative to each other.
86+ //!
87+ //! Currently, Bevy does not provide [a way to specify the ordering of observers](https://github.com/bevyengine/bevy/issues/14890)
88+ //! listening to the same event relative to each other.
89+ //!
90+ //! Commands sent by observers are [currently not immediately applied](https://github.com/bevyengine/bevy/issues/19569).
91+ //! Instead, all queued observers will run, and then all of the commands from those observers will be applied.
92+ //! Careful use of [`Schedule::apply_deferred`] may help as a workaround.
93+ //!
94+ //! ## Lifecycle events and observers
95+ //!
96+ //! It is important to note that observers, just like [hooks](crate::lifecycle::ComponentHooks),
97+ //! can listen to and respond to [lifecycle](crate::lifecycle) events.
98+ //! Unlike hooks, observers are not treated as an "innate" part of component behavior:
99+ //! they can be added or removed at runtime, and multiple observers
100+ //! can be registered for the same lifecycle event for the same component.
101+ //!
102+ //! The ordering of hooks versus observers differs based on the lifecycle event in question:
103+ //!
104+ //! - when adding components, hooks are evaluated first, then observers
105+ //! - when removing components, observers are evaluated first, then hooks
106+ //!
107+ //! This allows hooks to act as constructors and destructors for components,
108+ //! as they always have the first and final say in the component's lifecycle.
109+ //!
110+ //! ## Cleaning up observers
111+ //!
112+ //! Currently, observer entities are never cleaned up, even if their target entity(s) are despawned.
113+ //! This won't cause any runtime overhead, but is a waste of memory and can result in memory leaks.
114+ //!
115+ //! If you run into this problem, you could manually scan the world for observer entities and despawn them,
116+ //! by checking if the entity in [`Observer::descriptor`] still exists.
117+ //!
118+ //! ## Observers vs buffered events
119+ //!
120+ //! By contrast, [`EventReader`] and [`EventWriter`] ("buffered events"), are pull-based.
121+ //! They require periodically polling the world to check for new events, typically in a system that runs as part of a schedule.
122+ //!
123+ //! This imposes a small overhead, making observers a better choice for extremely rare events,
124+ //! but buffered events can be more efficient for events that are expected to occur multiple times per frame,
125+ //! as it allows for batch processing of events.
126+ //!
127+ //! The difference in timing is also an important consideration:
128+ //! buffered events are evaluated at fixed points during schedules,
129+ //! while observers are evaluated as soon as possible after the event is triggered.
130+ //!
131+ //! This provides more control over the timing of buffered event evaluation,
132+ //! but allows for a more ad hoc approach with observers,
133+ //! and enables indefinite chaining of observers triggering other observers (for both better and worse!).
2134
3135mod entity_observer;
4136mod runner;
@@ -29,6 +161,17 @@ use smallvec::SmallVec;
29161/// Type containing triggered [`Event`] information for a given run of an [`Observer`]. This contains the
30162/// [`Event`] data itself. If it was triggered for a specific [`Entity`], it includes that as well. It also
31163/// contains event propagation information. See [`Trigger::propagate`] for more information.
164+ ///
165+ /// The generic `B: Bundle` is used to modify the further specialize the events that this observer is interested in.
166+ /// The entity involved *does not* have to have these components, but the observer will only be
167+ /// triggered if the event matches the components in `B`.
168+ ///
169+ /// This is used to to avoid providing a generic argument in your event, as is done for [`OnAdd`]
170+ /// and the other lifecycle events.
171+ ///
172+ /// Providing multiple components in this bundle will cause this event to be triggered by any
173+ /// matching component in the bundle,
174+ /// [rather than requiring all of them to be present](https://github.com/bevyengine/bevy/issues/15325).
32175pub struct Trigger < ' w , E , B : Bundle = ( ) > {
33176 event : & ' w mut E ,
34177 propagate : & ' w mut bool ,
@@ -69,18 +212,6 @@ impl<'w, E, B: Bundle> Trigger<'w, E, B> {
69212
70213 /// Returns the [`Entity`] that was targeted by the `event` that triggered this observer. It may
71214 /// be [`None`] if the trigger is not for a particular entity.
72- ///
73- /// Observable events can target specific entities. When those events fire, they will trigger
74- /// any observers on the targeted entities. In this case, the `target()` and `observer()` are
75- /// the same, because the observer that was triggered is attached to the entity that was
76- /// targeted by the event.
77- ///
78- /// However, it is also possible for those events to bubble up the entity hierarchy and trigger
79- /// observers on *different* entities, or trigger a global observer. In these cases, the
80- /// observing entity is *different* from the entity being targeted by the event.
81- ///
82- /// This is an important distinction: the entity reacting to an event is not always the same as
83- /// the entity triggered by the event.
84215 pub fn target ( & self ) -> Option < Entity > {
85216 self . trigger . target
86217 }
@@ -172,10 +303,14 @@ impl<'w, E, B: Bundle> DerefMut for Trigger<'w, E, B> {
172303 }
173304}
174305
175- /// Represents a collection of targets for a specific [`Trigger`] of an [`Event`]. Targets can be of type [`Entity`] or [`ComponentId`].
306+ /// Represents a collection of targets for a specific [`Trigger`] of an [`Event`].
176307///
177308/// When a trigger occurs for a given event and [`TriggerTargets`], any [`Observer`] that watches for that specific event-target combination
178309/// will run.
310+ ///
311+ /// This trait is implemented for both [`Entity`] and [`ComponentId`], allowing you to target specific entities or components.
312+ /// It is also implemented for various collections of these types, such as [`Vec`], arrays, and tuples,
313+ /// allowing you to trigger events for multiple targets at once.
179314pub trait TriggerTargets {
180315 /// The components the trigger should target.
181316 fn components ( & self ) -> impl Iterator < Item = ComponentId > + Clone + ' _ ;
@@ -280,7 +415,9 @@ all_tuples!(
280415 T
281416) ;
282417
283- /// A description of what an [`Observer`] observes.
418+ /// Store information about what an [`Observer`] observes.
419+ ///
420+ /// This information is stored inside of the [`Observer`] component,
284421#[ derive( Default , Clone ) ]
285422pub struct ObserverDescriptor {
286423 /// The events the observer is watching.
@@ -331,7 +468,9 @@ impl ObserverDescriptor {
331468 }
332469}
333470
334- /// Event trigger metadata for a given [`Observer`],
471+ /// Metadata about a specific [`Event`] which triggered an observer.
472+ ///
473+ /// This information is exposed via methods on the [`Trigger`] system parameter.
335474#[ derive( Debug ) ]
336475pub struct ObserverTrigger {
337476 /// The [`Entity`] of the observer handling the trigger.
@@ -357,6 +496,8 @@ impl ObserverTrigger {
357496type ObserverMap = EntityHashMap < ObserverRunner > ;
358497
359498/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular trigger targeted at a specific component.
499+ ///
500+ /// This is stored inside of [`CachedObservers`].
360501#[ derive( Default , Debug ) ]
361502pub struct CachedComponentObservers {
362503 // Observers listening to triggers targeting this component
@@ -366,6 +507,8 @@ pub struct CachedComponentObservers {
366507}
367508
368509/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular trigger.
510+ ///
511+ /// This is stored inside of [`Observers`], specialized for each kind of observer.
369512#[ derive( Default , Debug ) ]
370513pub struct CachedObservers {
371514 // Observers listening for any time this trigger is fired
@@ -376,7 +519,13 @@ pub struct CachedObservers {
376519 entity_observers : EntityHashMap < ObserverMap > ,
377520}
378521
379- /// Metadata for observers. Stores a cache mapping trigger ids to the registered observers.
522+ /// An internal lookup table tracking all of the observers in the world.
523+ ///
524+ /// Stores a cache mapping trigger ids to the registered observers.
525+ /// Some observer kinds (like [lifecycle](crate::lifecycle) observers) have a dedicated field,
526+ /// saving lookups for the most common triggers.
527+ ///
528+ /// This is stored as a field of the [`World`].
380529#[ derive( Default , Debug ) ]
381530pub struct Observers {
382531 // Cached ECS observers to save a lookup most common triggers.
@@ -385,7 +534,7 @@ pub struct Observers {
385534 on_replace : CachedObservers ,
386535 on_remove : CachedObservers ,
387536 on_despawn : CachedObservers ,
388- // Map from trigger type to set of observers
537+ // Map from trigger type to set of observers listening to that trigger
389538 cache : HashMap < ComponentId , CachedObservers > ,
390539}
391540
0 commit comments