#[cfg(feature = "multi_threaded")]1use bevy_ecs::event::EventParIter;2use bevy_ecs::{3event::{BufferedEvent, EventCursor, EventIterator, EventIteratorWithId, Events},4system::{Local, Res, SystemParam},5};67/// Reads [`BufferedEvent`]s of type `T` in order and tracks which events have already been read.8///9/// # Concurrency10///11/// Unlike [`EventWriter<T>`], systems with `EventReader<T>` param can be executed concurrently12/// (but not concurrently with `EventWriter<T>` or `EventMutator<T>` systems for the same event type).13///14/// [`EventWriter<T>`]: super::EventWriter15#[derive(SystemParam, Debug)]16pub struct EventReader<'w, 's, E: BufferedEvent> {17pub(super) reader: Local<'s, EventCursor<E>>,18#[system_param(validation_message = "BufferedEvent not initialized")]19events: Res<'w, Events<E>>,20}2122impl<'w, 's, E: BufferedEvent> EventReader<'w, 's, E> {23/// Iterates over the events this [`EventReader`] has not seen yet. This updates the24/// [`EventReader`]'s event counter, which means subsequent event reads will not include events25/// that happened before now.26pub fn read(&mut self) -> EventIterator<'_, E> {27self.reader.read(&self.events)28}2930/// Like [`read`](Self::read), except also returning the [`EventId`](super::EventId) of the events.31pub fn read_with_id(&mut self) -> EventIteratorWithId<'_, E> {32self.reader.read_with_id(&self.events)33}3435/// Returns a parallel iterator over the events this [`EventReader`] has not seen yet.36/// See also [`for_each`](EventParIter::for_each).37///38/// # Example39/// ```40/// # use bevy_ecs::prelude::*;41/// # use std::sync::atomic::{AtomicUsize, Ordering};42///43/// #[derive(BufferedEvent)]44/// struct MyEvent {45/// value: usize,46/// }47///48/// #[derive(Resource, Default)]49/// struct Counter(AtomicUsize);50///51/// // setup52/// let mut world = World::new();53/// world.init_resource::<Events<MyEvent>>();54/// world.insert_resource(Counter::default());55///56/// let mut schedule = Schedule::default();57/// schedule.add_systems(|mut events: EventReader<MyEvent>, counter: Res<Counter>| {58/// events.par_read().for_each(|MyEvent { value }| {59/// counter.0.fetch_add(*value, Ordering::Relaxed);60/// });61/// });62/// for value in 0..100 {63/// world.write_event(MyEvent { value });64/// }65/// schedule.run(&mut world);66/// let Counter(counter) = world.remove_resource::<Counter>().unwrap();67/// // all events were processed68/// assert_eq!(counter.into_inner(), 4950);69/// ```70#[cfg(feature = "multi_threaded")]71pub fn par_read(&mut self) -> EventParIter<'_, E> {72self.reader.par_read(&self.events)73}7475/// Determines the number of events available to be read from this [`EventReader`] without consuming any.76pub fn len(&self) -> usize {77self.reader.len(&self.events)78}7980/// Returns `true` if there are no events available to read.81///82/// # Example83///84/// The following example shows a useful pattern where some behavior is triggered if new events are available.85/// [`EventReader::clear()`] is used so the same events don't re-trigger the behavior the next time the system runs.86///87/// ```88/// # use bevy_ecs::prelude::*;89/// #90/// #[derive(BufferedEvent)]91/// struct CollisionEvent;92///93/// fn play_collision_sound(mut events: EventReader<CollisionEvent>) {94/// if !events.is_empty() {95/// events.clear();96/// // Play a sound97/// }98/// }99/// # bevy_ecs::system::assert_is_system(play_collision_sound);100/// ```101pub fn is_empty(&self) -> bool {102self.reader.is_empty(&self.events)103}104105/// Consumes all available events.106///107/// This means these events will not appear in calls to [`EventReader::read()`] or108/// [`EventReader::read_with_id()`] and [`EventReader::is_empty()`] will return `true`.109///110/// For usage, see [`EventReader::is_empty()`].111pub fn clear(&mut self) {112self.reader.clear(&self.events);113}114}115116117