Add World::trigger_ref and World::trigger_targets_ref (#14894)

# 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>
This commit is contained in:
Christian Hughes 2024-09-23 11:31:44 -05:00 committed by GitHub
parent 9386bd0114
commit 4682f33e0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 72 additions and 2 deletions

View File

@ -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<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();

View File

@ -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>
{