From 5a5125671b4cdb9f557b940d9e7ac772d5266b5f Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 19 Feb 2023 16:19:56 +0000 Subject: [PATCH] Deprecate `ChangeTrackers` in favor of `Ref` (#7306) # Objective `ChangeTrackers<>` is a `WorldQuery` type that lets you access the change ticks for a component. #7097 has added `Ref<>`, which gives access to a component's value in addition to its change ticks. Since bevy's access model does not separate a component's value from its change ticks, there is no benefit to using `ChangeTrackers` over `Ref`. ## Solution Deprecate `ChangeTrackers<>`. --- ## Changelog * `ChangeTrackers` has been deprecated. It will be removed in Bevy 0.11. ## Migration Guide `ChangeTrackers` has been deprecated, and will be removed in the next release. Any usage should be replaced with `Ref`. ```rust // Before (0.9) fn my_system(q: Query<(&MyComponent, ChangeTrackers)>) { for (value, trackers) in &q { if trackers.is_changed() { // Do something with `value`. } } } // After (0.10) fn my_system(q: Query>) { for value in &q { if value.is_changed() { // Do something with `value`. } } } ``` --- crates/bevy_ecs/src/change_detection.rs | 19 +++++++++---------- crates/bevy_ecs/src/lib.rs | 15 ++++++++++----- crates/bevy_ecs/src/query/fetch.rs | 15 +++++++++------ crates/bevy_ecs/src/query/filter.rs | 2 +- examples/ecs/component_change_detection.rs | 22 +++++++++++----------- 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 73cdc168385bd..ad5576657830a 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -696,10 +696,9 @@ mod tests { use crate::{ self as bevy_ecs, change_detection::{ - Mut, NonSendMut, ResMut, TicksMut, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE, + Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE, }, component::{Component, ComponentTicks, Tick}, - query::ChangeTrackers, system::{IntoSystem, Query, System}, world::World, }; @@ -718,11 +717,11 @@ mod tests { #[test] fn change_expiration() { - fn change_detected(query: Query>) -> bool { + fn change_detected(query: Query>) -> bool { query.single().is_changed() } - fn change_expired(query: Query>) -> bool { + fn change_expired(query: Query>) -> bool { query.single().is_changed() } @@ -753,7 +752,7 @@ mod tests { #[test] fn change_tick_wraparound() { - fn change_detected(query: Query>) -> bool { + fn change_detected(query: Query>) -> bool { query.single().is_changed() } @@ -784,10 +783,10 @@ mod tests { *world.change_tick.get_mut() += MAX_CHANGE_AGE + CHECK_TICK_THRESHOLD; let change_tick = world.change_tick(); - let mut query = world.query::>(); + let mut query = world.query::>(); for tracker in query.iter(&world) { - let ticks_since_insert = change_tick.wrapping_sub(tracker.component_ticks.added.tick); - let ticks_since_change = change_tick.wrapping_sub(tracker.component_ticks.changed.tick); + let ticks_since_insert = change_tick.wrapping_sub(tracker.ticks.added.tick); + let ticks_since_change = change_tick.wrapping_sub(tracker.ticks.changed.tick); assert!(ticks_since_insert > MAX_CHANGE_AGE); assert!(ticks_since_change > MAX_CHANGE_AGE); } @@ -796,8 +795,8 @@ mod tests { world.check_change_ticks(); for tracker in query.iter(&world) { - let ticks_since_insert = change_tick.wrapping_sub(tracker.component_ticks.added.tick); - let ticks_since_change = change_tick.wrapping_sub(tracker.component_ticks.changed.tick); + let ticks_since_insert = change_tick.wrapping_sub(tracker.ticks.added.tick); + let ticks_since_change = change_tick.wrapping_sub(tracker.ticks.changed.tick); assert!(ticks_since_insert == MAX_CHANGE_AGE); assert!(ticks_since_change == MAX_CHANGE_AGE); } diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 8ed41658ea57a..1af971e52b197 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -25,6 +25,9 @@ pub use bevy_ptr as ptr; /// Most commonly used re-exported types. pub mod prelude { + #[doc(hidden)] + #[allow(deprecated)] + pub use crate::query::ChangeTrackers; #[doc(hidden)] #[cfg(feature = "bevy_reflect")] pub use crate::reflect::{ReflectComponent, ReflectResource}; @@ -35,7 +38,7 @@ pub mod prelude { component::Component, entity::Entity, event::{Event, EventReader, EventWriter, Events}, - query::{Added, AnyOf, ChangeTrackers, Changed, Or, QueryState, With, Without}, + query::{Added, AnyOf, Changed, Or, QueryState, With, Without}, removal_detection::RemovedComponents, schedule::{ apply_state_transition, apply_system_buffers, common_conditions::*, IntoSystemConfig, @@ -63,11 +66,10 @@ mod tests { use crate::prelude::Or; use crate::{ bundle::Bundle, + change_detection::Ref, component::{Component, ComponentId}, entity::Entity, - query::{ - Added, ChangeTrackers, Changed, FilteredAccess, ReadOnlyWorldQuery, With, Without, - }, + query::{Added, Changed, FilteredAccess, ReadOnlyWorldQuery, With, Without}, system::Resource, world::{Mut, World}, }; @@ -1297,7 +1299,10 @@ mod tests { } #[test] + #[allow(deprecated)] fn trackers_query() { + use crate::prelude::ChangeTrackers; + let mut world = World::default(); let e1 = world.spawn((A(0), B(0))).id(); world.spawn(B(0)); @@ -1541,7 +1546,7 @@ mod tests { assert_eq!(1, query_min_size![&B, (With, With)],); assert_eq!(1, query_min_size![(&A, &B), With],); assert_eq!(4, query_min_size![&A, ()], "Simple Archetypal"); - assert_eq!(4, query_min_size![ChangeTrackers, ()],); + assert_eq!(4, query_min_size![Ref, ()],); // All the following should set minimum size to 0, as it's impossible to predict // how many entities the filters will trim. assert_eq!(0, query_min_size![(), Added], "Simple Added"); diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index ee67a401af503..7e4c7a3f7434a 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -1115,6 +1115,7 @@ unsafe impl ReadOnlyWorldQuery for Option {} /// } /// # bevy_ecs::system::assert_is_system(print_moving_objects_system); /// ``` +#[deprecated = "`ChangeTrackers` will be removed in bevy 0.11. Use `bevy_ecs::prelude::Ref` instead."] pub struct ChangeTrackers { pub(crate) component_ticks: ComponentTicks, pub(crate) last_change_tick: u32, @@ -1122,18 +1123,17 @@ pub struct ChangeTrackers { marker: PhantomData, } +#[allow(deprecated)] impl Clone for ChangeTrackers { fn clone(&self) -> Self { - Self { - component_ticks: self.component_ticks, - last_change_tick: self.last_change_tick, - change_tick: self.change_tick, - marker: PhantomData, - } + *self } } + +#[allow(deprecated)] impl Copy for ChangeTrackers {} +#[allow(deprecated)] impl std::fmt::Debug for ChangeTrackers { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ChangeTrackers") @@ -1144,6 +1144,7 @@ impl std::fmt::Debug for ChangeTrackers { } } +#[allow(deprecated)] impl ChangeTrackers { /// Returns true if this component has been added since the last execution of this system. pub fn is_added(&self) -> bool { @@ -1171,6 +1172,7 @@ pub struct ChangeTrackersFetch<'w, T> { change_tick: u32, } +#[allow(deprecated)] // SAFETY: `ROQueryFetch` is the same as `QueryFetch` unsafe impl WorldQuery for ChangeTrackers { type Fetch<'w> = ChangeTrackersFetch<'w, T>; @@ -1317,6 +1319,7 @@ unsafe impl WorldQuery for ChangeTrackers { } } +#[allow(deprecated)] /// SAFETY: access is read only unsafe impl ReadOnlyWorldQuery for ChangeTrackers {} diff --git a/crates/bevy_ecs/src/query/filter.rs b/crates/bevy_ecs/src/query/filter.rs index 9732d5c3c8547..b2dd9023a69a8 100644 --- a/crates/bevy_ecs/src/query/filter.rs +++ b/crates/bevy_ecs/src/query/filter.rs @@ -572,7 +572,7 @@ impl_tick_filter!( /// A common use for this filter is one-time initialization. /// /// To retain all results without filtering but still check whether they were added after the - /// system last ran, use [`ChangeTrackers`](crate::query::ChangeTrackers). + /// system last ran, use [`Ref`](crate::change_detection::Ref). /// /// # Examples /// diff --git a/examples/ecs/component_change_detection.rs b/examples/ecs/component_change_detection.rs index 67d05f6fd04ca..8758e03c25792 100644 --- a/examples/ecs/component_change_detection.rs +++ b/examples/ecs/component_change_detection.rs @@ -1,6 +1,6 @@ //! This example illustrates how to react to component change. -use bevy::prelude::*; +use bevy::{ecs::world::Ref, prelude::*}; use rand::Rng; fn main() { @@ -43,15 +43,15 @@ fn change_detection(query: Query<(Entity, &MyComponent), Changed>) } } -// By looking at trackers, the query is not filtered but the information is available -fn tracker_monitoring( - query: Query<( - Entity, - Option<&MyComponent>, - Option>, - )>, -) { - for (entity, component, trackers) in &query { - info!("{:?}: {:?} -> {:?}", entity, component, trackers); +// By using `Ref`, the query is not filtered but the information is available +fn tracker_monitoring(query: Query<(Entity, Ref)>) { + for (entity, component) in &query { + info!( + "{:?}: {:?} -> {{is_added: {}, is_changed: {}}}", + entity, + component, + component.is_added(), + component.is_changed() + ); } }