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