From 5cb4808026c7f02f88916c4097ff95343fc9c722 Mon Sep 17 00:00:00 2001 From: MiniaczQ Date: Sat, 1 Jun 2024 23:00:38 +0200 Subject: [PATCH] Simplify state transitions (#13616) # Objective Prerequisite to #13579. Make state transition schedule running simpler. ## Solution - Remove `should_run_transition` which read the latest event and fake-fire an event for the startup transitions (e.g. startup `OnEnter()`). - Account for startup event, by actually emitting an event when adding states to `App`. - Replace `should_run_transition` with `last_transition`, which is a light wrapper over `EventReader::read().last()`. --------- Co-authored-by: Alice Cecile --- crates/bevy_app/src/sub_app.rs | 22 ++++++++- .../src/state/freely_mutable_state.rs | 6 +-- crates/bevy_state/src/state/state_set.rs | 29 ++++++------ crates/bevy_state/src/state/transitions.rs | 45 ++++++------------- 4 files changed, 50 insertions(+), 52 deletions(-) diff --git a/crates/bevy_app/src/sub_app.rs b/crates/bevy_app/src/sub_app.rs index b6974cc60f7e0..aece290d39741 100644 --- a/crates/bevy_app/src/sub_app.rs +++ b/crates/bevy_app/src/sub_app.rs @@ -308,6 +308,11 @@ impl SubApp { .add_event::>(); let schedule = self.get_schedule_mut(StateTransition).unwrap(); S::register_state(schedule); + let state = self.world.resource::>().get().clone(); + self.world.send_event(StateTransitionEvent { + exited: None, + entered: Some(state), + }); } self @@ -318,12 +323,15 @@ impl SubApp { pub fn insert_state(&mut self, state: S) -> &mut Self { if !self.world.contains_resource::>() { setup_state_transitions_in_world(&mut self.world, Some(Startup.intern())); - self.insert_resource::>(State::new(state)) + self.insert_resource::>(State::new(state.clone())) .init_resource::>() .add_event::>(); - let schedule = self.get_schedule_mut(StateTransition).unwrap(); S::register_state(schedule); + self.world.send_event(StateTransitionEvent { + exited: None, + entered: Some(state), + }); } self @@ -340,6 +348,11 @@ impl SubApp { self.add_event::>(); let schedule = self.get_schedule_mut(StateTransition).unwrap(); S::register_computed_state_systems(schedule); + let state = self.world.resource::>().get().clone(); + self.world.send_event(StateTransitionEvent { + exited: None, + entered: Some(state), + }); } self @@ -357,6 +370,11 @@ impl SubApp { self.add_event::>(); let schedule = self.get_schedule_mut(StateTransition).unwrap(); S::register_sub_state_systems(schedule); + let state = self.world.resource::>().get().clone(); + self.world.send_event(StateTransitionEvent { + exited: None, + entered: Some(state), + }); } self diff --git a/crates/bevy_state/src/state/freely_mutable_state.rs b/crates/bevy_state/src/state/freely_mutable_state.rs index 1fc809f9e5d1f..c1e4e72e5c68e 100644 --- a/crates/bevy_state/src/state/freely_mutable_state.rs +++ b/crates/bevy_state/src/state/freely_mutable_state.rs @@ -17,17 +17,17 @@ pub trait FreelyMutableState: States { apply_state_transition::.in_set(ApplyStateTransition::::apply()), ) .add_systems( - should_run_transition::> + last_transition:: .pipe(run_enter::) .in_set(StateTransitionSteps::EnterSchedules), ) .add_systems( - should_run_transition::> + last_transition:: .pipe(run_exit::) .in_set(StateTransitionSteps::ExitSchedules), ) .add_systems( - should_run_transition::> + last_transition:: .pipe(run_transition::) .in_set(StateTransitionSteps::TransitionSchedules), ) diff --git a/crates/bevy_state/src/state/state_set.rs b/crates/bevy_state/src/state/state_set.rs index 067711829dbf0..feb9f6e7ac695 100644 --- a/crates/bevy_state/src/state/state_set.rs +++ b/crates/bevy_state/src/state/state_set.rs @@ -9,9 +9,8 @@ use self::sealed::StateSetSealed; use super::{ apply_state_transition, computed_states::ComputedStates, internal_apply_state_transition, - run_enter, run_exit, run_transition, should_run_transition, sub_states::SubStates, - ApplyStateTransition, OnEnter, OnExit, OnTransition, State, StateTransitionEvent, - StateTransitionSteps, States, + last_transition, run_enter, run_exit, run_transition, sub_states::SubStates, + ApplyStateTransition, State, StateTransitionEvent, StateTransitionSteps, States, }; mod sealed { @@ -117,17 +116,17 @@ impl StateSet for S { schedule .add_systems(system.in_set(ApplyStateTransition::::apply())) .add_systems( - should_run_transition::> + last_transition:: .pipe(run_enter::) .in_set(StateTransitionSteps::EnterSchedules), ) .add_systems( - should_run_transition::> + last_transition:: .pipe(run_exit::) .in_set(StateTransitionSteps::ExitSchedules), ) .add_systems( - should_run_transition::> + last_transition:: .pipe(run_transition::) .in_set(StateTransitionSteps::TransitionSchedules), ) @@ -181,17 +180,17 @@ impl StateSet for S { apply_state_transition::.in_set(StateTransitionSteps::ManualTransitions), ) .add_systems( - should_run_transition::> + last_transition:: .pipe(run_enter::) .in_set(StateTransitionSteps::EnterSchedules), ) .add_systems( - should_run_transition::> + last_transition:: .pipe(run_exit::) .in_set(StateTransitionSteps::ExitSchedules), ) .add_systems( - should_run_transition::> + last_transition:: .pipe(run_transition::) .in_set(StateTransitionSteps::TransitionSchedules), ) @@ -232,9 +231,9 @@ macro_rules! impl_state_set_sealed_tuples { schedule .add_systems(system.in_set(ApplyStateTransition::::apply())) - .add_systems(should_run_transition::>.pipe(run_enter::).in_set(StateTransitionSteps::EnterSchedules)) - .add_systems(should_run_transition::>.pipe(run_exit::).in_set(StateTransitionSteps::ExitSchedules)) - .add_systems(should_run_transition::>.pipe(run_transition::).in_set(StateTransitionSteps::TransitionSchedules)) + .add_systems(last_transition::.pipe(run_enter::).in_set(StateTransitionSteps::EnterSchedules)) + .add_systems(last_transition::.pipe(run_exit::).in_set(StateTransitionSteps::ExitSchedules)) + .add_systems(last_transition::.pipe(run_transition::).in_set(StateTransitionSteps::TransitionSchedules)) .configure_sets( ApplyStateTransition::::apply() .in_set(StateTransitionSteps::DependentTransitions) @@ -271,9 +270,9 @@ macro_rules! impl_state_set_sealed_tuples { schedule .add_systems(system.in_set(ApplyStateTransition::::apply())) .add_systems(apply_state_transition::.in_set(StateTransitionSteps::ManualTransitions)) - .add_systems(should_run_transition::>.pipe(run_enter::).in_set(StateTransitionSteps::EnterSchedules)) - .add_systems(should_run_transition::>.pipe(run_exit::).in_set(StateTransitionSteps::ExitSchedules)) - .add_systems(should_run_transition::>.pipe(run_transition::).in_set(StateTransitionSteps::TransitionSchedules)) + .add_systems(last_transition::.pipe(run_enter::).in_set(StateTransitionSteps::EnterSchedules)) + .add_systems(last_transition::.pipe(run_exit::).in_set(StateTransitionSteps::ExitSchedules)) + .add_systems(last_transition::.pipe(run_transition::).in_set(StateTransitionSteps::TransitionSchedules)) .configure_sets( ApplyStateTransition::::apply() .in_set(StateTransitionSteps::DependentTransitions) diff --git a/crates/bevy_state/src/state/transitions.rs b/crates/bevy_state/src/state/transitions.rs index 1e54911df96b4..bb3480765b3cd 100644 --- a/crates/bevy_state/src/state/transitions.rs +++ b/crates/bevy_state/src/state/transitions.rs @@ -1,11 +1,11 @@ -use std::{marker::PhantomData, mem, ops::DerefMut}; +use std::{marker::PhantomData, mem}; use bevy_ecs::{ event::{Event, EventReader, EventWriter}, schedule::{ InternedScheduleLabel, IntoSystemSetConfigs, Schedule, ScheduleLabel, Schedules, SystemSet, }, - system::{Commands, In, Local, Res, ResMut}, + system::{Commands, In, ResMut}, world::World, }; @@ -202,34 +202,18 @@ pub fn apply_state_transition( *next_state_resource.as_mut() = NextState::::Unchanged; } -pub(crate) fn should_run_transition( - mut first: Local, - res: Option>>, - mut event: EventReader>, -) -> (Option>, PhantomData) { - let first_mut = first.deref_mut(); - if !*first_mut { - *first_mut = true; - if let Some(res) = res { - event.clear(); - - return ( - Some(StateTransitionEvent { - exited: None, - entered: Some(res.get().clone()), - }), - PhantomData, - ); - } - } - (event.read().last().cloned(), PhantomData) +/// Returns the latest state transition event of type `S`, if any are available. +pub fn last_transition( + mut reader: EventReader>, +) -> Option> { + reader.read().last().cloned() } pub(crate) fn run_enter( - In((transition, _)): In<(Option>, PhantomData>)>, + transition: In>>, world: &mut World, ) { - let Some(transition) = transition else { + let Some(transition) = transition.0 else { return; }; let Some(entered) = transition.entered else { @@ -240,10 +224,10 @@ pub(crate) fn run_enter( } pub(crate) fn run_exit( - In((transition, _)): In<(Option>, PhantomData>)>, + transition: In>>, world: &mut World, ) { - let Some(transition) = transition else { + let Some(transition) = transition.0 else { return; }; let Some(exited) = transition.exited else { @@ -254,13 +238,10 @@ pub(crate) fn run_exit( } pub(crate) fn run_transition( - In((transition, _)): In<( - Option>, - PhantomData>, - )>, + transition: In>>, world: &mut World, ) { - let Some(transition) = transition else { + let Some(transition) = transition.0 else { return; }; let Some(exited) = transition.exited else {