Skip to content

Replace VisitEntities with MapEntities #18432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 21, 2025

Conversation

cart
Copy link
Member

@cart cart commented Mar 20, 2025

Objective

There are currently too many disparate ways to handle entity mapping, especially after #17687. We now have MapEntities, VisitEntities, VisitEntitiesMut, Component::visit_entities, Component::visit_entities_mut.

Our only known use case at the moment for these is entity mapping. This means we have significant consolidation potential.

Additionally, VisitEntitiesMut cannot be implemented for map-style collections like HashSets, as you cant "just" mutate a &mut Entity. Our current approach to Component mapping requires VisitEntitiesMut, meaning this category of entity collection isn't mappable. MapEntities is more generally applicable. Additionally, the existence of the blanket From impl on VisitEntitiesMut blocks us from implementing MapEntities for HashSets (or any types we don't own), because the owner could always add a conflicting impl in the future.

Solution

Use MapEntities everywhere and remove all "visit entities" usages.

  • Add Component::map_entities
  • Remove Component::visit_entities, Component::visit_entities_mut, VisitEntities, and VisitEntitiesMut
  • Support deriving Component::map_entities in #[derive(Coomponent)]
  • Add #[derive(MapEntities)], and share logic with the Component::map_entities derive.
  • Add ComponentCloneCtx::queue_deferred, which is command-like logic that runs immediately after normal clones. Reframe FromWorld fallback logic in the "reflect clone" impl to use it. This cuts out a lot of unnecessary work and I think justifies the existence of a pseudo-command interface (given how niche, yet performance sensitive this is).

Note that we no longer auto-impl entity mapping for IntoIterator<Item = &'a Entity> types, as this would block our ability to implement cases like HashMap. This means the onus is on us (or type authors) to add explicit support for types that should be mappable.

Also note that the Component-related changes do not require a migration guide as there hasn't been a release with them yet.

Migration Guide

If you were previously implementing VisitEntities or VisitEntitiesMut (likely via a derive), instead use MapEntities. Those were almost certainly used in the context of Bevy Scenes or reflection via ReflectMapEntities. If you have a case that uses VisitEntities or VisitEntitiesMut directly, where MapEntities is not a viable replacement, please let us know!

// before
#[derive(VisitEntities, VisitEntitiesMut)]
struct Inventory {
  items: Vec<Entity>,
  #[visit_entities(ignore)]
  label: String,
}

// after
#[derive(MapEntities)]
struct Inventory {
  #[entities]
  items: Vec<Entity>,
  label: String,
}

@cart cart added A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use labels Mar 20, 2025
@cart cart added this to the 0.16 milestone Mar 20, 2025
@cart cart changed the title Component::map_entities and remove VisitEntities Replace VisitEntities with MapEntities Mar 20, 2025
@alice-i-cecile alice-i-cecile added M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Mar 20, 2025
@Brezak
Copy link
Contributor

Brezak commented Mar 20, 2025

I've opened up a pull request on this pull request to implement MapEntities on EntityHashSet so we can finally use it for relationships.

Copy link
Contributor

@Shatur Shatur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm excited about this change!

@cart
Copy link
Member Author

cart commented Mar 20, 2025

@Brezak

I've opened up a cart#33 on this pull request to implement MapEntities on EntityHashSet so we can finally use it for relationships.

I'm going to hold off on merging this, as I think I'd like to walk back the EntityHashSet wrapper type and use a type alias instead, which would allow us to use the general hashset impl instead.

@cart cart added this pull request to the merge queue Mar 20, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 20, 2025
@cart cart added this pull request to the merge queue Mar 20, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 20, 2025
@cart cart enabled auto-merge March 20, 2025 23:59
@cart cart added this pull request to the merge queue Mar 21, 2025
Merged via the queue into bevyengine:main with commit a033f1b Mar 21, 2025
32 checks passed
mockersf pushed a commit that referenced this pull request Mar 23, 2025
# Objective

There are currently too many disparate ways to handle entity mapping,
especially after #17687. We now have MapEntities, VisitEntities,
VisitEntitiesMut, Component::visit_entities,
Component::visit_entities_mut.

Our only known use case at the moment for these is entity mapping. This
means we have significant consolidation potential.

Additionally, VisitEntitiesMut cannot be implemented for map-style
collections like HashSets, as you cant "just" mutate a `&mut Entity`.
Our current approach to Component mapping requires VisitEntitiesMut,
meaning this category of entity collection isn't mappable. `MapEntities`
is more generally applicable. Additionally, the _existence_ of the
blanket From impl on VisitEntitiesMut blocks us from implementing
MapEntities for HashSets (or any types we don't own), because the owner
could always add a conflicting impl in the future.

## Solution

Use `MapEntities` everywhere and remove all "visit entities" usages.

* Add `Component::map_entities`
* Remove `Component::visit_entities`, `Component::visit_entities_mut`,
`VisitEntities`, and `VisitEntitiesMut`
* Support deriving `Component::map_entities` in `#[derive(Coomponent)]`
* Add `#[derive(MapEntities)]`, and share logic with the
`Component::map_entities` derive.
* Add `ComponentCloneCtx::queue_deferred`, which is command-like logic
that runs immediately after normal clones. Reframe `FromWorld` fallback
logic in the "reflect clone" impl to use it. This cuts out a lot of
unnecessary work and I think justifies the existence of a pseudo-command
interface (given how niche, yet performance sensitive this is).

Note that we no longer auto-impl entity mapping for ` IntoIterator<Item
= &'a Entity>` types, as this would block our ability to implement cases
like `HashMap`. This means the onus is on us (or type authors) to add
explicit support for types that should be mappable.

Also note that the Component-related changes do not require a migration
guide as there hasn't been a release with them yet.

## Migration Guide

If you were previously implementing `VisitEntities` or
`VisitEntitiesMut` (likely via a derive), instead use `MapEntities`.
Those were almost certainly used in the context of Bevy Scenes or
reflection via `ReflectMapEntities`. If you have a case that uses
`VisitEntities` or `VisitEntitiesMut` directly, where `MapEntities` is
not a viable replacement, please let us know!

```rust
// before
#[derive(VisitEntities, VisitEntitiesMut)]
struct Inventory {
  items: Vec<Entity>,
  #[visit_entities(ignore)]
  label: String,
}

// after
#[derive(MapEntities)]
struct Inventory {
  #[entities]
  items: Vec<Entity>,
  label: String,
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-Review Needs reviewer attention (from anyone!) to move forward
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants