diff --git a/crates/bevy_ecs/src/observer/mod.rs b/crates/bevy_ecs/src/observer/mod.rs index 3919321df2..304d2176b5 100644 --- a/crates/bevy_ecs/src/observer/mod.rs +++ b/crates/bevy_ecs/src/observer/mod.rs @@ -349,16 +349,41 @@ impl World { self.spawn(Observer::new(system)) } - /// Triggers the given `event`, which will run any observers watching for it. + /// Triggers the given [`Event`], which will run any [`Observer`]s watching for it. + /// + /// While event types commonly implement [`Copy`], + /// those that don't will be consumed and will no longer be accessible. + /// If you need to use the event after triggering it, use [`World::trigger_ref`] instead. pub fn trigger(&mut self, event: impl Event) { TriggerEvent { event, targets: () }.trigger(self); } - /// Triggers the given `event` for the given `targets`, which will run any observers watching for it. + /// Triggers the given [`Event`] as a mutable reference, which will run any [`Observer`]s watching for it. + /// + /// Compared to [`World::trigger`], this method is most useful when it's necessary to check + /// or use the event after it has been modified by observers. + pub fn trigger_ref(&mut self, event: &mut impl Event) { + TriggerEvent { event, targets: () }.trigger_ref(self); + } + + /// Triggers the given [`Event`] for the given `targets`, which will run any [`Observer`]s watching for it. + /// + /// While event types commonly implement [`Copy`], + /// those that don't will be consumed and will no longer be accessible. + /// If you need to use the event after triggering it, use [`World::trigger_targets_ref`] instead. pub fn trigger_targets(&mut self, event: impl Event, targets: impl TriggerTargets) { TriggerEvent { event, targets }.trigger(self); } + /// Triggers the given [`Event`] as a mutable reference for the given `targets`, + /// which will run any [`Observer`]s watching for it. + /// + /// Compared to [`World::trigger_targets`], this method is most useful when it's necessary to check + /// or use the event after it has been modified by observers. + pub fn trigger_targets_ref(&mut self, event: &mut impl Event, targets: impl TriggerTargets) { + TriggerEvent { event, targets }.trigger_ref(self); + } + /// Register an observer to the cache, called when an observer is created pub(crate) fn register_observer(&mut self, observer_entity: Entity) { // SAFETY: References do not alias. @@ -507,6 +532,11 @@ mod tests { #[derive(Event)] struct EventA; + #[derive(Event)] + struct EventWithData { + counter: usize, + } + #[derive(Resource, Default)] struct Order(Vec<&'static str>); @@ -652,6 +682,39 @@ mod tests { ); } + #[test] + fn observer_trigger_ref() { + let mut world = World::new(); + + world.observe(|mut trigger: Trigger| trigger.event_mut().counter += 1); + world.observe(|mut trigger: Trigger| trigger.event_mut().counter += 2); + world.observe(|mut trigger: Trigger| trigger.event_mut().counter += 4); + // This flush is required for the last observer to be called when triggering the event, + // due to `World::observe` returning `WorldEntityMut`. + world.flush(); + + let mut event = EventWithData { counter: 0 }; + world.trigger_ref(&mut event); + assert_eq!(7, event.counter); + } + + #[test] + fn observer_trigger_targets_ref() { + let mut world = World::new(); + + world.observe(|mut trigger: Trigger| trigger.event_mut().counter += 1); + world.observe(|mut trigger: Trigger| trigger.event_mut().counter += 2); + world.observe(|mut trigger: Trigger| trigger.event_mut().counter += 4); + // This flush is required for the last observer to be called when triggering the event, + // due to `World::observe` returning `WorldEntityMut`. + world.flush(); + + let mut event = EventWithData { counter: 0 }; + let component_a = world.init_component::(); + world.trigger_targets_ref(&mut event, component_a); + assert_eq!(5, event.counter); + } + #[test] fn observer_multiple_listeners() { let mut world = World::new(); diff --git a/crates/bevy_ecs/src/observer/trigger_event.rs b/crates/bevy_ecs/src/observer/trigger_event.rs index 6323eb42c9..ce368d9398 100644 --- a/crates/bevy_ecs/src/observer/trigger_event.rs +++ b/crates/bevy_ecs/src/observer/trigger_event.rs @@ -21,6 +21,13 @@ impl TriggerEvent { } } +impl TriggerEvent<&mut E, Targets> { + pub(super) fn trigger_ref(self, world: &mut World) { + let event_type = world.init_component::(); + trigger_event(world, event_type, self.event, self.targets); + } +} + impl Command for TriggerEvent {