diff --git a/crates/bevy_ecs/src/observer/mod.rs b/crates/bevy_ecs/src/observer/mod.rs index 600384d478438..3c6037b010dc1 100644 --- a/crates/bevy_ecs/src/observer/mod.rs +++ b/crates/bevy_ecs/src/observer/mod.rs @@ -55,11 +55,30 @@ impl<'w, E, B: Bundle> Trigger<'w, E, B> { Ptr::from(&self.event) } - /// Returns the entity that triggered the observer, could be [`Entity::PLACEHOLDER`]. + /// Returns the entity that triggered the observer. + /// + /// # Panics + /// + /// Panics if the entity is [`Entity::PLACEHOLDER`]. + /// Use [`Trigger::get_entity`] if you want to handle the case where the entity is a placeholder. pub fn entity(&self) -> Entity { + if self.trigger.entity == Entity::PLACEHOLDER { + panic!( + "called `Trigger::entity()` when the target entity was a `Entity::PLACEHOLDER`." + ); + } self.trigger.entity } + /// Returns the entity that triggered the observer, if it's not a placeholder entity. + pub fn get_entity(&self) -> Option { + if self.trigger.entity == Entity::PLACEHOLDER { + None + } else { + Some(self.trigger.entity) + } + } + /// Enables or disables event propagation, allowing the same event to trigger observers on a chain of different entities. /// /// The path an event will propagate along is specified by its associated [`Traversal`] component. By default, events @@ -665,7 +684,7 @@ mod tests { .spawn_empty() .observe(|_: Trigger| panic!("Trigger routed to non-targeted entity.")); world.observe(move |obs: Trigger, mut res: ResMut| { - assert_eq!(obs.entity(), Entity::PLACEHOLDER); + assert_eq!(obs.get_entity(), None); res.0 += 1; }); @@ -959,7 +978,11 @@ mod tests { world.observe( |trigger: Trigger, query: Query<&A>, mut res: ResMut| { - if query.get(trigger.entity()).is_ok() { + if trigger + .get_entity() + .map(|entity| query.get(entity).is_ok()) + .unwrap_or_default() + { res.0 += 1; } }, diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 9aa59bb6fd8ed..e2a2401e5271a 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -576,7 +576,7 @@ mod tests { }) } - fn observe_trigger(app: &mut App, scene_id: InstanceId, scene_entity: Entity) { + fn observe_trigger(app: &mut App, scene_id: InstanceId, scene_entity: Option) { // Add observer app.world_mut().observe( move |trigger: Trigger, @@ -588,7 +588,7 @@ mod tests { "`SceneInstanceReady` contains the wrong `InstanceId`" ); assert_eq!( - trigger.entity(), + trigger.get_entity(), scene_entity, "`SceneInstanceReady` triggered on the wrong parent entity" ); @@ -626,7 +626,7 @@ mod tests { }); // Check trigger. - observe_trigger(&mut app, scene_id, Entity::PLACEHOLDER); + observe_trigger(&mut app, scene_id, None); } #[test] @@ -644,7 +644,7 @@ mod tests { }); // Check trigger. - observe_trigger(&mut app, scene_id, Entity::PLACEHOLDER); + observe_trigger(&mut app, scene_id, None); } #[test] @@ -664,7 +664,7 @@ mod tests { ); // Check trigger. - observe_trigger(&mut app, scene_id, scene_entity); + observe_trigger(&mut app, scene_id, Some(scene_entity)); } #[test] @@ -684,7 +684,7 @@ mod tests { ); // Check trigger. - observe_trigger(&mut app, scene_id, scene_entity); + observe_trigger(&mut app, scene_id, Some(scene_entity)); } #[test] diff --git a/examples/ecs/observer_propagation.rs b/examples/ecs/observer_propagation.rs index f51b6e5f902c3..d90581036579d 100644 --- a/examples/ecs/observer_propagation.rs +++ b/examples/ecs/observer_propagation.rs @@ -78,8 +78,10 @@ fn attack_armor(entities: Query>, mut commands: Commands) { } fn attack_hits(trigger: Trigger, name: Query<&Name>) { - if let Ok(name) = name.get(trigger.entity()) { - info!("Attack hit {}", name); + if let Some(entity) = trigger.get_entity() { + if let Ok(name) = name.get(entity) { + info!("Attack hit {}", name); + } } } diff --git a/examples/ecs/observers.rs b/examples/ecs/observers.rs index aae7d446e96f4..85c07be72c940 100644 --- a/examples/ecs/observers.rs +++ b/examples/ecs/observers.rs @@ -147,7 +147,9 @@ fn on_remove_mine( fn explode_mine(trigger: Trigger, query: Query<&Mine>, mut commands: Commands) { // If a triggered event is targeting a specific entity you can access it with `.entity()` - let id = trigger.entity(); + let Some(id) = trigger.get_entity() else { + return; + }; let Some(mut entity) = commands.get_entity(id) else { return; };