1use crate::{
2 message::{Message, MessageId, Messages, WriteBatchIds},
3 system::{ResMut, SystemParam},
4};
56/// Writes [`Message`]s of type `T`.
7///
8/// This system parameter takes exclusive access to the [`Messages<T>`] resource,
9/// so a system cannot also have a [`MessageReader`](super::MessageReader) parameter of the same type.
10/// If you need to both read and write messages of the same type,
11/// use [`MessageMutator`](super::MessageMutator).
12///
13/// # Usage
14///
15/// `MessageWriter`s are usually declared as a [`SystemParam`].
16/// ```
17/// # use bevy_ecs::prelude::*;
18///
19/// #[derive(Message)]
20/// pub struct MyMessage(String); // Custom message type.
21/// fn my_system(mut writer: MessageWriter<MyMessage>) {
22/// writer.write(MyMessage("My custom payload!".to_string()));
23/// }
24///
25/// # bevy_ecs::system::assert_is_system(my_system);
26/// ```
27///
28/// # Concurrency
29///
30/// `MessageWriter` param has [`ResMut<Messages<T>>`](Messages) inside. So two systems declaring `MessageWriter<T>` params
31/// for the same message type won't be executed concurrently.
32///
33/// # Untyped messages
34///
35/// `MessageWriter` can only write messages of one specific type, which must be known at compile-time.
36/// This is not a problem most of the time, but you may find a situation where you cannot know
37/// ahead of time every kind of message you'll need to write. In this case, you can use the "type-erased message" pattern.
38///
39/// ```
40/// # use bevy_ecs::{prelude::*, message::Messages};
41/// # #[derive(Message)]
42/// # pub struct MyMessage;
43/// fn write_untyped(mut commands: Commands) {
44/// // Write a message of a specific type without having to declare that
45/// // type as a SystemParam.
46/// //
47/// // Effectively, we're just moving the type parameter from the /type/ to the /method/,
48/// // which allows one to do all kinds of clever things with type erasure, such as sending
49/// // custom messages to unknown 3rd party plugins (modding API).
50/// //
51/// // NOTE: the message won't actually be sent until commands get applied during
52/// // apply_deferred.
53/// commands.queue(|w: &mut World| {
54/// w.write_message(MyMessage);
55/// });
56/// }
57/// ```
58/// Note that this is considered *non-idiomatic*, and should only be used when `MessageWriter` will not work.
59///
60/// [`Observer`]: crate::observer::Observer
61#[derive(const _: () =
{
type __StructFieldsAlias<'w, 's, M> = (ResMut<'w, Messages<M>>,);
#[doc(hidden)]
pub struct FetchState<M: Message> {
state: <__StructFieldsAlias<'static, 'static, M> as
bevy_ecs::system::SystemParam>::State,
}
unsafe impl<M: Message> bevy_ecs::system::SystemParam for
MessageWriter<'_, M> {
type State = FetchState<M>;
type Item<'w, 's> = MessageWriter<'w, M>;
fn init_state(world: &mut bevy_ecs::world::World) -> Self::State {
FetchState {
state: <__StructFieldsAlias<'_, '_, M> as
bevy_ecs::system::SystemParam>::init_state(world),
}
}
fn init_access(state: &Self::State,
system_meta: &mut bevy_ecs::system::SystemMeta,
component_access_set: &mut bevy_ecs::query::FilteredAccessSet,
world: &mut bevy_ecs::world::World) {
<__StructFieldsAlias<'_, '_, M> as
bevy_ecs::system::SystemParam>::init_access(&state.state,
system_meta, component_access_set, world);
}
fn apply(state: &mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: &mut bevy_ecs::world::World) {
<__StructFieldsAlias<'_, '_, M> as
bevy_ecs::system::SystemParam>::apply(&mut state.state,
system_meta, world);
}
fn queue(state: &mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: bevy_ecs::world::DeferredWorld) {
<__StructFieldsAlias<'_, '_, M> as
bevy_ecs::system::SystemParam>::queue(&mut state.state,
system_meta, world);
}
#[inline]
unsafe fn get_param<'w,
's>(state: &'s mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world:
bevy_ecs::world::unsafe_world_cell::UnsafeWorldCell<'w>,
change_tick: bevy_ecs::change_detection::Tick)
->
::core::result::Result<Self::Item<'w, 's>,
bevy_ecs::system::SystemParamValidationError> {
let (fieldmessages,) = &mut state.state;
let fieldmessages =
unsafe {
<ResMut<'w, Messages<M>> as
bevy_ecs::system::SystemParam>::get_param(fieldmessages,
system_meta, world, change_tick)
}.map_err(|err|
bevy_ecs::system::SystemParamValidationError::new::<Self>(err.skipped,
"Message not initialized", "::messages"))?;
::core::result::Result::Ok(MessageWriter {
messages: fieldmessages,
})
}
}
unsafe impl<'w, 's, M: Message> bevy_ecs::system::ReadOnlySystemParam
for MessageWriter<'w, M> where
ResMut<'w, Messages<M>>: bevy_ecs::system::ReadOnlySystemParam {}
};SystemParam)]
62pub struct MessageWriter<'w, M: Message> {
63#[system_param(validation_message = "Message not initialized")]
64messages: ResMut<'w, Messages<M>>,
65}
6667impl<'w, M: Message> MessageWriter<'w, M> {
68/// Writes an `message`, which can later be read by [`MessageReader`](super::MessageReader)s.
69 /// This method returns the [ID](`MessageId`) of the written `message`.
70 ///
71 /// See [`Messages`] for details.
72#[doc(alias = "send")]
73 #[track_caller]
74pub fn write(&mut self, message: M) -> MessageId<M> {
75self.messages.write(message)
76 }
7778/// Writes a list of `messages` all at once, which can later be read by [`MessageReader`](super::MessageReader)s.
79 /// This is more efficient than writing each message individually.
80 /// This method returns the [IDs](`MessageId`) of the written `messages`.
81 ///
82 /// See [`Messages`] for details.
83#[doc(alias = "send_batch")]
84 #[track_caller]
85pub fn write_batch(&mut self, messages: impl IntoIterator<Item = M>) -> WriteBatchIds<M> {
86self.messages.write_batch(messages)
87 }
8889/// Writes the default value of the message. Useful when the message is an empty struct.
90 /// This method returns the [ID](`MessageId`) of the written `message`.
91 ///
92 /// See [`Messages`] for details.
93#[doc(alias = "send_default")]
94 #[track_caller]
95pub fn write_default(&mut self) -> MessageId<M>
96where
97M: Default,
98 {
99self.messages.write_default()
100 }
101}