From 89cbc78d3dcbaca9b962a6d8f805c8d37efd1eac Mon Sep 17 00:00:00 2001 From: CatThingy <32040424+CatThingy@users.noreply.github.com> Date: Tue, 6 Jun 2023 07:44:32 -0700 Subject: [PATCH] Require `#[derive(Event)]` on all Events (#7086) # Objective Be consistent with `Resource`s and `Components` and have `Event` types be more self-documenting. Although not susceptible to accidentally using a function instead of a value due to `Event`s only being initialized by their type, much of the same reasoning for removing the blanket impl on `Resource` also applies here. * Not immediately obvious if a type is intended to be an event * Prevent invisible conflicts if the same third-party or primitive types are used as events * Allows for further extensions (e.g. opt-in warning for missed events) ## Solution Remove the blanket impl for the `Event` trait. Add a derive macro for it. --- ## Changelog - `Event` is no longer implemented for all applicable types. Add the `#[derive(Event)]` macro for events. ## Migration Guide * Add the `#[derive(Event)]` macro for events. Third-party types used as events should be wrapped in a newtype. --- benches/benches/bevy_ecs/events/iter.rs | 7 ++-- benches/benches/bevy_ecs/events/send.rs | 18 +++++++--- crates/bevy_a11y/src/lib.rs | 6 +++- crates/bevy_app/src/app.rs | 3 +- crates/bevy_asset/src/assets.rs | 1 + crates/bevy_ecs/README.md | 1 + crates/bevy_ecs/examples/events.rs | 1 + crates/bevy_ecs/macros/src/component.rs | 18 ++++++++++ crates/bevy_ecs/macros/src/lib.rs | 5 +++ crates/bevy_ecs/src/event.rs | 16 +++++---- crates/bevy_ecs/src/removal_detection.rs | 6 ++-- crates/bevy_ecs/src/schedule/condition.rs | 7 +++- crates/bevy_ecs/src/system/function_system.rs | 2 ++ crates/bevy_ecs/src/system/system_param.rs | 1 + crates/bevy_hierarchy/src/events.rs | 4 +-- crates/bevy_input/src/gamepad.rs | 12 +++---- crates/bevy_input/src/keyboard.rs | 8 +++-- crates/bevy_input/src/mouse.rs | 12 ++++--- crates/bevy_input/src/touch.rs | 4 +-- crates/bevy_window/src/event.rs | 33 ++++++++++--------- crates/bevy_winit/src/accessibility.rs | 10 ++++-- .../external_source_external_thread.rs | 2 ++ examples/ecs/event.rs | 3 +- examples/games/breakout.rs | 2 +- examples/ui/size_constraints.rs | 1 + tests/how_to_test_systems.rs | 1 + 26 files changed, 130 insertions(+), 54 deletions(-) diff --git a/benches/benches/bevy_ecs/events/iter.rs b/benches/benches/bevy_ecs/events/iter.rs index 64684f5c734bf..4c5ed5375fa84 100644 --- a/benches/benches/bevy_ecs/events/iter.rs +++ b/benches/benches/bevy_ecs/events/iter.rs @@ -1,13 +1,16 @@ use bevy_ecs::prelude::*; -pub struct Benchmark(Events<[u8; SIZE]>); +#[derive(Event)] +struct BenchEvent([u8; SIZE]); + +pub struct Benchmark(Events>); impl Benchmark { pub fn new(count: usize) -> Self { let mut events = Events::default(); for _ in 0..count { - events.send([0u8; SIZE]); + events.send(BenchEvent([0u8; SIZE])); } Self(events) diff --git a/benches/benches/bevy_ecs/events/send.rs b/benches/benches/bevy_ecs/events/send.rs index ca816ab086685..2c81583d74ca1 100644 --- a/benches/benches/bevy_ecs/events/send.rs +++ b/benches/benches/bevy_ecs/events/send.rs @@ -1,18 +1,27 @@ use bevy_ecs::prelude::*; +#[derive(Event)] +struct BenchEvent([u8; SIZE]); + +impl Default for BenchEvent { + fn default() -> Self { + BenchEvent([0; SIZE]) + } +} + pub struct Benchmark { - events: Events<[u8; SIZE]>, + events: Events>, count: usize, } impl Benchmark { pub fn new(count: usize) -> Self { let mut events = Events::default(); - + // Force both internal buffers to be allocated. for _ in 0..2 { for _ in 0..count { - events.send([0u8; SIZE]); + events.send(BenchEvent([0u8; SIZE])); } events.update(); } @@ -22,7 +31,8 @@ impl Benchmark { pub fn run(&mut self) { for _ in 0..self.count { - self.events.send(std::hint::black_box([0u8; SIZE])); + self.events + .send(std::hint::black_box(BenchEvent([0u8; SIZE]))); } self.events.update(); } diff --git a/crates/bevy_a11y/src/lib.rs b/crates/bevy_a11y/src/lib.rs index 16808c17da258..ed86377e3ca2c 100644 --- a/crates/bevy_a11y/src/lib.rs +++ b/crates/bevy_a11y/src/lib.rs @@ -14,10 +14,14 @@ use accesskit::{NodeBuilder, NodeId}; use bevy_app::Plugin; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ - prelude::{Component, Entity}, + prelude::{Component, Entity, Event}, system::Resource, }; +/// Wrapper struct for [`accesskit::ActionRequest`]. Required to allow it to be used as an `Event`. +#[derive(Event, Deref, DerefMut)] +pub struct ActionRequest(pub accesskit::ActionRequest); + /// Resource that tracks whether an assistive technology has requested /// accessibility information. /// diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 4a2c1eb58dc69..b8805df49f3a5 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -522,6 +522,7 @@ impl App { /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # + /// # #[derive(Event)] /// # struct MyEvent; /// # let mut app = App::new(); /// # @@ -976,7 +977,7 @@ fn run_once(mut app: App) { /// If you don't require access to other components or resources, consider implementing the [`Drop`] /// trait on components/resources for code that runs on exit. That saves you from worrying about /// system schedule ordering, and is idiomatic Rust. -#[derive(Debug, Clone, Default)] +#[derive(Event, Debug, Clone, Default)] pub struct AppExit; #[cfg(test)] diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 7b4d488ca98a3..d1c166ee0d381 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -13,6 +13,7 @@ use std::fmt::Debug; /// /// Events sent via the [`Assets`] struct will always be sent with a _Weak_ handle, because the /// asset may not exist by the time the event is handled. +#[derive(Event)] pub enum AssetEvent { #[allow(missing_docs)] Created { handle: Handle }, diff --git a/crates/bevy_ecs/README.md b/crates/bevy_ecs/README.md index 457f386e89fa4..6bdee54c71b5d 100644 --- a/crates/bevy_ecs/README.md +++ b/crates/bevy_ecs/README.md @@ -286,6 +286,7 @@ Events offer a communication channel between one or more systems. Events can be ```rust use bevy_ecs::prelude::*; +#[derive(Event)] struct MyEvent { message: String, } diff --git a/crates/bevy_ecs/examples/events.rs b/crates/bevy_ecs/examples/events.rs index 27bd13b5f6f2e..637b0a2a81b5b 100644 --- a/crates/bevy_ecs/examples/events.rs +++ b/crates/bevy_ecs/examples/events.rs @@ -32,6 +32,7 @@ fn main() { } // This is our event that we will send and receive in systems +#[derive(Event)] struct MyEvent { pub message: String, pub random_value: f32, diff --git a/crates/bevy_ecs/macros/src/component.rs b/crates/bevy_ecs/macros/src/component.rs index d1e3a1e351432..65d26a0bf0102 100644 --- a/crates/bevy_ecs/macros/src/component.rs +++ b/crates/bevy_ecs/macros/src/component.rs @@ -3,6 +3,24 @@ use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; use syn::{parse_macro_input, parse_quote, DeriveInput, Ident, LitStr, Path, Result}; +pub fn derive_event(input: TokenStream) -> TokenStream { + let mut ast = parse_macro_input!(input as DeriveInput); + let bevy_ecs_path: Path = crate::bevy_ecs_path(); + + ast.generics + .make_where_clause() + .predicates + .push(parse_quote! { Self: Send + Sync + 'static }); + + let struct_name = &ast.ident; + let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl(); + + TokenStream::from(quote! { + impl #impl_generics #bevy_ecs_path::event::Event for #struct_name #type_generics #where_clause { + } + }) +} + pub fn derive_resource(input: TokenStream) -> TokenStream { let mut ast = parse_macro_input!(input as DeriveInput); let bevy_ecs_path: Path = crate::bevy_ecs_path(); diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 8be707bda63dd..110df68260981 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -452,6 +452,11 @@ pub(crate) fn bevy_ecs_path() -> syn::Path { BevyManifest::default().get_path("bevy_ecs") } +#[proc_macro_derive(Event)] +pub fn derive_event(input: TokenStream) -> TokenStream { + component::derive_event(input) +} + #[proc_macro_derive(Resource)] pub fn derive_resource(input: TokenStream) -> TokenStream { component::derive_resource(input) diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index 3be628eb08e2b..51365c8cb7c28 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -2,6 +2,7 @@ use crate as bevy_ecs; use crate::system::{Local, Res, ResMut, Resource, SystemParam}; +pub use bevy_ecs_macros::Event; use bevy_utils::detailed_trace; use std::ops::{Deref, DerefMut}; use std::{ @@ -17,7 +18,6 @@ use std::{ /// /// Events must be thread-safe. pub trait Event: Send + Sync + 'static {} -impl Event for T where T: Send + Sync + 'static {} /// An `EventId` uniquely identifies an event. /// @@ -109,8 +109,9 @@ struct EventInstance { /// /// # Example /// ``` -/// use bevy_ecs::event::Events; +/// use bevy_ecs::event::{Event, Events}; /// +/// #[derive(Event)] /// struct MyEvent { /// value: usize /// } @@ -248,6 +249,8 @@ impl<'w, 's, E: Event> EventReader<'w, 's, E> { /// /// ``` /// # use bevy_ecs::prelude::*; + /// # + /// #[derive(Event)] /// struct CollisionEvent; /// /// fn play_collision_sound(mut events: EventReader) { @@ -289,6 +292,7 @@ impl<'a, 'w, 's, E: Event> IntoIterator for &'a mut EventReader<'w, 's, E> { /// ``` /// # use bevy_ecs::prelude::*; /// +/// #[derive(Event)] /// pub struct MyEvent; // Custom event type. /// fn my_system(mut writer: EventWriter) { /// writer.send(MyEvent); @@ -305,7 +309,7 @@ impl<'a, 'w, 's, E: Event> IntoIterator for &'a mut EventReader<'w, 's, E> { /// /// ``` /// # use bevy_ecs::{prelude::*, event::Events}; -/// +/// # #[derive(Event)] /// # pub struct MyEvent; /// fn send_untyped(mut commands: Commands) { /// // Send an event of a specific type without having to declare that @@ -699,7 +703,7 @@ mod tests { use super::*; - #[derive(Copy, Clone, PartialEq, Eq, Debug)] + #[derive(Event, Copy, Clone, PartialEq, Eq, Debug)] struct TestEvent { i: usize, } @@ -802,7 +806,7 @@ mod tests { reader.iter(events).cloned().collect::>() } - #[derive(PartialEq, Eq, Debug)] + #[derive(Event, PartialEq, Eq, Debug)] struct E(usize); fn events_clear_and_read_impl(clear_func: impl FnOnce(&mut Events)) { @@ -1009,7 +1013,7 @@ mod tests { assert!(last.is_none(), "EventReader should be empty"); } - #[derive(Clone, PartialEq, Debug, Default)] + #[derive(Event, Clone, PartialEq, Debug, Default)] struct EmptyTestEvent; #[test] diff --git a/crates/bevy_ecs/src/removal_detection.rs b/crates/bevy_ecs/src/removal_detection.rs index f2c91d97ddfe6..0619752b89e95 100644 --- a/crates/bevy_ecs/src/removal_detection.rs +++ b/crates/bevy_ecs/src/removal_detection.rs @@ -4,7 +4,9 @@ use crate::{ self as bevy_ecs, component::{Component, ComponentId, ComponentIdFor, Tick}, entity::Entity, - event::{EventId, Events, ManualEventIterator, ManualEventIteratorWithId, ManualEventReader}, + event::{ + Event, EventId, Events, ManualEventIterator, ManualEventIteratorWithId, ManualEventReader, + }, prelude::Local, storage::SparseSet, system::{ReadOnlySystemParam, SystemMeta, SystemParam}, @@ -21,7 +23,7 @@ use std::{ /// Wrapper around [`Entity`] for [`RemovedComponents`]. /// Internally, `RemovedComponents` uses these as an `Events`. -#[derive(Debug, Clone)] +#[derive(Event, Debug, Clone)] pub struct RemovedComponentEntity(Entity); impl From for Entity { diff --git a/crates/bevy_ecs/src/schedule/condition.rs b/crates/bevy_ecs/src/schedule/condition.rs index 6b1d747e2773c..8ff15f116b98a 100644 --- a/crates/bevy_ecs/src/schedule/condition.rs +++ b/crates/bevy_ecs/src/schedule/condition.rs @@ -876,6 +876,7 @@ pub mod common_conditions { /// my_system.run_if(on_event::()), /// ); /// + /// #[derive(Event)] /// struct MyEvent; /// /// fn my_system(mut counter: ResMut) { @@ -1133,6 +1134,7 @@ mod tests { use crate::schedule::{common_conditions::not, State, States}; use crate::system::Local; use crate::{change_detection::ResMut, schedule::Schedule, world::World}; + use bevy_ecs_macros::Event; use bevy_ecs_macros::Resource; #[derive(Resource, Default)] @@ -1239,6 +1241,9 @@ mod tests { #[derive(Component)] struct TestComponent; + #[derive(Event)] + struct TestEvent; + fn test_system() {} // Ensure distributive_run_if compiles with the common conditions. @@ -1256,7 +1261,7 @@ mod tests { .distributive_run_if(state_exists::()) .distributive_run_if(in_state(TestState::A)) .distributive_run_if(state_changed::()) - .distributive_run_if(on_event::()) + .distributive_run_if(on_event::()) .distributive_run_if(any_with_component::()) .distributive_run_if(not(run_once())), ); diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 391ba99699584..376a407e7f4b9 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -85,6 +85,7 @@ impl SystemMeta { /// # use bevy_ecs::system::SystemState; /// # use bevy_ecs::event::Events; /// # +/// # #[derive(Event)] /// # struct MyEvent; /// # #[derive(Resource)] /// # struct MyResource(u32); @@ -117,6 +118,7 @@ impl SystemMeta { /// # use bevy_ecs::system::SystemState; /// # use bevy_ecs::event::Events; /// # +/// # #[derive(Event)] /// # struct MyEvent; /// #[derive(Resource)] /// struct CachedSystemState { diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 5800c5780ccca..41e541ee66512 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -308,6 +308,7 @@ fn assert_component_access_compatibility( /// ``` /// # use bevy_ecs::prelude::*; /// # +/// # #[derive(Event)] /// # struct MyEvent; /// # impl MyEvent { /// # pub fn new() -> Self { Self } diff --git a/crates/bevy_hierarchy/src/events.rs b/crates/bevy_hierarchy/src/events.rs index f68c2a0788a7d..8c8263cecfe74 100644 --- a/crates/bevy_hierarchy/src/events.rs +++ b/crates/bevy_hierarchy/src/events.rs @@ -1,9 +1,9 @@ -use bevy_ecs::prelude::Entity; +use bevy_ecs::{event::Event, prelude::Entity}; /// An [`Event`] that is fired whenever there is a change in the world's hierarchy. /// /// [`Event`]: bevy_ecs::event::Event -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Event, Debug, Clone, PartialEq, Eq)] pub enum HierarchyEvent { /// Fired whenever an [`Entity`] is added as a child to a parent. ChildAdded { diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index e08464a4b7871..00801d4e28acf 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1,5 +1,5 @@ use crate::{Axis, Input}; -use bevy_ecs::event::{EventReader, EventWriter}; +use bevy_ecs::event::{Event, EventReader, EventWriter}; use bevy_ecs::{ change_detection::DetectChangesMut, system::{Res, ResMut, Resource}, @@ -1039,7 +1039,7 @@ pub enum GamepadConnection { /// A Gamepad connection event. Created when a connection to a gamepad /// is established and when a gamepad is disconnected. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -1070,7 +1070,7 @@ impl GamepadConnectionEvent { } } -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -1095,7 +1095,7 @@ impl GamepadAxisChangedEvent { /// Gamepad event for when the "value" (amount of pressure) on the button /// changes by an amount larger than the threshold defined in [`GamepadSettings`]. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -1158,7 +1158,7 @@ pub fn gamepad_button_event_system( /// This event type is used over the [`GamepadConnectionEvent`], /// [`GamepadButtonChangedEvent`] and [`GamepadAxisChangedEvent`] when /// the in-frame relative ordering of events is important. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -1330,7 +1330,7 @@ impl GamepadRumbleIntensity { #[doc(alias = "force feedback")] #[doc(alias = "vibration")] #[doc(alias = "vibrate")] -#[derive(Clone)] +#[derive(Event, Clone)] pub enum GamepadRumbleRequest { /// Add a rumble to the given gamepad. /// diff --git a/crates/bevy_input/src/keyboard.rs b/crates/bevy_input/src/keyboard.rs index a792bc0f4b4df..cc14bac968689 100644 --- a/crates/bevy_input/src/keyboard.rs +++ b/crates/bevy_input/src/keyboard.rs @@ -1,5 +1,9 @@ use crate::{ButtonState, Input}; -use bevy_ecs::{change_detection::DetectChangesMut, event::EventReader, system::ResMut}; +use bevy_ecs::{ + change_detection::DetectChangesMut, + event::{Event, EventReader}, + system::ResMut, +}; use bevy_reflect::{FromReflect, Reflect}; #[cfg(feature = "serialize")] @@ -14,7 +18,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; /// /// The event is consumed inside of the [`keyboard_input_system`](crate::keyboard::keyboard_input_system) /// to update the [`Input`](crate::Input) resource. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", diff --git a/crates/bevy_input/src/mouse.rs b/crates/bevy_input/src/mouse.rs index 9fbac1ce937ff..5cc81cdcd9faf 100644 --- a/crates/bevy_input/src/mouse.rs +++ b/crates/bevy_input/src/mouse.rs @@ -1,5 +1,9 @@ use crate::{ButtonState, Input}; -use bevy_ecs::{change_detection::DetectChangesMut, event::EventReader, system::ResMut}; +use bevy_ecs::{ + change_detection::DetectChangesMut, + event::{Event, EventReader}, + system::ResMut, +}; use bevy_math::Vec2; use bevy_reflect::{FromReflect, Reflect}; @@ -14,7 +18,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; /// /// The event is read inside of the [`mouse_button_input_system`](crate::mouse::mouse_button_input_system) /// to update the [`Input`](crate::Input) resource. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -65,7 +69,7 @@ pub enum MouseButton { /// However, the event data does not make it possible to distinguish which device it is referring to. /// /// [`DeviceEvent::MouseMotion`]: https://docs.rs/winit/latest/winit/event/enum.DeviceEvent.html#variant.MouseMotion -#[derive(Debug, Clone, Copy, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -106,7 +110,7 @@ pub enum MouseScrollUnit { /// A mouse wheel event. /// /// This event is the translated version of the `WindowEvent::MouseWheel` from the `winit` crate. -#[derive(Debug, Clone, Copy, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", diff --git a/crates/bevy_input/src/touch.rs b/crates/bevy_input/src/touch.rs index 991a7b229c836..e06a3a2e4845a 100644 --- a/crates/bevy_input/src/touch.rs +++ b/crates/bevy_input/src/touch.rs @@ -1,4 +1,4 @@ -use bevy_ecs::event::EventReader; +use bevy_ecs::event::{Event, EventReader}; use bevy_ecs::system::{ResMut, Resource}; use bevy_math::Vec2; use bevy_reflect::{FromReflect, Reflect}; @@ -30,7 +30,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; /// /// This event is the translated version of the `WindowEvent::Touch` from the `winit` crate. /// It is available to the end user and can be used for game logic. -#[derive(Debug, Clone, Copy, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", diff --git a/crates/bevy_window/src/event.rs b/crates/bevy_window/src/event.rs index a1e4a4bda5565..94f8be6b60712 100644 --- a/crates/bevy_window/src/event.rs +++ b/crates/bevy_window/src/event.rs @@ -1,6 +1,7 @@ use std::path::PathBuf; use bevy_ecs::entity::Entity; +use bevy_ecs::event::Event; use bevy_math::{IVec2, Vec2}; use bevy_reflect::{FromReflect, Reflect}; @@ -10,7 +11,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; use crate::WindowTheme; /// A window event that is sent whenever a window's logical size has changed. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -28,7 +29,7 @@ pub struct WindowResized { /// An event that indicates all of the application's windows should be redrawn, /// even if their control flow is set to `Wait` and there have been no window events. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -40,7 +41,7 @@ pub struct RequestRedraw; /// An event that is sent whenever a new window is created. /// /// To create a new window, spawn an entity with a [`crate::Window`] on it. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -62,7 +63,7 @@ pub struct WindowCreated { /// /// [`WindowPlugin`]: crate::WindowPlugin /// [`Window`]: crate::Window -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -76,7 +77,7 @@ pub struct WindowCloseRequested { /// An event that is sent whenever a window is closed. This will be sent when /// the window entity loses its [`Window`](crate::window::Window) component or is despawned. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -99,7 +100,7 @@ pub struct WindowClosed { /// /// [`WindowEvent::CursorMoved`]: https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.CursorMoved /// [`MouseMotion`]: bevy_input::mouse::MouseMotion -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -114,7 +115,7 @@ pub struct CursorMoved { } /// An event that is sent whenever the user's cursor enters a window. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -127,7 +128,7 @@ pub struct CursorEntered { } /// An event that is sent whenever the user's cursor leaves a window. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -140,7 +141,7 @@ pub struct CursorLeft { } /// An event that is sent whenever a window receives a character from the OS or underlying system. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -159,7 +160,7 @@ pub struct ReceivedCharacter { /// This event is the translated version of the `WindowEvent::Ime` from the `winit` crate. /// /// It is only sent if IME was enabled on the window with [`Window::ime_enabled`](crate::window::Window::ime_enabled). -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -201,7 +202,7 @@ pub enum Ime { } /// An event that indicates a window has received or lost focus. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -216,7 +217,7 @@ pub struct WindowFocused { } /// An event that indicates a window's scale factor has changed. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -231,7 +232,7 @@ pub struct WindowScaleFactorChanged { } /// An event that indicates a window's OS-reported scale factor has changed. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -246,7 +247,7 @@ pub struct WindowBackendScaleFactorChanged { } /// Events related to files being dragged and dropped on a window. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -278,7 +279,7 @@ pub enum FileDragAndDrop { } /// An event that is sent when a window is repositioned in physical pixels. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -296,7 +297,7 @@ pub struct WindowMoved { /// /// This event is only sent when the window is relying on the system theme to control its appearance. /// i.e. It is only sent when [`Window::window_theme`](crate::window::Window::window_theme) is `None` and the system theme changes. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", diff --git a/crates/bevy_winit/src/accessibility.rs b/crates/bevy_winit/src/accessibility.rs index 592ef77951342..49e7a0f11c65b 100644 --- a/crates/bevy_winit/src/accessibility.rs +++ b/crates/bevy_winit/src/accessibility.rs @@ -6,6 +6,7 @@ use std::{ }; use accesskit_winit::Adapter; +use bevy_a11y::ActionRequest as ActionRequestWrapper; use bevy_a11y::{ accesskit::{ActionHandler, ActionRequest, NodeBuilder, NodeClassSet, Role, TreeUpdate}, AccessKitEntityExt, AccessibilityNode, AccessibilityRequested, Focus, @@ -73,11 +74,14 @@ fn window_closed( } } -fn poll_receivers(handlers: Res, mut actions: EventWriter) { +fn poll_receivers( + handlers: Res, + mut actions: EventWriter, +) { for (_id, handler) in handlers.iter() { let mut handler = handler.lock().unwrap(); while let Some(event) = handler.pop_front() { - actions.send(event); + actions.send(ActionRequestWrapper(event)); } } } @@ -164,7 +168,7 @@ impl Plugin for AccessibilityPlugin { fn build(&self, app: &mut App) { app.init_non_send_resource::() .init_resource::() - .add_event::() + .add_event::() .add_systems( PostUpdate, ( diff --git a/examples/async_tasks/external_source_external_thread.rs b/examples/async_tasks/external_source_external_thread.rs index 57a403ef2957d..68811310edacb 100644 --- a/examples/async_tasks/external_source_external_thread.rs +++ b/examples/async_tasks/external_source_external_thread.rs @@ -17,6 +17,8 @@ fn main() { #[derive(Resource, Deref)] struct StreamReceiver(Receiver); + +#[derive(Event)] struct StreamEvent(u32); fn setup(mut commands: Commands) { diff --git a/examples/ecs/event.rs b/examples/ecs/event.rs index 39e3468b8c288..8f7d68d5b0feb 100644 --- a/examples/ecs/event.rs +++ b/examples/ecs/event.rs @@ -13,11 +13,12 @@ fn main() { .run(); } +#[derive(Event)] struct MyEvent { pub message: String, } -#[derive(Default)] +#[derive(Event, Default)] struct PlaySound; #[derive(Resource)] diff --git a/examples/games/breakout.rs b/examples/games/breakout.rs index 577b5fe68197d..a1db60dab67ec 100644 --- a/examples/games/breakout.rs +++ b/examples/games/breakout.rs @@ -84,7 +84,7 @@ struct Velocity(Vec2); #[derive(Component)] struct Collider; -#[derive(Default)] +#[derive(Event, Default)] struct CollisionEvent; #[derive(Component)] diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index 24ae9eb98ccfb..562a892bd93c1 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -35,6 +35,7 @@ enum Constraint { #[derive(Copy, Clone, Component)] struct ButtonValue(Val); +#[derive(Event)] struct ButtonActivatedEvent(Entity); fn setup(mut commands: Commands, asset_server: Res) { diff --git a/tests/how_to_test_systems.rs b/tests/how_to_test_systems.rs index 3f983696969c1..192aff7cd2f39 100644 --- a/tests/how_to_test_systems.rs +++ b/tests/how_to_test_systems.rs @@ -6,6 +6,7 @@ struct Enemy { score_value: u32, } +#[derive(Event)] struct EnemyDied(u32); #[derive(Resource)]