Skip to content

Commit 560429e

Browse files
Observer trigger refactor (#19935)
# Objective - The usage of ComponentId is quite confusing: events are not components. By newtyping this, we can prevent stupid mistakes, avoid leaking internal details and make the code clearer for users and engine devs reading it. - Adopts #19755 --------- Co-authored-by: oscar-benderstone <oscarbenderstone@gmail.com> Co-authored-by: Oscar Bender-Stone <88625129+oscar-benderstone@users.noreply.github.com>
1 parent 1380a3b commit 560429e

File tree

13 files changed

+129
-102
lines changed

13 files changed

+129
-102
lines changed

crates/bevy_ecs/src/event/base.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,23 +94,23 @@ use core::{
9494
note = "consider annotating `{Self}` with `#[derive(Event)]`"
9595
)]
9696
pub trait Event: Send + Sync + 'static {
97-
/// Generates the [`ComponentId`] for this event type.
97+
/// Generates the [`EventKey`] for this event type.
9898
///
9999
/// If this type has already been registered,
100-
/// this will return the existing [`ComponentId`].
100+
/// this will return the existing [`EventKey`].
101101
///
102102
/// This is used by various dynamically typed observer APIs,
103103
/// such as [`World::trigger_targets_dynamic`].
104104
///
105105
/// # Warning
106106
///
107107
/// This method should not be overridden by implementers,
108-
/// and should always correspond to the implementation of [`component_id`](Event::component_id).
109-
fn register_component_id(world: &mut World) -> ComponentId {
110-
world.register_component::<EventWrapperComponent<Self>>()
108+
/// and should always correspond to the implementation of [`event_key`](Event::event_key).
109+
fn register_event_key(world: &mut World) -> EventKey {
110+
EventKey(world.register_component::<EventWrapperComponent<Self>>())
111111
}
112112

113-
/// Fetches the [`ComponentId`] for this event type,
113+
/// Fetches the [`EventKey`] for this event type,
114114
/// if it has already been generated.
115115
///
116116
/// This is used by various dynamically typed observer APIs,
@@ -119,9 +119,12 @@ pub trait Event: Send + Sync + 'static {
119119
/// # Warning
120120
///
121121
/// This method should not be overridden by implementers,
122-
/// and should always correspond to the implementation of [`register_component_id`](Event::register_component_id).
123-
fn component_id(world: &World) -> Option<ComponentId> {
124-
world.component_id::<EventWrapperComponent<Self>>()
122+
/// and should always correspond to the implementation of
123+
/// [`register_event_key`](Event::register_event_key).
124+
fn event_key(world: &World) -> Option<EventKey> {
125+
world
126+
.component_id::<EventWrapperComponent<Self>>()
127+
.map(EventKey)
125128
}
126129
}
127130

@@ -421,3 +424,19 @@ pub(crate) struct EventInstance<E: BufferedEvent> {
421424
pub event_id: EventId<E>,
422425
pub event: E,
423426
}
427+
428+
/// A unique identifier for an [`Event`], used by [observers].
429+
///
430+
/// You can look up the key for your event by calling the [`Event::event_key`] method.
431+
///
432+
/// [observers]: crate::observer
433+
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
434+
pub struct EventKey(pub(crate) ComponentId);
435+
436+
impl EventKey {
437+
/// Returns the internal [`ComponentId`].
438+
#[inline]
439+
pub(crate) fn component_id(&self) -> ComponentId {
440+
self.0
441+
}
442+
}

crates/bevy_ecs/src/event/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ mod update;
1111
mod writer;
1212

1313
pub(crate) use base::EventInstance;
14-
pub use base::{BufferedEvent, EntityEvent, Event, EventId};
14+
pub use base::{BufferedEvent, EntityEvent, Event, EventId, EventKey};
1515
pub use bevy_ecs_macros::{BufferedEvent, EntityEvent, Event};
1616
pub use collections::{Events, SendBatchIds};
1717
pub use event_cursor::EventCursor;

crates/bevy_ecs/src/event/registry.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use alloc::vec::Vec;
22
use bevy_ecs::{
33
change_detection::{DetectChangesMut, MutUntyped},
4-
component::{ComponentId, Tick},
5-
event::{BufferedEvent, Events},
4+
component::Tick,
5+
event::{BufferedEvent, EventKey, Events},
66
resource::Resource,
77
world::World,
88
};
99

1010
#[doc(hidden)]
1111
struct RegisteredEvent {
12-
component_id: ComponentId,
12+
event_key: EventKey,
1313
// Required to flush the secondary buffer and drop events even if left unchanged.
1414
previously_updated: bool,
1515
// SAFETY: The component ID and the function must be used to fetch the Events<T> resource
@@ -51,7 +51,7 @@ impl EventRegistry {
5151
let component_id = world.init_resource::<Events<T>>();
5252
let mut registry = world.get_resource_or_init::<Self>();
5353
registry.event_updates.push(RegisteredEvent {
54-
component_id,
54+
event_key: EventKey(component_id),
5555
previously_updated: false,
5656
update: |ptr| {
5757
// SAFETY: The resource was initialized with the type Events<T>.
@@ -66,7 +66,9 @@ impl EventRegistry {
6666
pub fn run_updates(&mut self, world: &mut World, last_change_tick: Tick) {
6767
for registered_event in &mut self.event_updates {
6868
// Bypass the type ID -> Component ID lookup with the cached component ID.
69-
if let Some(events) = world.get_resource_mut_by_id(registered_event.component_id) {
69+
if let Some(events) =
70+
world.get_resource_mut_by_id(registered_event.event_key.component_id())
71+
{
7072
let has_changed = events.has_changed_since(last_change_tick);
7173
if registered_event.previously_updated || has_changed {
7274
// SAFETY: The update function pointer is called with the resource
@@ -87,7 +89,7 @@ impl EventRegistry {
8789
let mut registry = world.get_resource_or_init::<Self>();
8890
registry
8991
.event_updates
90-
.retain(|e| e.component_id != component_id);
92+
.retain(|e| e.event_key.component_id() != component_id);
9193
world.remove_resource::<Events<T>>();
9294
}
9395
}

crates/bevy_ecs/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ pub mod prelude {
7979
entity::{ContainsEntity, Entity, EntityMapper},
8080
error::{BevyError, Result},
8181
event::{
82-
BufferedEvent, EntityEvent, Event, EventMutator, EventReader, EventWriter, Events,
82+
BufferedEvent, EntityEvent, Event, EventKey, EventMutator, EventReader, EventWriter,
83+
Events,
8384
},
8485
hierarchy::{ChildOf, ChildSpawner, ChildSpawnerCommands, Children},
8586
lifecycle::{

crates/bevy_ecs/src/lifecycle.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use crate::{
5555
entity::Entity,
5656
event::{
5757
BufferedEvent, EntityEvent, Event, EventCursor, EventId, EventIterator,
58-
EventIteratorWithId, Events,
58+
EventIteratorWithId, EventKey, Events,
5959
},
6060
query::FilteredAccessSet,
6161
relationship::RelationshipHookMode,
@@ -314,16 +314,16 @@ impl ComponentHooks {
314314
}
315315
}
316316

317-
/// [`ComponentId`] for [`Add`]
318-
pub const ADD: ComponentId = ComponentId::new(0);
319-
/// [`ComponentId`] for [`Insert`]
320-
pub const INSERT: ComponentId = ComponentId::new(1);
321-
/// [`ComponentId`] for [`Replace`]
322-
pub const REPLACE: ComponentId = ComponentId::new(2);
323-
/// [`ComponentId`] for [`Remove`]
324-
pub const REMOVE: ComponentId = ComponentId::new(3);
325-
/// [`ComponentId`] for [`Despawn`]
326-
pub const DESPAWN: ComponentId = ComponentId::new(4);
317+
/// [`EventKey`] for [`Add`]
318+
pub const ADD: EventKey = EventKey(ComponentId::new(0));
319+
/// [`EventKey`] for [`Insert`]
320+
pub const INSERT: EventKey = EventKey(ComponentId::new(1));
321+
/// [`EventKey`] for [`Replace`]
322+
pub const REPLACE: EventKey = EventKey(ComponentId::new(2));
323+
/// [`EventKey`] for [`Remove`]
324+
pub const REMOVE: EventKey = EventKey(ComponentId::new(3));
325+
/// [`EventKey`] for [`Despawn`]
326+
pub const DESPAWN: EventKey = EventKey(ComponentId::new(4));
327327

328328
/// Trigger emitted when a component is inserted onto an entity that does not already have that
329329
/// component. Runs before `Insert`.

crates/bevy_ecs/src/observer/centralized_storage.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,44 +37,44 @@ pub struct Observers {
3737
remove: CachedObservers,
3838
despawn: CachedObservers,
3939
// Map from trigger type to set of observers listening to that trigger
40-
cache: HashMap<ComponentId, CachedObservers>,
40+
cache: HashMap<EventKey, CachedObservers>,
4141
}
4242

4343
impl Observers {
44-
pub(crate) fn get_observers_mut(&mut self, event_type: ComponentId) -> &mut CachedObservers {
44+
pub(crate) fn get_observers_mut(&mut self, event_key: EventKey) -> &mut CachedObservers {
4545
use crate::lifecycle::*;
4646

47-
match event_type {
47+
match event_key {
4848
ADD => &mut self.add,
4949
INSERT => &mut self.insert,
5050
REPLACE => &mut self.replace,
5151
REMOVE => &mut self.remove,
5252
DESPAWN => &mut self.despawn,
53-
_ => self.cache.entry(event_type).or_default(),
53+
_ => self.cache.entry(event_key).or_default(),
5454
}
5555
}
5656

57-
/// Attempts to get the observers for the given `event_type`.
57+
/// Attempts to get the observers for the given `event_key`.
5858
///
5959
/// When accessing the observers for lifecycle events, such as [`Add`], [`Insert`], [`Replace`], [`Remove`], and [`Despawn`],
60-
/// use the [`ComponentId`] constants from the [`lifecycle`](crate::lifecycle) module.
61-
pub fn try_get_observers(&self, event_type: ComponentId) -> Option<&CachedObservers> {
60+
/// use the [`EventKey`] constants from the [`lifecycle`](crate::lifecycle) module.
61+
pub fn try_get_observers(&self, event_key: EventKey) -> Option<&CachedObservers> {
6262
use crate::lifecycle::*;
6363

64-
match event_type {
64+
match event_key {
6565
ADD => Some(&self.add),
6666
INSERT => Some(&self.insert),
6767
REPLACE => Some(&self.replace),
6868
REMOVE => Some(&self.remove),
6969
DESPAWN => Some(&self.despawn),
70-
_ => self.cache.get(&event_type),
70+
_ => self.cache.get(&event_key),
7171
}
7272
}
7373

74-
/// This will run the observers of the given `event_type`, targeting the given `entity` and `components`.
74+
/// This will run the observers of the given `event_key`, targeting the given `entity` and `components`.
7575
pub(crate) fn invoke<T>(
7676
mut world: DeferredWorld,
77-
event_type: ComponentId,
77+
event_key: EventKey,
7878
current_target: Option<Entity>,
7979
original_target: Option<Entity>,
8080
components: impl Iterator<Item = ComponentId> + Clone,
@@ -88,7 +88,7 @@ impl Observers {
8888
// SAFETY: There are no outstanding world references
8989
world.increment_trigger_id();
9090
let observers = world.observers();
91-
let Some(observers) = observers.try_get_observers(event_type) else {
91+
let Some(observers) = observers.try_get_observers(event_key) else {
9292
return;
9393
};
9494
// SAFETY: The only outstanding reference to world is `observers`
@@ -102,7 +102,7 @@ impl Observers {
102102
world.reborrow(),
103103
ObserverTrigger {
104104
observer,
105-
event_type,
105+
event_key,
106106
components: components.clone().collect(),
107107
current_target,
108108
original_target,
@@ -145,10 +145,10 @@ impl Observers {
145145
});
146146
}
147147

148-
pub(crate) fn is_archetype_cached(event_type: ComponentId) -> Option<ArchetypeFlags> {
148+
pub(crate) fn is_archetype_cached(event_key: EventKey) -> Option<ArchetypeFlags> {
149149
use crate::lifecycle::*;
150150

151-
match event_type {
151+
match event_key {
152152
ADD => Some(ArchetypeFlags::ON_ADD_OBSERVER),
153153
INSERT => Some(ArchetypeFlags::ON_INSERT_OBSERVER),
154154
REPLACE => Some(ArchetypeFlags::ON_REPLACE_OBSERVER),

crates/bevy_ecs/src/observer/distributed_storage.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,9 @@ impl Observer {
289289
/// Observe the given `event`. This will cause the [`Observer`] to run whenever an event with the given [`ComponentId`]
290290
/// is triggered.
291291
/// # Safety
292-
/// The type of the `event` [`ComponentId`] _must_ match the actual value
292+
/// The type of the `event` [`EventKey`] _must_ match the actual value
293293
/// of the event passed into the observer system.
294-
pub unsafe fn with_event(mut self, event: ComponentId) -> Self {
294+
pub unsafe fn with_event(mut self, event: EventKey) -> Self {
295295
self.descriptor.events.push(event);
296296
self
297297
}
@@ -350,7 +350,7 @@ impl Component for Observer {
350350
#[derive(Default, Clone)]
351351
pub struct ObserverDescriptor {
352352
/// The events the observer is watching.
353-
pub(super) events: Vec<ComponentId>,
353+
pub(super) events: Vec<EventKey>,
354354

355355
/// The components the observer is watching.
356356
pub(super) components: Vec<ComponentId>,
@@ -362,9 +362,9 @@ pub struct ObserverDescriptor {
362362
impl ObserverDescriptor {
363363
/// Add the given `events` to the descriptor.
364364
/// # Safety
365-
/// The type of each [`ComponentId`] in `events` _must_ match the actual value
365+
/// The type of each [`EventKey`] in `events` _must_ match the actual value
366366
/// of the event passed into the observer.
367-
pub unsafe fn with_events(mut self, events: Vec<ComponentId>) -> Self {
367+
pub unsafe fn with_events(mut self, events: Vec<EventKey>) -> Self {
368368
self.events = events;
369369
self
370370
}
@@ -382,7 +382,7 @@ impl ObserverDescriptor {
382382
}
383383

384384
/// Returns the `events` that the observer is watching.
385-
pub fn events(&self) -> &[ComponentId] {
385+
pub fn events(&self) -> &[EventKey] {
386386
&self.events
387387
}
388388

@@ -410,13 +410,13 @@ fn hook_on_add<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
410410
HookContext { entity, .. }: HookContext,
411411
) {
412412
world.commands().queue(move |world: &mut World| {
413-
let event_id = E::register_component_id(world);
413+
let event_key = E::register_event_key(world);
414414
let mut components = alloc::vec![];
415415
B::component_ids(&mut world.components_registrator(), &mut |id| {
416416
components.push(id);
417417
});
418418
if let Some(mut observer) = world.get_mut::<Observer>(entity) {
419-
observer.descriptor.events.push(event_id);
419+
observer.descriptor.events.push(event_key);
420420
observer.descriptor.components.extend(components);
421421

422422
let system: &mut dyn Any = observer.system.as_mut();

crates/bevy_ecs/src/observer/entity_cloning.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ fn component_clone_observed_by(_source: &SourceComponent, ctx: &mut ComponentClo
4343
.get_mut::<Observer>(observer_entity)
4444
.expect("Source observer entity must have Observer");
4545
observer_state.descriptor.entities.push(target);
46-
let event_types = observer_state.descriptor.events.clone();
46+
let event_keys = observer_state.descriptor.events.clone();
4747
let components = observer_state.descriptor.components.clone();
48-
for event_type in event_types {
49-
let observers = world.observers.get_observers_mut(event_type);
48+
for event_key in event_keys {
49+
let observers = world.observers.get_observers_mut(event_key);
5050
if components.is_empty() {
5151
if let Some(map) = observers.entity_observers.get(&source).cloned() {
5252
observers.entity_observers.insert(target, map);

0 commit comments

Comments
 (0)