Fix observer unregistering unsetting archetype flags (#14963)
# Objective - Fixes https://github.com/bevyengine/bevy/issues/14961 ## Solution - Check that the archetypes don't contain any other observed components before unsetting their flags ## Testing - I added a regression test: `observer_despawn_archetype_flags`
This commit is contained in:
		
							parent
							
								
									e08497dc8f
								
							
						
					
					
						commit
						f2cf02408f
					
				| @ -367,7 +367,7 @@ pub struct Archetype { | |||||||
|     edges: Edges, |     edges: Edges, | ||||||
|     entities: Vec<ArchetypeEntity>, |     entities: Vec<ArchetypeEntity>, | ||||||
|     components: ImmutableSparseSet<ComponentId, ArchetypeComponentInfo>, |     components: ImmutableSparseSet<ComponentId, ArchetypeComponentInfo>, | ||||||
|     flags: ArchetypeFlags, |     pub(crate) flags: ArchetypeFlags, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Archetype { | impl Archetype { | ||||||
|  | |||||||
| @ -429,7 +429,17 @@ impl World { | |||||||
|                     if observers.map.is_empty() && observers.entity_map.is_empty() { |                     if observers.map.is_empty() && observers.entity_map.is_empty() { | ||||||
|                         cache.component_observers.remove(component); |                         cache.component_observers.remove(component); | ||||||
|                         if let Some(flag) = Observers::is_archetype_cached(event_type) { |                         if let Some(flag) = Observers::is_archetype_cached(event_type) { | ||||||
|                             archetypes.update_flags(*component, flag, false); |                             for archetype in &mut archetypes.archetypes { | ||||||
|  |                                 if archetype.contains(*component) { | ||||||
|  |                                     let no_longer_observed = archetype | ||||||
|  |                                         .components() | ||||||
|  |                                         .all(|id| !cache.component_observers.contains_key(&id)); | ||||||
|  | 
 | ||||||
|  |                                     if no_longer_observed { | ||||||
|  |                                         archetype.flags.set(flag, false); | ||||||
|  |                                     } | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -656,6 +666,26 @@ mod tests { | |||||||
|         world.spawn(A).flush(); |         world.spawn(A).flush(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Regression test for https://github.com/bevyengine/bevy/issues/14961
 | ||||||
|  |     #[test] | ||||||
|  |     fn observer_despawn_archetype_flags() { | ||||||
|  |         let mut world = World::new(); | ||||||
|  |         world.init_resource::<R>(); | ||||||
|  | 
 | ||||||
|  |         let entity = world.spawn((A, B)).flush(); | ||||||
|  | 
 | ||||||
|  |         world.observe(|_: Trigger<OnRemove, A>, mut res: ResMut<R>| res.0 += 1); | ||||||
|  | 
 | ||||||
|  |         let observer = world | ||||||
|  |             .observe(|_: Trigger<OnRemove, B>| panic!("Observer triggered after being despawned.")) | ||||||
|  |             .flush(); | ||||||
|  |         world.despawn(observer); | ||||||
|  | 
 | ||||||
|  |         world.despawn(entity); | ||||||
|  | 
 | ||||||
|  |         assert_eq!(1, world.resource::<R>().0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn observer_multiple_matches() { |     fn observer_multiple_matches() { | ||||||
|         let mut world = World::new(); |         let mut world = World::new(); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Alix Bott
						Alix Bott