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 reader; | ||||
| mod registry; | ||||
| mod send_event; | ||||
| mod update; | ||||
| mod writer; | ||||
| 
 | ||||
| @ -24,6 +25,7 @@ pub use mut_iterators::{EventMutIterator, EventMutIteratorWithId}; | ||||
| pub use mutator::EventMutator; | ||||
| pub use reader::EventReader; | ||||
| pub use registry::{EventRegistry, ShouldUpdateEvents}; | ||||
| pub use send_event::SendEvent; | ||||
| pub use update::{ | ||||
|     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}, | ||||
|     component::{ComponentId, ComponentInfo}, | ||||
|     entity::{Entities, Entity}, | ||||
|     event::Event, | ||||
|     event::{Event, SendEvent}, | ||||
|     observer::{Observer, TriggerEvent, TriggerTargets}, | ||||
|     system::{RunSystemWithInput, SystemId}, | ||||
|     world::{ | ||||
| @ -788,6 +788,21 @@ impl<'w, 's> Commands<'w, 's> { | ||||
|     ) -> EntityCommands { | ||||
|         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`].
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 robtfm
						robtfm