Skip to content

Commit 345f935

Browse files
authored
Add Trigger::components, which lists the component targets that were triggered (#15811)
# Objective - Closes #14774 ## Solution Added: ```rust impl<'w, E, B: Bundle> Trigger<'w, E, B> { pub fn components(&self) -> &[ComponentId]; } ``` I went with storing it in the trigger as a `SmallVec<[Component; 1]>` because a singular target component will be the most common case, and it remains the same size as `Vec<ComponentId>`. ## Testing Added a test.
1 parent 9f5f5d3 commit 345f935

File tree

6 files changed

+65
-20
lines changed

6 files changed

+65
-20
lines changed

crates/bevy_ecs/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ derive_more = { version = "1", default-features = false, features = [
4141
] }
4242
nonmax = "0.5"
4343
arrayvec = { version = "0.7.4", optional = true }
44-
smallvec = "1"
44+
smallvec = { version = "1", features = ["union"] }
4545

4646
[dev-dependencies]
4747
rand = "0.8"

crates/bevy_ecs/src/archetype.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,15 @@ pub(crate) struct AddBundle {
135135
}
136136

137137
impl AddBundle {
138-
pub(crate) fn iter_inserted(&self) -> impl Iterator<Item = ComponentId> + '_ {
138+
pub(crate) fn iter_inserted(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
139139
self.added.iter().chain(self.existing.iter()).copied()
140140
}
141141

142-
pub(crate) fn iter_added(&self) -> impl Iterator<Item = ComponentId> + '_ {
142+
pub(crate) fn iter_added(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
143143
self.added.iter().copied()
144144
}
145145

146-
pub(crate) fn iter_existing(&self) -> impl Iterator<Item = ComponentId> + '_ {
146+
pub(crate) fn iter_existing(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
147147
self.existing.iter().copied()
148148
}
149149
}
@@ -489,7 +489,7 @@ impl Archetype {
489489
///
490490
/// All of the IDs are unique.
491491
#[inline]
492-
pub fn components(&self) -> impl Iterator<Item = ComponentId> + '_ {
492+
pub fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
493493
self.components.indices()
494494
}
495495

crates/bevy_ecs/src/bundle.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,15 +463,15 @@ impl BundleInfo {
463463
/// Returns an iterator over the [ID](ComponentId) of each component explicitly defined in this bundle (ex: this excludes Required Components).
464464
/// To iterate all components contributed by this bundle (including Required Components), see [`BundleInfo::iter_contributed_components`]
465465
#[inline]
466-
pub fn iter_explicit_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
466+
pub fn iter_explicit_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
467467
self.explicit_components().iter().copied()
468468
}
469469

470470
/// Returns an iterator over the [ID](ComponentId) of each component contributed by this bundle. This includes Required Components.
471471
///
472472
/// To iterate only components explicitly defined in this bundle, see [`BundleInfo::iter_explicit_components`]
473473
#[inline]
474-
pub fn iter_contributed_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
474+
pub fn iter_contributed_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
475475
self.component_ids.iter().copied()
476476
}
477477

crates/bevy_ecs/src/observer/mod.rs

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use core::{
2323
marker::PhantomData,
2424
ops::{Deref, DerefMut},
2525
};
26+
use smallvec::SmallVec;
2627

2728
/// Type containing triggered [`Event`] information for a given run of an [`Observer`]. This contains the
2829
/// [`Event`] data itself. If it was triggered for a specific [`Entity`], it includes that as well. It also
@@ -70,6 +71,13 @@ impl<'w, E, B: Bundle> Trigger<'w, E, B> {
7071
self.trigger.entity
7172
}
7273

