diff --git a/crates/bevy_a11y/src/lib.rs b/crates/bevy_a11y/src/lib.rs index aab4c23f2c..cdc653b0d2 100644 --- a/crates/bevy_a11y/src/lib.rs +++ b/crates/bevy_a11y/src/lib.rs @@ -103,6 +103,7 @@ pub enum AccessibilitySystem { } /// Plugin managing non-GUI aspects of integrating with accessibility APIs. +#[derive(Default)] pub struct AccessibilityPlugin; impl Plugin for AccessibilityPlugin { diff --git a/crates/bevy_app/src/plugin_group.rs b/crates/bevy_app/src/plugin_group.rs index 4ed220b4ae..0190ee762e 100644 --- a/crates/bevy_app/src/plugin_group.rs +++ b/crates/bevy_app/src/plugin_group.rs @@ -2,7 +2,159 @@ use crate::{App, AppError, Plugin}; use bevy_utils::{tracing::debug, tracing::warn, TypeIdMap}; use std::any::TypeId; +/// A macro for generating a well-documented [`PluginGroup`] from a list of [`Plugin`] paths. +/// +/// Every plugin must implement the [`Default`] trait. +/// +/// # Example +/// +/// ``` +/// # use bevy_app::*; +/// # +/// # mod velocity { +/// # use bevy_app::*; +/// # #[derive(Default)] +/// # pub struct VelocityPlugin; +/// # impl Plugin for VelocityPlugin { fn build(&self, _: &mut App) {} } +/// # } +/// # +/// # mod collision { +/// # pub mod capsule { +/// # use bevy_app::*; +/// # #[derive(Default)] +/// # pub struct CapsuleCollisionPlugin; +/// # impl Plugin for CapsuleCollisionPlugin { fn build(&self, _: &mut App) {} } +/// # } +/// # } +/// # +/// # #[derive(Default)] +/// # pub struct TickratePlugin; +/// # impl Plugin for TickratePlugin { fn build(&self, _: &mut App) {} } +/// # +/// # mod features { +/// # use bevy_app::*; +/// # #[derive(Default)] +/// # pub struct ForcePlugin; +/// # impl Plugin for ForcePlugin { fn build(&self, _: &mut App) {} } +/// # } +/// # +/// # mod web { +/// # use bevy_app::*; +/// # #[derive(Default)] +/// # pub struct WebCompatibilityPlugin; +/// # impl Plugin for WebCompatibilityPlugin { fn build(&self, _: &mut App) {} } +/// # } +/// # +/// # mod internal { +/// # use bevy_app::*; +/// # #[derive(Default)] +/// # pub struct InternalPlugin; +/// # impl Plugin for InternalPlugin { fn build(&self, _: &mut App) {} } +/// # } +/// # +/// plugin_group! { +/// /// Doc comments and annotations are supported: they will be added to the generated plugin +/// /// group. +/// #[derive(Debug)] +/// pub struct PhysicsPlugins { +/// // If referencing a plugin within the same module, you must prefix it with a colon `:`. +/// :TickratePlugin, +/// // If referencing a plugin within a different module, there must be three colons `:::` +/// // between the final module and the plugin name. +/// collision::capsule:::CapsuleCollisionPlugin, +/// velocity:::VelocityPlugin, +/// // If you feature-flag a plugin, it will be automatically documented. There can only be +/// // one automatically documented feature flag, and it must be first. All other +/// // `#[cfg()]` attributes must be wrapped by `#[custom()]`. +/// #[cfg(feature = "external_forces")] +/// features:::ForcePlugin, +/// // More complicated `#[cfg()]`s and annotations are not supported by automatic doc +/// // generation, in which case you must wrap it in `#[custom()]`. +/// #[custom(cfg(target_arch = "wasm32"))] +/// web:::WebCompatibilityPlugin, +/// // You can hide plugins from documentation. Due to macro limitations, hidden plugins +/// // must be last. +/// #[doc(hidden)] +/// internal:::InternalPlugin +/// } +/// /// You may add doc comments after the plugin group as well. They will be appended after +/// /// the documented list of plugins. +/// } +/// ``` +#[macro_export] +macro_rules! plugin_group { + { + $(#[$group_meta:meta])* + $vis:vis struct $group:ident { + $( + $(#[cfg(feature = $plugin_feature:literal)])? + $(#[custom($plugin_meta:meta)])* + $($plugin_path:ident::)* : $plugin_name:ident + ),* + $( + $(,)?$( + #[doc(hidden)] + $(#[cfg(feature = $hidden_plugin_feature:literal)])? + $(#[custom($hidden_plugin_meta:meta)])* + $($hidden_plugin_path:ident::)* : $hidden_plugin_name:ident + ),+ + )? + + $(,)? + } + $($(#[doc = $post_doc:literal])+)? + } => { + $(#[$group_meta])* + /// + $(#[doc = concat!( + " - [`", stringify!($plugin_name), "`](" $(, stringify!($plugin_path), "::")*, stringify!($plugin_name), ")" + $(, " - with feature `", $plugin_feature, "`")? + )])* + $( + /// + $(#[doc = $post_doc])+ + )? + $vis struct $group; + + impl $crate::PluginGroup for $group { + fn build(self) -> $crate::PluginGroupBuilder { + let mut group = $crate::PluginGroupBuilder::start::(); + + $( + $(#[cfg(feature = $plugin_feature)])? + $(#[$plugin_meta])* + { + const _: () = { + const fn check_default() {} + check_default::<$($plugin_path::)*$plugin_name>(); + }; + + group = group.add(<$($plugin_path::)*$plugin_name>::default()); + } + )* + $($( + $(#[cfg(feature = $hidden_plugin_feature)])? + $(#[$hidden_plugin_meta])* + { + const _: () = { + const fn check_default() {} + check_default::<$($hidden_plugin_path::)*$hidden_plugin_name>(); + }; + + group = group.add(<$($hidden_plugin_path::)*$hidden_plugin_name>::default()); + } + )+)? + + group + } + } + }; +} + /// Combines multiple [`Plugin`]s into a single unit. +/// +/// If you want an easier, but slightly more restrictive, method of implementing this trait, you +/// may be interested in the [`plugin_group!`] macro. pub trait PluginGroup: Sized { /// Configures the [`Plugin`]s that are to be added. fn build(self) -> PluginGroupBuilder; diff --git a/crates/bevy_dev_tools/src/ci_testing/mod.rs b/crates/bevy_dev_tools/src/ci_testing/mod.rs index 1ec0ebaac1..0e10eb1a5b 100644 --- a/crates/bevy_dev_tools/src/ci_testing/mod.rs +++ b/crates/bevy_dev_tools/src/ci_testing/mod.rs @@ -18,6 +18,7 @@ use std::time::Duration; /// This plugin is included within `DefaultPlugins` and `MinimalPlugins` when the `bevy_ci_testing` /// feature is enabled. It is recommended to only used this plugin during testing (manual or /// automatic), and disable it during regular development and for production builds. +#[derive(Default)] pub struct CiTestingPlugin; impl Plugin for CiTestingPlugin { diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 16547d7ce5..d5563a0bd9 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -47,6 +47,7 @@ pub mod states; /// /// Note: The third method is not recommended, as it requires you to remove the feature before /// creating a build for release to the public. +#[derive(Default)] pub struct DevToolsPlugin; impl Plugin for DevToolsPlugin { diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 1084cce1a6..8bab13a62b 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -113,6 +113,7 @@ const LINE_JOINT_SHADER_HANDLE: Handle = Handle::weak_from_u128(11627807 /// A [`Plugin`] that provides an immediate mode drawing api for visual debugging. /// /// Requires to be loaded after [`PbrPlugin`](bevy_pbr::PbrPlugin) or [`SpritePlugin`](bevy_sprite::SpritePlugin). +#[derive(Default)] pub struct GizmoPlugin; impl Plugin for GizmoPlugin { diff --git a/crates/bevy_internal/src/default_plugins.rs b/crates/bevy_internal/src/default_plugins.rs index 88f92f38e7..c2dd44045c 100644 --- a/crates/bevy_internal/src/default_plugins.rs +++ b/crates/bevy_internal/src/default_plugins.rs @@ -1,171 +1,78 @@ -use bevy_app::{Plugin, PluginGroup, PluginGroupBuilder}; - -/// This plugin group will add all the default plugins for a *Bevy* application: -/// * [`PanicHandlerPlugin`](crate::app::PanicHandlerPlugin) -/// * [`LogPlugin`](crate::log::LogPlugin) -/// * [`TaskPoolPlugin`](crate::core::TaskPoolPlugin) -/// * [`TypeRegistrationPlugin`](crate::core::TypeRegistrationPlugin) -/// * [`FrameCountPlugin`](crate::core::FrameCountPlugin) -/// * [`TimePlugin`](crate::time::TimePlugin) -/// * [`TransformPlugin`](crate::transform::TransformPlugin) -/// * [`HierarchyPlugin`](crate::hierarchy::HierarchyPlugin) -/// * [`DiagnosticsPlugin`](crate::diagnostic::DiagnosticsPlugin) -/// * [`InputPlugin`](crate::input::InputPlugin) -/// * [`WindowPlugin`](crate::window::WindowPlugin) -/// * [`AccessibilityPlugin`](crate::a11y::AccessibilityPlugin) -/// * [`AssetPlugin`](crate::asset::AssetPlugin) - with feature `bevy_asset` -/// * [`ScenePlugin`](crate::scene::ScenePlugin) - with feature `bevy_scene` -/// * [`WinitPlugin`](crate::winit::WinitPlugin) - with feature `bevy_winit` -/// * [`RenderPlugin`](crate::render::RenderPlugin) - with feature `bevy_render` -/// * [`ImagePlugin`](crate::render::texture::ImagePlugin) - with feature `bevy_render` -/// * [`PipelinedRenderingPlugin`](crate::render::pipelined_rendering::PipelinedRenderingPlugin) - with feature `bevy_render` when not targeting `wasm32` -/// * [`CorePipelinePlugin`](crate::core_pipeline::CorePipelinePlugin) - with feature `bevy_core_pipeline` -/// * [`SpritePlugin`](crate::sprite::SpritePlugin) - with feature `bevy_sprite` -/// * [`TextPlugin`](crate::text::TextPlugin) - with feature `bevy_text` -/// * [`UiPlugin`](crate::ui::UiPlugin) - with feature `bevy_ui` -/// * [`PbrPlugin`](crate::pbr::PbrPlugin) - with feature `bevy_pbr` -/// * [`GltfPlugin`](crate::gltf::GltfPlugin) - with feature `bevy_gltf` -/// * [`AudioPlugin`](crate::audio::AudioPlugin) - with feature `bevy_audio` -/// * [`GilrsPlugin`](crate::gilrs::GilrsPlugin) - with feature `bevy_gilrs` -/// * [`AnimationPlugin`](crate::animation::AnimationPlugin) - with feature `bevy_animation` -/// * [`GizmoPlugin`](crate::gizmos::GizmoPlugin) - with feature `bevy_gizmos` -/// * [`StatesPlugin`](crate::state::app::StatesPlugin) - with feature `bevy_state` -/// * [`DevToolsPlugin`](crate::dev_tools::DevToolsPlugin) - with feature `bevy_dev_tools` -/// * [`CiTestingPlugin`](crate::dev_tools::ci_testing::CiTestingPlugin) - with feature `bevy_ci_testing` -/// -/// [`DefaultPlugins`] obeys *Cargo* *feature* flags. Users may exert control over this plugin group -/// by disabling `default-features` in their `Cargo.toml` and enabling only those features -/// that they wish to use. -/// -/// [`DefaultPlugins`] contains all the plugins typically required to build -/// a *Bevy* application which includes a *window* and presentation components. -/// For *headless* cases – without a *window* or presentation, see [`MinimalPlugins`]. -pub struct DefaultPlugins; - -impl PluginGroup for DefaultPlugins { - fn build(self) -> PluginGroupBuilder { - let mut group = PluginGroupBuilder::start::(); - group = group - .add(bevy_app::PanicHandlerPlugin) - .add(bevy_log::LogPlugin::default()) - .add(bevy_core::TaskPoolPlugin::default()) - .add(bevy_core::TypeRegistrationPlugin) - .add(bevy_core::FrameCountPlugin) - .add(bevy_time::TimePlugin) - .add(bevy_transform::TransformPlugin) - .add(bevy_hierarchy::HierarchyPlugin) - .add(bevy_diagnostic::DiagnosticsPlugin) - .add(bevy_input::InputPlugin) - .add(bevy_window::WindowPlugin::default()) - .add(bevy_a11y::AccessibilityPlugin); - - #[cfg(not(target_arch = "wasm32"))] - { - group = group.add(bevy_app::TerminalCtrlCHandlerPlugin); - } +use bevy_app::{plugin_group, Plugin}; +plugin_group! { + /// This plugin group will add all the default plugins for a *Bevy* application: + pub struct DefaultPlugins { + bevy_app:::PanicHandlerPlugin, + bevy_log:::LogPlugin, + bevy_core:::TaskPoolPlugin, + bevy_core:::TypeRegistrationPlugin, + bevy_core:::FrameCountPlugin, + bevy_time:::TimePlugin, + bevy_transform:::TransformPlugin, + bevy_hierarchy:::HierarchyPlugin, + bevy_diagnostic:::DiagnosticsPlugin, + bevy_input:::InputPlugin, + bevy_window:::WindowPlugin, + bevy_a11y:::AccessibilityPlugin, + #[custom(cfg(not(target_arch = "wasm32")))] + bevy_app:::TerminalCtrlCHandlerPlugin, #[cfg(feature = "bevy_asset")] - { - group = group.add(bevy_asset::AssetPlugin::default()); - } - + bevy_asset:::AssetPlugin, #[cfg(feature = "bevy_scene")] - { - group = group.add(bevy_scene::ScenePlugin); - } - + bevy_scene:::ScenePlugin, #[cfg(feature = "bevy_winit")] - { - group = group.add::(bevy_winit::WinitPlugin::default()); - } - + bevy_winit:::WinitPlugin, #[cfg(feature = "bevy_render")] - { - group = group - .add(bevy_render::RenderPlugin::default()) - // NOTE: Load this after renderer initialization so that it knows about the supported - // compressed texture formats - .add(bevy_render::texture::ImagePlugin::default()); - - #[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))] - { - group = group.add(bevy_render::pipelined_rendering::PipelinedRenderingPlugin); - } - } - - #[cfg(feature = "bevy_core_pipeline")] - { - group = group.add(bevy_core_pipeline::CorePipelinePlugin); - } - - #[cfg(feature = "bevy_sprite")] - { - group = group.add(bevy_sprite::SpritePlugin); - } - - #[cfg(feature = "bevy_text")] - { - group = group.add(bevy_text::TextPlugin); - } - - #[cfg(feature = "bevy_ui")] - { - group = group.add(bevy_ui::UiPlugin); - } - - #[cfg(feature = "bevy_pbr")] - { - group = group.add(bevy_pbr::PbrPlugin::default()); - } - + bevy_render:::RenderPlugin, // NOTE: Load this after renderer initialization so that it knows about the supported - // compressed texture formats + // compressed texture formats. + #[cfg(feature = "bevy_render")] + bevy_render::texture:::ImagePlugin, + #[cfg(feature = "bevy_render")] + #[custom(cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded")))] + bevy_render::pipelined_rendering:::PipelinedRenderingPlugin, + #[cfg(feature = "bevy_core_pipeline")] + bevy_core_pipeline:::CorePipelinePlugin, + #[cfg(feature = "bevy_sprite")] + bevy_sprite:::SpritePlugin, + #[cfg(feature = "bevy_text")] + bevy_text:::TextPlugin, + #[cfg(feature = "bevy_ui")] + bevy_ui:::UiPlugin, + #[cfg(feature = "bevy_pbr")] + bevy_pbr:::PbrPlugin, + // NOTE: Load this after renderer initialization so that it knows about the supported + // compressed texture formats. #[cfg(feature = "bevy_gltf")] - { - group = group.add(bevy_gltf::GltfPlugin::default()); - } - + bevy_gltf:::GltfPlugin, #[cfg(feature = "bevy_audio")] - { - group = group.add(bevy_audio::AudioPlugin::default()); - } - + bevy_audio:::AudioPlugin, #[cfg(feature = "bevy_gilrs")] - { - group = group.add(bevy_gilrs::GilrsPlugin); - } - + bevy_gilrs:::GilrsPlugin, #[cfg(feature = "bevy_animation")] - { - group = group.add(bevy_animation::AnimationPlugin); - } - + bevy_animation:::AnimationPlugin, #[cfg(feature = "bevy_gizmos")] - { - group = group.add(bevy_gizmos::GizmoPlugin); - } - + bevy_gizmos:::GizmoPlugin, #[cfg(feature = "bevy_state")] - { - group = group.add(bevy_state::app::StatesPlugin); - } - + bevy_state::app:::StatesPlugin, #[cfg(feature = "bevy_dev_tools")] - { - group = group.add(bevy_dev_tools::DevToolsPlugin); - } - + bevy_dev_tools:::DevToolsPlugin, #[cfg(feature = "bevy_ci_testing")] - { - group = group.add(bevy_dev_tools::ci_testing::CiTestingPlugin); - } - - group = group.add(IgnoreAmbiguitiesPlugin); - - group + bevy_dev_tools::ci_testing:::CiTestingPlugin, + #[doc(hidden)] + :IgnoreAmbiguitiesPlugin, } + /// [`DefaultPlugins`] obeys *Cargo* *feature* flags. Users may exert control over this plugin group + /// by disabling `default-features` in their `Cargo.toml` and enabling only those features + /// that they wish to use. + /// + /// [`DefaultPlugins`] contains all the plugins typically required to build + /// a *Bevy* application which includes a *window* and presentation components. + /// For *headless* cases – without a *window* or presentation, see [`MinimalPlugins`]. } +#[derive(Default)] struct IgnoreAmbiguitiesPlugin; impl Plugin for IgnoreAmbiguitiesPlugin { @@ -185,39 +92,23 @@ impl Plugin for IgnoreAmbiguitiesPlugin { } } -/// This plugin group will add the minimal plugins for a *Bevy* application: -/// * [`TaskPoolPlugin`](crate::core::TaskPoolPlugin) -/// * [`TypeRegistrationPlugin`](crate::core::TypeRegistrationPlugin) -/// * [`FrameCountPlugin`](crate::core::FrameCountPlugin) -/// * [`TimePlugin`](crate::time::TimePlugin) -/// * [`ScheduleRunnerPlugin`](crate::app::ScheduleRunnerPlugin) -/// * [`CiTestingPlugin`](crate::dev_tools::ci_testing::CiTestingPlugin) - with feature `bevy_ci_testing` -/// -/// This group of plugins is intended for use for minimal, *headless* programs – -/// see the [*Bevy* *headless* example](https://github.com/bevyengine/bevy/blob/main/examples/app/headless.rs) -/// – and includes a [schedule runner (`ScheduleRunnerPlugin`)](crate::app::ScheduleRunnerPlugin) -/// to provide functionality that would otherwise be driven by a windowed application's -/// *event loop* or *message loop*. -/// -/// Windowed applications that wish to use a reduced set of plugins should consider the -/// [`DefaultPlugins`] plugin group which can be controlled with *Cargo* *feature* flags. -pub struct MinimalPlugins; - -impl PluginGroup for MinimalPlugins { - fn build(self) -> PluginGroupBuilder { - let mut group = PluginGroupBuilder::start::(); - group = group - .add(bevy_core::TaskPoolPlugin::default()) - .add(bevy_core::TypeRegistrationPlugin) - .add(bevy_core::FrameCountPlugin) - .add(bevy_time::TimePlugin) - .add(bevy_app::ScheduleRunnerPlugin::default()); - +plugin_group! { + /// This plugin group will add the minimal plugins for a *Bevy* application: + pub struct MinimalPlugins { + bevy_core:::TaskPoolPlugin, + bevy_core:::TypeRegistrationPlugin, + bevy_core:::FrameCountPlugin, + bevy_time:::TimePlugin, + bevy_app:::ScheduleRunnerPlugin, #[cfg(feature = "bevy_ci_testing")] - { - group = group.add(bevy_dev_tools::ci_testing::CiTestingPlugin); - } - - group + bevy_dev_tools::ci_testing:::CiTestingPlugin, } + /// This group of plugins is intended for use for minimal, *headless* programs – + /// see the [*Bevy* *headless* example](https://github.com/bevyengine/bevy/blob/main/examples/app/headless.rs) + /// – and includes a [schedule runner (`ScheduleRunnerPlugin`)](crate::app::ScheduleRunnerPlugin) + /// to provide functionality that would otherwise be driven by a windowed application's + /// *event loop* or *message loop*. + /// + /// Windowed applications that wish to use a reduced set of plugins should consider the + /// [`DefaultPlugins`] plugin group which can be controlled with *Cargo* *feature* flags. } diff --git a/crates/bevy_state/src/app.rs b/crates/bevy_state/src/app.rs index 62140f6756..43374828d4 100644 --- a/crates/bevy_state/src/app.rs +++ b/crates/bevy_state/src/app.rs @@ -211,6 +211,7 @@ impl AppExtStates for App { } /// Registers the [`StateTransition`] schedule in the [`MainScheduleOrder`] to enable state processing. +#[derive(Default)] pub struct StatesPlugin; impl Plugin for StatesPlugin {