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>
This commit is contained in:
parent
e63d7c340f
commit
45281e62d7
@ -7,6 +7,7 @@ mod mut_iterators;
|
|||||||
mod mutator;
|
mod mutator;
|
||||||
mod reader;
|
mod reader;
|
||||||
mod registry;
|
mod registry;
|
||||||
|
mod send_event;
|
||||||
mod update;
|
mod update;
|
||||||
mod writer;
|
mod writer;
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ pub use mut_iterators::{EventMutIterator, EventMutIteratorWithId};
|
|||||||
pub use mutator::EventMutator;
|
pub use mutator::EventMutator;
|
||||||
pub use reader::EventReader;
|
pub use reader::EventReader;
|
||||||
pub use registry::{EventRegistry, ShouldUpdateEvents};
|
pub use registry::{EventRegistry, ShouldUpdateEvents};
|
||||||
|
pub use send_event::SendEvent;
|
||||||
pub use update::{
|
pub use update::{
|
||||||
event_update_condition, event_update_system, signal_event_update_system, EventUpdates,
|
event_update_condition, event_update_system, signal_event_update_system, EventUpdates,
|
||||||
};
|
};
|
||||||
|
|||||||
15
crates/bevy_ecs/src/event/send_event.rs
Normal file
15
crates/bevy_ecs/src/event/send_event.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use super::{Event, Events};
|
||||||
|
use crate::world::{Command, World};
|
||||||
|
|
||||||
|
/// A command to send an arbitrary [`Event`], used by [`Commands::send_event`](crate::system::Commands::send_event).
|
||||||
|
pub struct SendEvent<E: Event> {
|
||||||
|
/// The event to send.
|
||||||
|
pub event: E,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Event> Command for SendEvent<E> {
|
||||||
|
fn apply(self, world: &mut World) {
|
||||||
|
let mut events = world.resource_mut::<Events<E>>();
|
||||||
|
events.send(self.event);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@ use crate::{
|
|||||||
bundle::{Bundle, InsertMode},
|
bundle::{Bundle, InsertMode},
|
||||||
component::{ComponentId, ComponentInfo},
|
component::{ComponentId, ComponentInfo},
|
||||||
entity::{Entities, Entity},
|
entity::{Entities, Entity},
|
||||||
event::Event,
|
event::{Event, SendEvent},
|
||||||
observer::{Observer, TriggerEvent, TriggerTargets},
|
observer::{Observer, TriggerEvent, TriggerTargets},
|
||||||
system::{RunSystemWithInput, SystemId},
|
system::{RunSystemWithInput, SystemId},
|
||||||
world::{
|
world::{
|
||||||
@ -788,6 +788,21 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
) -> EntityCommands {
|
) -> EntityCommands {
|
||||||
self.spawn(Observer::new(observer))
|
self.spawn(Observer::new(observer))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sends an arbitrary [`Event`].
|
||||||
|
///
|
||||||
|
/// This is a convenience method for sending events without requiring an [`EventWriter`].
|
||||||
|
/// ## Performance
|
||||||
|
/// Since this is a command, exclusive world access is used, which means that it will not profit from
|
||||||
|
/// system-level parallelism on supported platforms.
|
||||||
|
/// If these events are performance-critical or very frequently
|
||||||
|
/// sent, consider using a typed [`EventWriter`] instead.
|
||||||
|
///
|
||||||
|
/// [`EventWriter`]: crate::event::EventWriter
|
||||||
|
pub fn send_event<E: Event>(&mut self, event: E) -> &mut Self {
|
||||||
|
self.add(SendEvent { event });
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Command`] which gets executed for a given [`Entity`].
|
/// A [`Command`] which gets executed for a given [`Entity`].
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user