1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
//! This crate is about everything concerning the highest-level, application layer of a Bevy app.

#![warn(missing_docs)]

mod app;
mod config;
mod plugin;
mod plugin_group;
mod schedule_runner;

#[cfg(feature = "bevy_ci_testing")]
mod ci_testing;

pub use app::*;
pub use bevy_derive::DynamicPlugin;
pub use config::*;
pub use plugin::*;
pub use plugin_group::*;
pub use schedule_runner::*;

#[allow(missing_docs)]
pub mod prelude {
    #[cfg(feature = "bevy_reflect")]
    #[doc(hidden)]
    pub use crate::AppTypeRegistry;
    #[doc(hidden)]
    pub use crate::{
        app::App,
        config::{IntoSystemAppConfig, IntoSystemAppConfigs},
        CoreSchedule, CoreSet, DynamicPlugin, Plugin, PluginGroup, StartupSet,
    };
}

use bevy_ecs::{
    schedule::{
        apply_system_buffers, IntoSystemConfig, IntoSystemSetConfig, IntoSystemSetConfigs,
        Schedule, ScheduleLabel, SystemSet,
    },
    system::Local,
    world::World,
};

/// The names of the default [`App`] schedules.
///
/// The corresponding [`Schedule`](bevy_ecs::schedule::Schedule) objects are added by [`App::add_default_schedules`].
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
pub enum CoreSchedule {
    /// The schedule that runs once when the app starts.
    Startup,
    /// The schedule that contains the app logic that is evaluated each tick of [`App::update()`].
    Main,
    /// The schedule that controls which schedules run.
    ///
    /// This is typically created using the [`CoreSchedule::outer_schedule`] method,
    /// and does not need to manipulated during ordinary use.
    Outer,
    /// The schedule that contains systems which only run after a fixed period of time has elapsed.
    ///
    /// The exclusive `run_fixed_update_schedule` system runs this schedule during the [`CoreSet::FixedUpdate`] system set.
    FixedUpdate,
}

impl CoreSchedule {
    /// An exclusive system that controls which schedule should be running.
    ///
    /// [`CoreSchedule::Main`] is always run.
    ///
    /// If this is the first time this system has been run, [`CoreSchedule::Startup`] will run before [`CoreSchedule::Main`].
    pub fn outer_loop(world: &mut World, mut run_at_least_once: Local<bool>) {
        if !*run_at_least_once {
            world.run_schedule(CoreSchedule::Startup);
            *run_at_least_once = true;
        }

        world.run_schedule(CoreSchedule::Main);
    }

    /// Initializes a single threaded schedule for [`CoreSchedule::Outer`] that contains the [`outer_loop`](CoreSchedule::outer_loop) system.
    pub fn outer_schedule() -> Schedule {
        let mut schedule = Schedule::new();
        schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded);
        schedule.add_system(Self::outer_loop);
        schedule
    }
}

/// The names of the default [`App`] system sets.
///
/// These are ordered in the same order they are listed.
///
/// The corresponding [`SystemSets`](bevy_ecs::schedule::SystemSet) are added by [`App::add_default_schedules`].
///
/// The `*Flush` sets are assigned to the copy of [`apply_system_buffers`]
/// that runs immediately after the matching system set.
/// These can be useful for ordering, but you almost never want to add your systems to these sets.
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
#[system_set(base)]
pub enum CoreSet {
    /// Runs before all other members of this set.
    First,
    /// The copy of [`apply_system_buffers`] that runs immediately after `First`.
    FirstFlush,
    /// Runs before [`CoreSet::Update`].
    PreUpdate,
    /// The copy of [`apply_system_buffers`] that runs immediately after `PreUpdate`.
    PreUpdateFlush,
    /// Applies [`State`](bevy_ecs::schedule::State) transitions
    StateTransitions,
    /// Runs systems that should only occur after a fixed period of time.
    ///
    /// The `run_fixed_update_schedule` system runs the [`CoreSchedule::FixedUpdate`] system in this system set.
    FixedUpdate,
    /// Responsible for doing most app logic. Systems should be registered here by default.
    Update,
    /// The copy of [`apply_system_buffers`] that runs immediately after `Update`.
    UpdateFlush,
    /// Runs after [`CoreSet::Update`].
    PostUpdate,
    /// The copy of [`apply_system_buffers`] that runs immediately after `PostUpdate`.
    PostUpdateFlush,
    /// Runs after all other members of this set.
    Last,
    /// The copy of [`apply_system_buffers`] that runs immediately after `Last`.
    LastFlush,
}

