From 1bd7306a3ab9602007fdb7a3b049982f8a3790bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Fri, 24 Feb 2023 02:21:07 +0000 Subject: [PATCH 001/738] make bevy_text optional again (#7801) # Objective - `bevy_text` used to be "optional". the feature could be disabled, which meant that the systems were not added but `bevy_text` was still compiled because of a hard dependency in `bevy_ui` - Running something without `bevy_text` enabled and with `bevy_ui` enabled now crashes: ``` thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /bevy/crates/bevy_ecs/src/schedule/schedule.rs:1147:34 ``` - This is because `bevy_ui` declares some of its systems in ambiguity sets with systems from `bevy_text`, which were not added if `bevy_text` is disabled ## Solution - Make `bevy_text` completely optional ## Migration Guide - feature `bevy_text` now completely removes `bevy_text` from the dependencies when not enabled. Enable feature `bevy_text` if you use Bevy to render text --- crates/bevy_internal/Cargo.toml | 2 + crates/bevy_ui/Cargo.toml | 2 +- crates/bevy_ui/src/lib.rs | 85 ++++++++++++++++-------------- crates/bevy_ui/src/node_bundles.rs | 4 ++ crates/bevy_ui/src/render/mod.rs | 8 ++- crates/bevy_ui/src/widget/image.rs | 11 ++-- crates/bevy_ui/src/widget/mod.rs | 2 + 7 files changed, 68 insertions(+), 46 deletions(-) diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index be6ca626464263..0166d797f76fb5 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -82,6 +82,8 @@ dynamic_linking = ["bevy_diagnostic/dynamic_linking"] # Enable using a shared stdlib for cxx on Android. android_shared_stdcxx = ["bevy_audio/android_shared_stdcxx"] +bevy_text = ["dep:bevy_text", "bevy_ui?/bevy_text"] + [dependencies] # bevy bevy_app = { path = "../bevy_app", version = "0.9.0" } diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index f0724e65d5e971..697fee31492e01 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -24,7 +24,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.9.0", features = [ ] } bevy_render = { path = "../bevy_render", version = "0.9.0" } bevy_sprite = { path = "../bevy_sprite", version = "0.9.0" } -bevy_text = { path = "../bevy_text", version = "0.9.0" } +bevy_text = { path = "../bevy_text", version = "0.9.0", optional = true } bevy_transform = { path = "../bevy_transform", version = "0.9.0" } bevy_window = { path = "../bevy_window", version = "0.9.0" } bevy_utils = { path = "../bevy_utils", version = "0.9.0" } diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 8ea3b454108d85..4f5c0acea23b6a 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -14,7 +14,9 @@ pub mod node_bundles; pub mod update; pub mod widget; -use bevy_render::{camera::CameraUpdateSystem, extract_component::ExtractComponentPlugin}; +#[cfg(feature = "bevy_text")] +use bevy_render::camera::CameraUpdateSystem; +use bevy_render::extract_component::ExtractComponentPlugin; pub use flex::*; pub use focus::*; pub use geometry::*; @@ -103,44 +105,49 @@ impl Plugin for UiPlugin { .configure_set(UiSystem::Focus.in_base_set(CoreSet::PreUpdate)) .configure_set(UiSystem::Flex.in_base_set(CoreSet::PostUpdate)) .configure_set(UiSystem::Stack.in_base_set(CoreSet::PostUpdate)) - .add_system(ui_focus_system.in_set(UiSystem::Focus).after(InputSystem)) - // add these systems to front because these must run before transform update systems - .add_system( - widget::text_system - .in_base_set(CoreSet::PostUpdate) - .before(UiSystem::Flex) - // Potential conflict: `Assets` - // In practice, they run independently since `bevy_render::camera_update_system` - // will only ever observe its own render target, and `widget::text_system` - // will never modify a pre-existing `Image` asset. - .ambiguous_with(CameraUpdateSystem) - // Potential conflict: `Assets` - // Since both systems will only ever insert new [`Image`] assets, - // they will never observe each other's effects. - .ambiguous_with(bevy_text::update_text2d_layout), - ) - .add_system( - widget::update_image_calculated_size_system - .in_base_set(CoreSet::PostUpdate) - .before(UiSystem::Flex) - // Potential conflicts: `Assets` - // They run independently since `widget::image_node_system` will only ever observe - // its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout` - // will never modify a pre-existing `Image` asset. - .ambiguous_with(bevy_text::update_text2d_layout) - .ambiguous_with(widget::text_system), - ) - .add_system( - flex_node_system - .in_set(UiSystem::Flex) - .before(TransformSystem::TransformPropagate), - ) - .add_system(ui_stack_system.in_set(UiSystem::Stack)) - .add_system( - update_clipping_system - .after(TransformSystem::TransformPropagate) - .in_base_set(CoreSet::PostUpdate), - ); + .add_system(ui_focus_system.in_set(UiSystem::Focus).after(InputSystem)); + // add these systems to front because these must run before transform update systems + #[cfg(feature = "bevy_text")] + app.add_system( + widget::text_system + .in_base_set(CoreSet::PostUpdate) + .before(UiSystem::Flex) + // Potential conflict: `Assets` + // In practice, they run independently since `bevy_render::camera_update_system` + // will only ever observe its own render target, and `widget::text_system` + // will never modify a pre-existing `Image` asset. + .ambiguous_with(CameraUpdateSystem) + // Potential conflict: `Assets` + // Since both systems will only ever insert new [`Image`] assets, + // they will never observe each other's effects. + .ambiguous_with(bevy_text::update_text2d_layout), + ); + app.add_system({ + let system = widget::update_image_calculated_size_system + .in_base_set(CoreSet::PostUpdate) + .before(UiSystem::Flex); + // Potential conflicts: `Assets` + // They run independently since `widget::image_node_system` will only ever observe + // its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout` + // will never modify a pre-existing `Image` asset. + #[cfg(feature = "bevy_text")] + let system = system + .ambiguous_with(bevy_text::update_text2d_layout) + .ambiguous_with(widget::text_system); + + system + }) + .add_system( + flex_node_system + .in_set(UiSystem::Flex) + .before(TransformSystem::TransformPropagate), + ) + .add_system(ui_stack_system.in_set(UiSystem::Stack)) + .add_system( + update_clipping_system + .after(TransformSystem::TransformPropagate) + .in_base_set(CoreSet::PostUpdate), + ); crate::render::build_ui_render(app); } diff --git a/crates/bevy_ui/src/node_bundles.rs b/crates/bevy_ui/src/node_bundles.rs index f6a2433396344f..c5c3e3171fc42f 100644 --- a/crates/bevy_ui/src/node_bundles.rs +++ b/crates/bevy_ui/src/node_bundles.rs @@ -9,6 +9,7 @@ use bevy_render::{ prelude::{Color, ComputedVisibility}, view::Visibility, }; +#[cfg(feature = "bevy_text")] use bevy_text::{Text, TextAlignment, TextSection, TextStyle}; use bevy_transform::prelude::{GlobalTransform, Transform}; @@ -95,6 +96,7 @@ pub struct ImageBundle { pub z_index: ZIndex, } +#[cfg(feature = "bevy_text")] /// A UI node that is text #[derive(Bundle, Clone, Debug)] pub struct TextBundle { @@ -128,6 +130,7 @@ pub struct TextBundle { pub background_color: BackgroundColor, } +#[cfg(feature = "bevy_text")] impl Default for TextBundle { fn default() -> Self { Self { @@ -147,6 +150,7 @@ impl Default for TextBundle { } } +#[cfg(feature = "bevy_text")] impl TextBundle { /// Create a [`TextBundle`] from a single section. /// diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index f213118a01093f..0bc8a7ce39c868 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -3,6 +3,7 @@ mod render_pass; use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; use bevy_render::ExtractSchedule; +#[cfg(feature = "bevy_text")] use bevy_window::{PrimaryWindow, Window}; pub use pipeline::*; pub use render_pass::*; @@ -26,7 +27,10 @@ use bevy_render::{ view::{ComputedVisibility, ExtractedView, ViewUniforms}, Extract, RenderApp, RenderSet, }; -use bevy_sprite::{SpriteAssetEvents, TextureAtlas}; +use bevy_sprite::SpriteAssetEvents; +#[cfg(feature = "bevy_text")] +use bevy_sprite::TextureAtlas; +#[cfg(feature = "bevy_text")] use bevy_text::{Text, TextLayoutInfo}; use bevy_transform::components::GlobalTransform; use bevy_utils::FloatOrd; @@ -78,6 +82,7 @@ pub fn build_ui_render(app: &mut App) { extract_default_ui_camera_view::, extract_default_ui_camera_view::, extract_uinodes.in_set(RenderUiSystem::ExtractNode), + #[cfg(feature = "bevy_text")] extract_text_uinodes.after(RenderUiSystem::ExtractNode), ), ) @@ -288,6 +293,7 @@ pub fn extract_default_ui_camera_view( } } +#[cfg(feature = "bevy_text")] pub fn extract_text_uinodes( mut extracted_uinodes: ResMut, texture_atlases: Extract>>, diff --git a/crates/bevy_ui/src/widget/image.rs b/crates/bevy_ui/src/widget/image.rs index 232be96eb4047e..4b5777c841dd44 100644 --- a/crates/bevy_ui/src/widget/image.rs +++ b/crates/bevy_ui/src/widget/image.rs @@ -1,17 +1,18 @@ use crate::{CalculatedSize, UiImage}; use bevy_asset::Assets; -use bevy_ecs::{ - query::Without, - system::{Query, Res}, -}; +#[cfg(feature = "bevy_text")] +use bevy_ecs::query::Without; +use bevy_ecs::system::{Query, Res}; use bevy_math::Vec2; use bevy_render::texture::Image; +#[cfg(feature = "bevy_text")] use bevy_text::Text; /// Updates calculated size of the node based on the image provided pub fn update_image_calculated_size_system( textures: Res>, - mut query: Query<(&mut CalculatedSize, &UiImage), Without>, + #[cfg(feature = "bevy_text")] mut query: Query<(&mut CalculatedSize, &UiImage), Without>, + #[cfg(not(feature = "bevy_text"))] mut query: Query<(&mut CalculatedSize, &UiImage)>, ) { for (mut calculated_size, image) in &mut query { if let Some(texture) = textures.get(&image.texture) { diff --git a/crates/bevy_ui/src/widget/mod.rs b/crates/bevy_ui/src/widget/mod.rs index 12ed55620eb32a..e5c26ae689d4e0 100644 --- a/crates/bevy_ui/src/widget/mod.rs +++ b/crates/bevy_ui/src/widget/mod.rs @@ -2,8 +2,10 @@ mod button; mod image; +#[cfg(feature = "bevy_text")] mod text; pub use button::*; pub use image::*; +#[cfg(feature = "bevy_text")] pub use text::*; From e4fd25a95286f26b1dc5a2572f4669cc05ed0883 Mon Sep 17 00:00:00 2001 From: Edgar Geier Date: Fri, 24 Feb 2023 02:44:28 +0000 Subject: [PATCH 002/738] Only execute `#define` if current scope is accepting lines (#7798) # Objective While working on #7784, I noticed that a `#define VAR` in a `.wgsl` file is always effective, even if it its scope is not accepting lines. Example: ```c #define A #ifndef A #define B #endif ``` Currently, `B` will be defined although it shouldn't. This PR fixes that. ## Solution Move the branch responsible for `#define` lines into the last else branch, which is only evaluated if the current scope is accepting lines. --- .../bevy_render/src/render_resource/shader.rs | 68 +++++++++++++------ 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/crates/bevy_render/src/render_resource/shader.rs b/crates/bevy_render/src/render_resource/shader.rs index 8ba7bf6c5bb311..c45c687e90eee9 100644 --- a/crates/bevy_render/src/render_resource/shader.rs +++ b/crates/bevy_render/src/render_resource/shader.rs @@ -561,26 +561,6 @@ impl ShaderProcessor { let current_valid = scopes.last().unwrap().is_accepting_lines(); scopes.push(Scope::new(current_valid && new_scope)); - } else if let Some(cap) = self.define_regex.captures(line) { - let def = cap.get(1).unwrap(); - let name = def.as_str().to_string(); - - if let Some(val) = cap.get(2) { - if let Ok(val) = val.as_str().parse::() { - shader_defs_unique.insert(name.clone(), ShaderDefVal::UInt(name, val)); - } else if let Ok(val) = val.as_str().parse::() { - shader_defs_unique.insert(name.clone(), ShaderDefVal::Int(name, val)); - } else if let Ok(val) = val.as_str().parse::() { - shader_defs_unique.insert(name.clone(), ShaderDefVal::Bool(name, val)); - } else { - return Err(ProcessShaderError::InvalidShaderDefDefinitionValue { - shader_def_name: name, - value: val.as_str().to_string(), - }); - } - } else { - shader_defs_unique.insert(name.clone(), ShaderDefVal::Bool(name, true)); - } } else if let Some(cap) = self.else_ifdef_regex.captures(line) { // When should we accept the code in an // @@ -685,6 +665,26 @@ impl ShaderProcessor { .is_match(line) { // ignore import path lines + } else if let Some(cap) = self.define_regex.captures(line) { + let def = cap.get(1).unwrap(); + let name = def.as_str().to_string(); + + if let Some(val) = cap.get(2) { + if let Ok(val) = val.as_str().parse::() { + shader_defs_unique.insert(name.clone(), ShaderDefVal::UInt(name, val)); + } else if let Ok(val) = val.as_str().parse::() { + shader_defs_unique.insert(name.clone(), ShaderDefVal::Int(name, val)); + } else if let Ok(val) = val.as_str().parse::() { + shader_defs_unique.insert(name.clone(), ShaderDefVal::Bool(name, val)); + } else { + return Err(ProcessShaderError::InvalidShaderDefDefinitionValue { + shader_def_name: name, + value: val.as_str().to_string(), + }); + } + } else { + shader_defs_unique.insert(name.clone(), ShaderDefVal::Bool(name, true)); + } } else { let mut line_with_defs = line.to_string(); for capture in self.def_regex.captures_iter(line) { @@ -2508,6 +2508,34 @@ defined at end assert_eq!(result.get_wgsl_source().unwrap(), EXPECTED); } + #[test] + fn process_shader_define_only_in_accepting_scopes() { + #[rustfmt::skip] + const WGSL: &str = r" +#define GUARD +#ifndef GUARD +#define GUARDED +#endif +#ifdef GUARDED +This should not be part of the result +#endif +"; + + #[rustfmt::skip] + const EXPECTED: &str = r" +"; + let processor = ShaderProcessor::default(); + let result = processor + .process( + &Shader::from_wgsl(WGSL), + &[], + &HashMap::default(), + &HashMap::default(), + ) + .unwrap(); + assert_eq!(result.get_wgsl_source().unwrap(), EXPECTED); + } + #[test] fn process_shader_define_in_shader_with_value() { #[rustfmt::skip] From e27e04a4a717048d16089170cb96d208559e0355 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 24 Feb 2023 10:49:14 +0000 Subject: [PATCH 003/738] Remove a duplicate lookup in `apply_state_transitions` (#7800) # Objective Remove a duplicate resource lookup and an unnecessary panic. --- crates/bevy_ecs/src/schedule/state.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/state.rs b/crates/bevy_ecs/src/schedule/state.rs index 0982441ac1e7fb..92f7c3864ce859 100644 --- a/crates/bevy_ecs/src/schedule/state.rs +++ b/crates/bevy_ecs/src/schedule/state.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use std::mem; use crate as bevy_ecs; +use crate::change_detection::DetectChangesMut; use crate::schedule::{ScheduleLabel, SystemSet}; use crate::system::Resource; use crate::world::World; @@ -97,13 +98,14 @@ pub fn run_enter_schedule(world: &mut World) { /// - Runs the [`OnExit(exited_state)`] schedule. /// - Runs the [`OnEnter(entered_state)`] schedule. pub fn apply_state_transition(world: &mut World) { - if world.resource::>().0.is_some() { - let entered_state = world.resource_mut::>().0.take().unwrap(); - let exited_state = mem::replace( - &mut world.resource_mut::>().0, - entered_state.clone(), - ); - world.run_schedule(OnExit(exited_state)); - world.run_schedule(OnEnter(entered_state)); + // We want to take the `NextState` resource, + // but only mark it as changed if it wasn't empty. + let mut next_state_resource = world.resource_mut::>(); + if let Some(entered) = next_state_resource.bypass_change_detection().0.take() { + next_state_resource.set_changed(); + + let exited = mem::replace(&mut world.resource_mut::>().0, entered.clone()); + world.run_schedule(OnExit(exited)); + world.run_schedule(OnEnter(entered)); } } From d1a1f90902ad98115d6f19105bd8382a214377a2 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Fri, 24 Feb 2023 12:55:43 +0000 Subject: [PATCH 004/738] fix `Time::pause` docs (missing "not") (#7807) # Objective Time pausing does *not* affect `raw_*`. ## Solution - add missing word "not" --- crates/bevy_time/src/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_time/src/time.rs b/crates/bevy_time/src/time.rs index 730cf712cd99ea..29d1801c4b31d1 100644 --- a/crates/bevy_time/src/time.rs +++ b/crates/bevy_time/src/time.rs @@ -405,7 +405,7 @@ impl Time { /// Stops the clock, preventing it from advancing until resumed. /// - /// **Note:** This does affect the `raw_*` measurements. + /// **Note:** This does not affect the `raw_*` measurements. #[inline] pub fn pause(&mut self) { self.paused = true; From 40e90b51b551fdaae291be53d4654cedd156e01d Mon Sep 17 00:00:00 2001 From: ira Date: Fri, 24 Feb 2023 16:59:19 +0000 Subject: [PATCH 005/738] Avoid using `SystemTypeSet` for transform systems ambiguity (#7808) Alternative to #7804 Allows other instances of the `sync_simple_transforms` and `propagate_transforms` systems to be added. Co-authored-by: devil-ira --- crates/bevy_transform/src/lib.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 34a21276f4bbd0..4ebbc43f0cdfa5 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -90,6 +90,11 @@ pub struct TransformPlugin; impl Plugin for TransformPlugin { fn build(&self, app: &mut App) { + // A set for `propagate_transforms` to mark it as ambiguous with `sync_simple_transforms`. + // Used instead of the `SystemTypeSet` as that would not allow multiple instances of the system. + #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] + struct PropagateTransformsSet; + app.register_type::() .register_type::() .add_plugin(ValidParentCheckPlugin::::default()) @@ -106,14 +111,22 @@ impl Plugin for TransformPlugin { .add_startup_system( sync_simple_transforms .in_set(TransformSystem::TransformPropagate) - .ambiguous_with(propagate_transforms), + .ambiguous_with(PropagateTransformsSet), + ) + .add_startup_system( + propagate_transforms + .in_set(TransformSystem::TransformPropagate) + .in_set(PropagateTransformsSet), ) - .add_startup_system(propagate_transforms.in_set(TransformSystem::TransformPropagate)) .add_system( sync_simple_transforms .in_set(TransformSystem::TransformPropagate) - .ambiguous_with(propagate_transforms), + .ambiguous_with(PropagateTransformsSet), ) - .add_system(propagate_transforms.in_set(TransformSystem::TransformPropagate)); + .add_system( + propagate_transforms + .in_set(TransformSystem::TransformPropagate) + .in_set(PropagateTransformsSet), + ); } } From b8263b55fb29526f99b8644b84dff421877bad59 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 24 Feb 2023 18:33:55 +0000 Subject: [PATCH 006/738] Support `system.in_schedule()` and `system.on_startup()` (#7790) # Objective Support the following syntax for adding systems: ```rust App::new() .add_system(setup.on_startup()) .add_systems(( show_menu.in_schedule(OnEnter(GameState::Paused)), menu_ssytem.in_set(OnUpdate(GameState::Paused)), hide_menu.in_schedule(OnExit(GameState::Paused)), )) ``` ## Solution Add the traits `IntoSystemAppConfig{s}`, which provide the extension methods necessary for configuring which schedule a system belongs to. These extension methods return `IntoSystemAppConfig{s}`, which `App::add_system{s}` uses to choose which schedule to add systems to. --- ## Changelog + Added the extension methods `in_schedule(label)` and `on_startup()` for configuring the schedule a system belongs to. ## Future Work * Replace all uses of `add_startup_system` in the engine. * Deprecate this method --- crates/bevy_app/src/app.rs | 81 +++--- crates/bevy_app/src/config.rs | 291 +++++++++++++++++++ crates/bevy_app/src/lib.rs | 6 +- crates/bevy_core_pipeline/src/core_2d/mod.rs | 4 +- crates/bevy_core_pipeline/src/core_3d/mod.rs | 4 +- crates/bevy_ecs/src/schedule/config.rs | 55 +--- crates/bevy_pbr/src/lib.rs | 6 +- crates/bevy_pbr/src/material.rs | 4 +- crates/bevy_pbr/src/prepass/mod.rs | 4 +- crates/bevy_pbr/src/render/mesh.rs | 4 +- crates/bevy_render/src/camera/mod.rs | 4 +- crates/bevy_render/src/extract_component.rs | 6 +- crates/bevy_render/src/extract_resource.rs | 4 +- crates/bevy_render/src/globals.rs | 4 +- crates/bevy_render/src/render_asset.rs | 4 +- crates/bevy_render/src/view/window.rs | 4 +- crates/bevy_sprite/src/lib.rs | 6 +- crates/bevy_sprite/src/mesh2d/material.rs | 4 +- crates/bevy_sprite/src/mesh2d/mesh.rs | 4 +- crates/bevy_text/src/lib.rs | 7 +- crates/bevy_ui/src/render/mod.rs | 6 +- examples/2d/mesh2d_manual.rs | 2 +- examples/2d/rotation.rs | 6 +- examples/2d/texture_atlas.rs | 4 +- examples/ecs/fixed_timestep.rs | 2 +- examples/ecs/generic_system.rs | 11 +- examples/ecs/iter_combinations.rs | 2 +- examples/ecs/state.rs | 8 +- examples/games/alien_cake_addict.rs | 16 +- examples/games/breakout.rs | 6 +- examples/games/game_menu.rs | 62 ++-- examples/stress_tests/bevymark.rs | 2 +- 32 files changed, 444 insertions(+), 189 deletions(-) create mode 100644 crates/bevy_app/src/config.rs diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index de317e634a856c..f7f90c5e5a7ee1 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1,4 +1,7 @@ -use crate::{CoreSchedule, CoreSet, Plugin, PluginGroup, StartupSet}; +use crate::{ + CoreSchedule, CoreSet, IntoSystemAppConfig, IntoSystemAppConfigs, Plugin, PluginGroup, + StartupSet, SystemAppConfig, +}; pub use bevy_derive::AppLabel; use bevy_ecs::{ prelude::*, @@ -378,10 +381,18 @@ impl App { /// # /// app.add_system(my_system); /// ``` - pub fn add_system(&mut self, system: impl IntoSystemConfig) -> &mut Self { + pub fn add_system(&mut self, system: impl IntoSystemAppConfig) -> &mut Self { let mut schedules = self.world.resource_mut::(); - if let Some(default_schedule) = schedules.get_mut(&*self.default_schedule_label) { + let SystemAppConfig { system, schedule } = system.into_app_config(); + + if let Some(schedule_label) = schedule { + if let Some(schedule) = schedules.get_mut(&*schedule_label) { + schedule.add_system(system); + } else { + panic!("Schedule {schedule_label:?} does not exist.") + } + } else if let Some(default_schedule) = schedules.get_mut(&*self.default_schedule_label) { default_schedule.add_system(system); } else { let schedule_label = &self.default_schedule_label; @@ -406,48 +417,28 @@ impl App { /// # /// app.add_systems((system_a, system_b, system_c)); /// ``` - pub fn add_systems(&mut self, systems: impl IntoSystemConfigs) -> &mut Self { - let mut schedules = self.world.resource_mut::(); - - if let Some(default_schedule) = schedules.get_mut(&*self.default_schedule_label) { - default_schedule.add_systems(systems); - } else { - let schedule_label = &self.default_schedule_label; - panic!("Default schedule {schedule_label:?} does not exist.") - } - - self - } - - /// Adds a system to the provided [`Schedule`]. - pub fn add_system_to_schedule( - &mut self, - schedule_label: impl ScheduleLabel, - system: impl IntoSystemConfig, - ) -> &mut Self { - let mut schedules = self.world.resource_mut::(); - - if let Some(schedule) = schedules.get_mut(&schedule_label) { - schedule.add_system(system); - } else { - panic!("Provided schedule {schedule_label:?} does not exist.") - } - - self - } - - /// Adds a collection of system to the provided [`Schedule`]. - pub fn add_systems_to_schedule( - &mut self, - schedule_label: impl ScheduleLabel, - systems: impl IntoSystemConfigs, - ) -> &mut Self { + pub fn add_systems(&mut self, systems: impl IntoSystemAppConfigs) -> &mut Self { let mut schedules = self.world.resource_mut::(); - if let Some(schedule) = schedules.get_mut(&schedule_label) { - schedule.add_systems(systems); - } else { - panic!("Provided schedule {schedule_label:?} does not exist.") + match systems.into_app_configs().0 { + crate::InnerConfigs::Blanket { systems, schedule } => { + let schedule = if let Some(label) = schedule { + schedules + .get_mut(&*label) + .unwrap_or_else(|| panic!("Schedule '{label:?}' does not exist.")) + } else { + let label = &*self.default_schedule_label; + schedules + .get_mut(label) + .unwrap_or_else(|| panic!("Default schedule '{label:?}' does not exist.")) + }; + schedule.add_systems(systems); + } + crate::InnerConfigs::Granular(systems) => { + for system in systems { + self.add_system(system); + } + } } self @@ -472,7 +463,7 @@ impl App { /// .add_startup_system(my_startup_system); /// ``` pub fn add_startup_system(&mut self, system: impl IntoSystemConfig) -> &mut Self { - self.add_system_to_schedule(CoreSchedule::Startup, system) + self.add_system(system.in_schedule(CoreSchedule::Startup)) } /// Adds a collection of systems to [`CoreSchedule::Startup`]. @@ -497,7 +488,7 @@ impl App { /// ); /// ``` pub fn add_startup_systems(&mut self, systems: impl IntoSystemConfigs) -> &mut Self { - self.add_systems_to_schedule(CoreSchedule::Startup, systems) + self.add_systems(systems.into_configs().in_schedule(CoreSchedule::Startup)) } /// Configures a system set in the default schedule, adding the set if it does not exist. diff --git a/crates/bevy_app/src/config.rs b/crates/bevy_app/src/config.rs new file mode 100644 index 00000000000000..81d35f85744459 --- /dev/null +++ b/crates/bevy_app/src/config.rs @@ -0,0 +1,291 @@ +use bevy_ecs::{ + all_tuples, + schedule::{ + BoxedScheduleLabel, Condition, IntoSystemConfig, IntoSystemSet, ScheduleLabel, + SystemConfig, SystemConfigs, SystemSet, + }, +}; + +use crate::CoreSchedule; + +/// A [`System`] with [`App`]-aware scheduling metadata. +/// +/// [`System`]: bevy_ecs::prelude::System +/// [`App`]: crate::App +pub struct SystemAppConfig { + pub(crate) system: SystemConfig, + pub(crate) schedule: Option, +} + +/// Types that can be converted into a [`SystemAppConfig`]. +/// +/// This has been implemented for all `System` trait objects +/// and all functions that convert into such. +pub trait IntoSystemAppConfig: Sized { + /// Converts into a [`SystemAppConfig`]. + fn into_app_config(self) -> SystemAppConfig; + + /// Adds the system to the provided `schedule`. + /// + /// If a schedule is not specified, it will be added to the [`App`]'s default schedule. + /// + /// [`App`]: crate::App + /// + /// # Panics + /// + /// If the system has already been assigned to a schedule. + #[track_caller] + fn in_schedule(self, schedule: impl ScheduleLabel) -> SystemAppConfig { + let mut config = self.into_app_config(); + if let Some(old_schedule) = &config.schedule { + panic!( + "Cannot add system to schedule '{schedule:?}': it is already in '{old_schedule:?}'." + ); + } + config.schedule = Some(Box::new(schedule)); + + config + } + + /// Adds the system to [`CoreSchedule::Startup`]. + /// This is a shorthand for `self.in_schedule(CoreSchedule::Startup)`. + /// + /// Systems in this schedule will run exactly once, at the start of the [`App`]'s lifecycle. + /// + /// [`App`]: crate::App + /// + /// # Examples + /// + /// ``` + /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; + /// # + /// fn my_startup_system(_commands: Commands) { + /// println!("My startup system"); + /// } + /// + /// App::new() + /// .add_system(my_startup_system.on_startup()) + /// .run(); + /// ``` + /// + /// # Panics + /// + /// If the system has already been assigned to a schedule. + #[inline] + fn on_startup(self) -> SystemAppConfig { + self.in_schedule(CoreSchedule::Startup) + } +} + +impl IntoSystemConfig<(), Self> for SystemAppConfig { + fn into_config(self) -> Self { + self + } + + #[track_caller] + fn in_set(self, set: impl SystemSet) -> Self { + let Self { system, schedule } = self; + Self { + system: system.in_set(set), + schedule, + } + } + + #[track_caller] + fn in_base_set(self, set: impl SystemSet) -> Self { + let Self { system, schedule } = self; + Self { + system: system.in_base_set(set), + schedule, + } + } + + fn no_default_base_set(self) -> Self { + let Self { system, schedule } = self; + Self { + system: system.no_default_base_set(), + schedule, + } + } + + fn before(self, set: impl IntoSystemSet) -> Self { + let Self { system, schedule } = self; + Self { + system: system.before(set), + schedule, + } + } + + fn after(self, set: impl IntoSystemSet) -> Self { + let Self { system, schedule } = self; + Self { + system: system.after(set), + schedule, + } + } + + fn run_if

(self, condition: impl Condition

) -> Self { + let Self { system, schedule } = self; + Self { + system: system.run_if(condition), + schedule, + } + } + + fn ambiguous_with(self, set: impl IntoSystemSet) -> Self { + let Self { system, schedule } = self; + Self { + system: system.ambiguous_with(set), + schedule, + } + } + + fn ambiguous_with_all(self) -> Self { + let Self { system, schedule } = self; + Self { + system: system.ambiguous_with_all(), + schedule, + } + } +} + +impl IntoSystemAppConfig<()> for SystemAppConfig { + fn into_app_config(self) -> SystemAppConfig { + self + } +} + +impl IntoSystemAppConfig for T +where + T: IntoSystemConfig, +{ + fn into_app_config(self) -> SystemAppConfig { + SystemAppConfig { + system: self.into_config(), + schedule: None, + } + } +} + +/// A collection of [`SystemAppConfig`]s. +pub struct SystemAppConfigs(pub(crate) InnerConfigs); + +pub(crate) enum InnerConfigs { + /// This came from an instance of `SystemConfigs`. + /// All systems are in the same schedule. + Blanket { + systems: SystemConfigs, + schedule: Option, + }, + /// This came from several separate instances of `SystemAppConfig`. + /// Each system gets its own schedule. + Granular(Vec), +} + +/// Types that can convert into [`SystemAppConfigs`]. +pub trait IntoSystemAppConfigs: Sized { + /// Converts to [`SystemAppConfigs`]. + fn into_app_configs(self) -> SystemAppConfigs; + + /// Adds the systems to the provided `schedule`. + /// + /// If a schedule is not specified, they will be added to the [`App`]'s default schedule. + /// + /// [`App`]: crate::App + /// + /// # Panics + /// + /// If any of the systems have already been assigned to a schedule. + #[track_caller] + fn in_schedule(self, label: impl ScheduleLabel) -> SystemAppConfigs { + let mut configs = self.into_app_configs(); + + match &mut configs.0 { + InnerConfigs::Blanket { schedule, .. } => { + if schedule.is_some() { + panic!( + "Cannot add systems to the schedule '{label:?}: they are already in '{schedule:?}'" + ); + } + *schedule = Some(Box::new(label)); + } + InnerConfigs::Granular(configs) => { + for SystemAppConfig { schedule, .. } in configs { + if schedule.is_some() { + panic!( + "Cannot add system to the schedule '{label:?}': it is already in '{schedule:?}'." + ); + } + *schedule = Some(label.dyn_clone()); + } + } + } + + configs + } + + /// Adds the systems to [`CoreSchedule::Startup`]. + /// This is a shorthand for `self.in_schedule(CoreSchedule::Startup)`. + /// + /// # Examples + /// + /// ``` + /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; + /// # + /// # let mut app = App::new(); + /// # fn startup_system_a() {} + /// # fn startup_system_b() {} + /// # fn startup_system_c() {} + /// # + /// app.add_systems( + /// ( + /// startup_system_a, + /// startup_system_b, + /// startup_system_c, + /// ) + /// .on_startup() + /// ); + /// ``` + /// + /// # Panics + /// + /// If any of the systems have already been assigned to a schedule. + #[track_caller] + fn on_startup(self) -> SystemAppConfigs { + self.in_schedule(CoreSchedule::Startup) + } +} + +impl IntoSystemAppConfigs<()> for SystemAppConfigs { + fn into_app_configs(self) -> SystemAppConfigs { + self + } +} + +impl IntoSystemAppConfigs<()> for SystemConfigs { + fn into_app_configs(self) -> SystemAppConfigs { + SystemAppConfigs(InnerConfigs::Blanket { + systems: self, + schedule: None, + }) + } +} + +macro_rules! impl_system_collection { + ($(($param: ident, $sys: ident)),*) => { + impl<$($param, $sys),*> IntoSystemAppConfigs<($($param,)*)> for ($($sys,)*) + where + $($sys: IntoSystemAppConfig<$param>),* + { + #[allow(non_snake_case)] + fn into_app_configs(self) -> SystemAppConfigs { + let ($($sys,)*) = self; + SystemAppConfigs(InnerConfigs::Granular(vec![$($sys.into_app_config(),)*])) + } + } + } +} + +all_tuples!(impl_system_collection, 0, 15, P, S); diff --git a/crates/bevy_app/src/lib.rs b/crates/bevy_app/src/lib.rs index f03856aa18e45e..8348a7c16e15e1 100644 --- a/crates/bevy_app/src/lib.rs +++ b/crates/bevy_app/src/lib.rs @@ -3,6 +3,7 @@ #![warn(missing_docs)] mod app; +mod config; mod plugin; mod plugin_group; mod schedule_runner; @@ -12,6 +13,7 @@ mod ci_testing; pub use app::*; pub use bevy_derive::DynamicPlugin; +pub use config::*; pub use plugin::*; pub use plugin_group::*; pub use schedule_runner::*; @@ -23,7 +25,9 @@ pub mod prelude { pub use crate::AppTypeRegistry; #[doc(hidden)] pub use crate::{ - app::App, CoreSchedule, CoreSet, DynamicPlugin, Plugin, PluginGroup, StartupSet, + app::App, + config::{IntoSystemAppConfig, IntoSystemAppConfigs}, + CoreSchedule, CoreSet, DynamicPlugin, Plugin, PluginGroup, StartupSet, }; } diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index f02c78cf6d0f6a..233671a159ab0b 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -19,7 +19,7 @@ pub mod graph { pub use camera_2d::*; pub use main_pass_2d_node::*; -use bevy_app::{App, Plugin}; +use bevy_app::{App, IntoSystemAppConfig, Plugin}; use bevy_ecs::prelude::*; use bevy_render::{ camera::Camera, @@ -51,7 +51,7 @@ impl Plugin for Core2dPlugin { render_app .init_resource::>() - .add_system_to_schedule(ExtractSchedule, extract_core_2d_camera_phases) + .add_system(extract_core_2d_camera_phases.in_schedule(ExtractSchedule)) .add_system(sort_phase_system::.in_set(RenderSet::PhaseSort)) .add_system( batch_phase_system:: diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index 98042adcee5ee9..ab3f68df209043 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -22,7 +22,7 @@ use std::cmp::Reverse; pub use camera_3d::*; pub use main_pass_3d_node::*; -use bevy_app::{App, Plugin}; +use bevy_app::{App, IntoSystemAppConfig, Plugin}; use bevy_ecs::prelude::*; use bevy_render::{ camera::{Camera, ExtractedCamera}, @@ -67,7 +67,7 @@ impl Plugin for Core3dPlugin { .init_resource::>() .init_resource::>() .init_resource::>() - .add_system_to_schedule(ExtractSchedule, extract_core_3d_camera_phases) + .add_system(extract_core_3d_camera_phases.in_schedule(ExtractSchedule)) .add_system( prepare_core_3d_depth_textures .in_set(RenderSet::Prepare) diff --git a/crates/bevy_ecs/src/schedule/config.rs b/crates/bevy_ecs/src/schedule/config.rs index 54f68a8167e05d..7c0524a0944329 100644 --- a/crates/bevy_ecs/src/schedule/config.rs +++ b/crates/bevy_ecs/src/schedule/config.rs @@ -80,7 +80,7 @@ fn ambiguous_with(graph_info: &mut GraphInfo, set: BoxedSystemSet) { /// Types that can be converted into a [`SystemSetConfig`]. /// /// This has been implemented for all types that implement [`SystemSet`] and boxed trait objects. -pub trait IntoSystemSetConfig: sealed::IntoSystemSetConfig { +pub trait IntoSystemSetConfig { /// Convert into a [`SystemSetConfig`]. #[doc(hidden)] fn into_config(self) -> SystemSetConfig; @@ -109,10 +109,7 @@ pub trait IntoSystemSetConfig: sealed::IntoSystemSetConfig { fn ambiguous_with_all(self) -> SystemSetConfig; } -impl IntoSystemSetConfig for S -where - S: SystemSet + sealed::IntoSystemSetConfig, -{ +impl IntoSystemSetConfig for S { fn into_config(self) -> SystemSetConfig { SystemSetConfig::new(Box::new(self)) } @@ -274,38 +271,38 @@ impl IntoSystemSetConfig for SystemSetConfig { /// /// This has been implemented for boxed [`System`](crate::system::System) /// trait objects and all functions that turn into such. -pub trait IntoSystemConfig: sealed::IntoSystemConfig { +pub trait IntoSystemConfig { /// Convert into a [`SystemConfig`]. #[doc(hidden)] - fn into_config(self) -> SystemConfig; + fn into_config(self) -> Config; /// Add to `set` membership. #[track_caller] - fn in_set(self, set: impl SystemSet) -> SystemConfig; + fn in_set(self, set: impl SystemSet) -> Config; /// Add to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`]. #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> SystemConfig; + fn in_base_set(self, set: impl SystemSet) -> Config; /// Don't add this system to the schedules's default set. - fn no_default_base_set(self) -> SystemConfig; + fn no_default_base_set(self) -> Config; /// Run before all systems in `set`. - fn before(self, set: impl IntoSystemSet) -> SystemConfig; + fn before(self, set: impl IntoSystemSet) -> Config; /// Run after all systems in `set`. - fn after(self, set: impl IntoSystemSet) -> SystemConfig; + fn after(self, set: impl IntoSystemSet) -> Config; /// Run only if the [`Condition`] is `true`. /// /// The `Condition` will be evaluated at most once (per schedule run), /// when the system prepares to run. - fn run_if(self, condition: impl Condition) -> SystemConfig; + fn run_if(self, condition: impl Condition) -> Config; /// Suppress warnings and errors that would result from this system having ambiguities /// (conflicting access but indeterminate order) with systems in `set`. - fn ambiguous_with(self, set: impl IntoSystemSet) -> SystemConfig; + fn ambiguous_with(self, set: impl IntoSystemSet) -> Config; /// Suppress warnings and errors that would result from this system having ambiguities /// (conflicting access but indeterminate order) with any other system. - fn ambiguous_with_all(self) -> SystemConfig; + fn ambiguous_with_all(self) -> Config; } impl IntoSystemConfig for F where - F: IntoSystem<(), (), Marker> + sealed::IntoSystemConfig, + F: IntoSystem<(), (), Marker>, { fn into_config(self) -> SystemConfig { SystemConfig::new(Box::new(IntoSystem::into_system(self))) @@ -456,32 +453,6 @@ impl IntoSystemConfig<()> for SystemConfig { } } -// only `System` system objects can be scheduled -mod sealed { - use crate::{ - schedule::{BoxedSystemSet, SystemSet}, - system::{BoxedSystem, IntoSystem}, - }; - - use super::{SystemConfig, SystemSetConfig}; - - pub trait IntoSystemConfig {} - - impl> IntoSystemConfig for F {} - - impl IntoSystemConfig<()> for BoxedSystem<(), ()> {} - - impl IntoSystemConfig<()> for SystemConfig {} - - pub trait IntoSystemSetConfig {} - - impl IntoSystemSetConfig for S {} - - impl IntoSystemSetConfig for BoxedSystemSet {} - - impl IntoSystemSetConfig for SystemSetConfig {} -} - /// A collection of [`SystemConfig`]. pub struct SystemConfigs { pub(super) systems: Vec, diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 7635dc1b8ff734..884b08a423ac75 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -268,12 +268,12 @@ impl Plugin for PbrPlugin { .configure_set(RenderLightSystems::PrepareLights.in_set(RenderSet::Prepare)) .configure_set(RenderLightSystems::PrepareClusters.in_set(RenderSet::Prepare)) .configure_set(RenderLightSystems::QueueShadows.in_set(RenderSet::Queue)) - .add_systems_to_schedule( - ExtractSchedule, + .add_systems( ( render::extract_clusters.in_set(RenderLightSystems::ExtractClusters), render::extract_lights.in_set(RenderLightSystems::ExtractLights), - ), + ) + .in_schedule(ExtractSchedule), ) .add_system( render::prepare_lights diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 410b702c4933e4..7ab25bdd9d553a 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -2,7 +2,7 @@ use crate::{ AlphaMode, DrawMesh, EnvironmentMapLight, MeshPipeline, MeshPipelineKey, MeshUniform, PrepassPlugin, SetMeshBindGroup, SetMeshViewBindGroup, }; -use bevy_app::{App, Plugin}; +use bevy_app::{App, IntoSystemAppConfig, Plugin}; use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}; use bevy_core_pipeline::{ core_3d::{AlphaMask3d, Opaque3d, Transparent3d}, @@ -195,7 +195,7 @@ where .init_resource::>() .init_resource::>() .init_resource::>>() - .add_system_to_schedule(ExtractSchedule, extract_materials::) + .add_system(extract_materials::.in_schedule(ExtractSchedule)) .add_system( prepare_materials:: .in_set(RenderSet::Prepare) diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index f4f75f7a04b996..9f63d7b9ff4ea4 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -1,4 +1,4 @@ -use bevy_app::Plugin; +use bevy_app::{IntoSystemAppConfig, Plugin}; use bevy_asset::{load_internal_asset, AssetServer, Handle, HandleUntyped}; use bevy_core_pipeline::{ prelude::Camera3d, @@ -97,7 +97,7 @@ where }; render_app - .add_system_to_schedule(ExtractSchedule, extract_camera_prepass_phase) + .add_system(extract_camera_prepass_phase.in_schedule(ExtractSchedule)) .add_system( prepare_prepass_textures .in_set(RenderSet::Prepare) diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 0b4f5463eb758b..477e29795014ad 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -5,7 +5,7 @@ use crate::{ ViewShadowBindings, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS, }; -use bevy_app::Plugin; +use bevy_app::{IntoSystemAppConfigs, Plugin}; use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped}; use bevy_core_pipeline::{ prepass::ViewPrepassTextures, @@ -108,7 +108,7 @@ impl Plugin for MeshRenderPlugin { render_app .init_resource::() .init_resource::() - .add_systems_to_schedule(ExtractSchedule, (extract_meshes, extract_skinned_meshes)) + .add_systems((extract_meshes, extract_skinned_meshes).in_schedule(ExtractSchedule)) .add_system(prepare_skinned_meshes.in_set(RenderSet::Prepare)) .add_system(queue_mesh_bind_group.in_set(RenderSet::Queue)) .add_system( diff --git a/crates/bevy_render/src/camera/mod.rs b/crates/bevy_render/src/camera/mod.rs index cdd26a36c638ad..e1639a348f9917 100644 --- a/crates/bevy_render/src/camera/mod.rs +++ b/crates/bevy_render/src/camera/mod.rs @@ -8,7 +8,7 @@ pub use camera_driver_node::*; pub use projection::*; use crate::{render_graph::RenderGraph, ExtractSchedule, RenderApp}; -use bevy_app::{App, Plugin}; +use bevy_app::{App, IntoSystemAppConfig, Plugin}; #[derive(Default)] pub struct CameraPlugin; @@ -26,7 +26,7 @@ impl Plugin for CameraPlugin { .add_plugin(CameraProjectionPlugin::::default()); if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { - render_app.add_system_to_schedule(ExtractSchedule, extract_cameras); + render_app.add_system(extract_cameras.in_schedule(ExtractSchedule)); let camera_driver_node = CameraDriverNode::new(&mut render_app.world); let mut render_graph = render_app.world.resource_mut::(); render_graph.add_node(crate::main_graph::node::CAMERA_DRIVER, camera_driver_node); diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index 6f6241a59ebcbb..2b70a897a16fc0 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -4,7 +4,7 @@ use crate::{ view::ComputedVisibility, Extract, ExtractSchedule, RenderApp, RenderSet, }; -use bevy_app::{App, Plugin}; +use bevy_app::{App, IntoSystemAppConfig, Plugin}; use bevy_asset::{Asset, Handle}; use bevy_ecs::{ component::Component, @@ -180,9 +180,9 @@ impl Plugin for ExtractComponentPlugin { fn build(&self, app: &mut App) { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { if self.only_extract_visible { - render_app.add_system_to_schedule(ExtractSchedule, extract_visible_components::); + render_app.add_system(extract_visible_components::.in_schedule(ExtractSchedule)); } else { - render_app.add_system_to_schedule(ExtractSchedule, extract_components::); + render_app.add_system(extract_components::.in_schedule(ExtractSchedule)); } } } diff --git a/crates/bevy_render/src/extract_resource.rs b/crates/bevy_render/src/extract_resource.rs index 65b3d954fbb15c..a1e8b122f0857b 100644 --- a/crates/bevy_render/src/extract_resource.rs +++ b/crates/bevy_render/src/extract_resource.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use bevy_app::{App, Plugin}; +use bevy_app::{App, IntoSystemAppConfig, Plugin}; use bevy_ecs::prelude::*; pub use bevy_render_macros::ExtractResource; @@ -32,7 +32,7 @@ impl Default for ExtractResourcePlugin { impl Plugin for ExtractResourcePlugin { fn build(&self, app: &mut App) { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { - render_app.add_system_to_schedule(ExtractSchedule, extract_resource::); + render_app.add_system(extract_resource::.in_schedule(ExtractSchedule)); } } } diff --git a/crates/bevy_render/src/globals.rs b/crates/bevy_render/src/globals.rs index 474defa802e1b2..6b9fbdbc7f3d29 100644 --- a/crates/bevy_render/src/globals.rs +++ b/crates/bevy_render/src/globals.rs @@ -5,7 +5,7 @@ use crate::{ renderer::{RenderDevice, RenderQueue}, Extract, ExtractSchedule, RenderApp, RenderSet, }; -use bevy_app::{App, Plugin}; +use bevy_app::{App, IntoSystemAppConfigs, Plugin}; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_core::FrameCount; use bevy_ecs::prelude::*; @@ -26,7 +26,7 @@ impl Plugin for GlobalsPlugin { render_app .init_resource::() .init_resource::