-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Optimize Event Updates #12936
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize Event Updates #12936
Changes from 6 commits
65449ea
dd93284
59a3d3c
4a6e196
5a9f98a
b9830cb
f790cd2
c53777b
9759e9c
c906686
a5a8271
908003f
d726f5e
60e2cf3
d4b74a1
6f160a8
c53bca5
836ade6
99dca64
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,11 @@ | ||
//! Event handling types. | ||
|
||
use crate as bevy_ecs; | ||
use crate::system::{Local, Res, ResMut, Resource, SystemParam}; | ||
use crate::{ | ||
change_detection::Mut, | ||
system::{Local, Res, ResMut, Resource, SystemParam}, | ||
world::World, | ||
}; | ||
pub use bevy_ecs_macros::Event; | ||
use bevy_ecs_macros::SystemSet; | ||
use bevy_utils::detailed_trace; | ||
|
@@ -253,7 +257,13 @@ impl<E: Event> Events<E> { | |
/// | ||
/// If you need access to the events that were removed, consider using [`Events::update_drain`]. | ||
pub fn update(&mut self) { | ||
let _ = self.update_drain(); | ||
std::mem::swap(&mut self.events_a, &mut self.events_b); | ||
self.events_b.clear(); | ||
self.events_b.start_event_count = self.event_count; | ||
debug_assert_eq!( | ||
self.events_a.start_event_count + self.events_a.len(), | ||
self.events_b.start_event_count | ||
); | ||
} | ||
|
||
/// Swaps the event buffers and drains the oldest event buffer, returning an iterator | ||
|
@@ -798,6 +808,33 @@ impl<'a, E: Event> ExactSizeIterator for EventIteratorWithId<'a, E> { | |
} | ||
} | ||
|
||
/// A registry of all of the [`Events`] in the [`World`], used by [`event_update_system`] | ||
/// to update all of the events. | ||
#[derive(Resource, Default)] | ||
pub struct EventRegistry { | ||
event_updates: Vec<fn(&mut World)>, | ||
} | ||
|
||
impl EventRegistry { | ||
/// Registers an event type to be updated. | ||
pub fn register_event<T: Event>(world: &mut World) { | ||
world.init_resource::<Events<T>>(); | ||
let mut registry = world.get_resource_or_insert_with(Self::default); | ||
registry.event_updates.push(|world| { | ||
if let Some(mut events) = world.get_resource_mut::<Events<T>>() { | ||
events.update(); | ||
} | ||
}); | ||
} | ||
|
||
/// Updates all of the registered events in the World. | ||
pub fn run_updates(&mut self, world: &mut World) { | ||
for update in &mut self.event_updates { | ||
update(world); | ||
} | ||
} | ||
} | ||
|
||
#[doc(hidden)] | ||
#[derive(Resource, Default)] | ||
pub struct EventUpdateSignal(bool); | ||
|
@@ -813,33 +850,23 @@ pub fn signal_event_update_system(signal: Option<ResMut<EventUpdateSignal>>) { | |
} | ||
} | ||
|
||
/// Resets the `EventUpdateSignal` | ||
pub fn reset_event_update_signal_system(signal: Option<ResMut<EventUpdateSignal>>) { | ||
if let Some(mut s) = signal { | ||
s.0 = false; | ||
/// A system that calls [`Events::update`] on all registered [`Events`] in the world. | ||
pub fn event_update_system(world: &mut World) { | ||
if world.contains_resource::<EventRegistry>() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this better than just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If for whatever reason, someone is running without any events in their World, this would avoid stealth allocating it. |
||
world.resource_scope(|world, mut registry: Mut<EventRegistry>| { | ||
registry.run_updates(world); | ||
}); | ||
} | ||
} | ||
|
||
/// A system that calls [`Events::update`]. | ||
pub fn event_update_system<T: Event>( | ||
update_signal: Option<Res<EventUpdateSignal>>, | ||
mut events: ResMut<Events<T>>, | ||
) { | ||
if let Some(signal) = update_signal { | ||
// If we haven't got a signal to update the events, but we *could* get such a signal | ||
// return early and update the events later. | ||
if !signal.0 { | ||
return; | ||
} | ||
if let Some(mut s) = world.get_resource_mut::<EventUpdateSignal>() { | ||
s.0 = false; | ||
james7132 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
events.update(); | ||
} | ||
|
||
/// A run condition that checks if the event's [`event_update_system`] | ||
/// needs to run or not. | ||
pub fn event_update_condition<T: Event>(events: Res<Events<T>>) -> bool { | ||
!events.events_a.is_empty() || !events.events_b.is_empty() | ||
/// A run condition for [`event_update_system`]. | ||
pub fn event_update_condition(signal: Option<Res<EventUpdateSignal>>) -> bool { | ||
// If we haven't got a signal to update the events, but we *could* get such a signal | ||
// return early and update the events later. | ||
signal.map(|signal| signal.0).unwrap_or(false) | ||
james7132 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// [`Iterator`] over sent [`EventIds`](`EventId`) from a batch. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
use bevy_ecs::system::{Res, ResMut}; | ||
use bevy_reflect::Reflect; | ||
use bevy_utils::{tracing::debug, Duration}; | ||
|
||
|
@@ -268,11 +267,7 @@ impl Default for Virtual { | |
/// Advances [`Time<Virtual>`] and [`Time`] based on the elapsed [`Time<Real>`]. | ||
/// | ||
/// The virtual time will be advanced up to the provided [`Time::max_delta`]. | ||
pub fn virtual_time_system( | ||
mut current: ResMut<Time>, | ||
mut virt: ResMut<Time<Virtual>>, | ||
real: Res<Time<Real>>, | ||
) { | ||
pub fn update_virtual_time(current: &mut Time, virt: &mut Time<Virtual>, real: &Time<Real>) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are the bevy_time changes supposed to be part of this OR? I don't understand how they're related. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is in a similar vein of being a common cost in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a moderate preference to move these changes into their own PR, but won't block on it. |
||
let raw_delta = real.delta(); | ||
virt.advance_with_raw_delta(raw_delta); | ||
*current = virt.as_generic(); | ||
|
Uh oh!
There was an error while loading. Please reload this page.