bevy_ecs::change_detection

Trait DetectChangesMut

Source
pub trait DetectChangesMut: DetectChanges {
    type Inner: ?Sized;

    // Required methods
    fn set_changed(&mut self);
    fn set_last_changed(&mut self, last_changed: Tick);
    fn bypass_change_detection(&mut self) -> &mut Self::Inner;

    // Provided methods
    fn set_if_neq(&mut self, value: Self::Inner) -> bool
       where Self::Inner: Sized + PartialEq { ... }
    fn replace_if_neq(&mut self, value: Self::Inner) -> Option<Self::Inner>
       where Self::Inner: Sized + PartialEq { ... }
}
Expand description

Types that implement reliable change detection.

§Example

Using types that implement DetectChangesMut, such as ResMut, provide a way to query if a value has been mutated in another system. Normally change detection is triggered by either DerefMut or AsMut, however it can be manually triggered via set_changed.

To ensure that changes are only triggered when the value actually differs, check if the value would change before assignment, such as by checking that new != old. You must be sure that you are not mutably dereferencing in this process.

set_if_neq is a helper method for this common functionality.

use bevy_ecs::prelude::*;

#[derive(Resource)]
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`]
}

Required Associated Types§

Source

type Inner: ?Sized

The type contained within this smart pointer

For example, for ResMut<T> this would be T.

Required Methods§

Source

fn set_changed(&mut self)

Flags this value as having been changed.

Mutably accessing this smart pointer will automatically flag this value as having been changed. However, mutation through interior mutability requires manual reporting.

Note: This operation cannot be undone.

Source

fn set_last_changed(&mut self, last_changed: Tick)

Manually sets the change tick recording the time when this data was last mutated.

§Warning

This is a complex and error-prone operation, primarily intended for use with rollback networking strategies. If you merely want to flag this data as changed, use set_changed instead. If you want to avoid triggering change detection, use bypass_change_detection instead.

Source

fn bypass_change_detection(&mut self) -> &mut Self::Inner

Manually bypasses change detection, allowing you to mutate the underlying value without updating the change tick.

§Warning

This is a risky operation, that can have unexpected consequences on any system relying on this code. However, it can be an essential escape hatch when, for example, you are trying to synchronize representations using change detection and need to avoid infinite recursion.

Provided Methods§

Source

fn set_if_neq(&mut self, value: Self::Inner) -> bool
where Self::Inner: Sized + PartialEq,

Overwrites this smart pointer with the given value, if and only if *self != value. Returns true if the value was overwritten, and returns false if it was not.

This is useful to ensure change detection is only triggered when the underlying value changes, instead of every time it is mutably accessed.

If you’re dealing with non-trivial structs which have multiple fields of non-trivial size, then consider applying a map_unchanged beforehand to allow changing only the relevant field and prevent unnecessary copying and cloning. See the docs of Mut::map_unchanged, MutUntyped::map_unchanged, ResMut::map_unchanged or NonSendMut::map_unchanged for an example

If you need the previous value, use replace_if_neq.

§Examples
#[derive(Resource, PartialEq, Eq)]
pub struct Score(u32);

fn reset_score(mut score: ResMut<Score>) {
    // Set the score to zero, unless it is already zero.
    score.set_if_neq(Score(0));
}
Source

fn replace_if_neq(&mut self, value: Self::Inner) -> Option<Self::Inner>
where Self::Inner: Sized + PartialEq,

Overwrites this smart pointer with the given value, if and only if *self != value, returning the previous value if this occurs.

This is useful to ensure change detection is only triggered when the underlying value changes, instead of every time it is mutably accessed.

If you’re dealing with non-trivial structs which have multiple fields of non-trivial size, then consider applying a map_unchanged beforehand to allow changing only the relevant field and prevent unnecessary copying and cloning. See the docs of Mut::map_unchanged, MutUntyped::map_unchanged, ResMut::map_unchanged or NonSendMut::map_unchanged for an example

If you don’t need the previous value, use set_if_neq.

§Examples
#[derive(Resource, PartialEq, Eq)]
pub struct Score(u32);

#[derive(Event, PartialEq, Eq)]
pub struct ScoreChanged {
    current: u32,
    previous: u32,
}

fn reset_score(mut score: ResMut<Score>, mut score_changed: EventWriter<ScoreChanged>) {
    // Set the score to zero, unless it is already zero.
    let new_score = 0;
    if let Some(Score(previous_score)) = score.replace_if_neq(Score(new_score)) {
        // If `score` change, emit a `ScoreChanged` event.
        score_changed.send(ScoreChanged {
            current: new_score,
            previous: previous_score,
        });
    }
}

Implementors§

Source§

impl<'w> DetectChangesMut for MutUntyped<'w>

Source§

impl<'w, T: ?Sized + Resource> DetectChangesMut for ResMut<'w, T>

Source§

type Inner = T

Source§

impl<'w, T: ?Sized> DetectChangesMut for Mut<'w, T>

Source§

type Inner = T

Source§

impl<'w, T: ?Sized> DetectChangesMut for NonSendMut<'w, T>

Source§

type Inner = T