bevy_ecs/event/trigger.rs
1use crate::{
2 component::ComponentId,
3 entity::Entity,
4 event::{EntityEvent, Event},
5 observer::{CachedObservers, TriggerContext},
6 traversal::Traversal,
7 world::DeferredWorld,
8};
9use bevy_ptr::PtrMut;
10use core::{fmt, marker::PhantomData};
11
12/// [`Trigger`] determines _how_ an [`Event`] is triggered when [`World::trigger`](crate::world::World::trigger) is called.
13/// This decides which [`Observer`](crate::observer::Observer)s will run, what data gets passed to them, and the order they will
14/// be executed in.
15///
16/// Implementing [`Trigger`] is "advanced-level" territory, and is generally unnecessary unless you are developing highly specialized
17/// [`Event`] trigger logic.
18///
19/// Bevy comes with a number of built-in [`Trigger`] implementations (see their documentation for more info):
20/// - [`GlobalTrigger`]: The [`Event`] derive defaults to using this
21/// - [`EntityTrigger`]: The [`EntityEvent`] derive defaults to using this
22/// - [`PropagateEntityTrigger`]: The [`EntityEvent`] derive uses this when propagation is enabled.
23/// - [`EntityComponentsTrigger`]: Used by Bevy's [component lifecycle events](crate::lifecycle).
24///
25/// # Safety
26///
27/// Implementing this properly is _advanced_ soundness territory! Implementers must abide by the following:
28///
29/// - The `E`' [`Event::Trigger`] must be constrained to the implemented [`Trigger`] type, as part of the implementation.
30/// This prevents other [`Trigger`] implementations from directly deferring to your implementation, which is a very easy
31/// soundness misstep, as most [`Trigger`] implementations will invoke observers that are developed _for their specific [`Trigger`] type_.
32/// Without this constraint, something like [`GlobalTrigger`] could be called for _any_ [`Event`] type, even one that expects a different
33/// [`Trigger`] type. This would result in an unsound cast of [`GlobalTrigger`] reference.
34/// This is not expressed as an explicit type constraint,, as the `for<'a> Event::Trigger<'a>` lifetime can mismatch explicit lifetimes in
35/// some impls.
36pub unsafe trait Trigger<E: Event> {
37 /// Trigger the given `event`, running every [`Observer`](crate::observer::Observer) that matches the `event`, as defined by this
38 /// [`Trigger`] and the state stored on `self`.
39 ///
40 /// # Safety
41 /// - The [`CachedObservers`] `observers` must come from the [`DeferredWorld`] `world`
42 /// - [`TriggerContext`] must contain an [`EventKey`](crate::event::EventKey) that matches the `E` [`Event`] type
43 /// - `observers` must correspond to observers compatible with the event type `E`
44 /// - Read and abide by the "Safety" section defined in the top-level [`Trigger`] docs. Calling this function is
45 /// unintuitively risky. _Do not use it directly unless you know what you are doing_. Importantly, this should only
46 /// be called for an `event` whose [`Event::Trigger`] matches this trigger.
47 unsafe fn trigger(
48 &mut self,
49 world: DeferredWorld,
50 observers: &CachedObservers,
51 trigger_context: &TriggerContext,
52 event: &mut E,
53 );
54}
55
56/// A [`Trigger`] that runs _every_ "global" [`Observer`](crate::observer::Observer) (ex: registered via [`World::add_observer`](crate::world::World::add_observer))
57/// that matches the given [`Event`].
58///
59/// The [`Event`] derive defaults to using this [`Trigger`], and it is usable for any [`Event`] type.
60#[derive(Default, Debug)]
61pub struct GlobalTrigger;
62
63// SAFETY:
64// - `E`'s [`Event::Trigger`] is constrained to [`GlobalTrigger`]
65// - The implementation abides by the other safety constraints defined in [`Trigger`]
66unsafe impl<E: for<'a> Event<Trigger<'a> = Self>> Trigger<E> for GlobalTrigger {
67 unsafe fn trigger(
68 &mut self,
69 world: DeferredWorld,
70 observers: &CachedObservers,
71 trigger_context: &TriggerContext,
72 event: &mut E,
73 ) {
74 // SAFETY:
75 // - The caller of `trigger` ensures that `observers` come from the `world`
76 // - The passed in event ptr comes from `event`, which is E: Event
77 // - E: Event::Trigger is constrained to GlobalTrigger
78 // - The caller of `trigger` ensures that `TriggerContext::event_key` matches `event`
79 unsafe {
80 self.trigger_internal(world, observers, trigger_context, event.into());
81 }
82 }
83}
84
85impl GlobalTrigger {
86 /// # Safety
87 /// - `observers` must come from the `world` [`DeferredWorld`], and correspond to observers that match the `event` type
88 /// - `event` must point to an [`Event`]
89 /// - The `event` [`Event::Trigger`] must be [`GlobalTrigger`]
90 /// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.
91 unsafe fn trigger_internal(
92 &mut self,
93 mut world: DeferredWorld,
94 observers: &CachedObservers,
95 trigger_context: &TriggerContext,
96 mut event: PtrMut,
97 ) {
98 // SAFETY: `observers` is the only active reference to something in `world`
99 unsafe {
100 world.as_unsafe_world_cell().increment_trigger_id();
101 }
102 for (observer, runner) in observers.global_observers() {
103 // SAFETY:
104 // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`
105 // - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`
106 // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `event`, enforced by `trigger_internal`
107 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`
108 // - this abides by the nuances defined in the `Trigger` safety docs
109 unsafe {
110 (runner)(
111 world.reborrow(),
112 *observer,
113 trigger_context,
114 event.reborrow(),
115 self.into(),
116 );
117 }
118 }
119 }
120}
121
122/// An [`EntityEvent`] [`Trigger`] that does two things:
123/// - Runs all "global" [`Observer`] (ex: registered via [`World::add_observer`](crate::world::World::add_observer))
124/// that matches the given [`Event`]. This is the same behavior as [`GlobalTrigger`].
125/// - Runs every "entity scoped" [`Observer`] that watches the given [`EntityEvent::event_target`] entity.
126///
127/// The [`EntityEvent`] derive defaults to using this [`Trigger`], and it is usable for any [`EntityEvent`] type.
128///
129/// [`Observer`]: crate::observer::Observer
130#[derive(Default, Debug)]
131pub struct EntityTrigger;
132
133// SAFETY:
134// - `E`'s [`Event::Trigger`] is constrained to [`EntityTrigger`]
135// - The implementation abides by the other safety constraints defined in [`Trigger`]
136unsafe impl<E: EntityEvent + for<'a> Event<Trigger<'a> = Self>> Trigger<E> for EntityTrigger {
137 unsafe fn trigger(
138 &mut self,
139 world: DeferredWorld,
140 observers: &CachedObservers,
141 trigger_context: &TriggerContext,
142 event: &mut E,
143 ) {
144 let entity = event.event_target();
145 // SAFETY:
146 // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
147 // - the passed in event pointer comes from `event`, which is an `Event`
148 // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`
149 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
150 unsafe {
151 trigger_entity_internal(
152 world,
153 observers,
154 event.into(),
155 self.into(),
156 entity,
157 trigger_context,
158 );
159 }
160 }
161}
162
163/// Trigger observers watching for the given entity event.
164/// The `target_entity` should match the [`EntityEvent::event_target`] on `event` for logical correctness.
165///
166/// # Safety
167/// - `observers` must come from the `world` [`DeferredWorld`], and correspond to observers that match the `event` type
168/// - `event` must point to an [`Event`]
169/// - `trigger` must correspond to the [`Event::Trigger`] type expected by the `event`
170/// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.
171/// - Read, understand, and abide by the [`Trigger`] safety documentation
172// Note: this is not an EntityTrigger method because we want to reuse this logic for the entity propagation trigger
173#[inline(never)]
174pub unsafe fn trigger_entity_internal(
175 mut world: DeferredWorld,
176 observers: &CachedObservers,
177 mut event: PtrMut,
178 mut trigger: PtrMut,
179 target_entity: Entity,
180 trigger_context: &TriggerContext,
181) {
182 // SAFETY: there are no outstanding world references
183 unsafe {
184 world.as_unsafe_world_cell().increment_trigger_id();
185 }
186 for (observer, runner) in observers.global_observers() {
187 // SAFETY:
188 // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_entity_internal`
189 // - the passed in event pointer is an `Event`, enforced by the call to `trigger_entity_internal`
190 // - `trigger` is a matching trigger type, enforced by the call to `trigger_entity_internal`
191 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_entity_internal`
192 unsafe {
193 (runner)(
194 world.reborrow(),
195 *observer,
196 trigger_context,
197 event.reborrow(),
198 trigger.reborrow(),
199 );
200 }
201 }
202
203 if let Some(map) = observers.entity_observers().get(&target_entity) {
204 for (observer, runner) in map {
205 // SAFETY:
206 // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_entity_internal`
207 // - the passed in event pointer is an `Event`, enforced by the call to `trigger_entity_internal`
208 // - `trigger` is a matching trigger type, enforced by the call to `trigger_entity_internal`
209 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_entity_internal`
210 unsafe {
211 (runner)(
212 world.reborrow(),
213 *observer,
214 trigger_context,
215 event.reborrow(),
216 trigger.reborrow(),
217 );
218 }
219 }
220 }
221}
222
223/// An [`EntityEvent`] [`Trigger`] that behaves like [`EntityTrigger`], but "propagates" the event
224/// using an [`Entity`] [`Traversal`]. At each step in the propagation, the [`EntityTrigger`] logic will
225/// be run, until [`PropagateEntityTrigger::propagate`] is false, or there are no entities left to traverse.
226///
227/// This is used by the [`EntityEvent`] derive when `#[entity_event(propagate)]` is enabled. It is usable by every
228/// [`EntityEvent`] type.
229///
230/// If `AUTO_PROPAGATE` is `true`, [`PropagateEntityTrigger::propagate`] will default to `true`.
231pub struct PropagateEntityTrigger<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> {
232 /// The original [`Entity`] the [`Event`] was _first_ triggered for.
233 pub original_event_target: Entity,
234
235 /// Whether or not to continue propagating using the `T` [`Traversal`]. If this is false,
236 /// The [`Traversal`] will stop on the current entity.
237 pub propagate: bool,
238
239 _marker: PhantomData<(E, T)>,
240}
241
242impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> Default
243 for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>
244{
245 fn default() -> Self {
246 Self {
247 original_event_target: Entity::PLACEHOLDER,
248 propagate: AUTO_PROPAGATE,
249 _marker: Default::default(),
250 }
251 }
252}
253
254impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> fmt::Debug
255 for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>
256{
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 f.debug_struct("PropagateEntityTrigger")
259 .field("original_event_target", &self.original_event_target)
260 .field("propagate", &self.propagate)
261 .field("_marker", &self._marker)
262 .finish()
263 }
264}
265
266// SAFETY:
267// - `E`'s [`Event::Trigger`] is constrained to [`PropagateEntityTrigger<E>`]
268unsafe impl<
269 const AUTO_PROPAGATE: bool,
270 E: EntityEvent + for<'a> Event<Trigger<'a> = Self>,
271 T: Traversal<E>,
272 > Trigger<E> for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>
273{
274 unsafe fn trigger(
275 &mut self,
276 mut world: DeferredWorld,
277 observers: &CachedObservers,
278 trigger_context: &TriggerContext,
279 event: &mut E,
280 ) {
281 let mut current_entity = event.event_target();
282 self.original_event_target = current_entity;
283 // SAFETY:
284 // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
285 // - the passed in event pointer comes from `event`, which is an `Event`
286 // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`
287 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
288 unsafe {
289 trigger_entity_internal(
290 world.reborrow(),
291 observers,
292 event.into(),
293 self.into(),
294 current_entity,
295 trigger_context,
296 );
297 }
298
299 loop {
300 if !self.propagate {
301 return;
302 }
303 if let Ok(entity) = world.get_entity(current_entity)
304 && let Some(item) = entity.get_components::<T>()
305 && let Some(traverse_to) = T::traverse(item, event)
306 {
307 current_entity = traverse_to;
308 } else {
309 break;
310 }
311
312 *event.event_target_mut() = current_entity;
313 // SAFETY:
314 // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
315 // - the passed in event pointer comes from `event`, which is an `Event`
316 // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`
317 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
318 unsafe {
319 trigger_entity_internal(
320 world.reborrow(),
321 observers,
322 event.into(),
323 self.into(),
324 current_entity,
325 trigger_context,
326 );
327 }
328 }
329 }
330}
331
332/// An [`EntityEvent`] [`Trigger`] that, in addition to behaving like a normal [`EntityTrigger`], _also_ runs observers
333/// that watch for components that match the slice of [`ComponentId`]s referenced in [`EntityComponentsTrigger`]. This includes
334/// both _global_ observers of those components and "entity scoped" observers that watch the [`EntityEvent::event_target`].
335///
336/// This is used by Bevy's built-in [lifecycle events](crate::lifecycle).
337#[derive(Default)]
338pub struct EntityComponentsTrigger<'a> {
339 /// All of the components whose observers were triggered together for the target entity. For example,
340 /// if components `A` and `B` are added together, producing the [`Add`](crate::lifecycle::Add) event, this will
341 /// contain the [`ComponentId`] for both `A` and `B`.
342 pub components: &'a [ComponentId],
343}
344
345// SAFETY:
346// - `E`'s [`Event::Trigger`] is constrained to [`EntityComponentsTrigger`]
347unsafe impl<'a, E: EntityEvent + Event<Trigger<'a> = EntityComponentsTrigger<'a>>> Trigger<E>
348 for EntityComponentsTrigger<'a>
349{
350 unsafe fn trigger(
351 &mut self,
352 world: DeferredWorld,
353 observers: &CachedObservers,
354 trigger_context: &TriggerContext,
355 event: &mut E,
356 ) {
357 let entity = event.event_target();
358 // SAFETY:
359 // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
360 // - the passed in event pointer comes from `event`, which is an `Event`
361 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
362 unsafe {
363 self.trigger_internal(world, observers, event.into(), entity, trigger_context);
364 }
365 }
366}
367
368impl<'a> EntityComponentsTrigger<'a> {
369 /// # Safety
370 /// - `observers` must come from the `world` [`DeferredWorld`]
371 /// - `event` must point to an [`Event`] whose [`Event::Trigger`] is [`EntityComponentsTrigger`]
372 /// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.
373 #[inline(never)]
374 unsafe fn trigger_internal(
375 &mut self,
376 mut world: DeferredWorld,
377 observers: &CachedObservers,
378 mut event: PtrMut,
379 entity: Entity,
380 trigger_context: &TriggerContext,
381 ) {
382 // SAFETY:
383 // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
384 // - the passed in event pointer comes from `event`, which is an `Event`
385 // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`
386 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
387 unsafe {
388 trigger_entity_internal(
389 world.reborrow(),
390 observers,
391 event.reborrow(),
392 self.into(),
393 entity,
394 trigger_context,
395 );
396 }
397
398 // Trigger observers watching for a specific component
399 for id in self.components {
400 if let Some(component_observers) = observers.component_observers().get(id) {
401 for (observer, runner) in component_observers.global_observers() {
402 // SAFETY:
403 // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`
404 // - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`
405 // - `trigger` is a matching trigger type, enforced by the call to `trigger_internal`
406 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`
407 unsafe {
408 (runner)(
409 world.reborrow(),
410 *observer,
411 trigger_context,
412 event.reborrow(),
413 self.into(),
414 );
415 }
416 }
417
418 if let Some(map) = component_observers
419 .entity_component_observers()
420 .get(&entity)
421 {
422 for (observer, runner) in map {
423 // SAFETY:
424 // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`
425 // - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`
426 // - `trigger` is a matching trigger type, enforced by the call to `trigger_internal`
427 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`
428 unsafe {
429 (runner)(
430 world.reborrow(),
431 *observer,
432 trigger_context,
433 event.reborrow(),
434 self.into(),
435 );
436 }
437 }
438 }
439 }
440 }
441 }
442}