State changes appear to have system order ambiguities
- 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
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