Skip to content

Commit

Permalink
Add World::trigger_ref and World::trigger_targets_ref (#14894)
Browse files Browse the repository at this point in the history
# Objective

Closes #14888.

## Solution

Add non-consuming trigger functions:

```rust
impl World {
    pub fn trigger_ref(&mut self, event: &mut impl Event);
    pub fn trigger_targets_ref(&mut self, event: &mut impl Event, targets: impl TriggerTargets);
}
```

## Testing

- Added two new tests, `observer_trigger_ref` and
`observer_trigger_targets_ref`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
  • Loading branch information
ItsDoot and alice-i-cecile authored Sep 23, 2024
1 parent 9386bd0 commit 4682f33
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 2 deletions.
67 changes: 65 additions & 2 deletions crates/bevy_ecs/src/observer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -507,6 +532,11 @@ mod tests {
#[derive(Event)]
struct EventA;

#[derive(Event)]
struct EventWithData {
counter: usize,
}

#[derive(Resource, Default)]
struct Order(Vec<&'static str>);

Expand Down Expand Up @@ -652,6 +682,39 @@ mod tests {
);
}

#[test]
fn observer_trigger_ref() {
let mut world = World::new();

world.observe(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 1);
world.observe(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 2);
world.observe(|mut trigger: Trigger<EventWithData>| 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<EventWithData, A>| trigger.event_mut().counter += 1);
world.observe(|mut trigger: Trigger<EventWithData, B>| trigger.event_mut().counter += 2);
world.observe(|mut trigger: Trigger<EventWithData, A>| 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::<A>();
world.trigger_targets_ref(&mut event, component_a);
assert_eq!(5, event.counter);
}

#[test]
fn observer_multiple_listeners() {
let mut world = World::new();
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_ecs/src/observer/trigger_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ impl<E: Event, Targets: TriggerTargets> TriggerEvent<E, Targets> {
}
}

impl<E: Event, Targets: TriggerTargets> TriggerEvent<&mut E, Targets> {
pub(super) fn trigger_ref(self, world: &mut World) {
let event_type = world.init_component::<E>();
trigger_event(world, event_type, self.event, self.targets);
}
}

impl<E: Event, Targets: TriggerTargets + Send + Sync + 'static> Command
for TriggerEvent<E, Targets>
{
Expand Down

0 comments on commit 4682f33

Please sign in to comment.