bevy_ecs/observer/
trigger_event.rs

1use crate::{
2    component::ComponentId,
3    entity::Entity,
4    event::Event,
5    world::{Command, DeferredWorld, World},
6};
7
8/// A [`Command`] that emits a given trigger for a given set of targets.
9pub struct TriggerEvent<E, Targets: TriggerTargets = ()> {
10    /// The event to trigger.
11    pub event: E,
12
13    /// The targets to trigger the event for.
14    pub targets: Targets,
15}
16
17impl<E: Event, Targets: TriggerTargets> Command for TriggerEvent<E, Targets> {
18    fn apply(mut self, world: &mut World) {
19        let event_type = world.init_component::<E>();
20        trigger_event(world, event_type, &mut self.event, self.targets);
21    }
22}
23
24/// Emit a trigger for a dynamic component id. This is unsafe and must be verified manually.
25pub struct EmitDynamicTrigger<T, Targets: TriggerTargets = ()> {
26    event_type: ComponentId,
27    event_data: T,
28    targets: Targets,
29}
30
31impl<E, Targets: TriggerTargets> EmitDynamicTrigger<E, Targets> {
32    /// Sets the event type of the resulting trigger, used for dynamic triggers
33    /// # Safety
34    /// Caller must ensure that the component associated with `event_type` is accessible as E
35    pub unsafe fn new_with_id(event_type: ComponentId, event_data: E, targets: Targets) -> Self {
36        Self {
37            event_type,
38            event_data,
39            targets,
40        }
41    }
42}
43
44impl<E: Event, Targets: TriggerTargets> Command for EmitDynamicTrigger<E, Targets> {
45    fn apply(mut self, world: &mut World) {
46        trigger_event(world, self.event_type, &mut self.event_data, self.targets);
47    }
48}
49
50#[inline]
51fn trigger_event<E, Targets: TriggerTargets>(
52    world: &mut World,
53    event_type: ComponentId,
54    event_data: &mut E,
55    targets: Targets,
56) {
57    let mut world = DeferredWorld::from(world);
58    if targets.entities().len() == 0 {
59        // SAFETY: T is accessible as the type represented by self.trigger, ensured in `Self::new`
60        unsafe {
61            world.trigger_observers_with_data(
62                event_type,
63                Entity::PLACEHOLDER,
64                targets.components(),
65                event_data,
66            );
67        };
68    } else {
69        for target in targets.entities() {
70            // SAFETY: T is accessible as the type represented by self.trigger, ensured in `Self::new`
71            unsafe {
72                world.trigger_observers_with_data(
73                    event_type,
74                    target,
75                    targets.components(),
76                    event_data,
77                );
78            };
79        }
80    }
81}
82
83/// Represents a collection of targets for a specific [`Trigger`] of an [`Event`]. Targets can be of type [`Entity`] or [`ComponentId`].
84/// When a trigger occurs for a given event and [`TriggerTargets`], any [`Observer`] that watches for that specific event-target combination
85/// will run.
86///
87/// [`Trigger`]: crate::observer::Trigger
88/// [`Observer`]: crate::observer::Observer
89pub trait TriggerTargets: Send + Sync + 'static {
90    /// The components the trigger should target.
91    fn components(&self) -> impl ExactSizeIterator<Item = ComponentId>;
92
93    /// The entities the trigger should target.
94    fn entities(&self) -> impl ExactSizeIterator<Item = Entity>;
95}
96
97impl TriggerTargets for () {
98    fn components(&self) -> impl ExactSizeIterator<Item = ComponentId> {
99        [].into_iter()
100    }
101
102    fn entities(&self) -> impl ExactSizeIterator<Item = Entity> {
103        [].into_iter()
104    }
105}
106
107impl TriggerTargets for Entity {
108    fn components(&self) -> impl ExactSizeIterator<Item = ComponentId> {
109        [].into_iter()
110    }
111
112    fn entities(&self) -> impl ExactSizeIterator<Item = Entity> {
113        std::iter::once(*self)
114    }
115}
116
117impl TriggerTargets for Vec<Entity> {
118    fn components(&self) -> impl ExactSizeIterator<Item = ComponentId> {
119        [].into_iter()
120    }
121
122    fn entities(&self) -> impl ExactSizeIterator<Item = Entity> {
123        self.iter().copied()
124    }
125}
126
127impl<const N: usize> TriggerTargets for [Entity; N] {
128    fn components(&self) -> impl ExactSizeIterator<Item = ComponentId> {
129        [].into_iter()
130    }
131
132    fn entities(&self) -> impl ExactSizeIterator<Item = Entity> {
133        self.iter().copied()
134    }
135}
136
137impl TriggerTargets for ComponentId {
138    fn components(&self) -> impl ExactSizeIterator<Item = ComponentId> {
139        std::iter::once(*self)
140    }
141
142    fn entities(&self) -> impl ExactSizeIterator<Item = Entity> {
143        [].into_iter()
144    }
145}
146
147impl TriggerTargets for Vec<ComponentId> {
148    fn components(&self) -> impl ExactSizeIterator<Item = ComponentId> {
149        self.iter().copied()
150    }
151
152    fn entities(&self) -> impl ExactSizeIterator<Item = Entity> {
153        [].into_iter()
154    }
155}
156
157impl<const N: usize> TriggerTargets for [ComponentId; N] {
158    fn components(&self) -> impl ExactSizeIterator<Item = ComponentId> {
159        self.iter().copied()
160    }
161
162    fn entities(&self) -> impl ExactSizeIterator<Item = Entity> {
163        [].into_iter()
164    }
165}