Merge branch 'main' into Remove-entity-reserving/pending/flushing-system

This commit is contained in:
Eagster 2025-06-16 11:40:22 -04:00 committed by GitHub
commit 9df7a76cf1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 126 additions and 65 deletions

View File

@ -74,11 +74,16 @@ pub struct MotionVectorPrepass;
#[reflect(Component, Default)] #[reflect(Component, Default)]
pub struct DeferredPrepass; pub struct DeferredPrepass;
/// View matrices from the previous frame.
///
/// Useful for temporal rendering techniques that need access to last frame's camera data.
#[derive(Component, ShaderType, Clone)] #[derive(Component, ShaderType, Clone)]
pub struct PreviousViewData { pub struct PreviousViewData {
pub view_from_world: Mat4, pub view_from_world: Mat4,
pub clip_from_world: Mat4, pub clip_from_world: Mat4,
pub clip_from_view: Mat4, pub clip_from_view: Mat4,
pub world_from_clip: Mat4,
pub view_from_clip: Mat4,
} }
#[derive(Resource, Default)] #[derive(Resource, Default)]

View File

@ -253,9 +253,21 @@ impl<'w, E, B: Bundle> On<'w, E, B> {
impl<'w, E: EntityEvent, B: Bundle> On<'w, E, B> { impl<'w, E: EntityEvent, B: Bundle> On<'w, E, B> {
/// Returns the [`Entity`] that was targeted by the `event` that triggered this observer. /// Returns the [`Entity`] that was targeted by the `event` that triggered this observer.
/// ///
/// Note that if event propagation is enabled, this may not be the same as the original target of the event,
/// which can be accessed via [`On::original_target`].
///
/// If the event was not targeted at a specific entity, this will return [`Entity::PLACEHOLDER`]. /// If the event was not targeted at a specific entity, this will return [`Entity::PLACEHOLDER`].
pub fn target(&self) -> Entity { pub fn target(&self) -> Entity {
self.trigger.target.unwrap_or(Entity::PLACEHOLDER) self.trigger.current_target.unwrap_or(Entity::PLACEHOLDER)
}
/// Returns the original [`Entity`] that the `event` was targeted at when it was first triggered.
///
/// If event propagation is not enabled, this will always return the same value as [`On::target`].
///
/// If the event was not targeted at a specific entity, this will return [`Entity::PLACEHOLDER`].
pub fn original_target(&self) -> Entity {
self.trigger.original_target.unwrap_or(Entity::PLACEHOLDER)
} }
/// Enables or disables event propagation, allowing the same event to trigger observers on a chain of different entities. /// Enables or disables event propagation, allowing the same event to trigger observers on a chain of different entities.
@ -483,8 +495,15 @@ pub struct ObserverTrigger {
pub event_type: ComponentId, pub event_type: ComponentId,
/// The [`ComponentId`]s the trigger targeted. /// The [`ComponentId`]s the trigger targeted.
components: SmallVec<[ComponentId; 2]>, components: SmallVec<[ComponentId; 2]>,
/// The entity the trigger targeted. /// The entity that the entity-event targeted, if any.
pub target: Option<Entity>, ///
/// Note that if event propagation is enabled, this may not be the same as [`ObserverTrigger::original_target`].
pub current_target: Option<Entity>,
/// The entity that the entity-event was originally targeted at, if any.
///
/// If event propagation is enabled, this will be the first entity that the event was targeted at,
/// even if the event was propagated to other entities.
pub original_target: Option<Entity>,
/// The location of the source code that triggered the observer. /// The location of the source code that triggered the observer.
pub caller: MaybeLocation, pub caller: MaybeLocation,
} }
@ -573,7 +592,8 @@ impl Observers {
pub(crate) fn invoke<T>( pub(crate) fn invoke<T>(
mut world: DeferredWorld, mut world: DeferredWorld,
event_type: ComponentId, event_type: ComponentId,
target: Option<Entity>, current_target: Option<Entity>,
original_target: Option<Entity>,
components: impl Iterator<Item = ComponentId> + Clone, components: impl Iterator<Item = ComponentId> + Clone,
data: &mut T, data: &mut T,
propagate: &mut bool, propagate: &mut bool,
@ -601,7 +621,8 @@ impl Observers {
observer, observer,
event_type, event_type,
components: components.clone().collect(), components: components.clone().collect(),
target, current_target,
original_target,
caller, caller,
}, },
data.into(), data.into(),
@ -612,7 +633,7 @@ impl Observers {
observers.map.iter().for_each(&mut trigger_observer); observers.map.iter().for_each(&mut trigger_observer);
// Trigger entity observers listening for this kind of trigger // Trigger entity observers listening for this kind of trigger
if let Some(target_entity) = target { if let Some(target_entity) = current_target {
if let Some(map) = observers.entity_observers.get(&target_entity) { if let Some(map) = observers.entity_observers.get(&target_entity) {
map.iter().for_each(&mut trigger_observer); map.iter().for_each(&mut trigger_observer);
} }
@ -626,7 +647,7 @@ impl Observers {
.iter() .iter()
.for_each(&mut trigger_observer); .for_each(&mut trigger_observer);
if let Some(target_entity) = target { if let Some(target_entity) = current_target {
if let Some(map) = component_observers.entity_map.get(&target_entity) { if let Some(map) = component_observers.entity_map.get(&target_entity) {
map.iter().for_each(&mut trigger_observer); map.iter().for_each(&mut trigger_observer);
} }
@ -752,6 +773,7 @@ impl World {
world.trigger_observers_with_data::<_, ()>( world.trigger_observers_with_data::<_, ()>(
event_id, event_id,
None, None,
None,
core::iter::empty::<ComponentId>(), core::iter::empty::<ComponentId>(),
event_data, event_data,
false, false,
@ -863,6 +885,7 @@ impl World {
world.trigger_observers_with_data::<_, E::Traversal>( world.trigger_observers_with_data::<_, E::Traversal>(
event_id, event_id,
None, None,
None,
targets.components(), targets.components(),
event_data, event_data,
false, false,
@ -876,6 +899,7 @@ impl World {
world.trigger_observers_with_data::<_, E::Traversal>( world.trigger_observers_with_data::<_, E::Traversal>(
event_id, event_id,
Some(target_entity), Some(target_entity),
Some(target_entity),
targets.components(), targets.components(),
event_data, event_data,
E::AUTO_PROPAGATE, E::AUTO_PROPAGATE,
@ -1543,21 +1567,27 @@ mod tests {
let mut world = World::new(); let mut world = World::new();
world.init_resource::<Order>(); world.init_resource::<Order>();
let parent = world let parent = world.spawn_empty().id();
.spawn_empty() let child = world.spawn(ChildOf(parent)).id();
.observe(|_: On<EventPropagating>, mut res: ResMut<Order>| {
world.entity_mut(parent).observe(
move |trigger: On<EventPropagating>, mut res: ResMut<Order>| {
res.observed("parent"); res.observed("parent");
})
.id();
let child = world assert_eq!(trigger.target(), parent);
.spawn(ChildOf(parent)) assert_eq!(trigger.original_target(), child);
.observe(|_: On<EventPropagating>, mut res: ResMut<Order>| { },
);
world.entity_mut(child).observe(
move |trigger: On<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child"); res.observed("child");
}) assert_eq!(trigger.target(), child);
.id(); assert_eq!(trigger.original_target(), child);
},
);
// TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut // TODO: ideally this flush is not necessary, but right now observe() returns EntityWorldMut
// and therefore does not automatically flush. // and therefore does not automatically flush.
world.flush(); world.flush();
world.trigger_targets(EventPropagating, child); world.trigger_targets(EventPropagating, child);

View File

@ -756,6 +756,7 @@ impl<'w> DeferredWorld<'w> {
self.reborrow(), self.reborrow(),
event, event,
target, target,
target,
components, components,
&mut (), &mut (),
&mut false, &mut false,
@ -771,7 +772,8 @@ impl<'w> DeferredWorld<'w> {
pub(crate) unsafe fn trigger_observers_with_data<E, T>( pub(crate) unsafe fn trigger_observers_with_data<E, T>(
&mut self, &mut self,
event: ComponentId, event: ComponentId,
target: Option<Entity>, current_target: Option<Entity>,
original_target: Option<Entity>,
components: impl Iterator<Item = ComponentId> + Clone, components: impl Iterator<Item = ComponentId> + Clone,
data: &mut E, data: &mut E,
mut propagate: bool, mut propagate: bool,
@ -782,32 +784,36 @@ impl<'w> DeferredWorld<'w> {
Observers::invoke::<_>( Observers::invoke::<_>(
self.reborrow(), self.reborrow(),
event, event,
target, current_target,
original_target,
components.clone(), components.clone(),
data, data,
&mut propagate, &mut propagate,
caller, caller,
); );
let Some(mut target) = target else { return }; let Some(mut current_target) = current_target else {
return;
};
loop { loop {
if !propagate { if !propagate {
return; return;
} }
if let Some(traverse_to) = self if let Some(traverse_to) = self
.get_entity(target) .get_entity(current_target)
.ok() .ok()
.and_then(|entity| entity.get_components::<T>()) .and_then(|entity| entity.get_components::<T>())
.and_then(|item| T::traverse(item, data)) .and_then(|item| T::traverse(item, data))
{ {
target = traverse_to; current_target = traverse_to;
} else { } else {
break; break;
} }
Observers::invoke::<_>( Observers::invoke::<_>(
self.reborrow(), self.reborrow(),
event, event,
Some(target), Some(current_target),
original_target,
components.clone(), components.clone(),
data, data,
&mut propagate, &mut propagate,

View File

@ -216,11 +216,16 @@ pub fn update_previous_view_data(
query: Query<(Entity, &Camera, &GlobalTransform), Or<(With<Camera3d>, With<ShadowView>)>>, query: Query<(Entity, &Camera, &GlobalTransform), Or<(With<Camera3d>, With<ShadowView>)>>,
) { ) {
for (entity, camera, camera_transform) in &query { for (entity, camera, camera_transform) in &query {
let view_from_world = camera_transform.compute_matrix().inverse(); let world_from_view = camera_transform.compute_matrix();
let view_from_world = world_from_view.inverse();
let view_from_clip = camera.clip_from_view().inverse();
commands.entity(entity).try_insert(PreviousViewData { commands.entity(entity).try_insert(PreviousViewData {
view_from_world, view_from_world,
clip_from_world: camera.clip_from_view() * view_from_world, clip_from_world: camera.clip_from_view() * view_from_world,
clip_from_view: camera.clip_from_view(), clip_from_view: camera.clip_from_view(),
world_from_clip: world_from_view * view_from_clip,
view_from_clip,
}); });
} }
} }
@ -698,11 +703,16 @@ pub fn prepare_previous_view_uniforms(
let prev_view_data = match maybe_previous_view_uniforms { let prev_view_data = match maybe_previous_view_uniforms {
Some(previous_view) => previous_view.clone(), Some(previous_view) => previous_view.clone(),
None => { None => {
let view_from_world = camera.world_from_view.compute_matrix().inverse(); let world_from_view = camera.world_from_view.compute_matrix();
let view_from_world = world_from_view.inverse();
let view_from_clip = camera.clip_from_view.inverse();
PreviousViewData { PreviousViewData {
view_from_world, view_from_world,
clip_from_world: camera.clip_from_view * view_from_world, clip_from_world: camera.clip_from_view * view_from_world,
clip_from_view: camera.clip_from_view, clip_from_view: camera.clip_from_view,
world_from_clip: world_from_view * view_from_clip,
view_from_clip,
} }
} }
}; };

View File

@ -4,6 +4,8 @@ struct PreviousViewUniforms {
view_from_world: mat4x4<f32>, view_from_world: mat4x4<f32>,
clip_from_world: mat4x4<f32>, clip_from_world: mat4x4<f32>,
clip_from_view: mat4x4<f32>, clip_from_view: mat4x4<f32>,
world_from_clip: mat4x4<f32>,
view_from_clip: mat4x4<f32>,
} }
@group(0) @binding(2) var<uniform> previous_view_uniforms: PreviousViewUniforms; @group(0) @binding(2) var<uniform> previous_view_uniforms: PreviousViewUniforms;

View File

@ -63,8 +63,6 @@ use crate::{
#[entity_event(traversal = PointerTraversal, auto_propagate)] #[entity_event(traversal = PointerTraversal, auto_propagate)]
#[reflect(Component, Debug, Clone)] #[reflect(Component, Debug, Clone)]
pub struct Pointer<E: Debug + Clone + Reflect> { pub struct Pointer<E: Debug + Clone + Reflect> {
/// The original target of this picking event, before bubbling
pub target: Entity,
/// The pointer that triggered this event /// The pointer that triggered this event
pub pointer_id: PointerId, pub pointer_id: PointerId,
/// The location of the pointer during this event /// The location of the pointer during this event
@ -126,9 +124,8 @@ impl<E: Debug + Clone + Reflect> core::ops::Deref for Pointer<E> {
impl<E: Debug + Clone + Reflect> Pointer<E> { impl<E: Debug + Clone + Reflect> Pointer<E> {
/// Construct a new `Pointer<E>` event. /// Construct a new `Pointer<E>` event.
pub fn new(id: PointerId, location: Location, target: Entity, event: E) -> Self { pub fn new(id: PointerId, location: Location, event: E) -> Self {
Self { Self {
target,
pointer_id: id, pointer_id: id,
pointer_location: location, pointer_location: location,
event, event,
@ -497,12 +494,7 @@ pub fn pointer_events(
}; };
// Always send Out events // Always send Out events
let out_event = Pointer::new( let out_event = Pointer::new(pointer_id, location.clone(), Out { hit: hit.clone() });
pointer_id,
location.clone(),
hovered_entity,
Out { hit: hit.clone() },
);
commands.trigger_targets(out_event.clone(), hovered_entity); commands.trigger_targets(out_event.clone(), hovered_entity);
event_writers.out_events.write(out_event); event_writers.out_events.write(out_event);
@ -514,7 +506,6 @@ pub fn pointer_events(
let drag_leave_event = Pointer::new( let drag_leave_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
hovered_entity,
DragLeave { DragLeave {
button, button,
dragged: *drag_target, dragged: *drag_target,
@ -556,7 +547,6 @@ pub fn pointer_events(
let drag_enter_event = Pointer::new( let drag_enter_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
hovered_entity,
DragEnter { DragEnter {
button, button,
dragged: *drag_target, dragged: *drag_target,
@ -569,12 +559,7 @@ pub fn pointer_events(
} }
// Always send Over events // Always send Over events
let over_event = Pointer::new( let over_event = Pointer::new(pointer_id, location.clone(), Over { hit: hit.clone() });
pointer_id,
location.clone(),
hovered_entity,
Over { hit: hit.clone() },
);
commands.trigger_targets(over_event.clone(), hovered_entity); commands.trigger_targets(over_event.clone(), hovered_entity);
event_writers.over_events.write(over_event); event_writers.over_events.write(over_event);
} }
@ -600,7 +585,6 @@ pub fn pointer_events(
let pressed_event = Pointer::new( let pressed_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
hovered_entity,
Press { Press {
button, button,
hit: hit.clone(), hit: hit.clone(),
@ -628,7 +612,6 @@ pub fn pointer_events(
let click_event = Pointer::new( let click_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
hovered_entity,
Click { Click {
button, button,
hit: hit.clone(), hit: hit.clone(),
@ -642,7 +625,6 @@ pub fn pointer_events(
let released_event = Pointer::new( let released_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
hovered_entity,
Release { Release {
button, button,
hit: hit.clone(), hit: hit.clone(),
@ -659,7 +641,6 @@ pub fn pointer_events(
let drag_drop_event = Pointer::new( let drag_drop_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
*dragged_over,
DragDrop { DragDrop {
button, button,
dropped: drag_target, dropped: drag_target,
@ -673,7 +654,6 @@ pub fn pointer_events(
let drag_end_event = Pointer::new( let drag_end_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
drag_target,
DragEnd { DragEnd {
button, button,
distance: drag.latest_pos - drag.start_pos, distance: drag.latest_pos - drag.start_pos,
@ -686,7 +666,6 @@ pub fn pointer_events(
let drag_leave_event = Pointer::new( let drag_leave_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
*dragged_over,
DragLeave { DragLeave {
button, button,
dragged: drag_target, dragged: drag_target,
@ -727,7 +706,6 @@ pub fn pointer_events(
let drag_start_event = Pointer::new( let drag_start_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
*press_target,
DragStart { DragStart {
button, button,
hit: hit.clone(), hit: hit.clone(),
@ -746,7 +724,6 @@ pub fn pointer_events(
let drag_event = Pointer::new( let drag_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
*drag_target,
Drag { Drag {
button, button,
distance: location.position - drag.start_pos, distance: location.position - drag.start_pos,
@ -769,7 +746,6 @@ pub fn pointer_events(
let drag_over_event = Pointer::new( let drag_over_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
hovered_entity,
DragOver { DragOver {
button, button,
dragged: *drag_target, dragged: *drag_target,
@ -791,7 +767,6 @@ pub fn pointer_events(
let move_event = Pointer::new( let move_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
hovered_entity,
Move { Move {
hit: hit.clone(), hit: hit.clone(),
delta, delta,
@ -811,7 +786,6 @@ pub fn pointer_events(
let scroll_event = Pointer::new( let scroll_event = Pointer::new(
pointer_id, pointer_id,
location.clone(), location.clone(),
hovered_entity,
Scroll { Scroll {
unit, unit,
x, x,
@ -831,8 +805,7 @@ pub fn pointer_events(
.iter() .iter()
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned()))) .flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
{ {
let cancel_event = let cancel_event = Pointer::new(pointer_id, location.clone(), Cancel { hit });
Pointer::new(pointer_id, location.clone(), hovered_entity, Cancel { hit });
commands.trigger_targets(cancel_event.clone(), hovered_entity); commands.trigger_targets(cancel_event.clone(), hovered_entity);
event_writers.cancel_events.write(cancel_event); event_writers.cancel_events.write(cancel_event);
} }

View File

@ -128,7 +128,7 @@ fn fallible_observer(
mut step: Local<f32>, mut step: Local<f32>,
) -> Result { ) -> Result {
let mut transform = world let mut transform = world
.get_mut::<Transform>(trigger.target) .get_mut::<Transform>(trigger.target())
.ok_or("No transform found.")?; .ok_or("No transform found.")?;
*step = if transform.translation.x > 3. { *step = if transform.translation.x > 3. {

View File

@ -382,7 +382,6 @@ fn interact_with_focused_button(
if let Some(focused_entity) = input_focus.0 { if let Some(focused_entity) = input_focus.0 {
commands.trigger_targets( commands.trigger_targets(
Pointer::<Click> { Pointer::<Click> {
target: focused_entity,
// We're pretending that we're a mouse // We're pretending that we're a mouse
pointer_id: PointerId::Mouse, pointer_id: PointerId::Mouse,
// This field isn't used, so we're just setting it to a placeholder value // This field isn't used, so we're just setting it to a placeholder value

View File

@ -43,7 +43,7 @@ fn text_color_on_hover<T: Debug + Clone + Reflect>(
move |mut trigger: On<Pointer<T>>, move |mut trigger: On<Pointer<T>>,
mut text_color: Query<&mut TextColor>, mut text_color: Query<&mut TextColor>,
children: Query<&Children>| { children: Query<&Children>| {
let Ok(children) = children.get(trigger.event().target) else { let Ok(children) = children.get(trigger.original_target()) else {
return; return;
}; };
trigger.propagate(false); trigger.propagate(false);
@ -112,9 +112,7 @@ fn on_trigger_menu(trigger: On<OpenContextMenu>, mut commands: Commands) {
menu_items: Query<&ContextMenuItem>, menu_items: Query<&ContextMenuItem>,
mut clear_col: ResMut<ClearColor>, mut clear_col: ResMut<ClearColor>,
mut commands: Commands| { mut commands: Commands| {
// Note that we want to know the target of the `Pointer<Press>` event (Button) here. let target = trigger.original_target();
// Not to be confused with the trigger `target`
let target = trigger.event().target;
if let Ok(item) = menu_items.get(target) { if let Ok(item) = menu_items.get(target) {
clear_col.0 = item.0.into(); clear_col.0 = item.0.into();

View File

@ -0,0 +1,30 @@
---
title: Original target of `Pointer` picking events is now stored on observers
pull_requests: [19663]
---
The `Pointer.target` field, which tracks the original target of the pointer event before bubbling, has been removed.
Instead, all observers now track this information, available via the `On::original_target()` method.
If you were using this information via the buffered event API of picking, please migrate to observers.
If you cannot for performance reasons, please open an issue explaining your exact use case!
As a workaround, you can transform any entity-event into a buffered event that contains the targeted entity using
an observer than emits events.
```rust
#[derive(Event, BufferedEvent)]
struct TransformedEntityEvent<E: EntityEvent> {
entity: Entity,
event: E,
}
// A generic observer that handles this transformation
fn transform_entity_event<E: EntityEvent>(trigger: On<E>, event_writer: EventWriter<TransformedEntityEvent<E>>){
if trigger.target() == trigger.original_target(){
event_writer.send(trigger.event())
}
}
```
Additionally, the `ObserverTrigger::target` field has been renamed to `ObserverTrigger::current_target` and a new `ObserverTrigger::original_target` field has been added.

View File

@ -1,7 +1,7 @@
--- ---
title: Observer Overhaul title: Observer Overhaul
authors: ["@Jondolf"] authors: ["@Jondolf", "@alice-i-cecile"]
pull_requests: [19596] pull_requests: [19596, 19663]
--- ---
## Rename `Trigger` to `On` ## Rename `Trigger` to `On`
@ -32,3 +32,11 @@ where observers are very high-traffic APIs.
One concern that may come to mind is that `Add` can sometimes conflict with the `core::ops::Add` trait. One concern that may come to mind is that `Add` can sometimes conflict with the `core::ops::Add` trait.
However, in practice these scenarios should be rare, and when you do get conflicts, it should be straightforward However, in practice these scenarios should be rare, and when you do get conflicts, it should be straightforward
to disambiguate by using `ops::Add`, for example. to disambiguate by using `ops::Add`, for example.
## Original targets
`bevy_picking`'s `Pointer` events have always tracked the original target that an entity-event was targeting,
allowing you to bubble events up your hierarchy to see if any of the parents care,
then act on the entity that was actually picked in the first place.
This was handy! We've enabled this functionality for all entity-events: simply call `On::original_target`.