MapEntities for components containing HashMap behaving strangely
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## Bevy version
12.1
## \[Optional\] Relevant system information
Rust versoin = 1.74
## What you did
I have a custom component `TeamStatus`, with an internal HashMap keyed by Entity.
```rust
#[derive(Component, Debug, Default, Deref, DerefMut, Reflect)]
#[reflect(Component, MapEntities)]
pub struct TeamStatus(pub HashMap);
impl MapEntities for TeamStatus {
fn map_entities(&mut self, entity_mapper: &mut bevy::ecs::entity::EntityMapper) {
self.0 = self
.0
.iter()
.map(|(id, status)| {
let new_id = entity_mapper.get_or_reserve(id);
log::debug!("NOCOMMIT TEAM_STATUS {id:?} -> {new_id:?}");
(*new_id, *status)
})
.collect();
}
}
```
I have a scene file with this component defined:
```ron
0: (
"game_core::node::TeamStatus": ({
1: Undecided,
2: Undecided,
}),
...
1: ...
2: ...
)
```
## What went wrong
When I load the scene, it works just fine and ouputs this to logs:
```
17:51:44 [DEBUG] (1) game_core::node: NOCOMMIT TEAM_STATUS 1v0 -> 39v0
17:51:44 [DEBUG] (1) game_core::node: NOCOMMIT TEAM_STATUS 2v0 -> 40v0
```
But when I make an edit to the scene file (In an unrelated component), I get these logs:
```
17:52:44 [DEBUG] (1) game_core::node: NOCOMMIT TEAM_STATUS 39v0 -> 89v12
17:52:44 [DEBUG] (1) game_core::node: NOCOMMIT TEAM_STATUS 40v0 -> 89v13
17:52:44 [DEBUG] (1) game_core::node: NOCOMMIT TEAM_STATUS 1v0 -> 39v0
17:52:44 [DEBUG] (1) game_core::node: NOCOMMIT TEAM_STATUS 2v0 -> 40v0
```
And I have a system that detects changes of this component and outputs a debug message, showing that this was all applied to the same component:
```
TEAM STATUS CHANGED {39v0: Undecided, 40v0: Undecided, 89v12: Undecided, 89v13: Undecided}
```
I would expect it to only have the entities 39v0 and 40v0, without the obviously dead entities.
## Additional information
I'm currently doing a work around where instead of reserving dead entities if the entity doesn't exist, I simply filter them out of the HashMap. However I am curious about to how this came about, it seems like the serialized component is somehow being merged with the existing component, and I'm sure this isn't expected behavior.
Oh, and this is bevy::utils::HashMap, not the std::collections::HashMap
Contributor guide
Research direction
Start with scene loading and the MapEntities implementation using EntityMapper, comparing the initial load with the unrelated scene edit described in the report. Trace how the reflected TeamStatus component is deserialized and applied, and verify that reloading leaves only the current mapped entities rather than merging dead entries into the HashMap.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100