Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/entity/mod.rs
6849 views
1
//! Entity handling types.
2
//!
3
//! An **entity** exclusively owns zero or more [component] instances, all of different types, and can dynamically acquire or lose them over its lifetime.
4
//!
5
//! **empty entity**: Entity with zero components.
6
//! **pending entity**: Entity reserved, but not flushed yet (see [`Entities::flush`] docs for reference).
7
//! **reserved entity**: same as **pending entity**.
8
//! **invalid entity**: **pending entity** flushed with invalid (see [`Entities::flush_as_invalid`] docs for reference).
9
//!
10
//! See [`Entity`] to learn more.
11
//!
12
//! [component]: crate::component::Component
13
//!
14
//! # Usage
15
//!
16
//! Operations involving entities and their components are performed either from a system by submitting commands,
17
//! or from the outside (or from an exclusive system) by directly using [`World`] methods:
18
//!
19
//! |Operation|Command|Method|
20
//! |:---:|:---:|:---:|
21
//! |Spawn an entity with components|[`Commands::spawn`]|[`World::spawn`]|
22
//! |Spawn an entity without components|[`Commands::spawn_empty`]|[`World::spawn_empty`]|
23
//! |Despawn an entity|[`EntityCommands::despawn`]|[`World::despawn`]|
24
//! |Insert a component, bundle, or tuple of components and bundles to an entity|[`EntityCommands::insert`]|[`EntityWorldMut::insert`]|
25
//! |Remove a component, bundle, or tuple of components and bundles from an entity|[`EntityCommands::remove`]|[`EntityWorldMut::remove`]|
26
//!
27
//! [`World`]: crate::world::World
28
//! [`Commands::spawn`]: crate::system::Commands::spawn
29
//! [`Commands::spawn_empty`]: crate::system::Commands::spawn_empty
30
//! [`EntityCommands::despawn`]: crate::system::EntityCommands::despawn
31
//! [`EntityCommands::insert`]: crate::system::EntityCommands::insert
32
//! [`EntityCommands::remove`]: crate::system::EntityCommands::remove
33
//! [`World::spawn`]: crate::world::World::spawn
34
//! [`World::spawn_empty`]: crate::world::World::spawn_empty
35
//! [`World::despawn`]: crate::world::World::despawn
36
//! [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert
37
//! [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove
38
39
mod clone_entities;
40
mod entity_set;
41
mod map_entities;
42
#[cfg(feature = "bevy_reflect")]
43
use bevy_reflect::Reflect;
44
#[cfg(all(feature = "bevy_reflect", feature = "serialize"))]
45
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
46
47
pub use clone_entities::*;
48
use derive_more::derive::Display;
49
pub use entity_set::*;
50
pub use map_entities::*;
51
52
mod hash;
53
pub use hash::*;
54
55
pub mod hash_map;
56
pub mod hash_set;
57
58
pub use hash_map::EntityHashMap;
59
pub use hash_set::EntityHashSet;
60
61
pub mod index_map;
62
pub mod index_set;
63
64
pub use index_map::EntityIndexMap;
65
pub use index_set::EntityIndexSet;
66
67
pub mod unique_array;
68
pub mod unique_slice;
69
pub mod unique_vec;
70
71
use nonmax::NonMaxU32;
72
pub use unique_array::{UniqueEntityArray, UniqueEntityEquivalentArray};
73
pub use unique_slice::{UniqueEntityEquivalentSlice, UniqueEntitySlice};
74
pub use unique_vec::{UniqueEntityEquivalentVec, UniqueEntityVec};
75
76
use crate::{
77
archetype::{ArchetypeId, ArchetypeRow},
78
change_detection::MaybeLocation,
79
component::{CheckChangeTicks, Tick},
80
storage::{SparseSetIndex, TableId, TableRow},
81
};
82
use alloc::vec::Vec;
83
use bevy_platform::sync::atomic::Ordering;
84
use core::{fmt, hash::Hash, mem, num::NonZero, panic::Location};
85
use log::warn;
86
87
#[cfg(feature = "serialize")]
88
use serde::{Deserialize, Serialize};
89
90
#[cfg(target_has_atomic = "64")]
91
use bevy_platform::sync::atomic::AtomicI64 as AtomicIdCursor;
92
#[cfg(target_has_atomic = "64")]
93
type IdCursor = i64;
94
95
/// Most modern platforms support 64-bit atomics, but some less-common platforms
96
/// do not. This fallback allows compilation using a 32-bit cursor instead, with
97
/// the caveat that some conversions may fail (and panic) at runtime.
98
#[cfg(not(target_has_atomic = "64"))]
99
use bevy_platform::sync::atomic::AtomicIsize as AtomicIdCursor;
100
#[cfg(not(target_has_atomic = "64"))]
101
type IdCursor = isize;
102
103
/// This represents the row or "index" of an [`Entity`] within the [`Entities`] table.
104
/// This is a lighter weight version of [`Entity`].
105
///
106
/// This is a unique identifier for an entity in the world.
107
/// This differs from [`Entity`] in that [`Entity`] is unique for all entities total (unless the [`Entity::generation`] wraps),
108
/// but this is only unique for entities that are active.
109
///
110
/// This can be used over [`Entity`] to improve performance in some cases,
111
/// but improper use can cause this to identify a different entity than intended.
112
/// Use with caution.
113
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
114
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
115
#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
116
#[cfg_attr(feature = "bevy_reflect", reflect(Hash, PartialEq, Debug, Clone))]
117
#[repr(transparent)]
118
pub struct EntityRow(NonMaxU32);
119
120
impl EntityRow {
121
const PLACEHOLDER: Self = Self(NonMaxU32::MAX);
122
123
/// Constructs a new [`EntityRow`] from its index.
124
pub const fn new(index: NonMaxU32) -> Self {
125
Self(index)
126
}
127
128
/// Gets the index of the entity.
129
#[inline(always)]
130
pub const fn index(self) -> u32 {
131
self.0.get()
132
}
133
134
/// Gets some bits that represent this value.
135
/// The bits are opaque and should not be regarded as meaningful.
136
#[inline(always)]
137
const fn to_bits(self) -> u32 {
138
// SAFETY: NonMax is repr transparent.
139
unsafe { mem::transmute::<NonMaxU32, u32>(self.0) }
140
}
141
142
/// Reconstruct an [`EntityRow`] previously destructured with [`EntityRow::to_bits`].
143
///
144
/// Only useful when applied to results from `to_bits` in the same instance of an application.
145
///
146
/// # Panics
147
///
148
/// This method will likely panic if given `u32` values that did not come from [`EntityRow::to_bits`].
149
#[inline]
150
const fn from_bits(bits: u32) -> Self {
151
Self::try_from_bits(bits).expect("Attempted to initialize invalid bits as an entity row")
152
}
153
154
/// Reconstruct an [`EntityRow`] previously destructured with [`EntityRow::to_bits`].
155
///
156
/// Only useful when applied to results from `to_bits` in the same instance of an application.
157
///
158
/// This method is the fallible counterpart to [`EntityRow::from_bits`].
159
#[inline(always)]
160
const fn try_from_bits(bits: u32) -> Option<Self> {
161
match NonZero::<u32>::new(bits) {
162
// SAFETY: NonMax and NonZero are repr transparent.
163
Some(underlying) => Some(Self(unsafe {
164
mem::transmute::<NonZero<u32>, NonMaxU32>(underlying)
165
})),
166
None => None,
167
}
168
}
169
}
170
171
impl SparseSetIndex for EntityRow {
172
#[inline]
173
fn sparse_set_index(&self) -> usize {
174
self.index() as usize
175
}
176
177
#[inline]
178
fn get_sparse_set_index(value: usize) -> Self {
179
Self::from_bits(value as u32)
180
}
181
}
182
183
/// This tracks different versions or generations of an [`EntityRow`].
184
/// Importantly, this can wrap, meaning each generation is not necessarily unique per [`EntityRow`].
185
///
186
/// This should be treated as a opaque identifier, and its internal representation may be subject to change.
187
///
188
/// # Aliasing
189
///
190
/// Internally [`EntityGeneration`] wraps a `u32`, so it can't represent *every* possible generation.
191
/// Eventually, generations can (and do) wrap or alias.
192
/// This can cause [`Entity`] and [`EntityGeneration`] values to be equal while still referring to different conceptual entities.
193
/// This can cause some surprising behavior:
194
///
195
/// ```
196
/// # use bevy_ecs::entity::EntityGeneration;
197
/// let (aliased, did_alias) = EntityGeneration::FIRST.after_versions(1u32 << 31).after_versions_and_could_alias(1u32 << 31);
198
/// assert!(did_alias);
199
/// assert!(EntityGeneration::FIRST == aliased);
200
/// ```
201
///
202
/// This can cause some unintended side effects.
203
/// See [`Entity`] docs for practical concerns and how to minimize any risks.
204
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Display)]
205
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
206
#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
207
#[cfg_attr(feature = "bevy_reflect", reflect(Hash, PartialEq, Debug, Clone))]
208
#[repr(transparent)]
209
pub struct EntityGeneration(u32);
210
211
impl EntityGeneration {
212
/// Represents the first generation of an [`EntityRow`].
213
pub const FIRST: Self = Self(0);
214
215
/// Non-wrapping difference between two generations after which a signed interpretation becomes negative.
216
const DIFF_MAX: u32 = 1u32 << 31;
217
218
/// Gets some bits that represent this value.
219
/// The bits are opaque and should not be regarded as meaningful.
220
#[inline(always)]
221
pub const fn to_bits(self) -> u32 {
222
self.0
223
}
224
225
/// Reconstruct an [`EntityGeneration`] previously destructured with [`EntityGeneration::to_bits`].
226
///
227
/// Only useful when applied to results from `to_bits` in the same instance of an application.
228
#[inline]
229
pub const fn from_bits(bits: u32) -> Self {
230
Self(bits)
231
}
232
233
/// Returns the [`EntityGeneration`] that would result from this many more `versions` of the corresponding [`EntityRow`] from passing.
234
#[inline]
235
pub const fn after_versions(self, versions: u32) -> Self {
236
Self(self.0.wrapping_add(versions))
237
}
238
239
/// Identical to [`after_versions`](Self::after_versions) but also returns a `bool` indicating if,
240
/// after these `versions`, one such version could conflict with a previous one.
241
///
242
/// If this happens, this will no longer uniquely identify a version of an [`EntityRow`].
243
/// This is called entity aliasing.
244
#[inline]
245
pub const fn after_versions_and_could_alias(self, versions: u32) -> (Self, bool) {
246
let raw = self.0.overflowing_add(versions);
247
(Self(raw.0), raw.1)
248
}
249
250
/// Compares two generations.
251
///
252
/// Generations that are later will be [`Greater`](core::cmp::Ordering::Greater) than earlier ones.
253
///
254
/// ```
255
/// # use bevy_ecs::entity::EntityGeneration;
256
/// # use core::cmp::Ordering;
257
/// let later_generation = EntityGeneration::FIRST.after_versions(400);
258
/// assert_eq!(EntityGeneration::FIRST.cmp_approx(&later_generation), Ordering::Less);
259
///
260
/// let (aliased, did_alias) = EntityGeneration::FIRST.after_versions(400).after_versions_and_could_alias(u32::MAX);
261
/// assert!(did_alias);
262
/// assert_eq!(EntityGeneration::FIRST.cmp_approx(&aliased), Ordering::Less);
263
/// ```
264
///
265
/// Ordering will be incorrect and [non-transitive](https://en.wikipedia.org/wiki/Transitive_relation)
266
/// for distant generations:
267
///
268
/// ```should_panic
269
/// # use bevy_ecs::entity::EntityGeneration;
270
/// # use core::cmp::Ordering;
271
/// let later_generation = EntityGeneration::FIRST.after_versions(3u32 << 31);
272
/// let much_later_generation = later_generation.after_versions(3u32 << 31);
273
///
274
/// // while these orderings are correct and pass assertions...
275
/// assert_eq!(EntityGeneration::FIRST.cmp_approx(&later_generation), Ordering::Less);
276
/// assert_eq!(later_generation.cmp_approx(&much_later_generation), Ordering::Less);
277
///
278
/// // ... this ordering is not and the assertion fails!
279
/// assert_eq!(EntityGeneration::FIRST.cmp_approx(&much_later_generation), Ordering::Less);
280
/// ```
281
///
282
/// Because of this, `EntityGeneration` does not implement `Ord`/`PartialOrd`.
283
#[inline]
284
pub const fn cmp_approx(&self, other: &Self) -> core::cmp::Ordering {
285
use core::cmp::Ordering;
286
match self.0.wrapping_sub(other.0) {
287
0 => Ordering::Equal,
288
1..Self::DIFF_MAX => Ordering::Greater,
289
_ => Ordering::Less,
290
}
291
}
292
}
293
294
/// Lightweight identifier of an [entity](crate::entity).
295
///
296
/// The identifier is implemented using a [generational index]: a combination of an index ([`EntityRow`]) and a generation ([`EntityGeneration`]).
297
/// This allows fast insertion after data removal in an array while minimizing loss of spatial locality.
298
///
299
/// These identifiers are only valid on the [`World`] it's sourced from. Attempting to use an `Entity` to
300
/// fetch entity components or metadata from a different world will either fail or return unexpected results.
301
///
302
/// [generational index]: https://lucassardois.medium.com/generational-indices-guide-8e3c5f7fd594
303
///
304
/// # Aliasing
305
///
306
/// Once an entity is despawned, it ceases to exist.
307
/// However, its [`Entity`] id is still present, and may still be contained in some data.
308
/// This becomes problematic because it is possible for a later entity to be spawned at the exact same id!
309
/// If this happens, which is rare but very possible, it will be logged.
310
///
311
/// Aliasing can happen without warning.
312
/// Holding onto a [`Entity`] id corresponding to an entity well after that entity was despawned can cause un-intuitive behavior for both ordering, and comparing in general.
313
/// To prevent these bugs, it is generally best practice to stop holding an [`Entity`] or [`EntityGeneration`] value as soon as you know it has been despawned.
314
/// If you must do otherwise, do not assume the [`Entity`] corresponds to the same conceptual entity it originally did.
315
/// See [`EntityGeneration`]'s docs for more information about aliasing and why it occurs.
316
///
317
/// # Stability warning
318
/// For all intents and purposes, `Entity` should be treated as an opaque identifier. The internal bit
319
/// representation is liable to change from release to release as are the behaviors or performance
320
/// characteristics of any of its trait implementations (i.e. `Ord`, `Hash`, etc.). This means that changes in
321
/// `Entity`'s representation, though made readable through various functions on the type, are not considered
322
/// breaking changes under [SemVer].
323
///
324
/// In particular, directly serializing with `Serialize` and `Deserialize` make zero guarantee of long
325
/// term wire format compatibility. Changes in behavior will cause serialized `Entity` values persisted
326
/// to long term storage (i.e. disk, databases, etc.) will fail to deserialize upon being updated.
327
///
328
/// # Usage
329
///
330
/// This data type is returned by iterating a `Query` that has `Entity` as part of its query fetch type parameter ([learn more]).
331
/// It can also be obtained by calling [`EntityCommands::id`] or [`EntityWorldMut::id`].
332
///
333
/// ```
334
/// # use bevy_ecs::prelude::*;
335
/// # #[derive(Component)]
336
/// # struct SomeComponent;
337
/// fn setup(mut commands: Commands) {
338
/// // Calling `spawn` returns `EntityCommands`.
339
/// let entity = commands.spawn(SomeComponent).id();
340
/// }
341
///
342
/// fn exclusive_system(world: &mut World) {
343
/// // Calling `spawn` returns `EntityWorldMut`.
344
/// let entity = world.spawn(SomeComponent).id();
345
/// }
346
/// #
347
/// # bevy_ecs::system::assert_is_system(setup);
348
/// # bevy_ecs::system::assert_is_system(exclusive_system);
349
/// ```
350
///
351
/// It can be used to refer to a specific entity to apply [`EntityCommands`], or to call [`Query::get`] (or similar methods) to access its components.
352
///
353
/// ```
354
/// # use bevy_ecs::prelude::*;
355
/// #
356
/// # #[derive(Component)]
357
/// # struct Expired;
358
/// #
359
/// fn dispose_expired_food(mut commands: Commands, query: Query<Entity, With<Expired>>) {
360
/// for food_entity in &query {
361
/// commands.entity(food_entity).despawn();
362
/// }
363
/// }
364
/// #
365
/// # bevy_ecs::system::assert_is_system(dispose_expired_food);
366
/// ```
367
///
368
/// [learn more]: crate::system::Query#entity-id-access
369
/// [`EntityCommands::id`]: crate::system::EntityCommands::id
370
/// [`EntityWorldMut::id`]: crate::world::EntityWorldMut::id
371
/// [`EntityCommands`]: crate::system::EntityCommands
372
/// [`Query::get`]: crate::system::Query::get
373
/// [`World`]: crate::world::World
374
/// [SemVer]: https://semver.org/
375
#[derive(Clone, Copy)]
376
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
377
#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
378
#[cfg_attr(feature = "bevy_reflect", reflect(Hash, PartialEq, Debug, Clone))]
379
#[cfg_attr(
380
all(feature = "bevy_reflect", feature = "serialize"),
381
reflect(Serialize, Deserialize)
382
)]
383
// Alignment repr necessary to allow LLVM to better output
384
// optimized codegen for `to_bits`, `PartialEq` and `Ord`.
385
#[repr(C, align(8))]
386
pub struct Entity {
387
// Do not reorder the fields here. The ordering is explicitly used by repr(C)
388
// to make this struct equivalent to a u64.
389
#[cfg(target_endian = "little")]
390
row: EntityRow,
391
generation: EntityGeneration,
392
#[cfg(target_endian = "big")]
393
row: EntityRow,
394
}
395
396
// By not short-circuiting in comparisons, we get better codegen.
397
// See <https://github.com/rust-lang/rust/issues/117800>
398
impl PartialEq for Entity {
399
#[inline]
400
fn eq(&self, other: &Entity) -> bool {
401
// By using `to_bits`, the codegen can be optimized out even
402
// further potentially. Relies on the correct alignment/field
403
// order of `Entity`.
404
self.to_bits() == other.to_bits()
405
}
406
}
407
408
impl Eq for Entity {}
409
410
// The derive macro codegen output is not optimal and can't be optimized as well
411
// by the compiler. This impl resolves the issue of non-optimal codegen by relying
412
// on comparing against the bit representation of `Entity` instead of comparing
413
// the fields. The result is then LLVM is able to optimize the codegen for Entity
414
// far beyond what the derive macro can.
415
// See <https://github.com/rust-lang/rust/issues/106107>
416
impl PartialOrd for Entity {
417
#[inline]
418
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
419
// Make use of our `Ord` impl to ensure optimal codegen output
420
Some(self.cmp(other))
421
}
422
}
423
424
// The derive macro codegen output is not optimal and can't be optimized as well
425
// by the compiler. This impl resolves the issue of non-optimal codegen by relying
426
// on comparing against the bit representation of `Entity` instead of comparing
427
// the fields. The result is then LLVM is able to optimize the codegen for Entity
428
// far beyond what the derive macro can.
429
// See <https://github.com/rust-lang/rust/issues/106107>
430
impl Ord for Entity {
431
#[inline]
432
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
433
// This will result in better codegen for ordering comparisons, plus
434
// avoids pitfalls with regards to macro codegen relying on property
435
// position when we want to compare against the bit representation.
436
self.to_bits().cmp(&other.to_bits())
437
}
438
}
439
440
impl Hash for Entity {
441
#[inline]
442
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
443
self.to_bits().hash(state);
444
}
445
}
446
447
impl Entity {
448
/// Construct an [`Entity`] from a raw `row` value and a non-zero `generation` value.
449
/// Ensure that the generation value is never greater than `0x7FFF_FFFF`.
450
#[inline(always)]
451
pub(crate) const fn from_raw_and_generation(
452
row: EntityRow,
453
generation: EntityGeneration,
454
) -> Entity {
455
Self { row, generation }
456
}
457
458
/// An entity ID with a placeholder value. This may or may not correspond to an actual entity,
459
/// and should be overwritten by a new value before being used.
460
///
461
/// ## Examples
462
///
463
/// Initializing a collection (e.g. `array` or `Vec`) with a known size:
464
///
465
/// ```no_run
466
/// # use bevy_ecs::prelude::*;
467
/// // Create a new array of size 10 filled with invalid entity ids.
468
/// let mut entities: [Entity; 10] = [Entity::PLACEHOLDER; 10];
469
///
470
/// // ... replace the entities with valid ones.
471
/// ```
472
///
473
/// Deriving [`Reflect`] for a component that has an `Entity` field:
474
///
475
/// ```no_run
476
/// # use bevy_ecs::{prelude::*, component::*};
477
/// # use bevy_reflect::Reflect;
478
/// #[derive(Reflect, Component)]
479
/// #[reflect(Component)]
480
/// pub struct MyStruct {
481
/// pub entity: Entity,
482
/// }
483
///
484
/// impl FromWorld for MyStruct {
485
/// fn from_world(_world: &mut World) -> Self {
486
/// Self {
487
/// entity: Entity::PLACEHOLDER,
488
/// }
489
/// }
490
/// }
491
/// ```
492
pub const PLACEHOLDER: Self = Self::from_raw(EntityRow::PLACEHOLDER);
493
494
/// Creates a new entity ID with the specified `row` and a generation of 1.
495
///
496
/// # Note
497
///
498
/// Spawning a specific `entity` value is __rarely the right choice__. Most apps should favor
499
/// [`Commands::spawn`](crate::system::Commands::spawn). This method should generally
500
/// only be used for sharing entities across apps, and only when they have a scheme
501
/// worked out to share an index space (which doesn't happen by default).
502
///
503
/// In general, one should not try to synchronize the ECS by attempting to ensure that
504
/// `Entity` lines up between instances, but instead insert a secondary identifier as
505
/// a component.
506
#[inline(always)]
507
pub const fn from_raw(row: EntityRow) -> Entity {
508
Self::from_raw_and_generation(row, EntityGeneration::FIRST)
509
}
510
511
/// This is equivalent to [`from_raw`](Self::from_raw) except that it takes a `u32` instead of an [`EntityRow`].
512
///
513
/// Returns `None` if the row is `u32::MAX`.
514
#[inline(always)]
515
pub const fn from_raw_u32(row: u32) -> Option<Entity> {
516
match NonMaxU32::new(row) {
517
Some(row) => Some(Self::from_raw(EntityRow::new(row))),
518
None => None,
519
}
520
}
521
522
/// Convert to a form convenient for passing outside of rust.
523
///
524
/// Only useful for identifying entities within the same instance of an application. Do not use
525
/// for serialization between runs.
526
///
527
/// No particular structure is guaranteed for the returned bits.
528
#[inline(always)]
529
pub const fn to_bits(self) -> u64 {
530
self.row.to_bits() as u64 | ((self.generation.to_bits() as u64) << 32)
531
}
532
533
/// Reconstruct an `Entity` previously destructured with [`Entity::to_bits`].
534
///
535
/// Only useful when applied to results from `to_bits` in the same instance of an application.
536
///
537
/// # Panics
538
///
539
/// This method will likely panic if given `u64` values that did not come from [`Entity::to_bits`].
540
#[inline]
541
pub const fn from_bits(bits: u64) -> Self {
542
if let Some(id) = Self::try_from_bits(bits) {
543
id
544
} else {
545
panic!("Attempted to initialize invalid bits as an entity")
546
}
547
}
548
549
/// Reconstruct an `Entity` previously destructured with [`Entity::to_bits`].
550
///
551
/// Only useful when applied to results from `to_bits` in the same instance of an application.
552
///
553
/// This method is the fallible counterpart to [`Entity::from_bits`].
554
#[inline(always)]
555
pub const fn try_from_bits(bits: u64) -> Option<Self> {
556
let raw_row = bits as u32;
557
let raw_gen = (bits >> 32) as u32;
558
559
if let Some(row) = EntityRow::try_from_bits(raw_row) {
560
Some(Self {
561
row,
562
generation: EntityGeneration::from_bits(raw_gen),
563
})
564
} else {
565
None
566
}
567
}
568
569
/// Return a transiently unique identifier.
570
/// See also [`EntityRow`].
571
///
572
/// No two simultaneously-live entities share the same row, but dead entities' indices may collide
573
/// with both live and dead entities. Useful for compactly representing entities within a
574
/// specific snapshot of the world, such as when serializing.
575
#[inline]
576
pub const fn row(self) -> EntityRow {
577
self.row
578
}
579
580
/// Equivalent to `self.row().index()`. See [`Self::row`] for details.
581
#[inline]
582
pub const fn index(self) -> u32 {
583
self.row.index()
584
}
585
586
/// Returns the generation of this Entity's row. The generation is incremented each time an
587
/// entity with a given row is despawned. This serves as a "count" of the number of times a
588
/// given row has been reused (row, generation) pairs uniquely identify a given Entity.
589
#[inline]
590
pub const fn generation(self) -> EntityGeneration {
591
self.generation
592
}
593
}
594
595
#[cfg(feature = "serialize")]
596
impl Serialize for Entity {
597
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
598
where
599
S: serde::Serializer,
600
{
601
serializer.serialize_u64(self.to_bits())
602
}
603
}
604
605
#[cfg(feature = "serialize")]
606
impl<'de> Deserialize<'de> for Entity {
607
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
608
where
609
D: serde::Deserializer<'de>,
610
{
611
use serde::de::Error;
612
let id: u64 = Deserialize::deserialize(deserializer)?;
613
Entity::try_from_bits(id)
614
.ok_or_else(|| D::Error::custom("Attempting to deserialize an invalid entity."))
615
}
616
}
617
618
/// Outputs the short entity identifier, including the index and generation.
619
///
620
/// This takes the format: `{index}v{generation}`.
621
///
622
/// For [`Entity::PLACEHOLDER`], this outputs `PLACEHOLDER`.
623
///
624
/// For a unique [`u64`] representation, use [`Entity::to_bits`].
625
impl fmt::Debug for Entity {
626
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
627
fmt::Display::fmt(self, f)
628
}
629
}
630
631
/// Outputs the short entity identifier, including the index and generation.
632
///
633
/// This takes the format: `{index}v{generation}`.
634
///
635
/// For [`Entity::PLACEHOLDER`], this outputs `PLACEHOLDER`.
636
impl fmt::Display for Entity {
637
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
638
if self == &Self::PLACEHOLDER {
639
write!(f, "PLACEHOLDER")
640
} else {
641
write!(f, "{}v{}", self.index(), self.generation())
642
}
643
}
644
}
645
646
impl SparseSetIndex for Entity {
647
#[inline]
648
fn sparse_set_index(&self) -> usize {
649
self.row().sparse_set_index()
650
}
651
652
#[inline]
653
fn get_sparse_set_index(value: usize) -> Self {
654
Entity::from_raw(EntityRow::get_sparse_set_index(value))
655
}
656
}
657
658
/// An [`Iterator`] returning a sequence of [`Entity`] values from
659
pub struct ReserveEntitiesIterator<'a> {
660
// Metas, so we can recover the current generation for anything in the freelist.
661
meta: &'a [EntityMeta],
662
663
// Reserved indices formerly in the freelist to hand out.
664
freelist_indices: core::slice::Iter<'a, EntityRow>,
665
666
// New Entity indices to hand out, outside the range of meta.len().
667
new_indices: core::ops::Range<u32>,
668
}
669
670
impl<'a> Iterator for ReserveEntitiesIterator<'a> {
671
type Item = Entity;
672
673
fn next(&mut self) -> Option<Self::Item> {
674
self.freelist_indices
675
.next()
676
.map(|&row| {
677
Entity::from_raw_and_generation(row, self.meta[row.index() as usize].generation)
678
})
679
.or_else(|| {
680
self.new_indices.next().map(|index| {
681
// SAFETY: This came from an exclusive range so the max can't be hit.
682
let row = unsafe { EntityRow::new(NonMaxU32::new_unchecked(index)) };
683
Entity::from_raw(row)
684
})
685
})
686
}
687
688
fn size_hint(&self) -> (usize, Option<usize>) {
689
let len = self.freelist_indices.len() + self.new_indices.len();
690
(len, Some(len))
691
}
692
}
693
694
impl<'a> ExactSizeIterator for ReserveEntitiesIterator<'a> {}
695
696
impl<'a> core::iter::FusedIterator for ReserveEntitiesIterator<'a> {}
697
698
// SAFETY: Newly reserved entity values are unique.
699
unsafe impl EntitySetIterator for ReserveEntitiesIterator<'_> {}
700
701
/// A [`World`]'s internal metadata store on all of its entities.
702
///
703
/// Contains metadata on:
704
/// - The generation of every entity.
705
/// - The alive/dead status of a particular entity. (i.e. "has entity 3 been despawned?")
706
/// - The location of the entity's components in memory (via [`EntityLocation`])
707
///
708
/// [`World`]: crate::world::World
709
#[derive(Debug)]
710
pub struct Entities {
711
meta: Vec<EntityMeta>,
712
713
/// The `pending` and `free_cursor` fields describe three sets of Entity IDs
714
/// that have been freed or are in the process of being allocated:
715
///
716
/// - The `freelist` IDs, previously freed by `free()`. These IDs are available to any of
717
/// [`alloc`], [`reserve_entity`] or [`reserve_entities`]. Allocation will always prefer
718
/// these over brand new IDs.
719
///
720
/// - The `reserved` list of IDs that were once in the freelist, but got reserved by
721
/// [`reserve_entities`] or [`reserve_entity`]. They are now waiting for [`flush`] to make them
722
/// fully allocated.
723
///
724
/// - The count of new IDs that do not yet exist in `self.meta`, but which we have handed out
725
/// and reserved. [`flush`] will allocate room for them in `self.meta`.
726
///
727
/// The contents of `pending` look like this:
728
///
729
/// ```txt
730
/// ----------------------------
731
/// | freelist | reserved |
732
/// ----------------------------
733
/// ^ ^
734
/// free_cursor pending.len()
735
/// ```
736
///
737
/// As IDs are allocated, `free_cursor` is atomically decremented, moving
738
/// items from the freelist into the reserved list by sliding over the boundary.
739
///
740
/// Once the freelist runs out, `free_cursor` starts going negative.
741
/// The more negative it is, the more IDs have been reserved starting exactly at
742
/// the end of `meta.len()`.
743
///
744
/// This formulation allows us to reserve any number of IDs first from the freelist
745
/// and then from the new IDs, using only a single atomic subtract.
746
///
747
/// Once [`flush`] is done, `free_cursor` will equal `pending.len()`.
748
///
749
/// [`alloc`]: Entities::alloc
750
/// [`reserve_entity`]: Entities::reserve_entity
751
/// [`reserve_entities`]: Entities::reserve_entities
752
/// [`flush`]: Entities::flush
753
pending: Vec<EntityRow>,
754
free_cursor: AtomicIdCursor,
755
}
756
757
impl Entities {
758
pub(crate) const fn new() -> Self {
759
Entities {
760
meta: Vec::new(),
761
pending: Vec::new(),
762
free_cursor: AtomicIdCursor::new(0),
763
}
764
}
765
766
/// Reserve entity IDs concurrently.
767
///
768
/// Storage for entity generation and location is lazily allocated by calling [`flush`](Entities::flush).
769
#[expect(
770
clippy::allow_attributes,
771
reason = "`clippy::unnecessary_fallible_conversions` may not always lint."
772
)]
773
#[allow(
774
clippy::unnecessary_fallible_conversions,
775
reason = "`IdCursor::try_from` may fail on 32-bit platforms."
776
)]
777
pub fn reserve_entities(&self, count: u32) -> ReserveEntitiesIterator<'_> {
778
// Use one atomic subtract to grab a range of new IDs. The range might be
779
// entirely nonnegative, meaning all IDs come from the freelist, or entirely
780
// negative, meaning they are all new IDs to allocate, or a mix of both.
781
let range_end = self.free_cursor.fetch_sub(
782
IdCursor::try_from(count)
783
.expect("64-bit atomic operations are not supported on this platform."),
784
Ordering::Relaxed,
785
);
786
let range_start = range_end
787
- IdCursor::try_from(count)
788
.expect("64-bit atomic operations are not supported on this platform.");
789
790
let freelist_range = range_start.max(0) as usize..range_end.max(0) as usize;
791
792
let (new_id_start, new_id_end) = if range_start >= 0 {
793
// We satisfied all requests from the freelist.
794
(0, 0)
795
} else {
796
// We need to allocate some new Entity IDs outside of the range of self.meta.
797
//
798
// `range_start` covers some negative territory, e.g. `-3..6`.
799
// Since the nonnegative values `0..6` are handled by the freelist, that
800
// means we need to handle the negative range here.
801
//
802
// In this example, we truncate the end to 0, leaving us with `-3..0`.
803
// Then we negate these values to indicate how far beyond the end of `meta.end()`
804
// to go, yielding `meta.len()+0 .. meta.len()+3`.
805
let base = self.meta.len() as IdCursor;
806
807
let new_id_end = u32::try_from(base - range_start).expect("too many entities");
808
809
// `new_id_end` is in range, so no need to check `start`.
810
let new_id_start = (base - range_end.min(0)) as u32;
811
812
(new_id_start, new_id_end)
813
};
814
815
ReserveEntitiesIterator {
816
meta: &self.meta[..],
817
freelist_indices: self.pending[freelist_range].iter(),
818
new_indices: new_id_start..new_id_end,
819
}
820
}
821
822
/// Reserve one entity ID concurrently.
823
///
824
/// Equivalent to `self.reserve_entities(1).next().unwrap()`, but more efficient.
825
pub fn reserve_entity(&self) -> Entity {
826
let n = self.free_cursor.fetch_sub(1, Ordering::Relaxed);
827
if n > 0 {
828
// Allocate from the freelist.
829
let row = self.pending[(n - 1) as usize];
830
Entity::from_raw_and_generation(row, self.meta[row.index() as usize].generation)
831
} else {
832
// Grab a new ID, outside the range of `meta.len()`. `flush()` must
833
// eventually be called to make it valid.
834
//
835
// As `self.free_cursor` goes more and more negative, we return IDs farther
836
// and farther beyond `meta.len()`.
837
let raw = self.meta.len() as IdCursor - n;
838
if raw >= u32::MAX as IdCursor {
839
panic!("too many entities");
840
}
841
// SAFETY: We just checked the bounds
842
let row = unsafe { EntityRow::new(NonMaxU32::new_unchecked(raw as u32)) };
843
Entity::from_raw(row)
844
}
845
}
846
847
/// Check that we do not have pending work requiring `flush()` to be called.
848
fn verify_flushed(&mut self) {
849
debug_assert!(
850
!self.needs_flush(),
851
"flush() needs to be called before this operation is legal"
852
);
853
}
854
855
/// Allocate an entity ID directly.
856
pub fn alloc(&mut self) -> Entity {
857
self.verify_flushed();
858
if let Some(row) = self.pending.pop() {
859
let new_free_cursor = self.pending.len() as IdCursor;
860
*self.free_cursor.get_mut() = new_free_cursor;
861
Entity::from_raw_and_generation(row, self.meta[row.index() as usize].generation)
862
} else {
863
let index = u32::try_from(self.meta.len())
864
.ok()
865
.and_then(NonMaxU32::new)
866
.expect("too many entities");
867
self.meta.push(EntityMeta::EMPTY);
868
Entity::from_raw(EntityRow::new(index))
869
}
870
}
871
872
/// Destroy an entity, allowing it to be reused.
873
///
874
/// Returns the `Option<EntityLocation>` of the entity or `None` if the `entity` was not present.
875
///
876
/// Must not be called while reserved entities are awaiting `flush()`.
877
pub fn free(&mut self, entity: Entity) -> Option<EntityIdLocation> {
878
self.verify_flushed();
879
880
let meta = &mut self.meta[entity.index() as usize];
881
if meta.generation != entity.generation {
882
return None;
883
}
884
885
let (new_generation, aliased) = meta.generation.after_versions_and_could_alias(1);
886
meta.generation = new_generation;
887
if aliased {
888
warn!(
889
"Entity({}) generation wrapped on Entities::free, aliasing may occur",
890
entity.row()
891
);
892
}
893
894
let loc = mem::replace(&mut meta.location, EntityMeta::EMPTY.location);
895
896
self.pending.push(entity.row());
897
898
let new_free_cursor = self.pending.len() as IdCursor;
899
*self.free_cursor.get_mut() = new_free_cursor;
900
Some(loc)
901
}
902
903
/// Ensure at least `n` allocations can succeed without reallocating.
904
#[expect(
905
clippy::allow_attributes,
906
reason = "`clippy::unnecessary_fallible_conversions` may not always lint."
907
)]
908
#[allow(
909
clippy::unnecessary_fallible_conversions,
910
reason = "`IdCursor::try_from` may fail on 32-bit platforms."
911
)]
912
pub fn reserve(&mut self, additional: u32) {
913
self.verify_flushed();
914
915
let freelist_size = *self.free_cursor.get_mut();
916
let shortfall = IdCursor::try_from(additional)
917
.expect("64-bit atomic operations are not supported on this platform.")
918
- freelist_size;
919
if shortfall > 0 {
920
self.meta.reserve(shortfall as usize);
921
}
922
}
923
924
/// Returns true if the [`Entities`] contains [`entity`](Entity).
925
// This will return false for entities which have been freed, even if
926
// not reallocated since the generation is incremented in `free`
927
pub fn contains(&self, entity: Entity) -> bool {
928
self.resolve_from_id(entity.row())
929
.is_some_and(|e| e.generation() == entity.generation())
930
}
931
932
/// Clears all [`Entity`] from the World.
933
pub fn clear(&mut self) {
934
self.meta.clear();
935
self.pending.clear();
936
*self.free_cursor.get_mut() = 0;
937
}
938
939
/// Returns the [`EntityLocation`] of an [`Entity`].
940
/// Note: for pending entities and entities not participating in the ECS (entities with a [`EntityIdLocation`] of `None`), returns `None`.
941
#[inline]
942
pub fn get(&self, entity: Entity) -> Option<EntityLocation> {
943
self.get_id_location(entity).flatten()
944
}
945
946
/// Returns the [`EntityIdLocation`] of an [`Entity`].
947
/// Note: for pending entities, returns `None`.
948
#[inline]
949
pub fn get_id_location(&self, entity: Entity) -> Option<EntityIdLocation> {
950
self.meta
951
.get(entity.index() as usize)
952
.filter(|meta| meta.generation == entity.generation)
953
.map(|meta| meta.location)
954
}
955
956
/// Updates the location of an [`Entity`].
957
/// This must be called when moving the components of the existing entity around in storage.
958
///
959
/// # Safety
960
/// - `index` must be a valid entity index.
961
/// - `location` must be valid for the entity at `index` or immediately made valid afterwards
962
/// before handing control to unknown code.
963
#[inline]
964
pub(crate) unsafe fn set(&mut self, index: u32, location: EntityIdLocation) {
965
// SAFETY: Caller guarantees that `index` a valid entity index
966
let meta = unsafe { self.meta.get_unchecked_mut(index as usize) };
967
meta.location = location;
968
}
969
970
/// Mark an [`Entity`] as spawned or despawned in the given tick.
971
///
972
/// # Safety
973
/// - `index` must be a valid entity index.
974
#[inline]
975
pub(crate) unsafe fn mark_spawn_despawn(&mut self, index: u32, by: MaybeLocation, tick: Tick) {
976
// SAFETY: Caller guarantees that `index` a valid entity index
977
let meta = unsafe { self.meta.get_unchecked_mut(index as usize) };
978
meta.spawned_or_despawned = SpawnedOrDespawned { by, tick };
979
}
980
981
/// Increments the `generation` of a freed [`Entity`]. The next entity ID allocated with this
982
/// `index` will count `generation` starting from the prior `generation` + the specified
983
/// value + 1.
984
///
985
/// Does nothing if no entity with this `index` has been allocated yet.
986
pub(crate) fn reserve_generations(&mut self, index: u32, generations: u32) -> bool {
987
if (index as usize) >= self.meta.len() {
988
return false;
989
}
990
991
let meta = &mut self.meta[index as usize];
992
if meta.location.is_none() {
993
meta.generation = meta.generation.after_versions(generations);
994
true
995
} else {
996
false
997
}
998
}
999
1000
/// Get the [`Entity`] with a given id, if it exists in this [`Entities`] collection
1001
/// Returns `None` if this [`Entity`] is outside of the range of currently reserved Entities
1002
///
1003
/// Note: This method may return [`Entities`](Entity) which are currently free
1004
/// Note that [`contains`](Entities::contains) will correctly return false for freed
1005
/// entities, since it checks the generation
1006
pub fn resolve_from_id(&self, row: EntityRow) -> Option<Entity> {
1007
let idu = row.index() as usize;
1008
if let Some(&EntityMeta { generation, .. }) = self.meta.get(idu) {
1009
Some(Entity::from_raw_and_generation(row, generation))
1010
} else {
1011
// `id` is outside of the meta list - check whether it is reserved but not yet flushed.
1012
let free_cursor = self.free_cursor.load(Ordering::Relaxed);
1013
// If this entity was manually created, then free_cursor might be positive
1014
// Returning None handles that case correctly
1015
let num_pending = usize::try_from(-free_cursor).ok()?;
1016
(idu < self.meta.len() + num_pending).then_some(Entity::from_raw(row))
1017
}
1018
}
1019
1020
fn needs_flush(&mut self) -> bool {
1021
*self.free_cursor.get_mut() != self.pending.len() as IdCursor
1022
}
1023
1024
/// Allocates space for entities previously reserved with [`reserve_entity`](Entities::reserve_entity) or
1025
/// [`reserve_entities`](Entities::reserve_entities), then initializes each one using the supplied function.
1026
///
1027
/// See [`EntityLocation`] for details on its meaning and how to set it.
1028
///
1029
/// # Safety
1030
/// Flush _must_ set the entity location to the correct [`ArchetypeId`] for the given [`Entity`]
1031
/// each time init is called. This _can_ be [`ArchetypeId::INVALID`], provided the [`Entity`]
1032
/// has not been assigned to an [`Archetype`][crate::archetype::Archetype].
1033
///
1034
/// Note: freshly-allocated entities (ones which don't come from the pending list) are guaranteed
1035
/// to be initialized with the invalid archetype.
1036
pub unsafe fn flush(
1037
&mut self,
1038
mut init: impl FnMut(Entity, &mut EntityIdLocation),
1039
by: MaybeLocation,
1040
tick: Tick,
1041
) {
1042
let free_cursor = self.free_cursor.get_mut();
1043
let current_free_cursor = *free_cursor;
1044
1045
let new_free_cursor = if current_free_cursor >= 0 {
1046
current_free_cursor as usize
1047
} else {
1048
let old_meta_len = self.meta.len();
1049
let new_meta_len = old_meta_len + -current_free_cursor as usize;
1050
self.meta.resize(new_meta_len, EntityMeta::EMPTY);
1051
for (index, meta) in self.meta.iter_mut().enumerate().skip(old_meta_len) {
1052
// SAFETY: the index is less than the meta length, which can not exceeded u32::MAX
1053
let row = EntityRow::new(unsafe { NonMaxU32::new_unchecked(index as u32) });
1054
init(
1055
Entity::from_raw_and_generation(row, meta.generation),
1056
&mut meta.location,
1057
);
1058
meta.spawned_or_despawned = SpawnedOrDespawned { by, tick };
1059
}
1060
1061
*free_cursor = 0;
1062
0
1063
};
1064
1065
for row in self.pending.drain(new_free_cursor..) {
1066
let meta = &mut self.meta[row.index() as usize];
1067
init(
1068
Entity::from_raw_and_generation(row, meta.generation),
1069
&mut meta.location,
1070
);
1071
meta.spawned_or_despawned = SpawnedOrDespawned { by, tick };
1072
}
1073
}
1074
1075
/// Flushes all reserved entities to an "invalid" state. Attempting to retrieve them will return `None`
1076
/// unless they are later populated with a valid archetype.
1077
pub fn flush_as_invalid(&mut self, by: MaybeLocation, tick: Tick) {
1078
// SAFETY: as per `flush` safety docs, the archetype id can be set to [`ArchetypeId::INVALID`] if
1079
// the [`Entity`] has not been assigned to an [`Archetype`][crate::archetype::Archetype], which is the case here
1080
unsafe {
1081
self.flush(
1082
|_entity, location| {
1083
*location = None;
1084
},
1085
by,
1086
tick,
1087
);
1088
}
1089
}
1090
1091
/// The count of all entities in the [`World`] that have ever been allocated
1092
/// including the entities that are currently freed.
1093
///
1094
/// This does not include entities that have been reserved but have never been
1095
/// allocated yet.
1096
///
1097
/// [`World`]: crate::world::World
1098
#[inline]
1099
pub fn total_count(&self) -> usize {
1100
self.meta.len()
1101
}
1102
1103
/// The count of all entities in the [`World`] that are used,
1104
/// including both those allocated and those reserved, but not those freed.
1105
///
1106
/// [`World`]: crate::world::World
1107
#[inline]
1108
pub fn used_count(&self) -> usize {
1109
(self.meta.len() as isize - self.free_cursor.load(Ordering::Relaxed) as isize) as usize
1110
}
1111
1112
/// The count of all entities in the [`World`] that have ever been allocated or reserved, including those that are freed.
1113
/// This is the value that [`Self::total_count()`] would return if [`Self::flush()`] were called right now.
1114
///
1115
/// [`World`]: crate::world::World
1116
#[inline]
1117
pub fn total_prospective_count(&self) -> usize {
1118
self.meta.len() + (-self.free_cursor.load(Ordering::Relaxed)).min(0) as usize
1119
}
1120
1121
/// The count of currently allocated entities.
1122
#[inline]
1123
pub fn len(&self) -> u32 {
1124
// `pending`, by definition, can't be bigger than `meta`.
1125
(self.meta.len() - self.pending.len()) as u32
1126
}
1127
1128
/// Checks if any entity is currently active.
1129
#[inline]
1130
pub fn is_empty(&self) -> bool {
1131
self.len() == 0
1132
}
1133
1134
/// Try to get the source code location from which this entity has last been
1135
/// spawned, despawned or flushed.
1136
///
1137
/// Returns `None` if its index has been reused by another entity
1138
/// or if this entity has never existed.
1139
pub fn entity_get_spawned_or_despawned_by(
1140
&self,
1141
entity: Entity,
1142
) -> MaybeLocation<Option<&'static Location<'static>>> {
1143
MaybeLocation::new_with_flattened(|| {
1144
self.entity_get_spawned_or_despawned(entity)
1145
.map(|spawned_or_despawned| spawned_or_despawned.by)
1146
})
1147
}
1148
1149
/// Try to get the [`Tick`] at which this entity has last been
1150
/// spawned, despawned or flushed.
1151
///
1152
/// Returns `None` if its index has been reused by another entity or if this entity
1153
/// has never been spawned.
1154
pub fn entity_get_spawn_or_despawn_tick(&self, entity: Entity) -> Option<Tick> {
1155
self.entity_get_spawned_or_despawned(entity)
1156
.map(|spawned_or_despawned| spawned_or_despawned.tick)
1157
}
1158
1159
/// Try to get the [`SpawnedOrDespawned`] related to the entity's last spawn,
1160
/// despawn or flush.
1161
///
1162
/// Returns `None` if its index has been reused by another entity or if
1163
/// this entity has never been spawned.
1164
#[inline]
1165
fn entity_get_spawned_or_despawned(&self, entity: Entity) -> Option<SpawnedOrDespawned> {
1166
self.meta
1167
.get(entity.index() as usize)
1168
.filter(|meta|
1169
// Generation is incremented immediately upon despawn
1170
(meta.generation == entity.generation)
1171
|| meta.location.is_none()
1172
&& (meta.generation == entity.generation.after_versions(1)))
1173
.map(|meta| meta.spawned_or_despawned)
1174
}
1175
1176
/// Returns the source code location from which this entity has last been spawned
1177
/// or despawned and the Tick of when that happened.
1178
///
1179
/// # Safety
1180
///
1181
/// The entity index must belong to an entity that is currently alive or, if it
1182
/// despawned, was not overwritten by a new entity of the same index.
1183
#[inline]
1184
pub(crate) unsafe fn entity_get_spawned_or_despawned_unchecked(
1185
&self,
1186
entity: Entity,
1187
) -> (MaybeLocation, Tick) {
1188
// SAFETY: caller ensures entity is allocated
1189
let meta = unsafe { self.meta.get_unchecked(entity.index() as usize) };
1190
(meta.spawned_or_despawned.by, meta.spawned_or_despawned.tick)
1191
}
1192
1193
#[inline]
1194
pub(crate) fn check_change_ticks(&mut self, check: CheckChangeTicks) {
1195
for meta in &mut self.meta {
1196
meta.spawned_or_despawned.tick.check_tick(check);
1197
}
1198
}
1199
1200
/// Constructs a message explaining why an entity does not exist, if known.
1201
pub(crate) fn entity_does_not_exist_error_details(
1202
&self,
1203
entity: Entity,
1204
) -> EntityDoesNotExistDetails {
1205
EntityDoesNotExistDetails {
1206
location: self.entity_get_spawned_or_despawned_by(entity),
1207
}
1208
}
1209
}
1210
1211
/// An error that occurs when a specified [`Entity`] does not exist.
1212
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
1213
#[error("The entity with ID {entity} {details}")]
1214
pub struct EntityDoesNotExistError {
1215
/// The entity's ID.
1216
pub entity: Entity,
1217
/// Details on why the entity does not exist, if available.
1218
pub details: EntityDoesNotExistDetails,
1219
}
1220
1221
impl EntityDoesNotExistError {
1222
pub(crate) fn new(entity: Entity, entities: &Entities) -> Self {
1223
Self {
1224
entity,
1225
details: entities.entity_does_not_exist_error_details(entity),
1226
}
1227
}
1228
}
1229
1230
/// Helper struct that, when printed, will write the appropriate details
1231
/// regarding an entity that did not exist.
1232
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1233
pub struct EntityDoesNotExistDetails {
1234
location: MaybeLocation<Option<&'static Location<'static>>>,
1235
}
1236
1237
impl fmt::Display for EntityDoesNotExistDetails {
1238
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1239
match self.location.into_option() {
1240
Some(Some(location)) => write!(f, "was despawned by {location}"),
1241
Some(None) => write!(
1242
f,
1243
"does not exist (index has been reused or was never spawned)"
1244
),
1245
None => write!(
1246
f,
1247
"does not exist (enable `track_location` feature for more details)"
1248
),
1249
}
1250
}
1251
}
1252
1253
#[derive(Copy, Clone, Debug)]
1254
struct EntityMeta {
1255
/// The current [`EntityGeneration`] of the [`EntityRow`].
1256
generation: EntityGeneration,
1257
/// The current location of the [`EntityRow`].
1258
location: EntityIdLocation,
1259
/// Location and tick of the last spawn, despawn or flush of this entity.
1260
spawned_or_despawned: SpawnedOrDespawned,
1261
}
1262
1263
#[derive(Copy, Clone, Debug)]
1264
struct SpawnedOrDespawned {
1265
by: MaybeLocation,
1266
tick: Tick,
1267
}
1268
1269
impl EntityMeta {
1270
/// meta for **pending entity**
1271
const EMPTY: EntityMeta = EntityMeta {
1272
generation: EntityGeneration::FIRST,
1273
location: None,
1274
spawned_or_despawned: SpawnedOrDespawned {
1275
by: MaybeLocation::caller(),
1276
tick: Tick::new(0),
1277
},
1278
};
1279
}
1280
1281
/// A location of an entity in an archetype.
1282
#[derive(Copy, Clone, Debug, PartialEq)]
1283
pub struct EntityLocation {
1284
/// The ID of the [`Archetype`] the [`Entity`] belongs to.
1285
///
1286
/// [`Archetype`]: crate::archetype::Archetype
1287
pub archetype_id: ArchetypeId,
1288
1289
/// The index of the [`Entity`] within its [`Archetype`].
1290
///
1291
/// [`Archetype`]: crate::archetype::Archetype
1292
pub archetype_row: ArchetypeRow,
1293
1294
/// The ID of the [`Table`] the [`Entity`] belongs to.
1295
///
1296
/// [`Table`]: crate::storage::Table
1297
pub table_id: TableId,
1298
1299
/// The index of the [`Entity`] within its [`Table`].
1300
///
1301
/// [`Table`]: crate::storage::Table
1302
pub table_row: TableRow,
1303
}
1304
1305
/// An [`Entity`] id may or may not correspond to a valid conceptual entity.
1306
/// If it does, the conceptual entity may or may not have a location.
1307
/// If it has no location, the [`EntityLocation`] will be `None`.
1308
/// An location of `None` means the entity effectively does not exist; it has an id, but is not participating in the ECS.
1309
/// This is different from a location in the empty archetype, which is participating (queryable, etc) but just happens to have no components.
1310
///
1311
/// Setting a location to `None` is often helpful when you want to destruct an entity or yank it from the ECS without allowing another system to reuse the id for something else.
1312
/// It is also useful for reserving an id; commands will often allocate an `Entity` but not provide it a location until the command is applied.
1313
pub type EntityIdLocation = Option<EntityLocation>;
1314
1315
#[cfg(test)]
1316
mod tests {
1317
use super::*;
1318
use alloc::format;
1319
1320
#[test]
1321
fn entity_niche_optimization() {
1322
assert_eq!(size_of::<Entity>(), size_of::<Option<Entity>>());
1323
}
1324
1325
#[test]
1326
fn entity_bits_roundtrip() {
1327
let r = EntityRow::new(NonMaxU32::new(0xDEADBEEF).unwrap());
1328
assert_eq!(EntityRow::from_bits(r.to_bits()), r);
1329
1330
// Generation cannot be greater than 0x7FFF_FFFF else it will be an invalid Entity id
1331
let e = Entity::from_raw_and_generation(
1332
EntityRow::new(NonMaxU32::new(0xDEADBEEF).unwrap()),
1333
EntityGeneration::from_bits(0x5AADF00D),
1334
);
1335
assert_eq!(Entity::from_bits(e.to_bits()), e);
1336
}
1337
1338
#[test]
1339
fn reserve_entity_len() {
1340
let mut e = Entities::new();
1341
e.reserve_entity();
1342
// SAFETY: entity_location is left invalid
1343
unsafe { e.flush(|_, _| {}, MaybeLocation::caller(), Tick::default()) };
1344
assert_eq!(e.len(), 1);
1345
}
1346
1347
#[test]
1348
fn get_reserved_and_invalid() {
1349
let mut entities = Entities::new();
1350
let e = entities.reserve_entity();
1351
assert!(entities.contains(e));
1352
assert!(entities.get(e).is_none());
1353
1354
// SAFETY: entity_location is left invalid
1355
unsafe {
1356
entities.flush(
1357
|_entity, _location| {
1358
// do nothing ... leaving entity location invalid
1359
},
1360
MaybeLocation::caller(),
1361
Tick::default(),
1362
);
1363
};
1364
1365
assert!(entities.contains(e));
1366
assert!(entities.get(e).is_none());
1367
}
1368
1369
#[test]
1370
fn entity_const() {
1371
const C1: Entity = Entity::from_raw(EntityRow::new(NonMaxU32::new(42).unwrap()));
1372
assert_eq!(42, C1.index());
1373
assert_eq!(0, C1.generation().to_bits());
1374
1375
const C2: Entity = Entity::from_bits(0x0000_00ff_0000_00cc);
1376
assert_eq!(!0x0000_00cc, C2.index());
1377
assert_eq!(0x0000_00ff, C2.generation().to_bits());
1378
1379
const C3: u32 = Entity::from_raw(EntityRow::new(NonMaxU32::new(33).unwrap())).index();
1380
assert_eq!(33, C3);
1381
1382
const C4: u32 = Entity::from_bits(0x00dd_00ff_1111_1111)
1383
.generation()
1384
.to_bits();
1385
assert_eq!(0x00dd_00ff, C4);
1386
}
1387
1388
#[test]
1389
fn reserve_generations() {
1390
let mut entities = Entities::new();
1391
let entity = entities.alloc();
1392
entities.free(entity);
1393
1394
assert!(entities.reserve_generations(entity.index(), 1));
1395
}
1396
1397
#[test]
1398
fn reserve_generations_and_alloc() {
1399
const GENERATIONS: u32 = 10;
1400
1401
let mut entities = Entities::new();
1402
let entity = entities.alloc();
1403
entities.free(entity);
1404
1405
assert!(entities.reserve_generations(entity.index(), GENERATIONS));
1406
1407
// The very next entity allocated should be a further generation on the same index
1408
let next_entity = entities.alloc();
1409
assert_eq!(next_entity.index(), entity.index());
1410
assert!(next_entity
1411
.generation()
1412
.cmp_approx(&entity.generation().after_versions(GENERATIONS))
1413
.is_gt());
1414
}
1415
1416
#[test]
1417
#[expect(
1418
clippy::nonminimal_bool,
1419
reason = "This intentionally tests all possible comparison operators as separate functions; thus, we don't want to rewrite these comparisons to use different operators."
1420
)]
1421
fn entity_comparison() {
1422
assert_eq!(
1423
Entity::from_raw_and_generation(
1424
EntityRow::new(NonMaxU32::new(123).unwrap()),
1425
EntityGeneration::from_bits(456)
1426
),
1427
Entity::from_raw_and_generation(
1428
EntityRow::new(NonMaxU32::new(123).unwrap()),
1429
EntityGeneration::from_bits(456)
1430
)
1431
);
1432
assert_ne!(
1433
Entity::from_raw_and_generation(
1434
EntityRow::new(NonMaxU32::new(123).unwrap()),
1435
EntityGeneration::from_bits(789)
1436
),
1437
Entity::from_raw_and_generation(
1438
EntityRow::new(NonMaxU32::new(123).unwrap()),
1439
EntityGeneration::from_bits(456)
1440
)
1441
);
1442
assert_ne!(
1443
Entity::from_raw_and_generation(
1444
EntityRow::new(NonMaxU32::new(123).unwrap()),
1445
EntityGeneration::from_bits(456)
1446
),
1447
Entity::from_raw_and_generation(
1448
EntityRow::new(NonMaxU32::new(123).unwrap()),
1449
EntityGeneration::from_bits(789)
1450
)
1451
);
1452
assert_ne!(
1453
Entity::from_raw_and_generation(
1454
EntityRow::new(NonMaxU32::new(123).unwrap()),
1455
EntityGeneration::from_bits(456)
1456
),
1457
Entity::from_raw_and_generation(
1458
EntityRow::new(NonMaxU32::new(456).unwrap()),
1459
EntityGeneration::from_bits(123)
1460
)
1461
);
1462
1463
// ordering is by generation then by index
1464
1465
assert!(
1466
Entity::from_raw_and_generation(
1467
EntityRow::new(NonMaxU32::new(123).unwrap()),
1468
EntityGeneration::from_bits(456)
1469
) >= Entity::from_raw_and_generation(
1470
EntityRow::new(NonMaxU32::new(123).unwrap()),
1471
EntityGeneration::from_bits(456)
1472
)
1473
);
1474
assert!(
1475
Entity::from_raw_and_generation(
1476
EntityRow::new(NonMaxU32::new(123).unwrap()),
1477
EntityGeneration::from_bits(456)
1478
) <= Entity::from_raw_and_generation(
1479
EntityRow::new(NonMaxU32::new(123).unwrap()),
1480
EntityGeneration::from_bits(456)
1481
)
1482
);
1483
assert!(
1484
!(Entity::from_raw_and_generation(
1485
EntityRow::new(NonMaxU32::new(123).unwrap()),
1486
EntityGeneration::from_bits(456)
1487
) < Entity::from_raw_and_generation(
1488
EntityRow::new(NonMaxU32::new(123).unwrap()),
1489
EntityGeneration::from_bits(456)
1490
))
1491
);
1492
assert!(
1493
!(Entity::from_raw_and_generation(
1494
EntityRow::new(NonMaxU32::new(123).unwrap()),
1495
EntityGeneration::from_bits(456)
1496
) > Entity::from_raw_and_generation(
1497
EntityRow::new(NonMaxU32::new(123).unwrap()),
1498
EntityGeneration::from_bits(456)
1499
))
1500
);
1501
1502
assert!(
1503
Entity::from_raw_and_generation(
1504
EntityRow::new(NonMaxU32::new(9).unwrap()),
1505
EntityGeneration::from_bits(1)
1506
) < Entity::from_raw_and_generation(
1507
EntityRow::new(NonMaxU32::new(1).unwrap()),
1508
EntityGeneration::from_bits(9)
1509
)
1510
);
1511
assert!(
1512
Entity::from_raw_and_generation(
1513
EntityRow::new(NonMaxU32::new(1).unwrap()),
1514
EntityGeneration::from_bits(9)
1515
) > Entity::from_raw_and_generation(
1516
EntityRow::new(NonMaxU32::new(9).unwrap()),
1517
EntityGeneration::from_bits(1)
1518
)
1519
);
1520
1521
assert!(
1522
Entity::from_raw_and_generation(
1523
EntityRow::new(NonMaxU32::new(1).unwrap()),
1524
EntityGeneration::from_bits(1)
1525
) > Entity::from_raw_and_generation(
1526
EntityRow::new(NonMaxU32::new(2).unwrap()),
1527
EntityGeneration::from_bits(1)
1528
)
1529
);
1530
assert!(
1531
Entity::from_raw_and_generation(
1532
EntityRow::new(NonMaxU32::new(1).unwrap()),
1533
EntityGeneration::from_bits(1)
1534
) >= Entity::from_raw_and_generation(
1535
EntityRow::new(NonMaxU32::new(2).unwrap()),
1536
EntityGeneration::from_bits(1)
1537
)
1538
);
1539
assert!(
1540
Entity::from_raw_and_generation(
1541
EntityRow::new(NonMaxU32::new(2).unwrap()),
1542
EntityGeneration::from_bits(2)
1543
) < Entity::from_raw_and_generation(
1544
EntityRow::new(NonMaxU32::new(1).unwrap()),
1545
EntityGeneration::from_bits(2)
1546
)
1547
);
1548
assert!(
1549
Entity::from_raw_and_generation(
1550
EntityRow::new(NonMaxU32::new(2).unwrap()),
1551
EntityGeneration::from_bits(2)
1552
) <= Entity::from_raw_and_generation(
1553
EntityRow::new(NonMaxU32::new(1).unwrap()),
1554
EntityGeneration::from_bits(2)
1555
)
1556
);
1557
}
1558
1559
// Feel free to change this test if needed, but it seemed like an important
1560
// part of the best-case performance changes in PR#9903.
1561
#[test]
1562
fn entity_hash_keeps_similar_ids_together() {
1563
use core::hash::BuildHasher;
1564
let hash = EntityHash;
1565
1566
let first_id = 0xC0FFEE << 8;
1567
let first_hash = hash.hash_one(Entity::from_raw(EntityRow::new(
1568
NonMaxU32::new(first_id).unwrap(),
1569
)));
1570
1571
for i in 1..=255 {
1572
let id = first_id + i;
1573
let hash = hash.hash_one(Entity::from_raw(EntityRow::new(
1574
NonMaxU32::new(id).unwrap(),
1575
)));
1576
assert_eq!(first_hash.wrapping_sub(hash) as u32, i);
1577
}
1578
}
1579
1580
#[test]
1581
fn entity_hash_id_bitflip_affects_high_7_bits() {
1582
use core::hash::BuildHasher;
1583
1584
let hash = EntityHash;
1585
1586
let first_id = 0xC0FFEE;
1587
let first_hash = hash.hash_one(Entity::from_raw(EntityRow::new(
1588
NonMaxU32::new(first_id).unwrap(),
1589
))) >> 57;
1590
1591
for bit in 0..u32::BITS {
1592
let id = first_id ^ (1 << bit);
1593
let hash = hash.hash_one(Entity::from_raw(EntityRow::new(
1594
NonMaxU32::new(id).unwrap(),
1595
))) >> 57;
1596
assert_ne!(hash, first_hash);
1597
}
1598
}
1599
1600
#[test]
1601
fn entity_generation_is_approximately_ordered() {
1602
use core::cmp::Ordering;
1603
1604
let old = EntityGeneration::FIRST;
1605
let middle = old.after_versions(1);
1606
let younger_before_ord_wrap = middle.after_versions(EntityGeneration::DIFF_MAX);
1607
let younger_after_ord_wrap = younger_before_ord_wrap.after_versions(1);
1608
1609
assert_eq!(middle.cmp_approx(&old), Ordering::Greater);
1610
assert_eq!(middle.cmp_approx(&middle), Ordering::Equal);
1611
assert_eq!(middle.cmp_approx(&younger_before_ord_wrap), Ordering::Less);
1612
assert_eq!(
1613
middle.cmp_approx(&younger_after_ord_wrap),
1614
Ordering::Greater
1615
);
1616
}
1617
1618
#[test]
1619
fn entity_debug() {
1620
let entity = Entity::from_raw(EntityRow::new(NonMaxU32::new(42).unwrap()));
1621
let string = format!("{entity:?}");
1622
assert_eq!(string, "42v0");
1623
1624
let entity = Entity::PLACEHOLDER;
1625
let string = format!("{entity:?}");
1626
assert_eq!(string, "PLACEHOLDER");
1627
}
1628
1629
#[test]
1630
fn entity_display() {
1631
let entity = Entity::from_raw(EntityRow::new(NonMaxU32::new(42).unwrap()));
1632
let string = format!("{entity}");
1633
assert_eq!(string, "42v0");
1634
1635
let entity = Entity::PLACEHOLDER;
1636
let string = format!("{entity}");
1637
assert_eq!(string, "PLACEHOLDER");
1638
}
1639
}
1640
1641