bevy_ecs/event/
mutator.rs

1use crate as bevy_ecs;
2#[cfg(feature = "multi_threaded")]
3use bevy_ecs::event::EventMutParIter;
4use bevy_ecs::{
5    event::{Event, EventCursor, EventMutIterator, EventMutIteratorWithId, Events},
6    system::{Local, ResMut, SystemParam},
7};
8
9/// Mutably reads events of type `T` keeping track of which events have already been read
10/// by each system allowing multiple systems to read the same events. Ideal for chains of systems
11/// that all want to modify the same events.
12///
13/// # Usage
14///
15/// `EventMutators`s are usually declared as a [`SystemParam`].
16/// ```
17/// # use bevy_ecs::prelude::*;
18///
19/// #[derive(Event, Debug)]
20/// pub struct MyEvent(pub u32); // Custom event type.
21/// fn my_system(mut reader: EventMutator<MyEvent>) {
22///     for event in reader.read() {
23///         event.0 += 1;
24///         println!("received event: {:?}", event);
25///     }
26/// }
27/// ```
28///
29/// # Concurrency
30///
31/// Multiple systems with `EventMutator<T>` of the same event type can not run concurrently.
32/// They also can not be executed in parallel with [`EventReader`] or [`EventWriter`].
33///
34/// # Clearing, Reading, and Peeking
35///
36/// Events are stored in a double buffered queue that switches each frame. This switch also clears the previous
37/// frame's events. Events should be read each frame otherwise they may be lost. For manual control over this
38/// behavior, see [`Events`].
39///
40/// Most of the time systems will want to use [`EventMutator::read()`]. This function creates an iterator over
41/// all events that haven't been read yet by this system, marking the event as read in the process.
42///
43/// [`EventReader`]: super::EventReader
44/// [`EventWriter`]: super::EventWriter
45#[derive(SystemParam, Debug)]
46pub struct EventMutator<'w, 's, E: Event> {
47    pub(super) reader: Local<'s, EventCursor<E>>,
48    events: ResMut<'w, Events<E>>,
49}
50
51impl<'w, 's, E: Event> EventMutator<'w, 's, E> {
52    /// Iterates over the events this [`EventMutator`] has not seen yet. This updates the
53    /// [`EventMutator`]'s event counter, which means subsequent event reads will not include events
54    /// that happened before now.
55    pub fn read(&mut self) -> EventMutIterator<'_, E> {
56        self.reader.read_mut(&mut self.events)
57    }
58
59    /// Like [`read`](Self::read), except also returning the [`EventId`](super::EventId) of the events.
60    pub fn read_with_id(&mut self) -> EventMutIteratorWithId<'_, E> {
61        self.reader.read_mut_with_id(&mut self.events)
62    }
63
64    /// Returns a parallel iterator over the events this [`EventMutator`] has not seen yet.
65    /// See also [`for_each`](super::EventParIter::for_each).
66    ///
67    /// # Example
68    /// ```
69    /// # use bevy_ecs::prelude::*;
70    /// # use std::sync::atomic::{AtomicUsize, Ordering};
71    ///
72    /// #[derive(Event)]
73    /// struct MyEvent {
74    ///     value: usize,
75    /// }
76    ///
77    /// #[derive(Resource, Default)]
78    /// struct Counter(AtomicUsize);
79    ///
80    /// // setup
81    /// let mut world = World::new();
82    /// world.init_resource::<Events<MyEvent>>();
83    /// world.insert_resource(Counter::default());
84    ///
85    /// let mut schedule = Schedule::default();
86    /// schedule.add_systems(|mut events: EventMutator<MyEvent>, counter: Res<Counter>| {
87    ///     events.par_read().for_each(|MyEvent { value }| {
88    ///         counter.0.fetch_add(*value, Ordering::Relaxed);
89    ///     });
90    /// });
91    /// for value in 0..100 {
92    ///     world.send_event(MyEvent { value });
93    /// }
94    /// schedule.run(&mut world);
95    /// let Counter(counter) = world.remove_resource::<Counter>().unwrap();
96    /// // all events were processed
97    /// assert_eq!(counter.into_inner(), 4950);
98    /// ```
99    #[cfg(feature = "multi_threaded")]
100    pub fn par_read(&mut self) -> EventMutParIter<'_, E> {
101        self.reader.par_read_mut(&mut self.events)
102    }
103
104    /// Determines the number of events available to be read from this [`EventMutator`] without consuming any.
105    pub fn len(&self) -> usize {
106        self.reader.len(&self.events)
107    }
108
109    /// Returns `true` if there are no events available to read.
110    ///
111    /// # Example
112    ///
113    /// The following example shows a useful pattern where some behavior is triggered if new events are available.
114    /// [`EventMutator::clear()`] is used so the same events don't re-trigger the behavior the next time the system runs.
115    ///
116    /// ```
117    /// # use bevy_ecs::prelude::*;
118    /// #
119    /// #[derive(Event)]
120    /// struct CollisionEvent;
121    ///
122    /// fn play_collision_sound(mut events: EventMutator<CollisionEvent>) {
123    ///     if !events.is_empty() {
124    ///         events.clear();
125    ///         // Play a sound
126    ///     }
127    /// }
128    /// # bevy_ecs::system::assert_is_system(play_collision_sound);
129    /// ```
130    pub fn is_empty(&self) -> bool {
131        self.reader.is_empty(&self.events)
132    }
133
134    /// Consumes all available events.
135    ///
136    /// This means these events will not appear in calls to [`EventMutator::read()`] or
137    /// [`EventMutator::read_with_id()`] and [`EventMutator::is_empty()`] will return `true`.
138    ///
139    /// For usage, see [`EventMutator::is_empty()`].
140    pub fn clear(&mut self) {
141        self.reader.clear(&self.events);
142    }
143}