bevyengine / bevyengine/bevy

Mutating (or Inserting) pre-existing Components in Observers silently fails with stale Component data

Open
#18,819 4 comments 0 reactions 0 assignees View on GitHub
A-ECS C-Bug S-Needs-Investigation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## Bevy version

* bevy 0.16-rc.4
* bevy 0.15

This issue occurs in both 0.16 and 0.15 so I haven't added it to a milestone since it seems pre-existing.

## What you did

Repro repo: https://github.com/ChristopherBiscardi/scene-observer-bug

This repo uses some gltf content (small, but just a json blob so minimized here)

```json
{
"asset": {
"generator": "Khronos glTF Blender I/O v4.4.55",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"name": "Scene",
"nodes": [0]
}
],
"nodes": [
{
"camera": 0,
"name": "Camera",
"rotation": [
-0.20997299253940582, 0.3857799470424652, 0.09062844514846802,
0.8937962055206299
],
"translation": [7.358891487121582, 4.958309173583984, 6.925790786743164]
}
],
"cameras": [
{
"name": "Camera",
"perspective": {
"aspectRatio": 1.7777777777777777,
"yfov": 0.39959648408210363,
"zfar": 100,
"znear": 0.10000000149011612
},
"type": "perspective"
}
]
}
```

The scene only contains a camera. (I have also seen this issue with PointLights).

An observer listens to the `OnAdd` event for the `Camera` component and tries to mutate it to enable `hdr`.

```rust
app.add_observer(
|trigger: Trigger,
mut cameras: Query<&mut Camera>,
mut commands: Commands|
-> Result {
dbg!(&trigger.target());
let mut camera = cameras.get_mut(trigger.target())?;
// This hdr value does not persist
camera.hdr = true;
commands.entity(trigger.target()).insert(Bloom::default());
// perhaps you think this might work instead;
// it does not, but will trigger an OnInsert with the new value
// .insert(Camera {
// hdr: true,
// ..default()
// });
Ok(())
},
);
```

By contrast, a system run in response to input *can* change this value.

## What went wrong

The `Camera` component `OnAdd` fires, and the value is modified but this new value is not present in the actual inserted Component value. The `hdr` value is always false.

If you try to "override" the `Camera` component by wholly inserting a new one it also does not persist. Additionally, if the event is switched to `OnInsert` this causes a stack overflow (as expected) and the hdr value reads as true in future `OnInsert` iterations. This means the `OnInsert` is seeing the new Component value with `hdr: true`, but the final value in the scene is using the old, original value.

## Additional information

*new* components are successfully inserted. For example, the `Bloom` component used in the reproduction.

Actual Output does *not* have hdr

![Image](https://github.com/user-attachments/assets/d56eefa9-8d83-4d33-b930-55e2483d07de)

Expected output *should* have hdr

![Image](https://github.com/user-attachments/assets/71fa2b97-e7bf-4033-9120-86b542fd1998)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.