Skip to content

Add clear_schedule method to State #3932

Closed
@hlb8122

Description

@hlb8122

What problem does this solve or what need does it fill?

Suppose we wanted a State<Direction> to switch from Direction::Down, to Direction::Up, then again to Direction::Down, within one tick. While this seems pointless, we may want distinct systems to displace the current scheduled state operation. With the current semantics of overwrite_set this is not possible.

use bevy::{log::LogPlugin, prelude::*};

#[derive(Clone, PartialEq, Eq, Debug, Hash)]
enum Switch {
    On,
    Off,
}

#[derive(Clone, PartialEq, Eq, Debug, Hash)]
enum Direction {
    Up,
    Down,
}

fn main() {
    let up = SystemSet::on_enter(Switch::On)
        .label("A")
        .with_system(set_up);
    let down = SystemSet::on_enter(Switch::On)
        .label("B")
        .after("A")
        .with_system(set_down);
    App::new()
        .add_plugins(MinimalPlugins)
        .add_plugin(LogPlugin::default())
        .add_state(Switch::Off)
        .add_state(Direction::Down)
        .add_startup_system(switch_on)
        .add_system_set(up)
        .add_system_set(down)
        .add_system(print_direction)
        .run()
}

fn switch_on(mut state: ResMut<State<Switch>>) {
    state.set(Switch::On);
}

fn set_up(mut state: ResMut<State<Direction>>) {
    state.overwrite_set(Direction::Up);
}

fn set_down(mut state: ResMut<State<Direction>>) {
    state.overwrite_set(Direction::Down);
}

fn print_direction(state: Res<State<Direction>>) {
    info!("{:?}", state.current());
}

The following will print Up despite set_down being called strictly after set_up.

This is a direct result of the form of overwrite_set

    pub fn overwrite_set(&mut self, state: T) -> Result<(), StateError> {
        if self.stack.last().unwrap() == &state {
            // We're accepted into this branch and return early
            return Err(StateError::AlreadyInState);
        }

        self.scheduled = Some(ScheduledOperation::Set(state));
        Ok(())
    }

What solution would you like?

A non-breaking work around would be to add a clear_schedule method onto State which sets self.scheduled = None. This could then be called in the case when set_overwrite returns Err.

What alternative(s) have you considered?

Changing the semantics of overwrite_set, this would be a breaking change and non-obvious implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-FeatureA new feature, making something new possible

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions