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