Skip to content

Commit efb328f

Browse files
committed
Add top-level schedules
1 parent eaa137b commit efb328f

File tree

7 files changed

+185
-104
lines changed

7 files changed

+185
-104
lines changed

crates/bevy_app/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ pub mod prelude {
2525
pub use crate::{
2626
app::App,
2727
main_schedule::{
28-
First, FixedUpdate, Last, UpdateFlow, PostStartup, PostUpdate, PreStartup, PreUpdate, RenderFlow,
29-
Startup, StateTransition, Update,
28+
Control, First, FixedUpdate, FrameReady, Last, PostStartup, PostUpdate, PreStartup,
29+
PreUpdate, RenderFlow, Startup, StartupFlow, StateTransition, Update, UpdateFlow,
3030
},
3131
DynamicPlugin, Plugin, PluginGroup,
3232
};

crates/bevy_app/src/main_schedule.rs

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,48 @@
11
use crate::{App, Plugin};
22
use bevy_ecs::{
33
schedule::{ExecutorKind, Schedule, ScheduleLabel},
4-
system::{Local, Resource},
4+
system::Resource,
55
world::{Mut, World},
66
};
77

8-
/// The schedule that contains the app logic that is evaluated each tick of event loop.
9-
///
10-
/// By default, it will run the following schedules in the given order:
11-
///
128
/// On the first run of the schedule (and only on the first run), it will run:
139
/// * [`PreStartup`]
1410
/// * [`Startup`]
1511
/// * [`PostStartup`]
16-
///
17-
/// Then it will run:
18-
/// * [`First`]
19-
/// * [`PreUpdate`]
20-
/// * [`StateTransition`]
21-
/// * [`RunFixedUpdateLoop`]
22-
/// * This will run [`FixedUpdate`] zero to many times, based on how much time has elapsed.
23-
/// * [`Update`]
24-
/// * [`PostUpdate`]
25-
/// * [`Last`]
2612
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
27-
pub struct UpdateFlow;
13+
pub struct StartupFlow;
2814

2915
/// The schedule that runs before [`Startup`].
30-
/// This is run by the [`Main`] schedule.
16+
/// This is run by the [`StartupFlow`] schedule.
3117
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
3218
pub struct PreStartup;
3319

3420
/// The schedule that runs once when the app starts.
35-
/// This is run by the [`Main`] schedule.
21+
/// This is run by the [`StartupFlow`] schedule.
3622
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
3723
pub struct Startup;
3824

3925
/// The schedule that runs once after [`Startup`].
40-
/// This is run by the [`Main`] schedule.
26+
/// This is run by the [`StartupFlow`] schedule.
4127
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
4228
pub struct PostStartup;
4329

30+
/// The schedule that contains the app logic that is evaluated each tick of event loop.
31+
///
32+
/// By default, it will run the following schedules in the given order:
33+
/// * [`First`]
34+
/// * [`PreUpdate`]
35+
/// * [`StateTransition`]
36+
/// * [`RunFixedUpdateLoop`]
37+
/// * This will run [`FixedUpdate`] zero to many times, based on how much time has elapsed.
38+
/// * [`Update`]
39+
/// * [`PostUpdate`]
40+
/// * [`Last`]
41+
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
42+
pub struct UpdateFlow;
43+
4444
/// Runs first in the schedule.
45-
/// This is run by the [`Main`] schedule.
45+
/// This is run by the [`UpdateFlow`] schedule.
4646
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
4747
pub struct First;
4848

@@ -53,17 +53,17 @@ pub struct First;
5353
/// [`PreUpdate`] exists to do "engine/plugin preparation work" that ensures the APIs consumed in [`Update`] are "ready".
5454
/// [`PreUpdate`] abstracts out "pre work implementation details".
5555
///
56-
/// This is run by the [`Main`] schedule.
56+
/// This is run by the [`UpdateFlow`] schedule.
5757
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
5858
pub struct PreUpdate;
5959

6060
/// Runs [state transitions](bevy_ecs::schedule::States).
61-
/// This is run by the [`Main`] schedule.
61+
/// This is run by the [`UpdateFlow`] schedule.
6262
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
6363
pub struct StateTransition;
6464

6565
/// Runs the [`FixedUpdate`] schedule in a loop according until all relevant elapsed time has been "consumed".
66-
/// This is run by the [`Main`] schedule.
66+
/// This is run by the [`UpdateFlow`] schedule.
6767
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
6868
pub struct RunFixedUpdateLoop;
6969

@@ -75,7 +75,7 @@ pub struct RunFixedUpdateLoop;
7575
pub struct FixedUpdate;
7676

7777
/// The schedule that contains app logic.
78-
/// This is run by the [`Main`] schedule.
78+
/// This is run by the [`UpdateFlow`] schedule.
7979
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
8080
pub struct Update;
8181

@@ -86,16 +86,26 @@ pub struct Update;
8686
/// [`PostUpdate`] exists to do "engine/plugin response work" to things that happened in [`Update`].
8787
/// [`PostUpdate`] abstracts out "implementation details" from users defining systems in [`Update`].
8888
///
89-
/// This is run by the [`Main`] schedule.
89+
/// This is run by the [`UpdateFlow`] schedule.
9090
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
9191
pub struct PostUpdate;
9292

9393
/// Runs last in the schedule.
94-
/// This is run by the [`Main`] schedule.
94+
/// This is run by the [`UpdateFlow`] schedule.
9595
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
9696
pub struct Last;
9797

98-
/// The main render schedule.
98+
/// Each time an event is received from windows and devices, this schedule is run.
99+
/// This is useful for responding to events regardless of whether tick updates take place.
100+
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
101+
pub struct Control;
102+
103+
/// Each time a frame is ready to be updated, this schedule is run.
104+
/// This is the best place to decide whether to redraw.
105+
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
106+
pub struct FrameReady;
107+
108+
/// The schedule that builds and sends drawing queries to the GPU.
99109
#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)]
100110
pub struct RenderFlow;
101111

@@ -135,16 +145,19 @@ impl UpdateFlowOrder {
135145
}
136146
}
137147

