Add mutated state when inserting an already existing component (#404)

Add mutated state when inserting an already existing component
This commit is contained in:
Guillaume DALLENNE 2020-11-05 02:51:54 +01:00 committed by GitHub
parent 0db9e9494d
commit 5bd6deb974
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 17 deletions

View file

@ -406,11 +406,15 @@ impl Archetype {
size: usize,
index: usize,
added: bool,
mutated: bool,
) {
let state = self.state.get_mut(&ty).unwrap();
if added {
state.added_entities[index] = true;
}
if mutated {
state.mutated_entities[index] = true;
}
let ptr = (*self.data.get())
.as_ptr()
.add(state.offset + size * index)

View file

@ -900,24 +900,24 @@ mod tests {
}
}
fn get_changed_a(world: &mut World) -> Vec<Entity> {
fn get_mutated_a(world: &mut World) -> Vec<Entity> {
world
.query_mut::<(Mutated<A>, Entity)>()
.map(|(_a, e)| e)
.collect::<Vec<Entity>>()
};
assert_eq!(get_changed_a(&mut world), vec![e1, e3]);
assert_eq!(get_mutated_a(&mut world), vec![e1, e3]);
// ensure changing an entity's archetypes also moves its mutated state
world.insert(e1, (C,)).unwrap();
assert_eq!(get_changed_a(&mut world), vec![e3, e1], "changed entities list should not change (although the order will due to archetype moves)");
assert_eq!(get_mutated_a(&mut world), vec![e3, e1], "changed entities list should not change (although the order will due to archetype moves)");
// spawning a new A entity should not change existing mutated state
world.insert(e1, (A(0), B)).unwrap();
assert_eq!(
get_changed_a(&mut world),
get_mutated_a(&mut world),
vec![e3, e1],
"changed entities list should not change"
);
@ -925,7 +925,7 @@ mod tests {
// removing an unchanged entity should not change mutated state
world.despawn(e2).unwrap();
assert_eq!(
get_changed_a(&mut world),
get_mutated_a(&mut world),
vec![e3, e1],
"changed entities list should not change"
);
@ -933,7 +933,7 @@ mod tests {
// removing a changed entity should remove it from enumeration
world.despawn(e1).unwrap();
assert_eq!(
get_changed_a(&mut world),
get_mutated_a(&mut world),
vec![e3],
"e1 should no longer be returned"
);
@ -943,8 +943,46 @@ mod tests {
assert!(world
.query_mut::<(Mutated<A>, Entity)>()
.map(|(_a, e)| e)
.collect::<Vec<Entity>>()
.is_empty());
.next()
.is_none());
let e4 = world.spawn(());
world.insert_one(e4, A(0)).unwrap();
assert!(get_mutated_a(&mut world).is_empty());
world.insert_one(e4, A(1)).unwrap();
assert_eq!(get_mutated_a(&mut world), vec![e4]);
world.clear_trackers();
// ensure inserting multiple components set mutated state for
// already existing components and set added state for
// non existing components even when changing archetype.
world.insert(e4, (A(0), B(0))).unwrap();
let added_a = world
.query::<(Added<A>, Entity)>()
.iter()
.map(|(_, e)| e)
.next();
assert!(added_a.is_none());
assert_eq!(get_mutated_a(&mut world), vec![e4]);
let added_b = world
.query::<(Added<B>, Entity)>()
.iter()
.map(|(_, e)| e)
.next();
assert!(added_b.is_some());
let mutated_b = world
.query_mut::<(Mutated<B>, Entity)>()
.iter()
.map(|(_, e)| e)
.next();
assert!(mutated_b.is_none());
}
#[test]
@ -962,11 +1000,11 @@ mod tests {
b.0 += 1;
}
let a_b_changed = world
let a_b_mutated = world
.query_mut::<(Mutated<A>, Mutated<B>, Entity)>()
.map(|(_a, _b, e)| e)
.collect::<Vec<Entity>>();
assert_eq!(a_b_changed, vec![e2]);
assert_eq!(a_b_mutated, vec![e2]);
}
#[test]
@ -986,12 +1024,12 @@ mod tests {
b.0 += 1;
}
let a_b_changed = world
let a_b_mutated = world
.query_mut::<(Or<(Mutated<A>, Mutated<B>)>, Entity)>()
.map(|((_a, _b), e)| e)
.collect::<Vec<Entity>>();
// e1 has mutated A, e3 has mutated B, e2 has mutated A and B, _e4 has no mutated component
assert_eq!(a_b_changed, vec![e1, e2, e3]);
assert_eq!(a_b_mutated, vec![e1, e2, e3]);
}
#[test]

View file

@ -102,7 +102,7 @@ impl World {
unsafe {
let index = archetype.allocate(entity);
components.put(|ptr, ty, size| {
archetype.put_dynamic(ptr, ty, size, index, true);
archetype.put_dynamic(ptr, ty, size, index, true, false);
true
});
self.entities.meta[entity.id as usize].location = Location {
@ -530,7 +530,7 @@ impl World {
// Update components in the current archetype
let arch = &mut self.archetypes[loc.archetype as usize];
components.put(|ptr, ty, size| {
arch.put_dynamic(ptr, ty, size, loc.index, false);
arch.put_dynamic(ptr, ty, size, loc.index, false, true);
true
});
return Ok(());
@ -547,7 +547,7 @@ impl World {
let old_index = mem::replace(&mut loc.index, target_index);
if let Some(moved) =
source_arch.move_to(old_index, |ptr, ty, size, is_added, is_mutated| {
target_arch.put_dynamic(ptr, ty, size, target_index, false);
target_arch.put_dynamic(ptr, ty, size, target_index, false, false);
let type_state = target_arch.get_type_state_mut(ty).unwrap();
*type_state.added().as_ptr().add(target_index) = is_added;
*type_state.mutated().as_ptr().add(target_index) = is_mutated;
@ -557,7 +557,8 @@ impl World {
}
components.put(|ptr, ty, size| {
target_arch.put_dynamic(ptr, ty, size, target_index, true);
let had_component = source_arch.has_dynamic(ty);
target_arch.put_dynamic(ptr, ty, size, target_index, !had_component, had_component);
true
});
}
@ -1003,7 +1004,8 @@ where
unsafe {
let index = self.archetype.allocate(entity);
components.put(|ptr, ty, size| {
self.archetype.put_dynamic(ptr, ty, size, index, true);
self.archetype
.put_dynamic(ptr, ty, size, index, true, false);
true
});
self.entities.meta[entity.id as usize].location = Location {

View file

@ -231,6 +231,7 @@ impl Resources {
core::mem::size_of::<T>(),
index,
added,
!added,
);
std::mem::forget(resource);
}