74+
/// Returns the components that triggered the observer, out of the
75+
/// components defined in `B`. Does not necessarily include all of them as
76+
/// `B` acts like an `OR` filter rather than an `AND` filter.
77+
pub fn components(&self) -> &[ComponentId] {
78+
&self.trigger.components
79+
}
80+
7381
/// Returns the [`Entity`] that observed the triggered event.
7482
/// This allows you to despawn the observer, ceasing observation.
7583
///
@@ -193,14 +201,21 @@ impl ObserverDescriptor {
193201
pub struct ObserverTrigger {
194202
/// The [`Entity`] of the observer handling the trigger.
195203
pub observer: Entity,
196-
197-
/// The [`ComponentId`] the trigger targeted.
204+
/// The [`Event`] the trigger targeted.
198205
pub event_type: ComponentId,
199-
206+
/// The [`ComponentId`]s the trigger targeted.
207+
components: SmallVec<[ComponentId; 2]>,
200208
/// The entity the trigger targeted.
201209
pub entity: Entity,
202210
}
203211

212+
impl ObserverTrigger {
213+
/// Returns the components that the trigger targeted.
214+
pub fn components(&self) -> &[ComponentId] {
215+
&self.components
216+
}
217+
}
218+
204219
// Map between an observer entity and its runner
205220
type ObserverMap = EntityHashMap<ObserverRunner>;
206221

@@ -262,7 +277,7 @@ impl Observers {
262277
mut world: DeferredWorld,
263278
event_type: ComponentId,
264279
entity: Entity,
265-
components: impl Iterator<Item = ComponentId>,
280+
components: impl Iterator<Item = ComponentId> + Clone,
266281
data: &mut T,
267282
propagate: &mut bool,
268283
) {
@@ -279,12 +294,15 @@ impl Observers {
279294
(world.into_deferred(), observers)
280295
};
281296

297+
let trigger_for_components = components.clone();
298+
282299
let mut trigger_observer = |(&observer, runner): (&Entity, &ObserverRunner)| {
283300
(runner)(
284301
world.reborrow(),
285302
ObserverTrigger {
286303
observer,
287304
event_type,
305+
components: components.clone().collect(),
288306
entity,
289307
},
290308
data.into(),
@@ -302,7 +320,7 @@ impl Observers {
302320
}
303321

304322
// Trigger observers listening to this trigger targeting a specific component
305-
components.for_each(|id| {
323+
trigger_for_components.for_each(|id| {
306324
if let Some(component_observers) = observers.component_observers.get(&id) {
307325
component_observers
308326
.map
@@ -552,8 +570,10 @@ mod tests {
552570
use alloc::vec;
553571

554572
use bevy_ptr::OwningPtr;
573+
use bevy_utils::HashMap;
555574

556575
use crate as bevy_ecs;
576+
use crate::component::ComponentId;
557577
use crate::{
558578
observer::{EmitDynamicTrigger, Observer, ObserverDescriptor, ObserverState, OnReplace},
559579
prelude::*,
@@ -1268,9 +1288,6 @@ mod tests {
12681288

12691289
#[test]
12701290
fn observer_invalid_params() {
1271-
#[derive(Event)]
1272-
struct EventA;
1273-
12741291
#[derive(Resource)]
12751292
struct ResA;
12761293

@@ -1289,9 +1306,6 @@ mod tests {
12891306

12901307
#[test]
12911308
fn observer_apply_deferred_from_param_set() {
1292-
#[derive(Event)]
1293-
struct EventA;
1294-
12951309
#[derive(Resource)]
12961310
struct ResA;
12971311

@@ -1309,4 +1323,35 @@ mod tests {
13091323

13101324
assert!(world.get_resource::<ResA>().is_some());
13111325
}
1326+
1327+
#[test]
1328+
fn observer_triggered_components() {
1329+
#[derive(Resource, Default)]
1330+
struct Counter(HashMap<ComponentId, usize>);
1331+
1332+
let mut world = World::new();
1333+
world.init_resource::<Counter>();
1334+
let a_id = world.register_component::<A>();
1335+
let b_id = world.register_component::<B>();
1336+
1337+
world.add_observer(
1338+
|trigger: Trigger<EventA, (A, B)>, mut counter: ResMut<Counter>| {
1339+
for &component in trigger.components() {
1340+
*counter.0.entry(component).or_default() += 1;
1341+
}
1342+
},
1343+
);
1344+
world.flush();
1345+
1346+
world.trigger_targets(EventA, [a_id, b_id]);
1347+
world.trigger_targets(EventA, a_id);
1348+
world.trigger_targets(EventA, b_id);
1349+
world.trigger_targets(EventA, [a_id, b_id]);
1350+
world.trigger_targets(EventA, a_id);
1351+
world.flush();
1352+
1353+
let counter = world.resource::<Counter>();
1354+
assert_eq!(4, *counter.0.get(&a_id).unwrap());
1355+
assert_eq!(3, *counter.0.get(&b_id).unwrap());
1356+
}
13121357
}

crates/bevy_ecs/src/storage/sparse_set.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ macro_rules! impl_sparse_set {
423423
}
424424

425425
/// Returns an iterator visiting all keys (indices) in arbitrary order.
426-
pub fn indices(&self) -> impl Iterator<Item = I> + '_ {
426+
pub fn indices(&self) -> impl Iterator<Item = I> + Clone + '_ {
427427
self.indices.iter().cloned()
428428
}
429429

crates/bevy_ecs/src/world/deferred_world.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ impl<'w> DeferredWorld<'w> {
501501
&mut self,
502502
event: ComponentId,
503503
entity: Entity,
504-
components: impl Iterator<Item = ComponentId>,
504+
components: impl Iterator<Item = ComponentId> + Clone,
505505
) {
506506
Observers::invoke::<_>(
507507
self.reborrow(),

0 commit comments

Comments
 (0)