mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 22:20:20 +00:00
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.
This commit is contained in:
parent
9f5f5d3d41
commit
345f935b1a
6 changed files with 65 additions and 20 deletions
|
@ -41,7 +41,7 @@ derive_more = { version = "1", default-features = false, features = [
|
||||||
] }
|
] }
|
||||||
nonmax = "0.5"
|
nonmax = "0.5"
|
||||||
arrayvec = { version = "0.7.4", optional = true }
|
arrayvec = { version = "0.7.4", optional = true }
|
||||||
smallvec = "1"
|
smallvec = { version = "1", features = ["union"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
|
|
@ -135,15 +135,15 @@ pub(crate) struct AddBundle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddBundle {
|
impl AddBundle {
|
||||||
pub(crate) fn iter_inserted(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
pub(crate) fn iter_inserted(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
|
||||||
self.added.iter().chain(self.existing.iter()).copied()
|
self.added.iter().chain(self.existing.iter()).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn iter_added(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
pub(crate) fn iter_added(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
|
||||||
self.added.iter().copied()
|
self.added.iter().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn iter_existing(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
pub(crate) fn iter_existing(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
|
||||||
self.existing.iter().copied()
|
self.existing.iter().copied()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ impl Archetype {
|
||||||
///
|
///
|
||||||
/// All of the IDs are unique.
|
/// All of the IDs are unique.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn components(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
pub fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
|
||||||
self.components.indices()
|
self.components.indices()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -463,7 +463,7 @@ impl BundleInfo {
|
||||||
/// Returns an iterator over the [ID](ComponentId) of each component explicitly defined in this bundle (ex: this excludes Required Components).
|
/// Returns an iterator over the [ID](ComponentId) of each component explicitly defined in this bundle (ex: this excludes Required Components).
|
||||||
/// To iterate all components contributed by this bundle (including Required Components), see [`BundleInfo::iter_contributed_components`]
|
/// To iterate all components contributed by this bundle (including Required Components), see [`BundleInfo::iter_contributed_components`]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_explicit_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
pub fn iter_explicit_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
|
||||||
self.explicit_components().iter().copied()
|
self.explicit_components().iter().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,7 +471,7 @@ impl BundleInfo {
|
||||||
///
|
///
|
||||||
/// To iterate only components explicitly defined in this bundle, see [`BundleInfo::iter_explicit_components`]
|
/// To iterate only components explicitly defined in this bundle, see [`BundleInfo::iter_explicit_components`]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_contributed_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
pub fn iter_contributed_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
|
||||||
self.component_ids.iter().copied()
|
self.component_ids.iter().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ use core::{
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
/// Type containing triggered [`Event`] information for a given run of an [`Observer`]. This contains the
|
/// Type containing triggered [`Event`] information for a given run of an [`Observer`]. This contains the
|
||||||
/// [`Event`] data itself. If it was triggered for a specific [`Entity`], it includes that as well. It also
|
/// [`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> {
|
||||||
self.trigger.entity
|
self.trigger.entity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the components that triggered the observer, out of the
|
||||||
|
/// components defined in `B`. Does not necessarily include all of them as
|
||||||
|
/// `B` acts like an `OR` filter rather than an `AND` filter.
|
||||||
|
pub fn components(&self) -> &[ComponentId] {
|
||||||
|
&self.trigger.components
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the [`Entity`] that observed the triggered event.
|
/// Returns the [`Entity`] that observed the triggered event.
|
||||||
/// This allows you to despawn the observer, ceasing observation.
|
/// This allows you to despawn the observer, ceasing observation.
|
||||||
///
|
///
|
||||||
|
@ -193,14 +201,21 @@ impl ObserverDescriptor {
|
||||||
pub struct ObserverTrigger {
|
pub struct ObserverTrigger {
|
||||||
/// The [`Entity`] of the observer handling the trigger.
|
/// The [`Entity`] of the observer handling the trigger.
|
||||||
pub observer: Entity,
|
pub observer: Entity,
|
||||||
|
/// The [`Event`] the trigger targeted.
|
||||||
/// The [`ComponentId`] the trigger targeted.
|
|
||||||
pub event_type: ComponentId,
|
pub event_type: ComponentId,
|
||||||
|
/// The [`ComponentId`]s the trigger targeted.
|
||||||
|
components: SmallVec<[ComponentId; 2]>,
|
||||||
/// The entity the trigger targeted.
|
/// The entity the trigger targeted.
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ObserverTrigger {
|
||||||
|
/// Returns the components that the trigger targeted.
|
||||||
|
pub fn components(&self) -> &[ComponentId] {
|
||||||
|
&self.components
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Map between an observer entity and its runner
|
// Map between an observer entity and its runner
|
||||||
type ObserverMap = EntityHashMap<ObserverRunner>;
|
type ObserverMap = EntityHashMap<ObserverRunner>;
|
||||||
|
|
||||||
|
@ -262,7 +277,7 @@ impl Observers {
|
||||||
mut world: DeferredWorld,
|
mut world: DeferredWorld,
|
||||||
event_type: ComponentId,
|
event_type: ComponentId,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
components: impl Iterator<Item = ComponentId>,
|
components: impl Iterator<Item = ComponentId> + Clone,
|
||||||
data: &mut T,
|
data: &mut T,
|
||||||
propagate: &mut bool,
|
propagate: &mut bool,
|
||||||
) {
|
) {
|
||||||
|
@ -279,12 +294,15 @@ impl Observers {
|
||||||
(world.into_deferred(), observers)
|
(world.into_deferred(), observers)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let trigger_for_components = components.clone();
|
||||||
|
|
||||||
let mut trigger_observer = |(&observer, runner): (&Entity, &ObserverRunner)| {
|
let mut trigger_observer = |(&observer, runner): (&Entity, &ObserverRunner)| {
|
||||||
(runner)(
|
(runner)(
|
||||||
world.reborrow(),
|
world.reborrow(),
|
||||||
ObserverTrigger {
|
ObserverTrigger {
|
||||||
observer,
|
observer,
|
||||||
event_type,
|
event_type,
|
||||||
|
components: components.clone().collect(),
|
||||||
entity,
|
entity,
|
||||||
},
|
},
|
||||||
data.into(),
|
data.into(),
|
||||||
|
@ -302,7 +320,7 @@ impl Observers {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger observers listening to this trigger targeting a specific component
|
// Trigger observers listening to this trigger targeting a specific component
|
||||||
components.for_each(|id| {
|
trigger_for_components.for_each(|id| {
|
||||||
if let Some(component_observers) = observers.component_observers.get(&id) {
|
if let Some(component_observers) = observers.component_observers.get(&id) {
|
||||||
component_observers
|
component_observers
|
||||||
.map
|
.map
|
||||||
|
@ -552,8 +570,10 @@ mod tests {
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
|
|
||||||
use bevy_ptr::OwningPtr;
|
use bevy_ptr::OwningPtr;
|
||||||
|
use bevy_utils::HashMap;
|
||||||
|
|
||||||
use crate as bevy_ecs;
|
use crate as bevy_ecs;
|
||||||
|
use crate::component::ComponentId;
|
||||||
use crate::{
|
use crate::{
|
||||||
observer::{EmitDynamicTrigger, Observer, ObserverDescriptor, ObserverState, OnReplace},
|
observer::{EmitDynamicTrigger, Observer, ObserverDescriptor, ObserverState, OnReplace},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
@ -1268,9 +1288,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn observer_invalid_params() {
|
fn observer_invalid_params() {
|
||||||
#[derive(Event)]
|
|
||||||
struct EventA;
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
struct ResA;
|
struct ResA;
|
||||||
|
|
||||||
|
@ -1289,9 +1306,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn observer_apply_deferred_from_param_set() {
|
fn observer_apply_deferred_from_param_set() {
|
||||||
#[derive(Event)]
|
|
||||||
struct EventA;
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
struct ResA;
|
struct ResA;
|
||||||
|
|
||||||
|
@ -1309,4 +1323,35 @@ mod tests {
|
||||||
|
|
||||||
assert!(world.get_resource::<ResA>().is_some());
|
assert!(world.get_resource::<ResA>().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn observer_triggered_components() {
|
||||||
|
#[derive(Resource, Default)]
|
||||||
|
struct Counter(HashMap<ComponentId, usize>);
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
world.init_resource::<Counter>();
|
||||||
|
let a_id = world.register_component::<A>();
|
||||||
|
let b_id = world.register_component::<B>();
|
||||||
|
|
||||||
|
world.add_observer(
|
||||||
|
|trigger: Trigger<EventA, (A, B)>, mut counter: ResMut<Counter>| {
|
||||||
|
for &component in trigger.components() {
|
||||||
|
*counter.0.entry(component).or_default() += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
world.flush();
|
||||||
|
|
||||||
|
world.trigger_targets(EventA, [a_id, b_id]);
|
||||||
|
world.trigger_targets(EventA, a_id);
|
||||||
|
world.trigger_targets(EventA, b_id);
|
||||||
|
world.trigger_targets(EventA, [a_id, b_id]);
|
||||||
|
world.trigger_targets(EventA, a_id);
|
||||||
|
world.flush();
|
||||||
|
|
||||||
|
let counter = world.resource::<Counter>();
|
||||||
|
assert_eq!(4, *counter.0.get(&a_id).unwrap());
|
||||||
|
assert_eq!(3, *counter.0.get(&b_id).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -423,7 +423,7 @@ macro_rules! impl_sparse_set {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator visiting all keys (indices) in arbitrary order.
|
/// Returns an iterator visiting all keys (indices) in arbitrary order.
|
||||||
pub fn indices(&self) -> impl Iterator<Item = I> + '_ {
|
pub fn indices(&self) -> impl Iterator<Item = I> + Clone + '_ {
|
||||||
self.indices.iter().cloned()
|
self.indices.iter().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -501,7 +501,7 @@ impl<'w> DeferredWorld<'w> {
|
||||||
&mut self,
|
&mut self,
|
||||||
event: ComponentId,
|
event: ComponentId,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
components: impl Iterator<Item = ComponentId>,
|
components: impl Iterator<Item = ComponentId> + Clone,
|
||||||
) {
|
) {
|
||||||
Observers::invoke::<_>(
|
Observers::invoke::<_>(
|
||||||
self.reborrow(),
|
self.reborrow(),
|
||||||
|
|
Loading…
Reference in a new issue