bevy_ecs/observer/
entity_cloning.rs

1//! Logic to track observers when cloning entities.
2
3use crate::{
4    component::ComponentCloneBehavior,
5    entity::{
6        CloneByFilter, ComponentCloneCtx, EntityClonerBuilder, EntityMapper, SourceComponent,
7    },
8    observer::ObservedBy,
9    world::World,
10};
11
12use super::Observer;
13
14impl<Filter: CloneByFilter> EntityClonerBuilder<'_, Filter> {
15    /// Sets the option to automatically add cloned entities to the observers targeting source entity.
16    pub fn add_observers(&mut self, add_observers: bool) -> &mut Self {
17        if add_observers {
18            self.override_clone_behavior::<ObservedBy>(ComponentCloneBehavior::Custom(
19                component_clone_observed_by,
20            ))
21        } else {
22            self.remove_clone_behavior_override::<ObservedBy>()
23        }
24    }
25}
26
27fn component_clone_observed_by(_source: &SourceComponent, ctx: &mut ComponentCloneCtx) {
28    let target = ctx.target();
29    let source = ctx.source();
30
31    ctx.queue_deferred(move |world: &mut World, _mapper: &mut dyn EntityMapper| {
32        let observed_by = world
33            .get::<ObservedBy>(source)
34            .map(|observed_by| observed_by.0.clone())
35            .expect("Source entity must have ObservedBy");
36
37        world
38            .entity_mut(target)
39            .insert(ObservedBy(observed_by.clone()));
40
41        for observer_entity in observed_by.iter().copied() {
42            let mut observer_state = world
43                .get_mut::<Observer>(observer_entity)
44                .expect("Source observer entity must have Observer");
45            observer_state.descriptor.entities.push(target);
46            let event_keys = observer_state.descriptor.event_keys.clone();
47            let components = observer_state.descriptor.components.clone();
48            for event_key in event_keys {
49                let observers = world.observers.get_observers_mut(event_key);
50                if components.is_empty() {
51                    if let Some(map) = observers.entity_observers.get(&source).cloned() {
52                        observers.entity_observers.insert(target, map);
53                    }
54                } else {
55                    for component in &components {
56                        let Some(observers) = observers.component_observers.get_mut(component)
57                        else {
58                            continue;
59                        };
60                        if let Some(map) =
61                            observers.entity_component_observers.get(&source).cloned()
62                        {
63                            observers.entity_component_observers.insert(target, map);
64                        }
65                    }
66                }
67            }
68        }
69    });
70}
71
72#[cfg(test)]
73mod tests {
74    use crate::{
75        entity::{Entity, EntityCloner},
76        event::EntityEvent,
77        observer::On,
78        resource::Resource,
79        system::ResMut,
80        world::World,
81    };
82
83    #[derive(Resource, Default)]
84    struct Num(usize);
85
86    #[derive(EntityEvent)]
87    struct E(Entity);
88
89    #[test]
90    fn clone_entity_with_observer() {
91        let mut world = World::default();
92        world.init_resource::<Num>();
93
94        let e = world
95            .spawn_empty()
96            .observe(|_: On<E>, mut res: ResMut<Num>| res.0 += 1)
97            .id();
98        world.flush();
99
100        world.trigger(E(e));
101
102        let e_clone = world.spawn_empty().id();
103        EntityCloner::build_opt_out(&mut world)
104            .add_observers(true)
105            .clone_entity(e, e_clone);
106
107        world.trigger(E(e));
108        world.trigger(E(e_clone));
109
110        assert_eq!(world.resource::<Num>().0, 3);
111    }
112}