From 83084d5bbf8f19150988d56facafeb377fe9f92b Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 24 Oct 2022 21:20:33 +0000 Subject: [PATCH] Plugins own their settings. Rework PluginGroup trait. (#6336) # Objective Fixes #5884 #2879 Alternative to #2988 #5885 #2886 "Immutable" Plugin settings are currently represented as normal ECS resources, which are read as part of plugin init. This presents a number of problems: 1. If a user inserts the plugin settings resource after the plugin is initialized, it will be silently ignored (and use the defaults instead) 2. Users can modify the plugin settings resource after the plugin has been initialized. This creates a false sense of control over settings that can no longer be changed. (1) and (2) are especially problematic and confusing for the `WindowDescriptor` resource, but this is a general problem. ## Solution Immutable Plugin settings now live on each Plugin struct (ex: `WindowPlugin`). PluginGroups have been reworked to support overriding plugin values. This also removes the need for the `add_plugins_with` api, as the `add_plugins` api can use the builder pattern directly. Settings that can be used at runtime continue to be represented as ECS resources. Plugins are now configured like this: ```rust app.add_plugin(AssetPlugin { watch_for_changes: true, ..default() }) ``` PluginGroups are now configured like this: ```rust app.add_plugins(DefaultPlugins .set(AssetPlugin { watch_for_changes: true, ..default() }) ) ``` This is an alternative to #2988, which is similar. But I personally prefer this solution for a couple of reasons: * ~~#2988 doesn't solve (1)~~ #2988 does solve (1) and will panic in that case. I was wrong! * This PR directly ties plugin settings to Plugin types in a 1:1 relationship, rather than a loose "setup resource" <-> plugin coupling (where the setup resource is consumed by the first plugin that uses it). * I'm not a huge fan of overloading the ECS resource concept and implementation for something that has very different use cases and constraints. ## Changelog - PluginGroups can now be configured directly using the builder pattern. Individual plugin values can be overridden by using `plugin_group.set(SomePlugin {})`, which enables overriding default plugin values. - `WindowDescriptor` plugin settings have been moved to `WindowPlugin` and `AssetServerSettings` have been moved to `AssetPlugin` - `app.add_plugins_with` has been replaced by using `add_plugins` with the builder pattern. ## Migration Guide The `WindowDescriptor` settings have been moved from a resource to `WindowPlugin::window`: ```rust // Old (Bevy 0.8) app .insert_resource(WindowDescriptor { width: 400.0, ..default() }) .add_plugins(DefaultPlugins) // New (Bevy 0.9) app.add_plugins(DefaultPlugins.set(WindowPlugin { window: WindowDescriptor { width: 400.0, ..default() }, ..default() })) ``` The `AssetServerSettings` resource has been removed in favor of direct `AssetPlugin` configuration: ```rust // Old (Bevy 0.8) app .insert_resource(AssetServerSettings { watch_for_changes: true, ..default() }) .add_plugins(DefaultPlugins) // New (Bevy 0.9) app.add_plugins(DefaultPlugins.set(AssetPlugin { watch_for_changes: true, ..default() })) ``` `add_plugins_with` has been replaced by `add_plugins` in combination with the builder pattern: ```rust // Old (Bevy 0.8) app.add_plugins_with(DefaultPlugins, |group| group.disable::()); // New (Bevy 0.9) app.add_plugins(DefaultPlugins.build().disable::()); ``` --- crates/bevy_app/Cargo.toml | 1 + crates/bevy_app/src/app.rs | 63 ++--------- crates/bevy_app/src/plugin.rs | 6 +- crates/bevy_app/src/plugin_group.rs | 102 +++++++++++------- crates/bevy_asset/src/asset_server.rs | 6 +- crates/bevy_asset/src/assets.rs | 2 +- crates/bevy_asset/src/debug_asset_server.rs | 13 +-- crates/bevy_asset/src/lib.rs | 50 ++++----- crates/bevy_audio/src/lib.rs | 2 +- crates/bevy_internal/src/default_plugins.rs | 87 ++++++++++----- crates/bevy_log/src/lib.rs | 6 +- crates/bevy_window/src/lib.rs | 58 ++++------ crates/bevy_window/src/window.rs | 3 +- examples/app/plugin_group.rs | 17 +-- examples/app/return_after_run.rs | 4 +- examples/app/without_winit.rs | 2 +- examples/asset/custom_asset_io.rs | 35 +++--- examples/asset/hot_asset_reloading.rs | 9 +- examples/ios/src/lib.rs | 12 ++- examples/scene/scene.rs | 10 +- .../shader/compute_shader_game_of_life.rs | 12 ++- examples/stress_tests/bevymark.rs | 18 ++-- examples/stress_tests/many_buttons.rs | 10 +- examples/stress_tests/many_cubes.rs | 10 +- examples/stress_tests/many_foxes.rs | 12 ++- examples/stress_tests/many_lights.rs | 16 +-- examples/stress_tests/many_sprites.rs | 12 ++- examples/tools/scene_viewer.rs | 24 +++-- examples/ui/text_debug.rs | 10 +- examples/window/low_power.rs | 14 +-- examples/window/scale_factor_override.rs | 12 ++- examples/window/transparent_window.rs | 18 ++-- examples/window/window_settings.rs | 16 +-- tests/window/minimising.rs | 12 ++- tests/window/resizing.rs | 18 ++-- 35 files changed, 358 insertions(+), 344 deletions(-) diff --git a/crates/bevy_app/Cargo.toml b/crates/bevy_app/Cargo.toml index d8ce9e91d0298..af2d533437a46 100644 --- a/crates/bevy_app/Cargo.toml +++ b/crates/bevy_app/Cargo.toml @@ -24,6 +24,7 @@ bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" } # other serde = { version = "1.0", features = ["derive"], optional = true } ron = { version = "0.8.0", optional = true } +downcast-rs = "1.2.0" [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 25c2271365544..63ce7d052d16e 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1,4 +1,4 @@ -use crate::{CoreStage, Plugin, PluginGroup, PluginGroupBuilder, StartupSchedule, StartupStage}; +use crate::{CoreStage, Plugin, PluginGroup, StartupSchedule, StartupStage}; pub use bevy_derive::AppLabel; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ @@ -838,7 +838,8 @@ impl App { /// 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), see [`add_plugins_with`](Self::add_plugins_with). + /// before / after another plugin), call [`build()`](PluginGroup::build) on the group, + /// which will convert it to a [`PluginGroupBuilder`](crate::PluginGroupBuilder). /// /// ## Examples /// ``` @@ -847,61 +848,9 @@ impl App { /// App::new() /// .add_plugins(MinimalPlugins); /// ``` - pub fn add_plugins(&mut self, mut group: T) -> &mut Self { - let mut plugin_group_builder = PluginGroupBuilder::default(); - group.build(&mut plugin_group_builder); - plugin_group_builder.finish(self); - self - } - - /// Adds a group of [`Plugin`]s with an initializer method. - /// - /// Can be used to add a group of [`Plugin`]s, where the group is modified - /// before insertion into a Bevy application. For example, you can add - /// additional [`Plugin`]s at a specific place in the [`PluginGroup`], or deactivate - /// specific [`Plugin`]s while keeping the rest using a [`PluginGroupBuilder`]. - /// - /// # Examples - /// - /// ``` - /// # use bevy_app::{prelude::*, PluginGroupBuilder}; - /// # - /// # // Dummies created to avoid using `bevy_internal` and `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) {} - /// # } - /// # } - /// # struct DefaultPlugins; - /// # impl PluginGroup for DefaultPlugins { - /// # fn build(&mut self, group: &mut PluginGroupBuilder){ - /// # group.add(bevy_log::LogPlugin::default()); - /// # } - /// # } - /// # - /// # struct MyOwnPlugin; - /// # impl Plugin for MyOwnPlugin { - /// # fn build(&self, app: &mut App){;} - /// # } - /// # - /// App::new() - /// .add_plugins_with(DefaultPlugins, |group| { - /// group.add_before::(MyOwnPlugin) - /// }); - /// ``` - pub fn add_plugins_with(&mut self, mut group: T, func: F) -> &mut Self - where - T: PluginGroup, - F: FnOnce(&mut PluginGroupBuilder) -> &mut PluginGroupBuilder, - { - let mut plugin_group_builder = PluginGroupBuilder::default(); - group.build(&mut plugin_group_builder); - func(&mut plugin_group_builder); - plugin_group_builder.finish(self); + pub fn add_plugins(&mut self, group: T) -> &mut Self { + let builder = group.build(); + builder.finish(self); self } diff --git a/crates/bevy_app/src/plugin.rs b/crates/bevy_app/src/plugin.rs index e6e70cf856029..b768acd0f3dbd 100644 --- a/crates/bevy_app/src/plugin.rs +++ b/crates/bevy_app/src/plugin.rs @@ -1,3 +1,5 @@ +use downcast_rs::{impl_downcast, Downcast}; + use crate::App; use std::any::Any; @@ -5,7 +7,7 @@ use std::any::Any; /// /// Plugins configure an [`App`]. When an [`App`] registers a plugin, /// the plugin's [`Plugin::build`] function is run. -pub trait Plugin: Any + Send + Sync { +pub trait Plugin: Downcast + Any + Send + Sync { /// Configures the [`App`] to which this plugin is added. fn build(&self, app: &mut App); /// Configures a name for the [`Plugin`] which is primarily used for debugging. @@ -14,6 +16,8 @@ pub trait Plugin: Any + Send + Sync { } } +impl_downcast!(Plugin); + /// A type representing an unsafe function that returns a mutable pointer to a [`Plugin`]. /// It is used for dynamically loading plugins. /// diff --git a/crates/bevy_app/src/plugin_group.rs b/crates/bevy_app/src/plugin_group.rs index bc7f75d7d8113..91e6773b48d98 100644 --- a/crates/bevy_app/src/plugin_group.rs +++ b/crates/bevy_app/src/plugin_group.rs @@ -3,9 +3,13 @@ use bevy_utils::{tracing::debug, tracing::warn, HashMap}; use std::any::TypeId; /// Combines multiple [`Plugin`]s into a single unit. -pub trait PluginGroup { +pub trait PluginGroup: Sized { /// Configures the [`Plugin`]s that are to be added. - fn build(&mut self, group: &mut PluginGroupBuilder); + fn build(self) -> PluginGroupBuilder; + /// Sets the value of the given [`Plugin`], if it exists + fn set(self, plugin: T) -> PluginGroupBuilder { + self.build().set(plugin) + } } struct PluginEntry { @@ -13,6 +17,12 @@ struct PluginEntry { enabled: bool, } +impl PluginGroup for PluginGroupBuilder { + fn build(self) -> PluginGroupBuilder { + self + } +} + /// Facilitates the creation and configuration of a [`PluginGroup`]. /// Provides a build ordering to ensure that [`Plugin`]s which produce/require a [`Resource`](bevy_ecs::system::Resource) /// are built before/after dependent/depending [`Plugin`]s. [`Plugin`]s inside the group @@ -25,7 +35,7 @@ pub struct PluginGroupBuilder { impl PluginGroupBuilder { /// Finds the index of a target [`Plugin`]. Panics if the target's [`TypeId`] is not found. - fn index_of(&mut self) -> usize { + fn index_of(&self) -> usize { let index = self .order .iter() @@ -68,9 +78,27 @@ impl PluginGroupBuilder { } } + /// Sets the value of the given [`Plugin`], if it exists. + /// + /// # Panics + /// + /// Panics if the [`Plugin`] does not exist. + pub fn set(mut self, plugin: T) -> Self { + let entry = self.plugins.get_mut(&TypeId::of::()).unwrap_or_else(|| { + panic!( + "{} does not exist in this PluginGroup", + std::any::type_name::(), + ) + }); + entry.plugin = Box::new(plugin); + self + } + /// Adds the plugin [`Plugin`] at the end of this [`PluginGroupBuilder`]. If the plugin was /// already in the group, it is removed from its previous place. - pub fn add(&mut self, plugin: T) -> &mut Self { + // This is not confusing, clippy! + #[allow(clippy::should_implement_trait)] + pub fn add(mut self, plugin: T) -> Self { let target_index = self.order.len(); self.order.push(TypeId::of::()); self.upsert_plugin_state(plugin, target_index); @@ -80,7 +108,7 @@ impl PluginGroupBuilder { /// Adds a [`Plugin`] in this [`PluginGroupBuilder`] before the plugin of type `Target`. /// If the plugin was already the group, it is removed from its previous place. There must /// be a plugin of type `Target` in the group or it will panic. - pub fn add_before(&mut self, plugin: T) -> &mut Self { + pub fn add_before(mut self, plugin: T) -> Self { let target_index = self.index_of::(); self.order.insert(target_index, TypeId::of::()); self.upsert_plugin_state(plugin, target_index); @@ -90,7 +118,7 @@ impl PluginGroupBuilder { /// Adds a [`Plugin`] in this [`PluginGroupBuilder`] after the plugin of type `Target`. /// If the plugin was already the group, it is removed from its previous place. There must /// be a plugin of type `Target` in the group or it will panic. - pub fn add_after(&mut self, plugin: T) -> &mut Self { + pub fn add_after(mut self, plugin: T) -> Self { let target_index = self.index_of::() + 1; self.order.insert(target_index, TypeId::of::()); self.upsert_plugin_state(plugin, target_index); @@ -102,7 +130,7 @@ impl PluginGroupBuilder { /// [`Plugin`]s within a [`PluginGroup`] are enabled by default. This function is used to /// opt back in to a [`Plugin`] after [disabling](Self::disable) it. If there are no plugins /// of type `T` in this group, it will panic. - pub fn enable(&mut self) -> &mut Self { + pub fn enable(mut self) -> Self { let mut plugin_entry = self .plugins .get_mut(&TypeId::of::()) @@ -116,7 +144,7 @@ impl PluginGroupBuilder { /// still be used for ordering with [`add_before`](Self::add_before) or /// [`add_after`](Self::add_after), or it can be [re-enabled](Self::enable). If there are no /// plugins of type `T` in this group, it will panic. - pub fn disable(&mut self) -> &mut Self { + pub fn disable(mut self) -> Self { let mut plugin_entry = self .plugins .get_mut(&TypeId::of::()) @@ -152,7 +180,9 @@ impl PluginGroupBuilder { pub struct NoopPluginGroup; impl PluginGroup for NoopPluginGroup { - fn build(&mut self, _: &mut PluginGroupBuilder) {} + fn build(self) -> PluginGroupBuilder { + PluginGroupBuilder::default() + } } #[cfg(test)] @@ -177,10 +207,10 @@ mod tests { #[test] fn basic_ordering() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add(PluginC); assert_eq!( group.order, @@ -194,10 +224,10 @@ mod tests { #[test] fn add_after() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add_after::(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add_after::(PluginC); assert_eq!( group.order, @@ -211,10 +241,10 @@ mod tests { #[test] fn add_before() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add_before::(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add_before::(PluginC); assert_eq!( group.order, @@ -228,11 +258,11 @@ mod tests { #[test] fn readd() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add(PluginC); - group.add(PluginB); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add(PluginC) + .add(PluginB); assert_eq!( group.order, @@ -246,11 +276,11 @@ mod tests { #[test] fn readd_after() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add(PluginC); - group.add_after::(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add(PluginC) + .add_after::(PluginC); assert_eq!( group.order, @@ -264,11 +294,11 @@ mod tests { #[test] fn readd_before() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add(PluginC); - group.add_before::(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add(PluginC) + .add_before::(PluginC); assert_eq!( group.order, diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 46b2a0f5502e3..6e26ad1b23683 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -83,8 +83,8 @@ pub struct AssetServerInternal { /// # use bevy_asset::*; /// # use bevy_app::*; /// # let mut app = App::new(); -/// // AssetServerSettings must be inserted before adding the AssetPlugin or DefaultPlugins. -/// app.insert_resource(AssetServerSettings { +/// // The asset plugin can be configured to watch for asset changes. +/// app.add_plugin(AssetPlugin { /// watch_for_changes: true, /// ..Default::default() /// }); @@ -293,7 +293,7 @@ impl AssetServer { /// `"CARGO_MANIFEST_DIR"` is automatically set to the root folder of your crate (workspace). /// /// The name of the asset folder is set inside the - /// [`AssetServerSettings`](crate::AssetServerSettings) resource. The default name is + /// [`AssetPlugin`](crate::AssetPlugin). The default name is /// `"assets"`. /// /// The asset is loaded asynchronously, and will generally not be available by the time diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 97b30dd53d904..eb04ceb2cb81b 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -430,7 +430,7 @@ mod tests { struct MyAsset; let mut app = App::new(); app.add_plugin(bevy_core::CorePlugin) - .add_plugin(crate::AssetPlugin); + .add_plugin(crate::AssetPlugin::default()); app.add_asset::(); let mut assets_before = app.world.resource_mut::>(); let handle = assets_before.add(MyAsset); diff --git a/crates/bevy_asset/src/debug_asset_server.rs b/crates/bevy_asset/src/debug_asset_server.rs index fafc3be759164..690dd6769dc7c 100644 --- a/crates/bevy_asset/src/debug_asset_server.rs +++ b/crates/bevy_asset/src/debug_asset_server.rs @@ -16,8 +16,7 @@ use std::{ }; use crate::{ - Asset, AssetEvent, AssetPlugin, AssetServer, AssetServerSettings, Assets, FileAssetIo, Handle, - HandleUntyped, + Asset, AssetEvent, AssetPlugin, AssetServer, Assets, FileAssetIo, Handle, HandleUntyped, }; /// A helper [`App`] used for hot reloading internal assets, which are compiled-in to Bevy plugins. @@ -75,12 +74,10 @@ impl Plugin for DebugAssetServerPlugin { .build() }); let mut debug_asset_app = App::new(); - debug_asset_app - .insert_resource(AssetServerSettings { - asset_folder: "crates".to_string(), - watch_for_changes: true, - }) - .add_plugin(AssetPlugin); + debug_asset_app.add_plugin(AssetPlugin { + asset_folder: "crates".to_string(), + watch_for_changes: true, + }); app.insert_non_send_resource(DebugAssetApp(debug_asset_app)); app.add_system(run_debug_asset_app); } diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index 24e9d975b1193..ff125d3abd275 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -30,7 +30,7 @@ mod path; pub mod prelude { #[doc(hidden)] pub use crate::{ - AddAsset, AssetEvent, AssetServer, AssetServerSettings, Assets, Handle, HandleUntyped, + AddAsset, AssetEvent, AssetPlugin, AssetServer, Assets, Handle, HandleUntyped, }; } @@ -45,10 +45,7 @@ pub use loader::*; pub use path::*; use bevy_app::{prelude::Plugin, App}; -use bevy_ecs::{ - schedule::{StageLabel, SystemStage}, - system::Resource, -}; +use bevy_ecs::schedule::{StageLabel, SystemStage}; /// The names of asset stages in an [`App`] schedule. #[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] @@ -63,14 +60,7 @@ pub enum AssetStage { /// /// Assets are typed collections with change tracking, which are added as App Resources. Examples of /// assets: textures, sounds, 3d models, maps, scenes -#[derive(Default)] -pub struct AssetPlugin; - -/// Settings for the [`AssetServer`]. -/// -/// This resource must be added before the [`AssetPlugin`] or `DefaultPlugins` to take effect. -#[derive(Resource)] -pub struct AssetServerSettings { +pub struct AssetPlugin { /// The base folder where assets are loaded from, relative to the executable. pub asset_folder: String, /// Whether to watch for changes in asset files. Requires the `filesystem_watcher` feature, @@ -78,7 +68,7 @@ pub struct AssetServerSettings { pub watch_for_changes: bool, } -impl Default for AssetServerSettings { +impl Default for AssetPlugin { fn default() -> Self { Self { asset_folder: "assets".to_string(), @@ -87,29 +77,27 @@ impl Default for AssetServerSettings { } } -/// Creates an instance of the platform's default `AssetIo`. -/// -/// This is useful when providing a custom `AssetIo` instance that needs to -/// delegate to the default `AssetIo` for the platform. -pub fn create_platform_default_asset_io(app: &mut App) -> Box { - let settings = app - .world - .get_resource_or_insert_with(AssetServerSettings::default); +impl AssetPlugin { + /// Creates an instance of the platform's default `AssetIo`. + /// + /// This is useful when providing a custom `AssetIo` instance that needs to + /// delegate to the default `AssetIo` for the platform. + pub fn create_platform_default_asset_io(&self) -> Box { + #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))] + let source = FileAssetIo::new(&self.asset_folder, self.watch_for_changes); + #[cfg(target_arch = "wasm32")] + let source = WasmAssetIo::new(&self.asset_folder); + #[cfg(target_os = "android")] + let source = AndroidAssetIo::new(&self.asset_folder); - #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))] - let source = FileAssetIo::new(&settings.asset_folder, settings.watch_for_changes); - #[cfg(target_arch = "wasm32")] - let source = WasmAssetIo::new(&settings.asset_folder); - #[cfg(target_os = "android")] - let source = AndroidAssetIo::new(&settings.asset_folder); - - Box::new(source) + Box::new(source) + } } impl Plugin for AssetPlugin { fn build(&self, app: &mut App) { if !app.world.contains_resource::() { - let source = create_platform_default_asset_io(app); + let source = self.create_platform_default_asset_io(); let asset_server = AssetServer::with_boxed_io(source); app.insert_resource(asset_server); } diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index c4f2390ebf4eb..8ad4f95217b51 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -8,7 +8,7 @@ //! fn main() { //! App::new() //! .add_plugins(MinimalPlugins) -//! .add_plugin(AssetPlugin) +//! .add_plugin(AssetPlugin::default()) //! .add_plugin(AudioPlugin) //! .add_startup_system(play_background_audio) //! .run(); diff --git a/crates/bevy_internal/src/default_plugins.rs b/crates/bevy_internal/src/default_plugins.rs index 07383f5023f5a..bfbe7c5b832cd 100644 --- a/crates/bevy_internal/src/default_plugins.rs +++ b/crates/bevy_internal/src/default_plugins.rs @@ -25,59 +25,91 @@ use bevy_app::{PluginGroup, PluginGroupBuilder}; pub struct DefaultPlugins; impl PluginGroup for DefaultPlugins { - fn build(&mut self, group: &mut PluginGroupBuilder) { - group.add(bevy_log::LogPlugin::default()); - group.add(bevy_core::CorePlugin::default()); - group.add(bevy_time::TimePlugin::default()); - group.add(bevy_transform::TransformPlugin::default()); - group.add(bevy_hierarchy::HierarchyPlugin::default()); - group.add(bevy_diagnostic::DiagnosticsPlugin::default()); - group.add(bevy_input::InputPlugin::default()); - group.add(bevy_window::WindowPlugin::default()); + fn build(self) -> PluginGroupBuilder { + let mut group = PluginGroupBuilder::default(); + group = group + .add(bevy_log::LogPlugin::default()) + .add(bevy_core::CorePlugin::default()) + .add(bevy_time::TimePlugin::default()) + .add(bevy_transform::TransformPlugin::default()) + .add(bevy_hierarchy::HierarchyPlugin::default()) + .add(bevy_diagnostic::DiagnosticsPlugin::default()) + .add(bevy_input::InputPlugin::default()) + .add(bevy_window::WindowPlugin::default()); #[cfg(feature = "bevy_asset")] - group.add(bevy_asset::AssetPlugin::default()); + { + group = group.add(bevy_asset::AssetPlugin::default()); + } #[cfg(feature = "debug_asset_server")] - group.add(bevy_asset::debug_asset_server::DebugAssetServerPlugin::default()); + { + group = group.add(bevy_asset::debug_asset_server::DebugAssetServerPlugin::default()); + } #[cfg(feature = "bevy_scene")] - group.add(bevy_scene::ScenePlugin::default()); + { + group = group.add(bevy_scene::ScenePlugin::default()); + } #[cfg(feature = "bevy_winit")] - group.add(bevy_winit::WinitPlugin::default()); + { + group = group.add(bevy_winit::WinitPlugin::default()); + } #[cfg(feature = "bevy_render")] - group.add(bevy_render::RenderPlugin::default()); + { + group = group.add(bevy_render::RenderPlugin::default()); + } #[cfg(feature = "bevy_core_pipeline")] - group.add(bevy_core_pipeline::CorePipelinePlugin::default()); + { + group = group.add(bevy_core_pipeline::CorePipelinePlugin::default()); + } #[cfg(feature = "bevy_sprite")] - group.add(bevy_sprite::SpritePlugin::default()); + { + group = group.add(bevy_sprite::SpritePlugin::default()); + } #[cfg(feature = "bevy_text")] - group.add(bevy_text::TextPlugin::default()); + { + group = group.add(bevy_text::TextPlugin::default()); + } #[cfg(feature = "bevy_ui")] - group.add(bevy_ui::UiPlugin::default()); + { + group = group.add(bevy_ui::UiPlugin::default()); + } #[cfg(feature = "bevy_pbr")] - group.add(bevy_pbr::PbrPlugin::default()); + { + group = group.add(bevy_pbr::PbrPlugin::default()); + } // NOTE: Load this after renderer initialization so that it knows about the supported // compressed texture formats #[cfg(feature = "bevy_gltf")] - group.add(bevy_gltf::GltfPlugin::default()); + { + group = group.add(bevy_gltf::GltfPlugin::default()); + } #[cfg(feature = "bevy_audio")] - group.add(bevy_audio::AudioPlugin::default()); + { + group = group.add(bevy_audio::AudioPlugin::default()); + } #[cfg(feature = "bevy_gilrs")] - group.add(bevy_gilrs::GilrsPlugin::default()); + { + group = group.add(bevy_gilrs::GilrsPlugin::default()); + } #[cfg(feature = "bevy_animation")] - group.add(bevy_animation::AnimationPlugin::default()); + { + group = group.add(bevy_animation::AnimationPlugin::default()); + } + + group } } @@ -90,9 +122,10 @@ impl PluginGroup for DefaultPlugins { pub struct MinimalPlugins; impl PluginGroup for MinimalPlugins { - fn build(&mut self, group: &mut PluginGroupBuilder) { - group.add(bevy_core::CorePlugin::default()); - group.add(bevy_time::TimePlugin::default()); - group.add(bevy_app::ScheduleRunnerPlugin::default()); + fn build(self) -> PluginGroupBuilder { + PluginGroupBuilder::default() + .add(bevy_core::CorePlugin::default()) + .add(bevy_time::TimePlugin::default()) + .add(bevy_app::ScheduleRunnerPlugin::default()) } } diff --git a/crates/bevy_log/src/lib.rs b/crates/bevy_log/src/lib.rs index a7518327a5678..5718cee240a5b 100644 --- a/crates/bevy_log/src/lib.rs +++ b/crates/bevy_log/src/lib.rs @@ -71,13 +71,13 @@ use tracing_subscriber::{prelude::*, registry::Registry, EnvFilter}; /// will be ignored. /// /// If you want to setup your own tracing collector, you should disable this -/// plugin from `DefaultPlugins` with [`App::add_plugins_with`]: +/// plugin from `DefaultPlugins`: /// ```no_run -/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins}; +/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup}; /// # use bevy_log::LogPlugin; /// fn main() { /// App::new() -/// .add_plugins_with(DefaultPlugins, |group| group.disable::()) +/// .add_plugins(DefaultPlugins.build().disable::()) /// .run(); /// } /// ``` diff --git a/crates/bevy_window/src/lib.rs b/crates/bevy_window/src/lib.rs index 6b17c363d71be..a00f851d35b5d 100644 --- a/crates/bevy_window/src/lib.rs +++ b/crates/bevy_window/src/lib.rs @@ -17,8 +17,8 @@ pub mod prelude { #[doc(hidden)] pub use crate::{ CursorEntered, CursorIcon, CursorLeft, CursorMoved, FileDragAndDrop, MonitorSelection, - ReceivedCharacter, Window, WindowDescriptor, WindowMode, WindowMoved, WindowPosition, - Windows, + ReceivedCharacter, Window, WindowDescriptor, WindowMode, WindowMoved, WindowPlugin, + WindowPosition, Windows, }; } @@ -26,15 +26,22 @@ use bevy_app::prelude::*; use bevy_ecs::{ event::Events, schedule::{IntoSystemDescriptor, SystemLabel}, - system::Resource, }; -/// The configuration information for the [`WindowPlugin`]. -/// -/// It can be added as a [`Resource`](bevy_ecs::system::Resource) before the [`WindowPlugin`] -/// runs, to configure how it behaves. -#[derive(Resource, Clone)] -pub struct WindowSettings { +impl Default for WindowPlugin { + fn default() -> Self { + WindowPlugin { + window: Default::default(), + add_primary_window: true, + exit_on_all_closed: true, + close_when_requested: true, + } + } +} + +/// A [`Plugin`] that defines an interface for windowing support in Bevy. +pub struct WindowPlugin { + pub window: WindowDescriptor, /// Whether to create a window when added. /// /// Note that if there are no windows, by default the App will exit, @@ -58,20 +65,6 @@ pub struct WindowSettings { pub close_when_requested: bool, } -impl Default for WindowSettings { - fn default() -> Self { - WindowSettings { - add_primary_window: true, - exit_on_all_closed: true, - close_when_requested: true, - } - } -} - -/// A [`Plugin`] that defines an interface for windowing support in Bevy. -#[derive(Default)] -pub struct WindowPlugin; - impl Plugin for WindowPlugin { fn build(&self, app: &mut App) { app.add_event::() @@ -91,32 +84,21 @@ impl Plugin for WindowPlugin { .add_event::() .init_resource::(); - let settings = app - .world - .get_resource::() - .cloned() - .unwrap_or_default(); - - if settings.add_primary_window { - let window_descriptor = app - .world - .get_resource::() - .cloned() - .unwrap_or_default(); + if self.add_primary_window { let mut create_window_event = app.world.resource_mut::>(); create_window_event.send(CreateWindow { id: WindowId::primary(), - descriptor: window_descriptor, + descriptor: self.window.clone(), }); } - if settings.exit_on_all_closed { + if self.exit_on_all_closed { app.add_system_to_stage( CoreStage::PostUpdate, exit_on_all_closed.after(ModifiesWindows), ); } - if settings.close_when_requested { + if self.close_when_requested { app.add_system(close_when_requested); } } diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 2ee019d04bf94..1c7416b2c96a2 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -1,4 +1,3 @@ -use bevy_ecs::system::Resource; use bevy_math::{DVec2, IVec2, UVec2, Vec2}; use bevy_reflect::{FromReflect, Reflect}; use bevy_utils::{tracing::warn, Uuid}; @@ -895,7 +894,7 @@ pub enum MonitorSelection { /// See [`examples/window/window_settings.rs`] for usage. /// /// [`examples/window/window_settings.rs`]: https://github.com/bevyengine/bevy/blob/latest/examples/window/window_settings.rs -#[derive(Resource, Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct WindowDescriptor { /// The requested logical width of the window's client area. diff --git a/examples/app/plugin_group.rs b/examples/app/plugin_group.rs index 5eb4a27a7cd02..474bd5b6f5ca2 100644 --- a/examples/app/plugin_group.rs +++ b/examples/app/plugin_group.rs @@ -10,11 +10,14 @@ fn main() { // Adding a plugin group adds all plugins in the group by default .add_plugins(HelloWorldPlugins) // You can also modify a PluginGroup (such as disabling plugins) like this: - // .add_plugins_with(HelloWorldPlugins, |group| { - // group + // .add_plugins( + // HelloWorldPlugins + // .build() // .disable::() - // .add_before::(bevy::diagnostic::LogDiagnosticsPlugin::default()) }) + // .add_before::( + // bevy::diagnostic::LogDiagnosticsPlugin::default(), + // ), + // ) .run(); } @@ -22,8 +25,10 @@ fn main() { pub struct HelloWorldPlugins; impl PluginGroup for HelloWorldPlugins { - fn build(&mut self, group: &mut PluginGroupBuilder) { - group.add(PrintHelloPlugin).add(PrintWorldPlugin); + fn build(self) -> PluginGroupBuilder { + PluginGroupBuilder::default() + .add(PrintHelloPlugin) + .add(PrintWorldPlugin) } } diff --git a/examples/app/return_after_run.rs b/examples/app/return_after_run.rs index d1ef945390083..bc7e2b1f0e3b9 100644 --- a/examples/app/return_after_run.rs +++ b/examples/app/return_after_run.rs @@ -20,9 +20,7 @@ fn main() { ..default() }) .insert_resource(ClearColor(Color::rgb(0.2, 0.8, 0.2))) - .add_plugins_with(DefaultPlugins, |group| { - group.disable::() - }) + .add_plugins(DefaultPlugins.build().disable::()) .add_system(system2) .run(); println!("Done."); diff --git a/examples/app/without_winit.rs b/examples/app/without_winit.rs index b06a0129673fb..1171225661d13 100644 --- a/examples/app/without_winit.rs +++ b/examples/app/without_winit.rs @@ -5,7 +5,7 @@ use bevy::winit::WinitPlugin; fn main() { App::new() - .add_plugins_with(DefaultPlugins, |group| group.disable::()) + .add_plugins(DefaultPlugins.build().disable::()) .add_system(setup_system) .run(); } diff --git a/examples/asset/custom_asset_io.rs b/examples/asset/custom_asset_io.rs index 0255978ee6d5c..e8f369effa9cd 100644 --- a/examples/asset/custom_asset_io.rs +++ b/examples/asset/custom_asset_io.rs @@ -51,35 +51,30 @@ struct CustomAssetIoPlugin; impl Plugin for CustomAssetIoPlugin { fn build(&self, app: &mut App) { - let asset_io = { - // the platform default asset io requires a reference to the app - // builder to find its configuration + let default_io = AssetPlugin::default().create_platform_default_asset_io(); - let default_io = bevy::asset::create_platform_default_asset_io(app); - - // create the custom asset io instance - - CustomAssetIo(default_io) - }; + // create the custom asset io instance + let asset_io = CustomAssetIo(default_io); // the asset server is constructed and added the resource manager - app.insert_resource(AssetServer::new(asset_io)); } } fn main() { App::new() - .add_plugins_with(DefaultPlugins, |group| { - // the custom asset io plugin must be inserted in-between the - // `CorePlugin' and `AssetPlugin`. It needs to be after the - // CorePlugin, so that the IO task pool has already been constructed. - // And it must be before the `AssetPlugin` so that the asset plugin - // doesn't create another instance of an asset server. In general, - // the AssetPlugin should still run so that other aspects of the - // asset system are initialized correctly. - group.add_before::(CustomAssetIoPlugin) - }) + .add_plugins( + DefaultPlugins + .build() + // the custom asset io plugin must be inserted in-between the + // `CorePlugin' and `AssetPlugin`. It needs to be after the + // CorePlugin, so that the IO task pool has already been constructed. + // And it must be before the `AssetPlugin` so that the asset plugin + // doesn't create another instance of an asset server. In general, + // the AssetPlugin should still run so that other aspects of the + // asset system are initialized correctly. + .add_before::(CustomAssetIoPlugin), + ) .add_startup_system(setup) .run(); } diff --git a/examples/asset/hot_asset_reloading.rs b/examples/asset/hot_asset_reloading.rs index a6e28328922a2..2d716bc86f97f 100644 --- a/examples/asset/hot_asset_reloading.rs +++ b/examples/asset/hot_asset_reloading.rs @@ -2,16 +2,15 @@ //! running. This lets you immediately see the results of your changes without restarting the game. //! This example illustrates hot reloading mesh changes. -use bevy::{asset::AssetServerSettings, prelude::*}; +use bevy::prelude::*; fn main() { App::new() - // Tell the asset server to watch for asset changes on disk: - .insert_resource(AssetServerSettings { + .add_plugins(DefaultPlugins.set(AssetPlugin { + // Tell the asset server to watch for asset changes on disk: watch_for_changes: true, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_startup_system(setup) .run(); } diff --git a/examples/ios/src/lib.rs b/examples/ios/src/lib.rs index aca39c99a57b1..9924aa62a42c2 100644 --- a/examples/ios/src/lib.rs +++ b/examples/ios/src/lib.rs @@ -4,12 +4,14 @@ use bevy::{input::touch::TouchPhase, prelude::*, window::WindowMode}; #[bevy_main] fn main() { App::new() - .insert_resource(WindowDescriptor { - resizable: false, - mode: WindowMode::BorderlessFullscreen, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + resizable: false, + mode: WindowMode::BorderlessFullscreen, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_startup_system(setup_scene) .add_startup_system(setup_music) .add_system(touch_camera) diff --git a/examples/scene/scene.rs b/examples/scene/scene.rs index e8e0271af28a1..20efbc936fa4f 100644 --- a/examples/scene/scene.rs +++ b/examples/scene/scene.rs @@ -6,14 +6,12 @@ use bevy::{prelude::*, tasks::IoTaskPool, utils::Duration}; fn main() { App::new() - // This tells the AssetServer to watch for changes to assets. - // It enables our scenes to automatically reload in game when we modify their files. - // AssetServerSettings must be inserted before the DefaultPlugins are added. - .insert_resource(AssetServerSettings { + .add_plugins(DefaultPlugins.set(AssetPlugin { + // This tells the AssetServer to watch for changes to assets. + // It enables our scenes to automatically reload in game when we modify their files. watch_for_changes: true, ..default() - }) - .add_plugins(DefaultPlugins) + })) .register_type::() .register_type::() .add_startup_system(save_scene_system) diff --git a/examples/shader/compute_shader_game_of_life.rs b/examples/shader/compute_shader_game_of_life.rs index aff074fd28c87..af665f362a161 100644 --- a/examples/shader/compute_shader_game_of_life.rs +++ b/examples/shader/compute_shader_game_of_life.rs @@ -22,12 +22,14 @@ const WORKGROUP_SIZE: u32 = 8; fn main() { App::new() .insert_resource(ClearColor(Color::BLACK)) - .insert_resource(WindowDescriptor { - // uncomment for unthrottled FPS - // present_mode: bevy::window::PresentMode::AutoNoVsync, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + // uncomment for unthrottled FPS + // present_mode: bevy::window::PresentMode::AutoNoVsync, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_plugin(GameOfLifeComputePlugin) .add_startup_system(setup) .run(); diff --git a/examples/stress_tests/bevymark.rs b/examples/stress_tests/bevymark.rs index 6d40ec2d23220..f60df88edc957 100644 --- a/examples/stress_tests/bevymark.rs +++ b/examples/stress_tests/bevymark.rs @@ -29,15 +29,17 @@ struct Bird { fn main() { App::new() - .insert_resource(WindowDescriptor { - title: "BevyMark".to_string(), - width: 800., - height: 600., - present_mode: PresentMode::AutoNoVsync, - resizable: true, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + title: "BevyMark".to_string(), + width: 800., + height: 600., + present_mode: PresentMode::AutoNoVsync, + resizable: true, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_plugin(FrameTimeDiagnosticsPlugin::default()) .add_plugin(LogDiagnosticsPlugin::default()) .insert_resource(BevyCounter { diff --git a/examples/stress_tests/many_buttons.rs b/examples/stress_tests/many_buttons.rs index 74a3d6b37d6b4..8ea438753e7e2 100644 --- a/examples/stress_tests/many_buttons.rs +++ b/examples/stress_tests/many_buttons.rs @@ -11,11 +11,13 @@ const FONT_SIZE: f32 = 7.0; /// This example shows what happens when there is a lot of buttons on screen. fn main() { App::new() - .insert_resource(WindowDescriptor { - present_mode: PresentMode::Immediate, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + present_mode: PresentMode::Immediate, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_plugin(FrameTimeDiagnosticsPlugin::default()) .add_plugin(LogDiagnosticsPlugin::default()) .init_resource::() diff --git a/examples/stress_tests/many_cubes.rs b/examples/stress_tests/many_cubes.rs index b1afdadd64a29..b693205435078 100644 --- a/examples/stress_tests/many_cubes.rs +++ b/examples/stress_tests/many_cubes.rs @@ -21,11 +21,13 @@ use bevy::{ fn main() { App::new() - .insert_resource(WindowDescriptor { - present_mode: PresentMode::AutoNoVsync, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + present_mode: PresentMode::AutoNoVsync, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_plugin(FrameTimeDiagnosticsPlugin::default()) .add_plugin(LogDiagnosticsPlugin::default()) .add_startup_system(setup) diff --git a/examples/stress_tests/many_foxes.rs b/examples/stress_tests/many_foxes.rs index d67d05e5b50e0..80a940937a799 100644 --- a/examples/stress_tests/many_foxes.rs +++ b/examples/stress_tests/many_foxes.rs @@ -18,12 +18,14 @@ struct Foxes { fn main() { App::new() - .insert_resource(WindowDescriptor { - title: "🦊🦊🦊 Many Foxes! 🦊🦊🦊".to_string(), - present_mode: PresentMode::AutoNoVsync, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + title: "🦊🦊🦊 Many Foxes! 🦊🦊🦊".to_string(), + present_mode: PresentMode::AutoNoVsync, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_plugin(FrameTimeDiagnosticsPlugin) .add_plugin(LogDiagnosticsPlugin::default()) .insert_resource(Foxes { diff --git a/examples/stress_tests/many_lights.rs b/examples/stress_tests/many_lights.rs index fa63701feeb46..1e76e151624fd 100644 --- a/examples/stress_tests/many_lights.rs +++ b/examples/stress_tests/many_lights.rs @@ -15,14 +15,16 @@ use rand::{thread_rng, Rng}; fn main() { App::new() - .insert_resource(WindowDescriptor { - width: 1024.0, - height: 768.0, - title: "many_lights".to_string(), - present_mode: PresentMode::AutoNoVsync, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + width: 1024.0, + height: 768.0, + title: "many_lights".to_string(), + present_mode: PresentMode::AutoNoVsync, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_plugin(FrameTimeDiagnosticsPlugin::default()) .add_plugin(LogDiagnosticsPlugin::default()) .add_startup_system(setup) diff --git a/examples/stress_tests/many_sprites.rs b/examples/stress_tests/many_sprites.rs index 1a232c37ae30e..ef39c64b17026 100644 --- a/examples/stress_tests/many_sprites.rs +++ b/examples/stress_tests/many_sprites.rs @@ -24,17 +24,19 @@ struct ColorTint(bool); fn main() { App::new() - .insert_resource(WindowDescriptor { - present_mode: PresentMode::AutoNoVsync, - ..default() - }) .insert_resource(ColorTint( std::env::args().nth(1).unwrap_or_default() == "--colored", )) // Since this is also used as a benchmark, we want it to display performance data. .add_plugin(LogDiagnosticsPlugin::default()) .add_plugin(FrameTimeDiagnosticsPlugin::default()) - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + present_mode: PresentMode::AutoNoVsync, + ..default() + }, + ..default() + })) .add_startup_system(setup) .add_system(print_sprite_count) .add_system(move_camera.after(print_sprite_count)) diff --git a/examples/tools/scene_viewer.rs b/examples/tools/scene_viewer.rs index fac2833773c05..8f9c9af767caf 100644 --- a/examples/tools/scene_viewer.rs +++ b/examples/tools/scene_viewer.rs @@ -45,16 +45,22 @@ Controls: color: Color::WHITE, brightness: 1.0 / 5.0f32, }) - .insert_resource(AssetServerSettings { - asset_folder: std::env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".to_string()), - watch_for_changes: true, - }) - .insert_resource(WindowDescriptor { - title: "bevy scene viewer".to_string(), - ..default() - }) .init_resource::() - .add_plugins(DefaultPlugins) + .add_plugins( + DefaultPlugins + .set(WindowPlugin { + window: WindowDescriptor { + title: "bevy scene viewer".to_string(), + ..default() + }, + ..default() + }) + .set(AssetPlugin { + asset_folder: std::env::var("CARGO_MANIFEST_DIR") + .unwrap_or_else(|_| ".".to_string()), + watch_for_changes: true, + }), + ) .add_startup_system(setup) .add_system_to_stage(CoreStage::PreUpdate, scene_load_check) .add_system_to_stage(CoreStage::PreUpdate, setup_scene_after_load) diff --git a/examples/ui/text_debug.rs b/examples/ui/text_debug.rs index d67e61ace33b0..19cc0a0fb74df 100644 --- a/examples/ui/text_debug.rs +++ b/examples/ui/text_debug.rs @@ -8,11 +8,13 @@ use bevy::{ fn main() { App::new() - .insert_resource(WindowDescriptor { - present_mode: PresentMode::AutoNoVsync, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + present_mode: PresentMode::AutoNoVsync, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_plugin(FrameTimeDiagnosticsPlugin) .add_startup_system(infotext_system) .add_system(change_text_system) diff --git a/examples/window/low_power.rs b/examples/window/low_power.rs index e97f20fc5e501..bf747f76dd377 100644 --- a/examples/window/low_power.rs +++ b/examples/window/low_power.rs @@ -24,13 +24,15 @@ fn main() { }, ..default() }) - // Turn off vsync to maximize CPU/GPU usage - .insert_resource(WindowDescriptor { - present_mode: PresentMode::AutoNoVsync, - ..default() - }) .insert_resource(ExampleMode::Game) - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + // Turn off vsync to maximize CPU/GPU usage + present_mode: PresentMode::AutoNoVsync, + ..default() + }, + ..default() + })) .add_startup_system(test_setup::setup) .add_system(test_setup::cycle_modes) .add_system(test_setup::rotate_cube) diff --git a/examples/window/scale_factor_override.rs b/examples/window/scale_factor_override.rs index 648a67b5dc6df..2d95ceae9e65e 100644 --- a/examples/window/scale_factor_override.rs +++ b/examples/window/scale_factor_override.rs @@ -5,12 +5,14 @@ use bevy::prelude::*; fn main() { App::new() - .insert_resource(WindowDescriptor { - width: 500., - height: 300., + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + width: 500., + height: 300., + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_startup_system(setup) .add_system(toggle_override) .add_system(change_scale_factor) diff --git a/examples/window/transparent_window.rs b/examples/window/transparent_window.rs index b229b05092a28..b40c65c6d92db 100644 --- a/examples/window/transparent_window.rs +++ b/examples/window/transparent_window.rs @@ -10,15 +10,17 @@ fn main() { App::new() // ClearColor must have 0 alpha, otherwise some color will bleed through .insert_resource(ClearColor(Color::NONE)) - .insert_resource(WindowDescriptor { - // Setting `transparent` allows the `ClearColor`'s alpha value to take effect - transparent: true, - // Disabling window decorations to make it feel more like a widget than a window - decorations: false, - ..default() - }) .add_startup_system(setup) - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + // Setting `transparent` allows the `ClearColor`'s alpha value to take effect + transparent: true, + // Disabling window decorations to make it feel more like a widget than a window + decorations: false, + ..default() + }, + ..default() + })) .run(); } diff --git a/examples/window/window_settings.rs b/examples/window/window_settings.rs index 9fa9b6c9f8e65..06e1b5686f62d 100644 --- a/examples/window/window_settings.rs +++ b/examples/window/window_settings.rs @@ -9,14 +9,16 @@ use bevy::{ fn main() { App::new() - .insert_resource(WindowDescriptor { - title: "I am a window!".to_string(), - width: 500., - height: 300., - present_mode: PresentMode::AutoVsync, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + title: "I am a window!".to_string(), + width: 500., + height: 300., + present_mode: PresentMode::AutoVsync, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_plugin(LogDiagnosticsPlugin::default()) .add_plugin(FrameTimeDiagnosticsPlugin) .add_system(change_title) diff --git a/tests/window/minimising.rs b/tests/window/minimising.rs index f7198fd187904..55a28d6fde37f 100644 --- a/tests/window/minimising.rs +++ b/tests/window/minimising.rs @@ -6,11 +6,13 @@ fn main() { // TODO: Combine this with `resizing` once multiple_windows is simpler than // it is currently. App::new() - .insert_resource(WindowDescriptor { - title: "Minimising".into(), - ..Default::default() - }) - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + title: "Minimising".into(), + ..Default::default() + }, + ..default() + })) .add_system(minimise_automatically) .add_startup_system(setup_3d) .add_startup_system(setup_2d) diff --git a/tests/window/resizing.rs b/tests/window/resizing.rs index 24824e0ed0c42..446c45d0676cc 100644 --- a/tests/window/resizing.rs +++ b/tests/window/resizing.rs @@ -19,18 +19,20 @@ struct Dimensions { fn main() { App::new() - .insert_resource(WindowDescriptor { - width: MAX_WIDTH.try_into().unwrap(), - height: MAX_HEIGHT.try_into().unwrap(), - scale_factor_override: Some(1.), - title: "Resizing".into(), - ..Default::default() - }) .insert_resource(Dimensions { width: MAX_WIDTH, height: MAX_HEIGHT, }) - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + width: MAX_WIDTH.try_into().unwrap(), + height: MAX_HEIGHT.try_into().unwrap(), + scale_factor_override: Some(1.), + title: "Resizing".into(), + ..Default::default() + }, + ..default() + })) .insert_resource(Phase::ContractingY) .add_system(change_window_size) .add_system(sync_dimensions)