mirror of
https://github.com/bevyengine/bevy
synced 2024-09-20 06:22:01 +00:00
Refactor ResMut/Mut/ReflectMut to remove duplicated code (#2217)
`ResMut`, `Mut` and `ReflectMut` all share very similar code for change detection. This PR is a first pass at refactoring these implementation and removing a lot of the duplicated code. Note, this introduces a new trait `ChangeDetectable`. Please feel free to comment away and let me know what you think!
This commit is contained in:
parent
08e5939fd7
commit
173bb48d78
9 changed files with 231 additions and 234 deletions
169
crates/bevy_ecs/src/change_detection.rs
Normal file
169
crates/bevy_ecs/src/change_detection.rs
Normal file
|
@ -0,0 +1,169 @@
|
|||
use crate::component::{Component, ComponentTicks};
|
||||
use bevy_reflect::Reflect;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// Types that implement reliable change detection.
|
||||
///
|
||||
/// ## Example
|
||||
/// Using types that implement [`DetectChanges`], such as [`ResMut`], provide
|
||||
/// a way to query if a value has been mutated in another system.
|
||||
/// Normally change detecting is triggered by either [`DerefMut`] or [`AsMut`], however
|
||||
/// it can be manually triggered via [`DetectChanges::set_changed`].
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_ecs::prelude::*;
|
||||
///
|
||||
/// struct MyResource(u32);
|
||||
///
|
||||
/// fn my_system(mut resource: ResMut<MyResource>) {
|
||||
/// if resource.is_changed() {
|
||||
/// println!("My resource was mutated!");
|
||||
/// }
|
||||
///
|
||||
/// resource.0 = 42; // triggers change detection via [`DerefMut`]
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub trait DetectChanges {
|
||||
/// Returns true if (and only if) this value been added since the last execution of this
|
||||
/// system.
|
||||
fn is_added(&self) -> bool;
|
||||
|
||||
/// Returns true if (and only if) this value been changed since the last execution of this
|
||||
/// system.
|
||||
fn is_changed(&self) -> bool;
|
||||
|
||||
/// Manually flags this value as having been changed. This normally isn't
|
||||
/// required because accessing this pointer mutably automatically flags this
|
||||
/// value as "changed".
|
||||
///
|
||||
/// **Note**: This operation is irreversible.
|
||||
fn set_changed(&mut self);
|
||||
}
|
||||
|
||||
macro_rules! change_detection_impl {
|
||||
($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
|
||||
impl<$($generics),* $(: $traits)?> DetectChanges for $name<$($generics),*> {
|
||||
#[inline]
|
||||
fn is_added(&self) -> bool {
|
||||
self.ticks
|
||||
.component_ticks
|
||||
.is_added(self.ticks.last_change_tick, self.ticks.change_tick)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_changed(&self) -> bool {
|
||||
self.ticks
|
||||
.component_ticks
|
||||
.is_changed(self.ticks.last_change_tick, self.ticks.change_tick)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_changed(&mut self) {
|
||||
self.ticks
|
||||
.component_ticks
|
||||
.set_changed(self.ticks.change_tick);
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($generics),* $(: $traits)?> Deref for $name<$($generics),*> {
|
||||
type Target = $target;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($generics),* $(: $traits)?> DerefMut for $name<$($generics),*> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.set_changed();
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($generics),* $(: $traits)?> AsRef<$target> for $name<$($generics),*> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &$target {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($generics),* $(: $traits)?> AsMut<$target> for $name<$($generics),*> {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut $target {
|
||||
self.deref_mut()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_into_inner {
|
||||
($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
|
||||
impl<$($generics),* $(: $traits)?> $name<$($generics),*> {
|
||||
/// Consume `self` and return a mutable reference to the
|
||||
/// contained value while marking `self` as "changed".
|
||||
#[inline]
|
||||
pub fn into_inner(mut self) -> &'a mut $target {
|
||||
self.set_changed();
|
||||
self.value
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_debug {
|
||||
($name:ident < $( $generics:tt ),+ >, $($traits:ident)?) => {
|
||||
impl<$($generics),* $(: $traits)?> std::fmt::Debug for $name<$($generics),*>
|
||||
where T: std::fmt::Debug
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple(stringify!($name))
|
||||
.field(self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) struct Ticks<'a> {
|
||||
pub(crate) component_ticks: &'a mut ComponentTicks,
|
||||
pub(crate) last_change_tick: u32,
|
||||
pub(crate) change_tick: u32,
|
||||
}
|
||||
|
||||
/// Unique mutable borrow of a resource.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics when used as a [`SystemParameter`](crate::system::SystemParam) if the resource does not exist.
|
||||
///
|
||||
/// Use `Option<ResMut<T>>` instead if the resource might not always exist.
|
||||
pub struct ResMut<'a, T: Component> {
|
||||
pub(crate) value: &'a mut T,
|
||||
pub(crate) ticks: Ticks<'a>,
|
||||
}
|
||||
|
||||
change_detection_impl!(ResMut<'a, T>, T, Component);
|
||||
impl_into_inner!(ResMut<'a, T>, T, Component);
|
||||
impl_debug!(ResMut<'a, T>, Component);
|
||||
|
||||
/// Unique mutable borrow of an entity's component
|
||||
pub struct Mut<'a, T> {
|
||||
pub(crate) value: &'a mut T,
|
||||
pub(crate) ticks: Ticks<'a>,
|
||||
}
|
||||
|
||||
change_detection_impl!(Mut<'a, T>, T,);
|
||||
impl_into_inner!(Mut<'a, T>, T,);
|
||||
impl_debug!(Mut<'a, T>,);
|
||||
|
||||
/// Unique mutable borrow of a Reflected component
|
||||
pub struct ReflectMut<'a> {
|
||||
pub(crate) value: &'a mut dyn Reflect,
|
||||
pub(crate) ticks: Ticks<'a>,
|
||||
}
|
||||
|
||||
change_detection_impl!(ReflectMut<'a>, dyn Reflect,);
|
|
@ -1,5 +1,6 @@
|
|||
pub mod archetype;
|
||||
pub mod bundle;
|
||||
pub mod change_detection;
|
||||
pub mod component;
|
||||
pub mod entity;
|
||||
pub mod event;
|
||||
|
@ -18,6 +19,7 @@ pub mod prelude {
|
|||
#[doc(hidden)]
|
||||
pub use crate::{
|
||||
bundle::Bundle,
|
||||
change_detection::DetectChanges,
|
||||
entity::Entity,
|
||||
event::{EventReader, EventWriter},
|
||||
query::{Added, ChangeTrackers, Changed, Or, QueryState, With, WithBundle, Without},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{
|
||||
archetype::{Archetype, ArchetypeComponentId},
|
||||
change_detection::Ticks,
|
||||
component::{Component, ComponentId, ComponentTicks, StorageType},
|
||||
entity::Entity,
|
||||
query::{Access, FilteredAccess},
|
||||
|
@ -529,9 +530,11 @@ impl<'w, T: Component> Fetch<'w> for WriteFetch<T> {
|
|||
let table_row = *self.entity_table_rows.add(archetype_index);
|
||||
Mut {
|
||||
value: &mut *self.table_components.as_ptr().add(table_row),
|
||||
component_ticks: &mut *self.table_ticks.add(table_row),
|
||||
change_tick: self.change_tick,
|
||||
last_change_tick: self.last_change_tick,
|
||||
ticks: Ticks {
|
||||
component_ticks: &mut *self.table_ticks.add(table_row),
|
||||
change_tick: self.change_tick,
|
||||
last_change_tick: self.last_change_tick,
|
||||
},
|
||||
}
|
||||
}
|
||||
StorageType::SparseSet => {
|
||||
|
@ -540,9 +543,11 @@ impl<'w, T: Component> Fetch<'w> for WriteFetch<T> {
|
|||
(*self.sparse_set).get_with_ticks(entity).unwrap();
|
||||
Mut {
|
||||
value: &mut *component.cast::<T>(),
|
||||
component_ticks: &mut *component_ticks,
|
||||
change_tick: self.change_tick,
|
||||
last_change_tick: self.last_change_tick,
|
||||
ticks: Ticks {
|
||||
component_ticks: &mut *component_ticks,
|
||||
change_tick: self.change_tick,
|
||||
last_change_tick: self.last_change_tick,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -552,9 +557,11 @@ impl<'w, T: Component> Fetch<'w> for WriteFetch<T> {
|
|||
unsafe fn table_fetch(&mut self, table_row: usize) -> Self::Item {
|
||||
Mut {
|
||||
value: &mut *self.table_components.as_ptr().add(table_row),
|
||||
component_ticks: &mut *self.table_ticks.add(table_row),
|
||||
change_tick: self.change_tick,
|
||||
last_change_tick: self.last_change_tick,
|
||||
ticks: Ticks {
|
||||
component_ticks: &mut *self.table_ticks.add(table_row),
|
||||
change_tick: self.change_tick,
|
||||
last_change_tick: self.last_change_tick,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
pub use crate::change_detection::ReflectMut;
|
||||
use crate::{
|
||||
component::{Component, ComponentTicks},
|
||||
component::Component,
|
||||
entity::{Entity, EntityMap, MapEntities, MapEntitiesError},
|
||||
world::{FromWorld, World},
|
||||
};
|
||||
|
@ -104,56 +103,13 @@ impl<C: Component + Reflect + FromWorld> FromType<C> for ReflectComponent {
|
|||
.get_unchecked_mut::<C>(world.last_change_tick(), world.read_change_tick())
|
||||
.map(|c| ReflectMut {
|
||||
value: c.value as &mut dyn Reflect,
|
||||
component_ticks: c.component_ticks,
|
||||
last_change_tick: c.last_change_tick,
|
||||
change_tick: c.change_tick,
|
||||
ticks: c.ticks,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unique borrow of a Reflected component
|
||||
pub struct ReflectMut<'a> {
|
||||
pub(crate) value: &'a mut dyn Reflect,
|
||||
pub(crate) component_ticks: &'a mut ComponentTicks,
|
||||
pub(crate) last_change_tick: u32,
|
||||
pub(crate) change_tick: u32,
|
||||
}
|
||||
|
||||
impl<'a> Deref for ReflectMut<'a> {
|
||||
type Target = dyn Reflect;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &dyn Reflect {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for ReflectMut<'a> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut dyn Reflect {
|
||||
self.component_ticks.set_changed(self.change_tick);
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ReflectMut<'a> {
|
||||
/// Returns true if (and only if) this component been added since the last execution of this
|
||||
/// system.
|
||||
pub fn is_added(&self) -> bool {
|
||||
self.component_ticks
|
||||
.is_added(self.last_change_tick, self.change_tick)
|
||||
}
|
||||
|
||||
/// Returns true if (and only if) this component been changed since the last execution of this
|
||||
/// system.
|
||||
pub fn is_changed(&self) -> bool {
|
||||
self.component_ticks
|
||||
.is_changed(self.last_change_tick, self.change_tick)
|
||||
}
|
||||
}
|
||||
|
||||
impl_reflect_value!(Entity(Hash, PartialEq, Serialize, Deserialize));
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
pub use crate::change_detection::ResMut;
|
||||
use crate::{
|
||||
archetype::{Archetype, Archetypes},
|
||||
bundle::Bundles,
|
||||
change_detection::Ticks,
|
||||
component::{Component, ComponentId, ComponentTicks, Components},
|
||||
entity::{Entities, Entity},
|
||||
query::{FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, WorldQuery},
|
||||
|
@ -333,83 +335,6 @@ impl<'a, T: Component> SystemParamFetch<'a> for OptionResState<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Unique borrow of a resource.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics when used as a [`SystemParameter`](SystemParam) if the resource does not exist.
|
||||
///
|
||||
/// Use `Option<ResMut<T>>` instead if the resource might not always exist.
|
||||
pub struct ResMut<'w, T: Component> {
|
||||
value: &'w mut T,
|
||||
ticks: &'w mut ComponentTicks,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
}
|
||||
|
||||
impl<'w, T: Component> Debug for ResMut<'w, T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("ResMut").field(&self.value).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T: Component> ResMut<'w, T> {
|
||||
/// Returns true if (and only if) this resource been added since the last execution of this
|
||||
/// system.
|
||||
pub fn is_added(&self) -> bool {
|
||||
self.ticks.is_added(self.last_change_tick, self.change_tick)
|
||||
}
|
||||
|
||||
/// Returns true if (and only if) this resource been changed since the last execution of this
|
||||
/// system.
|
||||
pub fn is_changed(&self) -> bool {
|
||||
self.ticks
|
||||
.is_changed(self.last_change_tick, self.change_tick)
|
||||
}
|
||||
|
||||
/// Manually flags this resource as having been changed. This normally isn't
|
||||
/// required because accessing this pointer mutably automatically flags this
|
||||
/// resource as "changed".
|
||||
///
|
||||
/// **Note**: This operation is irreversible.
|
||||
#[inline]
|
||||
pub fn set_changed(&mut self) {
|
||||
self.ticks.set_changed(self.change_tick);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T: Component> Deref for ResMut<'w, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T: Component> DerefMut for ResMut<'w, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.set_changed();
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T: Component> AsRef<T> for ResMut<'w, T> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &T {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T: Component> AsMut<T> for ResMut<'w, T> {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
self.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`SystemParamState`] of [`ResMut`].
|
||||
pub struct ResMutState<T> {
|
||||
component_id: ComponentId,
|
||||
|
@ -476,9 +401,11 @@ impl<'a, T: Component> SystemParamFetch<'a> for ResMutState<T> {
|
|||
});
|
||||
ResMut {
|
||||
value: value.value,
|
||||
ticks: value.component_ticks,
|
||||
last_change_tick: system_state.last_change_tick,
|
||||
change_tick,
|
||||
ticks: Ticks {
|
||||
component_ticks: value.ticks.component_ticks,
|
||||
last_change_tick: system_state.last_change_tick,
|
||||
change_tick,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -514,9 +441,11 @@ impl<'a, T: Component> SystemParamFetch<'a> for OptionResMutState<T> {
|
|||
.get_resource_unchecked_mut_with_id(state.0.component_id)
|
||||
.map(|value| ResMut {
|
||||
value: value.value,
|
||||
ticks: value.component_ticks,
|
||||
last_change_tick: system_state.last_change_tick,
|
||||
change_tick,
|
||||
ticks: Ticks {
|
||||
component_ticks: value.ticks.component_ticks,
|
||||
last_change_tick: system_state.last_change_tick,
|
||||
change_tick,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
archetype::{Archetype, ArchetypeId, Archetypes, ComponentStatus},
|
||||
bundle::{Bundle, BundleInfo},
|
||||
change_detection::Ticks,
|
||||
component::{Component, ComponentId, ComponentTicks, Components, StorageType},
|
||||
entity::{Entities, Entity, EntityLocation},
|
||||
storage::{SparseSet, Storages},
|
||||
|
@ -80,9 +81,11 @@ impl<'w> EntityRef<'w> {
|
|||
get_component_and_ticks_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
|
||||
.map(|(value, ticks)| Mut {
|
||||
value: &mut *value.cast::<T>(),
|
||||
component_ticks: &mut *ticks,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
ticks: Ticks {
|
||||
component_ticks: &mut *ticks,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -161,9 +164,11 @@ impl<'w> EntityMut<'w> {
|
|||
)
|
||||
.map(|(value, ticks)| Mut {
|
||||
value: &mut *value.cast::<T>(),
|
||||
component_ticks: &mut *ticks,
|
||||
last_change_tick: self.world.last_change_tick(),
|
||||
change_tick: self.world.change_tick(),
|
||||
ticks: Ticks {
|
||||
component_ticks: &mut *ticks,
|
||||
last_change_tick: self.world.last_change_tick(),
|
||||
change_tick: self.world.change_tick(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -176,9 +181,11 @@ impl<'w> EntityMut<'w> {
|
|||
get_component_and_ticks_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
|
||||
.map(|(value, ticks)| Mut {
|
||||
value: &mut *value.cast::<T>(),
|
||||
component_ticks: &mut *ticks,
|
||||
last_change_tick: self.world.last_change_tick(),
|
||||
change_tick: self.world.read_change_tick(),
|
||||
ticks: Ticks {
|
||||
component_ticks: &mut *ticks,
|
||||
last_change_tick: self.world.last_change_tick(),
|
||||
change_tick: self.world.read_change_tick(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ pub use world_cell::*;
|
|||
use crate::{
|
||||
archetype::{ArchetypeComponentId, ArchetypeComponentInfo, ArchetypeId, Archetypes},
|
||||
bundle::{Bundle, Bundles},
|
||||
change_detection::Ticks,
|
||||
component::{
|
||||
Component, ComponentDescriptor, ComponentId, ComponentTicks, Components, ComponentsError,
|
||||
StorageType,
|
||||
|
@ -708,9 +709,11 @@ impl World {
|
|||
// SAFE: pointer is of type T
|
||||
let value = Mut {
|
||||
value: unsafe { &mut *ptr.cast::<T>() },
|
||||
component_ticks: &mut ticks,
|
||||
last_change_tick: self.last_change_tick(),
|
||||
change_tick: self.change_tick(),
|
||||
ticks: Ticks {
|
||||
component_ticks: &mut ticks,
|
||||
last_change_tick: self.last_change_tick(),
|
||||
change_tick: self.change_tick(),
|
||||
},
|
||||
};
|
||||
let result = f(self, value);
|
||||
let resource_archetype = self.archetypes.resource_mut();
|
||||
|
@ -747,9 +750,11 @@ impl World {
|
|||
let column = self.get_populated_resource_column(component_id)?;
|
||||
Some(Mut {
|
||||
value: &mut *column.get_ptr().as_ptr().cast::<T>(),
|
||||
component_ticks: &mut *column.get_ticks_mut_ptr(),
|
||||
last_change_tick: self.last_change_tick(),
|
||||
change_tick: self.read_change_tick(),
|
||||
ticks: Ticks {
|
||||
component_ticks: &mut *column.get_ticks_mut_ptr(),
|
||||
last_change_tick: self.last_change_tick(),
|
||||
change_tick: self.read_change_tick(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,80 +1 @@
|
|||
use crate::component::ComponentTicks;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// Unique borrow of an entity's component
|
||||
pub struct Mut<'a, T> {
|
||||
pub(crate) value: &'a mut T,
|
||||
pub(crate) component_ticks: &'a mut ComponentTicks,
|
||||
pub(crate) last_change_tick: u32,
|
||||
pub(crate) change_tick: u32,
|
||||
}
|
||||
|
||||
impl<'a, T> Mut<'a, T> {
|
||||
pub fn into_inner(self) -> &'a mut T {
|
||||
self.component_ticks.set_changed(self.change_tick);
|
||||
self.value
|
||||
}
|
||||
|
||||
/// Manually flags this value as having been changed. This normally isn't
|
||||
/// required because accessing this pointer mutably automatically flags this
|
||||
/// value as "changed".
|
||||
///
|
||||
/// **Note**: This operation is irreversible.
|
||||
#[inline]
|
||||
pub fn set_changed(&mut self) {
|
||||
self.component_ticks.set_changed(self.change_tick);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for Mut<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DerefMut for Mut<'a, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
self.set_changed();
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: core::fmt::Debug> core::fmt::Debug for Mut<'a, T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.value.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T> AsRef<T> for Mut<'w, T> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &T {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T> AsMut<T> for Mut<'w, T> {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
self.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T> Mut<'w, T> {
|
||||
/// Returns true if (and only if) this component been added since the last execution of this
|
||||
/// system.
|
||||
pub fn is_added(&self) -> bool {
|
||||
self.component_ticks
|
||||
.is_added(self.last_change_tick, self.change_tick)
|
||||
}
|
||||
|
||||
/// Returns true if (and only if) this component been changed
|
||||
/// since the last execution of this system.
|
||||
pub fn is_changed(&self) -> bool {
|
||||
self.component_ticks
|
||||
.is_changed(self.last_change_tick, self.change_tick)
|
||||
}
|
||||
}
|
||||
pub use crate::change_detection::Mut;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use super::CameraProjection;
|
||||
use bevy_ecs::{
|
||||
change_detection::DetectChanges,
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
event::EventReader,
|
||||
|
|
Loading…
Reference in a new issue