Composable Alternatives to Bevy's RunCriteria, States, FixedTimestep

Overview

Composable Alternatives to Bevy's RunCriteria, States, FixedTimestep

This crate offers alternatives to the Run Criteria, States, and FixedTimestep scheduling features currently offered by the Bevy game engine.

The ones provided by this crate do not use "looping stages", and can therefore be combined/composed together elegantly, solving some of the most annoying usability limitations of the respective APIs in Bevy.

How does this relate to the Bevy Stageless RFC?

This crate draws very heavy inspiration from the "Stageless RFC" proposal for Bevy.

Big thanks to all the authors that have worked on that RFC and the designs described there.

I am making this crate, because I believe the APIs currently in Bevy are sorely in need of a usability improvement.

I figured out a way to implement the ideas from the Stageless RFC in a way that works within the existing framework of current Bevy, without requiring the complete scheduling API overhaul that the RFC proposes.

This way we can have something usable now, while the remaining Stageless work is still in progress.

Dependencies

The "run conditions" functionality is always enabled, and depends only on bevy_ecs.

The "fixed timestep" functionality is optional ("fixedtimestep" cargo feature, enabled by default) and adds a dependency on bevy_core (needed for Res).

The "states" functionality is optional ("states" cargo feature, enabled by default) and adds a dependency on bevy_utils (to use Bevy's preferred HashMap implementation).

Run Conditions

This crate provides an alternative to Bevy Run Criteria, called "Run Conditions".

The different name was chosen to avoid naming conflicts and confusion with the APIs in Bevy. Bevy Run Criteria are pretty deeply integrated into Bevy's scheduling model, and this crate does not touch/replace them. They are technically still there and usable.

How Run Conditions Work?

You can convert any Bevy system into a "conditional system". This allows you to add any number of "conditions" on it, by repeatedly calling the .run_if builder method.

Each condition is just a Bevy system that outputs (returns) a bool.

The conditional system will present itself to Bevy as a single big system (similar to Bevy's system chaining), combining the system it was created from with all the condition systems attached.

When it runs, it will run each condition, and abort if any of them returns false. The main system will run only if all the conditions return true.

(see examples/conditions.rs for a more complete example)

use bevy::prelude::*;
use iyes_loopless::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_system(
            notify_server
                .run_if(in_multiplayer)
                .run_if(on_mytimer)
        )
        .run();
}

/// Condition checking our timer
fn on_mytimer(mytimer: Res
   ) -> 
   bool {
    mytimer.timer.
   just_finished()
}


   /// Condition checking if we are connected to multiplayer server

   fn 
   in_multiplayer(gamemode: Res
   
    , connected: Res
    
     ) -> 
     bool {
    
     *gamemode 
     == GameMode
     ::Multiplayer 
     &&
    connected.
     is_active()
}


     /// Some system that should only run on a timer in multiplayer

     fn 
     notify_server(
     /* ... */) {
    
     // ...
}
    
   
  

It is highly recommended that all your condition systems only access data immutably. Avoid mutable access or locals in condition systems, unless are really sure about what you are doing. If you add the same condition to many systems, it will run with each one.

There are also some helper methods for easily adding common kinds of Run Conditions:

  • .run_if_not: invert the output of the condition
  • .run_on_event:: () : run if there are events of a given type
  • .run_if_resource_exists:: () : run if a resource of a given type exists
  • .run_unless_resource_exists:: () : run if a resource of a given type does not exist
  • .run_if_resource_equals(value): run if the value of a resource equals the one provided
  • .run_unless_resource_equals(value): run if the value of a resource does not equal the one provided

Fixed Timestep

This crate offers a fixed timestep implementation that uses the Bevy Stage API. You can add a FixedTimestepStage to your App, wherever you would like it to run. Typically, a good place would be before CoreStage::Update.

It is a container for multiple child stages. You might want to add multiple child SystemStages, if you'd like to use Commands in your systems and have them applied between each child stage. Or you can just use one if you don't care. :)

