bevy/crates/bevy_state/src
mgi388 1f2fd3d29d
Fix SubStates with multiple source states not reacting to all source changes (#19595)
# Objective

- Fix issue where `SubStates` depending on multiple source states would
only react when _all_ source states changed simultaneously.
- SubStates should be created/destroyed whenever _any_ of their source
states transitions, not only when all change together.

# Solution

- Changed the "did parent change" detection logic from AND to OR. We
need to check if _any_ of the event readers changed, not if _all_ of
them changed.
- See
https://github.com/bevyengine/bevy/actions/runs/15610159742/job/43968937544?pr=19595
for failing test proof before I pushed the fix.
- The generated code we want needs `||`s not `&&`s like this:

```rust
fn register_sub_state_systems_in_schedule<T: SubStates<SourceStates = Self>>(schedule: &mut Schedule) {
  let apply_state_transition = |(mut ereader0, mut ereader1, mut ereader2): (
      EventReader<StateTransitionEvent<S0::RawState>>,
      EventReader<StateTransitionEvent<S1::RawState>>,
      EventReader<StateTransitionEvent<S2::RawState>>,
  ),
      event: EventWriter<StateTransitionEvent<T>>,
      commands: Commands,
      current_state_res: Option<ResMut<State<T>>>,
      next_state_res: Option<ResMut<NextState<T>>>,
      (s0, s1, s2): (
          Option<Res<State<S0::RawState>>>,
          Option<Res<State<S1::RawState>>>,
          Option<Res<State<S2::RawState>>>,
  )| {
    // With `||` we can correctly count parent changed if any of the sources changed.
    let parent_changed = (ereader0.read().last().is_some()
        || ereader1.read().last().is_some()
        || ereader2.read().last().is_some());
    let next_state = take_next_state(next_state_res);
    if !parent_changed && next_state.is_none() {
        return;
    }
    // ...
  }
}
```

# Testing

- Add new test.
- Check the fix worked in my game.
2025-06-16 21:34:22 +00:00
..
state Fix SubStates with multiple source states not reacting to all source changes (#19595) 2025-06-16 21:34:22 +00:00
app.rs Enable state scoped entities by default (#19354) 2025-05-26 20:26:41 +00:00
commands.rs Add no_std support to bevy_state (#17028) 2024-12-29 23:28:18 +00:00
condition.rs Rename Condition to SystemCondition` (#19328) 2025-05-22 15:50:19 +00:00
lib.rs Rename StateScoped to DespawnOnExitState and add DespawnOnEnterState (#18818) 2025-05-06 00:37:04 +00:00
reflect.rs Harden proc macro path resolution and add integration tests. (#17330) 2025-02-09 19:45:45 +00:00
state_scoped_events.rs Event Split: Event, EntityEvent, and BufferedEvent (#19647) 2025-06-15 16:46:34 +00:00
state_scoped.rs Enable state scoped entities by default (#19354) 2025-05-26 20:26:41 +00:00