use crate::{App, Plugin};1use alloc::{vec, vec::Vec};2use bevy_ecs::{3resource::Resource,4schedule::{5ExecutorKind, InternedScheduleLabel, IntoScheduleConfigs, Schedule, ScheduleLabel,6SystemSet,7},8system::Local,9world::{Mut, World},10};1112/// The schedule that contains the app logic that is evaluated each tick of [`App::update()`].13///14/// By default, it will run the following schedules in the given order:15///16/// On the first run of the schedule (and only on the first run), it will run:17/// * [`StateTransition`] [^1]18/// * This means that [`OnEnter(MyState::Foo)`] will be called *before* [`PreStartup`]19/// if `MyState` was added to the app with `MyState::Foo` as the initial state,20/// as well as [`OnEnter(MyComputedState)`] if it `compute`s to `Some(Self)` in `MyState::Foo`.21/// * If you want to run systems before any state transitions, regardless of which state is the starting state,22/// for example, for registering required components, you can add your own custom startup schedule23/// before [`StateTransition`]. See [`MainScheduleOrder::insert_startup_before`] for more details.24/// * [`PreStartup`]25/// * [`Startup`]26/// * [`PostStartup`]27///28/// Then it will run:29/// * [`First`]30/// * [`PreUpdate`]31/// * [`StateTransition`] [^1]32/// * [`RunFixedMainLoop`]33/// * This will run [`FixedMain`] zero to many times, based on how much time has elapsed.34/// * [`Update`]35/// * [`PostUpdate`]36/// * [`Last`]37///38/// # Rendering39///40/// Note rendering is not executed in the main schedule by default.41/// Instead, rendering is performed in a separate [`SubApp`]42/// which exchanges data with the main app in between the main schedule runs.43///44/// See [`RenderPlugin`] and [`PipelinedRenderingPlugin`] for more details.45///46/// [^1]: [`StateTransition`] is inserted only if you have `bevy_state` feature enabled. It is enabled in `default` features.47///48/// [`StateTransition`]: https://docs.rs/bevy/latest/bevy/prelude/struct.StateTransition.html49/// [`OnEnter(MyState::Foo)`]: https://docs.rs/bevy/latest/bevy/prelude/struct.OnEnter.html50/// [`OnEnter(MyComputedState)`]: https://docs.rs/bevy/latest/bevy/prelude/struct.OnEnter.html51/// [`RenderPlugin`]: https://docs.rs/bevy/latest/bevy/render/struct.RenderPlugin.html52/// [`PipelinedRenderingPlugin`]: https://docs.rs/bevy/latest/bevy/render/pipelined_rendering/struct.PipelinedRenderingPlugin.html53/// [`SubApp`]: crate::SubApp54#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]55pub struct Main;5657/// The schedule that runs before [`Startup`].58///59/// See the [`Main`] schedule for some details about how schedules are run.60#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]61pub struct PreStartup;6263/// The schedule that runs once when the app starts.64///65/// See the [`Main`] schedule for some details about how schedules are run.66#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]67pub struct Startup;6869/// The schedule that runs once after [`Startup`].70///71/// See the [`Main`] schedule for some details about how schedules are run.72#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]73pub struct PostStartup;7475/// Runs first in the schedule.76///77/// See the [`Main`] schedule for some details about how schedules are run.78#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]79pub struct First;8081/// The schedule that contains logic that must run before [`Update`]. For example, a system that reads raw keyboard82/// input OS events into an `Events` resource. This enables systems in [`Update`] to consume the events from the `Events`83/// resource without actually knowing about (or taking a direct scheduler dependency on) the "os-level keyboard event system".84///85/// [`PreUpdate`] exists to do "engine/plugin preparation work" that ensures the APIs consumed in [`Update`] are "ready".86/// [`PreUpdate`] abstracts out "pre work implementation details".87///88/// See the [`Main`] schedule for some details about how schedules are run.89#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]90pub struct PreUpdate;9192/// Runs the [`FixedMain`] schedule in a loop according until all relevant elapsed time has been "consumed".93///94/// If you need to order your variable timestep systems before or after95/// the fixed update logic, use the [`RunFixedMainLoopSystems`] system set.96///97/// Note that in contrast to most other Bevy schedules, systems added directly to98/// [`RunFixedMainLoop`] will *not* be parallelized between each other.99///100/// See the [`Main`] schedule for some details about how schedules are run.101#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]102pub struct RunFixedMainLoop;103104/// Runs first in the [`FixedMain`] schedule.105///106/// See the [`FixedMain`] schedule for details on how fixed updates work.107/// See the [`Main`] schedule for some details about how schedules are run.108#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]109pub struct FixedFirst;110111/// The schedule that contains logic that must run before [`FixedUpdate`].112///113/// See the [`FixedMain`] schedule for details on how fixed updates work.114/// See the [`Main`] schedule for some details about how schedules are run.115#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]116pub struct FixedPreUpdate;117118/// The schedule that contains most gameplay logic, which runs at a fixed rate rather than every render frame.119/// For logic that should run once per render frame, use the [`Update`] schedule instead.120///121/// Examples of systems that should run at a fixed rate include (but are not limited to):122/// - Physics123/// - AI124/// - Networking125/// - Game rules126///127/// See the [`Update`] schedule for examples of systems that *should not* use this schedule.128/// See the [`FixedMain`] schedule for details on how fixed updates work.129/// See the [`Main`] schedule for some details about how schedules are run.130#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]131pub struct FixedUpdate;132133/// The schedule that runs after the [`FixedUpdate`] schedule, for reacting134/// to changes made in the main update logic.135///136/// See the [`FixedMain`] schedule for details on how fixed updates work.137/// See the [`Main`] schedule for some details about how schedules are run.138#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]139pub struct FixedPostUpdate;140141/// The schedule that runs last in [`FixedMain`]142///143/// See the [`FixedMain`] schedule for details on how fixed updates work.144/// See the [`Main`] schedule for some details about how schedules are run.145#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]146pub struct FixedLast;147148/// The schedule that contains systems which only run after a fixed period of time has elapsed.149///150/// This is run by the [`RunFixedMainLoop`] schedule. If you need to order your variable timestep systems151/// before or after the fixed update logic, use the [`RunFixedMainLoopSystems`] system set.152///153/// Frequency of execution is configured by inserting `Time<Fixed>` resource, 64 Hz by default.154/// See [this example](https://github.com/bevyengine/bevy/blob/latest/examples/time/time.rs).155///156/// See the [`Main`] schedule for some details about how schedules are run.157#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]158pub struct FixedMain;159160/// The schedule that contains any app logic that must run once per render frame.161/// For most gameplay logic, consider using [`FixedUpdate`] instead.162///163/// Examples of systems that should run once per render frame include (but are not limited to):164/// - UI165/// - Input handling166/// - Audio control167///168/// See the [`FixedUpdate`] schedule for examples of systems that *should not* use this schedule.169/// See the [`Main`] schedule for some details about how schedules are run.170#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]171pub struct Update;172173/// The schedule that contains scene spawning.174///175/// See the [`Main`] schedule for some details about how schedules are run.176#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]177pub struct SpawnScene;178179/// The schedule that contains logic that must run after [`Update`]. For example, synchronizing "local transforms" in a hierarchy180/// to "global" absolute transforms. This enables the [`PostUpdate`] transform-sync system to react to "local transform" changes in181/// [`Update`] without the [`Update`] systems needing to know about (or add scheduler dependencies for) the "global transform sync system".182///183/// [`PostUpdate`] exists to do "engine/plugin response work" to things that happened in [`Update`].184/// [`PostUpdate`] abstracts out "implementation details" from users defining systems in [`Update`].185///186/// See the [`Main`] schedule for some details about how schedules are run.187#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]188pub struct PostUpdate;189190/// Runs last in the schedule.191///192/// See the [`Main`] schedule for some details about how schedules are run.193#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]194pub struct Last;195196/// Animation system set. This exists in [`PostUpdate`].197#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]198pub struct AnimationSystems;199200/// Deprecated alias for [`AnimationSystems`].201#[deprecated(since = "0.17.0", note = "Renamed to `AnimationSystems`.")]202pub type Animation = AnimationSystems;203204/// Defines the schedules to be run for the [`Main`] schedule, including205/// their order.206#[derive(Resource, Debug)]207pub struct MainScheduleOrder {208/// The labels to run for the main phase of the [`Main`] schedule (in the order they will be run).209pub labels: Vec<InternedScheduleLabel>,210/// The labels to run for the startup phase of the [`Main`] schedule (in the order they will be run).211pub startup_labels: Vec<InternedScheduleLabel>,212}213214impl Default for MainScheduleOrder {215fn default() -> Self {216Self {217labels: vec![218First.intern(),219PreUpdate.intern(),220RunFixedMainLoop.intern(),221Update.intern(),222SpawnScene.intern(),223PostUpdate.intern(),224Last.intern(),225],226startup_labels: vec![PreStartup.intern(), Startup.intern(), PostStartup.intern()],227}228}229}230231impl MainScheduleOrder {232/// Adds the given `schedule` after the `after` schedule in the main list of schedules.233pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {234let index = self235.labels236.iter()237.position(|current| (**current).eq(&after))238.unwrap_or_else(|| panic!("Expected {after:?} to exist"));239self.labels.insert(index + 1, schedule.intern());240}241242/// Adds the given `schedule` before the `before` schedule in the main list of schedules.243pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {244let index = self245.labels246.iter()247.position(|current| (**current).eq(&before))248.unwrap_or_else(|| panic!("Expected {before:?} to exist"));249self.labels.insert(index, schedule.intern());250}251252/// Adds the given `schedule` after the `after` schedule in the list of startup schedules.253pub fn insert_startup_after(254&mut self,255after: impl ScheduleLabel,256schedule: impl ScheduleLabel,257) {258let index = self259.startup_labels260.iter()261.position(|current| (**current).eq(&after))262.unwrap_or_else(|| panic!("Expected {after:?} to exist"));263self.startup_labels.insert(index + 1, schedule.intern());264}265266/// Adds the given `schedule` before the `before` schedule in the list of startup schedules.267pub fn insert_startup_before(268&mut self,269before: impl ScheduleLabel,270schedule: impl ScheduleLabel,271) {272let index = self273.startup_labels274.iter()275.position(|current| (**current).eq(&before))276.unwrap_or_else(|| panic!("Expected {before:?} to exist"));277self.startup_labels.insert(index, schedule.intern());278}279}280281impl Main {282/// A system that runs the "main schedule"283pub fn run_main(world: &mut World, mut run_at_least_once: Local<bool>) {284if !*run_at_least_once {285world.resource_scope(|world, order: Mut<MainScheduleOrder>| {286for &label in &order.startup_labels {287let _ = world.try_run_schedule(label);288}289});290*run_at_least_once = true;291}292293world.resource_scope(|world, order: Mut<MainScheduleOrder>| {294for &label in &order.labels {295let _ = world.try_run_schedule(label);296}297});298}299}300301/// Initializes the [`Main`] schedule, sub schedules, and resources for a given [`App`].302pub struct MainSchedulePlugin;303304impl Plugin for MainSchedulePlugin {305fn build(&self, app: &mut App) {306// simple "facilitator" schedules benefit from simpler single threaded scheduling307let mut main_schedule = Schedule::new(Main);308main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);309let mut fixed_main_schedule = Schedule::new(FixedMain);310fixed_main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);311let mut fixed_main_loop_schedule = Schedule::new(RunFixedMainLoop);312fixed_main_loop_schedule.set_executor_kind(ExecutorKind::SingleThreaded);313314app.add_schedule(main_schedule)315.add_schedule(fixed_main_schedule)316.add_schedule(fixed_main_loop_schedule)317.init_resource::<MainScheduleOrder>()318.init_resource::<FixedMainScheduleOrder>()319.add_systems(Main, Main::run_main)320.add_systems(FixedMain, FixedMain::run_fixed_main)321.configure_sets(322RunFixedMainLoop,323(324RunFixedMainLoopSystems::BeforeFixedMainLoop,325RunFixedMainLoopSystems::FixedMainLoop,326RunFixedMainLoopSystems::AfterFixedMainLoop,327)328.chain(),329);330331#[cfg(feature = "bevy_debug_stepping")]332{333use bevy_ecs::schedule::{IntoScheduleConfigs, Stepping};334app.add_systems(Main, Stepping::begin_frame.before(Main::run_main));335}336}337}338339/// Defines the schedules to be run for the [`FixedMain`] schedule, including340/// their order.341#[derive(Resource, Debug)]342pub struct FixedMainScheduleOrder {343/// The labels to run for the [`FixedMain`] schedule (in the order they will be run).344pub labels: Vec<InternedScheduleLabel>,345}346347impl Default for FixedMainScheduleOrder {348fn default() -> Self {349Self {350labels: vec![351FixedFirst.intern(),352FixedPreUpdate.intern(),353FixedUpdate.intern(),354FixedPostUpdate.intern(),355FixedLast.intern(),356],357}358}359}360361impl FixedMainScheduleOrder {362/// Adds the given `schedule` after the `after` schedule363pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {364let index = self365.labels366.iter()367.position(|current| (**current).eq(&after))368.unwrap_or_else(|| panic!("Expected {after:?} to exist"));369self.labels.insert(index + 1, schedule.intern());370}371372/// Adds the given `schedule` before the `before` schedule373pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {374let index = self375.labels376.iter()377.position(|current| (**current).eq(&before))378.unwrap_or_else(|| panic!("Expected {before:?} to exist"));379self.labels.insert(index, schedule.intern());380}381}382383impl FixedMain {384/// A system that runs the fixed timestep's "main schedule"385pub fn run_fixed_main(world: &mut World) {386world.resource_scope(|world, order: Mut<FixedMainScheduleOrder>| {387for &label in &order.labels {388let _ = world.try_run_schedule(label);389}390});391}392}393394/// Set enum for the systems that want to run inside [`RunFixedMainLoop`],395/// but before or after the fixed update logic. Systems in this set396/// will run exactly once per frame, regardless of the number of fixed updates.397/// They will also run under a variable timestep.398///399/// This is useful for handling things that need to run every frame, but400/// also need to be read by the fixed update logic. See the individual variants401/// for examples of what kind of systems should be placed in each.402///403/// Note that in contrast to most other Bevy schedules, systems added directly to404/// [`RunFixedMainLoop`] will *not* be parallelized between each other.405#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone, SystemSet)]406pub enum RunFixedMainLoopSystems {407/// Runs before the fixed update logic.408///409/// A good example of a system that fits here410/// is camera movement, which needs to be updated in a variable timestep,411/// as you want the camera to move with as much precision and updates as412/// the frame rate allows. A physics system that needs to read the camera413/// position and orientation, however, should run in the fixed update logic,414/// as it needs to be deterministic and run at a fixed rate for better stability.415/// Note that we are not placing the camera movement system in `Update`, as that416/// would mean that the physics system already ran at that point.417///418/// # Example419/// ```420/// # use bevy_app::prelude::*;421/// # use bevy_ecs::prelude::*;422/// App::new()423/// .add_systems(424/// RunFixedMainLoop,425/// update_camera_rotation.in_set(RunFixedMainLoopSystems::BeforeFixedMainLoop))426/// .add_systems(FixedUpdate, update_physics);427///428/// # fn update_camera_rotation() {}429/// # fn update_physics() {}430/// ```431BeforeFixedMainLoop,432/// Contains the fixed update logic.433/// Runs [`FixedMain`] zero or more times based on delta of434/// [`Time<Virtual>`] and [`Time::overstep`].435///436/// Don't place systems here, use [`FixedUpdate`] and friends instead.437/// Use this system instead to order your systems to run specifically inbetween the fixed update logic and all438/// other systems that run in [`RunFixedMainLoopSystems::BeforeFixedMainLoop`] or [`RunFixedMainLoopSystems::AfterFixedMainLoop`].439///440/// [`Time<Virtual>`]: https://docs.rs/bevy/latest/bevy/prelude/struct.Virtual.html441/// [`Time::overstep`]: https://docs.rs/bevy/latest/bevy/time/struct.Time.html#method.overstep442/// # Example443/// ```444/// # use bevy_app::prelude::*;445/// # use bevy_ecs::prelude::*;446/// App::new()447/// .add_systems(FixedUpdate, update_physics)448/// .add_systems(449/// RunFixedMainLoop,450/// (451/// // This system will be called before all interpolation systems452/// // that third-party plugins might add.453/// prepare_for_interpolation454/// .after(RunFixedMainLoopSystems::FixedMainLoop)455/// .before(RunFixedMainLoopSystems::AfterFixedMainLoop),456/// )457/// );458///459/// # fn prepare_for_interpolation() {}460/// # fn update_physics() {}461/// ```462FixedMainLoop,463/// Runs after the fixed update logic.464///465/// A good example of a system that fits here466/// is a system that interpolates the transform of an entity between the last and current fixed update.467/// See the [fixed timestep example] for more details.468///469/// [fixed timestep example]: https://github.com/bevyengine/bevy/blob/main/examples/movement/physics_in_fixed_timestep.rs470///471/// # Example472/// ```473/// # use bevy_app::prelude::*;474/// # use bevy_ecs::prelude::*;475/// App::new()476/// .add_systems(FixedUpdate, update_physics)477/// .add_systems(478/// RunFixedMainLoop,479/// interpolate_transforms.in_set(RunFixedMainLoopSystems::AfterFixedMainLoop));480///481/// # fn interpolate_transforms() {}482/// # fn update_physics() {}483/// ```484AfterFixedMainLoop,485}486487/// Deprecated alias for [`RunFixedMainLoopSystems`].488#[deprecated(since = "0.17.0", note = "Renamed to `RunFixedMainLoopSystems`.")]489pub type RunFixedMainLoopSystem = RunFixedMainLoopSystems;490491492