Skip to content

Commit

Permalink
Allow tuples and single plugins in add_plugins, remove add_plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
geieredgar committed Mar 18, 2023
1 parent f255872 commit c100d07
Show file tree
Hide file tree
Showing 73 changed files with 396 additions and 319 deletions.
90 changes: 32 additions & 58 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::{
First, Main, MainSchedulePlugin, Plugin, PluginGroup, Startup, StateTransition, Update,
};
use crate::{First, Main, MainSchedulePlugin, Plugin, Plugins, Startup, StateTransition, Update};
pub use bevy_derive::AppLabel;
use bevy_ecs::{
prelude::*,
Expand All @@ -18,6 +16,7 @@ use std::{

#[cfg(feature = "trace")]
use bevy_utils::tracing::info_span;

bevy_utils::define_label!(
/// A strongly-typed class of labels used to identify an [`App`].
AppLabel,
Expand Down Expand Up @@ -190,7 +189,7 @@ impl Default for App {
#[cfg(feature = "bevy_reflect")]
app.init_resource::<AppTypeRegistry>();

app.add_plugin(MainSchedulePlugin);
app.add_plugins(MainSchedulePlugin);
app.add_event::<AppExit>();

#[cfg(feature = "bevy_ci_testing")]
Expand Down Expand Up @@ -640,47 +639,7 @@ impl App {
self
}

/// Adds a single [`Plugin`].
///
/// One of Bevy's core principles is modularity. All Bevy engine features are implemented
/// as [`Plugin`]s. This includes internal features like the renderer.
///
/// Bevy also provides a few sets of default [`Plugin`]s. See [`add_plugins`](Self::add_plugins).
///
/// # Examples
///
/// ```
/// # use bevy_app::prelude::*;
/// #
/// # // Dummies created to avoid using `bevy_log`,
/// # // which pulls in too many dependencies and breaks rust-analyzer
/// # pub mod bevy_log {
/// # use bevy_app::prelude::*;
/// # #[derive(Default)]
/// # pub struct LogPlugin;
/// # impl Plugin for LogPlugin{
/// # fn build(&self, app: &mut App) {}
/// # }
/// # }
/// App::new().add_plugin(bevy_log::LogPlugin::default());
/// ```
///
/// # Panics
///
/// Panics if the plugin was already added to the application.
pub fn add_plugin<T>(&mut self, plugin: T) -> &mut Self
where
T: Plugin,
{
match self.add_boxed_plugin(Box::new(plugin)) {
Ok(app) => app,
Err(AppError::DuplicatePlugin { plugin_name }) => panic!(
"Error adding plugin {plugin_name}: : plugin was already added in application"
),
}
}

/// Boxed variant of `add_plugin`, can be used from a [`PluginGroup`]
/// Boxed variant of `add_plugin`, can be used from a [`PluginGroup`](super::PluginGroup)
pub(crate) fn add_boxed_plugin(
&mut self,
plugin: Box<dyn Plugin>,
Expand Down Expand Up @@ -730,7 +689,7 @@ impl App {
/// # fn build(&self, app: &mut App) {}
/// # }
/// # let mut app = App::new();
/// # app.add_plugin(ImagePlugin::default());
/// # app.add_plugins(ImagePlugin::default());
/// let default_sampler = app.get_added_plugins::<ImagePlugin>()[0].default_sampler;
/// ```
pub fn get_added_plugins<T>(&self) -> Vec<&T>
Expand All @@ -743,31 +702,46 @@ impl App {
.collect()
}

/// Adds a group of [`Plugin`]s.
/// Adds one or more [`Plugin`]s.
///
/// One of Bevy's core principles is modularity. All Bevy engine features are implemented
/// as [`Plugin`]s. This includes internal features like the renderer.
///
/// [`Plugin`]s can be grouped into a set by using a [`PluginGroup`].
///
/// There are built-in [`PluginGroup`]s that provide core engine functionality.
/// The [`PluginGroup`]s available by default are `DefaultPlugins` and `MinimalPlugins`.
///
/// To customize the plugins in the group (reorder, disable a plugin, add a new plugin
/// before / after another plugin), call [`build()`](PluginGroup::build) on the group,
/// before / after another plugin), call [`build()`](super::PluginGroup::build) on the group,
/// which will convert it to a [`PluginGroupBuilder`](crate::PluginGroupBuilder).
///
/// You can also specify a group of [`Plugin`]s by using a tuple over [`Plugin`]s and
/// [`PluginGroup`]s. See [`Plugins`] for more details.
///
/// ## Examples
/// ```
/// # use bevy_app::{prelude::*, PluginGroupBuilder, NoopPluginGroup as MinimalPlugins};
/// #
/// # // Dummies created to avoid using `bevy_log`,
/// # // which pulls in too many dependencies and breaks rust-analyzer
/// # pub struct LogPlugin;
/// # impl Plugin for LogPlugin {
/// # fn build(&self, app: &mut App) {}
/// # }
/// App::new()
/// .add_plugins(MinimalPlugins);
/// App::new()
/// .add_plugins((MinimalPlugins, LogPlugin));
/// ```
///
/// # Panics
///
/// Panics if one of the plugin in the group was already added to the application.
pub fn add_plugins<T: PluginGroup>(&mut self, group: T) -> &mut Self {
let builder = group.build();
builder.finish(self);
/// Panics if one of the plugins was already added to the application.
///
/// [`PluginGroup`]:super::PluginGroup
pub fn add_plugins<P>(&mut self, plugins: impl Plugins<P>) -> &mut Self {
plugins.add_to_app(self);
self
}

Expand Down Expand Up @@ -977,23 +951,23 @@ mod tests {

#[test]
fn can_add_two_plugins() {
App::new().add_plugin(PluginA).add_plugin(PluginB);
App::new().add_plugins((PluginA, PluginB));
}

#[test]
#[should_panic]
fn cant_add_twice_the_same_plugin() {
App::new().add_plugin(PluginA).add_plugin(PluginA);
App::new().add_plugins((PluginA, PluginA));
}

#[test]
fn can_add_twice_the_same_plugin_with_different_type_param() {
App::new().add_plugin(PluginC(0)).add_plugin(PluginC(true));
App::new().add_plugins((PluginC(0), PluginC(true)));
}

#[test]
fn can_add_twice_the_same_plugin_not_unique() {
App::new().add_plugin(PluginD).add_plugin(PluginD);
App::new().add_plugins((PluginD, PluginD));
}

#[test]
Expand All @@ -1006,10 +980,10 @@ mod tests {
}
impl Plugin for PluginRun {
fn build(&self, app: &mut crate::App) {
app.add_plugin(InnerPlugin).run();
app.add_plugins(InnerPlugin).run();
}
}
App::new().add_plugin(PluginRun);
App::new().add_plugins(PluginRun);
}

#[derive(States, PartialEq, Eq, Debug, Default, Hash, Clone)]
Expand Down
57 changes: 57 additions & 0 deletions crates/bevy_app/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,60 @@ impl_downcast!(Plugin);
///
/// See `bevy_dynamic_plugin/src/loader.rs#dynamically_load_plugin`.
pub type CreatePlugin = unsafe fn() -> *mut dyn Plugin;

/// Types that represent a set of [`Plugin`]s.
///
/// This is implemented for all types which implement [`Plugin`],
/// [`PluginGroup`](super::PluginGroup), and tuples over [`Plugins`].
pub trait Plugins<Marker>: sealed::Plugins<Marker> {}

impl<Marker, T> Plugins<Marker> for T where T: sealed::Plugins<Marker> {}

mod sealed {

use bevy_ecs::all_tuples;

use crate::{App, AppError, Plugin, PluginGroup};

pub trait Plugins<Marker> {
fn add_to_app(self, app: &mut App);
}

pub struct IsPlugin;
pub struct IsPluginGroup;

impl<P: Plugin> Plugins<IsPlugin> for P {
fn add_to_app(self, app: &mut App) {
if let Err(AppError::DuplicatePlugin { plugin_name }) =
app.add_boxed_plugin(Box::new(self))
{
panic!(
"Error adding plugin {plugin_name}: : plugin was already added in application"
)
}
}
}

impl<P: PluginGroup> Plugins<IsPluginGroup> for P {
fn add_to_app(self, app: &mut App) {
self.build().finish(app);
}
}

macro_rules! impl_plugins_tuples {
($(($param: ident, $plugins: ident)),*) => {
impl<$($param, $plugins),*> Plugins<($($param,)*)> for ($($plugins,)*)
where
$($plugins: Plugins<$param>),*
{
#[allow(non_snake_case, unused_variables)]
fn add_to_app(self, app: &mut App) {
let ($($plugins,)*) = self;
$($plugins.add_to_app(app);)*
}
}
}
}

all_tuples!(impl_plugins_tuples, 0, 15, P, S);
}
2 changes: 1 addition & 1 deletion crates/bevy_asset/src/asset_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub struct AssetServerInternal {
/// # use bevy_app::*;
/// # let mut app = App::new();
/// // The asset plugin can be configured to watch for asset changes.
/// app.add_plugin(AssetPlugin {
/// app.add_plugins(AssetPlugin {
/// watch_for_changes: true,
/// ..Default::default()
/// });
Expand Down
8 changes: 5 additions & 3 deletions crates/bevy_asset/src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,9 +492,11 @@ mod tests {
#[uuid = "44115972-f31b-46e5-be5c-2b9aece6a52f"]
struct MyAsset;
let mut app = App::new();
app.add_plugin(bevy_core::TaskPoolPlugin::default())
.add_plugin(bevy_core::TypeRegistrationPlugin::default())
.add_plugin(crate::AssetPlugin::default());
app.add_plugins((
bevy_core::TaskPoolPlugin::default(),
bevy_core::TypeRegistrationPlugin::default(),
crate::AssetPlugin::default(),
));
app.add_asset::<MyAsset>();
let mut assets_before = app.world.resource_mut::<Assets<MyAsset>>();
let handle = assets_before.add(MyAsset);
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_asset/src/debug_asset_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl Plugin for DebugAssetServerPlugin {
.build()
});
let mut debug_asset_app = App::new();
debug_asset_app.add_plugin(AssetPlugin {
debug_asset_app.add_plugins(AssetPlugin {
asset_folder: "crates".to_string(),
watch_for_changes: true,
});
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_asset/src/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ mod tests {
#[test]
fn test_reflect_asset_operations() {
let mut app = App::new();
app.add_plugin(AssetPlugin::default())
app.add_plugins(AssetPlugin::default())
.add_asset::<AssetType>()
.register_asset_reflect::<AssetType>();

Expand Down
4 changes: 1 addition & 3 deletions crates/bevy_audio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
//! # use bevy_app::{App, AppExit, NoopPluginGroup as MinimalPlugins, Startup};
//! fn main() {
//! App::new()
//! .add_plugins(MinimalPlugins)
//! .add_plugin(AssetPlugin::default())
//! .add_plugin(AudioPlugin)
//! .add_plugins((MinimalPlugins, AssetPlugin::default(), AudioPlugin))
//! .add_systems(Startup, play_background_audio)
//! .run();
//! }
Expand Down
11 changes: 6 additions & 5 deletions crates/bevy_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@ mod tests {
#[test]
fn runs_spawn_local_tasks() {
let mut app = App::new();
app.add_plugin(TaskPoolPlugin::default());
app.add_plugin(TypeRegistrationPlugin::default());
app.add_plugins((TaskPoolPlugin::default(), TypeRegistrationPlugin::default()));

let (async_tx, async_rx) = crossbeam_channel::unbounded();
AsyncComputeTaskPool::get()
Expand Down Expand Up @@ -192,9 +191,11 @@ mod tests {
#[test]
fn frame_counter_update() {
let mut app = App::new();
app.add_plugin(TaskPoolPlugin::default());
app.add_plugin(TypeRegistrationPlugin::default());
app.add_plugin(FrameCountPlugin::default());
app.add_plugins((
TaskPoolPlugin::default(),
TypeRegistrationPlugin::default(),
FrameCountPlugin::default(),
));
app.update();

let frame_count = app.world.resource::<FrameCount>();
Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_core_pipeline/src/bloom/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ impl Plugin for BloomPlugin {
app.register_type::<BloomSettings>();
app.register_type::<BloomPrefilterSettings>();
app.register_type::<BloomCompositeMode>();
app.add_plugin(ExtractComponentPlugin::<BloomSettings>::default());
app.add_plugin(UniformComponentPlugin::<BloomUniforms>::default());
app.add_plugins((
ExtractComponentPlugin::<BloomSettings>::default(),
UniformComponentPlugin::<BloomUniforms>::default(),
));

let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/core_2d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub struct Core2dPlugin;
impl Plugin for Core2dPlugin {
fn build(&self, app: &mut App) {
app.register_type::<Camera2d>()
.add_plugin(ExtractComponentPlugin::<Camera2d>::default());
.add_plugins(ExtractComponentPlugin::<Camera2d>::default());

let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/core_3d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl Plugin for Core3dPlugin {
fn build(&self, app: &mut App) {
app.register_type::<Camera3d>()
.register_type::<Camera3dDepthLoadOp>()
.add_plugin(ExtractComponentPlugin::<Camera3d>::default());
.add_plugins(ExtractComponentPlugin::<Camera3d>::default());

let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/fxaa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl Plugin for FxaaPlugin {
fn build(&self, app: &mut App) {
load_internal_asset!(app, FXAA_SHADER_HANDLE, "fxaa.wgsl", Shader::from_wgsl);

app.add_plugin(ExtractComponentPlugin::<Fxaa>::default());
app.add_plugins(ExtractComponentPlugin::<Fxaa>::default());

let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Expand Down
20 changes: 11 additions & 9 deletions crates/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,16 @@ impl Plugin for CorePipelinePlugin {
.register_type::<DepthPrepass>()
.register_type::<NormalPrepass>()
.init_resource::<ClearColor>()
.add_plugin(ExtractResourcePlugin::<ClearColor>::default())
.add_plugin(Core2dPlugin)
.add_plugin(Core3dPlugin)
.add_plugin(BlitPlugin)
.add_plugin(MsaaWritebackPlugin)
.add_plugin(TonemappingPlugin)
.add_plugin(UpscalingPlugin)
.add_plugin(BloomPlugin)
.add_plugin(FxaaPlugin);
.add_plugins((
ExtractResourcePlugin::<ClearColor>::default(),
Core2dPlugin,
Core3dPlugin,
BlitPlugin,
MsaaWritebackPlugin,
TonemappingPlugin,
UpscalingPlugin,
BloomPlugin,
FxaaPlugin,
));
}
}
Loading

0 comments on commit c100d07

Please sign in to comment.