
Right now, a direct reference to the target TaskPool is required to launch tasks on the pools, despite the three newtyped pools (AsyncComputeTaskPool, ComputeTaskPool, and IoTaskPool) effectively acting as global instances. The need to pass a TaskPool reference adds notable friction to spawning subtasks within existing tasks. Possible use cases for this may include chaining tasks within the same pool like spawning separate send/receive I/O tasks after waiting on a network connection to be established, or allowing cross-pool dependent tasks like starting dependent multi-frame computations following a long I/O load. Other task execution runtimes provide static access to spawning tasks (i.e. `tokio::spawn`), which is notably easier to use than the reference passing required by `bevy_tasks` right now. This PR makes does the following: * Adds `*TaskPool::init` which initializes a `OnceCell`'ed with a provided TaskPool. Failing if the pool has already been initialized. * Adds `*TaskPool::get` which fetches the initialized global pool of the respective type or panics. This generally should not be an issue in normal Bevy use, as the pools are initialized before they are accessed. * Updated default task pool initialization to either pull the global handles and save them as resources, or if they are already initialized, pull the a cloned global handle as the resource. This should make it notably easier to build more complex task hierarchies for dependent tasks. It should also make writing bevy-adjacent, but not strictly bevy-only plugin crates easier, as the global pools ensure it's all running on the same threads. One alternative considered is keeping a thread-local reference to the pool for all threads in each pool to enable the same `tokio::spawn` interface. This would spawn tasks on the same pool that a task is currently running in. However this potentially leads to potential footgun situations where long running blocking tasks run on `ComputeTaskPool`.
933 lines
31 KiB
Rust
933 lines
31 KiB
Rust
use crate::{CoreStage, Plugin, PluginGroup, PluginGroupBuilder, StartupSchedule, StartupStage};
|
|
pub use bevy_derive::AppLabel;
|
|
use bevy_ecs::{
|
|
event::{Event, Events},
|
|
prelude::{FromWorld, IntoExclusiveSystem},
|
|
schedule::{
|
|
IntoSystemDescriptor, Schedule, ShouldRun, Stage, StageLabel, State, StateData, SystemSet,
|
|
SystemStage,
|
|
},
|
|
system::Resource,
|
|
world::World,
|
|
};
|
|
use bevy_utils::{tracing::debug, HashMap};
|
|
use std::fmt::Debug;
|
|
|
|
#[cfg(feature = "trace")]
|
|
use bevy_utils::tracing::info_span;
|
|
bevy_utils::define_label!(AppLabel);
|
|
|
|
#[allow(clippy::needless_doctest_main)]
|
|
/// A container of app logic and data.
|
|
///
|
|
/// Bundles together the necessary elements like [`World`] and [`Schedule`] to create
|
|
/// an ECS-based application. It also stores a pointer to a [runner function](Self::set_runner).
|
|
/// The runner is responsible for managing the application's event loop and applying the
|
|
/// [`Schedule`] to the [`World`] to drive application logic.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// Here is a simple "Hello World" Bevy app:
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// fn main() {
|
|
/// App::new()
|
|
/// .add_system(hello_world_system)
|
|
/// .run();
|
|
/// }
|
|
///
|
|
/// fn hello_world_system() {
|
|
/// println!("hello world");
|
|
/// }
|
|
/// ```
|
|
pub struct App {
|
|
/// The main ECS [`World`] of the [`App`].
|
|
/// This stores and provides access to all the main data of the application.
|
|
/// The systems of the [`App`] will run using this [`World`].
|
|
/// If additional separate [`World`]-[`Schedule`] pairs are needed, you can use [`sub_app`](App::add_sub_app)s.
|
|
pub world: World,
|
|
/// The [runner function](Self::set_runner) is primarily responsible for managing
|
|
/// the application's event loop and advancing the [`Schedule`].
|
|
/// Typically, it is not configured manually, but set by one of Bevy's built-in plugins.
|
|
/// See `bevy::winit::WinitPlugin` and [`ScheduleRunnerPlugin`](crate::schedule_runner::ScheduleRunnerPlugin).
|
|
pub runner: Box<dyn Fn(App)>,
|
|
/// A container of [`Stage`]s set to be run in a linear order.
|
|
pub schedule: Schedule,
|
|
sub_apps: HashMap<Box<dyn AppLabel>, SubApp>,
|
|
}
|
|
|
|
/// Each `SubApp` has its own [`Schedule`] and [`World`], enabling a separation of concerns.
|
|
struct SubApp {
|
|
app: App,
|
|
runner: Box<dyn Fn(&mut World, &mut App)>,
|
|
}
|
|
|
|
impl Default for App {
|
|
fn default() -> Self {
|
|
let mut app = App::empty();
|
|
#[cfg(feature = "bevy_reflect")]
|
|
app.init_resource::<bevy_reflect::TypeRegistryArc>();
|
|
|
|
app.add_default_stages()
|
|
.add_event::<AppExit>()
|
|
.add_system_to_stage(CoreStage::Last, World::clear_trackers.exclusive_system());
|
|
|
|
#[cfg(feature = "bevy_ci_testing")]
|
|
{
|
|
crate::ci_testing::setup_app(&mut app);
|
|
}
|
|
|
|
app
|
|
}
|
|
}
|
|
|
|
impl App {
|
|
/// Creates a new [`App`] with some default structure to enable core engine features.
|
|
/// This is the preferred constructor for most use cases.
|
|
pub fn new() -> App {
|
|
App::default()
|
|
}
|
|
|
|
/// Creates a new empty [`App`] with minimal default configuration.
|
|
///
|
|
/// This constructor should be used if you wish to provide a custom schedule, exit handling, cleanup, etc.
|
|
pub fn empty() -> App {
|
|
Self {
|
|
world: Default::default(),
|
|
schedule: Default::default(),
|
|
runner: Box::new(run_once),
|
|
sub_apps: HashMap::default(),
|
|
}
|
|
}
|
|
|
|
/// Advances the execution of the [`Schedule`] by one cycle.
|
|
///
|
|
/// This method also updates sub apps.
|
|
///
|
|
/// See [`add_sub_app`](Self::add_sub_app) and [`run_once`](Schedule::run_once) for more details.
|
|
pub fn update(&mut self) {
|
|
#[cfg(feature = "trace")]
|
|
let _bevy_frame_update_span = info_span!("frame").entered();
|
|
self.schedule.run(&mut self.world);
|
|
for sub_app in self.sub_apps.values_mut() {
|
|
(sub_app.runner)(&mut self.world, &mut sub_app.app);
|
|
}
|
|
}
|
|
|
|
/// Starts the application by calling the app's [runner function](Self::set_runner).
|
|
///
|
|
/// Finalizes the [`App`] configuration. For general usage, see the example on the item
|
|
/// level documentation.
|
|
pub fn run(&mut self) {
|
|
#[cfg(feature = "trace")]
|
|
let _bevy_app_run_span = info_span!("bevy_app").entered();
|
|
|
|
let mut app = std::mem::replace(self, App::empty());
|
|
let runner = std::mem::replace(&mut app.runner, Box::new(run_once));
|
|
(runner)(app);
|
|
}
|
|
|
|
/// Adds a [`Stage`] with the given `label` to the last position of the app's
|
|
/// [`Schedule`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # let mut app = App::new();
|
|
/// #
|
|
/// app.add_stage("my_stage", SystemStage::parallel());
|
|
/// ```
|
|
pub fn add_stage<S: Stage>(&mut self, label: impl StageLabel, stage: S) -> &mut Self {
|
|
self.schedule.add_stage(label, stage);
|
|
self
|
|
}
|
|
|
|
/// Adds a [`Stage`] with the given `label` to the app's [`Schedule`], located
|
|
/// immediately after the stage labeled by `target`.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # let mut app = App::new();
|
|
/// #
|
|
/// app.add_stage_after(CoreStage::Update, "my_stage", SystemStage::parallel());
|
|
/// ```
|
|
pub fn add_stage_after<S: Stage>(
|
|
&mut self,
|
|
target: impl StageLabel,
|
|
label: impl StageLabel,
|
|
stage: S,
|
|
) -> &mut Self {
|
|
self.schedule.add_stage_after(target, label, stage);
|
|
self
|
|
}
|
|
|
|
/// Adds a [`Stage`] with the given `label` to the app's [`Schedule`], located
|
|
/// immediately before the stage labeled by `target`.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # let mut app = App::new();
|
|
/// #
|
|
/// app.add_stage_before(CoreStage::Update, "my_stage", SystemStage::parallel());
|
|
/// ```
|
|
pub fn add_stage_before<S: Stage>(
|
|
&mut self,
|
|
target: impl StageLabel,
|
|
label: impl StageLabel,
|
|
stage: S,
|
|
) -> &mut Self {
|
|
self.schedule.add_stage_before(target, label, stage);
|
|
self
|
|
}
|
|
|
|
/// Adds a [`Stage`] with the given `label` to the last position of the
|
|
/// [startup schedule](Self::add_default_stages).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # let mut app = App::new();
|
|
/// #
|
|
/// app.add_startup_stage("my_startup_stage", SystemStage::parallel());
|
|
/// ```
|
|
pub fn add_startup_stage<S: Stage>(&mut self, label: impl StageLabel, stage: S) -> &mut Self {
|
|
self.schedule
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
|
schedule.add_stage(label, stage)
|
|
});
|
|
self
|
|
}
|
|
|
|
/// Adds a [startup stage](Self::add_default_stages) with the given `label`, immediately
|
|
/// after the stage labeled by `target`.
|
|
///
|
|
/// The `target` label must refer to a stage inside the startup schedule.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # let mut app = App::new();
|
|
/// #
|
|
/// app.add_startup_stage_after(
|
|
/// StartupStage::Startup,
|
|
/// "my_startup_stage",
|
|
/// SystemStage::parallel()
|
|
/// );
|
|
/// ```
|
|
pub fn add_startup_stage_after<S: Stage>(
|
|
&mut self,
|
|
target: impl StageLabel,
|
|
label: impl StageLabel,
|
|
stage: S,
|
|
) -> &mut Self {
|
|
self.schedule
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
|
schedule.add_stage_after(target, label, stage)
|
|
});
|
|
self
|
|
}
|
|
|
|
/// Adds a [startup stage](Self::add_default_stages) with the given `label`, immediately
|
|
/// before the stage labeled by `target`.
|
|
///
|
|
/// The `target` label must refer to a stage inside the startup schedule.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # let mut app = App::new();
|
|
/// #
|
|
/// app.add_startup_stage_before(
|
|
/// StartupStage::Startup,
|
|
/// "my_startup_stage",
|
|
/// SystemStage::parallel()
|
|
/// );
|
|
/// ```
|
|
pub fn add_startup_stage_before<S: Stage>(
|
|
&mut self,
|
|
target: impl StageLabel,
|
|
label: impl StageLabel,
|
|
stage: S,
|
|
) -> &mut Self {
|
|
self.schedule
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
|
schedule.add_stage_before(target, label, stage)
|
|
});
|
|
self
|
|
}
|
|
|
|
/// Fetches the [`Stage`] of type `T` marked with `label` from the [`Schedule`], then
|
|
/// executes the provided `func` passing the fetched stage to it as an argument.
|
|
///
|
|
/// The `func` argument should be a function or a closure that accepts a mutable reference
|
|
/// to a struct implementing `Stage` and returns the same type. That means that it should
|
|
/// also assume that the stage has already been fetched successfully.
|
|
///
|
|
/// See [`stage`](Schedule::stage) for more details.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// Here the closure is used to add a system to the update stage:
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # let mut app = App::new();
|
|
/// # fn my_system() {}
|
|
/// #
|
|
/// app.stage(CoreStage::Update, |stage: &mut SystemStage| {
|
|
/// stage.add_system(my_system)
|
|
/// });
|
|
/// ```
|
|
pub fn stage<T: Stage, F: FnOnce(&mut T) -> &mut T>(
|
|
&mut self,
|
|
label: impl StageLabel,
|
|
func: F,
|
|
) -> &mut Self {
|
|
self.schedule.stage(label, func);
|
|
self
|
|
}
|
|
|
|
/// Adds a system to the [update stage](Self::add_default_stages) of the app's [`Schedule`].
|
|
///
|
|
/// Refer to the [system module documentation](bevy_ecs::system) to see how a system
|
|
/// can be defined.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # fn my_system() {}
|
|
/// # let mut app = App::new();
|
|
/// #
|
|
/// app.add_system(my_system);
|
|
/// ```
|
|
pub fn add_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut Self {
|
|
self.add_system_to_stage(CoreStage::Update, system)
|
|
}
|
|
|
|
/// Adds a [`SystemSet`] to the [update stage](Self::add_default_stages).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # let mut app = App::new();
|
|
/// # fn system_a() {}
|
|
/// # fn system_b() {}
|
|
/// # fn system_c() {}
|
|
/// #
|
|
/// app.add_system_set(
|
|
/// SystemSet::new()
|
|
/// .with_system(system_a)
|
|
/// .with_system(system_b)
|
|
/// .with_system(system_c),
|
|
/// );
|
|
/// ```
|
|
pub fn add_system_set(&mut self, system_set: SystemSet) -> &mut Self {
|
|
self.add_system_set_to_stage(CoreStage::Update, system_set)
|
|
}
|
|
|
|
/// Adds a system to the [`Stage`] identified by `stage_label`.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # let mut app = App::new();
|
|
/// # fn my_system() {}
|
|
/// #
|
|
/// app.add_system_to_stage(CoreStage::PostUpdate, my_system);
|
|
/// ```
|
|
pub fn add_system_to_stage<Params>(
|
|
&mut self,
|
|
stage_label: impl StageLabel,
|
|
system: impl IntoSystemDescriptor<Params>,
|
|
) -> &mut Self {
|
|
use std::any::TypeId;
|
|
assert!(
|
|
stage_label.type_id() != TypeId::of::<StartupStage>(),
|
|
"add systems to a startup stage using App::add_startup_system_to_stage"
|
|
);
|
|
self.schedule.add_system_to_stage(stage_label, system);
|
|
self
|
|
}
|
|
|
|
/// Adds a [`SystemSet`] to the [`Stage`] identified by `stage_label`.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # let mut app = App::new();
|
|
/// # fn system_a() {}
|
|
/// # fn system_b() {}
|
|
/// # fn system_c() {}
|
|
/// #
|
|
/// app.add_system_set_to_stage(
|
|
/// CoreStage::PostUpdate,
|
|
/// SystemSet::new()
|
|
/// .with_system(system_a)
|
|
/// .with_system(system_b)
|
|
/// .with_system(system_c),
|
|
/// );
|
|
/// ```
|
|
pub fn add_system_set_to_stage(
|
|
&mut self,
|
|
stage_label: impl StageLabel,
|
|
system_set: SystemSet,
|
|
) -> &mut Self {
|
|
use std::any::TypeId;
|
|
assert!(
|
|
stage_label.type_id() != TypeId::of::<StartupStage>(),
|
|
"add system sets to a startup stage using App::add_startup_system_set_to_stage"
|
|
);
|
|
self.schedule
|
|
.add_system_set_to_stage(stage_label, system_set);
|
|
self
|
|
}
|
|
|
|
/// Adds a system to the [startup stage](Self::add_default_stages) of the app's [`Schedule`].
|
|
///
|
|
/// * For adding a system that runs every frame, see [`add_system`](Self::add_system).
|
|
/// * For adding a system to a specific stage, see [`add_system_to_stage`](Self::add_system_to_stage).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// fn my_startup_system(_commands: Commands) {
|
|
/// println!("My startup system");
|
|
/// }
|
|
///
|
|
/// App::new()
|
|
/// .add_startup_system(my_startup_system);
|
|
/// ```
|
|
pub fn add_startup_system<Params>(
|
|
&mut self,
|
|
system: impl IntoSystemDescriptor<Params>,
|
|
) -> &mut Self {
|
|
self.add_startup_system_to_stage(StartupStage::Startup, system)
|
|
}
|
|
|
|
/// Adds a [`SystemSet`] to the [startup stage](Self::add_default_stages).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # let mut app = App::new();
|
|
/// # fn startup_system_a() {}
|
|
/// # fn startup_system_b() {}
|
|
/// # fn startup_system_c() {}
|
|
/// #
|
|
/// app.add_startup_system_set(
|
|
/// SystemSet::new()
|
|
/// .with_system(startup_system_a)
|
|
/// .with_system(startup_system_b)
|
|
/// .with_system(startup_system_c),
|
|
/// );
|
|
/// ```
|
|
pub fn add_startup_system_set(&mut self, system_set: SystemSet) -> &mut Self {
|
|
self.add_startup_system_set_to_stage(StartupStage::Startup, system_set)
|
|
}
|
|
|
|
/// Adds a system to the [startup schedule](Self::add_default_stages), in the stage
|
|
/// identified by `stage_label`.
|
|
///
|
|
/// `stage_label` must refer to a stage inside the startup schedule.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # let mut app = App::new();
|
|
/// # fn my_startup_system() {}
|
|
/// #
|
|
/// app.add_startup_system_to_stage(StartupStage::PreStartup, my_startup_system);
|
|
/// ```
|
|
pub fn add_startup_system_to_stage<Params>(
|
|
&mut self,
|
|
stage_label: impl StageLabel,
|
|
system: impl IntoSystemDescriptor<Params>,
|
|
) -> &mut Self {
|
|
self.schedule
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
|
schedule.add_system_to_stage(stage_label, system)
|
|
});
|
|
self
|
|
}
|
|
|
|
/// Adds a [`SystemSet`] to the [startup schedule](Self::add_default_stages), in the stage
|
|
/// identified by `stage_label`.
|
|
///
|
|
/// `stage_label` must refer to a stage inside the startup schedule.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # let mut app = App::new();
|
|
/// # fn startup_system_a() {}
|
|
/// # fn startup_system_b() {}
|
|
/// # fn startup_system_c() {}
|
|
/// #
|
|
/// app.add_startup_system_set_to_stage(
|
|
/// StartupStage::PreStartup,
|
|
/// SystemSet::new()
|
|
/// .with_system(startup_system_a)
|
|
/// .with_system(startup_system_b)
|
|
/// .with_system(startup_system_c),
|
|
/// );
|
|
/// ```
|
|
pub fn add_startup_system_set_to_stage(
|
|
&mut self,
|
|
stage_label: impl StageLabel,
|
|
system_set: SystemSet,
|
|
) -> &mut Self {
|
|
self.schedule
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
|
schedule.add_system_set_to_stage(stage_label, system_set)
|
|
});
|
|
self
|
|
}
|
|
|
|
/// Adds a new [`State`] with the given `initial` value.
|
|
/// This inserts a new `State<T>` resource and adds a new "driver" to [`CoreStage::Update`].
|
|
/// Each stage that uses `State<T>` for system run criteria needs a driver. If you need to use
|
|
/// your state in a different stage, consider using [`Self::add_state_to_stage`] or manually
|
|
/// adding [`State::get_driver`] to additional stages you need it in.
|
|
pub fn add_state<T>(&mut self, initial: T) -> &mut Self
|
|
where
|
|
T: StateData,
|
|
{
|
|
self.add_state_to_stage(CoreStage::Update, initial)
|
|
}
|
|
|
|
/// Adds a new [`State`] with the given `initial` value.
|
|
/// This inserts a new `State<T>` resource and adds a new "driver" to the given stage.
|
|
/// Each stage that uses `State<T>` for system run criteria needs a driver. If you need to use
|
|
/// your state in more than one stage, consider manually adding [`State::get_driver`] to the
|
|
/// stages you need it in.
|
|
pub fn add_state_to_stage<T>(&mut self, stage: impl StageLabel, initial: T) -> &mut Self
|
|
where
|
|
T: StateData,
|
|
{
|
|
self.insert_resource(State::new(initial))
|
|
.add_system_set_to_stage(stage, State::<T>::get_driver())
|
|
}
|
|
|
|
/// Adds utility stages to the [`Schedule`], giving it a standardized structure.
|
|
///
|
|
/// Adding those stages is necessary to make some core engine features work, like
|
|
/// adding systems without specifying a stage, or registering events. This is however
|
|
/// done by default by calling `App::default`, which is in turn called by
|
|
/// [`App::new`].
|
|
///
|
|
/// # The stages
|
|
///
|
|
/// All the added stages, with the exception of the startup stage, run every time the
|
|
/// schedule is invoked. The stages are the following, in order of execution:
|
|
///
|
|
/// - **First:** Runs at the very start of the schedule execution cycle, even before the
|
|
/// startup stage.
|
|
/// - **Startup:** This is actually a schedule containing sub-stages. Runs only once
|
|
/// when the app starts.
|
|
/// - **Pre-startup:** Intended for systems that need to run before other startup systems.
|
|
/// - **Startup:** The main startup stage. Startup systems are added here by default.
|
|
/// - **Post-startup:** Intended for systems that need to run after other startup systems.
|
|
/// - **Pre-update:** Often used by plugins to prepare their internal state before the
|
|
/// update stage begins.
|
|
/// - **Update:** Intended for user defined logic. Systems are added here by default.
|
|
/// - **Post-update:** Often used by plugins to finalize their internal state after the
|
|
/// world changes that happened during the update stage.
|
|
/// - **Last:** Runs right before the end of the schedule execution cycle.
|
|
///
|
|
/// The labels for those stages are defined in the [`CoreStage`] and [`StartupStage`] `enum`s.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// #
|
|
/// let app = App::empty().add_default_stages();
|
|
/// ```
|
|
pub fn add_default_stages(&mut self) -> &mut Self {
|
|
self.add_stage(CoreStage::First, SystemStage::parallel())
|
|
.add_stage(
|
|
StartupSchedule,
|
|
Schedule::default()
|
|
.with_run_criteria(ShouldRun::once)
|
|
.with_stage(StartupStage::PreStartup, SystemStage::parallel())
|
|
.with_stage(StartupStage::Startup, SystemStage::parallel())
|
|
.with_stage(StartupStage::PostStartup, SystemStage::parallel()),
|
|
)
|
|
.add_stage(CoreStage::PreUpdate, SystemStage::parallel())
|
|
.add_stage(CoreStage::Update, SystemStage::parallel())
|
|
.add_stage(CoreStage::PostUpdate, SystemStage::parallel())
|
|
.add_stage(CoreStage::Last, SystemStage::parallel())
|
|
}
|
|
|
|
/// Setup the application to manage events of type `T`.
|
|
///
|
|
/// This is done by adding a [`Resource`] of type [`Events::<T>`],
|
|
/// and inserting an [`update_system`](Events::update_system) into [`CoreStage::First`].
|
|
///
|
|
/// See [`Events`] for defining events.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # struct MyEvent;
|
|
/// # let mut app = App::new();
|
|
/// #
|
|
/// app.add_event::<MyEvent>();
|
|
/// ```
|
|
pub fn add_event<T>(&mut self) -> &mut Self
|
|
where
|
|
T: Event,
|
|
{
|
|
if !self.world.contains_resource::<Events<T>>() {
|
|
self.init_resource::<Events<T>>()
|
|
.add_system_to_stage(CoreStage::First, Events::<T>::update_system);
|
|
}
|
|
self
|
|
}
|
|
|
|
/// Inserts a [`Resource`] to the current [`App`] and overwrites any [`Resource`] previously added of the same type.
|
|
///
|
|
/// A [`Resource`] in Bevy represents globally unique data. [`Resource`]s must be added to Bevy apps
|
|
/// before using them. This happens with [`insert_resource`](Self::insert_resource).
|
|
///
|
|
/// See [`init_resource`](Self::init_resource) for [`Resource`]s that implement [`Default`] or [`FromWorld`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// #
|
|
/// struct MyCounter {
|
|
/// counter: usize,
|
|
/// }
|
|
///
|
|
/// App::new()
|
|
/// .insert_resource(MyCounter { counter: 0 });
|
|
/// ```
|
|
pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
|
|
self.world.insert_resource(resource);
|
|
self
|
|
}
|
|
|
|
/// Inserts a non-send [`Resource`] to the app.
|
|
///
|
|
/// You usually want to use [`insert_resource`](Self::insert_resource),
|
|
/// but there are some special cases when a [`Resource`] cannot be sent across threads.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// #
|
|
/// struct MyCounter {
|
|
/// counter: usize,
|
|
/// }
|
|
///
|
|
/// App::new()
|
|
/// .insert_non_send_resource(MyCounter { counter: 0 });
|
|
/// ```
|
|
pub fn insert_non_send_resource<R: 'static>(&mut self, resource: R) -> &mut Self {
|
|
self.world.insert_non_send_resource(resource);
|
|
self
|
|
}
|
|
|
|
/// Initialize a [`Resource`] with standard starting values by adding it to the [`World`].
|
|
///
|
|
/// If the [`Resource`] already exists, nothing happens.
|
|
///
|
|
/// The [`Resource`] must implement the [`FromWorld`] trait.
|
|
/// If the [`Default`] trait is implemented, the [`FromWorld`] trait will use
|
|
/// the [`Default::default`] method to initialize the [`Resource`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// #
|
|
/// struct MyCounter {
|
|
/// counter: usize,
|
|
/// }
|
|
///
|
|
/// impl Default for MyCounter {
|
|
/// fn default() -> MyCounter {
|
|
/// MyCounter {
|
|
/// counter: 100
|
|
/// }
|
|
/// }
|
|
/// }
|
|
///
|
|
/// App::new()
|
|
/// .init_resource::<MyCounter>();
|
|
/// ```
|
|
pub fn init_resource<R: Resource + FromWorld>(&mut self) -> &mut Self {
|
|
self.world.init_resource::<R>();
|
|
self
|
|
}
|
|
|
|
/// Initialize a non-send [`Resource`] with standard starting values by adding it to the [`World`].
|
|
///
|
|
/// The [`Resource`] must implement the [`FromWorld`] trait.
|
|
/// If the [`Default`] trait is implemented, the [`FromWorld`] trait will use
|
|
/// the [`Default::default`] method to initialize the [`Resource`].
|
|
pub fn init_non_send_resource<R: 'static + FromWorld>(&mut self) -> &mut Self {
|
|
self.world.init_non_send_resource::<R>();
|
|
self
|
|
}
|
|
|
|
/// Sets the function that will be called when the app is run.
|
|
///
|
|
/// The runner function `run_fn` is called only once by [`App::run`]. If the
|
|
/// presence of a main loop in the app is desired, it is the responsibility of the runner
|
|
/// function to provide it.
|
|
///
|
|
/// The runner function is usually not set manually, but by Bevy integrated plugins
|
|
/// (e.g. `WinitPlugin`).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// #
|
|
/// fn my_runner(mut app: App) {
|
|
/// loop {
|
|
/// println!("In main loop");
|
|
/// app.update();
|
|
/// }
|
|
/// }
|
|
///
|
|
/// App::new()
|
|
/// .set_runner(my_runner);
|
|
/// ```
|
|
pub fn set_runner(&mut self, run_fn: impl Fn(App) + 'static) -> &mut Self {
|
|
self.runner = Box::new(run_fn);
|
|
self
|
|
}
|
|
|
|
/// Adds a single [`Plugin`].
|
|
///
|
|
/// One of Bevy's core principles is modularity. All Bevy engine features are implemented
|
|
/// as [`Plugin`]s. This includes internal features like the renderer.
|
|
///
|
|
/// Bevy also provides a few sets of default [`Plugin`]s. See [`add_plugins`](Self::add_plugins).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::prelude::*;
|
|
/// #
|
|
/// App::new().add_plugin(bevy_log::LogPlugin::default());
|
|
/// ```
|
|
pub fn add_plugin<T>(&mut self, plugin: T) -> &mut Self
|
|
where
|
|
T: Plugin,
|
|
{
|
|
debug!("added plugin: {}", plugin.name());
|
|
plugin.build(self);
|
|
self
|
|
}
|
|
|
|
/// Adds a group of [`Plugin`]s.
|
|
///
|
|
/// [`Plugin`]s can be grouped into a set by using a [`PluginGroup`].
|
|
///
|
|
/// There are built-in [`PluginGroup`]s that provide core engine functionality.
|
|
/// The [`PluginGroup`]s available by default are `DefaultPlugins` and `MinimalPlugins`.
|
|
///
|
|
/// To customize the plugins in the group (reorder, disable a plugin, add a new plugin
|
|
/// before / after another plugin), see [`add_plugins_with`](Self::add_plugins_with).
|
|
///
|
|
/// ## Examples
|
|
/// ```
|
|
/// # use bevy_app::{prelude::*, PluginGroupBuilder};
|
|
/// #
|
|
/// # // Dummy created to avoid using bevy_internal, which pulls in to many dependencies.
|
|
/// # struct MinimalPlugins;
|
|
/// # impl PluginGroup for MinimalPlugins {
|
|
/// # fn build(&mut self, group: &mut PluginGroupBuilder){;}
|
|
/// # }
|
|
/// #
|
|
/// App::new()
|
|
/// .add_plugins(MinimalPlugins);
|
|
/// ```
|
|
pub fn add_plugins<T: PluginGroup>(&mut self, mut group: T) -> &mut Self {
|
|
let mut plugin_group_builder = PluginGroupBuilder::default();
|
|
group.build(&mut plugin_group_builder);
|
|
plugin_group_builder.finish(self);
|
|
self
|
|
}
|
|
|
|
/// Adds a group of [`Plugin`]s with an initializer method.
|
|
///
|
|
/// Can be used to add a group of [`Plugin`]s, where the group is modified
|
|
/// before insertion into a Bevy application. For example, you can add
|
|
/// additional [`Plugin`]s at a specific place in the [`PluginGroup`], or deactivate
|
|
/// specific [`Plugin`]s while keeping the rest using a [`PluginGroupBuilder`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_app::{prelude::*, PluginGroupBuilder};
|
|
/// #
|
|
/// # // Dummies created to avoid using bevy_internal which pulls in too many dependencies.
|
|
/// # struct DefaultPlugins;
|
|
/// # impl PluginGroup for DefaultPlugins {
|
|
/// # fn build(&mut self, group: &mut PluginGroupBuilder){
|
|
/// # group.add(bevy_log::LogPlugin::default());
|
|
/// # }
|
|
/// # }
|
|
/// #
|
|
/// # struct MyOwnPlugin;
|
|
/// # impl Plugin for MyOwnPlugin {
|
|
/// # fn build(&self, app: &mut App){;}
|
|
/// # }
|
|
/// #
|
|
/// App::new()
|
|
/// .add_plugins_with(DefaultPlugins, |group| {
|
|
/// group.add_before::<bevy_log::LogPlugin, _>(MyOwnPlugin)
|
|
/// });
|
|
/// ```
|
|
pub fn add_plugins_with<T, F>(&mut self, mut group: T, func: F) -> &mut Self
|
|
where
|
|
T: PluginGroup,
|
|
F: FnOnce(&mut PluginGroupBuilder) -> &mut PluginGroupBuilder,
|
|
{
|
|
let mut plugin_group_builder = PluginGroupBuilder::default();
|
|
group.build(&mut plugin_group_builder);
|
|
func(&mut plugin_group_builder);
|
|
plugin_group_builder.finish(self);
|
|
self
|
|
}
|
|
|
|
/// Adds the type `T` to the type registry [`Resource`].
|
|
#[cfg(feature = "bevy_reflect")]
|
|
pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
|
|
{
|
|
let registry = self.world.resource_mut::<bevy_reflect::TypeRegistryArc>();
|
|
registry.write().register::<T>();
|
|
}
|
|
self
|
|
}
|
|
|
|
/// Adds an [`App`] as a child of the current one.
|
|
///
|
|
/// The provided function `f` is called by the [`update`](Self::update) method. The [`World`]
|
|
/// parameter represents the main app world, while the [`App`] parameter is just a mutable
|
|
/// reference to the `SubApp` itself.
|
|
pub fn add_sub_app(
|
|
&mut self,
|
|
label: impl AppLabel,
|
|
app: App,
|
|
sub_app_runner: impl Fn(&mut World, &mut App) + 'static,
|
|
) -> &mut Self {
|
|
self.sub_apps.insert(
|
|
Box::new(label),
|
|
SubApp {
|
|
app,
|
|
runner: Box::new(sub_app_runner),
|
|
},
|
|
);
|
|
self
|
|
}
|
|
|
|
/// Retrieves a `SubApp` stored inside this [`App`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if the `SubApp` doesn't exist.
|
|
pub fn sub_app_mut(&mut self, label: impl AppLabel) -> &mut App {
|
|
match self.get_sub_app_mut(label) {
|
|
Ok(app) => app,
|
|
Err(label) => panic!("Sub-App with label '{:?}' does not exist", label),
|
|
}
|
|
}
|
|
|
|
/// Retrieves a `SubApp` inside this [`App`] with the given label, if it exists. Otherwise returns
|
|
/// an [`Err`] containing the given label.
|
|
pub fn get_sub_app_mut(&mut self, label: impl AppLabel) -> Result<&mut App, impl AppLabel> {
|
|
self.sub_apps
|
|
.get_mut((&label) as &dyn AppLabel)
|
|
.map(|sub_app| &mut sub_app.app)
|
|
.ok_or(label)
|
|
}
|
|
|
|
/// Retrieves a `SubApp` stored inside this [`App`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if the `SubApp` doesn't exist.
|
|
pub fn sub_app(&self, label: impl AppLabel) -> &App {
|
|
match self.get_sub_app(label) {
|
|
Ok(app) => app,
|
|
Err(label) => panic!("Sub-App with label '{:?}' does not exist", label),
|
|
}
|
|
}
|
|
|
|
/// Retrieves a `SubApp` inside this [`App`] with the given label, if it exists. Otherwise returns
|
|
/// an [`Err`] containing the given label.
|
|
pub fn get_sub_app(&self, label: impl AppLabel) -> Result<&App, impl AppLabel> {
|
|
self.sub_apps
|
|
.get((&label) as &dyn AppLabel)
|
|
.map(|sub_app| &sub_app.app)
|
|
.ok_or(label)
|
|
}
|
|
}
|
|
|
|
fn run_once(mut app: App) {
|
|
app.update();
|
|
}
|
|
|
|
/// An event that indicates the [`App`] should exit. This will fully exit the app process at the
|
|
/// start of the next tick of the schedule.
|
|
///
|
|
/// You can also use this event to detect that an exit was requested. In order to receive it, systems
|
|
/// subscribing to this event should run after it was emitted and before the schedule of the same
|
|
/// frame is over.
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct AppExit;
|