-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OnEnter triggers twice and OnExit is not triggered #13844
Comments
States have been significantly reworked for 0.14, so it would be worth testing with I am seeing something entirely different in
I think this could possibly be a bug with |
Pinging @MiniaczQ |
This patch results in the behavior I personally expect:
But folks more familiar with states should weigh in. I am not sure that the behavior of diff --git a/crates/bevy_state/src/app.rs b/crates/bevy_state/src/app.rs
index 2ff97f6ee..5fc7e8f49 100644
--- a/crates/bevy_state/src/app.rs
+++ b/crates/bevy_state/src/app.rs
@@ -76,19 +76,24 @@ impl AppExtStates for SubApp {
}
fn insert_state<S: FreelyMutableState>(&mut self, state: S) -> &mut Self {
- if !self.world().contains_resource::<State<S>>() {
+ let already_initialized = self.world().contains_resource::<State<S>>();
+
+ self.insert_resource::<State<S>>(State::new(state.clone()));
+
+ if !already_initialized {
setup_state_transitions_in_world(self.world_mut(), Some(Startup.intern()));
- self.insert_resource::<State<S>>(State::new(state.clone()))
- .init_resource::<NextState<S>>()
+
+ self.init_resource::<NextState<S>>()
.add_event::<StateTransitionEvent<S>>();
let schedule = self.get_schedule_mut(StateTransition).unwrap();
S::register_state(schedule);
- self.world_mut().send_event(StateTransitionEvent {
- exited: None,
- entered: Some(state),
- });
}
+ self.world_mut().send_event(StateTransitionEvent {
+ exited: None,
+ entered: Some(state),
+ });
+
self
} |
What's the use case behind initializing the same state twice? Using the first call and ignoring subsequent ones seems reasonable to me. This is the run result for
Only first call runs, initialization with |
It looks like So I was making an assumption based on the name
I think I agree with this. |
I can imagine state overwriting being useful when using external modules, which initialize state by themselves. Unless we have a proper use-case I don't think we need the overwrite support. |
Okay, so my assumption also seems in line with what the docs actually say about how that function behaves: https://dev-docs.bevyengine.org/bevy/prelude/trait.AppExtStates.html#tymethod.insert_state If we are going to officially stop supporting overwriting, we should make sure to update the docs. |
I have a main menu which takes you to a game. There is state |
If we already promise we support this then we should probably keep it that way, otherwise it's a breaking change :/ I'll see if we can get overwrite running, biggest problem is ensuring we get only one event after all setups |
# Objective - Fixes #13844 - Warn user when initializing state multiple times ## Solution - `insert_state` will overwrite previously initialized state value, reset transition events and re-insert it's own transition event. - `init_state`, `add_sub_state`, `add_computed_state` are idempotent, so calling them multiple times will emit a warning. ## Testing - 2 tests confirming overwrite works. - Given the example from #13844 ```rs use bevy::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) .insert_state(AppState::A) .insert_state(AppState::B) .add_systems(OnEnter(AppState::A), setup_a) .add_systems(OnEnter(AppState::B), setup_b) .add_systems(OnExit(AppState::A), cleanup_a) .add_systems(OnExit(AppState::B), cleanup_b) .run(); } #[derive(States, Debug, Clone, PartialEq, Eq, Hash)] enum AppState { A, B, } fn setup_a() { info!("setting up A"); } fn setup_b() { info!("setting up B"); } fn cleanup_a() { info!("cleaning up A"); } fn cleanup_b() { info!("cleaning up B"); } ``` We get the following result: ``` INFO states: setting up B ``` which matches our expectations.
# Objective - Fixes #13844 - Warn user when initializing state multiple times ## Solution - `insert_state` will overwrite previously initialized state value, reset transition events and re-insert it's own transition event. - `init_state`, `add_sub_state`, `add_computed_state` are idempotent, so calling them multiple times will emit a warning. ## Testing - 2 tests confirming overwrite works. - Given the example from #13844 ```rs use bevy::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) .insert_state(AppState::A) .insert_state(AppState::B) .add_systems(OnEnter(AppState::A), setup_a) .add_systems(OnEnter(AppState::B), setup_b) .add_systems(OnExit(AppState::A), cleanup_a) .add_systems(OnExit(AppState::B), cleanup_b) .run(); } #[derive(States, Debug, Clone, PartialEq, Eq, Hash)] enum AppState { A, B, } fn setup_a() { info!("setting up A"); } fn setup_b() { info!("setting up B"); } fn cleanup_a() { info!("cleaning up A"); } fn cleanup_b() { info!("cleaning up B"); } ``` We get the following result: ``` INFO states: setting up B ``` which matches our expectations.
Bevy version
0.13.2
[Optional] Relevant system information
Ubuntu 22.04.4 LTS 64-bit
Minimal project with the issue
The Output
Expected Output
OR
depending on the intended behaviour (I can say that what happens now is not intended behaviour).
The text was updated successfully, but these errors were encountered: