bevy_ecs/observer/
entity_observer.rs1use 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#[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 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 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}