`NextState<T>` event gets silently dropped under specific conditions
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## Bevy version
bevy = "0.15.0"
## What you did
Requested `ResMut>` in system where `T` is a `SubStates` and this substate is not "active" yet.
## What went wrong
System with `ResMut>` will get executed, next state set but no state transition/warn will happen.
## Additional information
This code
```rust
use std::any::type_name;
use bevy::{
log::LogPlugin,
prelude::*,
state::{app::StatesPlugin, state::FreelyMutableState},
};
fn main() {
let mut app = App::new();
app.add_plugins((MinimalPlugins, StatesPlugin, LogPlugin::default()))
.init_state::()
.add_sub_state::()
.add_sub_state::()
.add_systems(Update, ping(LeftInnerState::Right).run_if(run_once))
.add_systems(OnEnter(LeftInnerState::Right), pong(LeftInnerState::Right))
.add_systems(Update, ping(RightInnerState::Left).run_if(run_once))
.add_systems(OnEnter(RightInnerState::Left),pong(RightInnerState::Left))
.add_systems(Update, warn_me.run_if(run_once));
app.update();
app.update();
app.update();
}
fn ping(next: S) -> impl FnMut(ResMut>) {
move |mut next_state| {
next_state.set(next.clone());
info!("ping: {}::{:?}", type_name::(), next.clone())
}
}
fn pong(from: S) -> impl FnMut() {
move || info!("pong: {}::{:?}", type_name::(), from.clone())
}
#[derive(Debug, Default, States, Hash, PartialEq, Eq, Clone)]
enum OuterState {
#[default]
Left,
Right,
}
#[derive(Debug, Default, SubStates, Hash, PartialEq, Eq, Clone)]
#[source(OuterState = OuterState::Left)]
enum LeftInnerState {
#[default]
Left,
Right,
}
#[derive(Debug, Default, SubStates, Hash, PartialEq, Eq, Clone)]
#[source(OuterState = OuterState::Right)]
enum RightInnerState {
Left,
#[default]
Right,
}
fn warn_me(_: Res>) {}
```
produces this:
```
2024-12-02T17:07:47.826948Z INFO bevy_silent_event_drop_test: ping: bevy_silent_event_drop_test::RightInnerState::Left
2024-12-02T17:07:47.826948Z WARN bevy_ecs::system::function_system: bevy_silent_event_drop_test::warn_me did not run because it requested inaccessible system parameter Res>
2024-12-02T17:07:47.827291Z INFO bevy_silent_event_drop_test: ping: bevy_silent_event_drop_test::LeftInnerState::Right
2024-12-02T17:07:47.827927Z INFO bevy_silent_event_drop_test: pong: bevy_silent_event_drop_test::LeftInnerState::Right
```
From that 1 line is missing:
1. `INFO pong from bevy_silent_event_drop_test::RightInnerState::Left`
or
2. `WARN bevy_ecs::system::function_system: bevy_silent_event_drop_test::ping did not run because it requested inaccessible system parameter ResMut>`
or
3. `WARN received next state event for subsstate which is currently inaccessible due to it's parent not being in right state or something`
It should be 2 or 3.
Contributor guide
Research direction
Start with the minimal App reproduction in the issue and trace StatesPlugin, add_sub_state, and ResMut> handling when the parent state is inactive. Done means the inaccessible substate request is no longer silently dropped and produces the expected transition or warning, with the reproduction confirming the behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100