bevy_ecs/observer/system_param.rs
1//! System parameters for working with observers.
2
3use crate::{
4 change_detection::MaybeLocation,
5 event::{Event, EventKey, EventPattern, EventPatternTrigger, PropagateEntityTrigger},
6 prelude::*,
7 traversal::Traversal,
8};
9use bevy_ptr::Ptr;
10use core::{
11 fmt::Debug,
12 ops::{Deref, DerefMut},
13};
14
15/// A [system parameter] used by an observer to process events. See [`Observer`] and [`Event`] for examples.
16///
17/// `On` contains the triggered [`Event`] data for a given run of an `Observer`. It also provides access to the
18/// [`Trigger`](crate::event::Trigger), which for things like [`EntityEvent`] with a [`PropagateEntityTrigger`],
19/// includes control over event propagation.
20///
21/// [system parameter]: crate::system::SystemParam
22// SAFETY WARNING!
23// this type must _never_ expose anything with the 'w lifetime
24// See the safety discussion on `Trigger` for more details.
25pub struct On<'w, 't, E: EventPattern> {
26 observer: Entity,
27 // SAFETY WARNING: never expose this 'w lifetime
28 event: &'w mut E::Event,
29 // SAFETY WARNING: never expose this 'w lifetime
30 trigger: &'w mut EventPatternTrigger<'t, E>,
31 // SAFETY WARNING: never expose this 'w lifetime
32 trigger_context: &'w TriggerContext,
33}
34
35impl<'w, 't, E: EventPattern> On<'w, 't, E> {
36 /// Creates a new instance of [`On`] for the given triggered event.
37 pub fn new(
38 event: &'w mut E::Event,
39 observer: Entity,
40 trigger: &'w mut EventPatternTrigger<'t, E>,
41 trigger_context: &'w TriggerContext,
42 ) -> Self {
43 Self {
44 event,
45 observer,
46 trigger,
47 trigger_context,
48 }
49 }
50
51 /// Returns the event type of this [`On`] instance.
52 pub fn event_key(&self) -> EventKey {
53 self.trigger_context.event_key
54 }
55
56 /// Returns a reference to the triggered event.
57 pub fn event(&self) -> &E::Event {
58 self.event
59 }
60
61 /// Returns a mutable reference to the triggered event.
62 pub fn event_mut(&mut self) -> &mut E::Event {
63 self.event
64 }
65
66 /// Returns a pointer to the triggered event.
67 pub fn event_ptr(&self) -> Ptr<'_> {
68 Ptr::from(&self.event)
69 }
70
71 /// Returns the [`Trigger`](crate::event::Trigger) context for this event.
72 pub fn trigger(&self) -> &EventPatternTrigger<'t, E> {
73 self.trigger
74 }
75
76 /// Returns the mutable [`Trigger`](crate::event::Trigger) context for this event.
77 pub fn trigger_mut(&mut self) -> &mut EventPatternTrigger<'t, E> {
78 self.trigger
79 }
80
81 /// Returns the [`Entity`] of the [`Observer`] of the triggered event.
82 /// This allows you to despawn the observer, ceasing observation.
83 ///
84 /// # Examples
85 ///
86 /// ```rust
87 /// # use bevy_ecs::prelude::*;
88 ///
89 /// #[derive(EntityEvent)]
90 /// struct AssertEvent {
91 /// entity: Entity,
92 /// }
93 ///
94 /// fn assert_observer(event: On<AssertEvent>) {
95 /// assert_eq!(event.observer(), event.entity);
96 /// }
97 ///
98 /// let mut world = World::new();
99 /// let entity = world.spawn(Observer::new(assert_observer)).id();
100 ///
101 /// world.trigger(AssertEvent { entity });
102 /// ```
103 pub fn observer(&self) -> Entity {
104 self.observer
105 }
106
107 /// Returns the source code location that triggered this observer, if the `track_location` cargo feature is enabled.
108 pub fn caller(&self) -> MaybeLocation {
109 self.trigger_context.caller
110 }
111}
112
113impl<'w, 't, const AUTO_PROPAGATE: bool, E, T> On<'w, 't, E>
114where
115 E: EventPattern<
116 Event: EntityEvent<Trigger<'t> = PropagateEntityTrigger<AUTO_PROPAGATE, E::Event, T>>,
117 >,
118 T: Traversal<E::Event>,
119{
120 /// Returns the original [`Entity`] that this [`EntityEvent`] targeted via [`EntityEvent::event_target`] when it was _first_ triggered,
121 /// prior to any propagation logic.
122 pub fn original_event_target(&self) -> Entity {
123 self.trigger.original_event_target
124 }
125
126 /// Enables or disables event propagation, allowing the same event to trigger observers on a chain of different entities.
127 ///
128 /// The path an [`EntityEvent`] will propagate along is specified by the [`Traversal`] component defined in [`PropagateEntityTrigger`].
129 ///
130 /// [`EntityEvent`] does not propagate by default. To enable propagation, you must:
131 /// + Enable propagation in [`EntityEvent`] using `#[entity_event(propagate)]`. See [`EntityEvent`] for details.
132 /// + Either call `propagate(true)` in the first observer or in the [`EntityEvent`] derive add `#[entity_event(auto_propagate)]`.
133 ///
134 /// You can prevent an event from propagating further using `propagate(false)`. This will prevent the event from triggering on the next
135 /// [`Entity`] in the [`Traversal`], but note that all remaining observers for the _current_ entity will still run.
136 ///
137 ///
138 /// [`Traversal`]: crate::traversal::Traversal
139 pub fn propagate(&mut self, should_propagate: bool) {
140 self.trigger.propagate = should_propagate;
141 }
142
143 /// Returns the value of the flag that controls event propagation. See [`propagate`] for more information.
144 ///
145 /// [`propagate`]: On::propagate
146 pub fn get_propagate(&self) -> bool {
147 self.trigger.propagate
148 }
149}
150
151impl<'w, 't, E> Debug for On<'w, 't, E>
152where
153 E: EventPattern,
154 E::Event: Event<Trigger<'t>: Debug> + Debug,
155{
156 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
157 f.debug_struct("On")
158 .field("event", &self.event)
159 .field("trigger", &self.trigger)
160 .finish()
161 }
162}
163
164impl<'w, 't, E: EventPattern> Deref for On<'w, 't, E> {
165 type Target = E::Event;
166
167 fn deref(&self) -> &Self::Target {
168 self.event
169 }
170}
171
172impl<'w, 't, E: EventPattern> DerefMut for On<'w, 't, E> {
173 fn deref_mut(&mut self) -> &mut Self::Target {
174 self.event
175 }
176}
177
178/// Metadata about a specific [`Event`] that triggered an observer.
179///
180/// This information is exposed via methods on [`On`].
181pub struct TriggerContext {
182 /// The [`EventKey`] the trigger targeted.
183 pub event_key: EventKey,
184 /// The location of the source code that triggered the observer.
185 pub caller: MaybeLocation,
186}