Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/event/trigger.rs
9354 views
1
use crate::event::SetEntityEventTarget;
2
use crate::{
3
component::ComponentId,
4
entity::Entity,
5
event::{EntityEvent, Event},
6
observer::{CachedObservers, TriggerContext},
7
traversal::Traversal,
8
world::DeferredWorld,
9
};
10
use bevy_ptr::PtrMut;
11
use 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.
37
pub 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)]
62
pub 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`]
67
unsafe 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
86
impl 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)]
132
pub 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`]
137
unsafe 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)]
175
pub 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`.
232
pub 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
243
impl<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
255
impl<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>`]
269
unsafe 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)]
339
pub 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`]
348
unsafe 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
369
impl<'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
}
444
445