Skip to main content

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 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);
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(#[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.
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                {
    ::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    }
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    #[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)]
188        impl_plugins_tuples,
189        0,
190        15,
191        P,
192        S
193    );
194}