Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/event/trigger.rs
6849 views
1
use crate::{
2
component::ComponentId,
3
entity::Entity,
4
event::{EntityEvent, Event},
5
observer::{CachedObservers, TriggerContext},
6
traversal::Traversal,
7
world::DeferredWorld,
8
};
9
use bevy_ptr::PtrMut;
10
use 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.
36
pub 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)]
61
pub 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`]
66
unsafe 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
85
impl 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)]
131
pub 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`]
136
unsafe 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)]
174
pub 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`.
231
pub 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
242
impl<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
254
impl<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>`]
268
unsafe 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)]
338
pub 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`]
347
unsafe 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
368
impl<'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
}
443
444