# 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;
}
```