[Fixes #6059] `Entity`'s “ID” should be named “index” instead (#6107)

# Objective

Fixes #6059, changing all incorrect occurrences of ``id`` in the ``entity`` module to ``index``:

* struct level documentation,
* ``id`` struct field,
* ``id`` method and its documentation.

## Solution

Renaming and verifying using CI. 


Co-authored-by: Edvin Kjell <43633999+Edwox@users.noreply.github.com>
This commit is contained in:
Edvin Kjell 2022-11-02 15:19:50 +00:00
parent ed3ecda91d
commit a8a62fcf3d
9 changed files with 133 additions and 118 deletions

View file

@ -543,10 +543,10 @@ impl<'a, 'b> BundleInserter<'a, 'b> {
InsertBundleResult::NewArchetypeSameTable { new_archetype } => {
let result = self.archetype.swap_remove(location.index);
if let Some(swapped_entity) = result.swapped_entity {
self.entities.meta[swapped_entity.id as usize].location = location;
self.entities.meta[swapped_entity.index as usize].location = location;
}
let new_location = new_archetype.allocate(entity, result.table_row);
self.entities.meta[entity.id as usize].location = new_location;
self.entities.meta[entity.index as usize].location = new_location;
// PERF: this could be looked up during Inserter construction and stored (but borrowing makes this nasty)
let add_bundle = self
@ -571,7 +571,7 @@ impl<'a, 'b> BundleInserter<'a, 'b> {
} => {
let result = self.archetype.swap_remove(location.index);
if let Some(swapped_entity) = result.swapped_entity {
self.entities.meta[swapped_entity.id as usize].location = location;
self.entities.meta[swapped_entity.index as usize].location = location;
}
// PERF: store "non bundle" components in edge, then just move those to avoid
// redundant copies
@ -579,7 +579,7 @@ impl<'a, 'b> BundleInserter<'a, 'b> {
.table
.move_to_superset_unchecked(result.table_row, new_table);
let new_location = new_archetype.allocate(entity, move_result.new_row);
self.entities.meta[entity.id as usize].location = new_location;
self.entities.meta[entity.index as usize].location = new_location;
// if an entity was moved into this entity's table spot, update its table row
if let Some(swapped_entity) = move_result.swapped_entity {
@ -655,7 +655,7 @@ impl<'a, 'b> BundleSpawner<'a, 'b> {
self.change_tick,
bundle,
);
self.entities.meta[entity.id as usize].location = location;
self.entities.meta[entity.index as usize].location = location;
location
}

View file

@ -53,7 +53,7 @@ type IdCursor = isize;
/// Lightweight identifier of an [entity](crate::entity).
///
/// The identifier is implemented using a [generational index]: a combination of an ID and a generation.
/// The identifier is implemented using a [generational index]: a combination of an index and a generation.
/// This allows fast insertion after data removal in an array while minimizing loss of spatial locality.
///
/// [generational index]: https://lucassardois.medium.com/generational-indices-guide-8e3c5f7fd594
@ -106,7 +106,7 @@ type IdCursor = isize;
#[derive(Clone, Copy, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Entity {
pub(crate) generation: u32,
pub(crate) id: u32,
pub(crate) index: u32,
}
pub enum AllocAtWithoutReplacement {
@ -116,14 +116,14 @@ pub enum AllocAtWithoutReplacement {
}
impl Entity {
/// Creates a new entity reference with the specified `id` and a generation of 0.
/// Creates a new entity reference with the specified `index` and a generation of 0.
///
/// # Note
///
/// Spawning a specific `entity` value is __rarely the right choice__. Most apps should favor
/// [`Commands::spawn`](crate::system::Commands::spawn). This method should generally
/// only be used for sharing entities across apps, and only when they have a scheme
/// worked out to share an ID space (which doesn't happen by default).
/// worked out to share an index space (which doesn't happen by default).
///
/// In general, one should not try to synchronize the ECS by attempting to ensure that
/// `Entity` lines up between instances, but instead insert a secondary identifier as
@ -163,8 +163,11 @@ impl Entity {
/// }
/// }
/// ```
pub const fn from_raw(id: u32) -> Entity {
Entity { id, generation: 0 }
pub const fn from_raw(index: u32) -> Entity {
Entity {
index,
generation: 0,
}
}
/// Convert to a form convenient for passing outside of rust.
@ -174,7 +177,7 @@ impl Entity {
///
/// No particular structure is guaranteed for the returned bits.
pub fn to_bits(self) -> u64 {
u64::from(self.generation) << 32 | u64::from(self.id)
u64::from(self.generation) << 32 | u64::from(self.index)
}
/// Reconstruct an `Entity` previously destructured with [`Entity::to_bits`].
@ -183,23 +186,23 @@ impl Entity {
pub const fn from_bits(bits: u64) -> Self {
Self {
generation: (bits >> 32) as u32,
id: bits as u32,
index: bits as u32,
}
}
/// Return a transiently unique identifier.
///
/// No two simultaneously-live entities share the same ID, but dead entities' IDs may collide
/// No two simultaneously-live entities share the same index, but dead entities' indices may collide
/// with both live and dead entities. Useful for compactly representing entities within a
/// specific snapshot of the world, such as when serializing.
#[inline]
pub const fn id(self) -> u32 {
self.id
pub const fn index(self) -> u32 {
self.index
}
/// Returns the generation of this Entity's id. The generation is incremented each time an
/// entity with a given id is despawned. This serves as a "count" of the number of times a
/// given id has been reused (id, generation) pairs uniquely identify a given Entity.
/// Returns the generation of this Entity's index. The generation is incremented each time an
/// entity with a given index is despawned. This serves as a "count" of the number of times a
/// given index has been reused (index, generation) pairs uniquely identify a given Entity.
#[inline]
pub const fn generation(self) -> u32 {
self.generation
@ -208,13 +211,13 @@ impl Entity {
impl fmt::Debug for Entity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}v{}", self.id, self.generation)
write!(f, "{}v{}", self.index, self.generation)
}
}
impl SparseSetIndex for Entity {
fn sparse_set_index(&self) -> usize {
self.id() as usize
self.index() as usize
}
fn get_sparse_set_index(value: usize) -> Self {
@ -228,28 +231,33 @@ pub struct ReserveEntitiesIterator<'a> {
// Metas, so we can recover the current generation for anything in the freelist.
meta: &'a [EntityMeta],
// Reserved IDs formerly in the freelist to hand out.
id_iter: std::slice::Iter<'a, u32>,
// Reserved indices formerly in the freelist to hand out.
index_iter: std::slice::Iter<'a, u32>,
// New Entity IDs to hand out, outside the range of meta.len().
id_range: std::ops::Range<u32>,
// New Entity indices to hand out, outside the range of meta.len().
index_range: std::ops::Range<u32>,
}
impl<'a> Iterator for ReserveEntitiesIterator<'a> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.id_iter
self.index_iter
.next()
.map(|&id| Entity {
generation: self.meta[id as usize].generation,
id,
.map(|&index| Entity {
generation: self.meta[index as usize].generation,
index,
})
.or_else(|| {
self.index_range.next().map(|index| Entity {
generation: 0,
index,
})
})
.or_else(|| self.id_range.next().map(|id| Entity { generation: 0, id }))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.id_iter.len() + self.id_range.len();
let len = self.index_iter.len() + self.index_range.len();
(len, Some(len))
}
}
@ -344,8 +352,8 @@ impl Entities {
ReserveEntitiesIterator {
meta: &self.meta[..],
id_iter: self.pending[freelist_range].iter(),
id_range: new_id_start..new_id_end,
index_iter: self.pending[freelist_range].iter(),
index_range: new_id_start..new_id_end,
}
}
@ -356,10 +364,10 @@ impl Entities {
let n = self.free_cursor.fetch_sub(1, Ordering::Relaxed);
if n > 0 {
// Allocate from the freelist.
let id = self.pending[(n - 1) as usize];
let index = self.pending[(n - 1) as usize];
Entity {
generation: self.meta[id as usize].generation,
id,
generation: self.meta[index as usize].generation,
index,
}
} else {
// Grab a new ID, outside the range of `meta.len()`. `flush()` must
@ -369,7 +377,7 @@ impl Entities {
// and farther beyond `meta.len()`.
Entity {
generation: 0,
id: u32::try_from(self.meta.len() as IdCursor - n).expect("too many entities"),
index: u32::try_from(self.meta.len() as IdCursor - n).expect("too many entities"),
}
}
}
@ -386,17 +394,20 @@ impl Entities {
pub fn alloc(&mut self) -> Entity {
self.verify_flushed();
self.len += 1;
if let Some(id) = self.pending.pop() {
if let Some(index) = self.pending.pop() {
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
Entity {
generation: self.meta[id as usize].generation,
id,
generation: self.meta[index as usize].generation,
index,
}
} else {
let id = u32::try_from(self.meta.len()).expect("too many entities");
let index = u32::try_from(self.meta.len()).expect("too many entities");
self.meta.push(EntityMeta::EMPTY);
Entity { generation: 0, id }
Entity {
generation: 0,
index,
}
}
}
@ -407,14 +418,15 @@ impl Entities {
pub fn alloc_at(&mut self, entity: Entity) -> Option<EntityLocation> {
self.verify_flushed();
let loc = if entity.id as usize >= self.meta.len() {
self.pending.extend((self.meta.len() as u32)..entity.id);
let loc = if entity.index as usize >= self.meta.len() {
self.pending.extend((self.meta.len() as u32)..entity.index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.meta.resize(entity.id as usize + 1, EntityMeta::EMPTY);
self.meta
.resize(entity.index as usize + 1, EntityMeta::EMPTY);
self.len += 1;
None
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.id) {
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.index) {
self.pending.swap_remove(index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
@ -422,12 +434,12 @@ impl Entities {
None
} else {
Some(mem::replace(
&mut self.meta[entity.id as usize].location,
&mut self.meta[entity.index as usize].location,
EntityMeta::EMPTY.location,
))
};
self.meta[entity.id as usize].generation = entity.generation;
self.meta[entity.index as usize].generation = entity.generation;
loc
}
@ -438,21 +450,22 @@ impl Entities {
pub fn alloc_at_without_replacement(&mut self, entity: Entity) -> AllocAtWithoutReplacement {
self.verify_flushed();
let result = if entity.id as usize >= self.meta.len() {
self.pending.extend((self.meta.len() as u32)..entity.id);
let result = if entity.index as usize >= self.meta.len() {
self.pending.extend((self.meta.len() as u32)..entity.index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.meta.resize(entity.id as usize + 1, EntityMeta::EMPTY);
self.meta
.resize(entity.index as usize + 1, EntityMeta::EMPTY);
self.len += 1;
AllocAtWithoutReplacement::DidNotExist
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.id) {
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.index) {
self.pending.swap_remove(index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len += 1;
AllocAtWithoutReplacement::DidNotExist
} else {
let current_meta = &mut self.meta[entity.id as usize];
let current_meta = &mut self.meta[entity.index as usize];
if current_meta.location.archetype_id == ArchetypeId::INVALID {
AllocAtWithoutReplacement::DidNotExist
} else if current_meta.generation == entity.generation {
@ -462,7 +475,7 @@ impl Entities {
}
};
self.meta[entity.id as usize].generation = entity.generation;
self.meta[entity.index as usize].generation = entity.generation;
result
}
@ -472,7 +485,7 @@ impl Entities {
pub fn free(&mut self, entity: Entity) -> Option<EntityLocation> {
self.verify_flushed();
let meta = &mut self.meta[entity.id as usize];
let meta = &mut self.meta[entity.index as usize];
if meta.generation != entity.generation {
return None;
}
@ -480,7 +493,7 @@ impl Entities {
let loc = mem::replace(&mut meta.location, EntityMeta::EMPTY.location);
self.pending.push(entity.id);
self.pending.push(entity.index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
@ -505,7 +518,7 @@ impl Entities {
// This will return false for entities which have been freed, even if
// not reallocated since the generation is incremented in `free`
pub fn contains(&self, entity: Entity) -> bool {
self.resolve_from_id(entity.id())
self.resolve_from_id(entity.index())
.map_or(false, |e| e.generation() == entity.generation)
}
@ -518,8 +531,8 @@ impl Entities {
/// Returns `Ok(Location { archetype: Archetype::invalid(), index: undefined })` for pending entities.
pub fn get(&self, entity: Entity) -> Option<EntityLocation> {
if (entity.id as usize) < self.meta.len() {
let meta = &self.meta[entity.id as usize];
if (entity.index as usize) < self.meta.len() {
let meta = &self.meta[entity.index as usize];
if meta.generation != entity.generation
|| meta.location.archetype_id == ArchetypeId::INVALID
{
@ -537,17 +550,20 @@ impl Entities {
/// Note: This method may return [`Entities`](Entity) which are currently free
/// Note that [`contains`](Entities::contains) will correctly return false for freed
/// entities, since it checks the generation
pub fn resolve_from_id(&self, id: u32) -> Option<Entity> {
let idu = id as usize;
pub fn resolve_from_id(&self, index: u32) -> Option<Entity> {
let idu = index as usize;
if let Some(&EntityMeta { generation, .. }) = self.meta.get(idu) {
Some(Entity { generation, id })
Some(Entity { generation, index })
} else {
// `id` is outside of the meta list - check whether it is reserved but not yet flushed.
let free_cursor = self.free_cursor.load(Ordering::Relaxed);
// If this entity was manually created, then free_cursor might be positive
// Returning None handles that case correctly
let num_pending = usize::try_from(-free_cursor).ok()?;
(idu < self.meta.len() + num_pending).then_some(Entity { generation: 0, id })
(idu < self.meta.len() + num_pending).then_some(Entity {
generation: 0,
index,
})
}
}
@ -576,10 +592,10 @@ impl Entities {
let new_meta_len = old_meta_len + -current_free_cursor as usize;
self.meta.resize(new_meta_len, EntityMeta::EMPTY);
self.len += -current_free_cursor as u32;
for (id, meta) in self.meta.iter_mut().enumerate().skip(old_meta_len) {
for (index, meta) in self.meta.iter_mut().enumerate().skip(old_meta_len) {
init(
Entity {
id: id as u32,
index: index as u32,
generation: meta.generation,
},
&mut meta.location,
@ -591,11 +607,11 @@ impl Entities {
};
self.len += (self.pending.len() - new_free_cursor) as u32;
for id in self.pending.drain(new_free_cursor..) {
let meta = &mut self.meta[id as usize];
for index in self.pending.drain(new_free_cursor..) {
let meta = &mut self.meta[index as usize];
init(
Entity {
id,
index,
generation: meta.generation,
},
&mut meta.location,
@ -684,7 +700,7 @@ mod tests {
fn entity_bits_roundtrip() {
let e = Entity {
generation: 0xDEADBEEF,
id: 0xBAADF00D,
index: 0xBAADF00D,
};
assert_eq!(Entity::from_bits(e.to_bits()), e);
}
@ -719,14 +735,14 @@ mod tests {
#[test]
fn entity_const() {
const C1: Entity = Entity::from_raw(42);
assert_eq!(42, C1.id);
assert_eq!(42, C1.index);
assert_eq!(0, C1.generation);
const C2: Entity = Entity::from_bits(0x0000_00ff_0000_00cc);
assert_eq!(0x0000_00cc, C2.id);
assert_eq!(0x0000_00cc, C2.index);
assert_eq!(0x0000_00ff, C2.generation);
const C3: u32 = Entity::from_raw(33).id();
const C3: u32 = Entity::from_raw(33).index();
assert_eq!(33, C3);
const C4: u32 = Entity::from_bits(0x00dd_00ff_0000_0000).generation();

View file

@ -1453,7 +1453,7 @@ mod tests {
e4,
Entity {
generation: 0,
id: 3,
index: 3,
},
"new entity is created immediately after world_a's max entity"
);
@ -1487,7 +1487,7 @@ mod tests {
let e4_mismatched_generation = Entity {
generation: 1,
id: 3,
index: 3,
};
assert!(
world_b.get_or_spawn(e4_mismatched_generation).is_none(),
@ -1506,7 +1506,7 @@ mod tests {
let high_non_existent_entity = Entity {
generation: 0,
id: 6,
index: 6,
};
world_b
.get_or_spawn(high_non_existent_entity)
@ -1520,7 +1520,7 @@ mod tests {
let high_non_existent_but_reserved_entity = Entity {
generation: 0,
id: 5,
index: 5,
};
assert!(
world_b.get_entity(high_non_existent_but_reserved_entity).is_none(),
@ -1539,19 +1539,19 @@ mod tests {
vec![
Entity {
generation: 0,
id: 5
index: 5
},
Entity {
generation: 0,
id: 4
index: 4
},
Entity {
generation: 0,
id: 7,
index: 7,
},
Entity {
generation: 0,
id: 8,
index: 8,
},
],
"space between original entities and high entities is used for new entity ids"
@ -1603,7 +1603,7 @@ mod tests {
let e2 = world.spawn_empty().id();
let invalid_e2 = Entity {
generation: 1,
id: e2.id,
index: e2.index,
};
let values = vec![(e0, (B(0), C)), (e1, (B(1), C)), (invalid_e2, (B(2), C))];

View file

@ -120,18 +120,18 @@ impl ComponentSparseSet {
/// The `value` pointer must point to a valid address that matches the [`Layout`](std::alloc::Layout)
/// inside the [`ComponentInfo`] given when constructing this sparse set.
pub(crate) unsafe fn insert(&mut self, entity: Entity, value: OwningPtr<'_>, change_tick: u32) {
if let Some(&dense_index) = self.sparse.get(entity.id()) {
if let Some(&dense_index) = self.sparse.get(entity.index()) {
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index as usize]);
self.dense.replace(dense_index as usize, value, change_tick);
} else {
let dense_index = self.dense.len();
self.dense.push(value, ComponentTicks::new(change_tick));
self.sparse.insert(entity.id(), dense_index as u32);
self.sparse.insert(entity.index(), dense_index as u32);
#[cfg(debug_assertions)]
assert_eq!(self.entities.len(), dense_index);
#[cfg(not(debug_assertions))]
self.entities.push(entity.id());
self.entities.push(entity.index());
#[cfg(debug_assertions)]
self.entities.push(entity);
}
@ -141,7 +141,7 @@ impl ComponentSparseSet {
pub fn contains(&self, entity: Entity) -> bool {
#[cfg(debug_assertions)]
{
if let Some(&dense_index) = self.sparse.get(entity.id()) {
if let Some(&dense_index) = self.sparse.get(entity.index()) {
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index as usize]);
true
@ -150,12 +150,12 @@ impl ComponentSparseSet {
}
}
#[cfg(not(debug_assertions))]
self.sparse.contains(entity.id())
self.sparse.contains(entity.index())
}
#[inline]
pub fn get(&self, entity: Entity) -> Option<Ptr<'_>> {
self.sparse.get(entity.id()).map(|dense_index| {
self.sparse.get(entity.index()).map(|dense_index| {
let dense_index = *dense_index as usize;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index]);
@ -166,7 +166,7 @@ impl ComponentSparseSet {
#[inline]
pub fn get_with_ticks(&self, entity: Entity) -> Option<(Ptr<'_>, &UnsafeCell<ComponentTicks>)> {
let dense_index = *self.sparse.get(entity.id())? as usize;
let dense_index = *self.sparse.get(entity.index())? as usize;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index]);
// SAFETY: if the sparse index points to something in the dense vec, it exists
@ -180,7 +180,7 @@ impl ComponentSparseSet {
#[inline]
pub fn get_ticks(&self, entity: Entity) -> Option<&UnsafeCell<ComponentTicks>> {
let dense_index = *self.sparse.get(entity.id())? as usize;
let dense_index = *self.sparse.get(entity.index())? as usize;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index]);
// SAFETY: if the sparse index points to something in the dense vec, it exists
@ -191,7 +191,7 @@ impl ComponentSparseSet {
/// it exists).
#[must_use = "The returned pointer must be used to drop the removed component."]
pub(crate) fn remove_and_forget(&mut self, entity: Entity) -> Option<OwningPtr<'_>> {
self.sparse.remove(entity.id()).map(|dense_index| {
self.sparse.remove(entity.index()).map(|dense_index| {
let dense_index = dense_index as usize;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index]);
@ -202,17 +202,17 @@ impl ComponentSparseSet {
if !is_last {
let swapped_entity = self.entities[dense_index];
#[cfg(not(debug_assertions))]
let idx = swapped_entity;
let index = swapped_entity;
#[cfg(debug_assertions)]
let idx = swapped_entity.id();
*self.sparse.get_mut(idx).unwrap() = dense_index as u32;
let index = swapped_entity.index();
*self.sparse.get_mut(index).unwrap() = dense_index as u32;
}
value
})
}
pub(crate) fn remove(&mut self, entity: Entity) -> bool {
if let Some(dense_index) = self.sparse.remove(entity.id()) {
if let Some(dense_index) = self.sparse.remove(entity.index()) {
let dense_index = dense_index as usize;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index]);
@ -223,10 +223,10 @@ impl ComponentSparseSet {
if !is_last {
let swapped_entity = self.entities[dense_index];
#[cfg(not(debug_assertions))]
let idx = swapped_entity;
let index = swapped_entity;
#[cfg(debug_assertions)]
let idx = swapped_entity.id();
*self.sparse.get_mut(idx).unwrap() = dense_index as u32;
let index = swapped_entity.index();
*self.sparse.get_mut(index).unwrap() = dense_index as u32;
}
true
} else {

View file

@ -369,7 +369,7 @@ impl<'w> EntityMut<'w> {
let old_archetype = &mut archetypes[old_archetype_id];
let remove_result = old_archetype.swap_remove(old_location.index);
if let Some(swapped_entity) = remove_result.swapped_entity {
entities.meta[swapped_entity.id as usize].location = old_location;
entities.meta[swapped_entity.index as usize].location = old_location;
}
let old_table_row = remove_result.table_row;
let old_table_id = old_archetype.table_id();
@ -403,7 +403,7 @@ impl<'w> EntityMut<'w> {
};
*self_location = new_location;
entities.meta[entity.id as usize].location = new_location;
entities.meta[entity.index as usize].location = new_location;
}
#[deprecated(
@ -498,7 +498,7 @@ impl<'w> EntityMut<'w> {
}
let remove_result = archetype.swap_remove(location.index);
if let Some(swapped_entity) = remove_result.swapped_entity {
world.entities.meta[swapped_entity.id as usize].location = location;
world.entities.meta[swapped_entity.index as usize].location = location;
}
table_row = remove_result.table_row;

View file

@ -483,7 +483,7 @@ impl World {
// SAFETY: entity index was just allocated
self.entities
.meta
.get_unchecked_mut(entity.id() as usize)
.get_unchecked_mut(entity.index() as usize)
.location = location;
EntityMut::new(self, entity, location)
}

View file

@ -8,7 +8,7 @@ use std::collections::BTreeMap;
///
/// # Entity Order
///
/// Extracted entities will always be stored in ascending order based on their [id](Entity::id).
/// Extracted entities will always be stored in ascending order based on their [id](Entity::index).
/// This means that inserting `Entity(1v0)` then `Entity(0v0)` will always result in the entities
/// being ordered as `[Entity(0v0), Entity(1v0)]`.
///
@ -100,14 +100,14 @@ impl<'w> DynamicSceneBuilder<'w> {
let type_registry = self.type_registry.read();
for entity in entities {
let id = entity.id();
let index = entity.index();
if self.entities.contains_key(&id) {
if self.entities.contains_key(&index) {
continue;
}
let mut entry = DynamicEntity {
entity: id,
entity: index,
components: Vec::new(),
};
@ -125,8 +125,7 @@ impl<'w> DynamicSceneBuilder<'w> {
}
}
}
self.entities.insert(id, entry);
self.entities.insert(index, entry);
}
drop(type_registry);
@ -167,7 +166,7 @@ mod tests {
let scene = builder.build();
assert_eq!(scene.entities.len(), 1);
assert_eq!(scene.entities[0].entity, entity.id());
assert_eq!(scene.entities[0].entity, entity.index());
assert_eq!(scene.entities[0].components.len(), 1);
assert!(scene.entities[0].components[0].represents::<ComponentA>());
}
@ -188,7 +187,7 @@ mod tests {
let scene = builder.build();
assert_eq!(scene.entities.len(), 1);
assert_eq!(scene.entities[0].entity, entity.id());
assert_eq!(scene.entities[0].entity, entity.index());
assert_eq!(scene.entities[0].components.len(), 1);
assert!(scene.entities[0].components[0].represents::<ComponentA>());
}
@ -212,7 +211,7 @@ mod tests {
let scene = builder.build();
assert_eq!(scene.entities.len(), 1);
assert_eq!(scene.entities[0].entity, entity.id());
assert_eq!(scene.entities[0].entity, entity.index());
assert_eq!(scene.entities[0].components.len(), 2);
assert!(scene.entities[0].components[0].represents::<ComponentA>());
assert!(scene.entities[0].components[1].represents::<ComponentB>());
@ -239,10 +238,10 @@ mod tests {
let mut entities = builder.build().entities.into_iter();
// Assert entities are ordered
assert_eq!(entity_a.id(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_b.id(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_c.id(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_d.id(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_a.index(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_b.index(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_c.index(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_d.index(), entities.next().map(|e| e.entity).unwrap());
}
#[test]
@ -269,6 +268,6 @@ mod tests {
assert_eq!(scene.entities.len(), 2);
let mut scene_entities = vec![scene.entities[0].entity, scene.entities[1].entity];
scene_entities.sort();
assert_eq!(scene_entities, [entity_a_b.id(), entity_a.id()]);
assert_eq!(scene_entities, [entity_a_b.index(), entity_a.index()]);
}
}

View file

@ -525,7 +525,7 @@ pub fn queue_sprites(
);
view_entities.clear();
view_entities.extend(visible_entities.entities.iter().map(|e| e.id() as usize));
view_entities.extend(visible_entities.entities.iter().map(|e| e.index() as usize));
transparent_phase.items.reserve(extracted_sprites.len());
// Impossible starting values that will be replaced on the first iteration
@ -541,7 +541,7 @@ pub fn queue_sprites(
// Batches are merged later (in `batch_phase_system()`), so that they can be interrupted
// by any other phase item (and they can interrupt other items from batching).
for extracted_sprite in extracted_sprites.iter() {
if !view_entities.contains(extracted_sprite.entity.id() as usize) {
if !view_entities.contains(extracted_sprite.entity.index() as usize) {
continue;
}
let new_batch = SpriteBatch {

View file

@ -76,7 +76,7 @@ fn load_scene_system(mut commands: Commands, asset_server: Res<AssetServer>) {
// load_scene_example.scn. You should immediately see the changes appear in the console.
fn log_system(query: Query<(Entity, &ComponentA), Changed<ComponentA>>) {
for (entity, component_a) in &query {
info!(" Entity({})", entity.id());
info!(" Entity({})", entity.index());
info!(
" ComponentA: {{ x: {} y: {} }}\n",
component_a.x, component_a.y