bevy_app/plugin.rs
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
use downcast_rs::{impl_downcast, Downcast};
use crate::App;
use core::any::Any;
/// A collection of Bevy app logic and configuration.
///
/// Plugins configure an [`App`]. When an [`App`] registers a plugin,
/// the plugin's [`Plugin::build`] function is run. By default, a plugin
/// can only be added once to an [`App`].
///
/// If the plugin may need to be added twice or more, the function [`is_unique()`](Self::is_unique)
/// should be overridden to return `false`. Plugins are considered duplicate if they have the same
/// [`name()`](Self::name). The default `name()` implementation returns the type name, which means
/// generic plugins with different type parameters will not be considered duplicates.
///
/// ## Lifecycle of a plugin
///
/// When adding a plugin to an [`App`]:
/// * the app calls [`Plugin::build`] immediately, and register the plugin
/// * once the app started, it will wait for all registered [`Plugin::ready`] to return `true`
/// * it will then call all registered [`Plugin::finish`]
/// * and call all registered [`Plugin::cleanup`]
///
/// ## Defining a plugin.
///
/// Most plugins are simply functions that add configuration to an [`App`].
///
/// ```
/// # use bevy_app::{App, Update};
/// App::new().add_plugins(my_plugin).run();
///
/// // This function implements `Plugin`, along with every other `fn(&mut App)`.
/// pub fn my_plugin(app: &mut App) {
/// app.add_systems(Update, hello_world);
/// }
/// # fn hello_world() {}
/// ```
///
/// For more advanced use cases, the `Plugin` trait can be implemented manually for a type.
///
/// ```
/// # use bevy_app::*;
/// pub struct AccessibilityPlugin {
/// pub flicker_damping: bool,
/// // ...
/// }
///
/// impl Plugin for AccessibilityPlugin {
/// fn build(&self, app: &mut App) {
/// if self.flicker_damping {
/// app.add_systems(PostUpdate, damp_flickering);
/// }
/// }
/// }
/// # fn damp_flickering() {}
/// ```
pub trait Plugin: Downcast + Any + Send + Sync {
/// Configures the [`App`] to which this plugin is added.
fn build(&self, app: &mut App);
/// Has the plugin finished its setup? This can be useful for plugins that need something
/// asynchronous to happen before they can finish their setup, like the initialization of a renderer.
/// Once the plugin is ready, [`finish`](Plugin::finish) should be called.
fn ready(&self, _app: &App) -> bool {
true
}
/// Finish adding this plugin to the [`App`], once all plugins registered are ready. This can
/// be useful for plugins that depends on another plugin asynchronous setup, like the renderer.
fn finish(&self, _app: &mut App) {
// do nothing
}
/// Runs after all plugins are built and finished, but before the app schedule is executed.
/// This can be useful if you have some resource that other plugins need during their build step,
/// but after build you want to remove it and send it to another thread.
fn cleanup(&self, _app: &mut App) {
// do nothing
}
/// Configures a name for the [`Plugin`] which is primarily used for checking plugin
/// uniqueness and debugging.
fn name(&self) -> &str {
core::any::type_name::<Self>()
}
/// If the plugin can be meaningfully instantiated several times in an [`App`],
/// override this method to return `false`.
fn is_unique(&self) -> bool {
true
}
}
impl_downcast!(Plugin);
impl<T: Fn(&mut App) + Send + Sync + 'static> Plugin for T {
fn build(&self, app: &mut App) {
self(app);
}
}
/// Plugins state in the application
#[derive(PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)]
pub enum PluginsState {
/// Plugins are being added.
Adding,
/// All plugins already added are ready.
Ready,
/// Finish has been executed for all plugins added.
Finished,
/// Cleanup has been executed for all plugins added.
Cleaned,
}
/// A dummy plugin that's to temporarily occupy an entry in an app's plugin registry.
pub(crate) struct PlaceholderPlugin;
impl Plugin for PlaceholderPlugin {
fn build(&self, _app: &mut App) {}
}
/// Types that represent a set of [`Plugin`]s.
///
/// This is implemented for all types which implement [`Plugin`],
/// [`PluginGroup`](super::PluginGroup), and tuples over [`Plugins`].
pub trait Plugins<Marker>: sealed::Plugins<Marker> {}
impl<Marker, T> Plugins<Marker> for T where T: sealed::Plugins<Marker> {}
mod sealed {
use bevy_utils::all_tuples;
use crate::{App, AppError, Plugin, PluginGroup};
pub trait Plugins<Marker> {
fn add_to_app(self, app: &mut App);
}
pub struct PluginMarker;
pub struct PluginGroupMarker;
pub struct PluginsTupleMarker;
impl<P: Plugin> Plugins<PluginMarker> for P {
#[track_caller]
fn add_to_app(self, app: &mut App) {
if let Err(AppError::DuplicatePlugin { plugin_name }) =
app.add_boxed_plugin(Box::new(self))
{
panic!(
"Error adding plugin {plugin_name}: : plugin was already added in application"
)
}
}
}
impl<P: PluginGroup> Plugins<PluginGroupMarker> for P {
#[track_caller]
fn add_to_app(self, app: &mut App) {
self.build().finish(app);
}
}
macro_rules! impl_plugins_tuples {
($(#[$meta:meta])* $(($param: ident, $plugins: ident)),*) => {
$(#[$meta])*
impl<$($param, $plugins),*> Plugins<(PluginsTupleMarker, $($param,)*)> for ($($plugins,)*)
where
$($plugins: Plugins<$param>),*
{
// We use `allow` instead of `expect` here because the lint is not generated for all cases.
#[allow(non_snake_case, reason = "`all_tuples!()` generates non-snake-case variable names.")]
#[allow(unused_variables, reason = "`app` is unused when implemented for the unit type `()`.")]
#[track_caller]
fn add_to_app(self, app: &mut App) {
let ($($plugins,)*) = self;
$($plugins.add_to_app(app);)*
}
}
}
}
all_tuples!(
#[doc(fake_variadic)]
impl_plugins_tuples,
0,
15,
P,
S
);
}