Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/ecs/send_and_receive_events.rs
6592 views
1
//! From time to time, you may find that you want to both send and receive an event of the same type in a single system.
2
//!
3
//! Of course, this results in an error: the borrows of [`EventWriter`] and [`EventReader`] overlap,
4
//! if and only if the [`BufferedEvent`] type is the same.
5
//! One system parameter borrows the [`Events`] resource mutably, and another system parameter borrows the [`Events`] resource immutably.
6
//! If Bevy allowed this, this would violate Rust's rules against aliased mutability.
7
//! In other words, this would be Undefined Behavior (UB)!
8
//!
9
//! There are two ways to solve this problem:
10
//!
11
//! 1. Use [`ParamSet`] to check out the [`EventWriter`] and [`EventReader`] one at a time.
12
//! 2. Use a [`Local`] [`EventCursor`] instead of an [`EventReader`], and use [`ResMut`] to access [`Events`].
13
//!
14
//! In the first case, you're being careful to only check out only one of the [`EventWriter`] or [`EventReader`] at a time.
15
//! By "temporally" separating them, you avoid the overlap.
16
//!
17
//! In the second case, you only ever have one access to the underlying [`Events`] resource at a time.
18
//! But in exchange, you have to manually keep track of which events you've already read.
19
//!
20
//! Let's look at an example of each.
21
22
use bevy::{diagnostic::FrameCount, ecs::event::EventCursor, prelude::*};
23
24
fn main() {
25
let mut app = App::new();
26
app.add_plugins(MinimalPlugins)
27
.add_event::<DebugEvent>()
28
.add_event::<A>()
29
.add_event::<B>()
30
.add_systems(Update, read_and_write_different_event_types)
31
.add_systems(
32
Update,
33
(
34
send_events,
35
debug_events,
36
send_and_receive_param_set,
37
debug_events,
38
send_and_receive_manual_event_reader,
39
debug_events,
40
)
41
.chain(),
42
);
43
// We're just going to run a few frames, so we can see and understand the output.
44
app.update();
45
// By running for longer than one frame, we can see that we're caching our cursor in the event queue properly.
46
app.update();
47
}
48
49
#[derive(BufferedEvent)]
50
struct A;
51
52
#[derive(BufferedEvent)]
53
struct B;
54
55
// This works fine, because the types are different,
56
// so the borrows of the `EventWriter` and `EventReader` don't overlap.
57
// Note that these borrowing rules are checked at system initialization time,
58
// not at compile time, as Bevy uses internal unsafe code to split the `World` into disjoint pieces.
59
fn read_and_write_different_event_types(mut a: EventWriter<A>, mut b: EventReader<B>) {
60
for _ in b.read() {}
61
a.write(A);
62
}
63
64
/// A dummy event type.
65
#[derive(Debug, Clone, BufferedEvent)]
66
struct DebugEvent {
67
resend_from_param_set: bool,
68
resend_from_local_event_reader: bool,
69
times_sent: u8,
70
}
71
72
/// A system that sends all combinations of events.
73
fn send_events(mut events: EventWriter<DebugEvent>, frame_count: Res<FrameCount>) {
74
println!("Sending events for frame {}", frame_count.0);
75
76
events.write(DebugEvent {
77
resend_from_param_set: false,
78
resend_from_local_event_reader: false,
79
times_sent: 1,
80
});
81
events.write(DebugEvent {
82
resend_from_param_set: true,
83
resend_from_local_event_reader: false,
84
times_sent: 1,
85
});
86
events.write(DebugEvent {
87
resend_from_param_set: false,
88
resend_from_local_event_reader: true,
89
times_sent: 1,
90
});
91
events.write(DebugEvent {
92
resend_from_param_set: true,
93
resend_from_local_event_reader: true,
94
times_sent: 1,
95
});
96
}
97
98
/// A system that prints all events sent since the last time this system ran.
99
///
100
/// Note that some events will be printed twice, because they were sent twice.
101
fn debug_events(mut events: EventReader<DebugEvent>) {
102
for event in events.read() {
103
println!("{event:?}");
104
}
105
}
106
107
/// A system that both sends and receives events using [`ParamSet`].
108
fn send_and_receive_param_set(
109
mut param_set: ParamSet<(EventReader<DebugEvent>, EventWriter<DebugEvent>)>,
110
frame_count: Res<FrameCount>,
111
) {
112
println!(
113
"Sending and receiving events for frame {} with a `ParamSet`",
114
frame_count.0
115
);
116
117
// We must collect the events to resend, because we can't access the writer while we're iterating over the reader.
118
let mut events_to_resend = Vec::new();
119
120
// This is p0, as the first parameter in the `ParamSet` is the reader.
121
for event in param_set.p0().read() {
122
if event.resend_from_param_set {
123
events_to_resend.push(event.clone());
124
}
125
}
126
127
// This is p1, as the second parameter in the `ParamSet` is the writer.
128
for mut event in events_to_resend {
129
event.times_sent += 1;
130
param_set.p1().write(event);
131
}
132
}
133
134
/// A system that both sends and receives events using a [`Local`] [`EventCursor`].
135
fn send_and_receive_manual_event_reader(
136
// The `Local` `SystemParam` stores state inside the system itself, rather than in the world.
137
// `EventCursor<T>` is the internal state of `EventReader<T>`, which tracks which events have been seen.
138
mut local_event_reader: Local<EventCursor<DebugEvent>>,
139
// We can access the `Events` resource mutably, allowing us to both read and write its contents.
140
mut events: ResMut<Events<DebugEvent>>,
141
frame_count: Res<FrameCount>,
142
) {
143
println!(
144
"Sending and receiving events for frame {} with a `Local<EventCursor>",
145
frame_count.0
146
);
147
148
// We must collect the events to resend, because we can't mutate events while we're iterating over the events.
149
let mut events_to_resend = Vec::new();
150
151
for event in local_event_reader.read(&events) {
152
if event.resend_from_local_event_reader {
153
// For simplicity, we're cloning the event.
154
// In this case, since we have mutable access to the `Events` resource,
155
// we could also just mutate the event in-place,
156
// or drain the event queue into our `events_to_resend` vector.
157
events_to_resend.push(event.clone());
158
}
159
}
160
161
for mut event in events_to_resend {
162
event.times_sent += 1;
163
events.write(event);
164
}
165
}
166
167