Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_app/src/plugin.rs
6595 views
1
use crate::App;
2
use core::any::Any;
3
use 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
/// ```
57
pub 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
94
impl_downcast!(Plugin);
95
96
impl<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)]
104
pub 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.
116
pub(crate) struct PlaceholderPlugin;
117
118
impl 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`].
126
pub trait Plugins<Marker>: sealed::Plugins<Marker> {}
127
128
impl<Marker, T> Plugins<Marker> for T where T: sealed::Plugins<Marker> {}
129
130
mod 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
}
195
196