Make current state a property of StateStage #1125
Make current state a property of StateStage #1125DJMcNab wants to merge 3 commits intobevyengine:masterfrom
Conversation
Extends bevyengine#1021 Fixes bevyengine#1117 This also allows avoiding the Clone bound on state Possible future work: - Make state use Eq instead
Maybe this will seem a bit too much like magic to someone who doesn't know about mem::discriminant? Oh well! Also fix AppBuilder to not require otherwise unused clones
|
Hmm this changes things so that State transitions are no longer a global thing with a well defined order of execution. Each StateStage has its own "last state", which can cause confusing outcomes: |
|
Lazy illustrative example: use bevy::prelude::*;
#[derive(Clone)]
pub enum AppState {
X,
Y,
Z,
}
fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_resource(State::new(AppState::X))
// uncomment the next line and 'enter_system' is not called
.add_stage_after(
stage::UPDATE,
"STAGE_A",
StateStage::<AppState>::default()
.with_enter_stage(
AppState::X,
SystemStage::parallel()
.with_system(a.system())
.with_system(a_x_enter.system()),
)
.with_update_stage(AppState::X, SystemStage::parallel().with_system(a.system()))
.with_exit_stage(AppState::X, SystemStage::parallel().with_system(a.system()))
.with_enter_stage(AppState::Y, SystemStage::parallel().with_system(a.system()))
.with_update_stage(AppState::Y, SystemStage::parallel().with_system(a.system()))
.with_exit_stage(AppState::Y, SystemStage::parallel().with_system(a.system()))
.with_enter_stage(AppState::Z, SystemStage::parallel().with_system(a.system()))
.with_update_stage(AppState::Z, SystemStage::parallel().with_system(a.system()))
.with_exit_stage(AppState::Z, SystemStage::parallel().with_system(a.system())),
)
.add_stage_after(
"STAGE_A",
"STAGE_B",
StateStage::<AppState>::default()
.with_enter_stage(AppState::X, SystemStage::parallel().with_system(b.system()))
.with_update_stage(AppState::X, SystemStage::parallel().with_system(b.system()))
.with_exit_stage(AppState::X, SystemStage::parallel().with_system(b.system()))
.with_enter_stage(
AppState::Y,
SystemStage::parallel()
.with_system(b.system())
.with_system(b_y_enter.system()),
)
.with_update_stage(AppState::Y, SystemStage::parallel().with_system(b.system()))
.with_exit_stage(AppState::Y, SystemStage::parallel().with_system(b.system()))
.with_enter_stage(AppState::Z, SystemStage::parallel().with_system(b.system()))
.with_update_stage(AppState::Z, SystemStage::parallel().with_system(b.system()))
.with_exit_stage(AppState::Z, SystemStage::parallel().with_system(b.system())),
)
.add_system_to_stage(stage::LAST, end.system())
.run();
}
fn a_x_enter(mut state: ResMut<State<AppState>>) {
state.set_next(AppState::Y).unwrap();
}
fn b_y_enter(mut state: ResMut<State<AppState>>) {
state.set_next(AppState::Z).unwrap();
}
fn a() {
println!(" a")
}
fn b() {
println!(" b")
}
fn end(mut x: Local<usize>) {
*x+=1;
if *x == 2 {
panic!("end");
}
}// modify state.rs to print each state
#[allow(clippy::mem_discriminant_non_enum)]
impl<T: Resource> Stage for StateStage<T> {
fn run(&mut self, world: &mut World, resources: &mut Resources) {
let current_stage = loop {
let next = {
let mut state = resources
.get_mut::<State<T>>()
.expect("Missing state resource");
state.previous = state.apply_next().or_else(|| state.previous.take());
mem::discriminant(&state.current)
};
if self.current_stage == Some(next) {
break next;
} else {
let cur = self.current_stage.map(|i| i);
if let Some(current_state_stages) =
self.current_stage.and_then(|it| self.stages.get_mut(&it))
{
println!("exit {:?}", cur.unwrap());
current_state_stages.exit.run(world, resources);
}
self.current_stage = Some(next);
if let Some(next_state_stages) = self.stages.get_mut(&next) {
println!("enter {:?}", next);
next_state_stages.enter.run(world, resources);
}
}
};
if let Some(current_state_stages) = self.stages.get_mut(¤t_stage) {
println!("update {:?}", current_stage);
current_state_stages.update.run(world, resources);
}
}
} |
|
My mental model is that each StateStage is standalone, and That is, I would say that your unexpected behaviour is exactly what I would expect from |
|
Hmm yeah thats a reasonable take. I think whatever solution we land on needs to be reconciled with the upcoming SystemSet::with_run_criteria (#1144). I think it can be accomplished with a new |
|
This is probably superseded by #1424. |
Extends #1021
Fixes #1117
This also allows avoiding the
Clonebound on statePossible future work: