More improved entity comments
This commit is contained in:
parent
9d86e69ce2
commit
d86d241f68
@ -378,29 +378,10 @@ impl EntityGeneration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lightweight identifier of an [entity](crate::entity).
|
/// This uniquely identifies an entity in a [`World`].
|
||||||
///
|
/// Note that this is just an id, not the entity itself.
|
||||||
/// The identifier is implemented using a [generational index]: a combination of an index ([`EntityRow`]) and a generation ([`EntityGeneration`]).
|
/// Further, the entity this id refers to may no longer exist in the [`World`].
|
||||||
/// This allows fast insertion after data removal in an array while minimizing loss of spatial locality.
|
/// For more information about entities, their ids, and how to use them, see the module docs.
|
||||||
///
|
|
||||||
/// These identifiers are only valid on the [`World`] it's sourced from. Attempting to use an `Entity` to
|
|
||||||
/// fetch entity components or metadata from a different world will either fail or return unexpected results.
|
|
||||||
///
|
|
||||||
/// [generational index]: https://lucassardois.medium.com/generational-indices-guide-8e3c5f7fd594
|
|
||||||
///
|
|
||||||
/// # Entity ids
|
|
||||||
///
|
|
||||||
/// It is important to keep in mind that an [`Entity`] is just an id for a conceptual entity.
|
|
||||||
/// Conceptual entities are just a collection of zero or more components,
|
|
||||||
/// but [`Entity`] ids may or may not correspond to a conceptual entity.
|
|
||||||
///
|
|
||||||
/// Each [`EntityRow`] corresponds to a potential conceptual entity.
|
|
||||||
/// This can happen if, for example, the row has not been allocated, or it has been allocated and has not been [`constructed`](crate::world::World::construct), or it has been since [destructed](crate::world::World::destruct).
|
|
||||||
/// Entity rows may also be pending reuse, etc.
|
|
||||||
///
|
|
||||||
/// For a [`Entity`] id to correspond to a conceptual entity, its row must do so, and it must have the most up to date generation of that row.
|
|
||||||
/// This can be un-intuitive sometimes, because an allocated [`Entity`] id that is perfectly correct but not constructed yet, still does not correspond to a conceptual entity.
|
|
||||||
/// This is why spawning an entity from commands will provide an [`Entity`] that, technically, does not exist yet; it's just that it is *queued* to exist soon.
|
|
||||||
///
|
///
|
||||||
/// # Aliasing
|
/// # Aliasing
|
||||||
///
|
///
|
||||||
@ -783,13 +764,23 @@ impl SparseSetIndex for Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates [`Entity`] ids uniquely.
|
/// Allocates [`Entity`] ids uniquely.
|
||||||
|
/// This is used in [`World::construct`](crate::world::World::construct) and [`World::despawn`](crate::world::World::despawn) to track entity ids no longer in use.
|
||||||
|
/// Allocating is fully concurrent and can be done from multiple threads.
|
||||||
|
///
|
||||||
|
/// Conceptually, this is a collection of [`Entity`] ids who's [`EntityRow`] is destructed and who's [`EntityGeneration`] is the most recent.
|
||||||
|
/// See the module docs for how these ids and this allocator participate in the life cycle of an entity.
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct EntitiesAllocator {
|
pub struct EntitiesAllocator {
|
||||||
|
/// All the entities to reuse.
|
||||||
|
/// This is a buffer, which contains an array of [`Entity`] ids to hand out.
|
||||||
|
/// The next id to hand out is tracked by `free_len`.
|
||||||
free: Vec<Entity>,
|
free: Vec<Entity>,
|
||||||
/// This is continually subtracted from.
|
/// This is continually subtracted from.
|
||||||
/// If it wraps to a very large number, it will be outside the bounds of `free`,
|
/// If it wraps to a very large number, it will be outside the bounds of `free`,
|
||||||
/// and a new row will be needed.
|
/// and a new row will be needed.
|
||||||
free_len: AtomicU32,
|
free_len: AtomicU32,
|
||||||
|
/// This is the next "fresh" row to hand out.
|
||||||
|
/// If there are no rows to reuse, this row, which has a generation of 0, is the next to return.
|
||||||
next_row: AtomicU32,
|
next_row: AtomicU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,6 +889,8 @@ impl Entities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [`EntityLocation`] of an [`Entity`] if it exists and is constructed.
|
/// Returns the [`EntityLocation`] of an [`Entity`] if it exists and is constructed.
|
||||||
|
/// This can error if the [`EntityGeneration`] of this id has passed or if the [`EntityRow`] is not constructed.
|
||||||
|
/// See the module docs for a full explanation of these ids, entity life cycles, and the meaning of this result.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_constructed(
|
pub fn get_constructed(
|
||||||
&self,
|
&self,
|
||||||
@ -945,6 +938,8 @@ impl Entities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [`EntityIdLocation`] of an [`Entity`] if it exists.
|
/// Returns the [`EntityIdLocation`] of an [`Entity`] if it exists.
|
||||||
|
/// This can fail if the id's [`EntityGeneration`] has passed.
|
||||||
|
/// See the module docs for a full explanation of these ids, entity life cycles, and the meaning of this result.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, entity: Entity) -> Result<EntityIdLocation, EntityDoesNotExistError> {
|
pub fn get(&self, entity: Entity) -> Result<EntityIdLocation, EntityDoesNotExistError> {
|
||||||
match self.meta.get(entity.index() as usize) {
|
match self.meta.get(entity.index() as usize) {
|
||||||
@ -973,6 +968,7 @@ impl Entities {
|
|||||||
|
|
||||||
/// Get the [`Entity`] for the given [`EntityRow`].
|
/// Get the [`Entity`] for the given [`EntityRow`].
|
||||||
/// Note that this entity may not be constructed yet.
|
/// Note that this entity may not be constructed yet.
|
||||||
|
/// See the module docs for a full explanation of these ids, entity life cycles, and what it means for a row to be constructed or not.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn resolve_from_row(&self, row: EntityRow) -> Entity {
|
pub fn resolve_from_row(&self, row: EntityRow) -> Entity {
|
||||||
self.meta
|
self.meta
|
||||||
@ -982,6 +978,7 @@ impl Entities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the entity at this `row` is constructed or not.
|
/// Returns whether the entity at this `row` is constructed or not.
|
||||||
|
/// See the module docs for what it means for a row to be constructed or not.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_row_constructed(&self, row: EntityRow) -> bool {
|
pub fn is_row_constructed(&self, row: EntityRow) -> bool {
|
||||||
self.meta
|
self.meta
|
||||||
@ -992,16 +989,20 @@ impl Entities {
|
|||||||
|
|
||||||
/// Returns true if the entity exists.
|
/// Returns true if the entity exists.
|
||||||
/// This will return true for entities that exist but have not been constructed.
|
/// This will return true for entities that exist but have not been constructed.
|
||||||
|
/// See the module docs for a more precise explanation of which entities exist and what construction means.
|
||||||
pub fn contains(&self, entity: Entity) -> bool {
|
pub fn contains(&self, entity: Entity) -> bool {
|
||||||
self.resolve_from_row(entity.row()).generation() == entity.generation()
|
self.resolve_from_row(entity.row()).generation() == entity.generation()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the entity exists and are constructed.
|
/// Returns true if the entity exists and are constructed.
|
||||||
|
/// See the module docs for a more precise explanation of which entities exist and what construction means.
|
||||||
pub fn contains_constructed(&self, entity: Entity) -> bool {
|
pub fn contains_constructed(&self, entity: Entity) -> bool {
|
||||||
self.get_constructed(entity).is_ok()
|
self.get_constructed(entity).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides information regarding if `entity` may be constructed.
|
/// Provides information regarding if `entity` may be safely constructed.
|
||||||
|
/// This can error if the entity does not exist or if it is already constructed.
|
||||||
|
/// See the module docs for a more precise explanation of which entities exist and what construction means.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn validate_construction(&self, entity: Entity) -> Result<(), ConstructionError> {
|
pub fn validate_construction(&self, entity: Entity) -> Result<(), ConstructionError> {
|
||||||
match self.get(entity) {
|
match self.get(entity) {
|
||||||
@ -1043,14 +1044,14 @@ impl Entities {
|
|||||||
row: EntityRow,
|
row: EntityRow,
|
||||||
location: EntityIdLocation,
|
location: EntityIdLocation,
|
||||||
) -> EntityIdLocation {
|
) -> EntityIdLocation {
|
||||||
self.ensure_row(row);
|
self.ensure_row_index_is_valid(row);
|
||||||
// SAFETY: We just did `ensure_row`
|
// SAFETY: We just did `ensure_row`
|
||||||
self.update(row, location)
|
self.update(row, location)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures row is valid.
|
/// Ensures row is valid as an index in [`Self::meta`].
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ensure_row(&mut self, row: EntityRow) {
|
fn ensure_row_index_is_valid(&mut self, row: EntityRow) {
|
||||||
#[cold] // to help with branch prediction
|
#[cold] // to help with branch prediction
|
||||||
fn expand(meta: &mut Vec<EntityMeta>, len: usize) {
|
fn expand(meta: &mut Vec<EntityMeta>, len: usize) {
|
||||||
meta.resize(len, EntityMeta::FRESH);
|
meta.resize(len, EntityMeta::FRESH);
|
||||||
@ -1072,7 +1073,7 @@ impl Entities {
|
|||||||
/// - `row` must be destructed (have no location) already.
|
/// - `row` must be destructed (have no location) already.
|
||||||
pub(crate) unsafe fn mark_free(&mut self, row: EntityRow, generations: u32) -> Entity {
|
pub(crate) unsafe fn mark_free(&mut self, row: EntityRow, generations: u32) -> Entity {
|
||||||
// We need to do this in case an entity is being freed that was never constructed.
|
// We need to do this in case an entity is being freed that was never constructed.
|
||||||
self.ensure_row(row);
|
self.ensure_row_index_is_valid(row);
|
||||||
// SAFETY: We just did `ensure_row`
|
// SAFETY: We just did `ensure_row`
|
||||||
let meta = unsafe { self.meta.get_unchecked_mut(row.index() as usize) };
|
let meta = unsafe { self.meta.get_unchecked_mut(row.index() as usize) };
|
||||||
|
|
||||||
@ -1161,18 +1162,21 @@ impl Entities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The count of currently allocated entity rows.
|
/// The count of currently allocated entity rows.
|
||||||
|
/// For information on active entities, see [`Self::count_constructed`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn len(&self) -> u32 {
|
pub fn len(&self) -> u32 {
|
||||||
self.meta.len() as u32
|
self.meta.len() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if any entity has been declared
|
/// Checks if any entity has been declared.
|
||||||
|
/// For information on active entities, see [`Self::any_constructed`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Counts the number of entities currently constructed, those that have locations.
|
/// Counts the number of entity rows currently constructed.
|
||||||
|
/// See the module docs for a more precise explanation of what construction means.
|
||||||
pub fn count_constructed(&self) -> u32 {
|
pub fn count_constructed(&self) -> u32 {
|
||||||
self.meta
|
self.meta
|
||||||
.iter()
|
.iter()
|
||||||
@ -1180,7 +1184,8 @@ impl Entities {
|
|||||||
.count() as u32
|
.count() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if there are any entities currently constructed, entities that have locations.
|
/// Returns true if there are any entity rows currently constructed.
|
||||||
|
/// See the module docs for a more precise explanation of what construction means.
|
||||||
pub fn any_constructed(&self) -> bool {
|
pub fn any_constructed(&self) -> bool {
|
||||||
self.meta.iter().any(|meta| meta.location.is_some())
|
self.meta.iter().any(|meta| meta.location.is_some())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user