Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/event/mutator.rs
6600 views
1
#[cfg(feature = "multi_threaded")]
2
use bevy_ecs::event::EventMutParIter;
3
use bevy_ecs::{
4
event::{BufferedEvent, EventCursor, EventMutIterator, EventMutIteratorWithId, Events},
5
system::{Local, ResMut, SystemParam},
6
};
7
8
/// Mutably reads events of type `T` keeping track of which events have already been read
9
/// by each system allowing multiple systems to read the same events. Ideal for chains of systems
10
/// that all want to modify the same events.
11
///
12
/// # Usage
13
///
14
/// `EventMutators`s are usually declared as a [`SystemParam`].
15
/// ```
16
/// # use bevy_ecs::prelude::*;
17
///
18
/// #[derive(BufferedEvent, Debug)]
19
/// pub struct MyEvent(pub u32); // Custom event type.
20
/// fn my_system(mut reader: EventMutator<MyEvent>) {
21
/// for event in reader.read() {
22
/// event.0 += 1;
23
/// println!("received event: {:?}", event);
24
/// }
25
/// }
26
/// ```
27
///
28
/// # Concurrency
29
///
30
/// Multiple systems with `EventMutator<T>` of the same event type can not run concurrently.
31
/// They also can not be executed in parallel with [`EventReader`] or [`EventWriter`].
32
///
33
/// # Clearing, Reading, and Peeking
34
///
35
/// Events are stored in a double buffered queue that switches each frame. This switch also clears the previous
36
/// frame's events. Events should be read each frame otherwise they may be lost. For manual control over this
37
/// behavior, see [`Events`].
38
///
39
/// Most of the time systems will want to use [`EventMutator::read()`]. This function creates an iterator over
40
/// all events that haven't been read yet by this system, marking the event as read in the process.
41
///
42
/// [`EventReader`]: super::EventReader
43
/// [`EventWriter`]: super::EventWriter
44
#[derive(SystemParam, Debug)]
45
pub struct EventMutator<'w, 's, E: BufferedEvent> {
46
pub(super) reader: Local<'s, EventCursor<E>>,
47
#[system_param(validation_message = "BufferedEvent not initialized")]
48
events: ResMut<'w, Events<E>>,
49
}
50
51
impl<'w, 's, E: BufferedEvent> 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(BufferedEvent)]
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.write_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(BufferedEvent)]
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
}
144
145