bevy_app/
plugin.rs

1use downcast_rs::{impl_downcast, Downcast};
2
3use crate::App;
4use std::any::Any;
5
6/// A collection of Bevy app logic and configuration.
7///
8/// Plugins configure an [`App`]. When an [`App`] registers a plugin,
9/// the plugin's [`Plugin::build`] function is run. By default, a plugin
10/// can only be added once to an [`App`].
11///
12/// If the plugin may need to be added twice or more, the function [`is_unique()`](Self::is_unique)
13/// should be overridden to return `false`. Plugins are considered duplicate if they have the same
14/// [`name()`](Self::name). The default `name()` implementation returns the type name, which means
15/// generic plugins with different type parameters will not be considered duplicates.
16///
17/// ## Lifecycle of a plugin
18///
19/// When adding a plugin to an [`App`]:
20/// * the app calls [`Plugin::build`] immediately, and register the plugin
21/// * once the app started, it will wait for all registered [`Plugin::ready`] to return `true`
22/// * it will then call all registered [`Plugin::finish`]
23/// * and call all registered [`Plugin::cleanup`]
24///
25/// ## Defining a plugin.
26///
27/// Most plugins are simply functions that add configuration to an [`App`].
28///
29/// ```
30/// # use bevy_app::{App, Update};
31/// App::new().add_plugins(my_plugin).run();
32///
33/// // This function implements `Plugin`, along with every other `fn(&mut App)`.
34/// pub fn my_plugin(app: &mut App) {
35///     app.add_systems(Update, hello_world);
36/// }
37/// # fn hello_world() {}
38/// ```
39///
40/// For more advanced use cases, the `Plugin` trait can be implemented manually for a type.
41///
42/// ```
43/// # use bevy_app::*;
44/// pub struct AccessibilityPlugin {
45///     pub flicker_damping: bool,
46///     // ...
47/// }
48///
49/// impl Plugin for AccessibilityPlugin {
50///     fn build(&self, app: &mut App) {
51///         if self.flicker_damping {
52///             app.add_systems(PostUpdate, damp_flickering);
53///         }
54///     }
55/// }
56/// # fn damp_flickering() {}
57/// ```
58pub trait Plugin: Downcast + Any + Send + Sync {
59    /// Configures the [`App`] to which this plugin is added.
60    fn build(&self, app: &mut App);
61
62    /// Has the plugin finished its setup? This can be useful for plugins that need something
63    /// asynchronous to happen before they can finish their setup, like the initialization of a renderer.
64    /// Once the plugin is ready, [`finish`](Plugin::finish) should be called.
65    fn ready(&self, _app: &App) -> bool {
66        true
67    }
68
69    /// Finish adding this plugin to the [`App`], once all plugins registered are ready. This can
70    /// be useful for plugins that depends on another plugin asynchronous setup, like the renderer.
71    fn finish(&self, _app: &mut App) {
72        // do nothing
73    }
74
75    /// Runs after all plugins are built and finished, but before the app schedule is executed.
76    /// This can be useful if you have some resource that other plugins need during their build step,
77    /// but after build you want to remove it and send it to another thread.
78    fn cleanup(&self, _app: &mut App) {
79        // do nothing
80    }
81
82    /// Configures a name for the [`Plugin`] which is primarily used for checking plugin
83    /// uniqueness and debugging.
84    fn name(&self) -> &str {
85        std::any::type_name::<Self>()
86    }
87
88    /// If the plugin can be meaningfully instantiated several times in an [`App`],
89    /// override this method to return `false`.
90    fn is_unique(&self) -> bool {
91        true
92    }
93}
94
95impl_downcast!(Plugin);
96
97impl<T: Fn(&mut App) + Send + Sync + 'static> Plugin for T {
98    fn build(&self, app: &mut App) {
99        self(app);
100    }
101}
102
103/// Plugins state in the application
104#[derive(PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)]
105pub enum PluginsState {
106    /// Plugins are being added.
107    Adding,
108    /// All plugins already added are ready.
109    Ready,
110    /// Finish has been executed for all plugins added.
111    Finished,
112    /// Cleanup has been executed for all plugins added.
113    Cleaned,
114}
115
116/// A dummy plugin that's to temporarily occupy an entry in an app's plugin registry.
117pub(crate) struct PlaceholderPlugin;
118
119impl Plugin for PlaceholderPlugin {
120    fn build(&self, _app: &mut App) {}
121}
122
123/// A type representing an unsafe function that returns a mutable pointer to a [`Plugin`].
124/// It is used for dynamically loading plugins.
125///
126/// See `bevy_dynamic_plugin/src/loader.rs#dynamically_load_plugin`.
127#[deprecated(
128    since = "0.14.0",
129    note = "The current dynamic plugin system is unsound and will be removed in 0.15."
130)]
131pub type CreatePlugin = unsafe fn() -> *mut dyn Plugin;
132
133/// Types that represent a set of [`Plugin`]s.
134///
135/// This is implemented for all types which implement [`Plugin`],
136/// [`PluginGroup`](super::PluginGroup), and tuples over [`Plugins`].
137pub trait Plugins<Marker>: sealed::Plugins<Marker> {}
138
139impl<Marker, T> Plugins<Marker> for T where T: sealed::Plugins<Marker> {}
140
141mod sealed {
142    use bevy_utils::all_tuples;
143
144    use crate::{App, AppError, Plugin, PluginGroup};
145
146    pub trait Plugins<Marker> {
147        fn add_to_app(self, app: &mut App);
148    }
149
150    pub struct PluginMarker;
151    pub struct PluginGroupMarker;
152    pub struct PluginsTupleMarker;
153
154    impl<P: Plugin> Plugins<PluginMarker> for P {
155        #[track_caller]
156        fn add_to_app(self, app: &mut App) {
157            if let Err(AppError::DuplicatePlugin { plugin_name }) =
158                app.add_boxed_plugin(Box::new(self))
159            {
160                panic!(
161                    "Error adding plugin {plugin_name}: : plugin was already added in application"
162                )
163            }
164        }
165    }
166
167    impl<P: PluginGroup> Plugins<PluginGroupMarker> for P {
168        #[track_caller]
169        fn add_to_app(self, app: &mut App) {
170            self.build().finish(app);
171        }
172    }
173
174    macro_rules! impl_plugins_tuples {
175        ($(($param: ident, $plugins: ident)),*) => {
176            impl<$($param, $plugins),*> Plugins<(PluginsTupleMarker, $($param,)*)> for ($($plugins,)*)
177            where
178                $($plugins: Plugins<$param>),*
179            {
180                #[allow(non_snake_case, unused_variables)]
181                #[track_caller]
182                fn add_to_app(self, app: &mut App) {
183                    let ($($plugins,)*) = self;
184                    $($plugins.add_to_app(app);)*
185                }
186            }
187        }
188    }
189
190    all_tuples!(impl_plugins_tuples, 0, 15, P, S);
191}