bevy_ecs/observer/centralized_storage.rs
1//! Centralized storage for observers, allowing for efficient look-ups.
2//!
3//! This has multiple levels:
4//! - [`World::observers`](crate::world::World::observers) provides access to [`Observers`], which is a central storage for all observers.
5//! - [`Observers`] contains multiple distinct caches in the form of [`CachedObservers`].
6//! - Most observers are looked up by the [`ComponentId`] of the event they are observing
7//! - Lifecycle observers have their own fields to save lookups.
8//! - [`CachedObservers`] contains maps of [`ObserverRunner`]s, which are the actual functions that will be run when the observer is triggered.
9//! - These are split by target type, in order to allow for different lookup strategies.
10//! - [`CachedComponentObservers`] is one of these maps, which contains observers that are specifically targeted at a component.
11
12use bevy_platform::collections::HashMap;
13
14use crate::{
15 archetype::ArchetypeFlags, component::ComponentId, entity::EntityHashMap, event::EventKey,
16 observer::ObserverRunner,
17};
18
19/// An internal lookup table tracking all of the observers in the world.
20///
21/// Stores a cache mapping event ids to their registered observers.
22/// Some observer kinds (like [lifecycle](crate::lifecycle) observers) have a dedicated field,
23/// saving lookups for the most common triggers.
24///
25/// This can be accessed via [`World::observers`](crate::world::World::observers).
26#[derive(Default, Debug)]
27pub struct Observers {
28 // Cached ECS observers to save a lookup for high-traffic built-in event types.
29 add: CachedObservers,
30 insert: CachedObservers,
31 replace: CachedObservers,
32 remove: CachedObservers,
33 despawn: CachedObservers,
34 // Map from event type to set of observers watching for that event
35 cache: HashMap<EventKey, CachedObservers>,
36}
37
38impl Observers {
39 pub(crate) fn get_observers_mut(&mut self, event_key: EventKey) -> &mut CachedObservers {
40 use crate::lifecycle::*;
41
42 match event_key {
43 ADD => &mut self.add,
44 INSERT => &mut self.insert,
45 REPLACE => &mut self.replace,
46 REMOVE => &mut self.remove,
47 DESPAWN => &mut self.despawn,
48 _ => self.cache.entry(event_key).or_default(),
49 }
50 }
51
52 /// Attempts to get the observers for the given `event_key`.
53 ///
54 /// When accessing the observers for lifecycle events, such as [`Add`], [`Insert`], [`Replace`], [`Remove`], and [`Despawn`],
55 /// use the [`EventKey`] constants from the [`lifecycle`](crate::lifecycle) module.
56 ///
57 /// [`Add`]: crate::lifecycle::Add
58 /// [`Insert`]: crate::lifecycle::Insert
59 /// [`Replace`]: crate::lifecycle::Replace
60 /// [`Remove`]: crate::lifecycle::Remove
61 /// [`Despawn`]: crate::lifecycle::Despawn
62 pub fn try_get_observers(&self, event_key: EventKey) -> Option<&CachedObservers> {
63 use crate::lifecycle::*;
64
65 match event_key {
66 ADD => Some(&self.add),
67 INSERT => Some(&self.insert),
68 REPLACE => Some(&self.replace),
69 REMOVE => Some(&self.remove),
70 DESPAWN => Some(&self.despawn),
71 _ => self.cache.get(&event_key),
72 }
73 }
74
75 pub(crate) fn is_archetype_cached(event_key: EventKey) -> Option<ArchetypeFlags> {
76 use crate::lifecycle::*;
77
78 match event_key {
79 ADD => Some(ArchetypeFlags::ON_ADD_OBSERVER),
80 INSERT => Some(ArchetypeFlags::ON_INSERT_OBSERVER),
81 REPLACE => Some(ArchetypeFlags::ON_REPLACE_OBSERVER),
82 REMOVE => Some(ArchetypeFlags::ON_REMOVE_OBSERVER),
83 DESPAWN => Some(ArchetypeFlags::ON_DESPAWN_OBSERVER),
84 _ => None,
85 }
86 }
87
88 pub(crate) fn update_archetype_flags(
89 &self,
90 component_id: ComponentId,
91 flags: &mut ArchetypeFlags,
92 ) {
93 if self.add.component_observers.contains_key(&component_id) {
94 flags.insert(ArchetypeFlags::ON_ADD_OBSERVER);
95 }
96
97 if self.insert.component_observers.contains_key(&component_id) {
98 flags.insert(ArchetypeFlags::ON_INSERT_OBSERVER);
99 }
100
101 if self.replace.component_observers.contains_key(&component_id) {
102 flags.insert(ArchetypeFlags::ON_REPLACE_OBSERVER);
103 }
104
105 if self.remove.component_observers.contains_key(&component_id) {
106 flags.insert(ArchetypeFlags::ON_REMOVE_OBSERVER);
107 }
108
109 if self.despawn.component_observers.contains_key(&component_id) {
110 flags.insert(ArchetypeFlags::ON_DESPAWN_OBSERVER);
111 }
112 }
113}
114
115/// Collection of [`ObserverRunner`] for [`Observer`](crate::observer::Observer) registered to a particular event.
116///
117/// This is stored inside of [`Observers`], specialized for each kind of observer.
118#[derive(Default, Debug)]
119pub struct CachedObservers {
120 /// Observers watching for any time this event is triggered, regardless of target.
121 /// These will also respond to events targeting specific components or entities
122 pub(super) global_observers: ObserverMap,
123 /// Observers watching for triggers of events for a specific component
124 pub(super) component_observers: HashMap<ComponentId, CachedComponentObservers>,
125 /// Observers watching for triggers of events for a specific entity
126 pub(super) entity_observers: EntityHashMap<ObserverMap>,
127}
128
129impl CachedObservers {
130 /// Observers watching for any time this event is triggered, regardless of target.
131 /// These will also respond to events targeting specific components or entities
132 pub fn global_observers(&self) -> &ObserverMap {
133 &self.global_observers
134 }
135
136 /// Returns observers watching for triggers of events for a specific component.
137 pub fn component_observers(&self) -> &HashMap<ComponentId, CachedComponentObservers> {
138 &self.component_observers
139 }
140
141 /// Returns observers watching for triggers of events for a specific entity.
142 pub fn entity_observers(&self) -> &EntityHashMap<ObserverMap> {
143 &self.entity_observers
144 }
145}
146
147/// Map between an observer entity and its [`ObserverRunner`]
148pub type ObserverMap = EntityHashMap<ObserverRunner>;
149
150/// Collection of [`ObserverRunner`] for [`Observer`](crate::observer::Observer) registered to a particular event targeted at a specific component.
151///
152/// This is stored inside of [`CachedObservers`].
153#[derive(Default, Debug)]
154pub struct CachedComponentObservers {
155 // Observers watching for events targeting this component, but not a specific entity
156 pub(super) global_observers: ObserverMap,
157 // Observers watching for events targeting this component on a specific entity
158 pub(super) entity_component_observers: EntityHashMap<ObserverMap>,
159}
160
161impl CachedComponentObservers {
162 /// Returns observers watching for events targeting this component, but not a specific entity
163 pub fn global_observers(&self) -> &ObserverMap {
164 &self.global_observers
165 }
166
167 /// Returns observers watching for events targeting this component on a specific entity
168 pub fn entity_component_observers(&self) -> &EntityHashMap<ObserverMap> {
169 &self.entity_component_observers
170 }
171}