Add `World::entity_scope` to split the borrow on the `World` by extracting a single entity
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## What problem does this solve or what need does it fill?
When working with avatar-centric games (like platformers or FPS games), one object (the player avatar) is typically wildly more complex and important than others. Writing exclusive systems that fetch "the player" and operate on it in a game-object style can be an effective programming pattern.
In order to make this work, we often want to access that highly important entity, and relate it to "everything else around it". The current most obvious pattern is to fetch that data, clone or remove it out of the world, and then operate on it.
## What solution would you like?
Add `World::entity_scope`, which works like [`resource_scope`](https://docs.rs/bevy/latest/bevy/ecs/world/struct.World.html#method.resource_scope), but returns an `EntityMut` instead of a resource, in addition to a reference to the rest of the world.
This could be done by removing and then re-adding the entity but:
1. We need to avoid blanket-triggering change detection on all of the components: adding / inserting the object is
2. The `Entity` id of the object should remain unchanged.
A strong form of entity disabling (#11090), which makes it *fully* impossible to access the data of the object would be a clean way to do this, but would have more significant architectural implications. This would also come with less caveats: being able to add children to the requested entity without immediately panicking would be great.
## What alternative(s) have you considered?
An `EntityWorldMut` would be strictly more powerful, and makes more conceptual sense: being able to freely add and remove components would be really useful. However, actually providing that access is fundamentally unsound with the archetypal ECS that Bevy uses: changing this data requires changes to the metadata of the component storage itself, and requires a true hard lock.
Users could manually implement this pattern, by despawning and then spawning the player object, but without a way to clone entities (#1515) or otherwise extract all of their component, actually doing so is tedious.
Furthermore, any existing references to that entity (such as `Parent` components!) will break, since the `Entity` ID will be changed.
Change detection will also be triggered on *every* component, effectively rendering it useless for their game object style entity.
## Additional context
This is a conceptual sister to https://github.com/bevyengine/bevy/issues/13127: both are in the service of making the "get and work with a single entity in a loosely typed way" workflow easier.
Performance is always nice, but is a secondary concern for this style of API.
An equivalent `hierarchy_scope`, which extracts a whole tree of entities, is probably useful down the line as well: player objects are often conceptually composed of complete trees in order to support complex animated models.
Contributor guide
Research direction
Start by studying the linked World::resource_scope API and the entity-disabling discussion in issue #11090. Define an entity_scope design that preserves the entity ID, avoids blanket change detection, and provides access to the remaining World without exposing unsound component-storage mutations; consider the related workflow in issue #13127.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- game-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100