Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/change_detection/traits.rs
9395 views
1
use crate::{change_detection::MaybeLocation, change_detection::Tick};
2
use alloc::borrow::ToOwned;
3
use core::mem;
4
5
/// Types that can read change detection information.
6
/// This change detection is controlled by [`DetectChangesMut`] types such as [`ResMut`].
7
///
8
/// ## Example
9
/// Using types that implement [`DetectChanges`], such as [`Res`], provide
10
/// a way to query if a value has been mutated in another system.
11
///
12
/// ```
13
/// use bevy_ecs::prelude::*;
14
///
15
/// #[derive(Resource)]
16
/// struct MyResource(u32);
17
///
18
/// fn my_system(mut resource: Res<MyResource>) {
19
/// if resource.is_changed() {
20
/// println!("My component was mutated!");
21
/// }
22
/// }
23
/// ```
24
///
25
/// [`Res`]: crate::change_detection::params::Res
26
/// [`ResMut`]: crate::change_detection::params::ResMut
27
pub trait DetectChanges {
28
/// Returns `true` if this value was added after the system last ran.
29
fn is_added(&self) -> bool;
30
31
/// Returns `true` if this value was added or mutably dereferenced
32
/// either since the last time the system ran or, if the system never ran,
33
/// since the beginning of the program.
34
///
35
/// To check if the value was mutably dereferenced only,
36
/// use `this.is_changed() && !this.is_added()`.
37
fn is_changed(&self) -> bool;
38
39
/// Returns the change tick recording the time this data was most recently changed.
40
///
41
/// Note that components and resources are also marked as changed upon insertion.
42
///
43
/// For comparison, the previous change tick of a system can be read using the
44
/// [`SystemChangeTick`](crate::system::SystemChangeTick)
45
/// [`SystemParam`](crate::system::SystemParam).
46
fn last_changed(&self) -> Tick;
47
48
/// Returns the change tick recording the time this data was added.
49
fn added(&self) -> Tick;
50
51
/// The location that last caused this to change.
52
fn changed_by(&self) -> MaybeLocation;
53
}
54
55
/// Types that implement reliable change detection.
56
///
57
/// ## Example
58
/// Using types that implement [`DetectChangesMut`], such as [`ResMut`], provide
59
/// a way to query if a value has been mutated in another system.
60
/// Normally change detection is triggered by either [`DerefMut`] or [`AsMut`], however
61
/// it can be manually triggered via [`set_changed`](DetectChangesMut::set_changed).
62
///
63
/// To ensure that changes are only triggered when the value actually differs,
64
/// check if the value would change before assignment, such as by checking that `new != old`.
65
/// You must be *sure* that you are not mutably dereferencing in this process.
66
///
67
/// [`set_if_neq`](DetectChangesMut::set_if_neq) is a helper
68
/// method for this common functionality.
69
///
70
/// ```
71
/// use bevy_ecs::prelude::*;
72
///
73
/// #[derive(Resource)]
74
/// struct MyResource(u32);
75
///
76
/// fn my_system(mut resource: ResMut<MyResource>) {
77
/// if resource.is_changed() {
78
/// println!("My resource was mutated!");
79
/// }
80
///
81
/// resource.0 = 42; // triggers change detection via [`DerefMut`]
82
/// }
83
/// ```
84
///
85
/// [`ResMut`]: crate::change_detection::params::ResMut
86
/// [`DerefMut`]: core::ops::DerefMut
87
pub trait DetectChangesMut: DetectChanges {
88
/// The type contained within this smart pointer
89
///
90
/// For example, for `ResMut<T>` this would be `T`.
91
type Inner: ?Sized;
92
93
/// Flags this value as having been changed.
94
///
95
/// Mutably accessing this smart pointer will automatically flag this value as having been changed.
96
/// However, mutation through interior mutability requires manual reporting.
97
///
98
/// **Note**: This operation cannot be undone.
99
fn set_changed(&mut self);
100
101
/// Flags this value as having been added.
102
///
103
/// It is not normally necessary to call this method.
104
/// The 'added' tick is set when the value is first added,
105
/// and is not normally changed afterwards.
106
///
107
/// **Note**: This operation cannot be undone.
108
fn set_added(&mut self);
109
110
/// Manually sets the change tick recording the time when this data was last mutated.
111
///
112
/// # Warning
113
/// This is a complex and error-prone operation, primarily intended for use with rollback networking strategies.
114
/// If you merely want to flag this data as changed, use [`set_changed`](DetectChangesMut::set_changed) instead.
115
/// If you want to avoid triggering change detection, use [`bypass_change_detection`](DetectChangesMut::bypass_change_detection) instead.
116
fn set_last_changed(&mut self, last_changed: Tick);
117
118
/// Manually sets the added tick recording the time when this data was last added.
119
///
120
/// # Warning
121
/// The caveats of [`set_last_changed`](DetectChangesMut::set_last_changed) apply. This modifies both the added and changed ticks together.
122
fn set_last_added(&mut self, last_added: Tick);
123
124
// NOTE: if you are changing the following comment also change the [`ContiguousMut::bypass_change_detection`] comment.
125
/// Manually bypasses change detection, allowing you to mutate the underlying value without updating the change tick.
126
///
127
/// # Warning
128
/// This is a risky operation, that can have unexpected consequences on any system relying on this code.
129
/// However, it can be an essential escape hatch when, for example,
130
/// you are trying to synchronize representations using change detection and need to avoid infinite recursion.
131
fn bypass_change_detection(&mut self) -> &mut Self::Inner;
132
133
/// Overwrites this smart pointer with the given value, if and only if `*self != value`.
134
/// Returns `true` if the value was overwritten, and returns `false` if it was not.
135
///
136
/// This is useful to ensure change detection is only triggered when the underlying value
137
/// changes, instead of every time it is mutably accessed.
138
///
139
/// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,
140
/// then consider applying a `map_unchanged` beforehand to allow changing only the relevant
141
/// field and prevent unnecessary copying and cloning.
142
/// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],
143
/// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example
144
///
145
/// If you need the previous value, use [`replace_if_neq`](DetectChangesMut::replace_if_neq).
146
///
147
/// # Examples
148
///
149
/// ```
150
/// # use bevy_ecs::{prelude::*, schedule::common_conditions::resource_changed};
151
/// #[derive(Resource, PartialEq, Eq)]
152
/// pub struct Score(u32);
153
///
154
/// fn reset_score(mut score: ResMut<Score>) {
155
/// // Set the score to zero, unless it is already zero.
156
/// score.set_if_neq(Score(0));
157
/// }
158
/// # let mut world = World::new();
159
/// # world.insert_resource(Score(1));
160
/// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
161
/// # score_changed.initialize(&mut world);
162
/// # score_changed.run((), &mut world);
163
/// #
164
/// # let mut schedule = Schedule::default();
165
/// # schedule.add_systems(reset_score);
166
/// #
167
/// # // first time `reset_score` runs, the score is changed.
168
/// # schedule.run(&mut world);
169
/// # assert!(score_changed.run((), &mut world).unwrap());
170
/// # // second time `reset_score` runs, the score is not changed.
171
/// # schedule.run(&mut world);
172
/// # assert!(!score_changed.run((), &mut world).unwrap());
173
/// ```
174
///
175
/// [`Mut::map_unchanged`]: crate::change_detection::params::Mut::map_unchanged
176
/// [`MutUntyped::map_unchanged`]: crate::change_detection::params::MutUntyped::map_unchanged
177
/// [`ResMut::map_unchanged`]: crate::change_detection::params::ResMut::map_unchanged
178
/// [`NonSendMut::map_unchanged`]: crate::change_detection::params::NonSendMut::map_unchanged
179
#[inline]
180
#[track_caller]
181
fn set_if_neq(&mut self, value: Self::Inner) -> bool
182
where
183
Self::Inner: Sized + PartialEq,
184
{
185
let old = self.bypass_change_detection();
186
if *old != value {
187
*old = value;
188
self.set_changed();
189
true
190
} else {
191
false
192
}
193
}
194
195
/// Overwrites this smart pointer with the given value, if and only if `*self != value`,
196
/// returning the previous value if this occurs.
197
///
198
/// This is useful to ensure change detection is only triggered when the underlying value
199
/// changes, instead of every time it is mutably accessed.
200
///
201
/// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,
202
/// then consider applying a `map_unchanged` beforehand to allow
203
/// changing only the relevant field and prevent unnecessary copying and cloning.
204
/// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],
205
/// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example
206
///
207
/// If you don't need the previous value, use [`set_if_neq`](DetectChangesMut::set_if_neq).
208
///
209
/// # Examples
210
///
211
/// ```
212
/// # use bevy_ecs::{prelude::*, schedule::common_conditions::{resource_changed, on_message}};
213
/// #[derive(Resource, PartialEq, Eq)]
214
/// pub struct Score(u32);
215
///
216
/// #[derive(Message, PartialEq, Eq)]
217
/// pub struct ScoreChanged {
218
/// current: u32,
219
/// previous: u32,
220
/// }
221
///
222
/// fn reset_score(mut score: ResMut<Score>, mut score_changed: MessageWriter<ScoreChanged>) {
223
/// // Set the score to zero, unless it is already zero.
224
/// let new_score = 0;
225
/// if let Some(Score(previous_score)) = score.replace_if_neq(Score(new_score)) {
226
/// // If `score` change, emit a `ScoreChanged` event.
227
/// score_changed.write(ScoreChanged {
228
/// current: new_score,
229
/// previous: previous_score,
230
/// });
231
/// }
232
/// }
233
/// # let mut world = World::new();
234
/// # world.insert_resource(Messages::<ScoreChanged>::default());
235
/// # world.insert_resource(Score(1));
236
/// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
237
/// # score_changed.initialize(&mut world);
238
/// # score_changed.run((), &mut world);
239
/// #
240
/// # let mut score_changed_event = IntoSystem::into_system(on_message::<ScoreChanged>);
241
/// # score_changed_event.initialize(&mut world);
242
/// # score_changed_event.run((), &mut world);
243
/// #
244
/// # let mut schedule = Schedule::default();
245
/// # schedule.add_systems(reset_score);
246
/// #
247
/// # // first time `reset_score` runs, the score is changed.
248
/// # schedule.run(&mut world);
249
/// # assert!(score_changed.run((), &mut world).unwrap());
250
/// # assert!(score_changed_event.run((), &mut world).unwrap());
251
/// # // second time `reset_score` runs, the score is not changed.
252
/// # schedule.run(&mut world);
253
/// # assert!(!score_changed.run((), &mut world).unwrap());
254
/// # assert!(!score_changed_event.run((), &mut world).unwrap());
255
/// ```
256
///
257
/// [`Mut::map_unchanged`]: crate::change_detection::params::Mut::map_unchanged
258
/// [`MutUntyped::map_unchanged`]: crate::change_detection::params::MutUntyped::map_unchanged
259
/// [`ResMut::map_unchanged`]: crate::change_detection::params::ResMut::map_unchanged
260
/// [`NonSendMut::map_unchanged`]: crate::change_detection::params::NonSendMut::map_unchanged
261
#[inline]
262
#[must_use = "If you don't need to handle the previous value, use `set_if_neq` instead."]
263
fn replace_if_neq(&mut self, value: Self::Inner) -> Option<Self::Inner>
264
where
265
Self::Inner: Sized + PartialEq,
266
{
267
let old = self.bypass_change_detection();
268
if *old != value {
269
let previous = mem::replace(old, value);
270
self.set_changed();
271
Some(previous)
272
} else {
273
None
274
}
275
}
276
277
/// Overwrites this smart pointer with a clone of the given value, if and only if `*self != value`.
278
/// Returns `true` if the value was overwritten, and returns `false` if it was not.
279
///
280
/// This method is useful when the caller only has a borrowed form of `Inner`,
281
/// e.g. when writing a `&str` into a `Mut<String>`.
282
///
283
/// # Examples
284
/// ```
285
/// # extern crate alloc;
286
/// # use alloc::borrow::ToOwned;
287
/// # use bevy_ecs::{prelude::*, schedule::common_conditions::resource_changed};
288
/// #[derive(Resource)]
289
/// pub struct Message(String);
290
///
291
/// fn update_message(mut message: ResMut<Message>) {
292
/// // Set the score to zero, unless it is already zero.
293
/// ResMut::map_unchanged(message, |Message(msg)| msg).clone_from_if_neq("another string");
294
/// }
295
/// # let mut world = World::new();
296
/// # world.insert_resource(Message("initial string".into()));
297
/// # let mut message_changed = IntoSystem::into_system(resource_changed::<Message>);
298
/// # message_changed.initialize(&mut world);
299
/// # message_changed.run((), &mut world);
300
/// #
301
/// # let mut schedule = Schedule::default();
302
/// # schedule.add_systems(update_message);
303
/// #
304
/// # // first time `reset_score` runs, the score is changed.
305
/// # schedule.run(&mut world);
306
/// # assert!(message_changed.run((), &mut world).unwrap());
307
/// # // second time `reset_score` runs, the score is not changed.
308
/// # schedule.run(&mut world);
309
/// # assert!(!message_changed.run((), &mut world).unwrap());
310
/// ```
311
fn clone_from_if_neq<T>(&mut self, value: &T) -> bool
312
where
313
T: ToOwned<Owned = Self::Inner> + ?Sized,
314
Self::Inner: PartialEq<T>,
315
{
316
let old = self.bypass_change_detection();
317
if old != value {
318
value.clone_into(old);
319
self.set_changed();
320
true
321
} else {
322
false
323
}
324
}
325
}
326
327
macro_rules! change_detection_impl {
328
($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
329
impl<$($generics),* : ?Sized $(+ $traits)?> DetectChanges for $name<$($generics),*> {
330
#[inline]
331
fn is_added(&self) -> bool {
332
self.ticks
333
.added
334
.is_newer_than(self.ticks.last_run, self.ticks.this_run)
335
}
336
337
#[inline]
338
fn is_changed(&self) -> bool {
339
self.ticks
340
.changed
341
.is_newer_than(self.ticks.last_run, self.ticks.this_run)
342
}
343
344
#[inline]
345
fn last_changed(&self) -> Tick {
346
*self.ticks.changed
347
}
348
349
#[inline]
350
fn added(&self) -> Tick {
351
*self.ticks.added
352
}
353
354
#[inline]
355
fn changed_by(&self) -> MaybeLocation {
356
self.ticks.changed_by.copied()
357
}
358
}
359
360
impl<$($generics),*: ?Sized $(+ $traits)?> Deref for $name<$($generics),*> {
361
type Target = $target;
362
363
#[inline]
364
fn deref(&self) -> &Self::Target {
365
self.value
366
}
367
}
368
369
impl<$($generics),* $(: $traits)?> AsRef<$target> for $name<$($generics),*> {
370
#[inline]
371
fn as_ref(&self) -> &$target {
372
self.deref()
373
}
374
}
375
}
376
}
377
378
pub(crate) use change_detection_impl;
379
380
macro_rules! change_detection_mut_impl {
381
($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
382
impl<$($generics),* : ?Sized $(+ $traits)?> DetectChangesMut for $name<$($generics),*> {
383
type Inner = $target;
384
385
#[inline]
386
#[track_caller]
387
fn set_changed(&mut self) {
388
*self.ticks.changed = self.ticks.this_run;
389
self.ticks.changed_by.assign(MaybeLocation::caller());
390
}
391
392
#[inline]
393
#[track_caller]
394
fn set_added(&mut self) {
395
*self.ticks.changed = self.ticks.this_run;
396
*self.ticks.added = self.ticks.this_run;
397
self.ticks.changed_by.assign(MaybeLocation::caller());
398
}
399
400
#[inline]
401
#[track_caller]
402
fn set_last_changed(&mut self, last_changed: Tick) {
403
*self.ticks.changed = last_changed;
404
self.ticks.changed_by.assign(MaybeLocation::caller());
405
}
406
407
#[inline]
408
#[track_caller]
409
fn set_last_added(&mut self, last_added: Tick) {
410
*self.ticks.added = last_added;
411
*self.ticks.changed = last_added;
412
self.ticks.changed_by.assign(MaybeLocation::caller());
413
}
414
415
#[inline]
416
fn bypass_change_detection(&mut self) -> &mut Self::Inner {
417
self.value
418
}
419
}
420
421
impl<$($generics),* : ?Sized $(+ $traits)?> DerefMut for $name<$($generics),*> {
422
#[inline]
423
#[track_caller]
424
fn deref_mut(&mut self) -> &mut Self::Target {
425
self.set_changed();
426
self.ticks.changed_by.assign(MaybeLocation::caller());
427
self.value
428
}
429
}
430
431
impl<$($generics),* $(: $traits)?> AsMut<$target> for $name<$($generics),*> {
432
#[inline]
433
fn as_mut(&mut self) -> &mut $target {
434
self.deref_mut()
435
}
436
}
437
};
438
}
439
440
pub(crate) use change_detection_mut_impl;
441
442
macro_rules! impl_methods {
443
($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
444
impl<$($generics),* : ?Sized $(+ $traits)?> $name<$($generics),*> {
445
/// Consume `self` and return a mutable reference to the
446
/// contained value while marking `self` as "changed".
447
#[inline]
448
pub fn into_inner(mut self) -> &'w mut $target {
449
self.set_changed();
450
self.value
451
}
452
453
/// Returns a `Mut<>` with a smaller lifetime.
454
/// This is useful if you have `&mut
455
#[doc = stringify!($name)]
456
/// <T>`, but you need a `Mut<T>`.
457
pub fn reborrow(&mut self) -> Mut<'_, $target> {
458
Mut {
459
value: self.value,
460
ticks: ComponentTicksMut {
461
added: self.ticks.added,
462
changed: self.ticks.changed,
463
changed_by: self.ticks.changed_by.as_deref_mut(),
464
last_run: self.ticks.last_run,
465
this_run: self.ticks.this_run,
466
},
467
}
468
}
469
470
/// Maps to an inner value by applying a function to the contained reference, without flagging a change.
471
///
472
/// You should never modify the argument passed to the closure -- if you want to modify the data
473
/// without flagging a change, consider using [`DetectChangesMut::bypass_change_detection`] to make your intent explicit.
474
///
475
/// ```
476
/// # use bevy_ecs::prelude::*;
477
/// # #[derive(PartialEq)] pub struct Vec2;
478
/// # impl Vec2 { pub const ZERO: Self = Self; }
479
/// # #[derive(Component)] pub struct Transform { translation: Vec2 }
480
/// // When run, zeroes the translation of every entity.
481
/// fn reset_positions(mut transforms: Query<&mut Transform>) {
482
/// for transform in &mut transforms {
483
/// // We pinky promise not to modify `t` within the closure.
484
/// // Breaking this promise will result in logic errors, but will never cause undefined behavior.
485
/// let mut translation = transform.map_unchanged(|t| &mut t.translation);
486
/// // Only reset the translation if it isn't already zero;
487
/// translation.set_if_neq(Vec2::ZERO);
488
/// }
489
/// }
490
/// # bevy_ecs::system::assert_is_system(reset_positions);
491
/// ```
492
pub fn map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> &mut U) -> Mut<'w, U> {
493
Mut {
494
value: f(self.value),
495
ticks: self.ticks,
496
}
497
}
498
499
/// Optionally maps to an inner value by applying a function to the contained reference.
500
/// This is useful in a situation where you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains `U`.
501
///
502
/// As with `map_unchanged`, you should never modify the argument passed to the closure.
503
pub fn filter_map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> Option<&mut U>) -> Option<Mut<'w, U>> {
504
let value = f(self.value);
505
value.map(|value| Mut {
506
value,
507
ticks: self.ticks,
508
})
509
}
510
511
/// Optionally maps to an inner value by applying a function to the contained reference, returns an error on failure.
512
/// This is useful in a situation where you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains `U`.
513
///
514
/// As with `map_unchanged`, you should never modify the argument passed to the closure.
515
pub fn try_map_unchanged<U: ?Sized, E>(self, f: impl FnOnce(&mut $target) -> Result<&mut U, E>) -> Result<Mut<'w, U>, E> {
516
let value = f(self.value);
517
value.map(|value| Mut {
518
value,
519
ticks: self.ticks,
520
})
521
}
522
523
/// Allows you access to the dereferenced value of this pointer without immediately
524
/// triggering change detection.
525
pub fn as_deref_mut(&mut self) -> Mut<'_, <$target as Deref>::Target>
526
where $target: DerefMut
527
{
528
self.reborrow().map_unchanged(|v| v.deref_mut())
529
}
530
531
}
532
};
533
}
534
535
pub(crate) use impl_methods;
536
537
macro_rules! impl_debug {
538
($name:ident < $( $generics:tt ),+ >, $($traits:ident)?) => {
539
impl<$($generics),* : ?Sized $(+ $traits)?> core::fmt::Debug for $name<$($generics),*>
540
where T: core::fmt::Debug
541
{
542
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
543
f.debug_tuple(stringify!($name))
544
.field(&self.value)
545
.finish()
546
}
547
}
548
549
};
550
}
551
552
pub(crate) use impl_debug;
553
554