bevy_ecs/observer/
entity_observer.rs

1use crate::{
2    component::{
3        Component, ComponentCloneBehavior, ComponentHook, HookContext, Mutable, StorageType,
4    },
5    entity::{ComponentCloneCtx, Entity, EntityClonerBuilder, EntityMapper, SourceComponent},
6    observer::ObserverState,
7    world::World,
8};
9use alloc::vec::Vec;
10
11/// Tracks a list of entity observers for the [`Entity`] [`ObservedBy`] is added to.
12#[derive(Default)]
13pub struct ObservedBy(pub(crate) Vec<Entity>);
14
15impl Component for ObservedBy {
16    const STORAGE_TYPE: StorageType = StorageType::SparseSet;
17    type Mutability = Mutable;
18
19    fn on_remove() -> Option<ComponentHook> {
20        Some(|mut world, HookContext { entity, .. }| {
21            let observed_by = {
22                let mut component = world.get_mut::<ObservedBy>(entity).unwrap();
23                core::mem::take(&mut component.0)
24            };
25            for e in observed_by {
26                let (total_entities, despawned_watched_entities) = {
27                    let Ok(mut entity_mut) = world.get_entity_mut(e) else {
28                        continue;
29                    };
30                    let Some(mut state) = entity_mut.get_mut::<ObserverState>() else {
31                        continue;
32                    };
33                    state.despawned_watched_entities += 1;
34                    (
35                        state.descriptor.entities.len(),
36                        state.despawned_watched_entities as usize,
37                    )
38                };
39
40                // Despawn Observer if it has no more active sources.
41                if total_entities == despawned_watched_entities {
42                    world.commands().entity(e).despawn();
43                }
44            }
45        })
46    }
47
48    fn clone_behavior() -> ComponentCloneBehavior {
49        ComponentCloneBehavior::Ignore
50    }
51}
52
53impl EntityClonerBuilder<'_> {
54    /// Sets the option to automatically add cloned entities to the observers targeting source entity.
55    pub fn add_observers(&mut self, add_observers: bool) -> &mut Self {
56        if add_observers {
57            self.override_clone_behavior::<ObservedBy>(ComponentCloneBehavior::Custom(
58                component_clone_observed_by,
59            ))
60        } else {
61            self.remove_clone_behavior_override::<ObservedBy>()
62        }
63    }
64}
65
66fn component_clone_observed_by(_source: &SourceComponent, ctx: &mut ComponentCloneCtx) {
67    let target = ctx.target();
68    let source = ctx.source();
69
70    ctx.queue_deferred(move |world: &mut World, _mapper: &mut dyn EntityMapper| {
71        let observed_by = world
72            .get::<ObservedBy>(source)
73            .map(|observed_by| observed_by.0.clone())
74            .expect("Source entity must have ObservedBy");
75
76        world
77            .entity_mut(target)
78            .insert(ObservedBy(observed_by.clone()));
79
80        for observer in &observed_by {
81            let mut observer_state = world
82                .get_mut::<ObserverState>(*observer)
83                .expect("Source observer entity must have ObserverState");
84            observer_state.descriptor.entities.push(target);
85            let event_types = observer_state.descriptor.events.clone();
86            let components = observer_state.descriptor.components.clone();
87            for event_type in event_types {
88                let observers = world.observers.get_observers(event_type);
89                if components.is_empty() {
90                    if let Some(map) = observers.entity_observers.get(&source).cloned() {
91                        observers.entity_observers.insert(target, map);
92                    }
93                } else {
94                    for component in &components {
95                        let Some(observers) = observers.component_observers.get_mut(component)
96                        else {
97                            continue;
98                        };
99                        if let Some(map) = observers.entity_map.get(&source).cloned() {
100                            observers.entity_map.insert(target, map);
101                        }
102                    }
103                }
104            }
105        }
106    });
107}
108
109#[cfg(test)]
110mod tests {
111    use crate::{
112        entity::EntityCloner, event::Event, observer::Trigger, resource::Resource, system::ResMut,
113        world::World,
114    };
115
116    #[derive(Resource, Default)]
117    struct Num(usize);
118
119    #[derive(Event)]
120    struct E;
121
122    #[test]
123    fn clone_entity_with_observer() {
124        let mut world = World::default();
125        world.init_resource::<Num>();
126
127        let e = world
128            .spawn_empty()
129            .observe(|_: Trigger<E>, mut res: ResMut<Num>| res.0 += 1)
130            .id();
131        world.flush();
132
133        world.trigger_targets(E, e);
134
135        let e_clone = world.spawn_empty().id();
136        EntityCloner::build(&mut world)
137            .add_observers(true)
138            .clone_entity(e, e_clone);
139
140        world.trigger_targets(E, [e, e_clone]);
141
142        assert_eq!(world.resource::<Num>().0, 3);
143    }
144}