Skip to content

Remove entity placeholder from observers #19440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/bevy_ecs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,8 @@ let mut world = World::new();
let entity = world.spawn_empty().id();

world.add_observer(|trigger: Trigger<Explode>, mut commands: Commands| {
println!("Entity {} goes BOOM!", trigger.target());
commands.entity(trigger.target()).despawn();
println!("Entity {} goes BOOM!", trigger.target().unwrap());
commands.entity(trigger.target().unwrap()).despawn();
});

world.flush();
Expand Down
16 changes: 8 additions & 8 deletions crates/bevy_ecs/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ impl<'w> BundleInserter<'w> {
if archetype.has_replace_observer() {
deferred_world.trigger_observers(
ON_REPLACE,
entity,
Some(entity),
archetype_after_insert.iter_existing(),
caller,
);
Expand Down Expand Up @@ -1318,7 +1318,7 @@ impl<'w> BundleInserter<'w> {
if new_archetype.has_add_observer() {
deferred_world.trigger_observers(
ON_ADD,
entity,
Some(entity),
archetype_after_insert.iter_added(),
caller,
);
Expand All @@ -1336,7 +1336,7 @@ impl<'w> BundleInserter<'w> {
if new_archetype.has_insert_observer() {
deferred_world.trigger_observers(
ON_INSERT,
entity,
Some(entity),
archetype_after_insert.iter_inserted(),
caller,
);
Expand All @@ -1355,7 +1355,7 @@ impl<'w> BundleInserter<'w> {
if new_archetype.has_insert_observer() {
deferred_world.trigger_observers(
ON_INSERT,
entity,
Some(entity),
archetype_after_insert.iter_added(),
caller,
);
Expand Down Expand Up @@ -1499,7 +1499,7 @@ impl<'w> BundleRemover<'w> {
if self.old_archetype.as_ref().has_replace_observer() {
deferred_world.trigger_observers(
ON_REPLACE,
entity,
Some(entity),
bundle_components_in_archetype(),
caller,
);
Expand All @@ -1514,7 +1514,7 @@ impl<'w> BundleRemover<'w> {
if self.old_archetype.as_ref().has_remove_observer() {
deferred_world.trigger_observers(
ON_REMOVE,
entity,
Some(entity),
bundle_components_in_archetype(),
caller,
);
Expand Down Expand Up @@ -1757,7 +1757,7 @@ impl<'w> BundleSpawner<'w> {
if archetype.has_add_observer() {
deferred_world.trigger_observers(
ON_ADD,
entity,
Some(entity),
bundle_info.iter_contributed_components(),
caller,
);
Expand All @@ -1772,7 +1772,7 @@ impl<'w> BundleSpawner<'w> {
if archetype.has_insert_observer() {
deferred_world.trigger_observers(
ON_INSERT,
entity,
Some(entity),
bundle_info.iter_contributed_components(),
caller,
);
Expand Down
34 changes: 17 additions & 17 deletions crates/bevy_ecs/src/observer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl<'w, E, B: Bundle> Trigger<'w, E, B> {
}

/// Returns the [`Entity`] that was targeted by the `event` that triggered this observer. It may
/// be [`Entity::PLACEHOLDER`].
/// be [`None`] if the trigger is not for a particular entity.
///
/// Observable events can target specific entities. When those events fire, they will trigger
/// any observers on the targeted entities. In this case, the `target()` and `observer()` are
Expand All @@ -81,7 +81,7 @@ impl<'w, E, B: Bundle> Trigger<'w, E, B> {
///
/// This is an important distinction: the entity reacting to an event is not always the same as
/// the entity triggered by the event.
pub fn target(&self) -> Entity {
pub fn target(&self) -> Option<Entity> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation still talks about Entity::PLACEHOLDER, this should probably be updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed!

self.trigger.target
}

Expand Down Expand Up @@ -341,7 +341,7 @@ pub struct ObserverTrigger {
/// The [`ComponentId`]s the trigger targeted.
components: SmallVec<[ComponentId; 2]>,
/// The entity the trigger targeted.
pub target: Entity,
pub target: Option<Entity>,
/// The location of the source code that triggered the observer.
pub caller: MaybeLocation,
}
Expand Down Expand Up @@ -416,7 +416,7 @@ impl Observers {
pub(crate) fn invoke<T>(
mut world: DeferredWorld,
event_type: ComponentId,
target: Entity,
target: Option<Entity>,
components: impl Iterator<Item = ComponentId> + Clone,
data: &mut T,
propagate: &mut bool,
Expand Down Expand Up @@ -455,8 +455,8 @@ impl Observers {
observers.map.iter().for_each(&mut trigger_observer);

// Trigger entity observers listening for this kind of trigger
if target != Entity::PLACEHOLDER {
if let Some(map) = observers.entity_observers.get(&target) {
if let Some(target_entity) = target {
if let Some(map) = observers.entity_observers.get(&target_entity) {
map.iter().for_each(&mut trigger_observer);
}
}
Expand All @@ -469,8 +469,8 @@ impl Observers {
.iter()
.for_each(&mut trigger_observer);

if target != Entity::PLACEHOLDER {
if let Some(map) = component_observers.entity_map.get(&target) {
if let Some(target_entity) = target {
if let Some(map) = component_observers.entity_map.get(&target_entity) {
map.iter().for_each(&mut trigger_observer);
}
}
Expand Down Expand Up @@ -695,7 +695,7 @@ impl World {
unsafe {
world.trigger_observers_with_data::<_, E::Traversal>(
event_id,
Entity::PLACEHOLDER,
None,
targets.components(),
event_data,
false,
Expand All @@ -708,7 +708,7 @@ impl World {
unsafe {
world.trigger_observers_with_data::<_, E::Traversal>(
event_id,
target_entity,
Some(target_entity),
targets.components(),
event_data,
E::AUTO_PROPAGATE,
Expand Down Expand Up @@ -999,20 +999,20 @@ mod tests {
world.add_observer(
|obs: Trigger<OnAdd, A>, mut res: ResMut<Order>, mut commands: Commands| {
res.observed("add_a");
commands.entity(obs.target()).insert(B);
commands.entity(obs.target().unwrap()).insert(B);
},
);
world.add_observer(
|obs: Trigger<OnRemove, A>, mut res: ResMut<Order>, mut commands: Commands| {
res.observed("remove_a");
commands.entity(obs.target()).remove::<B>();
commands.entity(obs.target().unwrap()).remove::<B>();
},
);

world.add_observer(
|obs: Trigger<OnAdd, B>, mut res: ResMut<Order>, mut commands: Commands| {
res.observed("add_b");
commands.entity(obs.target()).remove::<A>();
commands.entity(obs.target().unwrap()).remove::<A>();
},
);
world.add_observer(|_: Trigger<OnRemove, B>, mut res: ResMut<Order>| {
Expand Down Expand Up @@ -1181,7 +1181,7 @@ mod tests {
};
world.spawn_empty().observe(system);
world.add_observer(move |obs: Trigger<EventA>, mut res: ResMut<Order>| {
assert_eq!(obs.target(), Entity::PLACEHOLDER);
assert_eq!(obs.target(), None);
res.observed("event_a");
});

Expand All @@ -1208,7 +1208,7 @@ mod tests {
.observe(|_: Trigger<EventA>, mut res: ResMut<Order>| res.observed("a_1"))
.id();
world.add_observer(move |obs: Trigger<EventA>, mut res: ResMut<Order>| {
assert_eq!(obs.target(), entity);
assert_eq!(obs.target().unwrap(), entity);
res.observed("a_2");
});

Expand Down Expand Up @@ -1628,7 +1628,7 @@ mod tests {

world.add_observer(
|trigger: Trigger<EventPropagating>, query: Query<&A>, mut res: ResMut<Order>| {
if query.get(trigger.target()).is_ok() {
if query.get(trigger.target().unwrap()).is_ok() {
res.observed("event");
}
},
Expand All @@ -1651,7 +1651,7 @@ mod tests {
fn observer_modifies_relationship() {
fn on_add(trigger: Trigger<OnAdd, A>, mut commands: Commands) {
commands
.entity(trigger.target())
.entity(trigger.target().unwrap())
.with_related_entities::<crate::hierarchy::ChildOf>(|rsc| {
rsc.spawn_empty();
});
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_ecs/src/observer/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// struct Explode;
///
/// world.add_observer(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("Entity {} goes BOOM!", trigger.target());
/// commands.entity(trigger.target()).despawn();
/// println!("Entity {} goes BOOM!", trigger.target().unwrap());
/// commands.entity(trigger.target().unwrap()).despawn();
/// });
///
/// world.flush();
Expand Down Expand Up @@ -157,7 +157,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// # struct Explode;
/// world.entity_mut(e1).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("Boom!");
/// commands.entity(trigger.target()).despawn();
/// commands.entity(trigger.target().unwrap()).despawn();
/// });
///
/// world.entity_mut(e2).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
Expand Down
41 changes: 26 additions & 15 deletions crates/bevy_ecs/src/world/deferred_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use super::{unsafe_world_cell::UnsafeWorldCell, Mut, World, ON_INSERT, ON_REPLAC
///
/// This means that in order to add entities, for example, you will need to use commands instead of the world directly.
pub struct DeferredWorld<'w> {
// SAFETY: Implementors must not use this reference to make structural changes
// SAFETY: Implementers must not use this reference to make structural changes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL these are both valid ways of spelling it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My typos just picked it up lol; just fixing those red squiggly lines. I can revert if this is the spelling bevy would prefer.

I believe these spellings are regional. IDK which region bevy is sticking to (or if there's a way to manually pick one on my end).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we stick to american english largely, but I couldn't care less either way

world: UnsafeWorldCell<'w>,
}

Expand Down Expand Up @@ -157,7 +157,7 @@ impl<'w> DeferredWorld<'w> {
if archetype.has_replace_observer() {
self.trigger_observers(
ON_REPLACE,
entity,
Some(entity),
[component_id].into_iter(),
MaybeLocation::caller(),
);
Expand Down Expand Up @@ -197,7 +197,7 @@ impl<'w> DeferredWorld<'w> {
if archetype.has_insert_observer() {
self.trigger_observers(
ON_INSERT,
entity,
Some(entity),
[component_id].into_iter(),
MaybeLocation::caller(),
);
Expand Down Expand Up @@ -738,7 +738,7 @@ impl<'w> DeferredWorld<'w> {
pub(crate) unsafe fn trigger_observers(
&mut self,
event: ComponentId,
target: Entity,
target: Option<Entity>,
components: impl Iterator<Item = ComponentId> + Clone,
caller: MaybeLocation,
) {
Expand All @@ -761,26 +761,28 @@ impl<'w> DeferredWorld<'w> {
pub(crate) unsafe fn trigger_observers_with_data<E, T>(
&mut self,
event: ComponentId,
mut target: Entity,
target: Option<Entity>,
components: impl Iterator<Item = ComponentId> + Clone,
data: &mut E,
mut propagate: bool,
caller: MaybeLocation,
) where
T: Traversal<E>,
{
Observers::invoke::<_>(
self.reborrow(),
event,
target,
components.clone(),
data,
&mut propagate,
caller,
);
let Some(mut target) = target else { return };

loop {
Observers::invoke::<_>(
self.reborrow(),
event,
target,
components.clone(),
data,
&mut propagate,
caller,
);
if !propagate {
break;
return;
Comment on lines +772 to +785
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all these changes here to avoid checking if target is some in the loop? It seems unfortunate to repeat this Observers::invoke call twice (these calls could skew).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It just saves checking for some. It is kinda annoying to have the second invoke, but I don't mind it. The first one is the root. All others are propagation based. They might diverge at some point anyway.

}
if let Some(traverse_to) = self
.get_entity(target)
Expand All @@ -792,6 +794,15 @@ impl<'w> DeferredWorld<'w> {
} else {
break;
}
Observers::invoke::<_>(
self.reborrow(),
event,
Some(target),
components.clone(),
data,
&mut propagate,
caller,
);
}
}

Expand Down
12 changes: 7 additions & 5 deletions crates/bevy_ecs/src/world/entity_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2369,7 +2369,7 @@ impl<'w> EntityWorldMut<'w> {
if archetype.has_despawn_observer() {
deferred_world.trigger_observers(
ON_DESPAWN,
self.entity,
Some(self.entity),
archetype.components(),
caller,
);
Expand All @@ -2383,7 +2383,7 @@ impl<'w> EntityWorldMut<'w> {
if archetype.has_replace_observer() {
deferred_world.trigger_observers(
ON_REPLACE,
self.entity,
Some(self.entity),
archetype.components(),
caller,
);
Expand All @@ -2398,7 +2398,7 @@ impl<'w> EntityWorldMut<'w> {
if archetype.has_remove_observer() {
deferred_world.trigger_observers(
ON_REMOVE,
self.entity,
Some(self.entity),
archetype.components(),
caller,
);
Expand Down Expand Up @@ -5726,7 +5726,9 @@ mod tests {
let entity = world
.spawn_empty()
.observe(|trigger: Trigger<TestEvent>, mut commands: Commands| {
commands.entity(trigger.target()).insert(TestComponent(0));
commands
.entity(trigger.target().unwrap())
.insert(TestComponent(0));
})
.id();

Expand All @@ -5746,7 +5748,7 @@ mod tests {
let mut world = World::new();
world.add_observer(
|trigger: Trigger<OnAdd, TestComponent>, mut commands: Commands| {
commands.entity(trigger.target()).despawn();
commands.entity(trigger.target().unwrap()).despawn();
},
);
let entity = world.spawn_empty().id();
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_input_focus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ mod tests {
trigger: Trigger<FocusedInput<KeyboardInput>>,
mut query: Query<&mut GatherKeyboardEvents>,
) {
if let Ok(mut gather) = query.get_mut(trigger.target()) {
if let Ok(mut gather) = query.get_mut(trigger.target().unwrap()) {
if let Key::Character(c) = &trigger.input.logical_key {
gather.0.push_str(c.as_str());
}
Expand Down
Loading