From 7ec89004dd57c9d4d9b6203a2abad451fea0094e Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 12 Apr 2023 13:07:13 -0400 Subject: [PATCH] Only trigger state transitons if `next_state != old_state` (#8359) # Objective Fix #8191. Currently, a state transition will be triggered whenever the `NextState` resource has a value, even if that "transition" is to the same state as the previous one. This caused surprising/meaningless behavior, such as the existence of an `OnTransition { from: A, to: A }` schedule. ## Solution State transition schedules now only run if the new state is not equal to the old state. Change detection works the same way, only being triggered when the states compare not equal. --- ## Changelog - State transition schedules are no longer run when transitioning to and from the same state. ## Migration Guide State transitions are now only triggered when the exited and entered state differ. This means that if the world is currently in state `A`, the `OnEnter(A)` schedule (or `OnExit`) will no longer be run if you queue up a state transition to the same state `A`. --- crates/bevy_ecs/src/schedule/state.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/state.rs b/crates/bevy_ecs/src/schedule/state.rs index 7bb65621e06bb..763198aa0f8e7 100644 --- a/crates/bevy_ecs/src/schedule/state.rs +++ b/crates/bevy_ecs/src/schedule/state.rs @@ -129,16 +129,18 @@ pub fn apply_state_transition(world: &mut World) { if let Some(entered) = next_state_resource.bypass_change_detection().0.take() { next_state_resource.set_changed(); - let exited = mem::replace(&mut world.resource_mut::>().0, entered.clone()); - - // Try to run the schedules if they exist. - world.try_run_schedule(OnExit(exited.clone())).ok(); - world - .try_run_schedule(OnTransition { - from: exited, - to: entered.clone(), - }) - .ok(); - world.try_run_schedule(OnEnter(entered)).ok(); + let mut state_resource = world.resource_mut::>(); + if *state_resource != entered { + let exited = mem::replace(&mut state_resource.0, entered.clone()); + // Try to run the schedules if they exist. + world.try_run_schedule(OnExit(exited.clone())).ok(); + world + .try_run_schedule(OnTransition { + from: exited, + to: entered.clone(), + }) + .ok(); + world.try_run_schedule(OnEnter(entered)).ok(); + } } }