Run Criteria

Consider using the iyes_loopless crate, which provides an alternative implementation that does not suffer from the usability issues of the one in Bevy.


Run Criteria are a mechanism for controlling if Bevy should run specific systems, at runtime. This is how you can make functionality that only runs under certain conditions.

Run Criteria can be applied to individual systems, system sets, and stages.

Run Criteria are Bevy systems that return a value of type enum ShouldRun. They can accept any system parameters, like a normal system.

This example shows how run criteria might be used to implement different multiplayer modes:

use bevy::ecs::schedule::ShouldRun;

#[derive(Debug, PartialEq, Eq)]
enum MultiplayerKind {
    Client,
    Host,
    Local,
}

fn run_if_connected(
    mode: Res<MultiplayerKind>,
    session: Res<MyNetworkSession>,
) -> ShouldRun
{
    if *mode == MultiplayerKind::Client && session.is_connected() {
        ShouldRun::Yes
    } else {
        ShouldRun::No
    }
}

fn run_if_host(
    mode: Res<MultiplayerKind>,
) -> ShouldRun
{
    if *mode == MultiplayerKind::Host || *mode == MultiplayerKind::Local {
        ShouldRun::Yes
    } else {
        ShouldRun::No
    }
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)

        // if we are currently connected to a server,
        // activate our client systems
        .add_system_set(
            SystemSet::new()
                .with_run_criteria(run_if_connected)
                .before("input")
                .with_system(server_session)
                .with_system(fetch_server_updates)
        )

        // if we are hosting the game,
        // activate our game hosting systems
        .add_system_set(
            SystemSet::new()
                .with_run_criteria(run_if_host)
                .before("input")
                .with_system(host_session)
                .with_system(host_player_movement)
                .with_system(host_enemy_ai)
        )

        // other systems in our game
        .add_system(smoke_particles)
        .add_system(water_animation)
        .add_system_set(
            SystemSet::new()
                .label("input")
                .with_system(keyboard_input)
                .with_system(gamepad_input)
        )
        .run();
}

Known Pitfalls

Combining Multiple Run Criteria

It is not possible to make a system that is conditional on multiple run criteria. Bevy has a .pipe method that allows you to "chain" run criteria, which could let you modify the output of a run criteria, but this is very limiting in practice.

Consider using iyes_loopless. It allows you to use any number of run conditions to control your systems, and does not prevent you from using states or fixed timestep.

Events

When receiving events in systems that don't run every frame, you will miss any events that are sent during the frames when the receiving systems are not running!

To mitigate this, you could implement a custom cleanup strategy, to manually manage the lifetime of the relevant event types.