bevy_ecs/event/
registry.rs

1use crate as bevy_ecs;
2use bevy_ecs::{
3    change_detection::{DetectChangesMut, MutUntyped},
4    component::{ComponentId, Tick},
5    event::{Event, Events},
6    system::Resource,
7    world::World,
8};
9
10#[doc(hidden)]
11struct RegisteredEvent {
12    component_id: ComponentId,
13    // Required to flush the secondary buffer and drop events even if left unchanged.
14    previously_updated: bool,
15    // SAFETY: The component ID and the function must be used to fetch the Events<T> resource
16    // of the same type initialized in `register_event`, or improper type casts will occur.
17    update: unsafe fn(MutUntyped),
18}
19
20/// A registry of all of the [`Events`] in the [`World`], used by [`event_update_system`](crate::event::update::event_update_system)
21/// to update all of the events.
22#[derive(Resource, Default)]
23pub struct EventRegistry {
24    /// Should the events be updated?
25    ///
26    /// This field is generally automatically updated by the [`signal_event_update_system`](crate::event::update::signal_event_update_system).
27    pub should_update: ShouldUpdateEvents,
28    event_updates: Vec<RegisteredEvent>,
29}
30
31/// Controls whether or not the events in an [`EventRegistry`] should be updated.
32#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
33pub enum ShouldUpdateEvents {
34    /// Without any fixed timestep, events should always be updated each frame.
35    #[default]
36    Always,
37    /// We need to wait until at least one pass of the fixed update schedules to update the events.
38    Waiting,
39    /// At least one pass of the fixed update schedules has occurred, and the events are ready to be updated.
40    Ready,
41}
42
43impl EventRegistry {
44    /// Registers an event type to be updated in a given [`World`]
45    ///
46    /// If no instance of the [`EventRegistry`] exists in the world, this will add one - otherwise it will use
47    /// the existing instance.
48    pub fn register_event<T: Event>(world: &mut World) {
49        // By initializing the resource here, we can be sure that it is present,
50        // and receive the correct, up-to-date `ComponentId` even if it was previously removed.
51        let component_id = world.init_resource::<Events<T>>();
52        let mut registry = world.get_resource_or_init::<Self>();
53        registry.event_updates.push(RegisteredEvent {
54            component_id,
55            previously_updated: false,
56            update: |ptr| {
57                // SAFETY: The resource was initialized with the type Events<T>.
58                unsafe { ptr.with_type::<Events<T>>() }
59                    .bypass_change_detection()
60                    .update();
61            },
62        });
63    }
64
65    /// Updates all of the registered events in the World.
66    pub fn run_updates(&mut self, world: &mut World, last_change_tick: Tick) {
67        for registered_event in &mut self.event_updates {
68            // 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) {
70                let has_changed = events.has_changed_since(last_change_tick);
71                if registered_event.previously_updated || has_changed {
72                    // SAFETY: The update function pointer is called with the resource
73                    // fetched from the same component ID.
74                    unsafe { (registered_event.update)(events) };
75                    // Always set to true if the events have changed, otherwise disable running on the second invocation
76                    // to wait for more changes.
77                    registered_event.previously_updated =
78                        has_changed || !registered_event.previously_updated;
79                }
80            }
81        }
82    }
83
84    /// Removes an event from the world and it's associated [`EventRegistry`].
85    pub fn deregister_events<T: Event>(world: &mut World) {
86        let component_id = world.init_resource::<Events<T>>();
87        let mut registry = world.get_resource_or_init::<Self>();
88        registry
89            .event_updates
90            .retain(|e| e.component_id != component_id);
91        world.remove_resource::<Events<T>>();
92    }
93}