bevyengine / bevyengine/bevy

State changes appear to have system order ambiguities

Open
#13,947 10 comments 0 reactions 0 assignees View on GitHub
A-ECS A-States C-Bug D-Complex S-Needs-Design
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## System Info

bevy 0.14.0-rc.2
Ubuntu 22.04

## Program

```rust
use bevy::{
input::{keyboard::KeyboardInput, mouse::MouseButtonInput, ButtonState},
prelude::*,
};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_state(S1::A)
.add_sub_state::()
.add_systems(Update, transition_to_s1_b_on_click.run_if(in_state(S1::A)))
.add_systems(Update, transition_to_s2_d_on_click.run_if(in_state(S2::C)))
.add_systems(Update, info_states)
.add_systems(Update, reset)
.run();
}

fn transition_to_s1_b_on_click(
mut mouse_events: EventReader,
mut ns_s1: ResMut>,
) {
for e in mouse_events.read() {
match e {
MouseButtonInput {
button: MouseButton::Left,
state: ButtonState::Pressed,
..
} => ns_s1.set(S1::B),
_ => {}
}
}
}

fn transition_to_s2_d_on_click(
mut mouse_events: EventReader,
mut ns_s2: ResMut>,
) {
for e in mouse_events.read() {
match e {
MouseButtonInput {
button: MouseButton::Left,
state: ButtonState::Pressed,
..
} => ns_s2.set(S2::D),
_ => {}
}
}
}

fn info_states(s1: Res>, s2: Option>>) {
info!("{:?}, {:?}", s1, s2);
}

fn reset(keyboard_input: Res>, mut ns_s1: ResMut>) {
if keyboard_input.just_pressed(KeyCode::Escape) {
ns_s1.set(S1::A);
}
}

#[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
enum S1 {
A,
B,
}

#[derive(SubStates, Debug, Clone, PartialEq, Eq, Hash, Default)]
#[source(S1 = S1::B)]
enum S2 {
#[default]
C,
D,
}
```

## Program summary:

state `S1` is set to `A`
state `S2` is a sub state of `S1` and has a default value of `C`
when the mouse is pressed, `S1` transitions to `B`

then sometimes, `S2` also transitions to `D`

## Output

I would expect the output to be:

```
2024-06-20T15:02:47.198639Z INFO gam: Res(State(A)), None
2024-06-20T15:02:47.213971Z INFO gam: Res(State(A)), None
2024-06-20T15:02:47.227818Z INFO gam: Res(State(A)), None

2024-06-20T15:02:47.254104Z INFO gam: Res(State(B)), Some(Res(State(C)))
2024-06-20T15:02:47.267907Z INFO gam: Res(State(B)), Some(Res(State(C)))
2024-06-20T15:02:47.280845Z INFO gam: Res(State(B)), Some(Res(State(C)))
```

but occasionally (apparently at random) the output is:

```
2024-06-20T15:10:34.521087Z INFO gam: Res(State(A)), None
2024-06-20T15:10:34.534237Z INFO gam: Res(State(A)), None
2024-06-20T15:10:34.547726Z INFO gam: Res(State(A)), None

2024-06-20T15:10:34.560954Z INFO gam: Res(State(B)), Some(Res(State(C)))
2024-06-20T15:10:34.587293Z INFO gam: Res(State(B)), Some(Res(State(D)))
2024-06-20T15:10:34.601005Z INFO gam: Res(State(B)), Some(Res(State(D)))
2024-06-20T15:10:34.613692Z INFO gam: Res(State(B)), Some(Res(State(D)))
```

("" is not logged)

(this is not a double press or anything like that, it happens consistently)

## My guess about what is happening in the expected output and why

The mouse click event happens and is in the first `EventReader`.
The state then changes to `S1::B`
The mouse click event leaves the `EventReader`
The `transition_to_s2_d_on_click` system runs
The mouse click event is no longer in the `EventReader`
The state does not change

## My guess about what is happening in the unexpected output and why

The mouse click event happens and is in the first `EventReader`.
The state then changes to `S1::B`
The `transition_to_s2_d_on_click` system runs
The mouse click event is still in the `EventReader`
The state changes to `S2::D`

Contributor guide

Open the contributing guide

Research direction

Start with the minimal reproduction in main, especially transition_to_s1_b_on_click, transition_to_s2_d_on_click, and info_states. Run it repeatedly with the shown mouse and keyboard inputs, then trace the state and event-reader ordering that produces the inconsistent output. Done should mean the behavior is deterministic and matches an explicitly tested expectation.

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
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.