Skip to content

Conversation

@Br3nnabee
Copy link
Contributor

Objective

Solution

  • Added a new PreviousState<S: States> resource.
  • Updated internal_apply_state_transition to manage the lifecycle of PreviousState:
    • Standard Transition: Updates PreviousState to the exited state.
    • Creation: If a state is initialized (transition from None), any existing PreviousState is removed.
    • Removal: If a state is removed, PreviousState is updated to preserve the last known state.
  • Registered PreviousState in AppExtStates for reflection and general access.
  • Ensured PreviousState is available for OnEnter systems by using ApplyDeferred ordering in setup_state_transitions_in_world.

Testing

  • Added a temporary local unit test previous_state_is_tracked_correctly which verifies that PreviousState is created, updated, and persisted correctly across multiple state transitions.
  • The implementation covered scenarios including standard transitions, state initialization (where no previous state exists), and state removal.
  • Don't think I handled all edge cases, would appreciate a second look.

Showcase

You can now access the state you just transitioned from directly in your systems!

fn handle_state_refresh<S: FreelyMutableState>(
    prev_state: Option<Res<PreviousState<S>>>, 
    mut next_state: ResMut<NextState<S>>
) {
    if let Some(prev) = prev_state {
        println!("We just came from {:?}", prev.0);
        // Example: revert to previous state
        next_state.set(prev.0.clone());
    }
}

app.add_systems(OnEnter(GameState::Refresh), handle_state_refresh::<GameState>);

This is my first contribution, would highly appreciate some feedback!

@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2025

Welcome, new contributor!

Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨

@Zeophlite Zeophlite added C-Bug An unexpected or incorrect behavior D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Needs-Review Needs reviewer attention (from anyone!) to move forward A-States App-level states machines labels Dec 4, 2025
Copy link
Contributor

@kfc35 kfc35 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your first contribution, and welcome! (Coming from a fellow new-ish contributor)

It looks good to me logic wise, but I defer to someone else to make doubly sure since I’m relatively inexperienced with the state code.

I wonder if this change is worth 1) a release note and 2) an update to the states.rs example to show how one can now read the PreviousState as a resource. The example update could be a candidate for a follow up if desired?

.chain(),
);
schedule.add_systems(
ApplyDeferred

This comment was marked as resolved.

@pablo-lua pablo-lua added C-Feature A new feature, making something new possible and removed C-Bug An unexpected or incorrect behavior labels Dec 12, 2025
Copy link
Contributor

@pablo-lua pablo-lua left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic is good, good work and thanks for the change. We probably could remove that ApplyDeferred though

Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ApplyDeferred needs to be removed, then this LGTM :)

@Br3nnabee Br3nnabee force-pushed the previous-state-resource branch from 8fd45f1 to 572ce0e Compare December 15, 2025 19:39
@Br3nnabee
Copy link
Contributor Author

Alright, so I've removed the ApplyDeferred section now. There's a merge conflict due to #21792, but as far as I see it's a quick fix. Should I be the one to handle that, or would you prefer to?

@alice-i-cecile
Copy link
Member

Yes please; handling merge conflicts is done by authors around here :)

@Br3nnabee Br3nnabee force-pushed the previous-state-resource branch from 572ce0e to d7c12e9 Compare December 16, 2025 06:54
@pablo-lua pablo-lua added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Dec 16, 2025
@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it labels Dec 17, 2025
@alice-i-cecile alice-i-cecile removed the S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged label Dec 17, 2025
@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Dec 17, 2025
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Dec 17, 2025
Merged via the queue into bevyengine:main with commit f8a9f29 Dec 17, 2025
38 checks passed
@Br3nnabee Br3nnabee deleted the previous-state-resource branch December 17, 2025 21:42
@mockersf
Copy link
Member

Should it be possible to disable this? It's keeping an extra clone in memory of the state when not everyone needs it

@LikeLakers2
Copy link
Contributor

LikeLakers2 commented Dec 17, 2025

@mockersf I wouldn't bother - unless you have many states using tens of megabytes each (at which point, you already need to do some optimizing), it's not going to use much extra memory.

That said, if you can find a way to let people opt-in to this on a per-state basis without much extra work, I wouldn't complain.

@mockersf
Copy link
Member

We put no limit on the size of the state, and it's not Copy, so we should not presume too much of how it will be used

@LikeLakers2
Copy link
Contributor

LikeLakers2 commented Dec 17, 2025

@mockersf Yet the hit (in terms of CPU usage and memory usage) is unlikely to be noticed by the end user, unless their state is quite large and complicated, or they are running quite slow hardware.

That said, if this "previous state" stuff could be moved to a wrapper that allows opting in on a per-case basis, then I wouldn't complain.

@pablo-lua
Copy link
Contributor

pablo-lua commented Dec 17, 2025

@mockersf Yet the hit (in terms of CPU usage and memory usage) is unlikely to be noticed by the end user, unless their state is quite large and complicated, or they are running quite slow hardware.

That said, if this "previous state" stuff could be moved to a wrapper that allows opting in on a per-case basis, then I wouldn't complain.

I think you can do just that by letting the user insert the resource (would need to change how this pr is now) if they want to use it or by feature flagging (would need to change a little of this pr, probably).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-States App-level states machines C-Feature A new feature, making something new possible D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A PreviousState Resource, accessible in OnEnter

7 participants