bevy_ecs/observer/
mod.rs

1//! Types for creating and storing [`Observer`]s
2
3mod entity_observer;
4mod runner;
5mod trigger_event;
6
7pub use runner::*;
8pub use trigger_event::*;
9
10use crate::observer::entity_observer::ObservedBy;
11use crate::{archetype::ArchetypeFlags, system::IntoObserverSystem, world::*};
12use crate::{component::ComponentId, prelude::*, world::DeferredWorld};
13use bevy_ptr::Ptr;
14use bevy_utils::{EntityHashMap, HashMap};
15use std::marker::PhantomData;
16
17/// Type containing triggered [`Event`] information for a given run of an [`Observer`]. This contains the
18/// [`Event`] data itself. If it was triggered for a specific [`Entity`], it includes that as well.
19pub struct Trigger<'w, E, B: Bundle = ()> {
20    event: &'w mut E,
21    trigger: ObserverTrigger,
22    _marker: PhantomData<B>,
23}
24
25impl<'w, E, B: Bundle> Trigger<'w, E, B> {
26    /// Creates a new trigger for the given event and observer information.
27    pub fn new(event: &'w mut E, trigger: ObserverTrigger) -> Self {
28        Self {
29            event,
30            trigger,
31            _marker: PhantomData,
32        }
33    }
34
35    /// Returns the event type of this trigger.
36    pub fn event_type(&self) -> ComponentId {
37        self.trigger.event_type
38    }
39
40    /// Returns a reference to the triggered event.
41    pub fn event(&self) -> &E {
42        self.event
43    }
44
45    /// Returns a mutable reference to the triggered event.
46    pub fn event_mut(&mut self) -> &mut E {
47        self.event
48    }
49
50    /// Returns a pointer to the triggered event.
51    pub fn event_ptr(&self) -> Ptr {
52        Ptr::from(&self.event)
53    }
54
55    /// Returns the entity that triggered the observer, could be [`Entity::PLACEHOLDER`].
56    pub fn entity(&self) -> Entity {
57        self.trigger.entity
58    }
59}
60
61/// A description of what an [`Observer`] observes.
62#[derive(Default, Clone)]
63pub struct ObserverDescriptor {
64    /// The events the observer is watching.
65    events: Vec<ComponentId>,
66
67    /// The components the observer is watching.
68    components: Vec<ComponentId>,
69
70    /// The entities the observer is watching.
71    entities: Vec<Entity>,
72}
73
74impl ObserverDescriptor {
75    /// Add the given `events` to the descriptor.
76    /// # Safety
77    /// The type of each [`ComponentId`] in `events` _must_ match the actual value
78    /// of the event passed into the observer.
79    pub unsafe fn with_events(mut self, events: Vec<ComponentId>) -> Self {
80        self.events = events;
81        self
82    }
83
84    /// Add the given `components` to the descriptor.
85    pub fn with_components(mut self, components: Vec<ComponentId>) -> Self {
86        self.components = components;
87        self
88    }
89
90    /// Add the given `entities` to the descriptor.
91    pub fn with_entities(mut self, entities: Vec<Entity>) -> Self {
92        self.entities = entities;
93        self
94    }
95
96    pub(crate) fn merge(&mut self, descriptor: &ObserverDescriptor) {
97        self.events.extend(descriptor.events.iter().copied());
98        self.components
99            .extend(descriptor.components.iter().copied());
100        self.entities.extend(descriptor.entities.iter().copied());
101    }
102}
103
104/// Event trigger metadata for a given [`Observer`],
105#[derive(Debug)]
106pub struct ObserverTrigger {
107    /// The [`Entity`] of the observer handling the trigger.
108    pub observer: Entity,
109
110    /// The [`ComponentId`] the trigger targeted.
111    pub event_type: ComponentId,
112
113    /// The entity the trigger targeted.
114    pub entity: Entity,
115}
116
117// Map between an observer entity and its runner
118type ObserverMap = EntityHashMap<Entity, ObserverRunner>;
119
120/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular trigger targeted at a specific component.
121#[derive(Default, Debug)]
122pub struct CachedComponentObservers {
123    // Observers listening to triggers targeting this component
124    map: ObserverMap,
125    // Observers listening to triggers targeting this component on a specific entity
126    entity_map: EntityHashMap<Entity, ObserverMap>,
127}
128
129/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular trigger.
130#[derive(Default, Debug)]
131pub struct CachedObservers {
132    // Observers listening for any time this trigger is fired
133    map: ObserverMap,
134    // Observers listening for this trigger fired at a specific component
135    component_observers: HashMap<ComponentId, CachedComponentObservers>,
136    // Observers listening for this trigger fired at a specific entity
137    entity_observers: EntityHashMap<Entity, ObserverMap>,
138}
139
140/// Metadata for observers. Stores a cache mapping trigger ids to the registered observers.
141#[derive(Default, Debug)]
142pub struct Observers {
143    // Cached ECS observers to save a lookup most common triggers.
144    on_add: CachedObservers,
145    on_insert: CachedObservers,
146    on_remove: CachedObservers,
147    // Map from trigger type to set of observers
148    cache: HashMap<ComponentId, CachedObservers>,
149}
150
151impl Observers {
152    pub(crate) fn get_observers(&mut self, event_type: ComponentId) -> &mut CachedObservers {
153        match event_type {
154            ON_ADD => &mut self.on_add,
155            ON_INSERT => &mut self.on_insert,
156            ON_REMOVE => &mut self.on_remove,
157            _ => self.cache.entry(event_type).or_default(),
158        }
159    }
160
161    pub(crate) fn try_get_observers(&self, event_type: ComponentId) -> Option<&CachedObservers> {
162        match event_type {
163            ON_ADD => Some(&self.on_add),
164            ON_INSERT => Some(&self.on_insert),
165            ON_REMOVE => Some(&self.on_remove),
166            _ => self.cache.get(&event_type),
167        }
168    }
169
170    /// This will run the observers of the given `event_type`, targeting the given `entity` and `components`.
171    pub(crate) fn invoke<T>(
172        mut world: DeferredWorld,
173        event_type: ComponentId,
174        entity: Entity,
175        components: impl Iterator<Item = ComponentId>,
176        data: &mut T,
177    ) {
178        // SAFETY: You cannot get a mutable reference to `observers` from `DeferredWorld`
179        let (mut world, observers) = unsafe {
180            let world = world.as_unsafe_world_cell();
181            // SAFETY: There are no outstanding world references
182            world.increment_trigger_id();
183            let observers = world.observers();
184            let Some(observers) = observers.try_get_observers(event_type) else {
185                return;
186            };
187            // SAFETY: The only outstanding reference to world is `observers`
188            (world.into_deferred(), observers)
189        };
190
191        let mut trigger_observer = |(&observer, runner): (&Entity, &ObserverRunner)| {
192            (runner)(
193                world.reborrow(),
194                ObserverTrigger {
195                    observer,
196                    event_type,
197                    entity,
198                },
199                data.into(),
200            );
201        };
202
203        // Trigger observers listening for any kind of this trigger
204        observers.map.iter().for_each(&mut trigger_observer);
205
206        // Trigger entity observers listening for this kind of trigger
207        if entity != Entity::PLACEHOLDER {
208            if let Some(map) = observers.entity_observers.get(&entity) {
209                map.iter().for_each(&mut trigger_observer);
210            }
211        }
212
213        // Trigger observers listening to this trigger targeting a specific component
214        components.for_each(|id| {
215            if let Some(component_observers) = observers.component_observers.get(&id) {
216                component_observers
217                    .map
218                    .iter()
219                    .for_each(&mut trigger_observer);
220
221                if entity != Entity::PLACEHOLDER {
222                    if let Some(map) = component_observers.entity_map.get(&entity) {
223                        map.iter().for_each(&mut trigger_observer);
224                    }
225                }
226            }
227        });
228    }
229
230    pub(crate) fn is_archetype_cached(event_type: ComponentId) -> Option<ArchetypeFlags> {
231        match event_type {
232            ON_ADD => Some(ArchetypeFlags::ON_ADD_OBSERVER),
233            ON_INSERT => Some(ArchetypeFlags::ON_INSERT_OBSERVER),
234            ON_REMOVE => Some(ArchetypeFlags::ON_REMOVE_OBSERVER),
235            _ => None,
236        }
237    }
238
239    pub(crate) fn update_archetype_flags(
240        &self,
241        component_id: ComponentId,
242        flags: &mut ArchetypeFlags,
243    ) {
244        if self.on_add.component_observers.contains_key(&component_id) {
245            flags.insert(ArchetypeFlags::ON_ADD_OBSERVER);
246        }
247        if self
248            .on_insert
249            .component_observers
250            .contains_key(&component_id)
251        {
252            flags.insert(ArchetypeFlags::ON_INSERT_OBSERVER);
253        }
254        if self
255            .on_remove
256            .component_observers
257            .contains_key(&component_id)
258        {
259            flags.insert(ArchetypeFlags::ON_REMOVE_OBSERVER);
260        }
261    }
262}
263
264impl World {
265    /// Spawn a "global" [`Observer`] and returns it's [`Entity`].
266    pub fn observe<E: Event, B: Bundle, M>(
267        &mut self,
268        system: impl IntoObserverSystem<E, B, M>,
269    ) -> EntityWorldMut {
270        self.spawn(Observer::new(system))
271    }
272
273    /// Triggers the given `event`, which will run any observers watching for it.
274    pub fn trigger(&mut self, event: impl Event) {
275        TriggerEvent { event, targets: () }.apply(self);
276    }
277
278    /// Triggers the given `event` for the given `targets`, which will run any observers watching for it.
279    pub fn trigger_targets(&mut self, event: impl Event, targets: impl TriggerTargets) {
280        TriggerEvent { event, targets }.apply(self);
281    }
282
283    /// Register an observer to the cache, called when an observer is created
284    pub(crate) fn register_observer(&mut self, observer_entity: Entity) {
285        // SAFETY: References do not alias.
286        let (observer_state, archetypes, observers) = unsafe {
287            let observer_state: *const ObserverState =
288                self.get::<ObserverState>(observer_entity).unwrap();
289            // Populate ObservedBy for each observed entity.
290            for watched_entity in &(*observer_state).descriptor.entities {
291                let mut entity_mut = self.entity_mut(*watched_entity);
292                let mut observed_by = entity_mut.entry::<ObservedBy>().or_default();
293                observed_by.0.push(observer_entity);
294            }
295            (&*observer_state, &mut self.archetypes, &mut self.observers)
296        };
297        let descriptor = &observer_state.descriptor;
298
299        for &event_type in &descriptor.events {
300            let cache = observers.get_observers(event_type);
301
302            if descriptor.components.is_empty() && descriptor.entities.is_empty() {
303                cache.map.insert(observer_entity, observer_state.runner);
304            } else if descriptor.components.is_empty() {
305                // Observer is not targeting any components so register it as an entity observer
306                for &watched_entity in &observer_state.descriptor.entities {
307                    let map = cache.entity_observers.entry(watched_entity).or_default();
308                    map.insert(observer_entity, observer_state.runner);
309                }
310            } else {
311                // Register observer for each watched component
312                for &component in &descriptor.components {
313                    let observers =
314                        cache
315                            .component_observers
316                            .entry(component)
317                            .or_insert_with(|| {
318                                if let Some(flag) = Observers::is_archetype_cached(event_type) {
319                                    archetypes.update_flags(component, flag, true);
320                                }
321                                CachedComponentObservers::default()
322                            });
323                    if descriptor.entities.is_empty() {
324                        // Register for all triggers targeting the component
325                        observers.map.insert(observer_entity, observer_state.runner);
326                    } else {
327                        // Register for each watched entity
328                        for &watched_entity in &descriptor.entities {
329                            let map = observers.entity_map.entry(watched_entity).or_default();
330                            map.insert(observer_entity, observer_state.runner);
331                        }
332                    }
333                }
334            }
335        }
336    }
337
338    /// Remove the observer from the cache, called when an observer gets despawned
339    pub(crate) fn unregister_observer(&mut self, entity: Entity, descriptor: ObserverDescriptor) {
340        let archetypes = &mut self.archetypes;
341        let observers = &mut self.observers;
342
343        for &event_type in &descriptor.events {
344            let cache = observers.get_observers(event_type);
345            if descriptor.components.is_empty() && descriptor.entities.is_empty() {
346                cache.map.remove(&entity);
347            } else if descriptor.components.is_empty() {
348                for watched_entity in &descriptor.entities {
349                    // This check should be unnecessary since this observer hasn't been unregistered yet
350                    let Some(observers) = cache.entity_observers.get_mut(watched_entity) else {
351                        continue;
352                    };
353                    observers.remove(&entity);
354                    if observers.is_empty() {
355                        cache.entity_observers.remove(watched_entity);
356                    }
357                }
358            } else {
359                for component in &descriptor.components {
360                    let Some(observers) = cache.component_observers.get_mut(component) else {
361                        continue;
362                    };
363                    if descriptor.entities.is_empty() {
364                        observers.map.remove(&entity);
365                    } else {
366                        for watched_entity in &descriptor.entities {
367                            let Some(map) = observers.entity_map.get_mut(watched_entity) else {
368                                continue;
369                            };
370                            map.remove(&entity);
371                            if map.is_empty() {
372                                observers.entity_map.remove(watched_entity);
373                            }
374                        }
375                    }
376
377                    if observers.map.is_empty() && observers.entity_map.is_empty() {
378                        cache.component_observers.remove(component);
379                        if let Some(flag) = Observers::is_archetype_cached(event_type) {
380                            archetypes.update_flags(*component, flag, false);
381                        }
382                    }
383                }
384            }
385        }
386    }
387}
388
389#[cfg(test)]
390mod tests {
391    use bevy_ptr::OwningPtr;
392
393    use crate as bevy_ecs;
394    use crate::observer::{EmitDynamicTrigger, Observer, ObserverDescriptor, ObserverState};
395    use crate::prelude::*;
396
397    #[derive(Component)]
398    struct A;
399
400    #[derive(Component)]
401    struct B;
402
403    #[derive(Component)]
404    struct C;
405
406    #[derive(Component)]
407    #[component(storage = "SparseSet")]
408    struct S;
409
410    #[derive(Event)]
411    struct EventA;
412
413    #[derive(Resource, Default)]
414    struct R(usize);
415
416    impl R {
417        #[track_caller]
418        fn assert_order(&mut self, count: usize) {
419            assert_eq!(count, self.0);
420            self.0 += 1;
421        }
422    }
423
424    #[test]
425    fn observer_order_spawn_despawn() {
426        let mut world = World::new();
427        world.init_resource::<R>();
428
429        world.observe(|_: Trigger<OnAdd, A>, mut res: ResMut<R>| res.assert_order(0));
430        world.observe(|_: Trigger<OnInsert, A>, mut res: ResMut<R>| res.assert_order(1));
431        world.observe(|_: Trigger<OnRemove, A>, mut res: ResMut<R>| res.assert_order(2));
432
433        let entity = world.spawn(A).id();
434        world.despawn(entity);
435        assert_eq!(3, world.resource::<R>().0);
436    }
437
438    #[test]
439    fn observer_order_insert_remove() {
440        let mut world = World::new();
441        world.init_resource::<R>();
442
443        world.observe(|_: Trigger<OnAdd, A>, mut res: ResMut<R>| res.assert_order(0));
444        world.observe(|_: Trigger<OnInsert, A>, mut res: ResMut<R>| res.assert_order(1));
445        world.observe(|_: Trigger<OnRemove, A>, mut res: ResMut<R>| res.assert_order(2));
446
447        let mut entity = world.spawn_empty();
448        entity.insert(A);
449        entity.remove::<A>();
450        entity.flush();
451        assert_eq!(3, world.resource::<R>().0);
452    }
453
454    #[test]
455    fn observer_order_insert_remove_sparse() {
456        let mut world = World::new();
457        world.init_resource::<R>();
458
459        world.observe(|_: Trigger<OnAdd, S>, mut res: ResMut<R>| res.assert_order(0));
460        world.observe(|_: Trigger<OnInsert, S>, mut res: ResMut<R>| res.assert_order(1));
461        world.observe(|_: Trigger<OnRemove, S>, mut res: ResMut<R>| res.assert_order(2));
462
463        let mut entity = world.spawn_empty();
464        entity.insert(S);
465        entity.remove::<S>();
466        entity.flush();
467        assert_eq!(3, world.resource::<R>().0);
468    }
469
470    #[test]
471    fn observer_order_recursive() {
472        let mut world = World::new();
473        world.init_resource::<R>();
474        world.observe(
475            |obs: Trigger<OnAdd, A>, mut res: ResMut<R>, mut commands: Commands| {
476                res.assert_order(0);
477                commands.entity(obs.entity()).insert(B);
478            },
479        );
480        world.observe(
481            |obs: Trigger<OnRemove, A>, mut res: ResMut<R>, mut commands: Commands| {
482                res.assert_order(2);
483                commands.entity(obs.entity()).remove::<B>();
484            },
485        );
486
487        world.observe(
488            |obs: Trigger<OnAdd, B>, mut res: ResMut<R>, mut commands: Commands| {
489                res.assert_order(1);
490                commands.entity(obs.entity()).remove::<A>();
491            },
492        );
493        world.observe(|_: Trigger<OnRemove, B>, mut res: ResMut<R>| {
494            res.assert_order(3);
495        });
496
497        let entity = world.spawn(A).flush();
498        let entity = world.get_entity(entity).unwrap();
499        assert!(!entity.contains::<A>());
500        assert!(!entity.contains::<B>());
501        assert_eq!(4, world.resource::<R>().0);
502    }
503
504    #[test]
505    fn observer_multiple_listeners() {
506        let mut world = World::new();
507        world.init_resource::<R>();
508
509        world.observe(|_: Trigger<OnAdd, A>, mut res: ResMut<R>| res.0 += 1);
510        world.observe(|_: Trigger<OnAdd, A>, mut res: ResMut<R>| res.0 += 1);
511
512        world.spawn(A).flush();
513        assert_eq!(2, world.resource::<R>().0);
514        // Our A entity plus our two observers
515        assert_eq!(world.entities().len(), 3);
516    }
517
518    #[test]
519    fn observer_multiple_events() {
520        let mut world = World::new();
521        world.init_resource::<R>();
522        let on_remove = world.init_component::<OnRemove>();
523        world.spawn(
524            // SAFETY: OnAdd and OnRemove are both unit types, so this is safe
525            unsafe {
526                Observer::new(|_: Trigger<OnAdd, A>, mut res: ResMut<R>| res.0 += 1)
527                    .with_event(on_remove)
528            },
529        );
530
531        let entity = world.spawn(A).id();
532        world.despawn(entity);
533        assert_eq!(2, world.resource::<R>().0);
534    }
535
536    #[test]
537    fn observer_multiple_components() {
538        let mut world = World::new();
539        world.init_resource::<R>();
540        world.init_component::<A>();
541        world.init_component::<B>();
542
543        world.observe(|_: Trigger<OnAdd, (A, B)>, mut res: ResMut<R>| res.0 += 1);
544
545        let entity = world.spawn(A).id();
546        world.entity_mut(entity).insert(B);
547        world.flush();
548        assert_eq!(2, world.resource::<R>().0);
549    }
550
551    #[test]
552    fn observer_despawn() {
553        let mut world = World::new();
554        world.init_resource::<R>();
555
556        let observer = world
557            .observe(|_: Trigger<OnAdd, A>| panic!("Observer triggered after being despawned."))
558            .id();
559        world.despawn(observer);
560        world.spawn(A).flush();
561    }
562
563    #[test]
564    fn observer_multiple_matches() {
565        let mut world = World::new();
566        world.init_resource::<R>();
567
568        world.observe(|_: Trigger<OnAdd, (A, B)>, mut res: ResMut<R>| res.0 += 1);
569
570        world.spawn((A, B)).flush();
571        assert_eq!(1, world.resource::<R>().0);
572    }
573
574    #[test]
575    fn observer_no_target() {
576        let mut world = World::new();
577        world.init_resource::<R>();
578
579        world
580            .spawn_empty()
581            .observe(|_: Trigger<EventA>| panic!("Trigger routed to non-targeted entity."));
582        world.observe(move |obs: Trigger<EventA>, mut res: ResMut<R>| {
583            assert_eq!(obs.entity(), Entity::PLACEHOLDER);
584            res.0 += 1;
585        });
586
587        // TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut
588        // and therefore does not automatically flush.
589        world.flush();
590        world.trigger(EventA);
591        world.flush();
592        assert_eq!(1, world.resource::<R>().0);
593    }
594
595    #[test]
596    fn observer_entity_routing() {
597        let mut world = World::new();
598        world.init_resource::<R>();
599
600        world
601            .spawn_empty()
602            .observe(|_: Trigger<EventA>| panic!("Trigger routed to non-targeted entity."));
603        let entity = world
604            .spawn_empty()
605            .observe(|_: Trigger<EventA>, mut res: ResMut<R>| res.0 += 1)
606            .id();
607        world.observe(move |obs: Trigger<EventA>, mut res: ResMut<R>| {
608            assert_eq!(obs.entity(), entity);
609            res.0 += 1;
610        });
611
612        // TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut
613        // and therefore does not automatically flush.
614        world.flush();
615        world.trigger_targets(EventA, entity);
616        world.flush();
617        assert_eq!(2, world.resource::<R>().0);
618    }
619
620    #[test]
621    fn observer_dynamic_component() {
622        let mut world = World::new();
623        world.init_resource::<R>();
624
625        let component_id = world.init_component::<A>();
626        world.spawn(
627            Observer::new(|_: Trigger<OnAdd>, mut res: ResMut<R>| res.0 += 1)
628                .with_component(component_id),
629        );
630
631        let mut entity = world.spawn_empty();
632        OwningPtr::make(A, |ptr| {
633            // SAFETY: we registered `component_id` above.
634            unsafe { entity.insert_by_id(component_id, ptr) };
635        });
636        let entity = entity.flush();
637
638        world.trigger_targets(EventA, entity);
639        world.flush();
640        assert_eq!(1, world.resource::<R>().0);
641    }
642
643    #[test]
644    fn observer_dynamic_trigger() {
645        let mut world = World::new();
646        world.init_resource::<R>();
647        let event_a = world.init_component::<EventA>();
648
649        world.spawn(ObserverState {
650            // SAFETY: we registered `event_a` above and it matches the type of TriggerA
651            descriptor: unsafe { ObserverDescriptor::default().with_events(vec![event_a]) },
652            runner: |mut world, _trigger, _ptr| {
653                world.resource_mut::<R>().0 += 1;
654            },
655            ..Default::default()
656        });
657
658        world.commands().add(
659            // SAFETY: we registered `event_a` above and it matches the type of TriggerA
660            unsafe { EmitDynamicTrigger::new_with_id(event_a, EventA, ()) },
661        );
662        world.flush();
663        assert_eq!(1, world.resource::<R>().0);
664    }
665}