fixed tests

This commit is contained in:
Elliott Pierce 2025-05-31 11:40:23 -04:00
parent c100f9e6ed
commit ea9a3bee7f
12 changed files with 54 additions and 27 deletions

View File

@ -1579,7 +1579,7 @@ mod tests {
app.add_systems(EnterMainMenu, (foo, bar));
app.world_mut().run_schedule(EnterMainMenu);
assert_eq!(app.world().entities().len(), 2);
assert_eq!(app.world().entities().count_active(), 2);
}
#[test]

View File

@ -22,6 +22,6 @@ impl EntityCountDiagnosticsPlugin {
pub const ENTITY_COUNT: DiagnosticPath = DiagnosticPath::const_new("entity_count");
pub fn diagnostic_system(mut diagnostics: Diagnostics, entities: &Entities) {
diagnostics.add_measurement(&Self::ENTITY_COUNT, || entities.len() as f64);
diagnostics.add_measurement(&Self::ENTITY_COUNT, || entities.count_active() as f64);
}
}

View File

@ -1,9 +1,3 @@
use alloc::{borrow::ToOwned, boxed::Box, collections::VecDeque, vec::Vec};
use bevy_platform::collections::{HashMap, HashSet};
use bevy_ptr::{Ptr, PtrMut};
use bumpalo::Bump;
use core::any::TypeId;
use crate::{
archetype::Archetype,
bundle::Bundle,
@ -13,6 +7,11 @@ use crate::{
relationship::RelationshipHookMode,
world::World,
};
use alloc::{borrow::ToOwned, boxed::Box, collections::VecDeque, vec::Vec};
use bevy_platform::collections::{HashMap, HashSet};
use bevy_ptr::{Ptr, PtrMut};
use bumpalo::Bump;
use core::any::TypeId;
use super::EntitiesAllocator;
@ -348,6 +347,8 @@ pub struct EntityCloner {
move_components: bool,
linked_cloning: bool,
default_clone_fn: ComponentCloneFn,
/// Represents a queue of entities to clone.
/// These will have targets in the entity map, which will need to be constructed.
clone_queue: VecDeque<Entity>,
deferred_commands: VecDeque<Box<dyn FnOnce(&mut World, &mut dyn EntityMapper)>>,
}
@ -458,6 +459,10 @@ impl EntityCloner {
relationship_hook_insert_mode: RelationshipHookMode,
) -> Entity {
let target = mapper.get_mapped(source);
// The target may need to be constructed if it hasn't been already.
// If this fails, it either didn't need to be constructed (ok) or doesn't exist (caught better later).
let _ = world.construct_empty(target);
// PERF: reusing allocated space across clones would be more efficient. Consider an allocation model similar to `Commands`.
let bundle_scratch_allocator = Bump::new();
let mut bundle_scratch: BundleScratch;
@ -536,6 +541,7 @@ impl EntityCloner {
}
world.flush();
world.entity_mut(target);
for deferred in self.deferred_commands.drain(..) {
(deferred)(world, mapper);

View File

@ -662,6 +662,9 @@ impl SparseSetIndex for Entity {
#[derive(Default, Debug)]
pub struct EntitiesAllocator {
free: Vec<Entity>,
/// This is continually subtracted from.
/// If it wraps to a very large number, it will be outside the bounds of `free`,
/// and a new row will be needed.
free_len: AtomicU32,
next_row: AtomicU32,
}
@ -675,7 +678,12 @@ impl EntitiesAllocator {
}
pub(crate) fn free(&mut self, freed: Entity) {
self.free.truncate(*self.free_len.get_mut() as usize);
let expected_len = *self.free_len.get_mut() as usize;
if expected_len > self.free.len() {
self.free.clear();
} else {
self.free.truncate(expected_len);
}
self.free.push(freed);
*self.free_len.get_mut() = self.free.len() as u32;
}
@ -846,7 +854,7 @@ impl Entities {
}
let index = row.index() as usize;
if self.meta.len() >= index {
if self.meta.len() <= index {
// TODO: hint unlikely once stable.
expand(&mut self.meta, index + 1);
}
@ -985,6 +993,19 @@ impl Entities {
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Counts the number of entities currently participating in the world, those that have locations.
pub fn count_active(&self) -> u32 {
self.meta
.iter()
.filter(|meta| meta.location.is_some())
.count() as u32
}
/// Returns true if there are any entities active in the world, entities that have locations.
pub fn any_active(&self) -> bool {
self.meta.iter().any(|meta| meta.location.is_some())
}
}
/// An error that occurs when a specified [`Entity`] can not be constructed.

View File

@ -358,9 +358,9 @@ mod tests {
let mut world = World::new();
let e = world.spawn((TableStored("abc"), A(123))).id();
let f = world.spawn((TableStored("def"), A(456))).id();
assert_eq!(world.entities.len(), 2);
assert_eq!(world.entities.count_active(), 2);
assert!(world.despawn(e));
assert_eq!(world.entities.len(), 1);
assert_eq!(world.entities.count_active(), 1);
assert!(world.get::<TableStored>(e).is_none());
assert!(world.get::<A>(e).is_none());
assert_eq!(world.get::<TableStored>(f).unwrap().0, "def");
@ -373,9 +373,9 @@ mod tests {
let e = world.spawn((TableStored("abc"), SparseStored(123))).id();
let f = world.spawn((TableStored("def"), SparseStored(456))).id();
assert_eq!(world.entities.len(), 2);
assert_eq!(world.entities.count_active(), 2);
assert!(world.despawn(e));
assert_eq!(world.entities.len(), 1);
assert_eq!(world.entities.count_active(), 1);
assert!(world.get::<TableStored>(e).is_none());
assert!(world.get::<SparseStored>(e).is_none());
assert_eq!(world.get::<TableStored>(f).unwrap().0, "def");
@ -1610,7 +1610,7 @@ mod tests {
assert_eq!(q1.iter(&world).len(), 1);
assert_eq!(q2.iter(&world).len(), 1);
assert_eq!(world.entities().len(), 2);
assert_eq!(world.entities().count_active(), 2);
world.clear_entities();
@ -1625,7 +1625,7 @@ mod tests {
"world should not contain sparse set components"
);
assert_eq!(
world.entities().len(),
world.entities().count_active(),
0,
"world should not have any entities"
);

View File

@ -1079,7 +1079,7 @@ mod tests {
world.spawn(A).flush();
assert_eq!(vec!["add_2", "add_1"], world.resource::<Order>().0);
// Our A entity plus our two observers
assert_eq!(world.entities().len(), 3);
assert_eq!(world.entities().count_active(), 3);
}
#[test]

View File

@ -2321,7 +2321,7 @@ mod tests {
.spawn((W(1u32), W(2u64)))
.id();
command_queue.apply(&mut world);
assert_eq!(world.entities().len(), 1);
assert_eq!(world.entities().count_active(), 1);
let results = world
.query::<(&W<u32>, &W<u64>)>()
.iter(&world)

View File

@ -423,9 +423,9 @@ mod tests {
#[test]
fn command_processing() {
let mut world = World::new();
assert_eq!(world.entities.len(), 0);
assert_eq!(world.entities.count_active(), 0);
world.run_system_once(spawn_entity).unwrap();
assert_eq!(world.entities.len(), 1);
assert_eq!(world.entities.count_active(), 1);
}
#[test]

View File

@ -657,9 +657,9 @@ mod tests {
let exclusive_system_id = world.register_system(|world: &mut World| {
world.spawn_empty();
});
let entity_count = world.entities.len();
let entity_count = world.entities.count_active();
let _ = world.run_system(exclusive_system_id);
assert_eq!(world.entities.len(), entity_count + 1);
assert_eq!(world.entities.count_active(), entity_count + 1);
}
#[test]

View File

@ -420,12 +420,12 @@ mod test {
let mut world = World::new();
queue.apply(&mut world);
assert_eq!(world.entities().len(), 2);
assert_eq!(world.entities().count_active(), 2);
// The previous call to `apply` cleared the queue.
// This call should do nothing.
queue.apply(&mut world);
assert_eq!(world.entities().len(), 2);
assert_eq!(world.entities().count_active(), 2);
}
#[expect(
@ -459,7 +459,7 @@ mod test {
queue.push(SpawnCommand);
queue.push(SpawnCommand);
queue.apply(&mut world);
assert_eq!(world.entities().len(), 3);
assert_eq!(world.entities().count_active(), 3);
}
#[test]

View File

@ -5818,7 +5818,6 @@ mod tests {
);
world.commands().queue(count_flush);
let entity = world.spawn_empty().id();
assert_eq!(world.resource::<TestFlush>().0, 1);
world.commands().queue(count_flush);
let mut a = world.entity_mut(entity);
a.trigger(TestEvent);

View File

@ -3645,7 +3645,7 @@ impl fmt::Debug for World {
// Accessing any data stored in the world would be unsound.
f.debug_struct("World")
.field("id", &self.id)
.field("entity_count", &self.entities.len())
.field("entity_count", &self.entities.count_active())
.field("archetype_count", &self.archetypes.len())
.field("component_count", &self.components.len())
.field("resource_count", &self.storages.resources.len())
@ -4349,6 +4349,7 @@ mod tests {
.is_ok());
world.entity_mut(e1).despawn();
assert!(world.get_entity_mut(e2).is_ok());
assert!(matches!(
world.get_entity_mut(e1).map(|_| {}),