-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Systems set to run on state resume do not respect .after()
constraints
#6130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
|
I didn't know that was possible, how do I do that? |
I tried this which doesn't seem to work either. .add_system_set(SystemSet::on_resume(AppState::MainMenu).after(on_previous_menu_event).with_system(on_resume)) |
I tried reproducing with the code below, but it behaves as i would expect. Spoileruse std::time::Duration;
use bevy::prelude::*;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
enum AppState {
One,
Two,
}
fn system_a(mut state: ResMut<State<AppState>>) {
match state.current() {
AppState::One => {
println!("push two");
let _ = state.push(AppState::Two);
}
AppState::Two => {
println!("resuming one");
let _ = state.pop();
}
}
println!("a");
std::thread::sleep(Duration::from_millis(500));
}
fn system_b() {
println!("b");
std::thread::sleep(Duration::from_millis(500));
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_state(AppState::One)
.add_system(system_a)
.add_system_set(SystemSet::on_resume(AppState::One).with_system(system_b.after(system_a)))
.run();
} |
I'll try to create a minimal reproduceable example, thanks a lot for that code sample. I'll build off on that to get something that better matches my code. |
In the process of trying to emonstrate this bug, I believe I may have found another one. use std::time::Duration;
use bevy::prelude::*;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
enum AppState {
MainMenu,
Options,
}
fn display_options_menu(mut state: ResMut<State<AppState>>) {
std::thread::sleep(Duration::from_millis(500));
println!("Switching to options menu");
state.push(AppState::Options).unwrap();
}
fn resume_main_menu() {
println!("Resuming main menu state");
}
struct PreviousMenuEvent;
fn return_to_main_menu(
mut state: ResMut<State<AppState>>,
mut prev_menu_evt: EventWriter<PreviousMenuEvent>,
) {
// std::thread::sleep(Duration::from_millis(500));
println!("Returning to main menu");
prev_menu_evt.send(PreviousMenuEvent);
state.pop().unwrap();
}
fn on_previous_menu_event(mut prev_menu_evt: EventReader<PreviousMenuEvent>) {
println!("Running on_previous_menu_event system");
for _ev in prev_menu_evt.iter() {
println!("Got previous menu event");
}
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_event::<PreviousMenuEvent>()
.add_system(on_previous_menu_event)
.add_state(AppState::MainMenu)
.add_system_set(SystemSet::on_update(AppState::MainMenu).with_system(display_options_menu))
.add_system_set(
SystemSet::on_update(AppState::Options)
.with_system(return_to_main_menu.before(on_previous_menu_event)),
)
.add_system_set(
SystemSet::on_resume(AppState::MainMenu)
.with_system(resume_main_menu.after(on_previous_menu_event)),
)
.run();
} In this example, the bug I intended to demonstrate was However when I run this example, the |
When a state transition happens it re-runs Jeez. The state stuff is super prone to footguns and nothing is documented :/ |
I'm very confused that I'll refactor it so that it doesn't run during a state update and see if that fixes it. |
I've reproduced the problem, where the resume code runs before the event is received. Although now I suspect that the event being received only after returning to the main menu is just due to the order that
However, this doesn't explain why the .after constraint on use bevy::prelude::*;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
enum AppState {
MainMenu,
Options,
}
fn switch_menus(
mut state: ResMut<State<AppState>>,
mut input: ResMut<Input<KeyCode>>,
mut prev_menu_evt: EventWriter<PreviousMenuEvent>,
) {
if !input.just_pressed(KeyCode::Return) {
return;
}
input.clear();
match state.current() {
AppState::MainMenu => {
println!("Switching to options menu");
state.push(AppState::Options);
}
AppState::Options => {
println!("Returning to main menu");
prev_menu_evt.send(PreviousMenuEvent);
state.pop().unwrap();
}
}
}
fn resume_main_menu() {
println!("Resuming main menu state");
}
struct PreviousMenuEvent;
fn on_previous_menu_event(mut prev_menu_evt: EventReader<PreviousMenuEvent>) {
// println!("Running on_previous_menu_event system");
for _ev in prev_menu_evt.iter() {
println!("Got previous menu event");
}
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_event::<PreviousMenuEvent>()
.add_system(on_previous_menu_event)
.add_state(AppState::MainMenu)
.add_system_set(SystemSet::on_update(AppState::MainMenu).with_system(switch_menus))
.add_system_set(SystemSet::on_update(AppState::Options).with_system(switch_menus))
.add_system_set(
SystemSet::on_resume(AppState::MainMenu)
.with_system(resume_main_menu.after(on_previous_menu_event)),
)
.run();
} I can work around this issue, e.g by using |
Obsoleted by #7267. On enter / on exit systems are now found their own schedules. |
Bevy version
0.8.1
What you did
Describe how you arrived at the problem. If you can, consider providing a code snippet or link.
I have my game menus each have a corresponding AppState. For example, there is a state for options menu, main menu etc.
I have two systems:
on_previous_menu_event
which I need ran beforeon_resume
, which gets ran when I resume a state.I tried to achieve this by doing the following:
The ordering is required for the logic to work correctly.
What went wrong
By inserting print statements into both systems, I see that about half the time, the systems are ran in the opposite order in which I declared above.
Additional information
Other information that can be used to further reproduce or isolate the problem.
This commonly includes:
The text was updated successfully, but these errors were encountered: