Skip to content

Adding run criteria to SystemSet::on_exit overwrites existing one #2609

@wilk10

Description

@wilk10

Bevy version

Checked on 0.5 and main.

Operating system & version

MacOS 11.4

What you did

use bevy::{ecs::schedule::ShouldRun, prelude::*};

fn main() {
    App::build()
        .add_plugins(MinimalPlugins)
        .add_state(MyState::S1)
        .add_system_set(
            SystemSet::on_enter(MyState::S1)
                .with_system(exit_state_1.system())
        )
        .add_system_set(
            SystemSet::on_exit(MyState::S1)
                .with_run_criteria(check.system())
                .with_system(success.system())
        )
        .run();
}

struct Foo;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum MyState {
    S1,
    S2,
}

fn exit_state_1(mut commands: Commands, mut state: ResMut<State<MyState>>) {
    commands.spawn().insert(Foo);
    state.set(MyState::S2).unwrap();
}

fn check(foo: Query<&Foo>) -> ShouldRun {
    dbg!(foo.iter().count());
    match foo.single() {
        Ok(_) => {
            println!("running");
            ShouldRun::Yes
        },
        Err(_) => {
            println!("not running");
            ShouldRun::No
        },
    }
}

fn success(foo: Query<&Foo>) {
    if let Ok(_) = foo.single() {
        println!("hurray");
        panic!("terminate");
    }
}

What you expected to happen

To print

running
hurray
thread 'Compute Task Pool (1)' panicked at 'terminate', src/main.rs:48:9

What actually happened

It loops indefinitely, printing:

[src/main.rs:33] foo.iter().count() = 0
not running

Additional information

I think the crux of the issue is that when building the SystemSet, with_run_criteria is called:

pub fn on_exit<T>(s: T) -> SystemSet
where
T: Component + Debug + Clone + Eq + Hash,
{
Self::new().with_run_criteria(State::<T>::on_exit(s))
}

but then when i add my own with_run_criteria, it is overwritten here:

pub fn with_run_criteria<Marker>(mut self, run_criteria: impl IntoRunCriteria<Marker>) -> Self {
self.run_criteria = Some(run_criteria.into());
self
}

So it's not run on State exit, and so it's run before it can detect the entity with Foo(i think).

Maybe a solution could be to pipe the custom run criteria on the one added on SystemSet init? That would be my preferred, if possible. Or if that's not possible/intended, perhaps to remove with_run_criteria from the public API for SystemSets?

Hope this is useful.
There's a tiny bit more information here
Thanks a lot!

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-BugAn unexpected or incorrect behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions