Skip to content

Commit c98f097

Browse files
author
xiejiaen
committed
mutate observer
1 parent e38618c commit c98f097

File tree

11 files changed

+42
-49
lines changed

11 files changed

+42
-49
lines changed

crates/bevy_ecs/src/change_detection.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Types that detect when their internal data mutate.
22
3+
use crate::world::entity_change::{EntityChange, EntityChanges};
34
use crate::{
45
component::{Tick, TickCells},
56
ptr::PtrMut,
@@ -16,7 +17,6 @@ use {
1617
bevy_ptr::ThinSlicePtr,
1718
core::{cell::UnsafeCell, panic::Location},
1819
};
19-
use crate::world::entity_change::{EntityChange, EntityChanges};
2020

2121
/// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans.
2222
///
@@ -1103,7 +1103,6 @@ where
11031103
}
11041104
}
11051105

1106-
11071106
change_detection_impl!(Mut<'w, T>, T,);
11081107
change_detection_mut_with_onchange_impl!(Mut<'w, T>, T,);
11091108
impl_methods_with_onchange!(Mut<'w, T>, T,);

crates/bevy_ecs/src/query/fetch.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::world::entity_change::{EntityChange, EntityChanges};
12
use crate::{
23
archetype::{Archetype, Archetypes},
34
bundle::Bundle,
@@ -14,9 +15,8 @@ use crate::{
1415
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
1516
use bevy_utils::all_tuples;
1617
use core::{cell::UnsafeCell, marker::PhantomData};
17-
use std::cell::RefCell;
1818
use smallvec::SmallVec;
19-
use crate::world::entity_change::{EntityChange, EntityChanges};
19+
use std::cell::RefCell;
2020

2121
/// Types that can be fetched from a [`World`] using a [`Query`].
2222
///
@@ -1431,7 +1431,7 @@ unsafe impl<'__w, T: Component> ReadOnlyQueryData for Ref<'__w, T> {}
14311431
/// The [`WorldQuery::Fetch`] type for `&mut T`.
14321432
pub struct WriteFetch<'w, T: Component> {
14331433
component_id: ComponentId,
1434-
changes: &'w RefCell<EntityChanges>,
1434+
changes: &'w RefCell<EntityChanges>,
14351435
components: StorageSwitch<
14361436
T,
14371437
// T::STORAGE_TYPE = StorageType::Table
@@ -1571,10 +1571,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
15711571
let caller = unsafe { _callers.get(table_row.as_usize()) };
15721572

15731573
Mut {
1574-
on_change: Some((
1575-
EntityChange::new(entity, fetch.component_id),
1576-
fetch.changes,
1577-
)),
1574+
on_change: Some((EntityChange::new(entity, fetch.component_id), fetch.changes)),
15781575
value: component.deref_mut(),
15791576
ticks: TicksMut {
15801577
added: added.deref_mut(),
@@ -1592,10 +1589,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
15921589
unsafe { sparse_set.get_with_ticks(entity).debug_checked_unwrap() };
15931590

15941591
Mut {
1595-
on_change: Some((
1596-
EntityChange::new(entity, fetch.component_id),
1597-
fetch.changes,
1598-
)),
1592+
on_change: Some((EntityChange::new(entity, fetch.component_id), fetch.changes)),
15991593
value: component.assert_unique().deref_mut(),
16001594
ticks: TicksMut::from_tick_cells(ticks, fetch.last_run, fetch.this_run),
16011595
#[cfg(feature = "track_change_detection")]

crates/bevy_ecs/src/query/filter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
277277
}
278278
};
279279
const IS_MUTATE: bool = false;
280-
280+
281281
#[inline]
282282
unsafe fn set_archetype(
283283
_fetch: &mut (),

crates/bevy_ecs/src/query/world_query.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ pub unsafe trait WorldQuery {
7777
/// iterators.
7878
const IS_DENSE: bool;
7979

80-
/// Return true if (and only if) TODO
80+
/// Return true if (and only if) this query will return a mutate access of any [`Component`]
8181
const IS_MUTATE: bool;
8282

8383
/// Adjusts internal state to account for the next [`Archetype`]. This will always be called on

crates/bevy_ecs/src/system/system_param.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::Populated;
12
pub use crate::change_detection::{NonSendMut, Res, ResMut};
23
use crate::{
34
archetype::{Archetype, Archetypes},
@@ -28,7 +29,6 @@ use core::{
2829
marker::PhantomData,
2930
ops::{Deref, DerefMut},
3031
};
31-
use super::Populated;
3232

3333
/// A parameter that can be used in a [`System`](super::System).
3434
///

crates/bevy_ecs/src/world/component_constants.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,4 @@ pub struct OnRemove;
4949
#[derive(Event, Debug)]
5050
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
5151
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
52-
pub struct OnMutate;
52+
pub struct OnMutate;

crates/bevy_ecs/src/world/entity_change.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::cell::RefCell;
2-
use bevy_utils::Parallel;
31
use crate::component::ComponentId;
42
use crate::entity::Entity;
3+
use bevy_utils::Parallel;
4+
use std::cell::RefCell;
55

66
/// A shorthand for [`Vec<EntityChange>`].
77
pub type EntityChanges = Vec<EntityChange>;
@@ -14,7 +14,6 @@ pub struct ParallelEntityChanges {
1414
}
1515

1616
impl ParallelEntityChanges {
17-
1817
/// Returns a default `Changes`
1918
2019
pub fn new() -> Self {
@@ -35,7 +34,7 @@ impl ParallelEntityChanges {
3534
/// A Record hint which entity's component has changed
3635
#[derive(Copy, Clone, Debug)]
3736
pub struct EntityChange {
38-
entity: Entity,
37+
entity: Entity,
3938
component: ComponentId,
4039
}
4140

@@ -53,4 +52,4 @@ impl EntityChange {
5352
pub fn component(&self) -> ComponentId {
5453
self.component
5554
}
56-
}
55+
}

crates/bevy_ecs/src/world/mod.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
33
pub(crate) mod command_queue;
44

5-
pub(crate) mod entity_change;
65
mod component_constants;
76
mod deferred_world;
7+
pub(crate) mod entity_change;
88
mod entity_fetch;
99
mod entity_ref;
1010
pub mod error;
@@ -63,9 +63,9 @@ use core::{
6363
#[cfg(feature = "track_change_detection")]
6464
use bevy_ptr::UnsafeCellDeref;
6565

66+
use crate::world::entity_change::ParallelEntityChanges;
6667
use core::panic::Location;
6768
use unsafe_world_cell::{UnsafeEntityCell, UnsafeWorldCell};
68-
use crate::world::entity_change::ParallelEntityChanges;
6969

7070
/// A [`World`] mutation.
7171
///
@@ -3024,12 +3024,18 @@ impl World {
30243024
pub(crate) fn flush_entity_changes(&mut self) {
30253025
let mut parallel_entity_changes = std::mem::take(&mut self.entity_changes);
30263026
let mut deferred_world = DeferredWorld::from(&mut *self);
3027-
parallel_entity_changes.iter_mut().for_each(|entity_changes| {
3028-
entity_changes.drain(..).for_each(|entity_change| unsafe {
3029-
// SAFETY: [`OnMutate`] Event is ZST
3030-
deferred_world.trigger_observers(ON_MUTATE, entity_change.entity(), std::iter::once(entity_change.component()))
3031-
})
3032-
});
3027+
parallel_entity_changes
3028+
.iter_mut()
3029+
.for_each(|entity_changes| {
3030+
entity_changes.drain(..).for_each(|entity_change| unsafe {
3031+
// SAFETY: [`OnMutate`] Event is ZST
3032+
deferred_world.trigger_observers(
3033+
ON_MUTATE,
3034+
entity_change.entity(),
3035+
std::iter::once(entity_change.component()),
3036+
)
3037+
})
3038+
});
30333039
_ = std::mem::replace(&mut self.entity_changes, parallel_entity_changes);
30343040
}
30353041

crates/bevy_ecs/src/world/unsafe_world_cell.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![warn(unsafe_op_in_unsafe_fn)]
44

55
use super::{Mut, Ref, World, WorldId};
6+
use crate::world::entity_change::{EntityChange, EntityChanges};
67
use crate::{
78
archetype::{Archetype, Archetypes},
89
bundle::Bundles,
@@ -22,7 +23,6 @@ use bevy_ptr::Ptr;
2223
use bevy_ptr::UnsafeCellDeref;
2324
use core::{any::TypeId, cell::UnsafeCell, fmt::Debug, marker::PhantomData, ptr};
2425
use std::cell::RefCell;
25-
use crate::world::entity_change::{EntityChange, EntityChanges};
2626

2727
/// Variant of the [`World`] where resource and component accesses take `&self`, and the responsibility to avoid
2828
/// aliasing violations are given to the caller instead of being checked at compile-time by rust's unique XOR shared rule.
@@ -332,7 +332,9 @@ impl<'w> UnsafeWorldCell<'w> {
332332
/// time as any other accesses to that same component.
333333
pub unsafe fn entity_changes(self) -> &'w RefCell<EntityChanges> {
334334
// SAFETY: The caller promises to only access world data allowed by this instance.
335-
&unsafe { self.unsafe_world() }.entity_changes.get_local_ref_cell()
335+
&unsafe { self.unsafe_world() }
336+
.entity_changes
337+
.get_local_ref_cell()
336338
}
337339

338340
/// Retrieves an [`UnsafeEntityCell`] that exposes read and write operations for the given `entity`.

crates/bevy_render/src/pipelined_rendering.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ impl RenderAppChannels {
4343
self.app_to_render_sender.send_blocking(render_app).unwrap();
4444
self.render_app_in_render_thread = true;
4545
}
46-
4746
}
4847

4948
impl Drop for RenderAppChannels {

examples/ecs/responding_to_changes.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
//! Bevy has two primary ways to respond to changes in your ECS data:
32
//!
43
//! 1. **Change detection:** whenever a component or resource is mutated, it will be flagged as changed.
@@ -192,11 +191,8 @@ fn update_counter_observer(
192191
trigger: Trigger<OnMutate, Interaction>,
193192
mut button_query: Query<(&mut CounterValue, &Interaction, &ChangeStrategy)>,
194193
) {
195-
let Ok((
196-
mut counter,
197-
interaction,
198-
change_strategy
199-
)) = button_query.get_mut(trigger.entity()) else {
194+
let Ok((mut counter, interaction, change_strategy)) = button_query.get_mut(trigger.entity())
195+
else {
200196
// Other entities may have the Interaction component, but we're only interested in these particular buttons.
201197
return;
202198
};
@@ -216,16 +212,14 @@ fn setup_ui(mut commands: Commands) {
216212
commands.spawn(Camera2d::default());
217213

218214
let root_node = commands
219-
.spawn((
220-
Node {
221-
width: Val::Percent(100.),
222-
height: Val::Percent(100.),
223-
flex_direction: FlexDirection::Column,
224-
justify_content: JustifyContent::Center,
225-
align_items: AlignItems::Center,
226-
..default()
227-
},
228-
))
215+
.spawn((Node {
216+
width: Val::Percent(100.),
217+
height: Val::Percent(100.),
218+
flex_direction: FlexDirection::Column,
219+
justify_content: JustifyContent::Center,
220+
align_items: AlignItems::Center,
221+
..default()
222+
},))
229223
.id();
230224

231225
let changed_filter_button =

0 commit comments

Comments
 (0)