use crate::App;1use core::any::Any;2use downcast_rs::{impl_downcast, Downcast};34/// A collection of Bevy app logic and configuration.5///6/// Plugins configure an [`App`]. When an [`App`] registers a plugin,7/// the plugin's [`Plugin::build`] function is run. By default, a plugin8/// can only be added once to an [`App`].9///10/// If the plugin may need to be added twice or more, the function [`is_unique()`](Self::is_unique)11/// should be overridden to return `false`. Plugins are considered duplicate if they have the same12/// [`name()`](Self::name). The default `name()` implementation returns the type name, which means13/// generic plugins with different type parameters will not be considered duplicates.14///15/// ## Lifecycle of a plugin16///17/// When adding a plugin to an [`App`]:18/// * the app calls [`Plugin::build`] immediately, and register the plugin19/// * once the app started, it will wait for all registered [`Plugin::ready`] to return `true`20/// * it will then call all registered [`Plugin::finish`]21/// * and call all registered [`Plugin::cleanup`]22///23/// ## Defining a plugin.24///25/// Most plugins are simply functions that add configuration to an [`App`].26///27/// ```28/// # use bevy_app::{App, Update};29/// App::new().add_plugins(my_plugin).run();30///31/// // This function implements `Plugin`, along with every other `fn(&mut App)`.32/// pub fn my_plugin(app: &mut App) {33/// app.add_systems(Update, hello_world);34/// }35/// # fn hello_world() {}36/// ```37///38/// For more advanced use cases, the `Plugin` trait can be implemented manually for a type.39///40/// ```41/// # use bevy_app::*;42/// pub struct AccessibilityPlugin {43/// pub flicker_damping: bool,44/// // ...45/// }46///47/// impl Plugin for AccessibilityPlugin {48/// fn build(&self, app: &mut App) {49/// if self.flicker_damping {50/// app.add_systems(PostUpdate, damp_flickering);51/// }52/// }53/// }54/// # fn damp_flickering() {}55/// ```56pub trait Plugin: Downcast + Any + Send + Sync {57/// Configures the [`App`] to which this plugin is added.58fn build(&self, app: &mut App);5960/// Has the plugin finished its setup? This can be useful for plugins that need something61/// asynchronous to happen before they can finish their setup, like the initialization of a renderer.62/// Once the plugin is ready, [`finish`](Plugin::finish) should be called.63fn ready(&self, _app: &App) -> bool {64true65}6667/// Finish adding this plugin to the [`App`], once all plugins registered are ready. This can68/// be useful for plugins that depends on another plugin asynchronous setup, like the renderer.69fn finish(&self, _app: &mut App) {70// do nothing71}7273/// Runs after all plugins are built and finished, but before the app schedule is executed.74/// This can be useful if you have some resource that other plugins need during their build step,75/// but after build you want to remove it and send it to another thread.76fn cleanup(&self, _app: &mut App) {77// do nothing78}7980/// Configures a name for the [`Plugin`] which is primarily used for checking plugin81/// uniqueness and debugging.82fn name(&self) -> &str {83core::any::type_name::<Self>()84}8586/// If the plugin can be meaningfully instantiated several times in an [`App`],87/// override this method to return `false`.88fn is_unique(&self) -> bool {89true90}91}9293impl_downcast!(Plugin);9495impl<T: Fn(&mut App) + Send + Sync + 'static> Plugin for T {96fn build(&self, app: &mut App) {97self(app);98}99}100101/// Plugins state in the application102#[derive(PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)]103pub enum PluginsState {104/// Plugins are being added.105Adding,106/// All plugins already added are ready.107Ready,108/// Finish has been executed for all plugins added.109Finished,110/// Cleanup has been executed for all plugins added.111Cleaned,112}113114/// A dummy plugin that's to temporarily occupy an entry in an app's plugin registry.115pub(crate) struct PlaceholderPlugin;116117impl Plugin for PlaceholderPlugin {118fn build(&self, _app: &mut App) {}119}120121/// Types that represent a set of [`Plugin`]s.122///123/// This is implemented for all types which implement [`Plugin`],124/// [`PluginGroup`](super::PluginGroup), and tuples over [`Plugins`].125pub trait Plugins<Marker>: sealed::Plugins<Marker> {}126127impl<Marker, T> Plugins<Marker> for T where T: sealed::Plugins<Marker> {}128129mod sealed {130use alloc::boxed::Box;131use variadics_please::all_tuples;132133use crate::{App, AppError, Plugin, PluginGroup};134135pub trait Plugins<Marker> {136fn add_to_app(self, app: &mut App);137}138139pub struct PluginMarker;140pub struct PluginGroupMarker;141pub struct PluginsTupleMarker;142143impl<P: Plugin> Plugins<PluginMarker> for P {144#[track_caller]145fn add_to_app(self, app: &mut App) {146if let Err(AppError::DuplicatePlugin { plugin_name }) =147app.add_boxed_plugin(Box::new(self))148{149panic!(150"Error adding plugin {plugin_name}: : plugin was already added in application"151)152}153}154}155156impl<P: PluginGroup> Plugins<PluginGroupMarker> for P {157#[track_caller]158fn add_to_app(self, app: &mut App) {159self.build().finish(app);160}161}162163macro_rules! impl_plugins_tuples {164($(#[$meta:meta])* $(($param: ident, $plugins: ident)),*) => {165$(#[$meta])*166impl<$($param, $plugins),*> Plugins<(PluginsTupleMarker, $($param,)*)> for ($($plugins,)*)167where168$($plugins: Plugins<$param>),*169{170#[expect(171clippy::allow_attributes,172reason = "This is inside a macro, and as such, may not trigger in all cases."173)]174#[allow(non_snake_case, reason = "`all_tuples!()` generates non-snake-case variable names.")]175#[allow(unused_variables, reason = "`app` is unused when implemented for the unit type `()`.")]176#[track_caller]177fn add_to_app(self, app: &mut App) {178let ($($plugins,)*) = self;179$($plugins.add_to_app(app);)*180}181}182}183}184185all_tuples!(186#[doc(fake_variadic)]187impl_plugins_tuples,1880,18915,190P,191S192);193}194195196