bevyengine / bevyengine/bevy

MapEntities for components containing HashMap behaving strangely

Open
#10,995 2 comments 0 reactions 0 assignees View on GitHub
A-ECS A-Scenes C-Bug S-Needs-Investigation
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.