Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/event/registry.rs
6600 views
1
use alloc::vec::Vec;
2
use bevy_ecs::{
3
change_detection::{DetectChangesMut, MutUntyped},
4
component::Tick,
5
event::{BufferedEvent, EventKey, Events},
6
resource::Resource,
7
world::World,
8
};
9
10
#[doc(hidden)]
11
struct RegisteredEvent {
12
event_key: EventKey,
13
// Required to flush the secondary buffer and drop events even if left unchanged.
14
previously_updated: bool,
15
// SAFETY: The `EventKey`'s 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)]
23
pub 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)]
33
pub 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
43
impl 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: BufferedEvent>(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
event_key: EventKey(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) =
70
world.get_resource_mut_by_id(registered_event.event_key.component_id())
71
{
72
let has_changed = events.has_changed_since(last_change_tick);
73
if registered_event.previously_updated || has_changed {
74
// SAFETY: The update function pointer is called with the resource
75
// fetched from the same component ID.
76
unsafe { (registered_event.update)(events) };
77
// Always set to true if the events have changed, otherwise disable running on the second invocation
78
// to wait for more changes.
79
registered_event.previously_updated =
80
has_changed || !registered_event.previously_updated;
81
}
82
}
83
}
84
}
85
86
/// Removes an event from the world and its associated [`EventRegistry`].
87
pub fn deregister_events<T: BufferedEvent>(world: &mut World) {
88
let component_id = world.init_resource::<Events<T>>();
89
let mut registry = world.get_resource_or_init::<Self>();
90
registry
91
.event_updates
92
.retain(|e| e.event_key.component_id() != component_id);
93
world.remove_resource::<Events<T>>();
94
}
95
}
96
97