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.
This commit is contained in:
CatThingy 2023-06-06 07:44:32 -07:00 committed by GitHub
parent 1e97c79ec1
commit 89cbc78d3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 130 additions and 54 deletions

View file

@ -1,13 +1,16 @@
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
pub struct Benchmark<const SIZE: usize>(Events<[u8; SIZE]>); #[derive(Event)]
struct BenchEvent<const SIZE: usize>([u8; SIZE]);
pub struct Benchmark<const SIZE: usize>(Events<BenchEvent<SIZE>>);
impl<const SIZE: usize> Benchmark<SIZE> { impl<const SIZE: usize> Benchmark<SIZE> {
pub fn new(count: usize) -> Self { pub fn new(count: usize) -> Self {
let mut events = Events::default(); let mut events = Events::default();
for _ in 0..count { for _ in 0..count {
events.send([0u8; SIZE]); events.send(BenchEvent([0u8; SIZE]));
} }
Self(events) Self(events)

View file

@ -1,18 +1,27 @@
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
#[derive(Event)]
struct BenchEvent<const SIZE: usize>([u8; SIZE]);
impl<const SIZE: usize> Default for BenchEvent<SIZE> {
fn default() -> Self {
BenchEvent([0; SIZE])
}
}
pub struct Benchmark<const SIZE: usize> { pub struct Benchmark<const SIZE: usize> {
events: Events<[u8; SIZE]>, events: Events<BenchEvent<SIZE>>,
count: usize, count: usize,
} }
impl<const SIZE: usize> Benchmark<SIZE> { impl<const SIZE: usize> Benchmark<SIZE> {
pub fn new(count: usize) -> Self { pub fn new(count: usize) -> Self {
let mut events = Events::default(); let mut events = Events::default();
// Force both internal buffers to be allocated. // Force both internal buffers to be allocated.
for _ in 0..2 { for _ in 0..2 {
for _ in 0..count { for _ in 0..count {
events.send([0u8; SIZE]); events.send(BenchEvent([0u8; SIZE]));
} }
events.update(); events.update();
} }
@ -22,7 +31,8 @@ impl<const SIZE: usize> Benchmark<SIZE> {
pub fn run(&mut self) { pub fn run(&mut self) {
for _ in 0..self.count { 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(); self.events.update();
} }

View file

@ -14,10 +14,14 @@ use accesskit::{NodeBuilder, NodeId};
use bevy_app::Plugin; use bevy_app::Plugin;
use bevy_derive::{Deref, DerefMut}; use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{ use bevy_ecs::{
prelude::{Component, Entity}, prelude::{Component, Entity, Event},
system::Resource, 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 /// Resource that tracks whether an assistive technology has requested
/// accessibility information. /// accessibility information.
/// ///

View file

@ -522,6 +522,7 @@ impl App {
/// # use bevy_app::prelude::*; /// # use bevy_app::prelude::*;
/// # use bevy_ecs::prelude::*; /// # use bevy_ecs::prelude::*;
/// # /// #
/// # #[derive(Event)]
/// # struct MyEvent; /// # struct MyEvent;
/// # let mut app = App::new(); /// # 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`] /// 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 /// trait on components/resources for code that runs on exit. That saves you from worrying about
/// system schedule ordering, and is idiomatic Rust. /// system schedule ordering, and is idiomatic Rust.
#[derive(Debug, Clone, Default)] #[derive(Event, Debug, Clone, Default)]
pub struct AppExit; pub struct AppExit;
#[cfg(test)] #[cfg(test)]

View file

@ -13,6 +13,7 @@ use std::fmt::Debug;
/// ///
/// Events sent via the [`Assets`] struct will always be sent with a _Weak_ handle, because the /// 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. /// asset may not exist by the time the event is handled.
#[derive(Event)]
pub enum AssetEvent<T: Asset> { pub enum AssetEvent<T: Asset> {
#[allow(missing_docs)] #[allow(missing_docs)]
Created { handle: Handle<T> }, Created { handle: Handle<T> },

View file

@ -286,6 +286,7 @@ Events offer a communication channel between one or more systems. Events can be
```rust ```rust
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
#[derive(Event)]
struct MyEvent { struct MyEvent {
message: String, message: String,
} }

View file

@ -32,6 +32,7 @@ fn main() {
} }
// This is our event that we will send and receive in systems // This is our event that we will send and receive in systems
#[derive(Event)]
struct MyEvent { struct MyEvent {
pub message: String, pub message: String,
pub random_value: f32, pub random_value: f32,

View file

@ -3,6 +3,24 @@ use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote; use quote::quote;
use syn::{parse_macro_input, parse_quote, DeriveInput, Ident, LitStr, Path, Result}; 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 { pub fn derive_resource(input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as DeriveInput); let mut ast = parse_macro_input!(input as DeriveInput);
let bevy_ecs_path: Path = crate::bevy_ecs_path(); let bevy_ecs_path: Path = crate::bevy_ecs_path();

View file

@ -452,6 +452,11 @@ pub(crate) fn bevy_ecs_path() -> syn::Path {
BevyManifest::default().get_path("bevy_ecs") 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)] #[proc_macro_derive(Resource)]
pub fn derive_resource(input: TokenStream) -> TokenStream { pub fn derive_resource(input: TokenStream) -> TokenStream {
component::derive_resource(input) component::derive_resource(input)

View file

@ -2,6 +2,7 @@
use crate as bevy_ecs; use crate as bevy_ecs;
use crate::system::{Local, Res, ResMut, Resource, SystemParam}; use crate::system::{Local, Res, ResMut, Resource, SystemParam};
pub use bevy_ecs_macros::Event;
use bevy_utils::detailed_trace; use bevy_utils::detailed_trace;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::{ use std::{
@ -17,7 +18,6 @@ use std::{
/// ///
/// Events must be thread-safe. /// Events must be thread-safe.
pub trait Event: Send + Sync + 'static {} pub trait Event: Send + Sync + 'static {}
impl<T> Event for T where T: Send + Sync + 'static {}
/// An `EventId` uniquely identifies an event. /// An `EventId` uniquely identifies an event.
/// ///
@ -109,8 +109,9 @@ struct EventInstance<E: Event> {
/// ///
/// # Example /// # Example
/// ``` /// ```
/// use bevy_ecs::event::Events; /// use bevy_ecs::event::{Event, Events};
/// ///
/// #[derive(Event)]
/// struct MyEvent { /// struct MyEvent {
/// value: usize /// value: usize
/// } /// }
@ -248,6 +249,8 @@ impl<'w, 's, E: Event> EventReader<'w, 's, E> {
/// ///
/// ``` /// ```
/// # use bevy_ecs::prelude::*; /// # use bevy_ecs::prelude::*;
/// #
/// #[derive(Event)]
/// struct CollisionEvent; /// struct CollisionEvent;
/// ///
/// fn play_collision_sound(mut events: EventReader<CollisionEvent>) { /// fn play_collision_sound(mut events: EventReader<CollisionEvent>) {
@ -289,6 +292,7 @@ impl<'a, 'w, 's, E: Event> IntoIterator for &'a mut EventReader<'w, 's, E> {
/// ``` /// ```
/// # use bevy_ecs::prelude::*; /// # use bevy_ecs::prelude::*;
/// ///
/// #[derive(Event)]
/// pub struct MyEvent; // Custom event type. /// pub struct MyEvent; // Custom event type.
/// fn my_system(mut writer: EventWriter<MyEvent>) { /// fn my_system(mut writer: EventWriter<MyEvent>) {
/// writer.send(MyEvent); /// 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}; /// # use bevy_ecs::{prelude::*, event::Events};
/// /// # #[derive(Event)]
/// # pub struct MyEvent; /// # pub struct MyEvent;
/// fn send_untyped(mut commands: Commands) { /// fn send_untyped(mut commands: Commands) {
/// // Send an event of a specific type without having to declare that /// // Send an event of a specific type without having to declare that
@ -699,7 +703,7 @@ mod tests {
use super::*; use super::*;
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Event, Copy, Clone, PartialEq, Eq, Debug)]
struct TestEvent { struct TestEvent {
i: usize, i: usize,
} }
@ -802,7 +806,7 @@ mod tests {
reader.iter(events).cloned().collect::<Vec<E>>() reader.iter(events).cloned().collect::<Vec<E>>()
} }
#[derive(PartialEq, Eq, Debug)] #[derive(Event, PartialEq, Eq, Debug)]
struct E(usize); struct E(usize);
fn events_clear_and_read_impl(clear_func: impl FnOnce(&mut Events<E>)) { fn events_clear_and_read_impl(clear_func: impl FnOnce(&mut Events<E>)) {
@ -1009,7 +1013,7 @@ mod tests {
assert!(last.is_none(), "EventReader should be empty"); assert!(last.is_none(), "EventReader should be empty");
} }
#[derive(Clone, PartialEq, Debug, Default)] #[derive(Event, Clone, PartialEq, Debug, Default)]
struct EmptyTestEvent; struct EmptyTestEvent;
#[test] #[test]

View file

@ -4,7 +4,9 @@ use crate::{
self as bevy_ecs, self as bevy_ecs,
component::{Component, ComponentId, ComponentIdFor, Tick}, component::{Component, ComponentId, ComponentIdFor, Tick},
entity::Entity, entity::Entity,
event::{EventId, Events, ManualEventIterator, ManualEventIteratorWithId, ManualEventReader}, event::{
Event, EventId, Events, ManualEventIterator, ManualEventIteratorWithId, ManualEventReader,
},
prelude::Local, prelude::Local,
storage::SparseSet, storage::SparseSet,
system::{ReadOnlySystemParam, SystemMeta, SystemParam}, system::{ReadOnlySystemParam, SystemMeta, SystemParam},
@ -21,7 +23,7 @@ use std::{
/// Wrapper around [`Entity`] for [`RemovedComponents`]. /// Wrapper around [`Entity`] for [`RemovedComponents`].
/// Internally, `RemovedComponents` uses these as an `Events<RemovedComponentEntity>`. /// Internally, `RemovedComponents` uses these as an `Events<RemovedComponentEntity>`.
#[derive(Debug, Clone)] #[derive(Event, Debug, Clone)]
pub struct RemovedComponentEntity(Entity); pub struct RemovedComponentEntity(Entity);
impl From<RemovedComponentEntity> for Entity { impl From<RemovedComponentEntity> for Entity {

View file

@ -876,6 +876,7 @@ pub mod common_conditions {
/// my_system.run_if(on_event::<MyEvent>()), /// my_system.run_if(on_event::<MyEvent>()),
/// ); /// );
/// ///
/// #[derive(Event)]
/// struct MyEvent; /// struct MyEvent;
/// ///
/// fn my_system(mut counter: ResMut<Counter>) { /// fn my_system(mut counter: ResMut<Counter>) {
@ -1133,6 +1134,7 @@ mod tests {
use crate::schedule::{common_conditions::not, State, States}; use crate::schedule::{common_conditions::not, State, States};
use crate::system::Local; use crate::system::Local;
use crate::{change_detection::ResMut, schedule::Schedule, world::World}; use crate::{change_detection::ResMut, schedule::Schedule, world::World};
use bevy_ecs_macros::Event;
use bevy_ecs_macros::Resource; use bevy_ecs_macros::Resource;
#[derive(Resource, Default)] #[derive(Resource, Default)]
@ -1239,6 +1241,9 @@ mod tests {
#[derive(Component)] #[derive(Component)]
struct TestComponent; struct TestComponent;
#[derive(Event)]
struct TestEvent;
fn test_system() {} fn test_system() {}
// Ensure distributive_run_if compiles with the common conditions. // Ensure distributive_run_if compiles with the common conditions.
@ -1256,7 +1261,7 @@ mod tests {
.distributive_run_if(state_exists::<TestState>()) .distributive_run_if(state_exists::<TestState>())
.distributive_run_if(in_state(TestState::A)) .distributive_run_if(in_state(TestState::A))
.distributive_run_if(state_changed::<TestState>()) .distributive_run_if(state_changed::<TestState>())
.distributive_run_if(on_event::<u8>()) .distributive_run_if(on_event::<TestEvent>())
.distributive_run_if(any_with_component::<TestComponent>()) .distributive_run_if(any_with_component::<TestComponent>())
.distributive_run_if(not(run_once())), .distributive_run_if(not(run_once())),
); );

View file

@ -85,6 +85,7 @@ impl SystemMeta {
/// # use bevy_ecs::system::SystemState; /// # use bevy_ecs::system::SystemState;
/// # use bevy_ecs::event::Events; /// # use bevy_ecs::event::Events;
/// # /// #
/// # #[derive(Event)]
/// # struct MyEvent; /// # struct MyEvent;
/// # #[derive(Resource)] /// # #[derive(Resource)]
/// # struct MyResource(u32); /// # struct MyResource(u32);
@ -117,6 +118,7 @@ impl SystemMeta {
/// # use bevy_ecs::system::SystemState; /// # use bevy_ecs::system::SystemState;
/// # use bevy_ecs::event::Events; /// # use bevy_ecs::event::Events;
/// # /// #
/// # #[derive(Event)]
/// # struct MyEvent; /// # struct MyEvent;
/// #[derive(Resource)] /// #[derive(Resource)]
/// struct CachedSystemState { /// struct CachedSystemState {

View file

@ -308,6 +308,7 @@ fn assert_component_access_compatibility(
/// ``` /// ```
/// # use bevy_ecs::prelude::*; /// # use bevy_ecs::prelude::*;
/// # /// #
/// # #[derive(Event)]
/// # struct MyEvent; /// # struct MyEvent;
/// # impl MyEvent { /// # impl MyEvent {
/// # pub fn new() -> Self { Self } /// # pub fn new() -> Self { Self }

View file

@ -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. /// An [`Event`] that is fired whenever there is a change in the world's hierarchy.
/// ///
/// [`Event`]: bevy_ecs::event::Event /// [`Event`]: bevy_ecs::event::Event
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Event, Debug, Clone, PartialEq, Eq)]
pub enum HierarchyEvent { pub enum HierarchyEvent {
/// Fired whenever an [`Entity`] is added as a child to a parent. /// Fired whenever an [`Entity`] is added as a child to a parent.
ChildAdded { ChildAdded {

View file

@ -1,5 +1,5 @@
use crate::{Axis, Input}; use crate::{Axis, Input};
use bevy_ecs::event::{EventReader, EventWriter}; use bevy_ecs::event::{Event, EventReader, EventWriter};
use bevy_ecs::{ use bevy_ecs::{
change_detection::DetectChangesMut, change_detection::DetectChangesMut,
system::{Res, ResMut, Resource}, system::{Res, ResMut, Resource},
@ -1039,7 +1039,7 @@ pub enum GamepadConnection {
/// A Gamepad connection event. Created when a connection to a gamepad /// A Gamepad connection event. Created when a connection to a gamepad
/// is established and when a gamepad is disconnected. /// is established and when a gamepad is disconnected.
#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)]
#[reflect(Debug, PartialEq)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -1070,7 +1070,7 @@ impl GamepadConnectionEvent {
} }
} }
#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)]
#[reflect(Debug, PartialEq)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -1095,7 +1095,7 @@ impl GamepadAxisChangedEvent {
/// Gamepad event for when the "value" (amount of pressure) on the button /// Gamepad event for when the "value" (amount of pressure) on the button
/// changes by an amount larger than the threshold defined in [`GamepadSettings`]. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -1158,7 +1158,7 @@ pub fn gamepad_button_event_system(
/// This event type is used over the [`GamepadConnectionEvent`], /// This event type is used over the [`GamepadConnectionEvent`],
/// [`GamepadButtonChangedEvent`] and [`GamepadAxisChangedEvent`] when /// [`GamepadButtonChangedEvent`] and [`GamepadAxisChangedEvent`] when
/// the in-frame relative ordering of events is important. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -1330,7 +1330,7 @@ impl GamepadRumbleIntensity {
#[doc(alias = "force feedback")] #[doc(alias = "force feedback")]
#[doc(alias = "vibration")] #[doc(alias = "vibration")]
#[doc(alias = "vibrate")] #[doc(alias = "vibrate")]
#[derive(Clone)] #[derive(Event, Clone)]
pub enum GamepadRumbleRequest { pub enum GamepadRumbleRequest {
/// Add a rumble to the given gamepad. /// Add a rumble to the given gamepad.
/// ///

View file

@ -1,5 +1,9 @@
use crate::{ButtonState, Input}; 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}; use bevy_reflect::{FromReflect, Reflect};
#[cfg(feature = "serialize")] #[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) /// The event is consumed inside of the [`keyboard_input_system`](crate::keyboard::keyboard_input_system)
/// to update the [`Input<KeyCode>`](crate::Input<KeyCode>) resource. /// to update the [`Input<KeyCode>`](crate::Input<KeyCode>) resource.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)] #[derive(Event, Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)]
#[reflect(Debug, PartialEq)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",

View file

@ -1,5 +1,9 @@
use crate::{ButtonState, Input}; 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_math::Vec2;
use bevy_reflect::{FromReflect, Reflect}; 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) /// The event is read inside of the [`mouse_button_input_system`](crate::mouse::mouse_button_input_system)
/// to update the [`Input<MouseButton>`](crate::Input<MouseButton>) resource. /// to update the [`Input<MouseButton>`](crate::Input<MouseButton>) resource.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)] #[derive(Event, Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)]
#[reflect(Debug, PartialEq)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", 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. /// 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 /// [`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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -106,7 +110,7 @@ pub enum MouseScrollUnit {
/// A mouse wheel event. /// A mouse wheel event.
/// ///
/// This event is the translated version of the `WindowEvent::MouseWheel` from the `winit` crate. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",

View file

@ -1,4 +1,4 @@
use bevy_ecs::event::EventReader; use bevy_ecs::event::{Event, EventReader};
use bevy_ecs::system::{ResMut, Resource}; use bevy_ecs::system::{ResMut, Resource};
use bevy_math::Vec2; use bevy_math::Vec2;
use bevy_reflect::{FromReflect, Reflect}; 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. /// 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. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",

View file

@ -1,6 +1,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use bevy_ecs::entity::Entity; use bevy_ecs::entity::Entity;
use bevy_ecs::event::Event;
use bevy_math::{IVec2, Vec2}; use bevy_math::{IVec2, Vec2};
use bevy_reflect::{FromReflect, Reflect}; use bevy_reflect::{FromReflect, Reflect};
@ -10,7 +11,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
use crate::WindowTheme; use crate::WindowTheme;
/// A window event that is sent whenever a window's logical size has changed. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -28,7 +29,7 @@ pub struct WindowResized {
/// An event that indicates all of the application's windows should be redrawn, /// 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. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -40,7 +41,7 @@ pub struct RequestRedraw;
/// An event that is sent whenever a new window is created. /// 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. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -62,7 +63,7 @@ pub struct WindowCreated {
/// ///
/// [`WindowPlugin`]: crate::WindowPlugin /// [`WindowPlugin`]: crate::WindowPlugin
/// [`Window`]: crate::Window /// [`Window`]: crate::Window
#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] #[derive(Event, Debug, Clone, PartialEq, Eq, Reflect, FromReflect)]
#[reflect(Debug, PartialEq)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -76,7 +77,7 @@ pub struct WindowCloseRequested {
/// An event that is sent whenever a window is closed. This will be sent when /// 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. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -99,7 +100,7 @@ pub struct WindowClosed {
/// ///
/// [`WindowEvent::CursorMoved`]: https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.CursorMoved /// [`WindowEvent::CursorMoved`]: https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.CursorMoved
/// [`MouseMotion`]: bevy_input::mouse::MouseMotion /// [`MouseMotion`]: bevy_input::mouse::MouseMotion
#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[derive(Event, Debug, Clone, PartialEq, Reflect, FromReflect)]
#[reflect(Debug, PartialEq)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -114,7 +115,7 @@ pub struct CursorMoved {
} }
/// An event that is sent whenever the user's cursor enters a window. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -127,7 +128,7 @@ pub struct CursorEntered {
} }
/// An event that is sent whenever the user's cursor leaves a window. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", 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. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -159,7 +160,7 @@ pub struct ReceivedCharacter {
/// This event is the translated version of the `WindowEvent::Ime` from the `winit` crate. /// 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). /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -201,7 +202,7 @@ pub enum Ime {
} }
/// An event that indicates a window has received or lost focus. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -216,7 +217,7 @@ pub struct WindowFocused {
} }
/// An event that indicates a window's scale factor has changed. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -231,7 +232,7 @@ pub struct WindowScaleFactorChanged {
} }
/// An event that indicates a window's OS-reported scale factor has changed. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -246,7 +247,7 @@ pub struct WindowBackendScaleFactorChanged {
} }
/// Events related to files being dragged and dropped on a window. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
@ -278,7 +279,7 @@ pub enum FileDragAndDrop {
} }
/// An event that is sent when a window is repositioned in physical pixels. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", 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. /// 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. /// 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)] #[reflect(Debug, PartialEq)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",

View file

@ -6,6 +6,7 @@ use std::{
}; };
use accesskit_winit::Adapter; use accesskit_winit::Adapter;
use bevy_a11y::ActionRequest as ActionRequestWrapper;
use bevy_a11y::{ use bevy_a11y::{
accesskit::{ActionHandler, ActionRequest, NodeBuilder, NodeClassSet, Role, TreeUpdate}, accesskit::{ActionHandler, ActionRequest, NodeBuilder, NodeClassSet, Role, TreeUpdate},
AccessKitEntityExt, AccessibilityNode, AccessibilityRequested, Focus, AccessKitEntityExt, AccessibilityNode, AccessibilityRequested, Focus,
@ -73,11 +74,14 @@ fn window_closed(
} }
} }
fn poll_receivers(handlers: Res<WinitActionHandlers>, mut actions: EventWriter<ActionRequest>) { fn poll_receivers(
handlers: Res<WinitActionHandlers>,
mut actions: EventWriter<ActionRequestWrapper>,
) {
for (_id, handler) in handlers.iter() { for (_id, handler) in handlers.iter() {
let mut handler = handler.lock().unwrap(); let mut handler = handler.lock().unwrap();
while let Some(event) = handler.pop_front() { 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) { fn build(&self, app: &mut App) {
app.init_non_send_resource::<AccessKitAdapters>() app.init_non_send_resource::<AccessKitAdapters>()
.init_resource::<WinitActionHandlers>() .init_resource::<WinitActionHandlers>()
.add_event::<ActionRequest>() .add_event::<ActionRequestWrapper>()
.add_systems( .add_systems(
PostUpdate, PostUpdate,
( (

View file

@ -17,6 +17,8 @@ fn main() {
#[derive(Resource, Deref)] #[derive(Resource, Deref)]
struct StreamReceiver(Receiver<u32>); struct StreamReceiver(Receiver<u32>);
#[derive(Event)]
struct StreamEvent(u32); struct StreamEvent(u32);
fn setup(mut commands: Commands) { fn setup(mut commands: Commands) {

View file

@ -13,11 +13,12 @@ fn main() {
.run(); .run();
} }
#[derive(Event)]
struct MyEvent { struct MyEvent {
pub message: String, pub message: String,
} }
#[derive(Default)] #[derive(Event, Default)]
struct PlaySound; struct PlaySound;
#[derive(Resource)] #[derive(Resource)]

View file

@ -84,7 +84,7 @@ struct Velocity(Vec2);
#[derive(Component)] #[derive(Component)]
struct Collider; struct Collider;
#[derive(Default)] #[derive(Event, Default)]
struct CollisionEvent; struct CollisionEvent;
#[derive(Component)] #[derive(Component)]

View file

@ -35,6 +35,7 @@ enum Constraint {
#[derive(Copy, Clone, Component)] #[derive(Copy, Clone, Component)]
struct ButtonValue(Val); struct ButtonValue(Val);
#[derive(Event)]
struct ButtonActivatedEvent(Entity); struct ButtonActivatedEvent(Entity);
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {

View file

@ -6,6 +6,7 @@ struct Enemy {
score_value: u32, score_value: u32,
} }
#[derive(Event)]
struct EnemyDied(u32); struct EnemyDied(u32);
#[derive(Resource)] #[derive(Resource)]