Skip to content

Systems ordering is unreliable with states and on_event #8606

@uvizhe

Description

@uvizhe

Bevy version

0.10.1

What you did

I'm working on a game and have recently found that my systems sometimes run in a wrong order, although chained (with chain()). I tried to reproduce this from the ground but failed to achieve the same behavior, however I hit something very similar (the code below):

Here's the code that runs 3 identical and chained systems on the same event
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(MinimalPlugins)
        .add_state::<AppState>()
        .add_event::<MyEvent>()
        .init_resource::<EventTriggerState>()
        .add_system(event_trigger.run_if(in_state(AppState::Events)))
        .add_systems(
            (
                event_listener1,
                event_listener2,
                event_listener3,
            )
                .chain()
                .distributive_run_if(on_event::<MyEvent>())
                .in_set(OnUpdate(AppState::Events))
        )
        .run();
}

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

struct MyEvent;

#[derive(Resource)]
struct EventTriggerState {
    event_timer: Timer,
}

impl Default for EventTriggerState {
    fn default() -> Self {
        EventTriggerState {
            event_timer: Timer::from_seconds(1.0, TimerMode::Repeating),
        }
    }
}

// sends MyEvent every second
fn event_trigger(
    time: Res<Time>,
    mut my_events: EventWriter<MyEvent>,
    mut state: ResMut<EventTriggerState>,
) {
    if state.event_timer.tick(time.delta()).finished() {
        my_events.send(MyEvent);
        println!("========");
    }
}

fn event_listener1() {
    println!("system 1");
}

fn event_listener2() {
    println!("system 2");
}

fn event_listener3() {
    println!("system 3");
}

On one of several runs it outputs the following:

========
system 2
system 3
system 1
========
system 2
system 3
system 1
========
system 2
system 3
system 1
...

It never outputs anything different from this or what is expected (123).

Introducing a state is necessary for this to reproduce (along with adding relevant .in_set(OnUpdate(AppState::Events)))

Running systems on_event is necessary as well.

I tried to simplify this code and replaced `Timer` with `thread::sleep`
use std::{thread, time};

use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(MinimalPlugins)
        .add_state::<AppState>()
        .add_event::<MyEvent>()
        .add_system(event_trigger.run_if(in_state(AppState::Events)))
        .add_systems(
            (
                event_listener1,
                event_listener2,
                event_listener3,
            )
                .chain()
                .distributive_run_if(on_event::<MyEvent>())
                .in_set(OnUpdate(AppState::Events))
        )
        .run();
}

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

struct MyEvent;

// sends MyEvent every second
fn event_trigger(
    mut my_events: EventWriter<MyEvent>,
) {
    thread::sleep(time::Duration::from_millis(1000));
    my_events.send(MyEvent);
    println!("========");
}

fn event_listener1(/*mut events: EventReader<MyEvent>*/) {
    println!("system 1");
}

fn event_listener2(/*mut events: EventReader<MyEvent>*/) {
    println!("system 2");
}

fn event_listener3(/*mut events: EventReader<MyEvent>*/) {
    println!("system 3");
}

And while it exhibits the same behavior as the first code snippet, it starts to act even more weird if you uncomment event_listeners EventReader argument. Sometimes it outputs this:

========
system 2
system 3
system 1
========
system 3
system 1
system 2
========
system 1
system 2
system 3
========
system 1
system 2
system 3
========
system 1
system 2
system 3
...

And again, it never outputs anything different from this or what is expected (123). Also, I cannot reproduce this on the first code snippet utilizing timer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-AppBevy apps and pluginsA-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