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`.
This commit is contained in:
JoJoJet 2023-04-12 13:07:13 -04:00 committed by GitHub
parent d623731e2c
commit 7ec89004dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -129,16 +129,18 @@ pub fn apply_state_transition<S: States>(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::<State<S>>().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::<State<S>>();
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();
}
}
}