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 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
49/// Deprecated in favor of [`On`].
50#[deprecated(since = "0.17.0", note = "Renamed to `On`.")]
51pub type Trigger<'w, 't, E, B = ()> = On<'w, 't, E, B>;
52
53impl<'w, 't, E: Event, B: Bundle> On<'w, 't, E, B> {
54    /// Creates a new instance of [`On`] for the given triggered event.
55    pub fn new(
56        event: &'w mut E,
57        observer: Entity,
58        trigger: &'w mut E::Trigger<'t>,
59        trigger_context: &'w TriggerContext,
60    ) -> Self {
61        Self {
62            event,
63            observer,
64            trigger,
65            trigger_context,
66            _marker: PhantomData,
67        }
68    }
69
70    /// Returns the event type of this [`On`] instance.
71    pub fn event_key(&self) -> EventKey {
72        self.trigger_context.event_key
73    }
74
75    /// Returns a reference to the triggered event.
76    pub fn event(&self) -> &E {
77        self.event
78    }
79
80    /// Returns a mutable reference to the triggered event.
81    pub fn event_mut(&mut self) -> &mut E {
82        self.event
83    }
84
85    /// Returns a pointer to the triggered event.
86    pub fn event_ptr(&self) -> Ptr<'_> {
87        Ptr::from(&self.event)
88    }
89
90    /// Returns the [`Trigger`](crate::event::Trigger) context for this event.
91    pub fn trigger(&self) -> &E::Trigger<'t> {
92        self.trigger
93    }
94
95    /// Returns the mutable [`Trigger`](crate::event::Trigger) context for this event.
96    pub fn trigger_mut(&mut self) -> &mut E::Trigger<'t> {
97        self.trigger
98    }
99
100    /// Returns the [`Entity`] of the [`Observer`] of the triggered event.
101    /// This allows you to despawn the observer, ceasing observation.
102    ///
103    /// # Examples
104    ///
105    /// ```rust
106    /// # use bevy_ecs::prelude::*;
107    ///
108    /// #[derive(EntityEvent)]  
109    /// struct AssertEvent {
110    ///     entity: Entity,
111    /// }
112    ///
113    /// fn assert_observer(event: On<AssertEvent>) {  
114    ///     assert_eq!(event.observer(), event.entity);  
115    /// }  
116    ///
117    /// let mut world = World::new();  
118    /// let entity = world.spawn(Observer::new(assert_observer)).id();  
119    ///
120    /// world.trigger(AssertEvent { entity });  
121    /// ```
122    pub fn observer(&self) -> Entity {
123        self.observer
124    }
125
126    /// Returns the source code location that triggered this observer, if the `track_location` cargo feature is enabled.
127    pub fn caller(&self) -> MaybeLocation {
128        self.trigger_context.caller
129    }
130}
131
132impl<'w, 't, E: EntityEvent, B: Bundle> On<'w, 't, E, B> {
133    /// A deprecated way to retrieve the entity that this [`EntityEvent`] targeted at.
134    ///
135    /// Access the event via [`On::event`], then read the entity that the event was targeting.
136    /// Prefer using the field name directly for clarity,
137    /// but if you are working in a generic context, you can use [`EntityEvent::event_target`].
138    #[deprecated(
139        since = "0.17.0",
140        note = "Call On::event() to access the event, then read the target entity from the event directly."
141    )]
142    pub fn target(&self) -> Entity {
143        self.event.event_target()
144    }
145}
146
147impl<
148        'w,
149        't,
150        const AUTO_PROPAGATE: bool,
151        E: EntityEvent + for<'a> Event<Trigger<'a> = PropagateEntityTrigger<AUTO_PROPAGATE, E, T>>,
152        B: Bundle,
153        T: Traversal<E>,
154    > On<'w, 't, E, B>
155{
156    /// Returns the original [`Entity`] that this [`EntityEvent`] targeted via [`EntityEvent::event_target`] when it was _first_ triggered,
157    /// prior to any propagation logic.
158    pub fn original_event_target(&self) -> Entity {
159        self.trigger.original_event_target
160    }
161
162    /// Enables or disables event propagation, allowing the same event to trigger observers on a chain of different entities.
163    ///
164    /// The path an [`EntityEvent`] will propagate along is specified by the [`Traversal`] component defined in [`PropagateEntityTrigger`].
165    ///
166    /// [`EntityEvent`] does not propagate by default. To enable propagation, you must:
167    /// + Enable propagation in [`EntityEvent`] using `#[entity_event(propagate)]`. See [`EntityEvent`] for details.
168    /// + Either call `propagate(true)` in the first observer or in the [`EntityEvent`] derive add `#[entity_event(auto_propagate)]`.
169    ///
170    /// You can prevent an event from propagating further using `propagate(false)`. This will prevent the event from triggering on the next
171    /// [`Entity`] in the [`Traversal`], but note that all remaining observers for the _current_ entity will still run.
172    ///
173    ///
174    /// [`Traversal`]: crate::traversal::Traversal
175    pub fn propagate(&mut self, should_propagate: bool) {
176        self.trigger.propagate = should_propagate;
177    }
178
179    /// Returns the value of the flag that controls event propagation. See [`propagate`] for more information.
180    ///
181    /// [`propagate`]: On::propagate
182    pub fn get_propagate(&self) -> bool {
183        self.trigger.propagate
184    }
185}
186
187impl<'w, 't, E: for<'a> Event<Trigger<'a>: Debug> + Debug, B: Bundle> Debug for On<'w, 't, E, B> {
188    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
189        f.debug_struct("On")
190            .field("event", &self.event)
191            .field("trigger", &self.trigger)
192            .field("_marker", &self._marker)
193            .finish()
194    }
195}
196
197impl<'w, 't, E: Event, B: Bundle> Deref for On<'w, 't, E, B> {
198    type Target = E;
199
200    fn deref(&self) -> &Self::Target {
201        self.event
202    }
203}
204
205impl<'w, 't, E: Event, B: Bundle> DerefMut for On<'w, 't, E, B> {
206    fn deref_mut(&mut self) -> &mut Self::Target {
207        self.event
208    }
209}
210
211/// Metadata about a specific [`Event`] that triggered an observer.
212///
213/// This information is exposed via methods on [`On`].
214pub struct TriggerContext {
215    /// The [`EventKey`] the trigger targeted.
216    pub event_key: EventKey,
217    /// The location of the source code that triggered the observer.
218    pub caller: MaybeLocation,
219}