EntityRef::get_ref should use the change ticks of the System (if it is called from within one)
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
## What problem does this solve or what need does it fill?
1) When you query a `Ref`, the `last_run` tick inside `Ref` is populated from the last time the system has run. So `Ref::is_changed()` tells you if the component has changed since the last time the system has run.
2) This is also the case when you call `EntityRef::get_ref::` from within an exclusive system.
(probably because of https://docs.rs/bevy/latest/bevy/ecs/world/struct.World.html#method.last_change_tick
> When called from within an exclusive system (a [System](https://docs.rs/bevy/latest/bevy/ecs/system/trait.System.html) that takes &mut World as its first parameter), this method returns the [Tick](https://docs.rs/bevy/latest/bevy/ecs/component/struct.Tick.html) indicating the last time the exclusive system was run.
Otherwise, this returns the Tick indicating the last time that [World::clear_trackers](https://docs.rs/bevy/latest/bevy/ecs/world/struct.World.html#method.clear_trackers) was called.
3) But when you call `EntityRef::get_ref::` outside of an exclusive system, the `last_run` tick is from the last time `World::clear_trackers` was called (which is called in every `Last` schedule).
I think this is fairly misleading, as users are taught to expect that `Ref::is_added()` and `Ref::is_changed()` will return true if the component was added/changed since **the last time the system ran**.
(in my use case, I was calling `EntityRef::get_ref` from a system that uses the `&World` SystemParam, so I was in case 3) )
Some code that shows the current behaviour:
```rust
#[test]
fn test_ref() {
let mut world = World::new();
world.init_component::();
let entity = world.spawn(A).id();
let update_a = world.register_system(move |world: &mut World | {
world.entity_mut(entity).get_mut::().unwrap().set_changed();
});
let check_change_detection_via_entity_ref = world.register_system(move |world: &World| {
let a_ref = world.entity(entity).get_ref::().unwrap();
// dbg!(&a_ref.ticks);
dbg!("via entity_ref: ", a_ref.is_changed());
});
let check_change_detection_via_entity_ref_in_exclusive_system = world.register_system(move |world: &mut World| {
let a_ref = world.entity(entity).get_ref::().unwrap();
// dbg!(&a_ref.ticks);
dbg!("via entity_ref in exclusive system: ", a_ref.is_changed());
});
let check_change_detection_via_query = world.register_system(|query: Query>| {
let a_ref = query.single();
dbg!("via query: ", a_ref.is_changed());
});
// all are true
world.run_system(check_change_detection_via_query).unwrap();
world.run_system(check_change_detection_via_entity_ref).unwrap();
world.run_system(check_change_detection_via_entity_ref_in_exclusive_system).unwrap();
// we update A
world.run_system(update_a).unwrap();
// we clear the world trackers
world.clear_trackers();
// is_changed = true (Ref uses the ticks since the last time the system ran)
world.run_system(check_change_detection_via_query).unwrap();
// is_changed = true (entity_ref.get_ref uses the ticks since the last time the system ran, when inside
// an exclusive system)
world.run_system(check_change_detection_via_entity_ref_in_exclusive_system).unwrap();
// is_changed = true (entity_ref.get_ref uses the ticks since the last world.clear_trackers(), when not
// inside an exclusive system)
world.run_system(check_change_detection_via_entity_ref).unwrap();
}
```
## What solution would you like?
When calling `entity_ref::get_ref()` from within a system, the `last_run` `Tick` of `Ref` is populated from the last time the system has run.
Contributor guide
Assessment
This issue has not been assessed yet.