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