diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index ebdd2ee0df54a..7906f206987c7 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1,7 +1,7 @@ use crate::{CoreStage, Plugin, PluginGroup, PluginGroupBuilder, StartupSchedule, StartupStage}; pub use bevy_derive::AppLabel; use bevy_ecs::{ - event::{Event, Events}, + event::{self, Event, Events}, prelude::{FromWorld, IntoExclusiveSystem}, schedule::{ IntoSystemDescriptor, Schedule, ShouldRun, Stage, StageLabel, State, StateData, SystemSet, @@ -620,6 +620,7 @@ impl App { /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// # + /// # #[derive(Event)] /// # struct MyEvent; /// # let mut app = App::new(); /// # @@ -627,11 +628,81 @@ impl App { /// ``` pub fn add_event(&mut self) -> &mut Self where - T: Event, + T: Event + event::Read + event::Write, + { + self.add_event_with_vis::() + } + + /// Setup the application to manage read-only events of type `T`. + /// See [`add_event`](#method.add_event) for more info. + /// + /// # Examples + /// + /// ``` + /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; + /// # + /// pub struct MyEvent; + /// + /// // Anyone can read `MyEvent` + /// impl bevy_ecs::event::Read for MyEvent {} + /// + /// // You can only write `MyEvent` if you have access `PrivateKey` + /// struct PrivateKey; + /// impl bevy_ecs::event::Write for MyEvent {} + /// + /// let mut app = App::new(); + /// app.add_read_only_event::(); + /// // this also works: + /// app.add_read_only_event::(); + /// ``` + pub fn add_read_only_event(&mut self) -> &mut Self + where + T: Event + event::Read + event::Write, + { + self.add_event_with_vis::() + } + + /// Setup the application to manage write-only events of type `T`. + /// See [`add_event`](#method.add_event) for more info. + /// + /// # Examples + /// + /// ``` + /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; + /// # + /// pub struct MyEvent; + /// + /// // Anyone can write `MyEvent` + /// impl bevy_ecs::event::Write for MyEvent {} + /// + /// // You can only read `MyEvent` if you have access `PrivateKey` + /// struct PrivateKey; + /// impl bevy_ecs::event::Read for MyEvent {} + /// + /// let mut app = App::new(); + /// app.add_write_only_event::(); + /// // this also works: + /// app.add_write_only_event::(); + /// ``` + pub fn add_write_only_event(&mut self) -> &mut Self + where + T: Event + event::Read + event::Write, + { + self.add_event_with_vis::() + } + + /// Like [`add_event`](#method.add_event), but supports events with restricted privacy. + /// When not in a generic context, consider [`add_read_only_event`](#method.add_read_only_event) + /// or [`add_write_only_event`](#method.add_write_only_event). + pub fn add_event_with_vis(&mut self) -> &mut Self + where + T: Event + event::Read + event::Write, { if !self.world.contains_resource::>() { self.init_resource::>() - .add_system_to_stage(CoreStage::First, Events::::update_system); + .add_system_to_stage(CoreStage::First, Events::::update_system::); } self } @@ -987,5 +1058,5 @@ fn run_once(mut app: App) { /// You can also use this event to detect that an exit was requested. In order to receive it, systems /// subscribing to this event should run after it was emitted and before the schedule of the same /// frame is over. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, Event)] pub struct AppExit; diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 9ba30143dc964..b410119379cf2 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -4,7 +4,7 @@ use crate::{ }; use bevy_app::App; use bevy_ecs::{ - event::{EventWriter, Events}, + event::{Event, EventWriter, Events}, system::ResMut, world::FromWorld, }; @@ -16,6 +16,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 7c8f8f0f300ee..a1008f14db76f 100644 --- a/crates/bevy_ecs/README.md +++ b/crates/bevy_ecs/README.md @@ -287,6 +287,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 acf66282e26dd..58b583e8faebc 100644 --- a/crates/bevy_ecs/examples/events.rs +++ b/crates/bevy_ecs/examples/events.rs @@ -35,6 +35,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/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 68023e315ddb0..0e42e4e195199 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -173,6 +173,25 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream { }) } +#[proc_macro_derive(Event, attributes(event))] +pub fn derive_event(input: TokenStream) -> TokenStream { + let path = bevy_ecs_path(); + + let input = parse_macro_input!(input as DeriveInput); + let ident = input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause { + where_token: Default::default(), + predicates: Default::default(), + }); + + quote! { + impl #impl_generics #path::event::Read for #ident #ty_generics #where_clause { } + impl #impl_generics #path::event::Write for #ident #ty_generics #where_clause { } + } + .into() +} + fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec { (0..count) .map(|i| Ident::new(&fmt_string(i), Span::call_site())) diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index 9a5a9a41863eb..c1836680e92b1 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -17,6 +17,8 @@ use std::{ pub trait Event: Send + Sync + 'static {} impl Event for T where T: Send + Sync + 'static {} +pub use bevy_ecs_macros::Event; + /// An `EventId` uniquely identifies an event. /// /// An `EventId` can among other things be used to trace the flow of an event from the point it was @@ -82,8 +84,9 @@ struct EventInstance { /// /// # Example /// ``` -/// use bevy_ecs::event::Events; +/// use bevy_ecs::prelude::*; /// +/// #[derive(Event)] /// struct MyEvent { /// value: usize /// } @@ -179,14 +182,32 @@ impl DerefMut for EventSequence { } } +/// Trait which allows an event type to be used with [`EventReader`]. +/// Type parameter `Vis` is a marker that restricts the visibility of `EvnetReader`. +pub trait Read {} + /// Reads events of type `T` in order and tracks which events have already been read. +/// +/// # Privacy +/// For an event type `E`, access to `EventReader` can be restricted through the `impl` of [`Read`] for `E`. +/// For more info, see the docs for [`EventWriter`], which uses the same pattern for privacy. #[derive(SystemParam)] -pub struct EventReader<'w, 's, E: Event> { - reader: Local<'s, ManualEventReader>, +pub struct EventReader<'w, 's, E, Vis = ()> +where + E: Read + Event, + Vis: 'static, +{ + reader: Local<'s, ManualEventReader>, events: Res<'w, Events>, + #[system_param(ignore)] + _marker: PhantomData Vis>, } -impl<'w, 's, E: Event> EventReader<'w, 's, E> { +impl<'w, 's, E, Vis> EventReader<'w, 's, E, Vis> +where + E: Read + Event, + Vis: 'static, +{ /// Iterates over the events this [`EventReader`] has not seen yet. This updates the /// [`EventReader`]'s event counter, which means subsequent event reads will not include events /// that happened before now. @@ -221,6 +242,7 @@ impl<'w, 's, E: Event> EventReader<'w, 's, E> { /// ``` /// # use bevy_ecs::prelude::*; /// # + /// #[derive(Event)] /// struct CollisionEvent; /// /// fn play_collision_sound(events: EventReader) { @@ -248,6 +270,13 @@ impl<'w, 's, E: Event> EventReader<'w, 's, E> { } } +/// Trait which allows an event type to be used with [`EventWriter`]. +/// Type parameter `Vis` is a marker that restricts the visibility of `EventWriter`. +/// +/// # Examples +/// Restricting visibility +pub trait Write {} + /// Sends events of type `T`. /// /// # Usage @@ -256,7 +285,9 @@ impl<'w, 's, E: Event> 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); /// } @@ -264,6 +295,53 @@ impl<'w, 's, E: Event> EventReader<'w, 's, E> { /// # bevy_ecs::system::assert_is_system(my_system); /// ``` /// +/// # Privacy +/// +/// For an event type `E`, access to `EventWriter` can be restricted through the `impl` of [`Write`] for `E`. +/// +/// ``` +/// mod inner { +/// # use bevy_ecs::event::{EventWriter}; +/// struct Private; +/// +/// #[derive(Default)] +/// pub struct MyEvent; +/// +/// // Can only send events if you can name the type `Private`. +/// // Here, that means only within the module `inner`. +/// impl bevy_ecs::event::Write for MyEvent {} +/// // No restrictions on where you can send events. +/// impl bevy_ecs::event::Read for MyEvent {} +/// +/// // the type `Private` is like a key that unlocks the `EventReader`. +/// fn inner_system(mut writer: EventWriter) { +/// writer.send_default(); +/// } +/// } +/// ``` +/// ```compile_fail +/// # use bevy_ecs::prelude::*; +/// # mod inner { +/// # struct Private; +/// # pub struct MyEvent; +/// # impl bevy_ecs::event::Write for MyEvent {} +/// # } +/// +/// // This doesn't compile, can't name `Private` outside of its module. +/// fn outer_system(mut writer: EventWriter) {} +/// ``` +/// ```compile_fail +/// # use bevy_ecs::prelude::*; +/// # mod inner { +/// # struct Private; +/// # pub struct MyEvent; +/// # impl bevy_ecs::event::Write for MyEvent {} +/// # } +/// +/// // ...and this doesn't compile either. +/// fn outer_system2(mut writer: EventWriter) {} +/// ``` +/// /// # Limitations /// /// `EventWriter` can only send events of one specific type, which must be known at compile-time. @@ -272,7 +350,7 @@ impl<'w, 's, E: Event> 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 @@ -292,13 +370,23 @@ impl<'w, 's, E: Event> EventReader<'w, 's, E> { /// ``` /// Note that this is considered *non-idiomatic*, and should only be used when `EventWriter` will not work. #[derive(SystemParam)] -pub struct EventWriter<'w, 's, E: Event> { +pub struct EventWriter<'w, 's, E, Vis = ()> +where + E: Write + Event, + Vis: 'static, +{ events: ResMut<'w, Events>, #[system_param(ignore)] marker: PhantomData<&'s usize>, + #[system_param(ignore)] + _vis_marker: PhantomData, } -impl<'w, 's, E: Event> EventWriter<'w, 's, E> { +impl<'w, 's, E, Vis> EventWriter<'w, 's, E, Vis> +where + E: Write + Event, + Vis: 'static, +{ /// Sends an `event`. [`EventReader`]s can then read the event. /// See [`Events`] for details. pub fn send(&mut self, event: E) { @@ -319,22 +407,33 @@ impl<'w, 's, E: Event> EventWriter<'w, 's, E> { } #[derive(Debug)] -pub struct ManualEventReader { +pub struct ManualEventReader +where + E: Read + Event, +{ last_event_count: usize, _marker: PhantomData, + _marker_vis: PhantomData Vis>, } -impl Default for ManualEventReader { +impl Default for ManualEventReader +where + E: Read + Event, +{ fn default() -> Self { ManualEventReader { last_event_count: 0, _marker: Default::default(), + _marker_vis: Default::default(), } } } #[allow(clippy::len_without_is_empty)] // Check fails since the is_empty implementation has a signature other than `(&self) -> bool` -impl ManualEventReader { +impl ManualEventReader +where + E: Read + Event, +{ /// See [`EventReader::iter`] pub fn iter<'a>( &'a mut self, @@ -442,7 +541,10 @@ impl ExactSizeIterator for ExactSize { impl Events { /// "Sends" an `event` by writing it to the current event buffer. [`EventReader`]s can then read /// the event. - pub fn send(&mut self, event: E) { + pub fn send(&mut self, event: E) + where + E: Write, + { let event_id = EventId { id: self.event_count, _marker: PhantomData, @@ -456,21 +558,27 @@ impl Events { } /// Sends the default value of the event. Useful when the event is an empty struct. - pub fn send_default(&mut self) + pub fn send_default(&mut self) where - E: Default, + E: Write + Default, { self.send(Default::default()); } /// Gets a new [`ManualEventReader`]. This will include all events already in the event buffers. - pub fn get_reader(&self) -> ManualEventReader { + pub fn get_reader(&self) -> ManualEventReader + where + E: Read, + { ManualEventReader::default() } /// 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(&self) -> ManualEventReader + where + E: Read, + { ManualEventReader { last_event_count: self.event_count, ..Default::default() @@ -479,7 +587,10 @@ 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) { + pub fn update(&mut self) + where + E: Read + Write, + { std::mem::swap(&mut self.events_a, &mut self.events_b); self.events_b.clear(); self.events_b.start_event_count = self.event_count; @@ -490,7 +601,10 @@ impl Events { } /// A system that calls [`Events::update`] once per frame. - pub fn update_system(mut events: ResMut) { + pub fn update_system(mut events: ResMut) + where + E: Read + Write, + { events.update(); } @@ -502,25 +616,37 @@ impl Events { /// Removes all events. #[inline] - pub fn clear(&mut self) { + pub fn clear(&mut self) + where + E: Write, + { self.reset_start_event_count(); self.events_a.clear(); self.events_b.clear(); } #[inline] - pub fn len(&self) -> usize { + pub fn len(&self) -> usize + where + E: Read, + { self.events_a.len() + self.events_b.len() } /// Returns true if there are no events in this collection. #[inline] - pub fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool + where + E: Read, + { self.len() == 0 } /// Creates a draining iterator that removes all events. - pub fn drain(&mut self) -> impl Iterator + '_ { + pub fn drain(&mut self) -> impl Iterator + '_ + where + E: Read + Write, + { self.reset_start_event_count(); // Drain the oldest events first, then the newest @@ -536,18 +662,25 @@ impl Events { /// between the last `update()` call and your call to `iter_current_update_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( + pub fn iter_current_update_events( &self, - ) -> impl DoubleEndedIterator + ExactSizeIterator { + ) -> impl DoubleEndedIterator + ExactSizeIterator + where + E: Read, + { self.events_b.iter().map(|i| &i.event) } -} -impl std::iter::Extend for Events { - fn extend(&mut self, iter: I) + pub fn extend(&mut self, iter: I) where I: IntoIterator, + E: Write, { + // NOTE: anything that reads or writes events must protected + // at either the type level or the method level. This means that trait impls cannot + // perform reads/writes on an 'unprotected' type like `Events<_>`. + // That's why this type does not impl `Extend`. + let mut event_count = self.event_count; let events = iter.into_iter().map(|event| { let event_id = EventId { @@ -575,7 +708,7 @@ mod tests { use super::*; - #[derive(Copy, Clone, PartialEq, Eq, Debug)] + #[derive(Copy, Clone, PartialEq, Eq, Debug, Event)] struct TestEvent { i: usize, } @@ -671,14 +804,14 @@ mod tests { ); } - fn get_events( + fn get_events( events: &Events, reader: &mut ManualEventReader, ) -> Vec { 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)) { @@ -826,7 +959,7 @@ mod tests { assert!(is_empty, "EventReader should be empty"); } - #[derive(Clone, PartialEq, Debug, Default)] + #[derive(Clone, PartialEq, Debug, Default, Event)] struct EmptyTestEvent; #[test] @@ -843,7 +976,7 @@ mod tests { #[test] fn ensure_reader_readonly() { - fn read_for() { + fn read_for() { let mut world = World::new(); world.init_resource::>(); let mut state = SystemState::>::new(&mut world); diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index cafacc2a2d929..1f29189313385 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -31,7 +31,7 @@ pub mod prelude { change_detection::DetectChanges, component::Component, entity::Entity, - event::{EventReader, EventWriter, Events}, + event::{Event, EventReader, EventWriter, Events}, query::{Added, AnyOf, ChangeTrackers, Changed, Or, QueryState, With, Without}, schedule::{ AmbiguitySetLabel, ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion, diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index a1e209e2426d8..97a2b039604c6 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -81,6 +81,7 @@ impl SystemMeta { /// use bevy_ecs::{system::SystemState}; /// use bevy_ecs::event::Events; /// +/// #[derive(Event)] /// struct MyEvent; /// struct MyResource(u32); /// @@ -109,6 +110,7 @@ impl SystemMeta { /// use bevy_ecs::{system::SystemState}; /// use bevy_ecs::event::Events; /// +/// #[derive(Event)] /// struct MyEvent; /// struct CachedSystemState<'w, 's>{ /// event_state: SystemState> diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index d849d4a39914a..3155e53a1202e 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -16,6 +16,7 @@ use crate::{ StorageType, }, entity::{AllocAtWithoutReplacement, Entities, Entity}, + event, query::{QueryState, WorldQuery}, storage::{Column, SparseSet, Storages}, system::Resource, @@ -1158,19 +1159,28 @@ impl World { /// Sends an [`Event`](crate::event::Event). #[inline] - pub fn send_event(&mut self, event: E) { + pub fn send_event(&mut self, event: E) + where + E: event::Event + event::Write, + { self.send_event_batch(std::iter::once(event)); } /// Sends the default value of the [`Event`](crate::event::Event) of type `E`. #[inline] - pub fn send_event_default(&mut self) { + pub fn send_event_default(&mut self) + where + E: event::Event + event::Write + Default, + { self.send_event_batch(std::iter::once(E::default())); } /// Sends a batch of [`Event`](crate::event::Event)s from an iterator. #[inline] - pub fn send_event_batch(&mut self, events: impl Iterator) { + pub fn send_event_batch(&mut self, events: impl Iterator) + where + E: event::Event + event::Write, + { match self.get_resource_mut::>() { Some(mut events_resource) => events_resource.extend(events), None => bevy_utils::tracing::error!( diff --git a/crates/bevy_hierarchy/src/events.rs b/crates/bevy_hierarchy/src/events.rs index 5fd3555de9470..feca20a031d56 100644 --- a/crates/bevy_hierarchy/src/events.rs +++ b/crates/bevy_hierarchy/src/events.rs @@ -1,10 +1,10 @@ -use bevy_ecs::prelude::Entity; +use bevy_ecs::{event::Event, prelude::Entity}; /// A [`Event`] that is fired whenever there is a change in the world's /// hierarchy. /// /// [`Event`]: bevy_ecs::event::Event -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub enum HierarchyEvent { /// Fired whenever an [`Entity`] is added as a child to a new parent. ChildAdded { diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index fd45219a30614..4fa6dde4a8906 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::system::{Res, ResMut}; use bevy_utils::{tracing::info, HashMap, HashSet}; @@ -54,7 +54,7 @@ pub enum GamepadEventType { AxisChanged(GamepadAxisType, f32), } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Event)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct GamepadEvent { pub gamepad: Gamepad, @@ -70,7 +70,7 @@ impl GamepadEvent { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Event)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct GamepadEventRaw { pub gamepad: Gamepad, diff --git a/crates/bevy_input/src/keyboard.rs b/crates/bevy_input/src/keyboard.rs index 40eec4b35a66b..8553860e324b3 100644 --- a/crates/bevy_input/src/keyboard.rs +++ b/crates/bevy_input/src/keyboard.rs @@ -1,5 +1,8 @@ use crate::{ButtonState, Input}; -use bevy_ecs::{event::EventReader, system::ResMut}; +use bevy_ecs::{ + event::{Event, EventReader}, + system::ResMut, +}; /// A keyboard input event. /// @@ -10,7 +13,7 @@ use bevy_ecs::{event::EventReader, system::ResMut}; /// /// 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)] +#[derive(Debug, Clone, Event)] pub struct KeyboardInput { /// The scan code of the key. pub scan_code: u32, diff --git a/crates/bevy_input/src/mouse.rs b/crates/bevy_input/src/mouse.rs index b06a5c2ae355a..3a178e459a36a 100644 --- a/crates/bevy_input/src/mouse.rs +++ b/crates/bevy_input/src/mouse.rs @@ -1,5 +1,8 @@ use crate::{ButtonState, Input}; -use bevy_ecs::{event::EventReader, system::ResMut}; +use bevy_ecs::{ + event::{Event, EventReader}, + system::ResMut, +}; use bevy_math::Vec2; /// A mouse button input event. @@ -10,7 +13,7 @@ use bevy_math::Vec2; /// /// 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)] +#[derive(Debug, Clone, Event)] pub struct MouseButtonInput { /// The mouse button assigned to the event. pub button: MouseButton, @@ -50,7 +53,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)] +#[derive(Debug, Clone, Event)] pub struct MouseMotion { /// The change in the position of the pointing device since the last event was sent. pub delta: Vec2, @@ -79,7 +82,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)] +#[derive(Debug, Clone, Event)] pub struct MouseWheel { /// The mouse scroll unit. pub unit: MouseScrollUnit, diff --git a/crates/bevy_input/src/touch.rs b/crates/bevy_input/src/touch.rs index cd0b59db7cabc..cbd401450f44f 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; use bevy_math::Vec2; use bevy_utils::HashMap; @@ -26,7 +26,7 @@ use bevy_utils::HashMap; /// /// 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)] +#[derive(Debug, Clone, Copy, PartialEq, Event)] pub struct TouchInput { /// The phase of the touch input. pub phase: TouchPhase, diff --git a/crates/bevy_window/src/event.rs b/crates/bevy_window/src/event.rs index 0ac0d01c2d37d..3dec3aaa9b663 100644 --- a/crates/bevy_window/src/event.rs +++ b/crates/bevy_window/src/event.rs @@ -1,10 +1,11 @@ use std::path::PathBuf; use super::{WindowDescriptor, WindowId}; +use bevy_ecs::event::Event; use bevy_math::{IVec2, Vec2}; /// A window event that is sent whenever a window's logical size has changed. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct WindowResized { pub id: WindowId, /// The new logical width of the window. @@ -14,7 +15,7 @@ pub struct WindowResized { } /// An event that indicates that a new window should be created. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct CreateWindow { pub id: WindowId, pub descriptor: WindowDescriptor, @@ -22,14 +23,14 @@ pub struct CreateWindow { /// An event that indicates the window should redraw, even if its control flow is set to `Wait` and /// there have been no window events. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct RequestRedraw; /// An event that is sent whenever a new window is created. /// /// To create a new window, send a [`CreateWindow`] event - this /// event will be sent in the handler for that event. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct WindowCreated { pub id: WindowId, } @@ -45,7 +46,7 @@ pub struct WindowCreated { /// [`WindowPlugin`]: crate::WindowPlugin /// [`Window`]: crate::Window /// [closing]: crate::Window::close -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct WindowCloseRequested { pub id: WindowId, } @@ -54,7 +55,7 @@ pub struct WindowCloseRequested { /// handler for [`Window::close`]. /// /// [`Window::close`]: crate::Window::close -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct WindowClosed { pub id: WindowId, } @@ -67,7 +68,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)] +#[derive(Debug, Clone, Event)] pub struct CursorMoved { /// The identifier of the window the cursor has moved on. pub id: WindowId, @@ -76,45 +77,45 @@ pub struct CursorMoved { pub position: Vec2, } /// An event that is sent whenever the user's cursor enters a window. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct CursorEntered { pub id: WindowId, } /// An event that is sent whenever the user's cursor leaves a window. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct CursorLeft { pub id: WindowId, } /// An event that is sent whenever a window receives a character from the OS or underlying system. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct ReceivedCharacter { pub id: WindowId, pub char: char, } /// An event that indicates a window has received or lost focus. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct WindowFocused { pub id: WindowId, pub focused: bool, } /// An event that indicates a window's scale factor has changed. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct WindowScaleFactorChanged { pub id: WindowId, pub scale_factor: f64, } /// An event that indicates a window's OS-reported scale factor has changed. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct WindowBackendScaleFactorChanged { pub id: WindowId, pub scale_factor: f64, } /// Events related to files being dragged and dropped on a window. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub enum FileDragAndDrop { DroppedFile { id: WindowId, path_buf: PathBuf }, @@ -124,7 +125,7 @@ pub enum FileDragAndDrop { } /// An event that is sent when a window is repositioned in physical pixels. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Event)] pub struct WindowMoved { pub id: WindowId, pub position: IVec2, diff --git a/examples/async_tasks/external_source_external_thread.rs b/examples/async_tasks/external_source_external_thread.rs index 679d67d6a626b..b5dc454d259fd 100644 --- a/examples/async_tasks/external_source_external_thread.rs +++ b/examples/async_tasks/external_source_external_thread.rs @@ -19,6 +19,7 @@ fn main() { #[derive(Deref)] struct StreamReceiver(Receiver); +#[derive(Event)] struct StreamEvent(u32); #[derive(Deref)] diff --git a/examples/ecs/event.rs b/examples/ecs/event.rs index f4c93c44d47a0..fffd451a945ed 100644 --- a/examples/ecs/event.rs +++ b/examples/ecs/event.rs @@ -15,11 +15,12 @@ fn main() { .run(); } +#[derive(Event)] struct MyEvent { pub message: String, } -#[derive(Default)] +#[derive(Default, Event)] struct PlaySound; struct EventTriggerState { diff --git a/examples/games/breakout.rs b/examples/games/breakout.rs index 2260ed91a58c8..eaffb30eae3e2 100644 --- a/examples/games/breakout.rs +++ b/examples/games/breakout.rs @@ -82,7 +82,7 @@ struct Velocity(Vec2); #[derive(Component)] struct Collider; -#[derive(Default)] +#[derive(Default, Event)] struct CollisionEvent; #[derive(Component)] diff --git a/tests/how_to_test_systems.rs b/tests/how_to_test_systems.rs index f03b224ce21b7..6735ac6bc738a 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); struct Score(u32);