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/// * [`SpawnScene`]36/// * [`PostUpdate`]37/// * [`Last`]38///39/// # Rendering40///41/// Note rendering is not executed in the main schedule by default.42/// Instead, rendering is performed in a separate [`SubApp`]43/// which exchanges data with the main app in between the main schedule runs.44///45/// See [`RenderPlugin`] and [`PipelinedRenderingPlugin`] for more details.46///47/// [^1]: [`StateTransition`] is inserted only if you have `bevy_state` feature enabled. It is enabled in `default` features.48///49/// [`StateTransition`]: https://docs.rs/bevy/latest/bevy/prelude/struct.StateTransition.html50/// [`OnEnter(MyState::Foo)`]: https://docs.rs/bevy/latest/bevy/prelude/struct.OnEnter.html51/// [`OnEnter(MyComputedState)`]: https://docs.rs/bevy/latest/bevy/prelude/struct.OnEnter.html52/// [`RenderPlugin`]: https://docs.rs/bevy/latest/bevy/render/struct.RenderPlugin.html53/// [`PipelinedRenderingPlugin`]: https://docs.rs/bevy/latest/bevy/render/pipelined_rendering/struct.PipelinedRenderingPlugin.html54/// [`SubApp`]: crate::SubApp55#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]56pub struct Main;5758/// The schedule that runs before [`Startup`].59///60/// See the [`Main`] schedule for some details about how schedules are run.61#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]62pub struct PreStartup;6364/// The schedule that runs once when the app starts.65///66/// See the [`Main`] schedule for some details about how schedules are run.67#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]68pub struct Startup;6970/// The schedule that runs once after [`Startup`].71///72/// See the [`Main`] schedule for some details about how schedules are run.73#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]74pub struct PostStartup;7576/// Runs first in the schedule.77///78/// See the [`Main`] schedule for some details about how schedules are run.79#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]80pub struct First;8182/// The schedule that contains logic that must run before [`Update`]. For example, a system that reads raw keyboard83/// input OS events into a `Messages` resource. This enables systems in [`Update`] to consume the messages from the `Messages`84/// resource without actually knowing about (or taking a direct scheduler dependency on) the "os-level keyboard event system".85///86/// [`PreUpdate`] exists to do "engine/plugin preparation work" that ensures the APIs consumed in [`Update`] are "ready".87/// [`PreUpdate`] abstracts out "pre work implementation details".88///89/// See the [`Main`] schedule for some details about how schedules are run.90#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]91pub struct PreUpdate;9293/// Runs the [`FixedMain`] schedule in a loop according until all relevant elapsed time has been "consumed".94///95/// If you need to order your variable timestep systems before or after96/// the fixed update logic, use the [`RunFixedMainLoopSystems`] system set.97///98/// Note that in contrast to most other Bevy schedules, systems added directly to99/// [`RunFixedMainLoop`] will *not* be parallelized between each other.100///101/// See the [`Main`] schedule for some details about how schedules are run.102#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]103pub struct RunFixedMainLoop;104105/// Runs first in the [`FixedMain`] schedule.106///107/// See the [`FixedMain`] schedule for details on how fixed updates work.108/// See the [`Main`] schedule for some details about how schedules are run.109#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]110pub struct FixedFirst;111112/// The schedule that contains logic that must run before [`FixedUpdate`].113///114/// See the [`FixedMain`] schedule for details on how fixed updates work.115/// See the [`Main`] schedule for some details about how schedules are run.116#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]117pub struct FixedPreUpdate;118119/// The schedule that contains most gameplay logic, which runs at a fixed rate rather than every render frame.120/// For logic that should run once per render frame, use the [`Update`] schedule instead.121///122/// Examples of systems that should run at a fixed rate include (but are not limited to):123/// - Physics124/// - AI125/// - Networking126/// - Game rules127///128/// See the [`Update`] schedule for examples of systems that *should not* use this schedule.129/// See the [`FixedMain`] schedule for details on how fixed updates work.130/// See the [`Main`] schedule for some details about how schedules are run.131#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]132pub struct FixedUpdate;133134/// The schedule that runs after the [`FixedUpdate`] schedule, for reacting135/// to changes made in the main update logic.136///137/// See the [`FixedMain`] schedule for details on how fixed updates work.138/// See the [`Main`] schedule for some details about how schedules are run.139#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]140pub struct FixedPostUpdate;141142/// The schedule that runs last in [`FixedMain`]143///144/// See the [`FixedMain`] schedule for details on how fixed updates work.145/// See the [`Main`] schedule for some details about how schedules are run.146#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]147pub struct FixedLast;148149/// The schedule that contains systems which only run after a fixed period of time has elapsed.150///151/// This is run by the [`RunFixedMainLoop`] schedule. If you need to order your variable timestep systems152/// before or after the fixed update logic, use the [`RunFixedMainLoopSystems`] system set.153///154/// Frequency of execution is configured by inserting `Time<Fixed>` resource, 64 Hz by default.155/// See [this example](https://github.com/bevyengine/bevy/blob/latest/examples/time/time.rs).156///157/// See the [`Main`] schedule for some details about how schedules are run.158#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]159pub struct FixedMain;160161/// The schedule that contains any app logic that must run once per render frame.162/// For most gameplay logic, consider using [`FixedUpdate`] instead.163///164/// Examples of systems that should run once per render frame include (but are not limited to):165/// - UI166/// - Input handling167/// - Audio control168///169/// See the [`FixedUpdate`] schedule for examples of systems that *should not* use this schedule.170/// See the [`Main`] schedule for some details about how schedules are run.171#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]172pub struct Update;173174/// The schedule that contains scene spawning.175///176/// This runs after [`Update`] and before [`PostUpdate`]. See the [`Main`] schedule for more details about how schedules are run.177#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]178pub struct SpawnScene;179180/// The schedule that contains logic that must run after [`Update`]. For example, synchronizing "local transforms" in a hierarchy181/// to "global" absolute transforms. This enables the [`PostUpdate`] transform-sync system to react to "local transform" changes in182/// [`Update`] without the [`Update`] systems needing to know about (or add scheduler dependencies for) the "global transform sync system".183///184/// [`PostUpdate`] exists to do "engine/plugin response work" to things that happened in [`Update`].185/// [`PostUpdate`] abstracts out "implementation details" from users defining systems in [`Update`].186///187/// See the [`Main`] schedule for some details about how schedules are run.188#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]189pub struct PostUpdate;190191/// Runs last in the schedule.192///193/// See the [`Main`] schedule for some details about how schedules are run.194#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]195pub struct Last;196197/// Animation system set. This exists in [`PostUpdate`].198#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]199pub struct AnimationSystems;200201/// Defines the schedules to be run for the [`Main`] schedule, including202/// their order.203#[derive(Resource, Debug)]204pub struct MainScheduleOrder {205/// The labels to run for the main phase of the [`Main`] schedule (in the order they will be run).206pub labels: Vec<InternedScheduleLabel>,207/// The labels to run for the startup phase of the [`Main`] schedule (in the order they will be run).208pub startup_labels: Vec<InternedScheduleLabel>,209}210211impl Default for MainScheduleOrder {212fn default() -> Self {213Self {214labels: vec![215First.intern(),216PreUpdate.intern(),217RunFixedMainLoop.intern(),218Update.intern(),219SpawnScene.intern(),220PostUpdate.intern(),221Last.intern(),222],223startup_labels: vec![PreStartup.intern(), Startup.intern(), PostStartup.intern()],224}225}226}227228impl MainScheduleOrder {229/// Adds the given `schedule` after the `after` schedule in the main list of schedules.230pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {231let index = self232.labels233.iter()234.position(|current| (**current).eq(&after))235.unwrap_or_else(|| panic!("Expected {after:?} to exist"));236self.labels.insert(index + 1, schedule.intern());237}238239/// Adds the given `schedule` before the `before` schedule in the main list of schedules.240pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {241let index = self242.labels243.iter()244.position(|current| (**current).eq(&before))245.unwrap_or_else(|| panic!("Expected {before:?} to exist"));246self.labels.insert(index, schedule.intern());247}248249/// Adds the given `schedule` after the `after` schedule in the list of startup schedules.250pub fn insert_startup_after(251&mut self,252after: impl ScheduleLabel,253schedule: impl ScheduleLabel,254) {255let index = self256.startup_labels257.iter()258.position(|current| (**current).eq(&after))259.unwrap_or_else(|| panic!("Expected {after:?} to exist"));260self.startup_labels.insert(index + 1, schedule.intern());261}262263/// Adds the given `schedule` before the `before` schedule in the list of startup schedules.264pub fn insert_startup_before(265&mut self,266before: impl ScheduleLabel,267schedule: impl ScheduleLabel,268) {269let index = self270.startup_labels271.iter()272.position(|current| (**current).eq(&before))273.unwrap_or_else(|| panic!("Expected {before:?} to exist"));274self.startup_labels.insert(index, schedule.intern());275}276}277278impl Main {279/// A system that runs the "main schedule"280pub fn run_main(world: &mut World, mut run_at_least_once: Local<bool>) {281if !*run_at_least_once {282world.resource_scope(|world, order: Mut<MainScheduleOrder>| {283for &label in &order.startup_labels {284let _ = world.try_run_schedule(label);285}286});287*run_at_least_once = true;288}289290world.resource_scope(|world, order: Mut<MainScheduleOrder>| {291for &label in &order.labels {292let _ = world.try_run_schedule(label);293}294});295}296}297298/// Initializes the [`Main`] schedule, sub schedules, and resources for a given [`App`].299pub struct MainSchedulePlugin;300301impl Plugin for MainSchedulePlugin {302fn build(&self, app: &mut App) {303// simple "facilitator" schedules benefit from simpler single threaded scheduling304let mut main_schedule = Schedule::new(Main);305main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);306let mut fixed_main_schedule = Schedule::new(FixedMain);307fixed_main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);308let mut fixed_main_loop_schedule = Schedule::new(RunFixedMainLoop);309fixed_main_loop_schedule.set_executor_kind(ExecutorKind::SingleThreaded);310311app.add_schedule(main_schedule)312.add_schedule(fixed_main_schedule)313.add_schedule(fixed_main_loop_schedule)314.init_resource::<MainScheduleOrder>()315.init_resource::<FixedMainScheduleOrder>()316.add_systems(Main, Main::run_main)317.add_systems(FixedMain, FixedMain::run_fixed_main)318.configure_sets(319RunFixedMainLoop,320(321RunFixedMainLoopSystems::BeforeFixedMainLoop,322RunFixedMainLoopSystems::FixedMainLoop,323RunFixedMainLoopSystems::AfterFixedMainLoop,324)325.chain(),326);327328#[cfg(feature = "bevy_debug_stepping")]329{330use bevy_ecs::schedule::{IntoScheduleConfigs, Stepping};331app.add_systems(Main, Stepping::begin_frame.before(Main::run_main));332}333}334}335336/// Defines the schedules to be run for the [`FixedMain`] schedule, including337/// their order.338#[derive(Resource, Debug)]339pub struct FixedMainScheduleOrder {340/// The labels to run for the [`FixedMain`] schedule (in the order they will be run).341pub labels: Vec<InternedScheduleLabel>,342}343344impl Default for FixedMainScheduleOrder {345fn default() -> Self {346Self {347labels: vec![348FixedFirst.intern(),349FixedPreUpdate.intern(),350FixedUpdate.intern(),351FixedPostUpdate.intern(),352FixedLast.intern(),353],354}355}356}357358impl FixedMainScheduleOrder {359/// Adds the given `schedule` after the `after` schedule360pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {361let index = self362.labels363.iter()364.position(|current| (**current).eq(&after))365.unwrap_or_else(|| panic!("Expected {after:?} to exist"));366self.labels.insert(index + 1, schedule.intern());367}368369/// Adds the given `schedule` before the `before` schedule370pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {371let index = self372.labels373.iter()374.position(|current| (**current).eq(&before))375.unwrap_or_else(|| panic!("Expected {before:?} to exist"));376self.labels.insert(index, schedule.intern());377}378}379380impl FixedMain {381/// A system that runs the fixed timestep's "main schedule"382pub fn run_fixed_main(world: &mut World) {383world.resource_scope(|world, order: Mut<FixedMainScheduleOrder>| {384for &label in &order.labels {385let _ = world.try_run_schedule(label);386}387});388}389}390391/// Set enum for the systems that want to run inside [`RunFixedMainLoop`],392/// but before or after the fixed update logic. Systems in this set393/// will run exactly once per frame, regardless of the number of fixed updates.394/// They will also run under a variable timestep.395///396/// This is useful for handling things that need to run every frame, but397/// also need to be read by the fixed update logic. See the individual variants398/// for examples of what kind of systems should be placed in each.399///400/// Note that in contrast to most other Bevy schedules, systems added directly to401/// [`RunFixedMainLoop`] will *not* be parallelized between each other.402#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone, SystemSet)]403pub enum RunFixedMainLoopSystems {404/// Runs before the fixed update logic.405///406/// A good example of a system that fits here407/// is camera movement, which needs to be updated in a variable timestep,408/// as you want the camera to move with as much precision and updates as409/// the frame rate allows. A physics system that needs to read the camera410/// position and orientation, however, should run in the fixed update logic,411/// as it needs to be deterministic and run at a fixed rate for better stability.412/// Note that we are not placing the camera movement system in `Update`, as that413/// would mean that the physics system already ran at that point.414///415/// # Example416/// ```417/// # use bevy_app::prelude::*;418/// # use bevy_ecs::prelude::*;419/// App::new()420/// .add_systems(421/// RunFixedMainLoop,422/// update_camera_rotation.in_set(RunFixedMainLoopSystems::BeforeFixedMainLoop))423/// .add_systems(FixedUpdate, update_physics);424///425/// # fn update_camera_rotation() {}426/// # fn update_physics() {}427/// ```428BeforeFixedMainLoop,429/// Contains the fixed update logic.430/// Runs [`FixedMain`] zero or more times based on delta of431/// [`Time<Virtual>`] and [`Time::overstep`].432///433/// Don't place systems here, use [`FixedUpdate`] and friends instead.434/// Use this system instead to order your systems to run specifically inbetween the fixed update logic and all435/// other systems that run in [`RunFixedMainLoopSystems::BeforeFixedMainLoop`] or [`RunFixedMainLoopSystems::AfterFixedMainLoop`].436///437/// [`Time<Virtual>`]: https://docs.rs/bevy/latest/bevy/prelude/struct.Virtual.html438/// [`Time::overstep`]: https://docs.rs/bevy/latest/bevy/time/struct.Time.html#method.overstep439/// # Example440/// ```441/// # use bevy_app::prelude::*;442/// # use bevy_ecs::prelude::*;443/// App::new()444/// .add_systems(FixedUpdate, update_physics)445/// .add_systems(446/// RunFixedMainLoop,447/// (448/// // This system will be called before all interpolation systems449/// // that third-party plugins might add.450/// prepare_for_interpolation451/// .after(RunFixedMainLoopSystems::FixedMainLoop)452/// .before(RunFixedMainLoopSystems::AfterFixedMainLoop),453/// )454/// );455///456/// # fn prepare_for_interpolation() {}457/// # fn update_physics() {}458/// ```459FixedMainLoop,460/// Runs after the fixed update logic.461///462/// A good example of a system that fits here463/// is a system that interpolates the transform of an entity between the last and current fixed update.464/// See the [fixed timestep example] for more details.465///466/// [fixed timestep example]: https://github.com/bevyengine/bevy/blob/main/examples/movement/physics_in_fixed_timestep.rs467///468/// # Example469/// ```470/// # use bevy_app::prelude::*;471/// # use bevy_ecs::prelude::*;472/// App::new()473/// .add_systems(FixedUpdate, update_physics)474/// .add_systems(475/// RunFixedMainLoop,476/// interpolate_transforms.in_set(RunFixedMainLoopSystems::AfterFixedMainLoop));477///478/// # fn interpolate_transforms() {}479/// # fn update_physics() {}480/// ```481AfterFixedMainLoop,482}483484485