1mod entity_observer;
4mod runner;
5
6pub use entity_observer::ObservedBy;
7pub use runner::*;
8use variadics_please::all_tuples;
9
10use crate::{
11 archetype::ArchetypeFlags,
12 change_detection::MaybeLocation,
13 component::ComponentId,
14 entity::EntityHashMap,
15 prelude::*,
16 system::IntoObserverSystem,
17 world::{DeferredWorld, *},
18};
19use alloc::vec::Vec;
20use bevy_platform::collections::HashMap;
21use bevy_ptr::Ptr;
22use core::{
23 fmt::Debug,
24 marker::PhantomData,
25 ops::{Deref, DerefMut},
26};
27use smallvec::SmallVec;
28
29pub struct Trigger<'w, E, B: Bundle = ()> {
33 event: &'w mut E,
34 propagate: &'w mut bool,
35 trigger: ObserverTrigger,
36 _marker: PhantomData<B>,
37}
38
39impl<'w, E, B: Bundle> Trigger<'w, E, B> {
40 pub fn new(event: &'w mut E, propagate: &'w mut bool, trigger: ObserverTrigger) -> Self {
42 Self {
43 event,
44 propagate,
45 trigger,
46 _marker: PhantomData,
47 }
48 }
49
50 pub fn event_type(&self) -> ComponentId {
52 self.trigger.event_type
53 }
54
55 pub fn event(&self) -> &E {
57 self.event
58 }
59
60 pub fn event_mut(&mut self) -> &mut E {
62 self.event
63 }
64
65 pub fn event_ptr(&self) -> Ptr {
67 Ptr::from(&self.event)
68 }
69
70 pub fn target(&self) -> Entity {
85 self.trigger.target
86 }
87
88 pub fn components(&self) -> &[ComponentId] {
92 &self.trigger.components
93 }
94
95 pub fn observer(&self) -> Entity {
118 self.trigger.observer
119 }
120
121 pub fn propagate(&mut self, should_propagate: bool) {
134 *self.propagate = should_propagate;
135 }
136
137 pub fn get_propagate(&self) -> bool {
141 *self.propagate
142 }
143
144 pub fn caller(&self) -> MaybeLocation {
146 self.trigger.caller
147 }
148}
149
150impl<'w, E: Debug, B: Bundle> Debug for Trigger<'w, E, B> {
151 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
152 f.debug_struct("Trigger")
153 .field("event", &self.event)
154 .field("propagate", &self.propagate)
155 .field("trigger", &self.trigger)
156 .field("_marker", &self._marker)
157 .finish()
158 }
159}
160
161impl<'w, E, B: Bundle> Deref for Trigger<'w, E, B> {
162 type Target = E;
163
164 fn deref(&self) -> &Self::Target {
165 self.event
166 }
167}
168
169impl<'w, E, B: Bundle> DerefMut for Trigger<'w, E, B> {
170 fn deref_mut(&mut self) -> &mut Self::Target {
171 self.event
172 }
173}
174
175pub trait TriggerTargets {
180 fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_;
182
183 fn entities(&self) -> impl Iterator<Item = Entity> + Clone + '_;
185}
186
187impl<T: TriggerTargets + ?Sized> TriggerTargets for &T {
188 fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
189 (**self).components()
190 }
191
192 fn entities(&self) -> impl Iterator<Item = Entity> + Clone + '_ {
193 (**self).entities()
194 }
195}
196
197impl TriggerTargets for Entity {
198 fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
199 [].into_iter()
200 }
201
202 fn entities(&self) -> impl Iterator<Item = Entity> + Clone + '_ {
203 core::iter::once(*self)
204 }
205}
206
207impl TriggerTargets for ComponentId {
208 fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
209 core::iter::once(*self)
210 }
211
212 fn entities(&self) -> impl Iterator<Item = Entity> + Clone + '_ {
213 [].into_iter()
214 }
215}
216
217impl<T: TriggerTargets> TriggerTargets for Vec<T> {
218 fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
219 self.iter().flat_map(T::components)
220 }
221
222 fn entities(&self) -> impl Iterator<Item = Entity> + Clone + '_ {
223 self.iter().flat_map(T::entities)
224 }
225}
226
227impl<const N: usize, T: TriggerTargets> TriggerTargets for [T; N] {
228 fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
229 self.iter().flat_map(T::components)
230 }
231
232 fn entities(&self) -> impl Iterator<Item = Entity> + Clone + '_ {
233 self.iter().flat_map(T::entities)
234 }
235}
236
237impl<T: TriggerTargets> TriggerTargets for [T] {
238 fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
239 self.iter().flat_map(T::components)
240 }
241
242 fn entities(&self) -> impl Iterator<Item = Entity> + Clone + '_ {
243 self.iter().flat_map(T::entities)
244 }
245}
246
247macro_rules! impl_trigger_targets_tuples {
248 ($(#[$meta:meta])* $($trigger_targets: ident),*) => {
249 #[expect(clippy::allow_attributes, reason = "can't guarantee violation of non_snake_case")]
250 #[allow(non_snake_case, reason = "`all_tuples!()` generates non-snake-case variable names.")]
251 $(#[$meta])*
252 impl<$($trigger_targets: TriggerTargets),*> TriggerTargets for ($($trigger_targets,)*)
253 {
254 fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
255 let iter = [].into_iter();
256 let ($($trigger_targets,)*) = self;
257 $(
258 let iter = iter.chain($trigger_targets.components());
259 )*
260 iter
261 }
262
263 fn entities(&self) -> impl Iterator<Item = Entity> + Clone + '_ {
264 let iter = [].into_iter();
265 let ($($trigger_targets,)*) = self;
266 $(
267 let iter = iter.chain($trigger_targets.entities());
268 )*
269 iter
270 }
271 }
272 }
273}
274
275all_tuples!(
276 #[doc(fake_variadic)]
277 impl_trigger_targets_tuples,
278 0,
279 15,
280 T
281);
282
283#[derive(Default, Clone)]
285pub struct ObserverDescriptor {
286 events: Vec<ComponentId>,
288
289 components: Vec<ComponentId>,
291
292 entities: Vec<Entity>,
294}
295
296impl ObserverDescriptor {
297 pub unsafe fn with_events(mut self, events: Vec<ComponentId>) -> Self {
302 self.events = events;
303 self
304 }
305
306 pub fn with_components(mut self, components: Vec<ComponentId>) -> Self {
308 self.components = components;
309 self
310 }
311
312 pub fn with_entities(mut self, entities: Vec<Entity>) -> Self {
314 self.entities = entities;
315 self
316 }
317
318 pub(crate) fn merge(&mut self, descriptor: &ObserverDescriptor) {
319 self.events.extend(descriptor.events.iter().copied());
320 self.components
321 .extend(descriptor.components.iter().copied());
322 self.entities.extend(descriptor.entities.iter().copied());
323 }
324
325 pub fn events(&self) -> &[ComponentId] {
327 &self.events
328 }
329
330 pub fn components(&self) -> &[ComponentId] {
332 &self.components
333 }
334
335 pub fn entities(&self) -> &[Entity] {
337 &self.entities
338 }
339}
340
341#[derive(Debug)]
343pub struct ObserverTrigger {
344 pub observer: Entity,
346 pub event_type: ComponentId,
348 components: SmallVec<[ComponentId; 2]>,
350 pub target: Entity,
352 pub caller: MaybeLocation,
354}
355
356impl ObserverTrigger {
357 pub fn components(&self) -> &[ComponentId] {
359 &self.components
360 }
361}
362
363type ObserverMap = EntityHashMap<ObserverRunner>;
365
366#[derive(Default, Debug)]
368pub struct CachedComponentObservers {
369 map: ObserverMap,
371 entity_map: EntityHashMap<ObserverMap>,
373}
374
375#[derive(Default, Debug)]
377pub struct CachedObservers {
378 map: ObserverMap,
380 component_observers: HashMap<ComponentId, CachedComponentObservers>,
382 entity_observers: EntityHashMap<ObserverMap>,
384}
385
386#[derive(Default, Debug)]
388pub struct Observers {
389 on_add: CachedObservers,
391 on_insert: CachedObservers,
392 on_replace: CachedObservers,
393 on_remove: CachedObservers,
394 on_despawn: CachedObservers,
395 cache: HashMap<ComponentId, CachedObservers>,
397}
398
399impl Observers {
400 pub(crate) fn get_observers(&mut self, event_type: ComponentId) -> &mut CachedObservers {
401 match event_type {
402 ON_ADD => &mut self.on_add,
403 ON_INSERT => &mut self.on_insert,
404 ON_REPLACE => &mut self.on_replace,
405 ON_REMOVE => &mut self.on_remove,
406 ON_DESPAWN => &mut self.on_despawn,
407 _ => self.cache.entry(event_type).or_default(),
408 }
409 }
410
411 pub(crate) fn try_get_observers(&self, event_type: ComponentId) -> Option<&CachedObservers> {
412 match event_type {
413 ON_ADD => Some(&self.on_add),
414 ON_INSERT => Some(&self.on_insert),
415 ON_REPLACE => Some(&self.on_replace),
416 ON_REMOVE => Some(&self.on_remove),
417 ON_DESPAWN => Some(&self.on_despawn),
418 _ => self.cache.get(&event_type),
419 }
420 }
421
422 pub(crate) fn invoke<T>(
424 mut world: DeferredWorld,
425 event_type: ComponentId,
426 target: Entity,
427 components: impl Iterator<Item = ComponentId> + Clone,
428 data: &mut T,
429 propagate: &mut bool,
430 caller: MaybeLocation,
431 ) {
432 let (mut world, observers) = unsafe {
434 let world = world.as_unsafe_world_cell();
435 world.increment_trigger_id();
437 let observers = world.observers();
438 let Some(observers) = observers.try_get_observers(event_type) else {
439 return;
440 };
441 (world.into_deferred(), observers)
443 };
444
445 let trigger_for_components = components.clone();
446
447 let mut trigger_observer = |(&observer, runner): (&Entity, &ObserverRunner)| {
448 (runner)(
449 world.reborrow(),
450 ObserverTrigger {
451 observer,
452 event_type,
453 components: components.clone().collect(),
454 target,
455 caller,
456 },
457 data.into(),
458 propagate,
459 );
460 };
461 observers.map.iter().for_each(&mut trigger_observer);
463
464 if target != Entity::PLACEHOLDER {
466 if let Some(map) = observers.entity_observers.get(&target) {
467 map.iter().for_each(&mut trigger_observer);
468 }
469 }
470
471 trigger_for_components.for_each(|id| {
473 if let Some(component_observers) = observers.component_observers.get(&id) {
474 component_observers
475 .map
476 .iter()
477 .for_each(&mut trigger_observer);
478
479 if target != Entity::PLACEHOLDER {
480 if let Some(map) = component_observers.entity_map.get(&target) {
481 map.iter().for_each(&mut trigger_observer);
482 }
483 }
484 }
485 });
486 }
487
488 pub(crate) fn is_archetype_cached(event_type: ComponentId) -> Option<ArchetypeFlags> {
489 match event_type {
490 ON_ADD => Some(ArchetypeFlags::ON_ADD_OBSERVER),
491 ON_INSERT => Some(ArchetypeFlags::ON_INSERT_OBSERVER),
492 ON_REPLACE => Some(ArchetypeFlags::ON_REPLACE_OBSERVER),
493 ON_REMOVE => Some(ArchetypeFlags::ON_REMOVE_OBSERVER),
494 ON_DESPAWN => Some(ArchetypeFlags::ON_DESPAWN_OBSERVER),
495 _ => None,
496 }
497 }
498
499 pub(crate) fn update_archetype_flags(
500 &self,
501 component_id: ComponentId,
502 flags: &mut ArchetypeFlags,
503 ) {
504 if self.on_add.component_observers.contains_key(&component_id) {
505 flags.insert(ArchetypeFlags::ON_ADD_OBSERVER);
506 }
507
508 if self
509 .on_insert
510 .component_observers
511 .contains_key(&component_id)
512 {
513 flags.insert(ArchetypeFlags::ON_INSERT_OBSERVER);
514 }
515
516 if self
517 .on_replace
518 .component_observers
519 .contains_key(&component_id)
520 {
521 flags.insert(ArchetypeFlags::ON_REPLACE_OBSERVER);
522 }
523
524 if self
525 .on_remove
526 .component_observers
527 .contains_key(&component_id)
528 {
529 flags.insert(ArchetypeFlags::ON_REMOVE_OBSERVER);
530 }
531
532 if self
533 .on_despawn
534 .component_observers
535 .contains_key(&component_id)
536 {
537 flags.insert(ArchetypeFlags::ON_DESPAWN_OBSERVER);
538 }
539 }
540}
541
542impl World {
543 pub fn add_observer<E: Event, B: Bundle, M>(
566 &mut self,
567 system: impl IntoObserverSystem<E, B, M>,
568 ) -> EntityWorldMut {
569 self.spawn(Observer::new(system))
570 }
571
572 #[track_caller]
578 pub fn trigger<E: Event>(&mut self, event: E) {
579 self.trigger_with_caller(event, MaybeLocation::caller());
580 }
581
582 pub(crate) fn trigger_with_caller<E: Event>(&mut self, mut event: E, caller: MaybeLocation) {
583 let event_id = E::register_component_id(self);
584 unsafe {
586 self.trigger_targets_dynamic_ref_with_caller(event_id, &mut event, (), caller);
587 }
588 }
589
590 #[track_caller]
595 pub fn trigger_ref<E: Event>(&mut self, event: &mut E) {
596 let event_id = E::register_component_id(self);
597 unsafe { self.trigger_targets_dynamic_ref(event_id, event, ()) };
599 }
600
601 #[track_caller]
607 pub fn trigger_targets<E: Event>(&mut self, event: E, targets: impl TriggerTargets) {
608 self.trigger_targets_with_caller(event, targets, MaybeLocation::caller());
609 }
610
611 pub(crate) fn trigger_targets_with_caller<E: Event>(
612 &mut self,
613 mut event: E,
614 targets: impl TriggerTargets,
615 caller: MaybeLocation,
616 ) {
617 let event_id = E::register_component_id(self);
618 unsafe {
620 self.trigger_targets_dynamic_ref_with_caller(event_id, &mut event, targets, caller);
621 }
622 }
623
624 #[track_caller]
630 pub fn trigger_targets_ref<E: Event>(&mut self, event: &mut E, targets: impl TriggerTargets) {
631 let event_id = E::register_component_id(self);
632 unsafe { self.trigger_targets_dynamic_ref(event_id, event, targets) };
634 }
635
636 #[track_caller]
646 pub unsafe fn trigger_targets_dynamic<E: Event, Targets: TriggerTargets>(
647 &mut self,
648 event_id: ComponentId,
649 mut event_data: E,
650 targets: Targets,
651 ) {
652 unsafe {
654 self.trigger_targets_dynamic_ref(event_id, &mut event_data, targets);
655 };
656 }
657
658 #[track_caller]
668 pub unsafe fn trigger_targets_dynamic_ref<E: Event, Targets: TriggerTargets>(
669 &mut self,
670 event_id: ComponentId,
671 event_data: &mut E,
672 targets: Targets,
673 ) {
674 self.trigger_targets_dynamic_ref_with_caller(
675 event_id,
676 event_data,
677 targets,
678 MaybeLocation::caller(),
679 );
680 }
681
682 unsafe fn trigger_targets_dynamic_ref_with_caller<E: Event, Targets: TriggerTargets>(
686 &mut self,
687 event_id: ComponentId,
688 event_data: &mut E,
689 targets: Targets,
690 caller: MaybeLocation,
691 ) {
692 let mut world = DeferredWorld::from(self);
693 let mut entity_targets = targets.entities().peekable();
694 if entity_targets.peek().is_none() {
695 unsafe {
697 world.trigger_observers_with_data::<_, E::Traversal>(
698 event_id,
699 Entity::PLACEHOLDER,
700 targets.components(),
701 event_data,
702 false,
703 caller,
704 );
705 };
706 } else {
707 for target_entity in entity_targets {
708 unsafe {
710 world.trigger_observers_with_data::<_, E::Traversal>(
711 event_id,
712 target_entity,
713 targets.components(),
714 event_data,
715 E::AUTO_PROPAGATE,
716 caller,
717 );
718 };
719 }
720 }
721 }
722
723 pub(crate) fn register_observer(&mut self, observer_entity: Entity) {
725 let (observer_state, archetypes, observers) = unsafe {
727 let observer_state: *const ObserverState =
728 self.get::<ObserverState>(observer_entity).unwrap();
729 for watched_entity in &(*observer_state).descriptor.entities {
731 let mut entity_mut = self.entity_mut(*watched_entity);
732 let mut observed_by = entity_mut.entry::<ObservedBy>().or_default().into_mut();
733 observed_by.0.push(observer_entity);
734 }
735 (&*observer_state, &mut self.archetypes, &mut self.observers)
736 };
737 let descriptor = &observer_state.descriptor;
738
739 for &event_type in &descriptor.events {
740 let cache = observers.get_observers(event_type);
741
742 if descriptor.components.is_empty() && descriptor.entities.is_empty() {
743 cache.map.insert(observer_entity, observer_state.runner);
744 } else if descriptor.components.is_empty() {
745 for &watched_entity in &observer_state.descriptor.entities {
747 let map = cache.entity_observers.entry(watched_entity).or_default();
748 map.insert(observer_entity, observer_state.runner);
749 }
750 } else {
751 for &component in &descriptor.components {
753 let observers =
754 cache
755 .component_observers
756 .entry(component)
757 .or_insert_with(|| {
758 if let Some(flag) = Observers::is_archetype_cached(event_type) {
759 archetypes.update_flags(component, flag, true);
760 }
761 CachedComponentObservers::default()
762 });
763 if descriptor.entities.is_empty() {
764 observers.map.insert(observer_entity, observer_state.runner);
766 } else {
767 for &watched_entity in &descriptor.entities {
769 let map = observers.entity_map.entry(watched_entity).or_default();
770 map.insert(observer_entity, observer_state.runner);
771 }
772 }
773 }
774 }
775 }
776 }
777
778 pub(crate) fn unregister_observer(&mut self, entity: Entity, descriptor: ObserverDescriptor) {
780 let archetypes = &mut self.archetypes;
781 let observers = &mut self.observers;
782
783 for &event_type in &descriptor.events {
784 let cache = observers.get_observers(event_type);
785 if descriptor.components.is_empty() && descriptor.entities.is_empty() {
786 cache.map.remove(&entity);
787 } else if descriptor.components.is_empty() {
788 for watched_entity in &descriptor.entities {
789 let Some(observers) = cache.entity_observers.get_mut(watched_entity) else {
791 continue;
792 };
793 observers.remove(&entity);
794 if observers.is_empty() {
795 cache.entity_observers.remove(watched_entity);
796 }
797 }
798 } else {
799 for component in &descriptor.components {
800 let Some(observers) = cache.component_observers.get_mut(component) else {
801 continue;
802 };
803 if descriptor.entities.is_empty() {
804 observers.map.remove(&entity);
805 } else {
806 for watched_entity in &descriptor.entities {
807 let Some(map) = observers.entity_map.get_mut(watched_entity) else {
808 continue;
809 };
810 map.remove(&entity);
811 if map.is_empty() {
812 observers.entity_map.remove(watched_entity);
813 }
814 }
815 }
816
817 if observers.map.is_empty() && observers.entity_map.is_empty() {
818 cache.component_observers.remove(component);
819 if let Some(flag) = Observers::is_archetype_cached(event_type) {
820 if let Some(by_component) = archetypes.by_component.get(component) {
821 for archetype in by_component.keys() {
822 let archetype = &mut archetypes.archetypes[archetype.index()];
823 if archetype.contains(*component) {
824 let no_longer_observed = archetype
825 .components()
826 .all(|id| !cache.component_observers.contains_key(&id));
827
828 if no_longer_observed {
829 archetype.flags.set(flag, false);
830 }
831 }
832 }
833 }
834 }
835 }
836 }
837 }
838 }
839 }
840}
841
842#[cfg(test)]
843mod tests {
844 use alloc::{vec, vec::Vec};
845
846 use bevy_platform::collections::HashMap;
847 use bevy_ptr::OwningPtr;
848
849 use crate::component::ComponentId;
850 use crate::{
851 change_detection::MaybeLocation,
852 observer::{Observer, ObserverDescriptor, ObserverState, OnReplace},
853 prelude::*,
854 traversal::Traversal,
855 };
856
857 #[derive(Component)]
858 struct A;
859
860 #[derive(Component)]
861 struct B;
862
863 #[derive(Component)]
864 struct C;
865
866 #[derive(Component)]
867 #[component(storage = "SparseSet")]
868 struct S;
869
870 #[derive(Event)]
871 struct EventA;
872
873 #[derive(Event)]
874 struct EventWithData {
875 counter: usize,
876 }
877
878 #[derive(Resource, Default)]
879 struct Order(Vec<&'static str>);
880
881 impl Order {
882 #[track_caller]
883 fn observed(&mut self, name: &'static str) {
884 self.0.push(name);
885 }
886 }
887
888 #[derive(Component)]
889 struct ChildOf(Entity);
890
891 impl<D> Traversal<D> for &'_ ChildOf {
892 fn traverse(item: Self::Item<'_>, _: &D) -> Option<Entity> {
893 Some(item.0)
894 }
895 }
896
897 #[derive(Component, Event)]
898 #[event(traversal = &'static ChildOf, auto_propagate)]
899 struct EventPropagating;
900
901 #[test]
902 fn observer_order_spawn_despawn() {
903 let mut world = World::new();
904 world.init_resource::<Order>();
905
906 world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add"));
907 world
908 .add_observer(|_: Trigger<OnInsert, A>, mut res: ResMut<Order>| res.observed("insert"));
909 world.add_observer(|_: Trigger<OnReplace, A>, mut res: ResMut<Order>| {
910 res.observed("replace");
911 });
912 world
913 .add_observer(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove"));
914
915 let entity = world.spawn(A).id();
916 world.despawn(entity);
917 assert_eq!(
918 vec!["add", "insert", "replace", "remove"],
919 world.resource::<Order>().0
920 );
921 }
922
923 #[test]
924 fn observer_order_insert_remove() {
925 let mut world = World::new();
926 world.init_resource::<Order>();
927
928 world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add"));
929 world
930 .add_observer(|_: Trigger<OnInsert, A>, mut res: ResMut<Order>| res.observed("insert"));
931 world.add_observer(|_: Trigger<OnReplace, A>, mut res: ResMut<Order>| {
932 res.observed("replace");
933 });
934 world
935 .add_observer(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove"));
936
937 let mut entity = world.spawn_empty();
938 entity.insert(A);
939 entity.remove::<A>();
940 entity.flush();
941 assert_eq!(
942 vec!["add", "insert", "replace", "remove"],
943 world.resource::<Order>().0
944 );
945 }
946
947 #[test]
948 fn observer_order_insert_remove_sparse() {
949 let mut world = World::new();
950 world.init_resource::<Order>();
951
952 world.add_observer(|_: Trigger<OnAdd, S>, mut res: ResMut<Order>| res.observed("add"));
953 world
954 .add_observer(|_: Trigger<OnInsert, S>, mut res: ResMut<Order>| res.observed("insert"));
955 world.add_observer(|_: Trigger<OnReplace, S>, mut res: ResMut<Order>| {
956 res.observed("replace");
957 });
958 world
959 .add_observer(|_: Trigger<OnRemove, S>, mut res: ResMut<Order>| res.observed("remove"));
960
961 let mut entity = world.spawn_empty();
962 entity.insert(S);
963 entity.remove::<S>();
964 entity.flush();
965 assert_eq!(
966 vec!["add", "insert", "replace", "remove"],
967 world.resource::<Order>().0
968 );
969 }
970
971 #[test]
972 fn observer_order_replace() {
973 let mut world = World::new();
974 world.init_resource::<Order>();
975
976 let entity = world.spawn(A).id();
977
978 world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add"));
979 world
980 .add_observer(|_: Trigger<OnInsert, A>, mut res: ResMut<Order>| res.observed("insert"));
981 world.add_observer(|_: Trigger<OnReplace, A>, mut res: ResMut<Order>| {
982 res.observed("replace");
983 });
984 world
985 .add_observer(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove"));
986
987 world.flush();
990
991 let mut entity = world.entity_mut(entity);
992 entity.insert(A);
993 entity.flush();
994 assert_eq!(vec!["replace", "insert"], world.resource::<Order>().0);
995 }
996
997 #[test]
998 fn observer_order_recursive() {
999 let mut world = World::new();
1000 world.init_resource::<Order>();
1001 world.add_observer(
1002 |obs: Trigger<OnAdd, A>, mut res: ResMut<Order>, mut commands: Commands| {
1003 res.observed("add_a");
1004 commands.entity(obs.target()).insert(B);
1005 },
1006 );
1007 world.add_observer(
1008 |obs: Trigger<OnRemove, A>, mut res: ResMut<Order>, mut commands: Commands| {
1009 res.observed("remove_a");
1010 commands.entity(obs.target()).remove::<B>();
1011 },
1012 );
1013
1014 world.add_observer(
1015 |obs: Trigger<OnAdd, B>, mut res: ResMut<Order>, mut commands: Commands| {
1016 res.observed("add_b");
1017 commands.entity(obs.target()).remove::<A>();
1018 },
1019 );
1020 world.add_observer(|_: Trigger<OnRemove, B>, mut res: ResMut<Order>| {
1021 res.observed("remove_b");
1022 });
1023
1024 let entity = world.spawn(A).flush();
1025 let entity = world.get_entity(entity).unwrap();
1026 assert!(!entity.contains::<A>());
1027 assert!(!entity.contains::<B>());
1028 assert_eq!(
1029 vec!["add_a", "add_b", "remove_a", "remove_b"],
1030 world.resource::<Order>().0
1031 );
1032 }
1033
1034 #[test]
1035 fn observer_trigger_ref() {
1036 let mut world = World::new();
1037
1038 world.add_observer(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 1);
1039 world.add_observer(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 2);
1040 world.add_observer(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 4);
1041 world.flush();
1044
1045 let mut event = EventWithData { counter: 0 };
1046 world.trigger_ref(&mut event);
1047 assert_eq!(7, event.counter);
1048 }
1049
1050 #[test]
1051 fn observer_trigger_targets_ref() {
1052 let mut world = World::new();
1053
1054 world.add_observer(|mut trigger: Trigger<EventWithData, A>| {
1055 trigger.event_mut().counter += 1;
1056 });
1057 world.add_observer(|mut trigger: Trigger<EventWithData, B>| {
1058 trigger.event_mut().counter += 2;
1059 });
1060 world.add_observer(|mut trigger: Trigger<EventWithData, A>| {
1061 trigger.event_mut().counter += 4;
1062 });
1063 world.flush();
1066
1067 let mut event = EventWithData { counter: 0 };
1068 let component_a = world.register_component::<A>();
1069 world.trigger_targets_ref(&mut event, component_a);
1070 assert_eq!(5, event.counter);
1071 }
1072
1073 #[test]
1074 fn observer_multiple_listeners() {
1075 let mut world = World::new();
1076 world.init_resource::<Order>();
1077
1078 world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add_1"));
1079 world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add_2"));
1080
1081 world.spawn(A).flush();
1082 assert_eq!(vec!["add_1", "add_2"], world.resource::<Order>().0);
1083 assert_eq!(world.entities().len(), 3);
1085 }
1086
1087 #[test]
1088 fn observer_multiple_events() {
1089 let mut world = World::new();
1090 world.init_resource::<Order>();
1091 let on_remove = OnRemove::register_component_id(&mut world);
1092 world.spawn(
1093 unsafe {
1095 Observer::new(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| {
1096 res.observed("add/remove");
1097 })
1098 .with_event(on_remove)
1099 },
1100 );
1101
1102 let entity = world.spawn(A).id();
1103 world.despawn(entity);
1104 assert_eq!(
1105 vec!["add/remove", "add/remove"],
1106 world.resource::<Order>().0
1107 );
1108 }
1109
1110 #[test]
1111 fn observer_multiple_components() {
1112 let mut world = World::new();
1113 world.init_resource::<Order>();
1114 world.register_component::<A>();
1115 world.register_component::<B>();
1116
1117 world.add_observer(|_: Trigger<OnAdd, (A, B)>, mut res: ResMut<Order>| {
1118 res.observed("add_ab");
1119 });
1120
1121 let entity = world.spawn(A).id();
1122 world.entity_mut(entity).insert(B);
1123 world.flush();
1124 assert_eq!(vec!["add_ab", "add_ab"], world.resource::<Order>().0);
1125 }
1126
1127 #[test]
1128 fn observer_despawn() {
1129 let mut world = World::new();
1130
1131 let system: fn(Trigger<OnAdd, A>) = |_| {
1132 panic!("Observer triggered after being despawned.");
1133 };
1134 let observer = world.add_observer(system).id();
1135 world.despawn(observer);
1136 world.spawn(A).flush();
1137 }
1138
1139 #[test]
1141 fn observer_despawn_archetype_flags() {
1142 let mut world = World::new();
1143 world.init_resource::<Order>();
1144
1145 let entity = world.spawn((A, B)).flush();
1146
1147 world.add_observer(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| {
1148 res.observed("remove_a");
1149 });
1150
1151 let system: fn(Trigger<OnRemove, B>) = |_: Trigger<OnRemove, B>| {
1152 panic!("Observer triggered after being despawned.");
1153 };
1154
1155 let observer = world.add_observer(system).flush();
1156 world.despawn(observer);
1157
1158 world.despawn(entity);
1159
1160 assert_eq!(vec!["remove_a"], world.resource::<Order>().0);
1161 }
1162
1163 #[test]
1164 fn observer_multiple_matches() {
1165 let mut world = World::new();
1166 world.init_resource::<Order>();
1167
1168 world.add_observer(|_: Trigger<OnAdd, (A, B)>, mut res: ResMut<Order>| {
1169 res.observed("add_ab");
1170 });
1171
1172 world.spawn((A, B)).flush();
1173 assert_eq!(vec!["add_ab"], world.resource::<Order>().0);
1174 }
1175
1176 #[test]
1177 fn observer_no_target() {
1178 let mut world = World::new();
1179 world.init_resource::<Order>();
1180
1181 let system: fn(Trigger<EventA>) = |_| {
1182 panic!("Trigger routed to non-targeted entity.");
1183 };
1184 world.spawn_empty().observe(system);
1185 world.add_observer(move |obs: Trigger<EventA>, mut res: ResMut<Order>| {
1186 assert_eq!(obs.target(), Entity::PLACEHOLDER);
1187 res.observed("event_a");
1188 });
1189
1190 world.flush();
1193 world.trigger(EventA);
1194 world.flush();
1195 assert_eq!(vec!["event_a"], world.resource::<Order>().0);
1196 }
1197
1198 #[test]
1199 fn observer_entity_routing() {
1200 let mut world = World::new();
1201 world.init_resource::<Order>();
1202
1203 let system: fn(Trigger<EventA>) = |_| {
1204 panic!("Trigger routed to non-targeted entity.");
1205 };
1206
1207 world.spawn_empty().observe(system);
1208 let entity = world
1209 .spawn_empty()
1210 .observe(|_: Trigger<EventA>, mut res: ResMut<Order>| res.observed("a_1"))
1211 .id();
1212 world.add_observer(move |obs: Trigger<EventA>, mut res: ResMut<Order>| {
1213 assert_eq!(obs.target(), entity);
1214 res.observed("a_2");
1215 });
1216
1217 world.flush();
1220 world.trigger_targets(EventA, entity);
1221 world.flush();
1222 assert_eq!(vec!["a_2", "a_1"], world.resource::<Order>().0);
1223 }
1224
1225 #[test]
1226 fn observer_multiple_targets() {
1227 #[derive(Resource, Default)]
1228 struct R(i32);
1229
1230 let mut world = World::new();
1231 let component_a = world.register_component::<A>();
1232 let component_b = world.register_component::<B>();
1233 world.init_resource::<R>();
1234
1235 let entity_1 = world
1237 .spawn_empty()
1238 .observe(|_: Trigger<EventA, A>, mut res: ResMut<R>| res.0 += 1)
1239 .id();
1240 let entity_2 = world
1242 .spawn_empty()
1243 .observe(|_: Trigger<EventA, B>, mut res: ResMut<R>| res.0 += 10)
1244 .id();
1245 world.add_observer(|_: Trigger<EventA>, mut res: ResMut<R>| res.0 += 100);
1247 world.add_observer(|_: Trigger<EventA, (A, B)>, mut res: ResMut<R>| res.0 += 1000);
1249 world.add_observer(|_: Trigger<EventA, (A, B, (A, B))>, mut res: ResMut<R>| res.0 += 10000);
1251 world.add_observer(
1252 |_: Trigger<EventA, (A, B, (A, B), ((A, B), (A, B)))>, mut res: ResMut<R>| {
1253 res.0 += 100000;
1254 },
1255 );
1256 world.add_observer(
1257 |_: Trigger<EventA, (A, B, (A, B), (B, A), (A, B, ((A, B), (B, A))))>,
1258 mut res: ResMut<R>| res.0 += 1000000,
1259 );
1260
1261 world.flush();
1263
1264 world.trigger_targets(EventA, (entity_1, component_a));
1266 world.flush();
1267 assert_eq!(1111101, world.resource::<R>().0);
1269 world.resource_mut::<R>().0 = 0;
1270
1271 world.trigger_targets(EventA, (entity_1, entity_2));
1273 world.flush();
1274 assert_eq!(200, world.resource::<R>().0);
1276 world.resource_mut::<R>().0 = 0;
1277
1278 world.trigger_targets(EventA, (component_a, component_b));
1280 world.flush();
1281 assert_eq!(1111100, world.resource::<R>().0);
1283 world.resource_mut::<R>().0 = 0;
1284
1285 world.trigger_targets(EventA, ((component_a, component_b), (entity_1, entity_2)));
1288 world.flush();
1289 assert_eq!(2222211, world.resource::<R>().0);
1290 world.resource_mut::<R>().0 = 0;
1291
1292 world.trigger_targets(
1294 EventA,
1295 (component_a, component_b, (component_a, component_b)),
1296 );
1297 world.flush();
1298 assert_eq!(1111100, world.resource::<R>().0);
1300 world.resource_mut::<R>().0 = 0;
1301
1302 world.trigger_targets(
1304 EventA,
1305 (
1306 component_a,
1307 component_b,
1308 (component_a, component_b),
1309 ((component_a, component_b), (component_a, component_b)),
1310 ),
1311 );
1312 world.flush();
1313 assert_eq!(1111100, world.resource::<R>().0);
1315 world.resource_mut::<R>().0 = 0;
1316
1317 world.trigger_targets(
1319 EventA,
1320 (
1321 component_a,
1322 component_b,
1323 (component_a, component_b),
1324 (component_b, component_a),
1325 (
1326 component_a,
1327 component_b,
1328 ((component_a, component_b), (component_b, component_a)),
1329 ),
1330 ),
1331 );
1332 world.flush();
1333 assert_eq!(1111100, world.resource::<R>().0);
1335 world.resource_mut::<R>().0 = 0;
1336 }
1337
1338 #[test]
1339 fn observer_dynamic_component() {
1340 let mut world = World::new();
1341 world.init_resource::<Order>();
1342
1343 let component_id = world.register_component::<A>();
1344 world.spawn(
1345 Observer::new(|_: Trigger<OnAdd>, mut res: ResMut<Order>| res.observed("event_a"))
1346 .with_component(component_id),
1347 );
1348
1349 let mut entity = world.spawn_empty();
1350 OwningPtr::make(A, |ptr| {
1351 unsafe { entity.insert_by_id(component_id, ptr) };
1353 });
1354 let entity = entity.flush();
1355
1356 world.trigger_targets(EventA, entity);
1357 world.flush();
1358 assert_eq!(vec!["event_a"], world.resource::<Order>().0);
1359 }
1360
1361 #[test]
1362 fn observer_dynamic_trigger() {
1363 let mut world = World::new();
1364 world.init_resource::<Order>();
1365 let event_a = OnRemove::register_component_id(&mut world);
1366
1367 world.spawn(ObserverState {
1368 descriptor: unsafe { ObserverDescriptor::default().with_events(vec![event_a]) },
1370 runner: |mut world, _trigger, _ptr, _propagate| {
1371 world.resource_mut::<Order>().observed("event_a");
1372 },
1373 ..Default::default()
1374 });
1375
1376 world.commands().queue(move |world: &mut World| {
1377 unsafe { world.trigger_targets_dynamic(event_a, EventA, ()) };
1379 });
1380 world.flush();
1381 assert_eq!(vec!["event_a"], world.resource::<Order>().0);
1382 }
1383
1384 #[test]
1385 fn observer_propagating() {
1386 let mut world = World::new();
1387 world.init_resource::<Order>();
1388
1389 let parent = world
1390 .spawn_empty()
1391 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1392 res.observed("parent");
1393 })
1394 .id();
1395
1396 let child = world
1397 .spawn(ChildOf(parent))
1398 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1399 res.observed("child");
1400 })
1401 .id();
1402
1403 world.flush();
1406 world.trigger_targets(EventPropagating, child);
1407 world.flush();
1408 assert_eq!(vec!["child", "parent"], world.resource::<Order>().0);
1409 }
1410
1411 #[test]
1412 fn observer_propagating_redundant_dispatch_same_entity() {
1413 let mut world = World::new();
1414 world.init_resource::<Order>();
1415
1416 let parent = world
1417 .spawn_empty()
1418 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1419 res.observed("parent");
1420 })
1421 .id();
1422
1423 let child = world
1424 .spawn(ChildOf(parent))
1425 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1426 res.observed("child");
1427 })
1428 .id();
1429
1430 world.flush();
1433 world.trigger_targets(EventPropagating, [child, child]);
1434 world.flush();
1435 assert_eq!(
1436 vec!["child", "parent", "child", "parent"],
1437 world.resource::<Order>().0
1438 );
1439 }
1440
1441 #[test]
1442 fn observer_propagating_redundant_dispatch_parent_child() {
1443 let mut world = World::new();
1444 world.init_resource::<Order>();
1445
1446 let parent = world
1447 .spawn_empty()
1448 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1449 res.observed("parent");
1450 })
1451 .id();
1452
1453 let child = world
1454 .spawn(ChildOf(parent))
1455 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1456 res.observed("child");
1457 })
1458 .id();
1459
1460 world.flush();
1463 world.trigger_targets(EventPropagating, [child, parent]);
1464 world.flush();
1465 assert_eq!(
1466 vec!["child", "parent", "parent"],
1467 world.resource::<Order>().0
1468 );
1469 }
1470
1471 #[test]
1472 fn observer_propagating_halt() {
1473 let mut world = World::new();
1474 world.init_resource::<Order>();
1475
1476 let parent = world
1477 .spawn_empty()
1478 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1479 res.observed("parent");
1480 })
1481 .id();
1482
1483 let child = world
1484 .spawn(ChildOf(parent))
1485 .observe(
1486 |mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1487 res.observed("child");
1488 trigger.propagate(false);
1489 },
1490 )
1491 .id();
1492
1493 world.flush();
1496 world.trigger_targets(EventPropagating, child);
1497 world.flush();
1498 assert_eq!(vec!["child"], world.resource::<Order>().0);
1499 }
1500
1501 #[test]
1502 fn observer_propagating_join() {
1503 let mut world = World::new();
1504 world.init_resource::<Order>();
1505
1506 let parent = world
1507 .spawn_empty()
1508 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1509 res.observed("parent");
1510 })
1511 .id();
1512
1513 let child_a = world
1514 .spawn(ChildOf(parent))
1515 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1516 res.observed("child_a");
1517 })
1518 .id();
1519
1520 let child_b = world
1521 .spawn(ChildOf(parent))
1522 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1523 res.observed("child_b");
1524 })
1525 .id();
1526
1527 world.flush();
1530 world.trigger_targets(EventPropagating, [child_a, child_b]);
1531 world.flush();
1532 assert_eq!(
1533 vec!["child_a", "parent", "child_b", "parent"],
1534 world.resource::<Order>().0
1535 );
1536 }
1537
1538 #[test]
1539 fn observer_propagating_no_next() {
1540 let mut world = World::new();
1541 world.init_resource::<Order>();
1542
1543 let entity = world
1544 .spawn_empty()
1545 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1546 res.observed("event");
1547 })
1548 .id();
1549
1550 world.flush();
1553 world.trigger_targets(EventPropagating, entity);
1554 world.flush();
1555 assert_eq!(vec!["event"], world.resource::<Order>().0);
1556 }
1557
1558 #[test]
1559 fn observer_propagating_parallel_propagation() {
1560 let mut world = World::new();
1561 world.init_resource::<Order>();
1562
1563 let parent_a = world
1564 .spawn_empty()
1565 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1566 res.observed("parent_a");
1567 })
1568 .id();
1569
1570 let child_a = world
1571 .spawn(ChildOf(parent_a))
1572 .observe(
1573 |mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1574 res.observed("child_a");
1575 trigger.propagate(false);
1576 },
1577 )
1578 .id();
1579
1580 let parent_b = world
1581 .spawn_empty()
1582 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1583 res.observed("parent_b");
1584 })
1585 .id();
1586
1587 let child_b = world
1588 .spawn(ChildOf(parent_b))
1589 .observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1590 res.observed("child_b");
1591 })
1592 .id();
1593
1594 world.flush();
1597 world.trigger_targets(EventPropagating, [child_a, child_b]);
1598 world.flush();
1599 assert_eq!(
1600 vec!["child_a", "child_b", "parent_b"],
1601 world.resource::<Order>().0
1602 );
1603 }
1604
1605 #[test]
1606 fn observer_propagating_world() {
1607 let mut world = World::new();
1608 world.init_resource::<Order>();
1609
1610 world.add_observer(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
1611 res.observed("event");
1612 });
1613
1614 let grandparent = world.spawn_empty().id();
1615 let parent = world.spawn(ChildOf(grandparent)).id();
1616 let child = world.spawn(ChildOf(parent)).id();
1617
1618 world.flush();
1621 world.trigger_targets(EventPropagating, child);
1622 world.flush();
1623 assert_eq!(vec!["event", "event", "event"], world.resource::<Order>().0);
1624 }
1625
1626 #[test]
1627 fn observer_propagating_world_skipping() {
1628 let mut world = World::new();
1629 world.init_resource::<Order>();
1630
1631 world.add_observer(
1632 |trigger: Trigger<EventPropagating>, query: Query<&A>, mut res: ResMut<Order>| {
1633 if query.get(trigger.target()).is_ok() {
1634 res.observed("event");
1635 }
1636 },
1637 );
1638
1639 let grandparent = world.spawn(A).id();
1640 let parent = world.spawn(ChildOf(grandparent)).id();
1641 let child = world.spawn((A, ChildOf(parent))).id();
1642
1643 world.flush();
1646 world.trigger_targets(EventPropagating, child);
1647 world.flush();
1648 assert_eq!(vec!["event", "event"], world.resource::<Order>().0);
1649 }
1650
1651 #[test]
1653 fn observer_modifies_relationship() {
1654 fn on_add(trigger: Trigger<OnAdd, A>, mut commands: Commands) {
1655 commands
1656 .entity(trigger.target())
1657 .with_related_entities::<crate::hierarchy::ChildOf>(|rsc| {
1658 rsc.spawn_empty();
1659 });
1660 }
1661
1662 let mut world = World::new();
1663 world.add_observer(on_add);
1664 world.spawn(A);
1665 world.flush();
1666 }
1667
1668 #[test]
1671 fn observer_on_remove_during_despawn_spawn_empty() {
1672 let mut world = World::new();
1673
1674 world.add_observer(|_: Trigger<OnRemove, A>, mut cmd: Commands| {
1676 cmd.spawn_empty();
1679 });
1680
1681 let ent = world.spawn(A).id();
1682
1683 world.despawn(ent);
1688 }
1689
1690 #[test]
1691 #[should_panic]
1692 fn observer_invalid_params() {
1693 #[derive(Resource)]
1694 struct ResA;
1695
1696 #[derive(Resource)]
1697 struct ResB;
1698
1699 let mut world = World::new();
1700 world.add_observer(|_: Trigger<EventA>, _: Res<ResA>, mut commands: Commands| {
1702 commands.insert_resource(ResB);
1703 });
1704 world.trigger(EventA);
1705 }
1706
1707 #[test]
1708 fn observer_apply_deferred_from_param_set() {
1709 #[derive(Resource)]
1710 struct ResA;
1711
1712 let mut world = World::new();
1713 world.add_observer(
1714 |_: Trigger<EventA>, mut params: ParamSet<(Query<Entity>, Commands)>| {
1715 params.p1().insert_resource(ResA);
1716 },
1717 );
1718 world.flush();
1721 world.trigger(EventA);
1722 world.flush();
1723
1724 assert!(world.get_resource::<ResA>().is_some());
1725 }
1726
1727 #[test]
1728 #[track_caller]
1729 fn observer_caller_location_event() {
1730 #[derive(Event)]
1731 struct EventA;
1732
1733 let caller = MaybeLocation::caller();
1734 let mut world = World::new();
1735 world.add_observer(move |trigger: Trigger<EventA>| {
1736 assert_eq!(trigger.caller(), caller);
1737 });
1738 world.trigger(EventA);
1739 }
1740
1741 #[test]
1742 #[track_caller]
1743 fn observer_caller_location_command_archetype_move() {
1744 #[derive(Component)]
1745 struct Component;
1746
1747 let caller = MaybeLocation::caller();
1748 let mut world = World::new();
1749 world.add_observer(move |trigger: Trigger<OnAdd, Component>| {
1750 assert_eq!(trigger.caller(), caller);
1751 });
1752 world.add_observer(move |trigger: Trigger<OnRemove, Component>| {
1753 assert_eq!(trigger.caller(), caller);
1754 });
1755 world.commands().spawn(Component).clear();
1756 world.flush();
1757 }
1758
1759 #[test]
1760 fn observer_triggered_components() {
1761 #[derive(Resource, Default)]
1762 struct Counter(HashMap<ComponentId, usize>);
1763
1764 let mut world = World::new();
1765 world.init_resource::<Counter>();
1766 let a_id = world.register_component::<A>();
1767 let b_id = world.register_component::<B>();
1768
1769 world.add_observer(
1770 |trigger: Trigger<EventA, (A, B)>, mut counter: ResMut<Counter>| {
1771 for &component in trigger.components() {
1772 *counter.0.entry(component).or_default() += 1;
1773 }
1774 },
1775 );
1776 world.flush();
1777
1778 world.trigger_targets(EventA, [a_id, b_id]);
1779 world.trigger_targets(EventA, a_id);
1780 world.trigger_targets(EventA, b_id);
1781 world.trigger_targets(EventA, [a_id, b_id]);
1782 world.trigger_targets(EventA, a_id);
1783 world.flush();
1784
1785 let counter = world.resource::<Counter>();
1786 assert_eq!(4, *counter.0.get(&a_id).unwrap());
1787 assert_eq!(3, *counter.0.get(&b_id).unwrap());
1788 }
1789}