From 3a3132b5dca79a93f60d370bad2be22fce928d24 Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sat, 27 Mar 2021 20:29:55 -0300 Subject: [PATCH 01/10] Rough draft for automatic event subscriptions --- crates/bevy_app/src/app_builder.rs | 3 +- crates/bevy_app/src/event.rs | 286 +++++++++++++++----------- crates/bevy_gilrs/src/gilrs_system.rs | 7 +- 3 files changed, 176 insertions(+), 120 deletions(-) diff --git a/crates/bevy_app/src/app_builder.rs b/crates/bevy_app/src/app_builder.rs index 36bb74953fe82..c96b900bd0b3f 100644 --- a/crates/bevy_app/src/app_builder.rs +++ b/crates/bevy_app/src/app_builder.rs @@ -2,7 +2,7 @@ use crate::{ app::{App, AppExit}, event::Events, plugin::Plugin, - CoreStage, PluginGroup, PluginGroupBuilder, StartupStage, + CoreStage, EventSubscriptions, PluginGroup, PluginGroupBuilder, StartupStage, }; use bevy_ecs::{ component::{Component, ComponentDescriptor}, @@ -228,6 +228,7 @@ impl AppBuilder { T: Component, { self.insert_resource(Events::::default()) + .insert_resource(EventSubscriptions::::default()) .add_system_to_stage(CoreStage::First, Events::::update_system.system()) } diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index d123b27d289e1..042c079085c0e 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -3,6 +3,7 @@ use bevy_ecs::{ system::{Local, Res, ResMut, SystemParam}, }; use bevy_utils::tracing::trace; +use std::cmp::min; use std::{ fmt::{self}, hash::Hash, @@ -49,12 +50,6 @@ struct EventInstance { pub event: T, } -#[derive(Debug)] -enum State { - A, - B, -} - /// An event collection that represents the events that occurred within the last two /// [`Events::update`] calls. /// Events can be written to using an [`EventWriter`] @@ -117,23 +112,17 @@ enum State { /// but can be done by adding your event as a resource instead of using [`AppBuilder::add_event`]. #[derive(Debug)] pub struct Events { - events_a: Vec>, - events_b: Vec>, - a_start_event_count: usize, - b_start_event_count: usize, + buffer: Vec>, event_count: usize, - state: State, + event_offset: usize, } impl Default for Events { fn default() -> Self { Events { - a_start_event_count: 0, - b_start_event_count: 0, + buffer: Vec::new(), event_count: 0, - events_a: Vec::new(), - events_b: Vec::new(), - state: State::A, + event_offset: 0, } } } @@ -146,10 +135,27 @@ fn map_instance_event(event_instance: &EventInstance) -> &T { &event_instance.event } +pub struct EventSubscriptions { + last_event_counts: Vec, + last_event_count: usize, + _phantom: PhantomData, +} + +impl Default for EventSubscriptions { + fn default() -> Self { + EventSubscriptions:: { + last_event_counts: Vec::new(), + last_event_count: 0, + _phantom: Default::default(), + } + } +} + /// Reads events of type `T` in order and tracks which events have already been read. #[derive(SystemParam)] pub struct EventReader<'a, T: Component> { - last_event_count: Local<'a, (usize, PhantomData)>, + subscription_id: Local<'a, (Option, PhantomData)>, + event_subscriptions: ResMut<'a, EventSubscriptions>, events: Res<'a, Events>, } @@ -206,47 +212,18 @@ fn internal_event_reader<'a, T>( ) -> impl DoubleEndedIterator)> { // if the reader has seen some of the events in a buffer, find the proper index offset. // otherwise read all events in the buffer - let a_index = if *last_event_count > events.a_start_event_count { - *last_event_count - events.a_start_event_count - } else { - 0 - }; - let b_index = if *last_event_count > events.b_start_event_count { - *last_event_count - events.b_start_event_count + let index = if *last_event_count > events.event_offset { + *last_event_count - events.event_offset } else { 0 }; *last_event_count = events.event_count; - match events.state { - State::A => events - .events_b - .get(b_index..) - .unwrap_or_else(|| &[]) - .iter() - .map(map_instance_event_with_id) - .chain( - events - .events_a - .get(a_index..) - .unwrap_or_else(|| &[]) - .iter() - .map(map_instance_event_with_id), - ), - State::B => events - .events_a - .get(a_index..) - .unwrap_or_else(|| &[]) - .iter() - .map(map_instance_event_with_id) - .chain( - events - .events_b - .get(b_index..) - .unwrap_or_else(|| &[]) - .iter() - .map(map_instance_event_with_id), - ), - } + events + .buffer + .get(index..) + .unwrap_or_else(|| &[]) + .iter() + .map(map_instance_event_with_id) } impl<'a, T: Component> EventReader<'a, T> { @@ -257,9 +234,30 @@ impl<'a, T: Component> EventReader<'a, T> { self.iter_with_id().map(|(event, _id)| event) } + fn get_subscription_id( + subscription_id: &mut Option, + event_subscriptions: &mut EventSubscriptions, + event_count: usize, + ) -> usize { + *subscription_id.get_or_insert_with(|| { + event_subscriptions.last_event_counts.push(event_count); + event_subscriptions.last_event_counts.len() - 1 + }) + } + /// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events. pub fn iter_with_id(&mut self) -> impl DoubleEndedIterator)> { - internal_event_reader(&mut self.last_event_count.0, &self.events).map(|(event, id)| { + let subscription_id = Self::get_subscription_id( + &mut self.subscription_id.0, + &mut *self.event_subscriptions, + self.events.event_offset, + ); + let mut last_event_count = self + .event_subscriptions + .last_event_counts + .get_mut(subscription_id) + .unwrap(); + internal_event_reader(&mut last_event_count, &self.events).map(|(event, id)| { trace!("EventReader::iter() -> {}", id); (event, id) }) @@ -278,16 +276,13 @@ impl Events { let event_instance = EventInstance { event_id, event }; - match self.state { - State::A => self.events_a.push(event_instance), - State::B => self.events_b.push(event_instance), - } + self.buffer.push(event_instance); self.event_count += 1; } /// Gets a new [ManualEventReader]. This will include all events already in the event buffers. - pub fn get_reader(&self) -> ManualEventReader { + pub fn get_reader(&mut self) -> ManualEventReader { ManualEventReader { last_event_count: 0, _marker: PhantomData, @@ -296,7 +291,7 @@ impl Events { /// Gets a new [ManualEventReader]. This will ignore all events already in the event buffers. It /// will read all future events. - pub fn get_reader_current(&self) -> ManualEventReader { + pub fn get_reader_current(&mut self) -> ManualEventReader { ManualEventReader { last_event_count: self.event_count, _marker: PhantomData, @@ -305,47 +300,42 @@ impl Events { /// Swaps the event buffers and clears the oldest event buffer. In general, this should be /// called once per frame/update. - pub fn update(&mut self) { - match self.state { - State::A => { - self.events_b = Vec::new(); - self.state = State::B; - self.b_start_event_count = self.event_count; - } - State::B => { - self.events_a = Vec::new(); - self.state = State::A; - self.a_start_event_count = self.event_count; - } + pub fn update(&mut self, event_subscriptions: &mut EventSubscriptions) { + if event_subscriptions.last_event_counts.is_empty() { + event_subscriptions.last_event_count = self.event_count; + self.event_offset = self.event_count; + self.buffer.clear(); + } else { + let read_count = event_subscriptions + .last_event_counts + .iter() + .fold(usize::max_value(), |count, next| min(count, *next)); + let remove_index = read_count - self.event_offset; + self.event_offset = read_count; + self.buffer.drain(0..remove_index); + event_subscriptions.last_event_count = self.event_count; } } /// A system that calls [Events::update] once per frame. - pub fn update_system(mut events: ResMut) { - events.update(); + pub fn update_system( + mut events: ResMut, + mut event_subscriptions: ResMut>, + ) { + events.update(&mut *event_subscriptions); } /// Removes all events. pub fn clear(&mut self) { - self.events_a.clear(); - self.events_b.clear(); + self.buffer.clear(); + self.event_offset = self.event_count; } /// Creates a draining iterator that removes all events. pub fn drain(&mut self) -> impl Iterator + '_ { + self.event_offset = self.event_count; let map = |i: EventInstance| i.event; - match self.state { - State::A => self - .events_b - .drain(..) - .map(map) - .chain(self.events_a.drain(..).map(map)), - State::B => self - .events_a - .drain(..) - .map(map) - .chain(self.events_b.drain(..).map(map)), - } + self.buffer.drain(..).map(map) } pub fn extend(&mut self, events: I) @@ -364,16 +354,18 @@ impl Events { /// If events happen outside that window, they will not be handled. For example, any events that /// happen after this call and before the next `update()` call will be dropped. pub fn iter_current_update_events(&self) -> impl DoubleEndedIterator { - match self.state { - State::A => self.events_a.iter().map(map_instance_event), - State::B => self.events_b.iter().map(map_instance_event), - } + self.buffer.iter().map(map_instance_event) } } +impl EventSubscriptions {} + #[cfg(test)] mod tests { use super::*; + use bevy_ecs::schedule::{Schedule, SystemStage}; + use bevy_ecs::system::IntoSystem; + use bevy_ecs::world::World; #[derive(Copy, Clone, PartialEq, Eq, Debug)] struct TestEvent { @@ -382,26 +374,71 @@ mod tests { #[test] fn test_events() { + fn event_writer_system1(mut event_writer: EventWriter) { + let event_0 = TestEvent { i: 0 }; + let event_1 = TestEvent { i: 1 }; + event_writer.send(event_0); + event_writer.send(event_1); + } + fn event_writer_system2(mut event_writer: EventWriter) { + let event_2 = TestEvent { i: 2 }; + event_writer.send(event_2); + } + fn event_reader_system1(mut event_reader: EventReader) { + for _event in event_reader.iter() { + // hi + } + } + let mut schedule = Schedule::default(); + let update1 = SystemStage::single(event_writer_system1.system()); + let update2 = SystemStage::single(event_reader_system1.system()); + let update3 = SystemStage::single(event_writer_system2.system()); + let update4 = SystemStage::single(event_reader_system1.system()); + let update5 = SystemStage::single(Events::::update_system.system()); + schedule.add_stage("update1", update1); + schedule.add_stage("update2", update2); + schedule.add_stage("update3", update3); + schedule.add_stage("update4", update4); + schedule.add_stage("update5", update5); + + let mut world = World::default(); + world.insert_resource(Events::::default()); + world.insert_resource(EventSubscriptions::::default()); + schedule.run_once(&mut world); + let events = world.get_resource::>().unwrap(); + assert_eq!( + events.event_offset, 2, + "All subscribed systems read the first two events." + ); + + schedule.run_once(&mut world); + let events = world.get_resource::>().unwrap(); + assert_eq!( + events.event_offset, 5, + "All subscribed systems read all events from last frame plus 2 new events from this frame" + ); + } + + #[test] + fn test_manual_events() { let mut events = Events::::default(); + let mut event_subscriptions = EventSubscriptions::::default(); let event_0 = TestEvent { i: 0 }; let event_1 = TestEvent { i: 1 }; let event_2 = TestEvent { i: 2 }; - // this reader will miss event_0 and event_1 because it wont read them over the course of - // two updates - let mut reader_missed = events.get_reader(); - + let mut reader_slow = events.get_reader(); let mut reader_a = events.get_reader(); events.send(event_0); assert_eq!( - get_events(&events, &mut reader_a), + get_events(&mut events, &mut reader_a), vec![event_0], "reader_a created before event receives event" ); assert_eq!( - get_events(&events, &mut reader_a), + get_events(&mut events, &mut reader_a), vec![], "second iteration of reader_a created before event results in zero events" ); @@ -409,12 +446,12 @@ mod tests { let mut reader_b = events.get_reader(); assert_eq!( - get_events(&events, &mut reader_b), + get_events(&mut events, &mut reader_b), vec![event_0], "reader_b created after event receives event" ); assert_eq!( - get_events(&events, &mut reader_b), + get_events(&mut events, &mut reader_b), vec![], "second iteration of reader_b created after event results in zero events" ); @@ -424,55 +461,70 @@ mod tests { let mut reader_c = events.get_reader(); assert_eq!( - get_events(&events, &mut reader_c), + get_events(&mut events, &mut reader_c), vec![event_0, event_1], "reader_c created after two events receives both events" ); assert_eq!( - get_events(&events, &mut reader_c), + get_events(&mut events, &mut reader_c), vec![], "second iteration of reader_c created after two event results in zero events" ); assert_eq!( - get_events(&events, &mut reader_a), + get_events(&mut events, &mut reader_a), vec![event_1], "reader_a receives next unread event" ); - events.update(); + events.update(&mut event_subscriptions); let mut reader_d = events.get_reader(); events.send(event_2); assert_eq!( - get_events(&events, &mut reader_a), + get_events(&mut events, &mut reader_a), vec![event_2], "reader_a receives event created after update" ); assert_eq!( - get_events(&events, &mut reader_b), - vec![event_1, event_2], - "reader_b receives events created before and after update" + get_events(&mut events, &mut reader_b), + vec![event_2], + "reader_b receives events created after update" + ); + assert_eq!( + get_events(&mut events, &mut reader_c), + vec![event_2], + "reader_c receives event created since last fetch" + ); + assert_eq!( + get_events(&mut events, &mut reader_d), + vec![event_2], + "reader_d receives all events created after update" ); + + events.update(&mut event_subscriptions); + assert_eq!( - get_events(&events, &mut reader_d), - vec![event_0, event_1, event_2], - "reader_d receives all events created before and after update" + get_events(&mut events, &mut reader_slow), + vec![], + "reader_slow misses all events" ); - events.update(); + events.update(&mut event_subscriptions); + // At this point, the event buffer should be emptied and the count and offset + // should be the same since all subscribed readers have read all the events. assert_eq!( - get_events(&events, &mut reader_missed), - vec![event_2], - "reader_missed missed events unread after to update() calls" + events.event_count, events.event_offset, + "all subscribed readers have read all events" ); + assert_eq!(events.buffer.is_empty(), true, "event buffer is empty"); } fn get_events( - events: &Events, + events: &mut Events, reader: &mut ManualEventReader, ) -> Vec { reader.iter(events).cloned().collect::>() diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index 4f34370e91619..ea1e0264b84e5 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -1,5 +1,5 @@ use crate::converter::{convert_axis, convert_button, convert_gamepad_id}; -use bevy_app::Events; +use bevy_app::{EventSubscriptions, Events}; use bevy_ecs::world::World; use bevy_input::{gamepad::GamepadEventRaw, prelude::*}; use gilrs::{EventType, Gilrs}; @@ -20,7 +20,10 @@ pub fn gilrs_event_system(world: &mut World) { let world = world.cell(); let mut gilrs = world.get_non_send_mut::().unwrap(); let mut event = world.get_resource_mut::>().unwrap(); - event.update(); + let mut event_subscriptions = world + .get_resource_mut::>() + .unwrap(); + event.update(&mut *event_subscriptions); while let Some(gilrs_event) = gilrs.next_event() { match gilrs_event.event { EventType::Connected => { From a481fcd701c42e5104b4fd732eb7afd215c98acf Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sun, 28 Mar 2021 00:22:20 -0300 Subject: [PATCH 02/10] Changed EventReader to only have read access to EventSubscriptions * SubscriberId SystemParam added to handle initializing the id correctly when system state is initialized, instead of on first use of an EventReader * Changed to use a command to update the subscriber last read counts to avoid write access to EventSubscriptions --- crates/bevy_app/Cargo.toml | 1 + crates/bevy_app/src/app_builder.rs | 2 +- crates/bevy_app/src/event.rs | 135 +++++++++++++++++++++-------- 3 files changed, 103 insertions(+), 35 deletions(-) diff --git a/crates/bevy_app/Cargo.toml b/crates/bevy_app/Cargo.toml index be1b36a05fc73..6eaf8874b9ca2 100644 --- a/crates/bevy_app/Cargo.toml +++ b/crates/bevy_app/Cargo.toml @@ -25,6 +25,7 @@ bevy_utils = { path = "../bevy_utils", version = "0.4.0" } # other serde = { version = "1.0", features = ["derive"] } +parking_lot = "0.11" [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = { version = "0.2" } diff --git a/crates/bevy_app/src/app_builder.rs b/crates/bevy_app/src/app_builder.rs index c96b900bd0b3f..3820cd5484006 100644 --- a/crates/bevy_app/src/app_builder.rs +++ b/crates/bevy_app/src/app_builder.rs @@ -229,7 +229,7 @@ impl AppBuilder { { self.insert_resource(Events::::default()) .insert_resource(EventSubscriptions::::default()) - .add_system_to_stage(CoreStage::First, Events::::update_system.system()) + .add_system_to_stage(CoreStage::Last, Events::::update_system.system()) } /// Inserts a resource to the current [App] and overwrites any resource previously added of the diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index 042c079085c0e..7a0a85a3bcd77 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -1,9 +1,13 @@ +use bevy_ecs::system::{Command, Commands, SystemParamFetch, SystemParamState, SystemState}; +use bevy_ecs::world::{FromWorld, World}; use bevy_ecs::{ component::Component, system::{Local, Res, ResMut, SystemParam}, }; use bevy_utils::tracing::trace; +use parking_lot::{Mutex, RwLock}; use std::cmp::min; +use std::ops::{Add, Deref, DerefMut}; use std::{ fmt::{self}, hash::Hash, @@ -136,26 +140,102 @@ fn map_instance_event(event_instance: &EventInstance) -> &T { } pub struct EventSubscriptions { - last_event_counts: Vec, - last_event_count: usize, + subscriber_last_counts: RwLock>, _phantom: PhantomData, } impl Default for EventSubscriptions { fn default() -> Self { EventSubscriptions:: { - last_event_counts: Vec::new(), - last_event_count: 0, + subscriber_last_counts: RwLock::default(), _phantom: Default::default(), } } } +impl EventSubscriptions { + pub fn add_subscriber(&self) -> usize { + let id = self.subscriber_last_counts.read().len(); + self.subscriber_last_counts.write().push(0); + id + } + + pub fn get_subscriber_count(&self, subscription_id: usize) -> usize { + self.subscriber_last_counts.read()[subscription_id] + } + + pub fn set_subscriber_count(&mut self, subscription_id: usize, count: usize) { + self.subscriber_last_counts.write()[subscription_id] = count; + } +} +pub struct SubscriberId<'a, T: Component>(&'a mut (usize, PhantomData)); + +impl<'a, T: Component> Deref for SubscriberId<'a, T> { + type Target = usize; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 .0 + } +} + +impl<'a, T: Component> DerefMut for SubscriberId<'a, T> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 .0 + } +} + +pub struct SubscriberIdState((usize, PhantomData)); + +impl<'a, T: Component> SystemParam for SubscriberId<'a, T> { + type Fetch = SubscriberIdState; +} + +// SAFE: only local state is accessed +unsafe impl SystemParamState for SubscriberIdState { + type Config = Option; + + fn init(world: &mut World, _system_state: &mut SystemState, _config: Self::Config) -> Self { + let event_subscriptions = world.get_resource::>().unwrap(); + let subscription_id = event_subscriptions.add_subscriber(); + Self((subscription_id, PhantomData::::default())) + } +} + +impl<'a, T: Component> SystemParamFetch<'a> for SubscriberIdState { + type Item = SubscriberId<'a, T>; + + #[inline] + unsafe fn get_param( + state: &'a mut Self, + _system_state: &'a SystemState, + _world: &'a World, + _change_tick: u32, + ) -> Self::Item { + SubscriberId(&mut state.0) + } +} + +struct UpdateSubscriberCount { + subscriber_id: usize, + new_count: usize, + phantom_data: PhantomData, +} + +impl Command for UpdateSubscriberCount { + fn write(self: Box, world: &mut World) { + let mut subscriptions = world.get_resource_mut::>().unwrap(); + subscriptions.set_subscriber_count(self.subscriber_id, self.new_count); + } +} + /// Reads events of type `T` in order and tracks which events have already been read. #[derive(SystemParam)] pub struct EventReader<'a, T: Component> { - subscription_id: Local<'a, (Option, PhantomData)>, - event_subscriptions: ResMut<'a, EventSubscriptions>, + commands: Commands<'a>, + subscriber_id: SubscriberId<'a, T>, + event_subscriptions: Res<'a, EventSubscriptions>, events: Res<'a, Events>, } @@ -234,29 +314,15 @@ impl<'a, T: Component> EventReader<'a, T> { self.iter_with_id().map(|(event, _id)| event) } - fn get_subscription_id( - subscription_id: &mut Option, - event_subscriptions: &mut EventSubscriptions, - event_count: usize, - ) -> usize { - *subscription_id.get_or_insert_with(|| { - event_subscriptions.last_event_counts.push(event_count); - event_subscriptions.last_event_counts.len() - 1 - }) - } - /// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events. pub fn iter_with_id(&mut self) -> impl DoubleEndedIterator)> { - let subscription_id = Self::get_subscription_id( - &mut self.subscription_id.0, - &mut *self.event_subscriptions, - self.events.event_offset, - ); - let mut last_event_count = self - .event_subscriptions - .last_event_counts - .get_mut(subscription_id) - .unwrap(); + let subscriber_id = self.subscriber_id.0 .0; + let mut last_event_count = self.event_subscriptions.get_subscriber_count(subscriber_id); + self.commands.add(UpdateSubscriberCount:: { + subscriber_id, + new_count: self.events.event_count, + phantom_data: Default::default(), + }); internal_event_reader(&mut last_event_count, &self.events).map(|(event, id)| { trace!("EventReader::iter() -> {}", id); (event, id) @@ -301,19 +367,18 @@ impl Events { /// Swaps the event buffers and clears the oldest event buffer. In general, this should be /// called once per frame/update. pub fn update(&mut self, event_subscriptions: &mut EventSubscriptions) { - if event_subscriptions.last_event_counts.is_empty() { - event_subscriptions.last_event_count = self.event_count; + if event_subscriptions.subscriber_last_counts.read().is_empty() { self.event_offset = self.event_count; self.buffer.clear(); } else { let read_count = event_subscriptions - .last_event_counts + .subscriber_last_counts + .read() .iter() .fold(usize::max_value(), |count, next| min(count, *next)); let remove_index = read_count - self.event_offset; self.event_offset = read_count; self.buffer.drain(0..remove_index); - event_subscriptions.last_event_count = self.event_count; } } @@ -363,6 +428,7 @@ impl EventSubscriptions {} #[cfg(test)] mod tests { use super::*; + use crate::App; use bevy_ecs::schedule::{Schedule, SystemStage}; use bevy_ecs::system::IntoSystem; use bevy_ecs::world::World; @@ -386,9 +452,10 @@ mod tests { } fn event_reader_system1(mut event_reader: EventReader) { for _event in event_reader.iter() { - // hi + println!("{}", _event.i) } } + let mut schedule = Schedule::default(); let update1 = SystemStage::single(event_writer_system1.system()); let update2 = SystemStage::single(event_reader_system1.system()); @@ -407,14 +474,14 @@ mod tests { schedule.run_once(&mut world); let events = world.get_resource::>().unwrap(); assert_eq!( - events.event_offset, 2, + events.event_offset, 0, "All subscribed systems read the first two events." ); schedule.run_once(&mut world); let events = world.get_resource::>().unwrap(); assert_eq!( - events.event_offset, 5, + events.event_offset, 0, "All subscribed systems read all events from last frame plus 2 new events from this frame" ); } From ede61533c9c6d0692dbbb3804c8f5ae2bbd92105 Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sun, 28 Mar 2021 14:19:05 -0300 Subject: [PATCH 03/10] Remove UpdateSubscriberCount command --- crates/bevy_app/src/event.rs | 55 ++++++++++++++---------------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index 7a0a85a3bcd77..5b0b028be4902 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -1,13 +1,13 @@ -use bevy_ecs::system::{Command, Commands, SystemParamFetch, SystemParamState, SystemState}; -use bevy_ecs::world::{FromWorld, World}; +use bevy_ecs::system::{SystemParamFetch, SystemParamState, SystemState}; +use bevy_ecs::world::World; use bevy_ecs::{ component::Component, - system::{Local, Res, ResMut, SystemParam}, + system::{Res, ResMut, SystemParam}, }; use bevy_utils::tracing::trace; -use parking_lot::{Mutex, RwLock}; +use parking_lot::RwLock; use std::cmp::min; -use std::ops::{Add, Deref, DerefMut}; +use std::ops::{Deref, DerefMut}; use std::{ fmt::{self}, hash::Hash, @@ -164,7 +164,7 @@ impl EventSubscriptions { self.subscriber_last_counts.read()[subscription_id] } - pub fn set_subscriber_count(&mut self, subscription_id: usize, count: usize) { + pub fn set_subscriber_count(&self, subscription_id: usize, count: usize) { self.subscriber_last_counts.write()[subscription_id] = count; } } @@ -217,23 +217,9 @@ impl<'a, T: Component> SystemParamFetch<'a> for SubscriberIdState { } } -struct UpdateSubscriberCount { - subscriber_id: usize, - new_count: usize, - phantom_data: PhantomData, -} - -impl Command for UpdateSubscriberCount { - fn write(self: Box, world: &mut World) { - let mut subscriptions = world.get_resource_mut::>().unwrap(); - subscriptions.set_subscriber_count(self.subscriber_id, self.new_count); - } -} - /// Reads events of type `T` in order and tracks which events have already been read. #[derive(SystemParam)] pub struct EventReader<'a, T: Component> { - commands: Commands<'a>, subscriber_id: SubscriberId<'a, T>, event_subscriptions: Res<'a, EventSubscriptions>, events: Res<'a, Events>, @@ -318,15 +304,14 @@ impl<'a, T: Component> EventReader<'a, T> { pub fn iter_with_id(&mut self) -> impl DoubleEndedIterator)> { let subscriber_id = self.subscriber_id.0 .0; let mut last_event_count = self.event_subscriptions.get_subscriber_count(subscriber_id); - self.commands.add(UpdateSubscriberCount:: { - subscriber_id, - new_count: self.events.event_count, - phantom_data: Default::default(), - }); - internal_event_reader(&mut last_event_count, &self.events).map(|(event, id)| { - trace!("EventReader::iter() -> {}", id); - (event, id) - }) + let result = + internal_event_reader(&mut last_event_count, &self.events).map(|(event, id)| { + trace!("EventReader::iter() -> {}", id); + (event, id) + }); + self.event_subscriptions + .set_subscriber_count(subscriber_id, last_event_count); + result } } @@ -428,7 +413,6 @@ impl EventSubscriptions {} #[cfg(test)] mod tests { use super::*; - use crate::App; use bevy_ecs::schedule::{Schedule, SystemStage}; use bevy_ecs::system::IntoSystem; use bevy_ecs::world::World; @@ -452,13 +436,16 @@ mod tests { } fn event_reader_system1(mut event_reader: EventReader) { for _event in event_reader.iter() { - println!("{}", _event.i) + // hi } } let mut schedule = Schedule::default(); let update1 = SystemStage::single(event_writer_system1.system()); - let update2 = SystemStage::single(event_reader_system1.system()); + let mut update2 = SystemStage::parallel(); + update2 + .add_system(event_reader_system1.system()) + .add_system(event_reader_system1.system()); let update3 = SystemStage::single(event_writer_system2.system()); let update4 = SystemStage::single(event_reader_system1.system()); let update5 = SystemStage::single(Events::::update_system.system()); @@ -474,14 +461,14 @@ mod tests { schedule.run_once(&mut world); let events = world.get_resource::>().unwrap(); assert_eq!( - events.event_offset, 0, + events.event_offset, 2, "All subscribed systems read the first two events." ); schedule.run_once(&mut world); let events = world.get_resource::>().unwrap(); assert_eq!( - events.event_offset, 0, + events.event_offset, 5, "All subscribed systems read all events from last frame plus 2 new events from this frame" ); } From fb20d4ec4c3424f673658bc4ca6bbf406a333c64 Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sun, 28 Mar 2021 14:29:35 -0300 Subject: [PATCH 04/10] Merge EventSubscriptions into Events --- crates/bevy_app/src/app_builder.rs | 3 +- crates/bevy_app/src/event.rs | 50 +++++++++--------------------- 2 files changed, 16 insertions(+), 37 deletions(-) diff --git a/crates/bevy_app/src/app_builder.rs b/crates/bevy_app/src/app_builder.rs index 3820cd5484006..c4626396f9465 100644 --- a/crates/bevy_app/src/app_builder.rs +++ b/crates/bevy_app/src/app_builder.rs @@ -2,7 +2,7 @@ use crate::{ app::{App, AppExit}, event::Events, plugin::Plugin, - CoreStage, EventSubscriptions, PluginGroup, PluginGroupBuilder, StartupStage, + CoreStage, PluginGroup, PluginGroupBuilder, StartupStage, }; use bevy_ecs::{ component::{Component, ComponentDescriptor}, @@ -228,7 +228,6 @@ impl AppBuilder { T: Component, { self.insert_resource(Events::::default()) - .insert_resource(EventSubscriptions::::default()) .add_system_to_stage(CoreStage::Last, Events::::update_system.system()) } diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index 5b0b028be4902..31f057816af87 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -117,6 +117,7 @@ struct EventInstance { #[derive(Debug)] pub struct Events { buffer: Vec>, + subscriber_last_counts: RwLock>, event_count: usize, event_offset: usize, } @@ -125,6 +126,7 @@ impl Default for Events { fn default() -> Self { Events { buffer: Vec::new(), + subscriber_last_counts: RwLock::default(), event_count: 0, event_offset: 0, } @@ -139,21 +141,7 @@ fn map_instance_event(event_instance: &EventInstance) -> &T { &event_instance.event } -pub struct EventSubscriptions { - subscriber_last_counts: RwLock>, - _phantom: PhantomData, -} - -impl Default for EventSubscriptions { - fn default() -> Self { - EventSubscriptions:: { - subscriber_last_counts: RwLock::default(), - _phantom: Default::default(), - } - } -} - -impl EventSubscriptions { +impl Events { pub fn add_subscriber(&self) -> usize { let id = self.subscriber_last_counts.read().len(); self.subscriber_last_counts.write().push(0); @@ -197,8 +185,8 @@ unsafe impl SystemParamState for SubscriberIdState { type Config = Option; fn init(world: &mut World, _system_state: &mut SystemState, _config: Self::Config) -> Self { - let event_subscriptions = world.get_resource::>().unwrap(); - let subscription_id = event_subscriptions.add_subscriber(); + let events = world.get_resource::>().unwrap(); + let subscription_id = events.add_subscriber(); Self((subscription_id, PhantomData::::default())) } } @@ -221,7 +209,6 @@ impl<'a, T: Component> SystemParamFetch<'a> for SubscriberIdState { #[derive(SystemParam)] pub struct EventReader<'a, T: Component> { subscriber_id: SubscriberId<'a, T>, - event_subscriptions: Res<'a, EventSubscriptions>, events: Res<'a, Events>, } @@ -303,13 +290,13 @@ impl<'a, T: Component> EventReader<'a, T> { /// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events. pub fn iter_with_id(&mut self) -> impl DoubleEndedIterator)> { let subscriber_id = self.subscriber_id.0 .0; - let mut last_event_count = self.event_subscriptions.get_subscriber_count(subscriber_id); + let mut last_event_count = self.events.get_subscriber_count(subscriber_id); let result = internal_event_reader(&mut last_event_count, &self.events).map(|(event, id)| { trace!("EventReader::iter() -> {}", id); (event, id) }); - self.event_subscriptions + self.events .set_subscriber_count(subscriber_id, last_event_count); result } @@ -351,12 +338,12 @@ impl Events { /// Swaps the event buffers and clears the oldest event buffer. In general, this should be /// called once per frame/update. - pub fn update(&mut self, event_subscriptions: &mut EventSubscriptions) { - if event_subscriptions.subscriber_last_counts.read().is_empty() { + pub fn update(&mut self) { + if self.subscriber_last_counts.read().is_empty() { self.event_offset = self.event_count; self.buffer.clear(); } else { - let read_count = event_subscriptions + let read_count = self .subscriber_last_counts .read() .iter() @@ -368,11 +355,8 @@ impl Events { } /// A system that calls [Events::update] once per frame. - pub fn update_system( - mut events: ResMut, - mut event_subscriptions: ResMut>, - ) { - events.update(&mut *event_subscriptions); + pub fn update_system(mut events: ResMut) { + events.update(); } /// Removes all events. @@ -408,8 +392,6 @@ impl Events { } } -impl EventSubscriptions {} - #[cfg(test)] mod tests { use super::*; @@ -457,7 +439,6 @@ mod tests { let mut world = World::default(); world.insert_resource(Events::::default()); - world.insert_resource(EventSubscriptions::::default()); schedule.run_once(&mut world); let events = world.get_resource::>().unwrap(); assert_eq!( @@ -476,7 +457,6 @@ mod tests { #[test] fn test_manual_events() { let mut events = Events::::default(); - let mut event_subscriptions = EventSubscriptions::::default(); let event_0 = TestEvent { i: 0 }; let event_1 = TestEvent { i: 1 }; let event_2 = TestEvent { i: 2 }; @@ -531,7 +511,7 @@ mod tests { "reader_a receives next unread event" ); - events.update(&mut event_subscriptions); + events.update(); let mut reader_d = events.get_reader(); @@ -558,7 +538,7 @@ mod tests { "reader_d receives all events created after update" ); - events.update(&mut event_subscriptions); + events.update(); assert_eq!( get_events(&mut events, &mut reader_slow), @@ -566,7 +546,7 @@ mod tests { "reader_slow misses all events" ); - events.update(&mut event_subscriptions); + events.update(); // At this point, the event buffer should be emptied and the count and offset // should be the same since all subscribed readers have read all the events. From b69b64a94624e2d56930261dcdf2f906b1b4fa28 Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sun, 28 Mar 2021 15:48:49 -0300 Subject: [PATCH 05/10] ManualEventReaders are now obtained from the Events * Each ManualEventReader tracks its subscription through the use of a string id * These will lock resources the same way that EventReaders do * If a ManualEventReader is made after events have been read by other readers, they will not see those events. --- crates/bevy_app/src/event.rs | 151 ++++++++++-------- crates/bevy_app/src/schedule_runner.rs | 135 ++++++++-------- crates/bevy_gilrs/src/gilrs_system.rs | 7 +- crates/bevy_render/src/render_graph/base.rs | 2 +- .../render_graph/nodes/texture_copy_node.rs | 14 +- .../nodes/window_swapchain_node.rs | 21 ++- .../render_graph/nodes/window_texture_node.rs | 16 +- crates/bevy_scene/src/scene_spawner.rs | 9 +- crates/bevy_sprite/src/color_material.rs | 8 +- crates/bevy_wgpu/src/wgpu_renderer.rs | 15 +- crates/bevy_winit/src/lib.rs | 18 +-- 11 files changed, 191 insertions(+), 205 deletions(-) diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index 31f057816af87..c4579d271f6e3 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -5,6 +5,7 @@ use bevy_ecs::{ system::{Res, ResMut, SystemParam}, }; use bevy_utils::tracing::trace; +use bevy_utils::HashMap; use parking_lot::RwLock; use std::cmp::min; use std::ops::{Deref, DerefMut}; @@ -118,6 +119,7 @@ struct EventInstance { pub struct Events { buffer: Vec>, subscriber_last_counts: RwLock>, + manual_subscriber_ids: RwLock>, event_count: usize, event_offset: usize, } @@ -127,6 +129,7 @@ impl Default for Events { Events { buffer: Vec::new(), subscriber_last_counts: RwLock::default(), + manual_subscriber_ids: Default::default(), event_count: 0, event_offset: 0, } @@ -141,21 +144,6 @@ fn map_instance_event(event_instance: &EventInstance) -> &T { &event_instance.event } -impl Events { - pub fn add_subscriber(&self) -> usize { - let id = self.subscriber_last_counts.read().len(); - self.subscriber_last_counts.write().push(0); - id - } - - pub fn get_subscriber_count(&self, subscription_id: usize) -> usize { - self.subscriber_last_counts.read()[subscription_id] - } - - pub fn set_subscriber_count(&self, subscription_id: usize, count: usize) { - self.subscriber_last_counts.write()[subscription_id] = count; - } -} pub struct SubscriberId<'a, T: Component>(&'a mut (usize, PhantomData)); impl<'a, T: Component> Deref for SubscriberId<'a, T> { @@ -229,31 +217,28 @@ impl<'a, T: Component> EventWriter<'a, T> { } pub struct ManualEventReader { - last_event_count: usize, + subscriber_id: usize, _marker: PhantomData, } -impl Default for ManualEventReader { - fn default() -> Self { - ManualEventReader { - last_event_count: 0, - _marker: Default::default(), - } - } -} - -impl ManualEventReader { +impl ManualEventReader { /// See [`EventReader::iter`] - pub fn iter<'a>(&mut self, events: &'a Events) -> impl DoubleEndedIterator { - internal_event_reader(&mut self.last_event_count, events).map(|(e, _)| e) + pub fn iter<'a>(&self, events: &'a Events) -> impl DoubleEndedIterator { + let mut last_event_count = events.get_subscriber_read_count(self.subscriber_id); + let result = internal_event_reader(&mut last_event_count, events).map(|(e, _)| e); + events.set_subscriber_read_count(self.subscriber_id, last_event_count); + result } /// See [`EventReader::iter_with_id`] pub fn iter_with_id<'a>( - &mut self, + &self, events: &'a Events, ) -> impl DoubleEndedIterator)> { - internal_event_reader(&mut self.last_event_count, events) + let mut last_event_count = events.get_subscriber_read_count(self.subscriber_id); + let result = internal_event_reader(&mut last_event_count, events); + events.set_subscriber_read_count(self.subscriber_id, last_event_count); + result } } @@ -290,14 +275,14 @@ impl<'a, T: Component> EventReader<'a, T> { /// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events. pub fn iter_with_id(&mut self) -> impl DoubleEndedIterator)> { let subscriber_id = self.subscriber_id.0 .0; - let mut last_event_count = self.events.get_subscriber_count(subscriber_id); + let mut last_event_count = self.events.get_subscriber_read_count(subscriber_id); let result = internal_event_reader(&mut last_event_count, &self.events).map(|(event, id)| { trace!("EventReader::iter() -> {}", id); (event, id) }); self.events - .set_subscriber_count(subscriber_id, last_event_count); + .set_subscriber_read_count(subscriber_id, last_event_count); result } } @@ -319,29 +304,44 @@ impl Events { self.event_count += 1; } - /// Gets a new [ManualEventReader]. This will include all events already in the event buffers. - pub fn get_reader(&mut self) -> ManualEventReader { - ManualEventReader { - last_event_count: 0, - _marker: PhantomData, - } + pub fn add_subscriber(&self) -> usize { + let mut subscriber_last_counts_write = self.subscriber_last_counts.write(); + let id = subscriber_last_counts_write.len(); + subscriber_last_counts_write.push(0); + id } - /// Gets a new [ManualEventReader]. This will ignore all events already in the event buffers. It - /// will read all future events. - pub fn get_reader_current(&mut self) -> ManualEventReader { + pub fn get_reader(&self, name: &str) -> ManualEventReader { + let manual_subscriber_ids_read = self.manual_subscriber_ids.read(); + let id = if let Some(id) = manual_subscriber_ids_read.get(name) { + *id + } else { + let id = self.add_subscriber(); + drop(manual_subscriber_ids_read); + self.manual_subscriber_ids + .write() + .insert(name.to_string(), id); + id + }; ManualEventReader { - last_event_count: self.event_count, - _marker: PhantomData, + subscriber_id: id, + _marker: Default::default(), } } + pub fn get_subscriber_read_count(&self, subscription_id: usize) -> usize { + self.subscriber_last_counts.read()[subscription_id] + } + + pub fn set_subscriber_read_count(&self, subscription_id: usize, count: usize) { + self.subscriber_last_counts.write()[subscription_id] = count; + } + /// Swaps the event buffers and clears the oldest event buffer. In general, this should be /// called once per frame/update. pub fn update(&mut self) { if self.subscriber_last_counts.read().is_empty() { - self.event_offset = self.event_count; - self.buffer.clear(); + // todo: what should happen here? } else { let read_count = self .subscriber_last_counts @@ -461,93 +461,106 @@ mod tests { let event_1 = TestEvent { i: 1 }; let event_2 = TestEvent { i: 2 }; - let mut reader_slow = events.get_reader(); - let mut reader_a = events.get_reader(); + let reader_slow = events.get_reader("slow"); + let reader_a = events.get_reader("a"); events.send(event_0); assert_eq!( - get_events(&mut events, &mut reader_a), + get_events(&mut events, &reader_a), vec![event_0], "reader_a created before event receives event" ); assert_eq!( - get_events(&mut events, &mut reader_a), + get_events(&mut events, &reader_a), vec![], "second iteration of reader_a created before event results in zero events" ); - let mut reader_b = events.get_reader(); + let reader_b = events.get_reader("b"); assert_eq!( - get_events(&mut events, &mut reader_b), + get_events(&mut events, &reader_b), vec![event_0], "reader_b created after event receives event" ); assert_eq!( - get_events(&mut events, &mut reader_b), + get_events(&mut events, &reader_b), vec![], "second iteration of reader_b created after event results in zero events" ); events.send(event_1); - let mut reader_c = events.get_reader(); + let reader_c = events.get_reader("c"); assert_eq!( - get_events(&mut events, &mut reader_c), + get_events(&mut events, &reader_c), vec![event_0, event_1], "reader_c created after two events receives both events" ); assert_eq!( - get_events(&mut events, &mut reader_c), + get_events(&mut events, &reader_c), vec![], "second iteration of reader_c created after two event results in zero events" ); assert_eq!( - get_events(&mut events, &mut reader_a), + get_events(&mut events, &reader_a), vec![event_1], "reader_a receives next unread event" ); events.update(); - let mut reader_d = events.get_reader(); + let reader_d = events.get_reader("d"); events.send(event_2); assert_eq!( - get_events(&mut events, &mut reader_a), + get_events(&mut events, &reader_a), vec![event_2], "reader_a receives event created after update" ); assert_eq!( - get_events(&mut events, &mut reader_b), - vec![event_2], - "reader_b receives events created after update" + get_events(&mut events, &reader_b), + vec![event_1, event_2], + "reader_b receives events sent since its last read" ); assert_eq!( - get_events(&mut events, &mut reader_c), + get_events(&mut events, &reader_c), vec![event_2], "reader_c receives event created since last fetch" ); assert_eq!( - get_events(&mut events, &mut reader_d), - vec![event_2], - "reader_d receives all events created after update" + get_events(&mut events, &reader_d), + vec![event_0, event_1, event_2], + "reader_d receives all events created so far because reader_slow is locking up the old events" ); events.update(); assert_eq!( - get_events(&mut events, &mut reader_slow), - vec![], - "reader_slow misses all events" + get_events(&mut events, &reader_slow), + vec![event_0, event_1, event_2], + "reader_slow receives all events" ); events.update(); + assert_eq!( + get_events(&mut events, &reader_slow), + vec![], + "reader slow has read all the events" + ); + + let slowest_reader = events.get_reader("slowest_reader"); + assert_eq!( + get_events(&mut events, &slowest_reader), + vec![], + "the events have all been read, so this reader is too late" + ); + // At this point, the event buffer should be emptied and the count and offset // should be the same since all subscribed readers have read all the events. assert_eq!( @@ -559,7 +572,7 @@ mod tests { fn get_events( events: &mut Events, - reader: &mut ManualEventReader, + reader: &ManualEventReader, ) -> Vec { reader.iter(events).cloned().collect::>() } diff --git a/crates/bevy_app/src/schedule_runner.rs b/crates/bevy_app/src/schedule_runner.rs index 86b6dd1299be8..a98b00ba73ab3 100644 --- a/crates/bevy_app/src/schedule_runner.rs +++ b/crates/bevy_app/src/schedule_runner.rs @@ -1,5 +1,5 @@ use super::{App, AppBuilder}; -use crate::{app::AppExit, event::Events, plugin::Plugin, ManualEventReader}; +use crate::{app::AppExit, event::Events, plugin::Plugin}; use bevy_utils::{Duration, Instant}; #[cfg(target_arch = "wasm32")] @@ -52,90 +52,83 @@ impl Plugin for ScheduleRunnerPlugin { .world_mut() .get_resource_or_insert_with(ScheduleRunnerSettings::default) .to_owned(); - app.set_runner(move |mut app: App| { - let mut app_exit_event_reader = ManualEventReader::::default(); - match settings.run_mode { - RunMode::Once => { - app.update(); - } - RunMode::Loop { wait } => { - let mut tick = move |app: &mut App, - wait: Option| - -> Result, AppExit> { - let start_time = Instant::now(); - - if let Some(app_exit_events) = - app.world.get_resource_mut::>() - { - if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last() - { - return Err(exit.clone()); - } + app.set_runner(move |mut app: App| match settings.run_mode { + RunMode::Once => { + app.update(); + } + RunMode::Loop { wait } => { + let tick = move |app: &mut App, + wait: Option| + -> Result, AppExit> { + let start_time = Instant::now(); + + if let Some(app_exit_events) = app.world.get_resource_mut::>() { + let app_exit_event_reader = app_exit_events.get_reader("app_runner"); + if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last() { + return Err(exit.clone()); } + } - app.update(); + app.update(); - if let Some(app_exit_events) = - app.world.get_resource_mut::>() - { - if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last() - { - return Err(exit.clone()); - } + if let Some(app_exit_events) = app.world.get_resource_mut::>() { + let app_exit_event_reader = app_exit_events.get_reader("app_runner"); + if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last() { + return Err(exit.clone()); } + } - let end_time = Instant::now(); + let end_time = Instant::now(); - if let Some(wait) = wait { - let exe_time = end_time - start_time; - if exe_time < wait { - return Ok(Some(wait - exe_time)); - } + if let Some(wait) = wait { + let exe_time = end_time - start_time; + if exe_time < wait { + return Ok(Some(wait - exe_time)); } + } - Ok(None) - }; + Ok(None) + }; - #[cfg(not(target_arch = "wasm32"))] - { - while let Ok(delay) = tick(&mut app, wait) { - if let Some(delay) = delay { - std::thread::sleep(delay); - } + #[cfg(not(target_arch = "wasm32"))] + { + while let Ok(delay) = tick(&mut app, wait) { + if let Some(delay) = delay { + std::thread::sleep(delay); } } + } - #[cfg(target_arch = "wasm32")] - { - fn set_timeout(f: &Closure, dur: Duration) { - web_sys::window() - .unwrap() - .set_timeout_with_callback_and_timeout_and_arguments_0( - f.as_ref().unchecked_ref(), - dur.as_millis() as i32, - ) - .expect("Should register `setTimeout`."); - } - let asap = Duration::from_millis(1); - - let mut rc = Rc::new(app); - let f = Rc::new(RefCell::new(None)); - let g = f.clone(); - - let c = move || { - let mut app = Rc::get_mut(&mut rc).unwrap(); - let delay = tick(&mut app, wait); - match delay { - Ok(delay) => { - set_timeout(f.borrow().as_ref().unwrap(), delay.unwrap_or(asap)) - } - Err(_) => {} + #[cfg(target_arch = "wasm32")] + { + fn set_timeout(f: &Closure, dur: Duration) { + web_sys::window() + .unwrap() + .set_timeout_with_callback_and_timeout_and_arguments_0( + f.as_ref().unchecked_ref(), + dur.as_millis() as i32, + ) + .expect("Should register `setTimeout`."); + } + let asap = Duration::from_millis(1); + + let mut rc = Rc::new(app); + let f = Rc::new(RefCell::new(None)); + let g = f.clone(); + + let c = move || { + let mut app = Rc::get_mut(&mut rc).unwrap(); + let delay = tick(&mut app, wait); + match delay { + Ok(delay) => { + set_timeout(f.borrow().as_ref().unwrap(), delay.unwrap_or(asap)) } - }; - *g.borrow_mut() = Some(Closure::wrap(Box::new(c) as Box)); - set_timeout(g.borrow().as_ref().unwrap(), asap); + Err(_) => {} + } }; - } + *g.borrow_mut() = Some(Closure::wrap(Box::new(c) as Box)); + set_timeout(g.borrow().as_ref().unwrap(), asap); + }; } }); } diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index ea1e0264b84e5..4f34370e91619 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -1,5 +1,5 @@ use crate::converter::{convert_axis, convert_button, convert_gamepad_id}; -use bevy_app::{EventSubscriptions, Events}; +use bevy_app::Events; use bevy_ecs::world::World; use bevy_input::{gamepad::GamepadEventRaw, prelude::*}; use gilrs::{EventType, Gilrs}; @@ -20,10 +20,7 @@ pub fn gilrs_event_system(world: &mut World) { let world = world.cell(); let mut gilrs = world.get_non_send_mut::().unwrap(); let mut event = world.get_resource_mut::>().unwrap(); - let mut event_subscriptions = world - .get_resource_mut::>() - .unwrap(); - event.update(&mut *event_subscriptions); + event.update(); while let Some(gilrs_event) = gilrs.next_event() { match gilrs_event.event { EventType::Connected => { diff --git a/crates/bevy_render/src/render_graph/base.rs b/crates/bevy_render/src/render_graph/base.rs index bf7f349aaf5ed..012b77f69cd06 100644 --- a/crates/bevy_render/src/render_graph/base.rs +++ b/crates/bevy_render/src/render_graph/base.rs @@ -100,7 +100,7 @@ pub(crate) fn add_base_graph(config: &BaseRenderGraphConfig, world: &mut World) let mut graph = world.get_resource_mut::().unwrap(); let msaa = world.get_resource::().unwrap(); - graph.add_node(node::TEXTURE_COPY, TextureCopyNode::default()); + graph.add_node(node::TEXTURE_COPY, TextureCopyNode::new("texture_copy")); if config.add_3d_camera { graph.add_system_node(node::CAMERA_3D, CameraNode::new(camera::CAMERA_3D)); } diff --git a/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs b/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs index ac7c72fe843a9..007c0891f695d 100644 --- a/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs @@ -3,14 +3,19 @@ use crate::{ renderer::{BufferInfo, BufferUsage, RenderContext}, texture::{Texture, TextureDescriptor, TEXTURE_ASSET_INDEX}, }; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_asset::{AssetEvent, Assets}; use bevy_ecs::world::World; use bevy_utils::HashSet; -#[derive(Default)] pub struct TextureCopyNode { - pub texture_event_reader: ManualEventReader>, + pub name: &'static str, +} + +impl TextureCopyNode { + pub fn new(name: &'static str) -> Self { + TextureCopyNode { name } + } } impl Node for TextureCopyNode { @@ -24,7 +29,8 @@ impl Node for TextureCopyNode { let texture_events = world.get_resource::>>().unwrap(); let textures = world.get_resource::>().unwrap(); let mut copied_textures = HashSet::default(); - for event in self.texture_event_reader.iter(&texture_events) { + let texture_event_reader = texture_events.get_reader(self.name); + for event in texture_event_reader.iter(&texture_events) { match event { AssetEvent::Created { handle } | AssetEvent::Modified { handle } => { if let Some(texture) = textures.get(handle) { diff --git a/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs b/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs index 959f39b4a14a3..e1a2bbc017d8b 100644 --- a/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs @@ -2,26 +2,20 @@ use crate::{ render_graph::{Node, ResourceSlotInfo, ResourceSlots}, renderer::{RenderContext, RenderResourceId, RenderResourceType}, }; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_ecs::world::World; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; use std::borrow::Cow; pub struct WindowSwapChainNode { window_id: WindowId, - window_created_event_reader: ManualEventReader, - window_resized_event_reader: ManualEventReader, } impl WindowSwapChainNode { pub const OUT_TEXTURE: &'static str = "texture"; pub fn new(window_id: WindowId) -> Self { - WindowSwapChainNode { - window_id, - window_created_event_reader: Default::default(), - window_resized_event_reader: Default::default(), - } + WindowSwapChainNode { window_id } } } @@ -44,6 +38,11 @@ impl Node for WindowSwapChainNode { const WINDOW_TEXTURE: usize = 0; let window_created_events = world.get_resource::>().unwrap(); let window_resized_events = world.get_resource::>().unwrap(); + let window_created_event_reader = window_created_events + .get_reader(format!("swapchain_window_{}", self.window_id).as_str()); + let window_resized_event_reader = window_resized_events + .get_reader(format!("swapchain_window_{}", self.window_id).as_str()); + let windows = world.get_resource::().unwrap(); let window = windows @@ -53,12 +52,10 @@ impl Node for WindowSwapChainNode { let render_resource_context = render_context.resources_mut(); // create window swapchain when window is resized or created - if self - .window_created_event_reader + if window_created_event_reader .iter(&window_created_events) .any(|e| e.id == window.id()) - || self - .window_resized_event_reader + || window_resized_event_reader .iter(&window_resized_events) .any(|e| e.id == window.id()) { diff --git a/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs b/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs index 8bec3b0888f29..18ef2b02cbe9a 100644 --- a/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs @@ -3,7 +3,7 @@ use crate::{ renderer::{RenderContext, RenderResourceId, RenderResourceType}, texture::TextureDescriptor, }; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_ecs::world::World; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; use std::borrow::Cow; @@ -11,8 +11,6 @@ use std::borrow::Cow; pub struct WindowTextureNode { window_id: WindowId, descriptor: TextureDescriptor, - window_created_event_reader: ManualEventReader, - window_resized_event_reader: ManualEventReader, } impl WindowTextureNode { @@ -22,8 +20,6 @@ impl WindowTextureNode { WindowTextureNode { window_id, descriptor, - window_created_event_reader: Default::default(), - window_resized_event_reader: Default::default(), } } } @@ -47,18 +43,20 @@ impl Node for WindowTextureNode { const WINDOW_TEXTURE: usize = 0; let window_created_events = world.get_resource::>().unwrap(); let window_resized_events = world.get_resource::>().unwrap(); + let window_created_event_reader = + window_created_events.get_reader(format!("texture_window_{}", self.window_id).as_str()); + let window_resized_event_reader = + window_resized_events.get_reader(format!("texture_window_{}", self.window_id).as_str()); let windows = world.get_resource::().unwrap(); let window = windows .get(self.window_id) .expect("Window texture node refers to a non-existent window."); - if self - .window_created_event_reader + if window_created_event_reader .iter(&window_created_events) .any(|e| e.id == window.id()) - || self - .window_resized_event_reader + || window_resized_event_reader .iter(&window_resized_events) .any(|e| e.id == window.id()) { diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 71fd41aabf638..ff04845a06b6f 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -1,5 +1,5 @@ use crate::{DynamicScene, Scene}; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_ecs::{ entity::{Entity, EntityMap}, @@ -31,7 +31,6 @@ pub struct SceneSpawner { spawned_scenes: HashMap, Vec>, spawned_dynamic_scenes: HashMap, Vec>, spawned_instances: HashMap, - scene_asset_event_reader: ManualEventReader>, dynamic_scenes_to_spawn: Vec>, scenes_to_spawn: Vec<(Handle, InstanceId)>, scenes_to_despawn: Vec>, @@ -303,10 +302,8 @@ pub fn scene_spawner_system(world: &mut World) { .unwrap(); let mut updated_spawned_scenes = Vec::new(); - for event in scene_spawner - .scene_asset_event_reader - .iter(&scene_asset_events) - { + let scene_asset_event_reader = scene_asset_events.get_reader("scene_spawner_system"); + for event in scene_asset_event_reader.iter(&scene_asset_events) { if let AssetEvent::Modified { handle } = event { if scene_spawner.spawned_dynamic_scenes.contains_key(handle) { updated_spawned_scenes.push(handle.clone_weak()); diff --git a/crates/bevy_sprite/src/color_material.rs b/crates/bevy_sprite/src/color_material.rs index 61c70954b832e..a2a518a1428a6 100644 --- a/crates/bevy_sprite/src/color_material.rs +++ b/crates/bevy_sprite/src/color_material.rs @@ -1,4 +1,4 @@ -use bevy_app::{EventReader, Events, ManualEventReader}; +use bevy_app::{EventReader, Events}; use bevy_asset::{self, AssetEvent, Assets, Handle}; use bevy_ecs::system::{Local, Res, ResMut}; use bevy_reflect::TypeUuid; @@ -64,11 +64,9 @@ pub(crate) fn material_texture_detection_system( mut material_to_texture: Local, Handle>>, materials: Res>, mut texture_events: EventReader>, - (mut material_events_reader, mut material_events): ( - Local>>, - ResMut>>, - ), + mut material_events: ResMut>>, ) { + let material_events_reader = material_events.get_reader("material_texture_detection"); for event in material_events_reader.iter(&material_events) { match event { AssetEvent::Created { handle } => { diff --git a/crates/bevy_wgpu/src/wgpu_renderer.rs b/crates/bevy_wgpu/src/wgpu_renderer.rs index cdd5e3cf0f5e0..5552c504ddd2f 100644 --- a/crates/bevy_wgpu/src/wgpu_renderer.rs +++ b/crates/bevy_wgpu/src/wgpu_renderer.rs @@ -3,21 +3,19 @@ use crate::{ wgpu_type_converter::WgpuInto, WgpuBackend, WgpuOptions, WgpuPowerOptions, }; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_ecs::world::{Mut, World}; use bevy_render::{ render_graph::{DependentNodeStager, RenderGraph, RenderGraphStager}, renderer::RenderResourceContext, }; -use bevy_window::{WindowCreated, WindowResized, Windows}; +use bevy_window::{WindowCreated, Windows}; use std::{ops::Deref, sync::Arc}; pub struct WgpuRenderer { pub instance: wgpu::Instance, pub device: Arc, pub queue: wgpu::Queue, - pub window_resized_event_reader: ManualEventReader, - pub window_created_event_reader: ManualEventReader, pub initialized: bool, } @@ -67,8 +65,6 @@ impl WgpuRenderer { instance, device, queue, - window_resized_event_reader: Default::default(), - window_created_event_reader: Default::default(), initialized: false, } } @@ -83,10 +79,9 @@ impl WgpuRenderer { .unwrap(); let windows = world.get_resource::().unwrap(); let window_created_events = world.get_resource::>().unwrap(); - for window_created_event in self - .window_created_event_reader - .iter(&window_created_events) - { + let window_created_event_reader = + window_created_events.get_reader("renderer_window_created"); + for window_created_event in window_created_event_reader.iter(&window_created_events) { let window = windows .get(window_created_event.id) .expect("Received window created event for non-existent window."); diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 978009f4e4b77..6d6d79487c8b3 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -10,7 +10,7 @@ use bevy_input::{ pub use winit_config::*; pub use winit_windows::*; -use bevy_app::{App, AppBuilder, AppExit, CoreStage, Events, ManualEventReader, Plugin}; +use bevy_app::{App, AppBuilder, AppExit, CoreStage, Events, Plugin}; use bevy_ecs::{system::IntoExclusiveSystem, world::World}; use bevy_math::{ivec2, Vec2}; use bevy_utils::tracing::{error, trace, warn}; @@ -223,8 +223,6 @@ pub fn winit_runner_any_thread(app: App) { } pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { - let mut create_window_event_reader = ManualEventReader::::default(); - let mut app_exit_event_reader = ManualEventReader::::default(); app.world.insert_non_send(event_loop.create_proxy()); trace!("Entering winit event loop"); @@ -240,6 +238,7 @@ pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { *control_flow = ControlFlow::Poll; if let Some(app_exit_events) = app.world.get_resource_mut::>() { + let app_exit_event_reader = app_exit_events.get_reader("winit_runner"); if app_exit_event_reader .iter(&app_exit_events) .next_back() @@ -477,11 +476,7 @@ pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { }); } event::Event::MainEventsCleared => { - handle_create_window_events( - &mut app.world, - event_loop, - &mut create_window_event_reader, - ); + handle_create_window_events(&mut app.world, event_loop); app.update(); } _ => (), @@ -494,16 +489,13 @@ pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { } } -fn handle_create_window_events( - world: &mut World, - event_loop: &EventLoopWindowTarget<()>, - create_window_event_reader: &mut ManualEventReader, -) { +fn handle_create_window_events(world: &mut World, event_loop: &EventLoopWindowTarget<()>) { let world = world.cell(); let mut winit_windows = world.get_resource_mut::().unwrap(); let mut windows = world.get_resource_mut::().unwrap(); let create_window_events = world.get_resource::>().unwrap(); let mut window_created_events = world.get_resource_mut::>().unwrap(); + let create_window_event_reader = create_window_events.get_reader("create_window_events"); for create_window_event in create_window_event_reader.iter(&create_window_events) { let window = winit_windows.create_window( event_loop, From 401edd5564eee2b66fdad7cd890802312b88a755 Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sun, 28 Mar 2021 16:33:02 -0300 Subject: [PATCH 06/10] Change ManualEventReader to match EventReader implementation * EventReader can now just use ManualEventReader for its own implementation --- crates/bevy_app/src/event.rs | 110 +++++++++--------- crates/bevy_app/src/schedule_runner.rs | 4 +- .../render_graph/nodes/texture_copy_node.rs | 2 +- .../nodes/window_swapchain_node.rs | 4 +- .../render_graph/nodes/window_texture_node.rs | 4 +- crates/bevy_scene/src/scene_spawner.rs | 2 +- crates/bevy_sprite/src/color_material.rs | 2 +- crates/bevy_wgpu/src/wgpu_renderer.rs | 2 +- crates/bevy_winit/src/lib.rs | 8 +- 9 files changed, 65 insertions(+), 73 deletions(-) diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index c4579d271f6e3..2db25cc106ba5 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -84,7 +84,7 @@ struct EventInstance { /// /// // setup /// let mut events = Events::::default(); -/// let mut reader = events.get_reader(); +/// let reader = events.get_reader("unique_id"); /// /// // run this once per update/frame /// events.update(); @@ -216,28 +216,27 @@ impl<'a, T: Component> EventWriter<'a, T> { } } -pub struct ManualEventReader { +pub struct ManualEventReader<'a, T> { subscriber_id: usize, - _marker: PhantomData, + events: &'a Events, } -impl ManualEventReader { +impl<'a, T: Component> ManualEventReader<'a, T> { /// See [`EventReader::iter`] - pub fn iter<'a>(&self, events: &'a Events) -> impl DoubleEndedIterator { - let mut last_event_count = events.get_subscriber_read_count(self.subscriber_id); - let result = internal_event_reader(&mut last_event_count, events).map(|(e, _)| e); - events.set_subscriber_read_count(self.subscriber_id, last_event_count); + pub fn iter(&self) -> impl DoubleEndedIterator { + let mut last_event_count = self.events.get_subscriber_read_count(self.subscriber_id); + let result = internal_event_reader(&mut last_event_count, self.events).map(|(e, _)| e); + self.events + .set_subscriber_read_count(self.subscriber_id, last_event_count); result } /// See [`EventReader::iter_with_id`] - pub fn iter_with_id<'a>( - &self, - events: &'a Events, - ) -> impl DoubleEndedIterator)> { - let mut last_event_count = events.get_subscriber_read_count(self.subscriber_id); - let result = internal_event_reader(&mut last_event_count, events); - events.set_subscriber_read_count(self.subscriber_id, last_event_count); + pub fn iter_with_id(&self) -> impl DoubleEndedIterator)> { + let mut last_event_count = self.events.get_subscriber_read_count(self.subscriber_id); + let result = internal_event_reader(&mut last_event_count, self.events); + self.events + .set_subscriber_read_count(self.subscriber_id, last_event_count); result } } @@ -275,15 +274,11 @@ impl<'a, T: Component> EventReader<'a, T> { /// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events. pub fn iter_with_id(&mut self) -> impl DoubleEndedIterator)> { let subscriber_id = self.subscriber_id.0 .0; - let mut last_event_count = self.events.get_subscriber_read_count(subscriber_id); - let result = - internal_event_reader(&mut last_event_count, &self.events).map(|(event, id)| { - trace!("EventReader::iter() -> {}", id); - (event, id) - }); - self.events - .set_subscriber_read_count(subscriber_id, last_event_count); - result + let manual_reader = ManualEventReader { + subscriber_id, + events: &*self.events, + }; + manual_reader.iter_with_id() } } @@ -311,6 +306,14 @@ impl Events { id } + pub fn get_subscriber_read_count(&self, subscription_id: usize) -> usize { + self.subscriber_last_counts.read()[subscription_id] + } + + pub fn set_subscriber_read_count(&self, subscription_id: usize, count: usize) { + self.subscriber_last_counts.write()[subscription_id] = count; + } + pub fn get_reader(&self, name: &str) -> ManualEventReader { let manual_subscriber_ids_read = self.manual_subscriber_ids.read(); let id = if let Some(id) = manual_subscriber_ids_read.get(name) { @@ -325,18 +328,10 @@ impl Events { }; ManualEventReader { subscriber_id: id, - _marker: Default::default(), + events: self, } } - pub fn get_subscriber_read_count(&self, subscription_id: usize) -> usize { - self.subscriber_last_counts.read()[subscription_id] - } - - pub fn set_subscriber_read_count(&self, subscription_id: usize, count: usize) { - self.subscriber_last_counts.write()[subscription_id] = count; - } - /// Swaps the event buffers and clears the oldest event buffer. In general, this should be /// called once per frame/update. pub fn update(&mut self) { @@ -461,18 +456,17 @@ mod tests { let event_1 = TestEvent { i: 1 }; let event_2 = TestEvent { i: 2 }; - let reader_slow = events.get_reader("slow"); - let reader_a = events.get_reader("a"); - events.send(event_0); + let _reader_slow = events.get_reader("slow"); + let reader_a = events.get_reader("a"); assert_eq!( - get_events(&mut events, &reader_a), + get_events(&reader_a), vec![event_0], "reader_a created before event receives event" ); assert_eq!( - get_events(&mut events, &reader_a), + get_events(&reader_a), vec![], "second iteration of reader_a created before event results in zero events" ); @@ -480,83 +474,88 @@ mod tests { let reader_b = events.get_reader("b"); assert_eq!( - get_events(&mut events, &reader_b), + get_events(&reader_b), vec![event_0], "reader_b created after event receives event" ); assert_eq!( - get_events(&mut events, &reader_b), + get_events(&reader_b), vec![], "second iteration of reader_b created after event results in zero events" ); events.send(event_1); + let reader_a = events.get_reader("a"); let reader_c = events.get_reader("c"); assert_eq!( - get_events(&mut events, &reader_c), + get_events(&reader_c), vec![event_0, event_1], "reader_c created after two events receives both events" ); assert_eq!( - get_events(&mut events, &reader_c), + get_events(&reader_c), vec![], "second iteration of reader_c created after two event results in zero events" ); assert_eq!( - get_events(&mut events, &reader_a), + get_events(&reader_a), vec![event_1], "reader_a receives next unread event" ); events.update(); - let reader_d = events.get_reader("d"); - events.send(event_2); + let reader_a = events.get_reader("a"); + let reader_b = events.get_reader("b"); + let reader_c = events.get_reader("c"); + let reader_d = events.get_reader("d"); assert_eq!( - get_events(&mut events, &reader_a), + get_events(&reader_a), vec![event_2], "reader_a receives event created after update" ); assert_eq!( - get_events(&mut events, &reader_b), + get_events(&reader_b), vec![event_1, event_2], "reader_b receives events sent since its last read" ); assert_eq!( - get_events(&mut events, &reader_c), + get_events(&reader_c), vec![event_2], "reader_c receives event created since last fetch" ); assert_eq!( - get_events(&mut events, &reader_d), + get_events(&reader_d), vec![event_0, event_1, event_2], "reader_d receives all events created so far because reader_slow is locking up the old events" ); events.update(); + let reader_slow = events.get_reader("slow"); assert_eq!( - get_events(&mut events, &reader_slow), + get_events(&reader_slow), vec![event_0, event_1, event_2], "reader_slow receives all events" ); events.update(); + let reader_slow = events.get_reader("slow"); assert_eq!( - get_events(&mut events, &reader_slow), + get_events(&reader_slow), vec![], "reader slow has read all the events" ); let slowest_reader = events.get_reader("slowest_reader"); assert_eq!( - get_events(&mut events, &slowest_reader), + get_events(&slowest_reader), vec![], "the events have all been read, so this reader is too late" ); @@ -570,10 +569,7 @@ mod tests { assert_eq!(events.buffer.is_empty(), true, "event buffer is empty"); } - fn get_events( - events: &mut Events, - reader: &ManualEventReader, - ) -> Vec { - reader.iter(events).cloned().collect::>() + fn get_events(reader: &ManualEventReader) -> Vec { + reader.iter().cloned().collect::>() } } diff --git a/crates/bevy_app/src/schedule_runner.rs b/crates/bevy_app/src/schedule_runner.rs index a98b00ba73ab3..ba5244900da91 100644 --- a/crates/bevy_app/src/schedule_runner.rs +++ b/crates/bevy_app/src/schedule_runner.rs @@ -64,7 +64,7 @@ impl Plugin for ScheduleRunnerPlugin { if let Some(app_exit_events) = app.world.get_resource_mut::>() { let app_exit_event_reader = app_exit_events.get_reader("app_runner"); - if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last() { + if let Some(exit) = app_exit_event_reader.iter().last() { return Err(exit.clone()); } } @@ -73,7 +73,7 @@ impl Plugin for ScheduleRunnerPlugin { if let Some(app_exit_events) = app.world.get_resource_mut::>() { let app_exit_event_reader = app_exit_events.get_reader("app_runner"); - if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last() { + if let Some(exit) = app_exit_event_reader.iter().last() { return Err(exit.clone()); } } diff --git a/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs b/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs index 007c0891f695d..726e9e4ef1aa2 100644 --- a/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs @@ -30,7 +30,7 @@ impl Node for TextureCopyNode { let textures = world.get_resource::>().unwrap(); let mut copied_textures = HashSet::default(); let texture_event_reader = texture_events.get_reader(self.name); - for event in texture_event_reader.iter(&texture_events) { + for event in texture_event_reader.iter() { match event { AssetEvent::Created { handle } | AssetEvent::Modified { handle } => { if let Some(texture) = textures.get(handle) { diff --git a/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs b/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs index e1a2bbc017d8b..3f8fa422e6daf 100644 --- a/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs @@ -53,10 +53,10 @@ impl Node for WindowSwapChainNode { // create window swapchain when window is resized or created if window_created_event_reader - .iter(&window_created_events) + .iter() .any(|e| e.id == window.id()) || window_resized_event_reader - .iter(&window_resized_events) + .iter() .any(|e| e.id == window.id()) { render_resource_context.create_swap_chain(window); diff --git a/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs b/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs index 18ef2b02cbe9a..611978aafbfaa 100644 --- a/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs @@ -54,10 +54,10 @@ impl Node for WindowTextureNode { .expect("Window texture node refers to a non-existent window."); if window_created_event_reader - .iter(&window_created_events) + .iter() .any(|e| e.id == window.id()) || window_resized_event_reader - .iter(&window_resized_events) + .iter() .any(|e| e.id == window.id()) { let render_resource_context = render_context.resources_mut(); diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index ff04845a06b6f..47e5dc928f171 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -303,7 +303,7 @@ pub fn scene_spawner_system(world: &mut World) { let mut updated_spawned_scenes = Vec::new(); let scene_asset_event_reader = scene_asset_events.get_reader("scene_spawner_system"); - for event in scene_asset_event_reader.iter(&scene_asset_events) { + for event in scene_asset_event_reader.iter() { if let AssetEvent::Modified { handle } = event { if scene_spawner.spawned_dynamic_scenes.contains_key(handle) { updated_spawned_scenes.push(handle.clone_weak()); diff --git a/crates/bevy_sprite/src/color_material.rs b/crates/bevy_sprite/src/color_material.rs index a2a518a1428a6..0c71d53803d77 100644 --- a/crates/bevy_sprite/src/color_material.rs +++ b/crates/bevy_sprite/src/color_material.rs @@ -67,7 +67,7 @@ pub(crate) fn material_texture_detection_system( mut material_events: ResMut>>, ) { let material_events_reader = material_events.get_reader("material_texture_detection"); - for event in material_events_reader.iter(&material_events) { + for event in material_events_reader.iter() { match event { AssetEvent::Created { handle } => { if let Some(texture) = materials.get(handle).and_then(|mat| mat.texture.as_ref()) { diff --git a/crates/bevy_wgpu/src/wgpu_renderer.rs b/crates/bevy_wgpu/src/wgpu_renderer.rs index 5552c504ddd2f..6e58b2e95ede7 100644 --- a/crates/bevy_wgpu/src/wgpu_renderer.rs +++ b/crates/bevy_wgpu/src/wgpu_renderer.rs @@ -81,7 +81,7 @@ impl WgpuRenderer { let window_created_events = world.get_resource::>().unwrap(); let window_created_event_reader = window_created_events.get_reader("renderer_window_created"); - for window_created_event in window_created_event_reader.iter(&window_created_events) { + for window_created_event in window_created_event_reader.iter() { let window = windows .get(window_created_event.id) .expect("Received window created event for non-existent window."); diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 6d6d79487c8b3..a96844bc6be54 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -239,11 +239,7 @@ pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { if let Some(app_exit_events) = app.world.get_resource_mut::>() { let app_exit_event_reader = app_exit_events.get_reader("winit_runner"); - if app_exit_event_reader - .iter(&app_exit_events) - .next_back() - .is_some() - { + if app_exit_event_reader.iter().next_back().is_some() { *control_flow = ControlFlow::Exit; } } @@ -496,7 +492,7 @@ fn handle_create_window_events(world: &mut World, event_loop: &EventLoopWindowTa let create_window_events = world.get_resource::>().unwrap(); let mut window_created_events = world.get_resource_mut::>().unwrap(); let create_window_event_reader = create_window_events.get_reader("create_window_events"); - for create_window_event in create_window_event_reader.iter(&create_window_events) { + for create_window_event in create_window_event_reader.iter() { let window = winit_windows.create_window( event_loop, create_window_event.id, From a5ef02df33a7ee79bd9f4ff4e33b175b966313d2 Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sun, 28 Mar 2021 16:43:51 -0300 Subject: [PATCH 07/10] Some comment changes --- crates/bevy_app/src/event.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index 2db25cc106ba5..606418cb9bc23 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -93,12 +93,12 @@ struct EventInstance { /// events.send(MyEvent { value: 1 }); /// /// // somewhere else: read the events -/// for event in reader.iter(&events) { +/// for event in reader.iter() { /// assert_eq!(event.value, 1) /// } /// /// // events are only processed once per reader -/// assert_eq!(reader.iter(&events).count(), 0); +/// assert_eq!(reader.iter().count(), 0); /// ``` /// /// # Details @@ -457,6 +457,7 @@ mod tests { let event_2 = TestEvent { i: 2 }; events.send(event_0); + // _reader_slow sets up the subscription, even though it won't be used till later. let _reader_slow = events.get_reader("slow"); let reader_a = events.get_reader("a"); From 2e3917596e45bb82fd9fa4a3cc6ca7a5c44ef60e Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sun, 28 Mar 2021 18:00:34 -0300 Subject: [PATCH 08/10] Manual event deferral example / test --- crates/bevy_app/src/event.rs | 41 +++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index 606418cb9bc23..e4ed21ccad577 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -391,7 +391,7 @@ impl Events { mod tests { use super::*; use bevy_ecs::schedule::{Schedule, SystemStage}; - use bevy_ecs::system::IntoSystem; + use bevy_ecs::system::{IntoSystem, Local}; use bevy_ecs::world::World; #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -570,6 +570,45 @@ mod tests { assert_eq!(events.buffer.is_empty(), true, "event buffer is empty"); } + #[test] + fn event_deferral() { + fn event_writer_system(mut event_writer: EventWriter) { + let event = TestEvent { i: 2 }; + event_writer.send(event); + } + fn event_reader_system( + mut event_reader: EventReader, + mut deferred_events: Local>, + mut event_reads: ResMut, + ) { + *event_reads = 0; + let mut defer = Vec::new(); + for event in event_reader.iter().chain(deferred_events.iter()) { + *event_reads = *event_reads + 1; + defer.push(*event); + } + std::mem::swap(&mut defer, &mut *deferred_events); + } + let mut schedule = Schedule::default(); + let update1 = SystemStage::single(event_writer_system.system()); + let update2 = SystemStage::single(event_reader_system.system()); + schedule.add_stage("update1", update1); + schedule.add_stage("update2", update2); + + let mut world = World::default(); + world.insert_resource(Events::::default()); + world.insert_resource(0usize); + schedule.run_once(&mut world); + let event_reads = world.get_resource::().unwrap(); + assert_eq!(*event_reads, 1usize, "Only one event was fired."); + schedule.run_once(&mut world); + let event_reads = world.get_resource::().unwrap(); + assert_eq!( + *event_reads, 2usize, + "One new event was fired, and one was deferred from last time." + ); + } + fn get_events(reader: &ManualEventReader) -> Vec { reader.iter().cloned().collect::>() } From 9cb4b5f564a50ef0ba9730d3cc948541e87f0a5e Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sun, 28 Mar 2021 18:15:28 -0300 Subject: [PATCH 09/10] clippy thing --- crates/bevy_app/src/event.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index e4ed21ccad577..95ac4e5ef3646 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -584,7 +584,7 @@ mod tests { *event_reads = 0; let mut defer = Vec::new(); for event in event_reader.iter().chain(deferred_events.iter()) { - *event_reads = *event_reads + 1; + *event_reads += 1; defer.push(*event); } std::mem::swap(&mut defer, &mut *deferred_events); From 53f881028156d4c4e865538a024df26d1f161c81 Mon Sep 17 00:00:00 2001 From: James Higgins Date: Sun, 28 Mar 2021 18:18:50 -0300 Subject: [PATCH 10/10] Remove unnecessary swap --- crates/bevy_app/src/event.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index 95ac4e5ef3646..788ea3fd0f43b 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -587,7 +587,7 @@ mod tests { *event_reads += 1; defer.push(*event); } - std::mem::swap(&mut defer, &mut *deferred_events); + *deferred_events = defer; } let mut schedule = Schedule::default(); let update1 = SystemStage::single(event_writer_system.system());