1use crate::App;
2use core::any::Any;
3use downcast_rs::{impl_downcast, Downcast};
45/// 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.
59fn build(&self, app: &mut App);
6061/// 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.
64fn ready(&self, _app: &App) -> bool {
65true
66}
6768/// 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.
70fn finish(&self, _app: &mut App) {
71// do nothing
72}
7374/// 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.
77fn cleanup(&self, _app: &mut App) {
78// do nothing
79}
8081/// Configures a name for the [`Plugin`] which is primarily used for checking plugin
82 /// uniqueness and debugging.
83fn name(&self) -> &str {
84 core::any::type_name::<Self>()
85 }
8687/// If the plugin can be meaningfully instantiated several times in an [`App`],
88 /// override this method to return `false`.
89fn is_unique(&self) -> bool {
90true
91}
92}
9394impl dyn Plugin<> {
/// Returns true if the trait object wraps an object of type `__T`.
#[inline]
pub fn is<__T: Plugin<>>(&self) -> bool {
::downcast_rs::Downcast::as_any(self).is::<__T>()
}
/// Returns a boxed object from a boxed trait object if the underlying object is of type
/// `__T`. Returns the original boxed trait if it isn't.
#[inline]
pub fn downcast<__T: Plugin<>>(self:
::downcast_rs::__alloc::boxed::Box<Self>)
->
::downcast_rs::__std::result::Result<::downcast_rs::__alloc::boxed::Box<__T>,
::downcast_rs::__alloc::boxed::Box<Self>> {
if self.is::<__T>() {
Ok(::downcast_rs::Downcast::into_any(self).downcast::<__T>().unwrap())
} else { Err(self) }
}
/// Returns an `Rc`-ed object from an `Rc`-ed trait object if the underlying object is of
/// type `__T`. Returns the original `Rc`-ed trait if it isn't.
#[inline]
pub fn downcast_rc<__T: Plugin<>>(self:
::downcast_rs::__alloc::rc::Rc<Self>)
->
::downcast_rs::__std::result::Result<::downcast_rs::__alloc::rc::Rc<__T>,
::downcast_rs::__alloc::rc::Rc<Self>> {
if self.is::<__T>() {
Ok(::downcast_rs::Downcast::into_any_rc(self).downcast::<__T>().unwrap())
} else { Err(self) }
}
/// Returns a reference to the object within the trait object if it is of type `__T`, or
/// `None` if it isn't.
#[inline]
pub fn downcast_ref<__T: Plugin<>>(&self)
-> ::downcast_rs::__std::option::Option<&__T> {
::downcast_rs::Downcast::as_any(self).downcast_ref::<__T>()
}
/// Returns a mutable reference to the object within the trait object if it is of type
/// `__T`, or `None` if it isn't.
#[inline]
pub fn downcast_mut<__T: Plugin<>>(&mut self)
-> ::downcast_rs::__std::option::Option<&mut __T> {
::downcast_rs::Downcast::as_any_mut(self).downcast_mut::<__T>()
}
}impl_downcast!(Plugin);
9596impl<T: Fn(&mut App) + Send + Sync + 'static> Pluginfor T {
97fn build(&self, app: &mut App) {
98self(app);
99 }
100}
101102/// Plugins state in the application
103#[derive(#[automatically_derived]
impl ::core::cmp::PartialEq for PluginsState {
#[inline]
fn eq(&self, other: &PluginsState) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for PluginsState {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for PluginsState {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
PluginsState::Adding => "Adding",
PluginsState::Ready => "Ready",
PluginsState::Finished => "Finished",
PluginsState::Cleaned => "Cleaned",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for PluginsState {
#[inline]
fn clone(&self) -> PluginsState { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for PluginsState { }Copy, #[automatically_derived]
impl ::core::cmp::PartialOrd for PluginsState {
#[inline]
fn partial_cmp(&self, other: &PluginsState)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for PluginsState {
#[inline]
fn cmp(&self, other: &PluginsState) -> ::core::cmp::Ordering {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr)
}
}Ord)]
104pub enum PluginsState {
105/// Plugins are being added.
106Adding,
107/// All plugins already added are ready.
108Ready,
109/// Finish has been executed for all plugins added.
110Finished,
111/// Cleanup has been executed for all plugins added.
112Cleaned,
113}
114115/// A dummy plugin that's to temporarily occupy an entry in an app's plugin registry.
116pub(crate) struct PlaceholderPlugin;
117118impl Pluginfor PlaceholderPlugin {
119fn build(&self, _app: &mut App) {}
120}
121122/// 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> {}
127128impl<Marker, T> Plugins<Marker> for T where T: sealed::Plugins<Marker> {}
129130mod sealed {
131use alloc::boxed::Box;
132use variadics_please::all_tuples;
133134use crate::{App, AppError, Plugin, PluginGroup};
135136pub trait Plugins<Marker> {
137fn add_to_app(self, app: &mut App);
138 }
139140pub struct PluginMarker;
141pub struct PluginGroupMarker;
142pub struct PluginsTupleMarker;
143144impl<P: Plugin> Plugins<PluginMarker> for P {
145#[track_caller]
146fn add_to_app(self, app: &mut App) {
147if let Err(AppError::DuplicatePlugin { plugin_name }) =
148app.add_boxed_plugin(Box::new(self))
149 {
150{
::core::panicking::panic_fmt(format_args!("Error adding plugin {0}: : plugin was already added in application",
plugin_name));
}panic!(
151"Error adding plugin {plugin_name}: : plugin was already added in application"
152)153 }
154 }
155 }
156157impl<P: PluginGroup> Plugins<PluginGroupMarker> for P {
158#[track_caller]
159fn add_to_app(self, app: &mut App) {
160self.build().finish(app);
161 }
162 }
163164macro_rules! impl_plugins_tuples {
165 ($(#[$meta:meta])* $(($param: ident, $plugins: ident)),*) => {
166 $(#[$meta])*
167impl<$($param, $plugins),*> Plugins<(PluginsTupleMarker, $($param,)*)> for ($($plugins,)*)
168where
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]
178fn add_to_app(self, app: &mut App) {
179let ($($plugins,)*) = self;
180 $($plugins.add_to_app(app);)*
181 }
182 }
183 }
184 }
185186#[doc(hidden)]
impl<P0, S0, P1, S1, P2, S2, P3, S3, P4, S4, P5, S5, P6, S6, P7, S7, P8, S8,
P9, S9, P10, S10, P11, S11, P12, S12, P13, S13, P14, S14>
Plugins<(PluginsTupleMarker, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10,
P11, P12, P13, P14)> for
(S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14) where
S0: Plugins<P0>, S1: Plugins<P1>, S2: Plugins<P2>, S3: Plugins<P3>,
S4: Plugins<P4>, S5: Plugins<P5>, S6: Plugins<P6>, S7: Plugins<P7>,
S8: Plugins<P8>, S9: Plugins<P9>, S10: Plugins<P10>, S11: Plugins<P11>,
S12: Plugins<P12>, S13: Plugins<P13>, S14: Plugins<P14> {
#[expect(clippy :: allow_attributes, reason =
"This is inside a macro, and as such, may not trigger in 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 (S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13,
S14) = self;
S0.add_to_app(app);
S1.add_to_app(app);
S2.add_to_app(app);
S3.add_to_app(app);
S4.add_to_app(app);
S5.add_to_app(app);
S6.add_to_app(app);
S7.add_to_app(app);
S8.add_to_app(app);
S9.add_to_app(app);
S10.add_to_app(app);
S11.add_to_app(app);
S12.add_to_app(app);
S13.add_to_app(app);
S14.add_to_app(app);
}
}all_tuples!(
187#[doc(fake_variadic)]
188impl_plugins_tuples,
1890,
19015,
191 P,
192 S
193 );
194}