2024-06-10 21:45:01 +00:00
|
|
|
//! Event handling types.
|
|
|
|
mod base;
|
|
|
|
mod collections;
|
2024-07-08 14:53:06 +00:00
|
|
|
mod event_cursor;
|
2024-06-10 21:45:01 +00:00
|
|
|
mod iterators;
|
2024-07-08 14:53:06 +00:00
|
|
|
mod mut_iterators;
|
|
|
|
mod mutator;
|
2024-06-10 21:45:01 +00:00
|
|
|
mod reader;
|
|
|
|
mod registry;
|
Commands::send_event (#14933)
# Objective
sending events tends to be low-frequency so ergonomics can be
prioritized over efficiency.
add `Commands::send_event` to send any type of event without needing a
writer in hand.
i don't know how we feel about these kind of ergonomic things, i add
this to all my projects and find it useful. adding `mut
this_particular_event_writer: EventWriter<ThisParticularEvent>` every
time i want to send something is unnecessarily cumbersome.
it also simplifies the "send and receive in the same system" pattern
significantly.
basic example before:
```rs
fn my_func(
q: Query<(Entity, &State)>,
mut damage_event_writer: EventWriter<DamageEvent>,
mut heal_event_writer: EventWriter<HealEvent>,
) {
for (entity, state) in q.iter() {
if let Some(damage) = state.get_damage() {
damage_event_writer.send(DamageEvent { entity, damage });
}
if let Some(heal) = state.get_heal() {
heal_event_writer.send(HealEvent { entity, heal });
}
}
}
```
basic example after:
```rs
import bevy::ecs::event::SendEventEx;
fn my_func(
mut commands: Commands,
q: Query<(Entity, &State)>,
) {
for (entity, state) in q.iter() {
if let Some(damage) = state.get_damage() {
commands.send_event(DamageEvent { entity, damage });
}
if let Some(heal) = state.get_heal() {
commands.send_event(HealEvent { entity, heal });
}
}
}
```
send/receive in the same system before:
```rs
fn send_and_receive_param_set(
mut param_set: ParamSet<(EventReader<DebugEvent>, EventWriter<DebugEvent>)>,
) {
// 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);
}
}
```
after:
```rs
use bevy::ecs::event::SendEventEx;
fn send_via_commands_and_receive(
mut reader: EventReader<DebugEvent>,
mut commands: Commands,
) {
for event in reader.read() {
if event.resend_via_commands {
commands.send_event(DebugEvent {
times_sent: event.times_sent + 1,
..event.clone()
});
}
}
}
```
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2024-08-27 23:43:40 +00:00
|
|
|
mod send_event;
|
2024-06-10 21:45:01 +00:00
|
|
|
mod update;
|
|
|
|
mod writer;
|
|
|
|
|
|
|
|
pub(crate) use base::EventInstance;
|
|
|
|
pub use base::{Event, EventId};
|
|
|
|
pub use bevy_ecs_macros::Event;
|
|
|
|
pub use collections::{Events, SendBatchIds};
|
2024-07-08 14:53:06 +00:00
|
|
|
pub use event_cursor::EventCursor;
|
2024-06-25 15:36:06 +00:00
|
|
|
#[cfg(feature = "multi_threaded")]
|
|
|
|
pub use iterators::EventParIter;
|
|
|
|
pub use iterators::{EventIterator, EventIteratorWithId};
|
2024-07-08 14:53:06 +00:00
|
|
|
#[cfg(feature = "multi_threaded")]
|
|
|
|
pub use mut_iterators::EventMutParIter;
|
|
|
|
pub use mut_iterators::{EventMutIterator, EventMutIteratorWithId};
|
|
|
|
pub use mutator::EventMutator;
|
|
|
|
pub use reader::EventReader;
|
Ensure that events are updated even when using a bare-bones Bevy App (#13808)
# Objective
As discovered in
https://github.com/Leafwing-Studios/leafwing-input-manager/issues/538,
there appears to be some real weirdness going on in how event updates
are processed between Bevy 0.13 and Bevy 0.14.
To identify the cause and prevent regression, I've added tests to
validate the intended behavior.
My initial suspicion was that this would be fixed by
https://github.com/bevyengine/bevy/pull/13762, but that doesn't seem to
be the case.
Instead, events appear to never be updated at all when using `bevy_app`
by itself. This is part of the problem resolved by
https://github.com/bevyengine/bevy/pull/11528, and introduced by
https://github.com/bevyengine/bevy/pull/10077.
After some investigation, it appears that `signal_event_update_system`
is never added using a bare-bones `App`, and so event updates are always
skipped.
This can be worked around by adding your own copy to a
later-in-the-frame schedule, but that's not a very good fix.
## Solution
Ensure that if we're not using a `FixedUpdate` schedule, events are
always updated every frame.
To do this, I've modified the logic of `event_update_condition` and
`event_update_system` to clearly and correctly differentiate between the
two cases: where we're waiting for a "you should update now" signal and
where we simply don't care.
To encode this, I've added the `ShouldUpdateEvents` enum, replacing a
simple `bool` in `EventRegistry`'s `needs_update` field.
Now, both tests pass as expected, without having to manually add a
system!
## Testing
I've written two parallel unit tests to cover the intended behavior:
1. Test that `iter_current_update_events` works as expected in
`bevy_ecs`.
2. Test that `iter_current_update_events` works as expected in
`bevy_app`
I've also added a test to verify that event updating works correctly in
the presence of a fixed main schedule, and a second test to verify that
fixed updating works at all to help future authors narrow down failures.
## Outstanding
- [x] figure out why the `bevy_app` version of this test fails but the
`bevy_ecs` version does not
- [x] figure out why `EventRegistry::run_updates` isn't working properly
- [x] figure out why `EventRegistry::run_updates` is never getting
called
- [x] figure out why `event_update_condition` is always returning false
- [x] figure out why `EventRegistry::needs_update` is always false
- [x] verify that the problem is a missing `signal_events_update_system`
---------
Co-authored-by: Mike <mike.hsu@gmail.com>
2024-06-12 14:28:51 +00:00
|
|
|
pub use registry::{EventRegistry, ShouldUpdateEvents};
|
Commands::send_event (#14933)
# Objective
sending events tends to be low-frequency so ergonomics can be
prioritized over efficiency.
add `Commands::send_event` to send any type of event without needing a
writer in hand.
i don't know how we feel about these kind of ergonomic things, i add
this to all my projects and find it useful. adding `mut
this_particular_event_writer: EventWriter<ThisParticularEvent>` every
time i want to send something is unnecessarily cumbersome.
it also simplifies the "send and receive in the same system" pattern
significantly.
basic example before:
```rs
fn my_func(
q: Query<(Entity, &State)>,
mut damage_event_writer: EventWriter<DamageEvent>,
mut heal_event_writer: EventWriter<HealEvent>,
) {
for (entity, state) in q.iter() {
if let Some(damage) = state.get_damage() {
damage_event_writer.send(DamageEvent { entity, damage });
}
if let Some(heal) = state.get_heal() {
heal_event_writer.send(HealEvent { entity, heal });
}
}
}
```
basic example after:
```rs
import bevy::ecs::event::SendEventEx;
fn my_func(
mut commands: Commands,
q: Query<(Entity, &State)>,
) {
for (entity, state) in q.iter() {
if let Some(damage) = state.get_damage() {
commands.send_event(DamageEvent { entity, damage });
}
if let Some(heal) = state.get_heal() {
commands.send_event(HealEvent { entity, heal });
}
}
}
```
send/receive in the same system before:
```rs
fn send_and_receive_param_set(
mut param_set: ParamSet<(EventReader<DebugEvent>, EventWriter<DebugEvent>)>,
) {
// 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);
}
}
```
after:
```rs
use bevy::ecs::event::SendEventEx;
fn send_via_commands_and_receive(
mut reader: EventReader<DebugEvent>,
mut commands: Commands,
) {
for event in reader.read() {
if event.resend_via_commands {
commands.send_event(DebugEvent {
times_sent: event.times_sent + 1,
..event.clone()
});
}
}
}
```
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2024-08-27 23:43:40 +00:00
|
|
|
pub use send_event::SendEvent;
|
2024-06-10 21:45:01 +00:00
|
|
|
pub use update::{
|
|
|
|
event_update_condition, event_update_system, signal_event_update_system, EventUpdates,
|
|
|
|
};
|
|
|
|
pub use writer::EventWriter;
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use crate as bevy_ecs;
|
|
|
|
use bevy_ecs::{event::*, system::assert_is_read_only_system};
|
|
|
|
use bevy_ecs_macros::Event;
|
|
|
|
|
|
|
|
#[derive(Event, Copy, Clone, PartialEq, Eq, Debug)]
|
|
|
|
struct TestEvent {
|
|
|
|
i: usize,
|
|
|
|
}
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
#[derive(Event, Clone, PartialEq, Debug, Default)]
|
|
|
|
struct EmptyTestEvent;
|
|
|
|
|
|
|
|
fn get_events<E: Event + Clone>(events: &Events<E>, cursor: &mut EventCursor<E>) -> Vec<E> {
|
|
|
|
cursor.read(events).cloned().collect::<Vec<E>>()
|
|
|
|
}
|
|
|
|
|
2024-06-10 21:45:01 +00:00
|
|
|
#[test]
|
|
|
|
fn test_events() {
|
|
|
|
let mut events = Events::<TestEvent>::default();
|
|
|
|
let event_0 = TestEvent { i: 0 };
|
|
|
|
let event_1 = TestEvent { i: 1 };
|
|
|
|
let event_2 = TestEvent { i: 2 };
|
|
|
|
|
|
|
|
// this reader will miss event_0 and event_1 because it wont read them over the course of
|
|
|
|
// two updates
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut reader_missed: EventCursor<TestEvent> = events.get_cursor();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut reader_a: EventCursor<TestEvent> = events.get_cursor();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
|
|
|
events.send(event_0);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_a),
|
|
|
|
vec![event_0],
|
|
|
|
"reader_a created before event receives event"
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_a),
|
|
|
|
vec![],
|
|
|
|
"second iteration of reader_a created before event results in zero events"
|
|
|
|
);
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut reader_b: EventCursor<TestEvent> = events.get_cursor();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_b),
|
|
|
|
vec![event_0],
|
|
|
|
"reader_b created after event receives event"
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_b),
|
|
|
|
vec![],
|
|
|
|
"second iteration of reader_b created after event results in zero events"
|
|
|
|
);
|
|
|
|
|
|
|
|
events.send(event_1);
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut reader_c = events.get_cursor();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_c),
|
|
|
|
vec![event_0, event_1],
|
|
|
|
"reader_c created after two events receives both events"
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_c),
|
|
|
|
vec![],
|
|
|
|
"second iteration of reader_c created after two event results in zero events"
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_a),
|
|
|
|
vec![event_1],
|
|
|
|
"reader_a receives next unread event"
|
|
|
|
);
|
|
|
|
|
|
|
|
events.update();
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut reader_d = events.get_cursor();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
|
|
|
events.send(event_2);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_a),
|
|
|
|
vec![event_2],
|
|
|
|
"reader_a receives event created after update"
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_b),
|
|
|
|
vec![event_1, event_2],
|
|
|
|
"reader_b receives events created before and after update"
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_d),
|
|
|
|
vec![event_0, event_1, event_2],
|
|
|
|
"reader_d receives all events created before and after update"
|
|
|
|
);
|
|
|
|
|
|
|
|
events.update();
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
get_events(&events, &mut reader_missed),
|
|
|
|
vec![event_2],
|
|
|
|
"reader_missed missed events unread after two update() calls"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
// Events Collection
|
|
|
|
fn events_clear_and_read_impl(clear_func: impl FnOnce(&mut Events<TestEvent>)) {
|
|
|
|
let mut events = Events::<TestEvent>::default();
|
|
|
|
let mut reader = events.get_cursor();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
|
|
|
assert!(reader.read(&events).next().is_none());
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
events.send(TestEvent { i: 0 });
|
|
|
|
assert_eq!(*reader.read(&events).next().unwrap(), TestEvent { i: 0 });
|
2024-06-10 21:45:01 +00:00
|
|
|
assert_eq!(reader.read(&events).next(), None);
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
events.send(TestEvent { i: 1 });
|
2024-06-10 21:45:01 +00:00
|
|
|
clear_func(&mut events);
|
|
|
|
assert!(reader.read(&events).next().is_none());
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
events.send(TestEvent { i: 2 });
|
2024-06-10 21:45:01 +00:00
|
|
|
events.update();
|
2024-07-08 14:53:06 +00:00
|
|
|
events.send(TestEvent { i: 3 });
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
assert!(reader
|
|
|
|
.read(&events)
|
|
|
|
.eq([TestEvent { i: 2 }, TestEvent { i: 3 }].iter()));
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_events_clear_and_read() {
|
2024-07-01 15:54:40 +00:00
|
|
|
events_clear_and_read_impl(Events::clear);
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_events_drain_and_read() {
|
|
|
|
events_clear_and_read_impl(|events| {
|
2024-07-08 14:53:06 +00:00
|
|
|
assert!(events
|
|
|
|
.drain()
|
|
|
|
.eq(vec![TestEvent { i: 0 }, TestEvent { i: 1 }].into_iter()));
|
2024-06-10 21:45:01 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_events_send_default() {
|
|
|
|
let mut events = Events::<EmptyTestEvent>::default();
|
|
|
|
events.send_default();
|
|
|
|
|
|
|
|
let mut reader = events.get_cursor();
|
|
|
|
assert_eq!(get_events(&events, &mut reader), vec![EmptyTestEvent]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_send_events_ids() {
|
2024-06-10 21:45:01 +00:00
|
|
|
let mut events = Events::<TestEvent>::default();
|
2024-07-08 14:53:06 +00:00
|
|
|
let event_0 = TestEvent { i: 0 };
|
|
|
|
let event_1 = TestEvent { i: 1 };
|
|
|
|
let event_2 = TestEvent { i: 2 };
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let event_0_id = events.send(event_0);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
events.get_event(event_0_id.id),
|
|
|
|
Some((&event_0, event_0_id)),
|
|
|
|
"Getting a sent event by ID should return the original event"
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut event_ids = events.send_batch([event_1, event_2]);
|
|
|
|
|
|
|
|
let event_id = event_ids.next().expect("Event 1 must have been sent");
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
events.get_event(event_id.id),
|
|
|
|
Some((&event_1, event_id)),
|
|
|
|
"Getting a sent event by ID should return the original event"
|
|
|
|
);
|
|
|
|
|
|
|
|
let event_id = event_ids.next().expect("Event 2 must have been sent");
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
events.get_event(event_id.id),
|
|
|
|
Some((&event_2, event_id)),
|
|
|
|
"Getting a sent event by ID should return the original event"
|
|
|
|
);
|
|
|
|
|
|
|
|
assert!(
|
|
|
|
event_ids.next().is_none(),
|
|
|
|
"Only sent two events; got more than two IDs"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_event_registry_can_add_and_remove_events_to_world() {
|
|
|
|
use bevy_ecs::prelude::*;
|
|
|
|
|
|
|
|
let mut world = World::new();
|
|
|
|
EventRegistry::register_event::<TestEvent>(&mut world);
|
|
|
|
|
|
|
|
let has_events = world.get_resource::<Events<TestEvent>>().is_some();
|
|
|
|
assert!(has_events, "Should have the events resource");
|
|
|
|
|
|
|
|
EventRegistry::deregister_events::<TestEvent>(&mut world);
|
|
|
|
|
|
|
|
let has_events = world.get_resource::<Events<TestEvent>>().is_some();
|
|
|
|
assert!(!has_events, "Should not have the events resource");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_events_update_drain() {
|
|
|
|
let mut events = Events::<TestEvent>::default();
|
|
|
|
let mut reader = events.get_cursor();
|
|
|
|
|
|
|
|
events.send(TestEvent { i: 0 });
|
|
|
|
events.send(TestEvent { i: 1 });
|
|
|
|
assert_eq!(reader.read(&events).count(), 2);
|
|
|
|
|
|
|
|
let mut old_events = Vec::from_iter(events.update_drain());
|
|
|
|
assert!(old_events.is_empty());
|
|
|
|
|
|
|
|
events.send(TestEvent { i: 2 });
|
|
|
|
assert_eq!(reader.read(&events).count(), 1);
|
|
|
|
|
|
|
|
old_events.extend(events.update_drain());
|
|
|
|
assert_eq!(old_events.len(), 2);
|
|
|
|
|
|
|
|
old_events.extend(events.update_drain());
|
|
|
|
assert_eq!(
|
|
|
|
old_events,
|
|
|
|
&[TestEvent { i: 0 }, TestEvent { i: 1 }, TestEvent { i: 2 }]
|
|
|
|
);
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_events_empty() {
|
|
|
|
let mut events = Events::<TestEvent>::default();
|
|
|
|
assert!(events.is_empty());
|
|
|
|
|
|
|
|
events.send(TestEvent { i: 0 });
|
|
|
|
assert!(!events.is_empty());
|
|
|
|
|
|
|
|
events.update();
|
|
|
|
assert!(!events.is_empty());
|
|
|
|
|
|
|
|
// events are only empty after the second call to update
|
|
|
|
// due to double buffering.
|
|
|
|
events.update();
|
|
|
|
assert!(events.is_empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_events_extend_impl() {
|
|
|
|
let mut events = Events::<TestEvent>::default();
|
|
|
|
let mut reader = events.get_cursor();
|
|
|
|
|
|
|
|
events.extend(vec![TestEvent { i: 0 }, TestEvent { i: 1 }]);
|
|
|
|
assert!(reader
|
|
|
|
.read(&events)
|
|
|
|
.eq([TestEvent { i: 0 }, TestEvent { i: 1 }].iter()));
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
// Cursor
|
2024-06-10 21:45:01 +00:00
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_cursor_read() {
|
2024-06-10 21:45:01 +00:00
|
|
|
let mut events = Events::<TestEvent>::default();
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut cursor = events.get_cursor();
|
|
|
|
assert!(cursor.read(&events).next().is_none());
|
|
|
|
|
2024-06-10 21:45:01 +00:00
|
|
|
events.send(TestEvent { i: 0 });
|
2024-07-08 14:53:06 +00:00
|
|
|
let sent_event = cursor.read(&events).next().unwrap();
|
|
|
|
assert_eq!(sent_event, &TestEvent { i: 0 });
|
|
|
|
assert!(cursor.read(&events).next().is_none());
|
|
|
|
|
|
|
|
events.send(TestEvent { i: 2 });
|
|
|
|
let sent_event = cursor.read(&events).next().unwrap();
|
|
|
|
assert_eq!(sent_event, &TestEvent { i: 2 });
|
|
|
|
assert!(cursor.read(&events).next().is_none());
|
|
|
|
|
|
|
|
events.clear();
|
|
|
|
assert!(cursor.read(&events).next().is_none());
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_cursor_read_mut() {
|
2024-06-10 21:45:01 +00:00
|
|
|
let mut events = Events::<TestEvent>::default();
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut write_cursor = events.get_cursor();
|
|
|
|
let mut read_cursor = events.get_cursor();
|
|
|
|
assert!(write_cursor.read_mut(&mut events).next().is_none());
|
|
|
|
assert!(read_cursor.read(&events).next().is_none());
|
|
|
|
|
2024-06-10 21:45:01 +00:00
|
|
|
events.send(TestEvent { i: 0 });
|
2024-07-08 14:53:06 +00:00
|
|
|
let sent_event = write_cursor.read_mut(&mut events).next().unwrap();
|
|
|
|
assert_eq!(sent_event, &mut TestEvent { i: 0 });
|
|
|
|
*sent_event = TestEvent { i: 1 }; // Mutate whole event
|
|
|
|
assert_eq!(
|
|
|
|
read_cursor.read(&events).next().unwrap(),
|
|
|
|
&TestEvent { i: 1 }
|
|
|
|
);
|
|
|
|
assert!(read_cursor.read(&events).next().is_none());
|
|
|
|
|
2024-06-10 21:45:01 +00:00
|
|
|
events.send(TestEvent { i: 2 });
|
2024-07-08 14:53:06 +00:00
|
|
|
let sent_event = write_cursor.read_mut(&mut events).next().unwrap();
|
|
|
|
assert_eq!(sent_event, &mut TestEvent { i: 2 });
|
|
|
|
sent_event.i = 3; // Mutate sub value
|
|
|
|
assert_eq!(
|
|
|
|
read_cursor.read(&events).next().unwrap(),
|
|
|
|
&TestEvent { i: 3 }
|
|
|
|
);
|
|
|
|
assert!(read_cursor.read(&events).next().is_none());
|
|
|
|
|
|
|
|
events.clear();
|
|
|
|
assert!(write_cursor.read(&events).next().is_none());
|
|
|
|
assert!(read_cursor.read(&events).next().is_none());
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_cursor_clear() {
|
2024-06-10 21:45:01 +00:00
|
|
|
let mut events = Events::<TestEvent>::default();
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut reader = events.get_cursor();
|
|
|
|
|
2024-06-10 21:45:01 +00:00
|
|
|
events.send(TestEvent { i: 0 });
|
|
|
|
assert_eq!(reader.len(&events), 1);
|
2024-07-08 14:53:06 +00:00
|
|
|
reader.clear(&events);
|
|
|
|
assert_eq!(reader.len(&events), 0);
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_cursor_len_update() {
|
2024-06-10 21:45:01 +00:00
|
|
|
let mut events = Events::<TestEvent>::default();
|
|
|
|
events.send(TestEvent { i: 0 });
|
|
|
|
events.send(TestEvent { i: 0 });
|
2024-07-08 14:53:06 +00:00
|
|
|
let reader = events.get_cursor();
|
2024-06-10 21:45:01 +00:00
|
|
|
assert_eq!(reader.len(&events), 2);
|
|
|
|
events.update();
|
|
|
|
events.send(TestEvent { i: 0 });
|
|
|
|
assert_eq!(reader.len(&events), 3);
|
|
|
|
events.update();
|
|
|
|
assert_eq!(reader.len(&events), 1);
|
|
|
|
events.update();
|
|
|
|
assert!(reader.is_empty(&events));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_cursor_len_current() {
|
2024-06-10 21:45:01 +00:00
|
|
|
let mut events = Events::<TestEvent>::default();
|
|
|
|
events.send(TestEvent { i: 0 });
|
2024-07-08 14:53:06 +00:00
|
|
|
let reader = events.get_cursor_current();
|
|
|
|
assert!(reader.is_empty(&events));
|
|
|
|
events.send(TestEvent { i: 0 });
|
|
|
|
assert_eq!(reader.len(&events), 1);
|
|
|
|
assert!(!reader.is_empty(&events));
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
2024-07-01 16:18:14 +00:00
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_cursor_iter_len_updated() {
|
|
|
|
let mut events = Events::<TestEvent>::default();
|
|
|
|
events.send(TestEvent { i: 0 });
|
|
|
|
events.send(TestEvent { i: 1 });
|
|
|
|
events.send(TestEvent { i: 2 });
|
|
|
|
let mut reader = events.get_cursor();
|
|
|
|
let mut iter = reader.read(&events);
|
|
|
|
assert_eq!(iter.len(), 3);
|
|
|
|
iter.next();
|
|
|
|
assert_eq!(iter.len(), 2);
|
|
|
|
iter.next();
|
|
|
|
assert_eq!(iter.len(), 1);
|
|
|
|
iter.next();
|
|
|
|
assert_eq!(iter.len(), 0);
|
|
|
|
}
|
2024-07-01 16:18:14 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
#[test]
|
|
|
|
fn test_event_cursor_len_empty() {
|
|
|
|
let events = Events::<TestEvent>::default();
|
|
|
|
assert_eq!(events.get_cursor().len(&events), 0);
|
|
|
|
assert!(events.get_cursor().is_empty(&events));
|
2024-07-01 16:18:14 +00:00
|
|
|
}
|
|
|
|
|
2024-06-10 21:45:01 +00:00
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_cursor_len_filled() {
|
2024-06-10 21:45:01 +00:00
|
|
|
let mut events = Events::<TestEvent>::default();
|
|
|
|
events.send(TestEvent { i: 0 });
|
2024-07-08 14:53:06 +00:00
|
|
|
assert_eq!(events.get_cursor().len(&events), 1);
|
|
|
|
assert!(!events.get_cursor().is_empty(&events));
|
|
|
|
}
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
#[cfg(feature = "multi_threaded")]
|
|
|
|
#[test]
|
|
|
|
fn test_event_cursor_par_read() {
|
|
|
|
use crate::prelude::*;
|
2024-09-27 00:59:59 +00:00
|
|
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
#[derive(Resource)]
|
|
|
|
struct Counter(AtomicUsize);
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Events<TestEvent>>();
|
|
|
|
for _ in 0..100 {
|
|
|
|
world.send_event(TestEvent { i: 1 });
|
|
|
|
}
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut schedule = Schedule::default();
|
|
|
|
|
|
|
|
schedule.add_systems(
|
|
|
|
|mut cursor: Local<EventCursor<TestEvent>>,
|
|
|
|
events: Res<Events<TestEvent>>,
|
|
|
|
counter: ResMut<Counter>| {
|
|
|
|
cursor.par_read(&events).for_each(|event| {
|
|
|
|
counter.0.fetch_add(event.i, Ordering::Relaxed);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
world.insert_resource(Counter(AtomicUsize::new(0)));
|
|
|
|
schedule.run(&mut world);
|
|
|
|
let counter = world.remove_resource::<Counter>().unwrap();
|
|
|
|
assert_eq!(counter.0.into_inner(), 100);
|
|
|
|
|
|
|
|
world.insert_resource(Counter(AtomicUsize::new(0)));
|
|
|
|
schedule.run(&mut world);
|
|
|
|
let counter = world.remove_resource::<Counter>().unwrap();
|
2024-06-10 21:45:01 +00:00
|
|
|
assert_eq!(
|
2024-07-08 14:53:06 +00:00
|
|
|
counter.0.into_inner(),
|
|
|
|
0,
|
|
|
|
"par_read should have consumed events but didn't"
|
2024-06-10 21:45:01 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
#[cfg(feature = "multi_threaded")]
|
2024-06-10 21:45:01 +00:00
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_cursor_par_read_mut() {
|
|
|
|
use crate::prelude::*;
|
2024-09-27 00:59:59 +00:00
|
|
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
2024-07-08 14:53:06 +00:00
|
|
|
|
|
|
|
#[derive(Resource)]
|
|
|
|
struct Counter(AtomicUsize);
|
2024-06-10 21:45:01 +00:00
|
|
|
|
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Events<TestEvent>>();
|
2024-07-08 14:53:06 +00:00
|
|
|
for _ in 0..100 {
|
|
|
|
world.send_event(TestEvent { i: 1 });
|
|
|
|
}
|
2024-06-10 21:45:01 +00:00
|
|
|
let mut schedule = Schedule::default();
|
2024-07-08 14:53:06 +00:00
|
|
|
schedule.add_systems(
|
|
|
|
|mut cursor: Local<EventCursor<TestEvent>>,
|
|
|
|
mut events: ResMut<Events<TestEvent>>,
|
|
|
|
counter: ResMut<Counter>| {
|
|
|
|
cursor.par_read_mut(&mut events).for_each(|event| {
|
|
|
|
event.i += 1;
|
|
|
|
counter.0.fetch_add(event.i, Ordering::Relaxed);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
);
|
|
|
|
world.insert_resource(Counter(AtomicUsize::new(0)));
|
|
|
|
schedule.run(&mut world);
|
|
|
|
let counter = world.remove_resource::<Counter>().unwrap();
|
|
|
|
assert_eq!(counter.0.into_inner(), 200, "Initial run failed");
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
world.insert_resource(Counter(AtomicUsize::new(0)));
|
2024-06-10 21:45:01 +00:00
|
|
|
schedule.run(&mut world);
|
2024-07-08 14:53:06 +00:00
|
|
|
let counter = world.remove_resource::<Counter>().unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
counter.0.into_inner(),
|
|
|
|
0,
|
|
|
|
"par_read_mut should have consumed events but didn't"
|
|
|
|
);
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
// Reader & Mutator
|
2024-06-10 21:45:01 +00:00
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn ensure_reader_readonly() {
|
|
|
|
fn reader_system(_: EventReader<EmptyTestEvent>) {}
|
|
|
|
|
|
|
|
assert_is_read_only_system(reader_system);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_event_reader_iter_last() {
|
2024-06-10 21:45:01 +00:00
|
|
|
use bevy_ecs::prelude::*;
|
|
|
|
|
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Events<TestEvent>>();
|
|
|
|
|
|
|
|
let mut reader =
|
|
|
|
IntoSystem::into_system(|mut events: EventReader<TestEvent>| -> Option<TestEvent> {
|
|
|
|
events.read().last().copied()
|
|
|
|
});
|
|
|
|
reader.initialize(&mut world);
|
|
|
|
|
|
|
|
let last = reader.run((), &mut world);
|
|
|
|
assert!(last.is_none(), "EventReader should be empty");
|
|
|
|
|
|
|
|
world.send_event(TestEvent { i: 0 });
|
|
|
|
let last = reader.run((), &mut world);
|
|
|
|
assert_eq!(last, Some(TestEvent { i: 0 }));
|
|
|
|
|
|
|
|
world.send_event(TestEvent { i: 1 });
|
|
|
|
world.send_event(TestEvent { i: 2 });
|
|
|
|
world.send_event(TestEvent { i: 3 });
|
|
|
|
let last = reader.run((), &mut world);
|
|
|
|
assert_eq!(last, Some(TestEvent { i: 3 }));
|
|
|
|
|
|
|
|
let last = reader.run((), &mut world);
|
|
|
|
assert!(last.is_none(), "EventReader should be empty");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_mutator_iter_last() {
|
|
|
|
use bevy_ecs::prelude::*;
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Events<TestEvent>>();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut mutator =
|
|
|
|
IntoSystem::into_system(|mut events: EventMutator<TestEvent>| -> Option<TestEvent> {
|
|
|
|
events.read().last().copied()
|
|
|
|
});
|
|
|
|
mutator.initialize(&mut world);
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let last = mutator.run((), &mut world);
|
|
|
|
assert!(last.is_none(), "EventMutator should be empty");
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
world.send_event(TestEvent { i: 0 });
|
|
|
|
let last = mutator.run((), &mut world);
|
|
|
|
assert_eq!(last, Some(TestEvent { i: 0 }));
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
world.send_event(TestEvent { i: 1 });
|
|
|
|
world.send_event(TestEvent { i: 2 });
|
|
|
|
world.send_event(TestEvent { i: 3 });
|
|
|
|
let last = mutator.run((), &mut world);
|
|
|
|
assert_eq!(last, Some(TestEvent { i: 3 }));
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let last = mutator.run((), &mut world);
|
|
|
|
assert!(last.is_none(), "EventMutator should be empty");
|
|
|
|
}
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
#[allow(clippy::iter_nth_zero)]
|
|
|
|
#[test]
|
|
|
|
fn test_event_reader_iter_nth() {
|
|
|
|
use bevy_ecs::prelude::*;
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Events<TestEvent>>();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
world.send_event(TestEvent { i: 0 });
|
|
|
|
world.send_event(TestEvent { i: 1 });
|
|
|
|
world.send_event(TestEvent { i: 2 });
|
|
|
|
world.send_event(TestEvent { i: 3 });
|
|
|
|
world.send_event(TestEvent { i: 4 });
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
let mut schedule = Schedule::default();
|
|
|
|
schedule.add_systems(|mut events: EventReader<TestEvent>| {
|
|
|
|
let mut iter = events.read();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
|
|
|
|
assert_eq!(iter.nth(2), Some(&TestEvent { i: 3 }));
|
|
|
|
assert_eq!(iter.nth(1), None);
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
assert!(events.is_empty());
|
|
|
|
});
|
|
|
|
schedule.run(&mut world);
|
2024-06-10 21:45:01 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
#[allow(clippy::iter_nth_zero)]
|
2024-06-10 21:45:01 +00:00
|
|
|
#[test]
|
2024-07-08 14:53:06 +00:00
|
|
|
fn test_event_mutator_iter_nth() {
|
|
|
|
use bevy_ecs::prelude::*;
|
2024-06-10 21:45:01 +00:00
|
|
|
|
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Events<TestEvent>>();
|
2024-07-08 14:53:06 +00:00
|
|
|
|
|
|
|
world.send_event(TestEvent { i: 0 });
|
|
|
|
world.send_event(TestEvent { i: 1 });
|
|
|
|
world.send_event(TestEvent { i: 2 });
|
|
|
|
world.send_event(TestEvent { i: 3 });
|
|
|
|
world.send_event(TestEvent { i: 4 });
|
|
|
|
|
2024-06-10 21:45:01 +00:00
|
|
|
let mut schedule = Schedule::default();
|
2024-07-08 14:53:06 +00:00
|
|
|
schedule.add_systems(|mut events: EventReader<TestEvent>| {
|
|
|
|
let mut iter = events.read();
|
2024-06-10 21:45:01 +00:00
|
|
|
|
2024-07-08 14:53:06 +00:00
|
|
|
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
|
|
|
|
assert_eq!(iter.nth(2), Some(&TestEvent { i: 3 }));
|
|
|
|
assert_eq!(iter.nth(1), None);
|
|
|
|
|
|
|
|
assert!(events.is_empty());
|
|
|
|
});
|
2024-06-10 21:45:01 +00:00
|
|
|
schedule.run(&mut world);
|
|
|
|
}
|
|
|
|
}
|