138-
impl UpdateFlow {
139-
/// A system that runs the "main schedule"
140-
pub fn run_main(world: &mut World, mut run_at_least_once: Local<bool>) {
141-
if !*run_at_least_once {
142-
let _ = world.try_run_schedule(PreStartup);
143-
let _ = world.try_run_schedule(Startup);
144-
let _ = world.try_run_schedule(PostStartup);
145-
*run_at_least_once = true;
146-
}
148+
/// Initializes the [`StartupFlow`] schedule, [`UpdateFlow`] schedule, sub schedules, and resources for a given [`App`].
149+
pub struct MainSchedulePlugin;
147150

151+
impl MainSchedulePlugin {
152+
/// A system that runs the `StartupFlow` sub schedules
153+
pub fn run_startup(world: &mut World) {
154+
let _ = world.try_run_schedule(PreStartup);
155+
let _ = world.try_run_schedule(Startup);
156+
let _ = world.try_run_schedule(PostStartup);
157+
}
158+
159+
/// A system that runs the `UpdateFlow` sub schedules
160+
pub fn run_update(world: &mut World) {
148161
world.resource_scope(|world, order: Mut<UpdateFlowOrder>| {
149162
for label in &order.labels {
150163
let _ = world.try_run_schedule(&**label);
@@ -153,20 +166,21 @@ impl UpdateFlow {
153166
}
154167
}
155168

156-
/// Initializes the [`Main`] schedule, sub schedules, and resources for a given [`App`].
157-
pub struct MainSchedulePlugin;
158-
159169
impl Plugin for MainSchedulePlugin {
160170
fn build(&self, app: &mut App) {
161171
// simple "facilitator" schedules benefit from simpler single threaded scheduling
162-
let mut main_schedule = Schedule::new();
163-
main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
172+
let mut startup_schedule = Schedule::new();
173+
startup_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
174+
let mut update_schedule = Schedule::new();
175+
update_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
164176
let mut fixed_update_loop_schedule = Schedule::new();
165177
fixed_update_loop_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
166178

167-
app.add_schedule(UpdateFlow, main_schedule)
179+
app.add_schedule(StartupFlow, startup_schedule)
180+
.add_schedule(UpdateFlow, update_schedule)
168181
.add_schedule(RunFixedUpdateLoop, fixed_update_loop_schedule)
169182
.init_resource::<UpdateFlowOrder>()
170-
.add_systems(UpdateFlow, UpdateFlow::run_main);
183+
.add_systems(StartupFlow, Self::run_startup)
184+
.add_systems(UpdateFlow, Self::run_update);
171185
}
172186
}

crates/bevy_app/src/schedule_runner.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
app::{App, AppExit},
33
plugin::Plugin,
4-
UpdateFlow,
4+
StartupFlow, UpdateFlow,
55
};
66
use bevy_ecs::{
77
event::{Events, ManualEventReader},
@@ -53,18 +53,22 @@ impl Default for RunMode {
5353
pub struct ScheduleRunnerPlugin {
5454
/// Determines whether the [`Schedule`](bevy_ecs::schedule::Schedule) is run once or repeatedly.
5555
pub run_mode: RunMode,
56-
/// The schedule to run by default.
56+
/// This schedule is run only once at startup.
5757
///
58-
/// This is initially set to [`Main`].
59-
pub main_schedule_label: BoxedScheduleLabel,
58+
/// The default is [`StartupFlow`].
59+
pub startup_schedule_label: BoxedScheduleLabel,
60+
/// This schedule is run for each tick.
61+
///
62+
/// The default is [`UpdateFlow`].
63+
pub update_schedule_label: BoxedScheduleLabel,
6064
}
6165

6266
impl ScheduleRunnerPlugin {
6367
/// See [`RunMode::Once`].
6468
pub fn run_once() -> Self {
6569
ScheduleRunnerPlugin {
6670
run_mode: RunMode::Once,
67-
main_schedule_label: Box::new(UpdateFlow),
71+
..Default::default()
6872
}
6973
}
7074

@@ -74,7 +78,7 @@ impl ScheduleRunnerPlugin {
7478
run_mode: RunMode::Loop {
7579
wait: Some(wait_duration),
7680
},
77-
main_schedule_label: Box::new(UpdateFlow),
81+
..Default::default()
7882
}
7983
}
8084
}
@@ -83,27 +87,36 @@ impl Default for ScheduleRunnerPlugin {
8387
fn default() -> Self {
8488
ScheduleRunnerPlugin {
8589
run_mode: RunMode::Loop { wait: None },
86-
main_schedule_label: Box::new(UpdateFlow),
90+
startup_schedule_label: Box::new(StartupFlow),
91+
update_schedule_label: Box::new(UpdateFlow),
8792
}
8893
}
8994
}
9095

9196
impl Plugin for ScheduleRunnerPlugin {
9297
fn build(&self, app: &mut App) {
9398
let run_mode = self.run_mode;
94-
let main_schedule_label = self.main_schedule_label.clone();
99+
let startup_schedule_label = self.startup_schedule_label.clone();
100+
let update_schedule_label = self.update_schedule_label.clone();
95101
app.set_runner(move |mut app: App| {
96102
// Prevent panic when schedules do not exist
97-
app.init_schedule(main_schedule_label.clone());
103+
app.init_schedule(startup_schedule_label.clone());
104+
app.init_schedule(update_schedule_label.clone());
105+
106+
{
107+
#[cfg(feature = "trace")]
108+
let _ = info_span!("run top schedule", name = ?startup_schedule_label).entered();
109+
app.world.run_schedule(startup_schedule_label);
110+
}
98111

99112
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
100113
match run_mode {
101114
RunMode::Once => {
102115
{
103116
#[cfg(feature = "trace")]
104-
let _main_schedule_span =
105-
info_span!("main schedule", name = ?main_schedule_label).entered();
106-
app.world.run_schedule(main_schedule_label);
117+
let _ =
118+
info_span!("run top schedule", name = ?update_schedule_label).entered();
119+
app.world.run_schedule(update_schedule_label);
107120
}
108121
app.update_sub_apps();
109122
}
@@ -124,9 +137,9 @@ impl Plugin for ScheduleRunnerPlugin {
124137

125138
{
126139
#[cfg(feature = "trace")]
127-
let _main_schedule_span =
128-
info_span!("main schedule", name = ?main_schedule_label).entered();
129-
app.world.run_schedule(&main_schedule_label);
140+
let _ = info_span!("run top schedule", name = ?update_schedule_label)
141+
.entered();
142+
app.world.run_schedule(&update_schedule_label);
130143
}
131144
app.update_sub_apps();
132145
app.world.clear_trackers();

crates/bevy_window/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,17 @@ impl Plugin for WindowPlugin {
9595

9696
match self.exit_condition {
9797
ExitCondition::OnPrimaryClosed => {
98-
app.add_systems(PostUpdate, exit_on_primary_closed);
98+
app.add_systems(Control, exit_on_primary_closed);
9999
}
100100
ExitCondition::OnAllClosed => {
101-
app.add_systems(PostUpdate, exit_on_all_closed);
101+
app.add_systems(Control, exit_on_all_closed);
102102
}
103103
ExitCondition::DontExit => {}
104104
}
105105

106106
if self.close_when_requested {
107107
// Need to run before `exit_on_*` systems
108-
app.add_systems(Update, close_when_requested);
108+
app.add_systems(Control, close_when_requested);
109109
}
110110

111111
// Register event types

0 commit comments

Comments
 (0)