impl CoreSet {
    /// Sets up the base structure of [`CoreSchedule::Main`].
    ///
    /// The sets defined in this enum are configured to run in order,
    /// and a copy of [`apply_system_buffers`] is inserted into each `*Flush` set.
    pub fn base_schedule() -> Schedule {
        use CoreSet::*;
        let mut schedule = Schedule::new();

        // Create "stage-like" structure using buffer flushes + ordering
        schedule
            .set_default_base_set(Update)
            .add_system(apply_system_buffers.in_base_set(FirstFlush))
            .add_system(apply_system_buffers.in_base_set(PreUpdateFlush))
            .add_system(apply_system_buffers.in_base_set(UpdateFlush))
            .add_system(apply_system_buffers.in_base_set(PostUpdateFlush))
            .add_system(apply_system_buffers.in_base_set(LastFlush))
            .configure_sets(
                (
                    First,
                    FirstFlush,
                    PreUpdate,
                    PreUpdateFlush,
                    StateTransitions,
                    FixedUpdate,
                    Update,
                    UpdateFlush,
                    PostUpdate,
                    PostUpdateFlush,
                    Last,
                    LastFlush,
                )
                    .chain(),
            );
        schedule
    }
}

/// The names of the default [`App`] startup sets, which live in [`CoreSchedule::Startup`].
///
/// The corresponding [`SystemSets`](bevy_ecs::schedule::SystemSet) are added by [`App::add_default_schedules`].
///
/// The `*Flush` sets are assigned to the copy of [`apply_system_buffers`]
/// that runs immediately after the matching system set.
/// These can be useful for ordering, but you almost never want to add your systems to these sets.
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
#[system_set(base)]
pub enum StartupSet {
    /// Runs once before [`StartupSet::Startup`].
    PreStartup,
    /// The copy of [`apply_system_buffers`] that runs immediately after `PreStartup`.
    PreStartupFlush,
    /// Runs once when an [`App`] starts up.
    Startup,
    /// The copy of [`apply_system_buffers`] that runs immediately after `Startup`.
    StartupFlush,
    /// Runs once after [`StartupSet::Startup`].
    PostStartup,
    /// The copy of [`apply_system_buffers`] that runs immediately after `PostStartup`.
    PostStartupFlush,
}

impl StartupSet {
    /// Sets up the base structure of [`CoreSchedule::Startup`].
    ///
    /// The sets defined in this enum are configured to run in order,
    /// and a copy of [`apply_system_buffers`] is inserted into each `*Flush` set.
    pub fn base_schedule() -> Schedule {
        use StartupSet::*;
        let mut schedule = Schedule::new();
        schedule.set_default_base_set(Startup);

        // Create "stage-like" structure using buffer flushes + ordering
        schedule.add_system(apply_system_buffers.in_base_set(PreStartupFlush));
        schedule.add_system(apply_system_buffers.in_base_set(StartupFlush));
        schedule.add_system(apply_system_buffers.in_base_set(PostStartupFlush));

        schedule.configure_set(PreStartup.before(PreStartupFlush));
        schedule.configure_set(Startup.after(PreStartupFlush).before(StartupFlush));
        schedule.configure_set(PostStartup.after(StartupFlush).before(PostStartupFlush));

        schedule
    }
}