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