mirror of
https://github.com/bevyengine/bevy
synced 2024-11-14 00:47:32 +00:00
Deprecate ChangeTrackers<T>
in favor of Ref<T>
(#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<T>` over `Ref<T>`. ## Solution Deprecate `ChangeTrackers<>`. --- ## Changelog * `ChangeTrackers<T>` has been deprecated. It will be removed in Bevy 0.11. ## Migration Guide `ChangeTrackers<T>` has been deprecated, and will be removed in the next release. Any usage should be replaced with `Ref<T>`. ```rust // Before (0.9) fn my_system(q: Query<(&MyComponent, ChangeTrackers<MyComponent>)>) { for (value, trackers) in &q { if trackers.is_changed() { // Do something with `value`. } } } // After (0.10) fn my_system(q: Query<Ref<MyComponent>>) { for value in &q { if value.is_changed() { // Do something with `value`. } } } ```
This commit is contained in:
parent
0af001edd4
commit
5a5125671b
5 changed files with 40 additions and 33 deletions
|
@ -696,10 +696,9 @@ mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
self as bevy_ecs,
|
self as bevy_ecs,
|
||||||
change_detection::{
|
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},
|
component::{Component, ComponentTicks, Tick},
|
||||||
query::ChangeTrackers,
|
|
||||||
system::{IntoSystem, Query, System},
|
system::{IntoSystem, Query, System},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
@ -718,11 +717,11 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn change_expiration() {
|
fn change_expiration() {
|
||||||
fn change_detected(query: Query<ChangeTrackers<C>>) -> bool {
|
fn change_detected(query: Query<Ref<C>>) -> bool {
|
||||||
query.single().is_changed()
|
query.single().is_changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_expired(query: Query<ChangeTrackers<C>>) -> bool {
|
fn change_expired(query: Query<Ref<C>>) -> bool {
|
||||||
query.single().is_changed()
|
query.single().is_changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,7 +752,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn change_tick_wraparound() {
|
fn change_tick_wraparound() {
|
||||||
fn change_detected(query: Query<ChangeTrackers<C>>) -> bool {
|
fn change_detected(query: Query<Ref<C>>) -> bool {
|
||||||
query.single().is_changed()
|
query.single().is_changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,10 +783,10 @@ mod tests {
|
||||||
*world.change_tick.get_mut() += MAX_CHANGE_AGE + CHECK_TICK_THRESHOLD;
|
*world.change_tick.get_mut() += MAX_CHANGE_AGE + CHECK_TICK_THRESHOLD;
|
||||||
let change_tick = world.change_tick();
|
let change_tick = world.change_tick();
|
||||||
|
|
||||||
let mut query = world.query::<ChangeTrackers<C>>();
|
let mut query = world.query::<Ref<C>>();
|
||||||
for tracker in query.iter(&world) {
|
for tracker in query.iter(&world) {
|
||||||
let ticks_since_insert = change_tick.wrapping_sub(tracker.component_ticks.added.tick);
|
let ticks_since_insert = change_tick.wrapping_sub(tracker.ticks.added.tick);
|
||||||
let ticks_since_change = change_tick.wrapping_sub(tracker.component_ticks.changed.tick);
|
let ticks_since_change = change_tick.wrapping_sub(tracker.ticks.changed.tick);
|
||||||
assert!(ticks_since_insert > MAX_CHANGE_AGE);
|
assert!(ticks_since_insert > MAX_CHANGE_AGE);
|
||||||
assert!(ticks_since_change > MAX_CHANGE_AGE);
|
assert!(ticks_since_change > MAX_CHANGE_AGE);
|
||||||
}
|
}
|
||||||
|
@ -796,8 +795,8 @@ mod tests {
|
||||||
world.check_change_ticks();
|
world.check_change_ticks();
|
||||||
|
|
||||||
for tracker in query.iter(&world) {
|
for tracker in query.iter(&world) {
|
||||||
let ticks_since_insert = change_tick.wrapping_sub(tracker.component_ticks.added.tick);
|
let ticks_since_insert = change_tick.wrapping_sub(tracker.ticks.added.tick);
|
||||||
let ticks_since_change = change_tick.wrapping_sub(tracker.component_ticks.changed.tick);
|
let ticks_since_change = change_tick.wrapping_sub(tracker.ticks.changed.tick);
|
||||||
assert!(ticks_since_insert == MAX_CHANGE_AGE);
|
assert!(ticks_since_insert == MAX_CHANGE_AGE);
|
||||||
assert!(ticks_since_change == MAX_CHANGE_AGE);
|
assert!(ticks_since_change == MAX_CHANGE_AGE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,9 @@ pub use bevy_ptr as ptr;
|
||||||
|
|
||||||
/// Most commonly used re-exported types.
|
/// Most commonly used re-exported types.
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(deprecated)]
|
||||||
|
pub use crate::query::ChangeTrackers;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[cfg(feature = "bevy_reflect")]
|
#[cfg(feature = "bevy_reflect")]
|
||||||
pub use crate::reflect::{ReflectComponent, ReflectResource};
|
pub use crate::reflect::{ReflectComponent, ReflectResource};
|
||||||
|
@ -35,7 +38,7 @@ pub mod prelude {
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
event::{Event, EventReader, EventWriter, Events},
|
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,
|
removal_detection::RemovedComponents,
|
||||||
schedule::{
|
schedule::{
|
||||||
apply_state_transition, apply_system_buffers, common_conditions::*, IntoSystemConfig,
|
apply_state_transition, apply_system_buffers, common_conditions::*, IntoSystemConfig,
|
||||||
|
@ -63,11 +66,10 @@ mod tests {
|
||||||
use crate::prelude::Or;
|
use crate::prelude::Or;
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::Bundle,
|
bundle::Bundle,
|
||||||
|
change_detection::Ref,
|
||||||
component::{Component, ComponentId},
|
component::{Component, ComponentId},
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{
|
query::{Added, Changed, FilteredAccess, ReadOnlyWorldQuery, With, Without},
|
||||||
Added, ChangeTrackers, Changed, FilteredAccess, ReadOnlyWorldQuery, With, Without,
|
|
||||||
},
|
|
||||||
system::Resource,
|
system::Resource,
|
||||||
world::{Mut, World},
|
world::{Mut, World},
|
||||||
};
|
};
|
||||||
|
@ -1297,7 +1299,10 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(deprecated)]
|
||||||
fn trackers_query() {
|
fn trackers_query() {
|
||||||
|
use crate::prelude::ChangeTrackers;
|
||||||
|
|
||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
let e1 = world.spawn((A(0), B(0))).id();
|
let e1 = world.spawn((A(0), B(0))).id();
|
||||||
world.spawn(B(0));
|
world.spawn(B(0));
|
||||||
|
@ -1541,7 +1546,7 @@ mod tests {
|
||||||
assert_eq!(1, query_min_size![&B, (With<A>, With<C>)],);
|
assert_eq!(1, query_min_size![&B, (With<A>, With<C>)],);
|
||||||
assert_eq!(1, query_min_size![(&A, &B), With<C>],);
|
assert_eq!(1, query_min_size![(&A, &B), With<C>],);
|
||||||
assert_eq!(4, query_min_size![&A, ()], "Simple Archetypal");
|
assert_eq!(4, query_min_size![&A, ()], "Simple Archetypal");
|
||||||
assert_eq!(4, query_min_size![ChangeTrackers<A>, ()],);
|
assert_eq!(4, query_min_size![Ref<A>, ()],);
|
||||||
// All the following should set minimum size to 0, as it's impossible to predict
|
// All the following should set minimum size to 0, as it's impossible to predict
|
||||||
// how many entities the filters will trim.
|
// how many entities the filters will trim.
|
||||||
assert_eq!(0, query_min_size![(), Added<A>], "Simple Added");
|
assert_eq!(0, query_min_size![(), Added<A>], "Simple Added");
|
||||||
|
|
|
@ -1115,6 +1115,7 @@ unsafe impl<T: ReadOnlyWorldQuery> ReadOnlyWorldQuery for Option<T> {}
|
||||||
/// }
|
/// }
|
||||||
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
|
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
|
||||||
/// ```
|
/// ```
|
||||||
|
#[deprecated = "`ChangeTrackers<T>` will be removed in bevy 0.11. Use `bevy_ecs::prelude::Ref<T>` instead."]
|
||||||
pub struct ChangeTrackers<T: Component> {
|
pub struct ChangeTrackers<T: Component> {
|
||||||
pub(crate) component_ticks: ComponentTicks,
|
pub(crate) component_ticks: ComponentTicks,
|
||||||
pub(crate) last_change_tick: u32,
|
pub(crate) last_change_tick: u32,
|
||||||
|
@ -1122,18 +1123,17 @@ pub struct ChangeTrackers<T: Component> {
|
||||||
marker: PhantomData<T>,
|
marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
impl<T: Component> Clone for ChangeTrackers<T> {
|
impl<T: Component> Clone for ChangeTrackers<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
*self
|
||||||
component_ticks: self.component_ticks,
|
|
||||||
last_change_tick: self.last_change_tick,
|
|
||||||
change_tick: self.change_tick,
|
|
||||||
marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
impl<T: Component> Copy for ChangeTrackers<T> {}
|
impl<T: Component> Copy for ChangeTrackers<T> {}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
impl<T: Component> std::fmt::Debug for ChangeTrackers<T> {
|
impl<T: Component> std::fmt::Debug for ChangeTrackers<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("ChangeTrackers")
|
f.debug_struct("ChangeTrackers")
|
||||||
|
@ -1144,6 +1144,7 @@ impl<T: Component> std::fmt::Debug for ChangeTrackers<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
impl<T: Component> ChangeTrackers<T> {
|
impl<T: Component> ChangeTrackers<T> {
|
||||||
/// Returns true if this component has been added since the last execution of this system.
|
/// Returns true if this component has been added since the last execution of this system.
|
||||||
pub fn is_added(&self) -> bool {
|
pub fn is_added(&self) -> bool {
|
||||||
|
@ -1171,6 +1172,7 @@ pub struct ChangeTrackersFetch<'w, T> {
|
||||||
change_tick: u32,
|
change_tick: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
||||||
unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
||||||
type Fetch<'w> = ChangeTrackersFetch<'w, T>;
|
type Fetch<'w> = ChangeTrackersFetch<'w, T>;
|
||||||
|
@ -1317,6 +1319,7 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
/// SAFETY: access is read only
|
/// SAFETY: access is read only
|
||||||
unsafe impl<T: Component> ReadOnlyWorldQuery for ChangeTrackers<T> {}
|
unsafe impl<T: Component> ReadOnlyWorldQuery for ChangeTrackers<T> {}
|
||||||
|
|
||||||
|
|
|
@ -572,7 +572,7 @@ impl_tick_filter!(
|
||||||
/// A common use for this filter is one-time initialization.
|
/// 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
|
/// To retain all results without filtering but still check whether they were added after the
|
||||||
/// system last ran, use [`ChangeTrackers<T>`](crate::query::ChangeTrackers).
|
/// system last ran, use [`Ref<T>`](crate::change_detection::Ref).
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! This example illustrates how to react to component change.
|
//! This example illustrates how to react to component change.
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::{ecs::world::Ref, prelude::*};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -43,15 +43,15 @@ fn change_detection(query: Query<(Entity, &MyComponent), Changed<MyComponent>>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// By looking at trackers, the query is not filtered but the information is available
|
// By using `Ref`, the query is not filtered but the information is available
|
||||||
fn tracker_monitoring(
|
fn tracker_monitoring(query: Query<(Entity, Ref<MyComponent>)>) {
|
||||||
query: Query<(
|
for (entity, component) in &query {
|
||||||
Entity,
|
info!(
|
||||||
Option<&MyComponent>,
|
"{:?}: {:?} -> {{is_added: {}, is_changed: {}}}",
|
||||||
Option<ChangeTrackers<MyComponent>>,
|
entity,
|
||||||
)>,
|
component,
|
||||||
) {
|
component.is_added(),
|
||||||
for (entity, component, trackers) in &query {
|
component.is_changed()
|
||||||
info!("{:?}: {:?} -> {:?}", entity, component, trackers);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue