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:
Alix Bott 2024-08-30 02:43:56 +02:00 committed by GitHub
parent e08497dc8f
commit f2cf02408f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 2 deletions

View file

@ -367,7 +367,7 @@ pub struct Archetype {
edges: Edges,
entities: Vec<ArchetypeEntity>,
components: ImmutableSparseSet<ComponentId, ArchetypeComponentInfo>,
flags: ArchetypeFlags,
pub(crate) flags: ArchetypeFlags,
}
impl Archetype {

View file

@ -429,7 +429,17 @@ impl World {
if observers.map.is_empty() && observers.entity_map.is_empty() {
cache.component_observers.remove(component);
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();
}
// 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]
fn observer_multiple_matches() {
let mut world = World::new();