diff --git a/crates/bevy_ecs/src/event/base.rs b/crates/bevy_ecs/src/event/base.rs index 52839f369d0c4..4f646a929c937 100644 --- a/crates/bevy_ecs/src/event/base.rs +++ b/crates/bevy_ecs/src/event/base.rs @@ -94,10 +94,10 @@ use core::{ note = "consider annotating `{Self}` with `#[derive(Event)]`" )] pub trait Event: Send + Sync + 'static { - /// Generates the [`ComponentId`] for this event type. + /// Generates the [`EventKey`] for this event type. /// /// If this type has already been registered, - /// this will return the existing [`ComponentId`]. + /// this will return the existing [`EventKey`]. /// /// This is used by various dynamically typed observer APIs, /// such as [`World::trigger_targets_dynamic`]. @@ -105,12 +105,12 @@ pub trait Event: Send + Sync + 'static { /// # Warning /// /// This method should not be overridden by implementers, - /// and should always correspond to the implementation of [`component_id`](Event::component_id). - fn register_component_id(world: &mut World) -> ComponentId { - world.register_component::>() + /// and should always correspond to the implementation of [`event_type`](Event::event_type). + fn register_event_type(world: &mut World) -> EventKey { + EventKey(world.register_component::>()) } - /// Fetches the [`ComponentId`] for this event type, + /// Fetches the [`EventKey`] for this event type, /// if it has already been generated. /// /// This is used by various dynamically typed observer APIs, @@ -119,9 +119,12 @@ pub trait Event: Send + Sync + 'static { /// # Warning /// /// This method should not be overridden by implementers, - /// and should always correspond to the implementation of [`register_component_id`](Event::register_component_id). - fn component_id(world: &World) -> Option { - world.component_id::>() + /// and should always correspond to the implementation of + /// [`register_event_type`](Event::register_event_type). + fn event_type(world: &World) -> Option { + world + .component_id::>() + .map(EventKey) } } @@ -421,3 +424,28 @@ pub(crate) struct EventInstance { pub event_id: EventId, pub event: E, } + +/// # Warning +/// +/// This struct should only be instantiated internally to this crate. +/// +/// [`EventKey`]s are created in: +/// - `crate::observer::trigger_dynamic_ref_with_caller` +/// - `crate::observer::trigger_dynamic_ref_with_caller` +/// - `crate::observer::observer_multiple_events` +/// - `crate::observer::observer_dynamic_trigger` +/// - `crate::observer::runner::hook_on_add` +#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct EventKey(pub(crate) ComponentId); + +impl EventKey { + /// Returns id of the underlying [`Event`]. + /// Used internally in: + /// - [`crate::event::register_event`] + /// - [`crate::event::run_updates`] + /// - [`crate::event::deregister_events`] + #[inline] + pub(crate) fn component_id(&self) -> ComponentId { + self.0 + } +} diff --git a/crates/bevy_ecs/src/event/mod.rs b/crates/bevy_ecs/src/event/mod.rs index fd624d1abf593..a96559ea6088a 100644 --- a/crates/bevy_ecs/src/event/mod.rs +++ b/crates/bevy_ecs/src/event/mod.rs @@ -11,7 +11,7 @@ mod update; mod writer; pub(crate) use base::EventInstance; -pub use base::{BufferedEvent, EntityEvent, Event, EventId}; +pub use base::{BufferedEvent, EntityEvent, Event, EventId, EventKey}; pub use bevy_ecs_macros::{BufferedEvent, EntityEvent, Event}; pub use collections::{Events, SendBatchIds}; pub use event_cursor::EventCursor; diff --git a/crates/bevy_ecs/src/event/registry.rs b/crates/bevy_ecs/src/event/registry.rs index 7889de62da366..a7d6d6121a323 100644 --- a/crates/bevy_ecs/src/event/registry.rs +++ b/crates/bevy_ecs/src/event/registry.rs @@ -1,15 +1,16 @@ use alloc::vec::Vec; use bevy_ecs::{ change_detection::{DetectChangesMut, MutUntyped}, - component::{ComponentId, Tick}, - event::{BufferedEvent, Events}, + component::Tick, + event::{BufferedEvent, EventKey, Events}, resource::Resource, world::World, }; #[doc(hidden)] struct RegisteredEvent { - component_id: ComponentId, + event_type: EventKey, + // event_type: // Required to flush the secondary buffer and drop events even if left unchanged. previously_updated: bool, // SAFETY: The component ID and the function must be used to fetch the Events resource @@ -51,7 +52,7 @@ impl EventRegistry { let component_id = world.init_resource::>(); let mut registry = world.get_resource_or_init::(); registry.event_updates.push(RegisteredEvent { - component_id, + event_type: EventKey(component_id), previously_updated: false, update: |ptr| { // SAFETY: The resource was initialized with the type Events. @@ -66,7 +67,9 @@ impl EventRegistry { pub fn run_updates(&mut self, world: &mut World, last_change_tick: Tick) { for registered_event in &mut self.event_updates { // Bypass the type ID -> Component ID lookup with the cached component ID. - if let Some(events) = world.get_resource_mut_by_id(registered_event.component_id) { + if let Some(events) = + world.get_resource_mut_by_id(registered_event.event_type.component_id()) + { let has_changed = events.has_changed_since(last_change_tick); if registered_event.previously_updated || has_changed { // SAFETY: The update function pointer is called with the resource @@ -87,7 +90,7 @@ impl EventRegistry { let mut registry = world.get_resource_or_init::(); registry .event_updates - .retain(|e| e.component_id != component_id); + .retain(|e| e.event_type.component_id() != component_id); world.remove_resource::>(); } } diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index e5f0e908e56c5..ea61d2956240a 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -79,7 +79,8 @@ pub mod prelude { entity::{ContainsEntity, Entity, EntityMapper}, error::{BevyError, Result}, event::{ - BufferedEvent, EntityEvent, Event, EventMutator, EventReader, EventWriter, Events, + BufferedEvent, EntityEvent, Event, EventKey, EventMutator, EventReader, EventWriter, + Events, }, hierarchy::{ChildOf, ChildSpawner, ChildSpawnerCommands, Children}, lifecycle::{ diff --git a/crates/bevy_ecs/src/lifecycle.rs b/crates/bevy_ecs/src/lifecycle.rs index e92c6cc7f92d4..08f178eda133e 100644 --- a/crates/bevy_ecs/src/lifecycle.rs +++ b/crates/bevy_ecs/src/lifecycle.rs @@ -55,7 +55,7 @@ use crate::{ entity::Entity, event::{ BufferedEvent, EntityEvent, Event, EventCursor, EventId, EventIterator, - EventIteratorWithId, Events, + EventIteratorWithId, EventKey, Events, }, query::FilteredAccessSet, relationship::RelationshipHookMode, @@ -314,16 +314,16 @@ impl ComponentHooks { } } -/// [`ComponentId`] for [`Add`] -pub const ADD: ComponentId = ComponentId::new(0); -/// [`ComponentId`] for [`Insert`] -pub const INSERT: ComponentId = ComponentId::new(1); -/// [`ComponentId`] for [`Replace`] -pub const REPLACE: ComponentId = ComponentId::new(2); -/// [`ComponentId`] for [`Remove`] -pub const REMOVE: ComponentId = ComponentId::new(3); -/// [`ComponentId`] for [`Despawn`] -pub const DESPAWN: ComponentId = ComponentId::new(4); +/// [`EventKey`] for [`Add`] +pub const ADD: EventKey = EventKey(ComponentId::new(0)); +/// [`EventKey`] for [`Insert`] +pub const INSERT: EventKey = EventKey(ComponentId::new(1)); +/// [`EventKey`] for [`Replace`] +pub const REPLACE: EventKey = EventKey(ComponentId::new(2)); +/// [`EventKey`] for [`Remove`] +pub const REMOVE: EventKey = EventKey(ComponentId::new(3)); +/// [`EventKey`] for [`Despawn`] +pub const DESPAWN: EventKey = EventKey(ComponentId::new(4)); /// Trigger emitted when a component is inserted onto an entity that does not already have that /// component. Runs before `Insert`. diff --git a/crates/bevy_ecs/src/observer/mod.rs b/crates/bevy_ecs/src/observer/mod.rs index b3a8b3b5cd2c7..28b3503aa2247 100644 --- a/crates/bevy_ecs/src/observer/mod.rs +++ b/crates/bevy_ecs/src/observer/mod.rs @@ -192,7 +192,7 @@ impl<'w, E, B: Bundle> On<'w, E, B> { } /// Returns the event type of this [`On`] instance. - pub fn event_type(&self) -> ComponentId { + pub fn event_type(&self) -> EventKey { self.trigger.event_type } @@ -437,7 +437,7 @@ all_tuples!( #[derive(Default, Clone)] pub struct ObserverDescriptor { /// The events the observer is watching. - events: Vec, + events: Vec, /// The components the observer is watching. components: Vec, @@ -451,7 +451,7 @@ impl ObserverDescriptor { /// # Safety /// The type of each [`ComponentId`] in `events` _must_ match the actual value /// of the event passed into the observer. - pub unsafe fn with_events(mut self, events: Vec) -> Self { + pub unsafe fn with_events(mut self, events: Vec) -> Self { self.events = events; self } @@ -469,7 +469,7 @@ impl ObserverDescriptor { } /// Returns the `events` that the observer is watching. - pub fn events(&self) -> &[ComponentId] { + pub fn events(&self) -> &[EventKey] { &self.events } @@ -492,7 +492,8 @@ pub struct ObserverTrigger { /// The [`Entity`] of the observer handling the trigger. pub observer: Entity, /// The [`Event`] the trigger targeted. - pub event_type: ComponentId, + // pub event_type: ComponentId, + pub event_type: EventKey, /// The [`ComponentId`]s the trigger targeted. components: SmallVec<[ComponentId; 2]>, /// The entity that the entity-event targeted, if any. @@ -590,11 +591,11 @@ pub struct Observers { remove: CachedObservers, despawn: CachedObservers, // Map from trigger type to set of observers listening to that trigger - cache: HashMap, + cache: HashMap, } impl Observers { - pub(crate) fn get_observers_mut(&mut self, event_type: ComponentId) -> &mut CachedObservers { + pub(crate) fn get_observers_mut(&mut self, event_type: EventKey) -> &mut CachedObservers { use crate::lifecycle::*; match event_type { @@ -610,8 +611,8 @@ impl Observers { /// Attempts to get the observers for the given `event_type`. /// /// When accessing the observers for lifecycle events, such as [`Add`], [`Insert`], [`Replace`], [`Remove`], and [`Despawn`], - /// use the [`ComponentId`] constants from the [`lifecycle`](crate::lifecycle) module. - pub fn try_get_observers(&self, event_type: ComponentId) -> Option<&CachedObservers> { + /// use the [`EventKey`] constants from the [`lifecycle`](crate::lifecycle) module. + pub fn try_get_observers(&self, event_type: EventKey) -> Option<&CachedObservers> { use crate::lifecycle::*; match event_type { @@ -627,7 +628,7 @@ impl Observers { /// This will run the observers of the given `event_type`, targeting the given `entity` and `components`. pub(crate) fn invoke( mut world: DeferredWorld, - event_type: ComponentId, + event_type: EventKey, current_target: Option, original_target: Option, components: impl Iterator + Clone, @@ -698,7 +699,7 @@ impl Observers { }); } - pub(crate) fn is_archetype_cached(event_type: ComponentId) -> Option { + pub(crate) fn is_archetype_cached(event_type: EventKey) -> Option { use crate::lifecycle::*; match event_type { @@ -785,10 +786,10 @@ impl World { } pub(crate) fn trigger_with_caller(&mut self, mut event: E, caller: MaybeLocation) { - let event_id = E::register_component_id(self); + let event_type = E::register_event_type(self); // SAFETY: We just registered `event_id` with the type of `event` unsafe { - self.trigger_dynamic_ref_with_caller(event_id, &mut event, caller); + self.trigger_dynamic_ref_with_caller(event_type, &mut event, caller); } } @@ -798,14 +799,14 @@ impl World { /// or use the event after it has been modified by observers. #[track_caller] pub fn trigger_ref(&mut self, event: &mut E) { - let event_id = E::register_component_id(self); + let event_type = E::register_event_type(self); // SAFETY: We just registered `event_id` with the type of `event` - unsafe { self.trigger_dynamic_ref_with_caller(event_id, event, MaybeLocation::caller()) }; + unsafe { self.trigger_dynamic_ref_with_caller(event_type, event, MaybeLocation::caller()) }; } unsafe fn trigger_dynamic_ref_with_caller( &mut self, - event_id: ComponentId, + event_type: EventKey, event_data: &mut E, caller: MaybeLocation, ) { @@ -813,7 +814,7 @@ impl World { // SAFETY: `event_data` is accessible as the type represented by `event_id` unsafe { world.trigger_observers_with_data::<_, ()>( - event_id, + event_type, None, None, core::iter::empty::(), @@ -840,10 +841,10 @@ impl World { targets: impl TriggerTargets, caller: MaybeLocation, ) { - let event_id = E::register_component_id(self); + let event_type = E::register_event_type(self); // SAFETY: We just registered `event_id` with the type of `event` unsafe { - self.trigger_targets_dynamic_ref_with_caller(event_id, &mut event, targets, caller); + self.trigger_targets_dynamic_ref_with_caller(event_type, &mut event, targets, caller); } } @@ -858,9 +859,9 @@ impl World { event: &mut E, targets: impl TriggerTargets, ) { - let event_id = E::register_component_id(self); + let event_type = E::register_event_type(self); // SAFETY: We just registered `event_id` with the type of `event` - unsafe { self.trigger_targets_dynamic_ref(event_id, event, targets) }; + unsafe { self.trigger_targets_dynamic_ref(event_type, event, targets) }; } /// Triggers the given [`EntityEvent`] for the given `targets`, which will run any [`Observer`]s watching for it. @@ -875,13 +876,13 @@ impl World { #[track_caller] pub unsafe fn trigger_targets_dynamic( &mut self, - event_id: ComponentId, + event_type: EventKey, mut event_data: E, targets: Targets, ) { // SAFETY: `event_data` is accessible as the type represented by `event_id` unsafe { - self.trigger_targets_dynamic_ref(event_id, &mut event_data, targets); + self.trigger_targets_dynamic_ref(event_type, &mut event_data, targets); }; } @@ -897,12 +898,12 @@ impl World { #[track_caller] pub unsafe fn trigger_targets_dynamic_ref( &mut self, - event_id: ComponentId, + event_type: EventKey, event_data: &mut E, targets: Targets, ) { self.trigger_targets_dynamic_ref_with_caller( - event_id, + event_type, event_data, targets, MaybeLocation::caller(), @@ -914,7 +915,7 @@ impl World { /// See `trigger_targets_dynamic_ref` unsafe fn trigger_targets_dynamic_ref_with_caller( &mut self, - event_id: ComponentId, + event_type: EventKey, event_data: &mut E, targets: Targets, caller: MaybeLocation, @@ -925,7 +926,7 @@ impl World { // SAFETY: `event_data` is accessible as the type represented by `event_id` unsafe { world.trigger_observers_with_data::<_, E::Traversal>( - event_id, + event_type, None, None, targets.components(), @@ -939,7 +940,7 @@ impl World { // SAFETY: `event_data` is accessible as the type represented by `event_id` unsafe { world.trigger_observers_with_data::<_, E::Traversal>( - event_id, + event_type, Some(target_entity), Some(target_entity), targets.components(), @@ -1322,7 +1323,7 @@ mod tests { fn observer_multiple_events() { let mut world = World::new(); world.init_resource::(); - let on_remove = Remove::register_component_id(&mut world); + let on_remove = Remove::register_event_type(&mut world); world.spawn( // SAFETY: Add and Remove are both unit types, so this is safe unsafe { @@ -1596,7 +1597,7 @@ mod tests { fn observer_dynamic_trigger() { let mut world = World::new(); world.init_resource::(); - let event_a = Remove::register_component_id(&mut world); + let event_a = Remove::register_event_type(&mut world); // SAFETY: we registered `event_a` above and it matches the type of EventA let observe = unsafe { diff --git a/crates/bevy_ecs/src/observer/runner.rs b/crates/bevy_ecs/src/observer/runner.rs index d6bffd8f22ddf..7c6456a7369a1 100644 --- a/crates/bevy_ecs/src/observer/runner.rs +++ b/crates/bevy_ecs/src/observer/runner.rs @@ -283,7 +283,7 @@ impl Observer { /// # Safety /// The type of the `event` [`ComponentId`] _must_ match the actual value /// of the event passed into the observer system. - pub unsafe fn with_event(mut self, event: ComponentId) -> Self { + pub unsafe fn with_event(mut self, event: EventKey) -> Self { self.descriptor.events.push(event); self } @@ -443,13 +443,13 @@ fn hook_on_add>( HookContext { entity, .. }: HookContext, ) { world.commands().queue(move |world: &mut World| { - let event_id = E::register_component_id(world); + let event_type = E::register_event_type(world); let mut components = vec![]; B::component_ids(&mut world.components_registrator(), &mut |id| { components.push(id); }); if let Some(mut observer) = world.get_mut::(entity) { - observer.descriptor.events.push(event_id); + observer.descriptor.events.push(event_type); observer.descriptor.components.extend(components); let system: &mut dyn Any = observer.system.as_mut(); diff --git a/crates/bevy_ecs/src/world/deferred_world.rs b/crates/bevy_ecs/src/world/deferred_world.rs index edf4b186a37d5..146a9101739de 100644 --- a/crates/bevy_ecs/src/world/deferred_world.rs +++ b/crates/bevy_ecs/src/world/deferred_world.rs @@ -7,7 +7,7 @@ use crate::{ change_detection::{MaybeLocation, MutUntyped}, component::{ComponentId, Mutable}, entity::Entity, - event::{BufferedEvent, EntityEvent, Event, EventId, Events, SendBatchIds}, + event::{BufferedEvent, EntityEvent, Event, EventId, EventKey, Events, SendBatchIds}, lifecycle::{HookContext, INSERT, REPLACE}, observer::{Observers, TriggerTargets}, prelude::{Component, QueryState}, @@ -740,7 +740,7 @@ impl<'w> DeferredWorld<'w> { #[inline] pub(crate) unsafe fn trigger_observers( &mut self, - event: ComponentId, + event: EventKey, target: Option, components: impl Iterator + Clone, caller: MaybeLocation, @@ -764,7 +764,7 @@ impl<'w> DeferredWorld<'w> { #[inline] pub(crate) unsafe fn trigger_observers_with_data( &mut self, - event: ComponentId, + event: EventKey, current_target: Option, original_target: Option, components: impl Iterator + Clone, diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index fca9091dd5f96..ba9c881bbc135 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -152,19 +152,19 @@ impl World { #[inline] fn bootstrap(&mut self) { // The order that we register these events is vital to ensure that the constants are correct! - let on_add = Add::register_component_id(self); + let on_add = Add::register_event_type(self); assert_eq!(ADD, on_add); - let on_insert = Insert::register_component_id(self); + let on_insert = Insert::register_event_type(self); assert_eq!(INSERT, on_insert); - let on_replace = Replace::register_component_id(self); + let on_replace = Replace::register_event_type(self); assert_eq!(REPLACE, on_replace); - let on_remove = Remove::register_component_id(self); + let on_remove = Remove::register_event_type(self); assert_eq!(REMOVE, on_remove); - let on_despawn = Despawn::register_component_id(self); + let on_despawn = Despawn::register_event_type(self); assert_eq!(DESPAWN, on_despawn); // This sets up `Disabled` as a disabling component, via the FromWorld impl