mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Make initial StateTransition
run before PreStartup
(#14208)
# Objective - Fixes #14206 ## Solution - Run initial `StateTransition` as a startup schedule before `PreStartup`, instead of running it inside `Startup` as an exclusive system. Related discord discussion: https://discord.com/channels/691052431525675048/692572690833473578/1259543775668207678 ## Testing Reproduction now works correctly: ```rs use bevy::prelude::*; #[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)] enum AppState { #[default] Menu, InGame, } fn main() { App::new() .add_plugins(DefaultPlugins) .init_state::<AppState>() .add_systems(Startup, setup) .add_systems(OnEnter(AppState::Menu), enter_menu_state) .run(); } fn setup(mut next_state: ResMut<NextState<AppState>>) { next_state.set(AppState::Menu); } fn enter_menu_state() { println!("Entered menu state"); } ``` ![image](https://github.com/bevyengine/bevy/assets/13040204/96d7a533-c439-4c0b-8f15-49f620903ce1) --- ## Changelog - Initial `StateTransition` runs before `PreStartup` instead of inside `Startup`.
This commit is contained in:
parent
7f3fea9a5b
commit
524fb01457
3 changed files with 16 additions and 34 deletions
|
@ -1,9 +1,5 @@
|
|||
use bevy_app::{App, MainScheduleOrder, Plugin, PreUpdate, Startup, SubApp};
|
||||
use bevy_ecs::{
|
||||
event::Events,
|
||||
schedule::{IntoSystemConfigs, ScheduleLabel},
|
||||
world::FromWorld,
|
||||
};
|
||||
use bevy_app::{App, MainScheduleOrder, Plugin, PreStartup, PreUpdate, SubApp};
|
||||
use bevy_ecs::{event::Events, schedule::IntoSystemConfigs, world::FromWorld};
|
||||
use bevy_utils::{tracing::warn, warn_once};
|
||||
|
||||
use crate::state::{
|
||||
|
@ -215,7 +211,8 @@ impl Plugin for StatesPlugin {
|
|||
fn build(&self, app: &mut App) {
|
||||
let mut schedule = app.world_mut().resource_mut::<MainScheduleOrder>();
|
||||
schedule.insert_after(PreUpdate, StateTransition);
|
||||
setup_state_transitions_in_world(app.world_mut(), Some(Startup.intern()));
|
||||
schedule.insert_startup_before(PreStartup, StateTransition);
|
||||
setup_state_transitions_in_world(app.world_mut());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ pub use transitions::*;
|
|||
mod tests {
|
||||
use bevy_ecs::event::EventRegistry;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_ecs::schedule::ScheduleLabel;
|
||||
use bevy_state_macros::States;
|
||||
use bevy_state_macros::SubStates;
|
||||
|
||||
|
@ -64,7 +63,7 @@ mod tests {
|
|||
|
||||
world.insert_resource(schedules);
|
||||
|
||||
setup_state_transitions_in_world(&mut world, None);
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
|
||||
world.run_schedule(StateTransition);
|
||||
assert_eq!(world.resource::<State<SimpleState>>().0, SimpleState::A);
|
||||
|
@ -120,7 +119,7 @@ mod tests {
|
|||
|
||||
world.insert_resource(schedules);
|
||||
|
||||
setup_state_transitions_in_world(&mut world, None);
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
|
||||
world.run_schedule(StateTransition);
|
||||
assert_eq!(world.resource::<State<SimpleState>>().0, SimpleState::A);
|
||||
|
@ -180,7 +179,7 @@ mod tests {
|
|||
|
||||
world.insert_resource(schedules);
|
||||
|
||||
setup_state_transitions_in_world(&mut world, None);
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
|
||||
world.run_schedule(StateTransition);
|
||||
assert_eq!(world.resource::<State<SimpleState>>().0, SimpleState::A);
|
||||
|
@ -275,7 +274,7 @@ mod tests {
|
|||
|
||||
world.insert_resource(schedules);
|
||||
|
||||
setup_state_transitions_in_world(&mut world, None);
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
|
||||
world.run_schedule(StateTransition);
|
||||
assert_eq!(world.resource::<State<SimpleState>>().0, SimpleState::A);
|
||||
|
@ -354,9 +353,6 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
struct Startup;
|
||||
|
||||
#[test]
|
||||
fn computed_state_transitions_are_produced_correctly() {
|
||||
let mut world = World::new();
|
||||
|
@ -367,7 +363,7 @@ mod tests {
|
|||
world.init_resource::<State<SimpleState2>>();
|
||||
world.init_resource::<Schedules>();
|
||||
|
||||
setup_state_transitions_in_world(&mut world, Some(Startup.intern()));
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
|
||||
let mut schedules = world
|
||||
.get_resource_mut::<Schedules>()
|
||||
|
@ -431,7 +427,7 @@ mod tests {
|
|||
|
||||
world.init_resource::<ComputedStateTransitionCounter>();
|
||||
|
||||
setup_state_transitions_in_world(&mut world, None);
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
|
||||
assert_eq!(world.resource::<State<SimpleState>>().0, SimpleState::A);
|
||||
assert_eq!(world.resource::<State<SimpleState2>>().0, SimpleState2::A1);
|
||||
|
@ -508,7 +504,7 @@ mod tests {
|
|||
#[test]
|
||||
fn same_state_transition_should_emit_event_and_not_run_schedules() {
|
||||
let mut world = World::new();
|
||||
setup_state_transitions_in_world(&mut world, None);
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
EventRegistry::register_event::<StateTransitionEvent<SimpleState>>(&mut world);
|
||||
world.init_resource::<State<SimpleState>>();
|
||||
let mut schedules = world.resource_mut::<Schedules>();
|
||||
|
@ -568,7 +564,7 @@ mod tests {
|
|||
SubState::register_sub_state_systems(&mut apply_changes);
|
||||
schedules.insert(apply_changes);
|
||||
world.insert_resource(schedules);
|
||||
setup_state_transitions_in_world(&mut world, None);
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
|
||||
world.insert_resource(NextState::Pending(SimpleState::B(true)));
|
||||
world.run_schedule(StateTransition);
|
||||
|
@ -599,7 +595,7 @@ mod tests {
|
|||
TestComputedState::register_computed_state_systems(&mut apply_changes);
|
||||
schedules.insert(apply_changes);
|
||||
world.insert_resource(schedules);
|
||||
setup_state_transitions_in_world(&mut world, None);
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
|
||||
world.insert_resource(NextState::Pending(SimpleState::B(true)));
|
||||
world.run_schedule(StateTransition);
|
||||
|
@ -651,7 +647,7 @@ mod tests {
|
|||
#[test]
|
||||
fn check_transition_orders() {
|
||||
let mut world = World::new();
|
||||
setup_state_transitions_in_world(&mut world, None);
|
||||
setup_state_transitions_in_world(&mut world);
|
||||
EventRegistry::register_event::<StateTransitionEvent<SimpleState>>(&mut world);
|
||||
EventRegistry::register_event::<StateTransitionEvent<SubState>>(&mut world);
|
||||
EventRegistry::register_event::<StateTransitionEvent<TransitionTestingComputedState>>(
|
||||
|
|
|
@ -2,9 +2,7 @@ use std::{marker::PhantomData, mem};
|
|||
|
||||
use bevy_ecs::{
|
||||
event::{Event, EventReader, EventWriter},
|
||||
schedule::{
|
||||
InternedScheduleLabel, IntoSystemSetConfigs, Schedule, ScheduleLabel, Schedules, SystemSet,
|
||||
},
|
||||
schedule::{IntoSystemSetConfigs, Schedule, ScheduleLabel, Schedules, SystemSet},
|
||||
system::{Commands, In, ResMut},
|
||||
world::World,
|
||||
};
|
||||
|
@ -181,10 +179,7 @@ pub(crate) fn internal_apply_state_transition<S: States>(
|
|||
///
|
||||
/// Runs automatically when using `App` to insert states, but needs to
|
||||
/// be added manually in other situations.
|
||||
pub fn setup_state_transitions_in_world(
|
||||
world: &mut World,
|
||||
startup_label: Option<InternedScheduleLabel>,
|
||||
) {
|
||||
pub fn setup_state_transitions_in_world(world: &mut World) {
|
||||
let mut schedules = world.get_resource_or_insert_with(Schedules::default);
|
||||
if schedules.contains(StateTransition) {
|
||||
return;
|
||||
|
@ -200,12 +195,6 @@ pub fn setup_state_transitions_in_world(
|
|||
.chain(),
|
||||
);
|
||||
schedules.insert(schedule);
|
||||
|
||||
if let Some(startup) = startup_label {
|
||||
schedules.add_systems(startup, |world: &mut World| {
|
||||
let _ = world.try_run_schedule(StateTransition);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the latest state transition event of type `S`, if any are available.
|
||||
|
|
Loading…
Reference in a new issue