diff --git a/crates/bevy_state/src/app.rs b/crates/bevy_state/src/app.rs index 955c957ede..33a141e8d6 100644 --- a/crates/bevy_state/src/app.rs +++ b/crates/bevy_state/src/app.rs @@ -4,6 +4,7 @@ use bevy_ecs::{ schedule::{IntoSystemConfigs, ScheduleLabel}, world::FromWorld, }; +use bevy_utils::tracing::warn; use crate::state::{ setup_state_transitions_in_world, ComputedStates, FreelyMutableState, NextState, State, @@ -70,6 +71,9 @@ impl AppExtStates for SubApp { exited: None, entered: Some(state), }); + } else { + let name = std::any::type_name::(); + warn!("State {} is already initialized.", name); } self @@ -87,6 +91,16 @@ impl AppExtStates for SubApp { exited: None, entered: Some(state), }); + } else { + // Overwrite previous state and initial event + self.insert_resource::>(State::new(state.clone())); + self.world_mut() + .resource_mut::>>() + .clear(); + self.world_mut().send_event(StateTransitionEvent { + exited: None, + entered: Some(state), + }); } self @@ -109,6 +123,9 @@ impl AppExtStates for SubApp { exited: None, entered: state, }); + } else { + let name = std::any::type_name::(); + warn!("Computed state {} is already initialized.", name); } self @@ -132,6 +149,9 @@ impl AppExtStates for SubApp { exited: None, entered: state, }); + } else { + let name = std::any::type_name::(); + warn!("Sub state {} is already initialized.", name); } self @@ -192,3 +212,62 @@ impl Plugin for StatesPlugin { schedule.insert_after(PreUpdate, StateTransition); } } + +#[cfg(test)] +mod tests { + use crate::{ + self as bevy_state, + state::{State, StateTransition, StateTransitionEvent}, + }; + use bevy_app::App; + use bevy_ecs::event::Events; + use bevy_state_macros::States; + + use super::AppExtStates; + + #[derive(States, Default, PartialEq, Eq, Hash, Debug, Clone)] + enum TestState { + #[default] + A, + B, + C, + } + + #[test] + fn insert_state_can_overwrite_init_state() { + let mut app = App::new(); + + app.init_state::(); + app.insert_state(TestState::B); + + let world = app.world_mut(); + world.run_schedule(StateTransition); + + assert_eq!(world.resource::>().0, TestState::B); + let events = world.resource::>>(); + assert_eq!(events.len(), 1); + let mut reader = events.get_reader(); + let last = reader.read(events).last().unwrap(); + assert_eq!(last.exited, None); + assert_eq!(last.entered, Some(TestState::B)); + } + + #[test] + fn insert_state_can_overwrite_insert_state() { + let mut app = App::new(); + + app.insert_state(TestState::B); + app.insert_state(TestState::C); + + let world = app.world_mut(); + world.run_schedule(StateTransition); + + assert_eq!(world.resource::>().0, TestState::C); + let events = world.resource::>>(); + assert_eq!(events.len(), 1); + let mut reader = events.get_reader(); + let last = reader.read(events).last().unwrap(); + assert_eq!(last.exited, None); + assert_eq!(last.entered, Some(TestState::C)); + } +}