Optimize observer unregistration (#15150)

# Objective

Fixes #14980

## Solution

Only iterate over archetypes containing the component.

## Alternatives

Additionally, for each archetype, cache how many observers are watching
one of its components & use this to speed up the check for each affected
archetype ([implemented
here](55c89aa033)).
Benchmarking showed this to lead only to a minor speedup.

## Testing

There's both already a test checking that observers don't run after
being despawned as well as a regression test for the bug that
necessitates the check this PR optimizes.
This commit is contained in:
SpecificProtagonist 2024-09-13 17:47:24 +02:00 committed by GitHub
parent c454db88a3
commit f570f52aa2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 11 additions and 8 deletions

View file

@ -766,7 +766,7 @@ pub struct Archetypes {
/// find the archetype id by the archetype's components
by_components: HashMap<ArchetypeComponents, ArchetypeId>,
/// find all the archetypes that contain a component
by_component: ComponentIndex,
pub(crate) by_component: ComponentIndex,
}
/// Metadata about how a component is stored in an [`Archetype`].

View file

@ -456,7 +456,9 @@ 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) {
for archetype in &mut archetypes.archetypes {
if let Some(by_component) = archetypes.by_component.get(component) {
for archetype in by_component.keys() {
let archetype = &mut archetypes.archetypes[archetype.index()];
if archetype.contains(*component) {
let no_longer_observed = archetype
.components()
@ -473,6 +475,7 @@ impl World {
}
}
}
}
}
#[cfg(test)]