Fix Sparse Change Detection (#6896)
# Objective #6547 accidentally broke change detection for SparseSet components by using `Ticks::from_tick_cells` with the wrong argument order. ## Solution Use the right argument order. Add a regression test.
This commit is contained in:
parent
a5d70b8952
commit
6308041772
@ -960,6 +960,90 @@ mod tests {
|
||||
assert_eq!(get_filtered::<Changed<B>>(&mut world), vec![e4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn changed_trackers_sparse() {
|
||||
let mut world = World::default();
|
||||
let e1 = world.spawn(SparseStored(0)).id();
|
||||
let e2 = world.spawn(SparseStored(0)).id();
|
||||
let e3 = world.spawn(SparseStored(0)).id();
|
||||
world.spawn(SparseStored(0));
|
||||
|
||||
world.clear_trackers();
|
||||
|
||||
for (i, mut a) in world
|
||||
.query::<&mut SparseStored>()
|
||||
.iter_mut(&mut world)
|
||||
.enumerate()
|
||||
{
|
||||
if i % 2 == 0 {
|
||||
a.0 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_filtered<F: ReadOnlyWorldQuery>(world: &mut World) -> Vec<Entity> {
|
||||
world
|
||||
.query_filtered::<Entity, F>()
|
||||
.iter(world)
|
||||
.collect::<Vec<Entity>>()
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
get_filtered::<Changed<SparseStored>>(&mut world),
|
||||
vec![e1, e3]
|
||||
);
|
||||
|
||||
// ensure changing an entity's archetypes also moves its changed state
|
||||
world.entity_mut(e1).insert(C);
|
||||
|
||||
assert_eq!(get_filtered::<Changed<SparseStored>>(&mut world), vec![e3, e1], "changed entities list should not change (although the order will due to archetype moves)");
|
||||
|
||||
// spawning a new SparseStored entity should not change existing changed state
|
||||
world.entity_mut(e1).insert(SparseStored(0));
|
||||
assert_eq!(
|
||||
get_filtered::<Changed<SparseStored>>(&mut world),
|
||||
vec![e3, e1],
|
||||
"changed entities list should not change"
|
||||
);
|
||||
|
||||
// removing an unchanged entity should not change changed state
|
||||
assert!(world.despawn(e2));
|
||||
assert_eq!(
|
||||
get_filtered::<Changed<SparseStored>>(&mut world),
|
||||
vec![e3, e1],
|
||||
"changed entities list should not change"
|
||||
);
|
||||
|
||||
// removing a changed entity should remove it from enumeration
|
||||
assert!(world.despawn(e1));
|
||||
assert_eq!(
|
||||
get_filtered::<Changed<SparseStored>>(&mut world),
|
||||
vec![e3],
|
||||
"e1 should no longer be returned"
|
||||
);
|
||||
|
||||
world.clear_trackers();
|
||||
|
||||
assert!(get_filtered::<Changed<SparseStored>>(&mut world).is_empty());
|
||||
|
||||
let e4 = world.spawn_empty().id();
|
||||
|
||||
world.entity_mut(e4).insert(SparseStored(0));
|
||||
assert_eq!(get_filtered::<Changed<SparseStored>>(&mut world), vec![e4]);
|
||||
assert_eq!(get_filtered::<Added<SparseStored>>(&mut world), vec![e4]);
|
||||
|
||||
world.entity_mut(e4).insert(A(1));
|
||||
assert_eq!(get_filtered::<Changed<SparseStored>>(&mut world), vec![e4]);
|
||||
|
||||
world.clear_trackers();
|
||||
|
||||
// ensure inserting multiple components set changed state for all components and set added
|
||||
// state for non existing components even when changing archetype.
|
||||
world.entity_mut(e4).insert(SparseStored(0));
|
||||
|
||||
assert!(get_filtered::<Added<SparseStored>>(&mut world).is_empty());
|
||||
assert_eq!(get_filtered::<Changed<SparseStored>>(&mut world), vec![e4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_spawn() {
|
||||
let mut world = World::default();
|
||||
|
||||
@ -771,7 +771,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||
.debug_checked_unwrap();
|
||||
Mut {
|
||||
value: component.assert_unique().deref_mut(),
|
||||
ticks: Ticks::from_tick_cells(ticks, fetch.change_tick, fetch.last_change_tick),
|
||||
ticks: Ticks::from_tick_cells(ticks, fetch.last_change_tick, fetch.change_tick),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user