Every frame, the FixedTimestepStage will accumulate the time delta. When it goes over the set timestep value, it will run all the child stages. It will repeat the sequence of child stages multiple times if needed, if more than one timestep has accumulated.

(see examples/fixedtimestep.rs for a complete working example)

use bevy::prelude::*;
use iyes_loopless::prelude::*;

fn main() {
    // prepare our stages for fixed timestep
    // (creating variables to prevent code indentation
    // from drifting too far to the right)

    // can create multiple, to use Commands
    let mut fixed_first = SystemStage::parallel();
    // ... add systems to it ...

    let mut fixed_second = SystemStage::parallel();
    // ... add systems to it ...

    App::new()
        .add_plugins(DefaultPlugins)
        // add the fixed timestep stage:
        .add_stage_before(
            CoreStage::Update,
            "my_fixed_update",
            FixedTimestepStage::new(Duration::from_millis(250))
                .with_stage(fixed_first)
                .with_stage(fixed_second)
        )
        // add normal bevy systems:
        .add_startup_system(setup)
        .add_system(do_thing)
        .run();
}

Since this implementation does not use Run Criteria, you are free to use Run Criteria for other purposes. Or better yet: don't, and use the Run Conditions from this crate instead! ;)

States

(see examples/menu.rs for a complete example)

This crate offers a states abstraction that works as follows:

You create one (or more) state types, usually enums, just like when using Bevy States.

However, here we track states using two resource types:

  • CurrentState(T): the current state you are in
  • NextState(T): insert this (using Commands) whenever you want to change state

Registering the state type, how to add enter/exit systems

To "drive" the states, you add a StateTransitionStage to your App. This is a Stage that will take care of performing state transitions and managing CurrentState . It being a separate stage allows you to control at what point in your App state transitions happen.

You can add child stages to it, to run when entering or exiting different states. This is how you specify your "on enter/exit" systems. They are optional, you don't need them for every state value.

When the transition stage runs, it will check if a NextState resource exists. If yes, it will remove it. If it contains a different value from the one in CurrentState, a transition will be performed:

  • run the "exit stage" (if any) for the current state
  • change the value of CurrentState
  • run the "enter stage" (if any) for the next state

Triggering a Transition

Please do not manually insert or remove CurrentState . It should be managed entirely by StateTransitionStage. It will insert it when it first runs.

If you want to perform a state transition, simply insert a NextState . If you mutate CurrentState , you will effectively force a transition without running the exit/enter systems (you probably don't want to do this).

Multiple state transitions can be performed in a single frame, if you insert a new instance of NextState from within an exit/enter stage.

Update systems

For the systems that you want to run every frame, we provide a .run_in_state(state) and .run_not_in_state(state) run conditions.

You can add systems anywhere, to any stage (incl. behind fixed timestep), and make them conditional on one or more states, using those helper methods.

use bevy::prelude::*;
use iyes_loopless::prelude::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum GameState {
    MainMenu,
    InGame,
}

fn main() {
    // prepare any stages for our transitions:

    let mut enter_menu = SystemStage::parallel();
    enter_menu.add_system(setup_menu);
    // ...

    let mut exit_menu = SystemStage::parallel();
    exit_menu.add_system(despawn_menu);
    // ...

    let mut enter_game = SystemStage::parallel();
    enter_game.add_system(setup_game);
    // ...

    // stage for anything we want to do on a fixed timestep
    let mut fixedupdate = SystemStage::parallel();
    fixedupdate.add_system(
        fixed_thing
            // only do it in-game
            .run_in_state(GameState::InGame)
    );

    App::new()
        .add_plugins(DefaultPlugins)
        // Add the "driver" stage that will perform state transitions
        // After `CoreStage::PreUpdate` is a good place to put it, so that
        // all the states are settled before we run any of our own systems.
        .add_stage_after(
            CoreStage::PreUpdate,
            "TransitionStage",
            StateTransitionStage::new(GameState::MainMenu)
                .with_enter_stage(GameState::MainMenu, enter_menu)
                .with_exit_stage(GameState::MainMenu, exit_menu)
                .with_enter_stage(GameState::InGame, enter_game)
        )
        // If we had more state types, we would add transition stages for them too...

        // Add a FixedTimestep, cuz we can!
        .add_stage_before(
            CoreStage::Update,
            "FixedUpdate",
            FixedTimestepStage::from_stage(Duration::from_millis(125), fixedupdate)
        )

        // Add our various systems
        .add_system(menu_stuff.run_in_state(GameState::MainMenu))
        .add_system(animate.run_in_state(GameState::InGame))

        .run();
}

State transitions under fixed timestep

If you have a state type that you are using for controlling fixed timestep stuff, you might want state transitions to happen only on fixed timestep (not just on any frame).

To accomplish that, you can add the StateTransitionStage as a child stage at the beginning of your FixedTimestepStage.

The stage types from this crate are composable like that! :) They accept any stage type.

