mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 14:10:19 +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"
|
||||
arrayvec = { version = "0.7.4", optional = true }
|
||||
smallvec = "1"
|
||||
smallvec = { version = "1", features = ["union"] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8"
|
||||
|
|
|
@ -135,15 +135,15 @@ pub(crate) struct 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()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ impl Archetype {
|
|||
///
|
||||
/// All of the IDs are unique.
|
||||
#[inline]
|
||||
pub fn components(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
||||
pub fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
|
||||
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).
|
||||
/// To iterate all components contributed by this bundle (including Required Components), see [`BundleInfo::iter_contributed_components`]
|
||||
#[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()
|
||||
}
|
||||
|
||||
|
@ -471,7 +471,7 @@ impl BundleInfo {
|
|||
///
|
||||
/// To iterate only components explicitly defined in this bundle, see [`BundleInfo::iter_explicit_components`]
|
||||
#[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()
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ use core::{
|
|||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// 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
|
||||
|
@ -70,6 +71,13 @@ impl<'w, E, B: Bundle> Trigger<'w, E, B> {
|
|||
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.
|
||||
/// This allows you to despawn the observer, ceasing observation.
|
||||
///
|
||||
|
@ -193,14 +201,21 @@ impl ObserverDescriptor {
|
|||
pub struct ObserverTrigger {
|
||||
/// The [`Entity`] of the observer handling the trigger.
|
||||
pub observer: Entity,
|
||||
|
||||
/// The [`ComponentId`] the trigger targeted.
|
||||
/// The [`Event`] the trigger targeted.
|
||||
pub event_type: ComponentId,
|
||||
|
||||
/// The [`ComponentId`]s the trigger targeted.
|
||||
components: SmallVec<[ComponentId; 2]>,
|
||||
/// The entity the trigger targeted.
|
||||
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
|
||||
type ObserverMap = EntityHashMap<ObserverRunner>;
|
||||
|
||||
|
@ -262,7 +277,7 @@ impl Observers {
|
|||
mut world: DeferredWorld,
|
||||
event_type: ComponentId,
|
||||
entity: Entity,
|
||||
components: impl Iterator<Item = ComponentId>,
|
||||
components: impl Iterator<Item = ComponentId> + Clone,
|
||||
data: &mut T,
|
||||
propagate: &mut bool,
|
||||
) {
|
||||
|
@ -279,12 +294,15 @@ impl Observers {
|
|||
(world.into_deferred(), observers)
|
||||
};
|
||||
|
||||
let trigger_for_components = components.clone();
|
||||
|
||||
let mut trigger_observer = |(&observer, runner): (&Entity, &ObserverRunner)| {
|
||||
(runner)(
|
||||
world.reborrow(),
|
||||
ObserverTrigger {
|
||||
observer,
|
||||
event_type,
|
||||
components: components.clone().collect(),
|
||||
entity,
|
||||
},
|
||||
data.into(),
|
||||
|
@ -302,7 +320,7 @@ impl Observers {
|
|||
}
|
||||
|
||||
// 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) {
|
||||
component_observers
|
||||
.map
|
||||
|
@ -552,8 +570,10 @@ mod tests {
|
|||
use alloc::vec;
|
||||
|
||||
use bevy_ptr::OwningPtr;
|
||||
use bevy_utils::HashMap;
|
||||
|
||||
use crate as bevy_ecs;
|
||||
use crate::component::ComponentId;
|
||||
use crate::{
|
||||
observer::{EmitDynamicTrigger, Observer, ObserverDescriptor, ObserverState, OnReplace},
|
||||
prelude::*,
|
||||
|
@ -1268,9 +1288,6 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn observer_invalid_params() {
|
||||
#[derive(Event)]
|
||||
struct EventA;
|
||||
|
||||
#[derive(Resource)]
|
||||
struct ResA;
|
||||
|
||||
|
@ -1289,9 +1306,6 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn observer_apply_deferred_from_param_set() {
|
||||
#[derive(Event)]
|
||||
struct EventA;
|
||||
|
||||
#[derive(Resource)]
|
||||
struct ResA;
|
||||
|
||||
|
@ -1309,4 +1323,35 @@ mod tests {
|
|||
|
||||
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.
|
||||
pub fn indices(&self) -> impl Iterator<Item = I> + '_ {
|
||||
pub fn indices(&self) -> impl Iterator<Item = I> + Clone + '_ {
|
||||
self.indices.iter().cloned()
|
||||
}
|
||||
|
||||
|
|
|
@ -501,7 +501,7 @@ impl<'w> DeferredWorld<'w> {
|
|||
&mut self,
|
||||
event: ComponentId,
|
||||
entity: Entity,
|
||||
components: impl Iterator<Item = ComponentId>,
|
||||
components: impl Iterator<Item = ComponentId> + Clone,
|
||||
) {
|
||||
Observers::invoke::<_>(
|
||||
self.reborrow(),
|
||||
|
|
Loading…
Reference in a new issue