# Basically SystemSets ## Motivation - [bevyengine/bevy#16432](https://github.com/bevyengine/bevy/issues/16432) - Back to Base Sets - [bevyengine/bevy#9139](https://github.com/bevyengine/bevy/issues/9139) - Affinitize System Sets to Schedules - [bevyengine/bevy#9792](https://github.com/bevyengine/bevy/issues/9792) - System sets do not share their configuration across schedules ## TL;DR - Get rid of `Schedules` (plural). - Move `Schedules::ignored_ambiguities` into a new `IgnoredAmbiguities` resource. - Add `MainSchedule` resource that holds a `Schedule`. - Add `FixedMainSchedule` resource that holds a `Schedule`. - Add `StartupSchedule` resource that holds a `Schedule`. - Remove `MainScheduleOrder` and `FixedMainScheduleOrder`. - Order is now defined in terms of normal system set ordering constraints: - `app.configure_sets((First, PreUpdate, Update, PostUpdate, Last).chain());` - `app.configure_fixed_sets((First, PreUpdate, Update, PostUpdate, Last).chain());` - `app.configure_startup_sets((First, PreUpdate, Update, PostUpdate, Last).chain());` ## Considerations - Should we discard the `FixedX` and `XStartup` system sets, and instead use the `XUpdate` sets across all of the bevy-provided schedules? - I don't think we could do this immediately for backwards compatibility reasons, so this is more of a long-term thought. I am highly in favor of this, though. - If a system is added to a set in `MainSchedule`, and that set is not a member of the `Main` system set (even transitively), should the system be ran? Should orphaned system sets be included in execution? ## Ideal API *Note: With the understanding that we will need a backwards compatible transition stage, which is described below.* ```rust // Extracted from Schedules::ignored_ambiguities #[derive(Resource)] pub struct IgnoredAmbiguities(BTreeSet<ComponentId>); // First/PreUpdate/Update/PostUpdate/Last systems and sets go here. #[derive(Resource)] pub struct MainSchedule(Schedule); // FixedFirst/FixedPreUpdate/FixedUpdate/FixedPostUpdate/FixedLast // systems and sets go here. #[derive(Resource)] pub struct FixedMainSchedule(Schedule); // PreStartup/Startup/PostStartup systems and sets go here. #[derive(Resource)] pub struct StartupSchedule(Schedule); // The old ScheduleLabels are changed into SystemSets // and merged into an enum for better discoverability. // We would also use these sets for all of the schedules // above, rather than each of them having their own. #[derive(SystemSet)] pub enum CoreSets { First, PreUpdate, Update, PostUpdate, Last } // Re-export them for good UX and backwards compat. pub use CoreSets::{First, PreUpdate, Update, PostUpdate, Last}; impl App { // Systems registered here go into MainSchedule. pub fn add_systems(&mut self, set: impl SystemSet, systems: impl IntoSystemConfigs<ScheduleSystem>) -> &mut Self; // Sets configured here go into MainSchedule. pub fn configure_sets(&mut self, sets: impl IntoSystemConfigs<InternedSystemSet>) -> &mut Self; // Systems registered here go into FixedMainSchedule. pub fn add_fixed_systems(&mut self, set: impl SystemSet, systems: impl IntoSystemConfigs<ScheduleSystem>) -> &mut Self; // Sets configured here go in FixedMainSchedule. pub fn configure_fixed_sets(&mut self, sets: impl IntoSystemConfigs<InternedSystemSet>) -> &mut Self; // Systems registered here go into StartupSchedule. pub fn add_startup_systems(&mut self, set: impl SystemSet, systems: impl IntoSystemConfigs<ScheduleSystem>) -> &mut Self; // Sets configured here go in StartupSchedule. pub fn configure_startup_sets(&mut self, sets: impl IntoSystemConfigs<InternedSystemSet>) -> &mut Self; } ``` ### Notes - `ScheduleLabel`s are solely used for debugging/visualization now. ## Backwards compatibility To ease the transition we'll need to modify `add_systems` so that the old way of registering systems is still doable. ```rust pub trait TargetSchedule { fn schedule(world: &mut World) -> Mut<'_, Schedule>; } // And for First, PreUpdate, PostUpdate, Last impl TargetSchedule for Update { fn schedule(world: &mut World) -> Mut<'_, Schedule> { world.get_resource_or_init::<MainSchedule>() } } // And for FixedFirst, FixedPreUpdate, FixedPostUpdate, FixedLast impl TargetSchedule for FixedUpdate { fn schedule(world: &mut World) -> Mut<'_, Schedule> { world.get_resource_or_init::<FixedMainSchedule>() } } // And for PreStartup, PostStartup impl TargetSchedule for Startup { fn schedule(world: &mut World) -> Mut<'_, Schedule> { world.get_resource_or_init::<StartupSchedule>() } } impl App { pub fn add_systems(&mut self, set: impl SystemSet + TargetSchedule, systems: impl IntoSystemConfigs<ScheduleSystem>); pub fn configure_sets(&mut self, set: impl SystemSet + TargetSchedule, sets: impl IntoSystemConfigs<InternedSystemSet>); } ``` ## `bevy_state` ```rust // Add a new Schedule resource to store state transitions in. #[derive(Resource)] pub struct StateTransitionSchedule(Schedule); // These were previously ScheduleLabels, and separate structs. #[derive(SystemSet)] pub enum TransitionSets<S: States> { OnEnter(S), OnTransition { from: S, to: S }, OnExit(S) } #[derive(SystemSet)] pub struct FlushState<S: States>(pub S); impl App { pub fn add_state<S: State>(&mut self) -> &mut Self; // The idea here is to let the user configure the order of their state transition sets. pub fn configure_state<S: State>(&mut self, transitions: impl IntoTransitionConfigs<S>) -> &mut Self; pub fn add_state_systems<S>(&mut self, transition: TransitionSets<S>, systems: impl IntoSystemConfigs<ScheduleSystem>) -> &mut Self; pub fn configure_state_sets(&mut self, sets: impl IntoSystemConfigs<ScheduleSystem>) -> &mut Self; } ```