Comments
  • `Stage::run::<StateTransitionStage>()` causes the initial state to exit and enter again on first run

    `Stage::run::()` causes the initial state to exit and enter again on first run

    By setting NextState on first run in line 122 in state.rs the initial state will be switched to itself, thus triggering the exit and enter stages. If exit and enter are expensive (e.g. procedural generation) it will cause needless processing.

    Link: https://github.com/IyesGames/iyes_loopless/blob/cf8e61b2fbf1151171b0feb8199d500c1f6aa20d/src/state.rs#L122

    opened by tjamaan 5
  • Panic: State Transition Stage not found (assuming auto-added label)

    Panic: State Transition Stage not found (assuming auto-added label)

    After upgrade from 0.7 to 0.8 I started to get the following error:

    thread 'main' panicked at 'State Transition Stage not found (assuming auto-added label)', /home/indy/.cargo/registry/src/github.com-1ecc6299db9ec823/iyes_loopless-0.8.0/src/state.rs:343:25
    stack backtrace:
       0: rust_begin_unwind
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/panicking.rs:584:5
       1: core::panicking::panic_fmt
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:142:14
       2: core::panicking::panic_display
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:72:5
       3: core::panicking::panic_str
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:56:5
       4: core::option::expect_failed
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/option.rs:1880:5
       5: core::option::Option<T>::expect
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/option.rs:738:21
       6: <bevy_app::app::App as iyes_loopless::state::app::AppLooplessStateExt>::add_enter_system
                 at /home/indy/.cargo/registry/src/github.com-1ecc6299db9ec823/iyes_loopless-0.8.0/src/state.rs:343:25
       7: <de_menu::mainmenu::MainMenuPlugin as bevy_app::plugin::Plugin>::build
                 at ./crates/menu/src/mainmenu.rs:16:9
       8: bevy_app::plugin_group::PluginGroupBuilder::finish
                 at /home/indy/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.8.1/src/plugin_group.rs:135:21
       9: bevy_app::app::App::add_plugins
                 at /home/indy/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.8.1/src/app.rs:810:9
      10: de_game::main
                 at ./src/main.rs:27:5
      11: core::ops::function::FnOnce::call_once
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/ops/function.rs:248:5
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    

    Note that I do this in a plugin (which is executed first):

    app.add_loopless_state(AppState::InMenu)
        .add_loopless_state(GameState::None);
    

    and this in another plugin (which executes later):

    app.add_enter_system(AppState::InMenu, setup)
        .add_exit_system(AppState::InMenu, cleanup)
    
    opened by Indy2222 4
  • Support for Custom Command Queues? ( I have an Implementation )

    Support for Custom Command Queues? ( I have an Implementation )

    Hey there!

    For my game I implemented a custom command queue that can be used to flush certain sets of commands before the end of the frame. This is something that was mentioned in the Bevy stageless design, and I wasn't sure if it was something you might want to add to this crate.

    I feel like it's a feature other people might want to use, and it'd be good to have in a crate, but I wasn't sure if a new crate would be warranted, or if it'd fit in here, because it's kind of a preview to the stageless bevy design.

    Here's a gist with the implementation and usage example. It's really quite simple:

    https://gist.github.com/zicklag/3446143d563657d54e292cc7e2c15378

    opened by zicklag 4
  • Ambiguity when mixing exclusive and normal systems

    Ambiguity when mixing exclusive and normal systems

    It seems I must manually bring in iyes_loopless::condition::IntoConditionalExclusiveSystem to support exclusive systems with conditions, however this appears to cause an ambiguity problem with non-exclusive systems if I bring it into the same scope. This example demonstrates my issue:

    use bevy::prelude::*;
    use iyes_loopless::prelude::*;
    use iyes_loopless::condition::IntoConditionalExclusiveSystem;
    
    fn main() {
        App::new()
            .add_plugins(MinimalPlugins)
            .add_loopless_state(DevState::Loading)
            .add_enter_system(DevState::Loading, setup)
            .add_system(ready
                .run_in_state(DevState::Ready)
                .run_unless_resource_exists::<Thing>()
            )
            .add_system(process
                .run_in_state(DevState::Loading)
                .run_if_resource_exists::<Thing>()
                .at_end()
            )
            .run()
        ;
    }
    
    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub enum DevState {
        Loading,
        Ready,
    }
    
    #[derive(Debug, Clone, Copy)]
    pub struct Thing(pub u32);
    
    fn setup(mut commands: Commands) {
        commands.insert_resource(Thing(1));
    }
    
    fn ready(mut commands: Commands) {
        println!("ready");
        commands.insert_resource(Thing(2));
    }
    
    fn process(mut world: &mut World) {
        println!("removed {:?}", world.remove_resource::<Thing>());
        world.insert_resource(NextState(DevState::Ready));
    }
    
       --> examples\test.rs:11:14
        |
    11  |             .run_in_state(DevState::Loading)
        |              ^^^^^^^^^^^^ multiple `run_in_state` found
        |
        = note: candidate #1 is defined in an impl of the trait `iyes_loopless::condition::IntoConditionalSystem` for the type `S`
        = note: candidate #2 is defined in an impl of the trait `IntoConditionalExclusiveSystem` for the type `S`
    note: candidate #3 is defined in the trait `iyes_loopless::condition::ConditionHelpers`
       --> C:\Users\s33n\.cargo\registry\src\github.com-1ecc6299db9ec823\iyes_loopless-0.5.1\src\condition.rs:366:5
        |
    366 |     fn run_in_state<T: bevy_ecs::schedule::StateData>(self, state: T) -> Self {
        |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    help: disambiguate the associated function for candidate #1
        |
    10  |         .add_system(iyes_loopless::condition::IntoConditionalSystem::run_in_state(ready, DevState::Loading)
        |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    help: disambiguate the associated function for candidate #2
        |
    10  |         .add_system(IntoConditionalExclusiveSystem::run_in_state(ready, DevState::Loading)
        |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    help: disambiguate the associated function for candidate #3
        |
    10  |         .add_system(iyes_loopless::condition::ConditionHelpers::run_in_state(ready, DevState::Loading)
        |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    One option I see is to fully qualify the extension for each exclusive system I add. This works, but seems verbose and ugly:

    .add_system(iyes_loopless::condition::IntoConditionalExclusiveSystem::run_in_state(process,DevState::Loading)
        .run_if_resource_exists::<Thing>()
        .at_end()
    )
    

    Another option I've found is to scope the exclusive trait. This at least preserves the look and feel of the builder API, but still feels quite verbose:

    use bevy::prelude::*;
    use iyes_loopless::prelude::*;
    
    fn main() {
        let mut app = App::new();
        app.add_plugins(MinimalPlugins)
            .add_loopless_state(DevState::Loading)
            .add_enter_system(DevState::Loading, setup)
            .add_system(ready
                .run_in_state(DevState::Ready)
                .run_unless_resource_exists::<Thing>()
            )
        ;
        // scope for exclusive systems
        {
            use iyes_loopless::condition::IntoConditionalExclusiveSystem;
    
            app.add_system(process
                .run_in_state(DevState::Loading)
                .run_if_resource_exists::<Thing>()
                .at_end()
            );
        }
        app.run();
    }
    

    Any better options?

    opened by thebluefish 4
  • "State Transition not found" when adding an enter_system

    I have a barebones StatePlugin that crashes whenever I try to add_enter_system(). I saw another opened issue mentioning that the API may have some issue with the Plugin architecture, so I tried moving the add_enter_system to main but did not work either.

    this is the error I get:

    thread 'main' panicked at 'State Transiton Stage not found (assuming auto-added label)', /{my_directory}/github.com-1ecc6299db9ec823/iyes_loopless-0.6.1/src/state.rs:306:18

    Here's a snippet of my main.rs file

    fn main() {
        let mut app = App::new();
        app.insert_resource(WindowDescriptor {
            // some not relevant code
        })
        .add_plugins(DefaultPlugins)
        .add_plugin(CameraPlugin)
        .add_plugin(StatePlugin)
        .add_plugin(UiPlugin)
        .add_plugin(GamePlugin);
    
        app.run();
    }
    

    and the StatePlugin file:

    use bevy::prelude::*;
    use iyes_loopless::prelude::*;
    
    pub const STARTING_GAME_STATE: GameState = GameState::MainMenu;
    
    #[derive(Debug, Clone, Eq, PartialEq, Hash)]
    pub enum GameState {
        MainMenu,
        Options,
        InGame,
    }
    
    pub struct StatePlugin;
    impl Plugin for StatePlugin {
        fn build(&self, app: &mut App) {
            app
                .add_loopless_state(STARTING_GAME_STATE)
                .add_system(stage_key_bindings)
                .add_enter_system(&GameState::InGame, setup_game); // adding this line crashes the game
        }
    }
    
    // This works fine
    fn stage_key_bindings(mut commands: Commands, kb_input: Res<Input<KeyCode>>) {
        if kb_input.just_pressed(KeyCode::Escape) {
            commands.insert_resource(NextState(GameState::MainMenu));
        }
    }
    
    // Mockup reset_game function when entering a new game
    fn setup_game(mut commands: Commands) {
        dbg!("reset_game!");
        commands.insert_resource(NextState(GameState::InGame));
    }
    

    What am I doing wrong? Thanks!

    opened by CTred 3
  • Can't use system.after() within a ConditionSet

    Can't use system.after() within a ConditionSet

    Hello, I have an issue with systems ordering within a ConditionSet.

    With a standard SystemSet, this works:

    .with_system_set(
        SystemSet::new()
            .label("update")
            .with_system(movement::apply_velocity)
            .with_system(movement::constrain_entities.after(movement::apply_velocity)),
    )
    

    But with a ConditionSet this doesn't:

    .with_system_set(
        ConditionSet::new()
            .label("update")
            .run_if(state_is_in_game)
            .with_system(movement::apply_velocity)
            .with_system(movement::constrain_entities.after(movement::apply_velocity)) // Error on this line
            .into(),
    )
    

    the trait bound ParallelSystemDescriptor: IntoSystem<(), (), _> is not satisfied the trait AddConditionalToSet<ConditionSystemSet, ()> is implemented for ConditionalSystemDescriptor required because of the requirements on the impl of IntoConditionalSystem<_> for ParallelSystemDescriptor required because of the requirements on the impl of AddConditionalToSet<ConditionSystemSet, _> for ParallelSystemDescriptorrustcE0277

    If I use a .into() after the .after(), the error changes to

    type annotations needed cannot infer type of the type parameter S declared on the associated function with_systemrustcE0282 mod.rs(52, 37): consider specifying the generic arguments: ::<S, P>

    Edit: I can use .chain() for this specific case, but being able to use .after() and .before() within a ConditionSet would be better

    opened by scambier 2
  • Cannot use Run_If with systems taking Local<LocalStateType>

    Cannot use Run_If with systems taking Local

    I would love it if run_if could take Local Arguments in. With the below code I get the following error: .add_system(self::gamelobby::lobby.run_if(show_lobby_screen))

    System:

    use super::{UIState, UIStateRes};
    
    pub struct LobbyStateRes{
        pub selected_map: String
    }
    
    pub fn lobby(mut egui_context: ResMut<EguiContext>, mut ui_state: ResMut<UIStateRes>, mut maps_manifest: ResMut<MapManifest>, mut lobby_state: Local<LobbyStateRes>) {
        Window::new("Game Lobby")
            .anchor(Align2::CENTER_CENTER, egui::vec2(0.0, -50.0))
            .show(egui_context.ctx_mut(), |ui| {
                egui::ScrollArea::vertical().show(ui, |ui|{
                    for map in &maps_manifest.map_files{
                        let sel_map_btn = ui.radio_value(&mut lobby_state.selected_map, map.clone(), map);
                    }
                });
    
                let play_btn = ui.button("Launch Game");
    
                if play_btn.clicked() && lobby_state.selected_map != *"".to_string(){ //Such unrust shall not stand!
                    ui_state.current_state = UIState::Game
                }
    
                let back_btn = ui.button("Main Menu");
    
                if back_btn.clicked() {
                    ui_state.current_state = UIState::MainMenu;
                }
            });
    }
    

    Error

    [{
    	"resource": "/e:/rust/macrophage/src/ui/mod.rs",
    	"owner": "rustc",
    	"code": {
    		"value": "E0599",
    		"target": {
    			"$mid": 1,
    			"external": "https://doc.rust-lang.org/error-index.html#E0599",
    			"path": "/error-index.html",
    			"scheme": "https",
    			"authority": "doc.rust-lang.org",
    			"fragment": "E0599"
    		}
    	},
    	"severity": 8,
    	"message": "the method `run_if` exists for fn item `for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}`, but its trait bounds were not satisfied\nthe following trait bounds were not satisfied:\n`for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: bevy::prelude::IntoSystem<(), (), _>`\nwhich is required by `for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: iyes_loopless::condition::IntoConditionalSystem<_>`\n`&for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: bevy::prelude::IntoSystem<(), (), _>`\nwhich is required by `&for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: iyes_loopless::condition::IntoConditionalSystem<_>`\n`&mut for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: bevy::prelude::IntoSystem<(), (), _>`\nwhich is required by `&mut for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: iyes_loopless::condition::IntoConditionalSystem<_>`",
    	"source": "rustc",
    	"startLineNumber": 45,
    	"startColumn": 44,
    	"endLineNumber": 45,
    	"endColumn": 50,
    	"relatedInformation": [
    		{
    			"startLineNumber": 45,
    			"startColumn": 21,
    			"endLineNumber": 45,
    			"endColumn": 43,
    			"message": "this is a function, perhaps you wish to call it",
    			"resource": "/e:/rust/macrophage/src/ui/mod.rs"
    		}
    	]
    }]
    
    
    opened by Braymatter 2
  • Supply extension trait for Schedule

    Supply extension trait for Schedule

    I am using this for the loading state schedule in bevy_asset_loader

    Mostly a copy from the App extension trait. Just the add_loopless_state doesn't make much sense, since the Schedule might not have a CoreStage.

    opened by NiklasEi 2
  • Is there alternative to bevy's state stack?

    Is there alternative to bevy's state stack?

    I've switched from bevy state system into loopless, because there wasn't any information about "setup" systems in it, only loop, but I've found such implementation there. But after I found out such realization in bevy cheatbook (which I've not remarked somehow), I've also seen such thing as "stacks" which lets you make implementation of "pause" state etc. Does similar thing exists in loopless, or I need to get back to bevy systems?

    P.S.: Or is there another way to implement pause menu or smth like this? Thx

    opened by konceptosociala 2
  • migrate some bevy changes

    migrate some bevy changes

    1. Bevy time is now exported from bevy_time package https://github.com/bevyengine/bevy/commit/644bd5dbc6c281a4fae65c603f09b6666de8c566
    2. Bevy removed Ortho camera and UI Camera. The 3d/2d cameras now handle UI elements https://github.com/bevyengine/bevy/pull/4745
    3. bevy::input::system::exit_on_esc_system is now bevy::window::close_on_esc
    4. Rect is now UIRect for UI Elements
    5. as_system_label is now not needed. (Screenshot taken from bevy source)
    CleanShot 2022-06-14 at 13 57 27@2x
    opened by lecoqjacob 2
  • How to get the new methods on App

    How to get the new methods on App

    Hello

    Some background first; Im pretty new to Rust and Bevy.

    I've added iyes_loopless to my dependencies (0.3.0 as I use bevy 0.6 still).

    However, when trying to use a method like .add_enter_system or add_loopless_state on the App::new() from Bevy I get this error from the compiler: no method named add_enter_system found for mutable reference &mut bevy::prelude::App in the current scope

    I've looked at your examples in this repository and I can't see anything specific I'm missing. My dependency is specified like this: [dependencies.iyes_loopless] version = "0.3.0" in my Cargo.toml

    I did a cargo tree -f "{p} {f}" just to see if there was maybe something with the features, but this was the output: ├── iyes_loopless v0.3.0 bevy-compat,bevy_core,bevy_utils,default,fixedtimestep,states │ ├── bevy_core v0.6.0 (*) │ ├── bevy_ecs v0.6.1 bevy_reflect,default (*) │ └── bevy_utils v0.6.0 (*)

    Am a bit lost now, would really like to try this way of doing it before just using the Bevy built-in way of doing it.

    opened by Elogain 2
  • Add `QueuedState` resource

    Add `QueuedState` resource

    Add a QueuedState resource that is only available to exit systems which contains the state being transitioned to. Somewhat related to #8 which has been reverted since it was closed.

    Also cargo fmt happened, I can undo the formatting if needed :sweat_smile:

    opened by AnActualEmerald 0
  • Documentation Clarification: What ordering is guaranteed? When can things run in parallel?

    Documentation Clarification: What ordering is guaranteed? When can things run in parallel?

    I left the documentation with the following questions:

    • If my system has sub-stages, do they run in order? As is, does stage 1 always run after stage 0 runs?
    • If I create a system set, do they run in order?
    • When do systems run in parallel? If they are part of different labeled systems?
    opened by dmurph 0
  • Missing Downcast: StateTransitionStageLabel

    Missing Downcast: StateTransitionStageLabel

    Whenever I start up my game, I get a message in the console about how my states are missing downcasts. I have no idea what it means, and I'm not sure it causes problems.

    opened by Semihazah 4
  • Tick timers

    Tick timers

    It would be cool to provide a "tick timers" implementation that works with our FixedTimestep. Timers/Stopwatches that count timesteps, instead of real time durations.

    opened by inodentry 0
  • Loopless Stage

    Loopless Stage

    Implement an alternative to use instead of Bevy's SystemStage, which:

    • does not support Bevy Run Criteria
    • natively supports our Run Conditions
    • evaluates run conditions in-line and removes the perf overhead of unnecessarily spawning tasks
    opened by inodentry 0
  • Explore how to make APIs play nicer with Plugins

    Explore how to make APIs play nicer with Plugins

    Because of how our fixed timestep and states implementations rely on the user adding custom stages, that nest other stages, it is difficult to make this play nicely with Bevy's Plugin API.

    If a plugin needs to add stuff to happen on state transitions, or on fixed timestep, it has no way of accessing the actual SystemStages to add systems to. Labels don't help, because Bevy's SystemLabels are a top-level Schedule thing, and cannot refer to nested stages.

    The only way right now seems to be to sidestep the Plugin API altogether, and just use functions that take &mut SystemStage (for whatever they need access to) instead.

    This might not be solvable while our stuff is in an external crate, and I cannot think of a better design. I'm open to ideas.

    enhancement 
    opened by inodentry 5
Owner
Indie Game Development with Bevy, by @inodentry
null
Bevy plugin to help implement loading states

This is a plugin for the Bevy game engine, to help you implement loading states.

Ida Iyes 70 Jan 7, 2023
Stack buffer provides alternatives to Buf{Reader,Writer} allocated on the stack instead of the heap.

StackBuf{Reader,Writer} Stack buffer provides alternatives to BufReader and BufWriter allocated on the stack instead of the heap. Its implementation i

Alex Saveau 14 Nov 20, 2022
Reusable Reproducible Composable Software

Reusable Reproducible Composable Software Welcome What is this? Fractalide is a free and open source service programming platform using dataflow graph

Fractalide 787 Dec 29, 2022
Structured, contextual, extensible, composable logging for Rust

Getting started Introduction FAQ Crate list slog-rs - The Logging for Rust Introduction (please read) slog is an ecosystem of reusable components for

slog-rs 1.4k Jan 3, 2023
Composable probability distributions

porco Composable probability distributions. Examples Create simple probability distributions. enum Coin { Heads, Tails, } impl Coin { fn

ming li 15 Jan 9, 2022
A super-easy, composable, web server framework for warp speeds.

warp A super-easy, composable, web server framework for warp speeds. The fundamental building block of warp is the Filter: they can be combined and co

Sean McArthur 7.5k Jan 2, 2023
🌱🦀🌱 Trillium is a composable toolkit for building web applications with async rust 🌱🦀🌱

?????? Trillium is a composable toolkit for building web applications with async rust ??????

Trillium 243 Jan 2, 2023
Wrapped ICP (WICP) - A composable and interoperable wrapped version of ICP.

Wrapped ICP - WICP Wrapped ICP (WICP) is a wrapped version of the IC's native token, ICP. Each WICP will be backed 1:1 with ICP, meaning that 1 WICP w

Psychedelic 16 Sep 23, 2022
Composable proof transcripts for public-coin arguments of knowledge

Merlin: composable proof transcripts for public-coin arguments of knowledge Merlin is a STROBE-based transcript construction for zero-knowledge proofs

dalek cryptography 99 Dec 22, 2022
Composable n-gram combinators that are ergonomic and bare-metal fast

CREATURE FEATUR(ization) A crate for polymorphic ML & NLP featurization that leverages zero-cost abstraction. It provides composable n-gram combinator

null 3 Aug 25, 2022
A collection of lower-level libraries for composable network services.

Actix Net A collection of lower-level libraries for composable network services. Example See actix-server/examples and actix-tls/examples for some bas

Actix 582 Dec 28, 2022
Composable WebSockets made easy, for Rust 🦀

ezsockets Have you ever struggle with creating a WebSocket server or a client in Rust? This crate is for you. High level abstraction of WebSocket, han

Grzegorz Baranski 55 Dec 30, 2022
dWallet Network, a composable modular signature network is the home of dWallets

Welcome to dWallet Network dWallet Network, a composable modular signature network is the home of dWallets. A dWallet is a noncollusive and massively

dWallet Labs 8 Feb 26, 2024