Skip to content
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

FixedTimeStep systems do not honor their associated app state #8059

Closed
derchr opened this issue Mar 12, 2023 · 6 comments
Closed

FixedTimeStep systems do not honor their associated app state #8059

derchr opened this issue Mar 12, 2023 · 6 comments
Labels
A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior
Milestone

Comments

@derchr
Copy link

derchr commented Mar 12, 2023

Bevy version

0.10

What you did

Consider the following Bevy app:

use bevy::prelude::*;

#[derive(States, PartialEq, Eq, Debug, Default, Hash, Clone, Copy)]
enum AppState {
    #[default]
    First,
    Second,
}

fn main() {
    App::new()
        .add_plugins(MinimalPlugins)
        .insert_resource(FixedTime::new_from_secs(1.0))
        .add_state::<AppState>()
        .add_system(transition_state.in_set(OnUpdate(AppState::First)))
        .add_system(
            print_hello
                .in_schedule(CoreSchedule::FixedUpdate)
                .in_set(OnUpdate(AppState::Second)),
        )
        .run();
}

fn transition_state(time: Res<Time>, mut next_state: ResMut<NextState<AppState>>) {
    if time.elapsed_seconds() > 3.0 {
        println!("Transition state!");
        next_state.set(AppState::Second);
    }
}

fn print_hello() {
    println!("Hello!");
}

What went wrong

The print_hello system runs regardless of the application state. It should only run in the AppState::Second state but it runs also in the AppState::First state.
The following output is generated:

Hello!
Hello!
Transition state!
Hello!
Hello!

If line the line with .in_schedule(CoreSchedule::FixedUpdate) is commented out, the output is:

Transition state!
Hello!
Hello!
Hello!

It's as expected. But of course the system is now run every frame.

@derchr derchr added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Mar 12, 2023
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events and removed S-Needs-Triage This issue needs to be labelled labels Mar 12, 2023
@alice-i-cecile
Copy link
Member

Does this work if you use a .run_if(in_state(AppState::Second)) instead? OnUpdate was really only ever intended for the main schedule.

@alice-i-cecile alice-i-cecile added this to the 0.11 milestone Mar 12, 2023
@derchr
Copy link
Author

derchr commented Mar 12, 2023

Does this work if you use a .run_if(in_state(AppState::Second)) instead?

Yes, then it works. Thanks!

@bschwind
Copy link

@alice-i-cecile I'm trying to run a set of systems only when the game is in a certain state, and with a fixed timestep.

First I tried this:

app.add_systems(
    (
        system_a,
        system_b,
        system_c,
    )
    .in_set(labels::Lobby)
    .after(labels::Network)
    .in_set(OnUpdate(GameState::Lobby))
    .in_schedule(CoreSchedule::FixedUpdate)
)

which led me to this issue.

Then I tried

app.add_systems(
    (
        system_a,
        system_b,
        system_c,
    )
    .in_set(labels::Lobby)
    .after(labels::Network)
    .run_if(in_state(GameState::Lobby))
    .in_schedule(CoreSchedule::FixedUpdate)
)

Which gave me some unsatisfied trait bounds:

358 | pub struct SystemConfigs {
    | ------------------------
    | |
    | doesn't satisfy `SystemConfigs: IntoSystem<(), (), _>`
    | doesn't satisfy `SystemConfigs: IntoSystemConfig<_>`
    |
    = note: the following trait bounds were not satisfied:
            `SystemConfigs: IntoSystem<(), (), _>`
            which is required by `SystemConfigs: IntoSystemConfig<_>`
            `&SystemConfigs: IntoSystem<(), (), _>`
            which is required by `&SystemConfigs: IntoSystemConfig<_>`
            `&mut SystemConfigs: IntoSystem<(), (), _>`
            which is required by `&mut SystemConfigs: IntoSystemConfig<_>`

I found distributive_run_if() and tried that:

app.add_systems(
    (
        system_a,
        system_b,
        system_c,
    )
    .in_set(labels::Lobby)
    .after(labels::Network)
    .distributive_run_if(in_state(GameState::Lobby))
    .in_schedule(CoreSchedule::FixedUpdate)
)

which gave:

error[E0277]: the trait bound `impl for<'a> FnMut(Res<'a, State<GameState>>) -> bool: Clone` is not satisfied
   --> server/src/systems/lobby.rs:59:38
    |
59  |                 .distributive_run_if(in_state(GameState::Lobby))
    |                  ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl for<'a> FnMut(Res<'a, State<GameState>>) -> bool`
    |                  |
    |                  required by a bound introduced by this call
    |
note: required by a bound in `distributive_run_if`
   --> /Users/brian/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/bevy_ecs-0.10.0/src/schedule/config.rs:425:68
    |
425 |     fn distributive_run_if<M>(self, condition: impl Condition<M> + Clone) -> SystemConfigs {
    |                                                                    ^^^^^ required by this bound in `distributive_run_if`
help: use parentheses to call this opaque type
    |
59  |                 .distributive_run_if(in_state(GameState::Lobby)(/* Res<'_, State<GameState>> */))
    |                                                                +++++++++++++++++++++++++++++++++

For more information about this error, try `rustc --explain E0277`.
error: could not compile `sus-server` due to previous error

At this point I'm not sure of the best way to specify that a set of systems should run on a fixed timestep, and only while in a certain state.

If the answer is currently "add the run_if condition on every system in the set", that's totally fine. Just wanted to make sure I wasn't missing something else that'll solve the problem.

Thanks so much for your work on the new stageless API, it's been really cool to see my bevy code shrink in size while remaining functionally the same (along with gaining new ergonomics!)

@st0rmbtw
Copy link
Contributor

@bschwind There is an issue about that #8058.
Before it fixed, you can use:

distributive_run_if(|state: Res<State<GameState>>>| *state == GameState::Lobby)

@bschwind
Copy link

@st0rmbtw nice! I changed *state to state.0 and it worked perfectly.

@hymm
Copy link
Contributor

hymm commented Apr 16, 2023

@alice-i-cecile can this be closed now that #8260 has been merged?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior
Projects
None yet
Development

No branches or pull requests

5 participants