Path: blob/main/crates/bevy_ecs/src/message/message_mutator.rs
6849 views
#[cfg(feature = "multi_threaded")]1use crate::message::MessageMutParIter;2use crate::{3message::{Message, MessageCursor, MessageMutIterator, MessageMutIteratorWithId, Messages},4system::{Local, ResMut, SystemParam},5};67/// Mutably reads messages of type `T` keeping track of which messages have already been read8/// by each system allowing multiple systems to read the same messages. Ideal for chains of systems9/// that all want to modify the same messages.10///11/// # Usage12///13/// [`MessageMutator`]s are usually declared as a [`SystemParam`].14/// ```15/// # use bevy_ecs::prelude::*;16///17/// #[derive(Message, Debug)]18/// pub struct MyMessage(pub u32); // Custom message type.19/// fn my_system(mut reader: MessageMutator<MyMessage>) {20/// for message in reader.read() {21/// message.0 += 1;22/// println!("received message: {:?}", message);23/// }24/// }25/// ```26///27/// # Concurrency28///29/// Multiple systems with `MessageMutator<T>` of the same message type can not run concurrently.30/// They also can not be executed in parallel with [`MessageReader`] or [`MessageWriter`].31///32/// # Clearing, Reading, and Peeking33///34/// Messages are stored in a double buffered queue that switches each frame. This switch also clears the previous35/// frame's messages. Messages should be read each frame otherwise they may be lost. For manual control over this36/// behavior, see [`Messages`].37///38/// Most of the time systems will want to use [`MessageMutator::read()`]. This function creates an iterator over39/// all messages that haven't been read yet by this system, marking the message as read in the process.40///41/// [`MessageReader`]: super::MessageReader42/// [`MessageWriter`]: super::MessageWriter43#[derive(SystemParam, Debug)]44pub struct MessageMutator<'w, 's, E: Message> {45pub(super) reader: Local<'s, MessageCursor<E>>,46#[system_param(validation_message = "Message not initialized")]47messages: ResMut<'w, Messages<E>>,48}4950impl<'w, 's, E: Message> MessageMutator<'w, 's, E> {51/// Iterates over the messages this [`MessageMutator`] has not seen yet. This updates the52/// [`MessageMutator`]'s message counter, which means subsequent message reads will not include messages53/// that happened before now.54pub fn read(&mut self) -> MessageMutIterator<'_, E> {55self.reader.read_mut(&mut self.messages)56}5758/// Like [`read`](Self::read), except also returning the [`MessageId`](super::MessageId) of the messages.59pub fn read_with_id(&mut self) -> MessageMutIteratorWithId<'_, E> {60self.reader.read_mut_with_id(&mut self.messages)61}6263/// Returns a parallel iterator over the messages this [`MessageMutator`] has not seen yet.64/// See also [`for_each`](super::MessageParIter::for_each).65///66/// # Example67/// ```68/// # use bevy_ecs::prelude::*;69/// # use std::sync::atomic::{AtomicUsize, Ordering};70///71/// #[derive(Message)]72/// struct MyMessage {73/// value: usize,74/// }75///76/// #[derive(Resource, Default)]77/// struct Counter(AtomicUsize);78///79/// // setup80/// let mut world = World::new();81/// world.init_resource::<Messages<MyMessage>>();82/// world.insert_resource(Counter::default());83///84/// let mut schedule = Schedule::default();85/// schedule.add_systems(|mut messages: MessageMutator<MyMessage>, counter: Res<Counter>| {86/// messages.par_read().for_each(|MyMessage { value }| {87/// counter.0.fetch_add(*value, Ordering::Relaxed);88/// });89/// });90/// for value in 0..100 {91/// world.write_message(MyMessage { value });92/// }93/// schedule.run(&mut world);94/// let Counter(counter) = world.remove_resource::<Counter>().unwrap();95/// // all messages were processed96/// assert_eq!(counter.into_inner(), 4950);97/// ```98#[cfg(feature = "multi_threaded")]99pub fn par_read(&mut self) -> MessageMutParIter<'_, E> {100self.reader.par_read_mut(&mut self.messages)101}102103/// Determines the number of messages available to be read from this [`MessageMutator`] without consuming any.104pub fn len(&self) -> usize {105self.reader.len(&self.messages)106}107108/// Returns `true` if there are no messages available to read.109///110/// # Example111///112/// The following example shows a useful pattern where some behavior is triggered if new messages are available.113/// [`MessageMutator::clear()`] is used so the same messages don't re-trigger the behavior the next time the system runs.114///115/// ```116/// # use bevy_ecs::prelude::*;117/// #118/// #[derive(Message)]119/// struct Collision;120///121/// fn play_collision_sound(mut messages: MessageMutator<Collision>) {122/// if !messages.is_empty() {123/// messages.clear();124/// // Play a sound125/// }126/// }127/// # bevy_ecs::system::assert_is_system(play_collision_sound);128/// ```129pub fn is_empty(&self) -> bool {130self.reader.is_empty(&self.messages)131}132133/// Consumes all available messages.134///135/// This means these messages will not appear in calls to [`MessageMutator::read()`] or136/// [`MessageMutator::read_with_id()`] and [`MessageMutator::is_empty()`] will return `true`.137///138/// For usage, see [`MessageMutator::is_empty()`].139pub fn clear(&mut self) {140self.reader.clear(&self.messages);141}142}143144145