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
	 robtfm
						robtfm