bevy/release-content/migration-guides/entities_apis.md
Elliott Pierce 4c0d752547 More suggestions from review
Co-Authored-By: urben1680 <55257931+urben1680@users.noreply.github.com>
2025-07-09 08:11:55 -04:00

3.6 KiB

title pull_requests
Entities APIs
19350
19433
19451

In 0.16, entities could have zero or more components. In 0.17, a new state for an entity is introduced: null/not constructed. Entities can now be constructed and destructed within their spawned life cycle. For a full explanation of the new entity life cycle, see the new entity module docs. This opens up a lot of room for performance improvement but also caused a lot of breaking changes:

Entities rework

A lot has changed here. First, alloc, free, reserve, reserve_entity, reserve_entities, flush, flush_as_invalid, total_count, used_count, and total_prospective_count have all been removed. Allocation and freeing have been made private, but there are new ways to accomplish this. Reservation and flushing have been completely removed as they are no longer needed. Instead of reserving an entity and later flushing it, you can World::spawn_null (which does not need mutable access), and World::construct can be used to "flush" the null entity. The counting methods have been reworked in the absence of flushing: len and is_empty now deal with how many entity rows have been allocated (not necessarily the number that have been constructed/spawned), and the new count_constructed and any_constructed are similar to the old len and is_empty behavior. In terms of getting information from Entities, get and contains has been reworked to include non-constructed entities. If you only want constructed entities, get_constructed and contains_constructed are available. Additionally, get now returns Result<EntityIdLocation, EntityDoesNotExistError> instead of Option<EntityLocation> for clarity. EntityIdLocation is an alias for Option<EntityLocation>, as entities now may or may not have a location, depending on if it is constructed or not.

EntityDoesNotExistError::location has been replaced by EntityDoesNotExistError::generation of type EntityGeneration. This is because a not constructed entity is now still considered to exist. The only way an Entity can not exist is if it has the wrong generation; the right one is now in EntityDoesNotExistError::generation. If you only want constructed entities, the new ConstructedEntityDoesNotExistError is available.

As an alternative to free, simply create a EntityWorldMut (if it fails, it's already been freed), and despawn it. If the entity was already destructed, despawning will just free the entity internally.

Entity Pointers

All entity pointers location information has changed from EntityLocation to EntityIdLocation, as they can now point to non-constructed entities. This extends to archetypes too, many .archetype methods now return Option<&Archetype>. Notably, EntityWorldMut continues to have panicking methods which assume the entity is constructed.

Entity Commands

Commands::new_from_entities now also needs &EntitiesAllocator, which can be obtained from UnsafeWorldCell::entities_allocator. Commands::get_entity does not error for non-constructed entities. If you only want constructed entities, use Commands::get_constructed_entity

Other entity interactions

BundleSpawner::spawn_non_existent is now BundleSpawner::construct. World::inspect_entity now errors with ConstructedEntityDoesNotExistError instead of EntityDoesNotExistError. QueryEntityError::EntityDoesNotExist now wraps ConstructedEntityDoesNotExistError. EntityDespawnError has been renamed to EntityDestructError. ComputeGlobalTransformError::NoSuchEntity and ComputeGlobalTransformError::MalformedHierarchy now wrap ConstructedEntityDoesNotExistError.