From 0e55a0a2bc9a7be3bfec34d5ee7018551b7fb424 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 12 Mar 2023 21:05:38 -0700 Subject: [PATCH 01/38] Update is a Schedule, add_systems_to, remove base sets --- crates/bevy_animation/src/lib.rs | 9 +- crates/bevy_app/src/app.rs | 232 +++++++------ crates/bevy_app/src/config.rs | 294 ----------------- crates/bevy_app/src/lib.rs | 305 ++++++++---------- crates/bevy_asset/src/assets.rs | 12 +- crates/bevy_asset/src/lib.rs | 54 ++-- crates/bevy_audio/src/lib.rs | 5 +- crates/bevy_core/src/lib.rs | 4 +- crates/bevy_core_pipeline/src/core_2d/mod.rs | 19 +- crates/bevy_core_pipeline/src/core_3d/mod.rs | 4 +- .../src/log_diagnostics_plugin.rs | 4 +- crates/bevy_ecs/macros/src/lib.rs | 2 +- crates/bevy_ecs/macros/src/set.rs | 69 +--- crates/bevy_ecs/src/schedule/config.rs | 148 +-------- crates/bevy_ecs/src/schedule/graph_utils.rs | 31 -- crates/bevy_ecs/src/schedule/mod.rs | 136 -------- crates/bevy_ecs/src/schedule/schedule.rs | 202 +----------- crates/bevy_ecs/src/schedule/set.rs | 24 -- crates/bevy_gilrs/src/lib.rs | 12 +- .../src/valid_parent_check_plugin.rs | 13 +- crates/bevy_input/src/lib.rs | 11 +- crates/bevy_pbr/src/lib.rs | 106 +++--- 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/camera/projection.rs | 15 +- 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/lib.rs | 6 +- crates/bevy_render/src/pipelined_rendering.rs | 5 +- crates/bevy_render/src/render_asset.rs | 8 +- crates/bevy_render/src/view/visibility/mod.rs | 87 +++-- crates/bevy_render/src/view/window.rs | 4 +- crates/bevy_scene/src/lib.rs | 3 +- 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 | 11 +- crates/bevy_time/src/fixed_timestep.rs | 4 +- crates/bevy_time/src/lib.rs | 11 +- crates/bevy_transform/src/lib.rs | 44 +-- crates/bevy_ui/src/lib.rs | 37 ++- crates/bevy_ui/src/render/mod.rs | 6 +- crates/bevy_window/src/lib.rs | 5 +- crates/bevy_winit/src/lib.rs | 8 +- examples/2d/bloom_2d.rs | 3 +- examples/2d/mesh2d_manual.rs | 6 +- examples/2d/move_sprite.rs | 3 +- examples/2d/pixel_perfect.rs | 3 +- examples/2d/rotation.rs | 6 +- examples/2d/sprite_sheet.rs | 5 +- examples/2d/text2d.rs | 8 +- examples/2d/texture_atlas.rs | 8 +- examples/3d/3d_shapes.rs | 3 +- examples/3d/blend_modes.rs | 3 +- examples/3d/bloom_3d.rs | 7 +- examples/3d/fxaa.rs | 3 +- examples/3d/lighting.rs | 3 +- examples/3d/load_gltf.rs | 3 +- examples/3d/msaa.rs | 3 +- examples/3d/parenting.rs | 3 +- examples/3d/pbr.rs | 3 +- examples/3d/render_to_texture.rs | 3 +- examples/3d/shadow_biases.rs | 2 +- examples/3d/shadow_caster_receiver.rs | 3 +- examples/3d/skybox.rs | 2 +- examples/3d/split_screen.rs | 3 +- examples/3d/spotlight.rs | 3 +- examples/3d/update_gltf_scene.rs | 3 +- examples/animation/animated_fox.rs | 2 +- examples/animation/custom_skinned_mesh.rs | 3 +- examples/animation/gltf_skinned_mesh.rs | 3 +- examples/asset/custom_asset.rs | 3 +- .../external_source_external_thread.rs | 3 +- examples/audio/audio_control.rs | 3 +- examples/audio/spatial_audio_2d.rs | 3 +- examples/audio/spatial_audio_3d.rs | 3 +- examples/diagnostics/custom_diagnostic.rs | 3 +- examples/ecs/apply_system_buffers.rs | 2 +- examples/ecs/component_change_detection.rs | 8 +- examples/ecs/ecs_guide.rs | 20 +- examples/ecs/fixed_timestep.rs | 10 +- examples/ecs/generic_system.rs | 10 +- examples/ecs/hierarchy.rs | 3 +- examples/ecs/iter_combinations.rs | 2 +- examples/ecs/nondeterministic_system_order.rs | 2 +- examples/ecs/parallel_query.rs | 3 +- examples/ecs/removal_detection.rs | 7 +- examples/ecs/state.rs | 12 +- examples/ecs/system_param.rs | 3 +- examples/ecs/timers.rs | 3 +- examples/games/alien_cake_addict.rs | 12 +- examples/games/breakout.rs | 6 +- examples/games/game_menu.rs | 57 ++-- examples/input/text_input.rs | 2 +- examples/shader/array_texture.rs | 3 +- examples/shader/post_processing.rs | 3 +- .../shader_material_screenspace_texture.rs | 3 +- examples/shader/shader_prepass.rs | 3 +- examples/stress_tests/bevymark.rs | 4 +- .../stress_tests/many_animated_sprites.rs | 2 +- examples/stress_tests/many_buttons.rs | 3 +- examples/stress_tests/many_cubes.rs | 3 +- examples/stress_tests/many_foxes.rs | 2 +- examples/stress_tests/many_lights.rs | 3 +- examples/stress_tests/many_sprites.rs | 7 +- examples/stress_tests/text_pipeline.rs | 3 +- examples/tools/scene_viewer/main.rs | 2 +- .../tools/scene_viewer/scene_viewer_plugin.rs | 8 +- examples/transforms/3d_rotation.rs | 3 +- examples/transforms/scale.rs | 3 +- examples/transforms/transform.rs | 2 +- examples/transforms/translation.rs | 3 +- examples/ui/button.rs | 3 +- examples/ui/font_atlas_debug.rs | 3 +- examples/ui/relative_cursor_position.rs | 3 +- examples/ui/text.rs | 3 +- examples/ui/text_debug.rs | 3 +- examples/ui/ui.rs | 3 +- examples/ui/ui_scaling.rs | 7 +- examples/window/clear_color.rs | 3 +- examples/window/low_power.rs | 2 +- examples/window/scale_factor_override.rs | 8 +- 125 files changed, 721 insertions(+), 1651 deletions(-) delete mode 100644 crates/bevy_app/src/config.rs diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index 7312a5fcf659f..34df6d03b5dfe 100644 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -5,7 +5,7 @@ use std::ops::Deref; use std::time::Duration; -use bevy_app::{App, CoreSet, Plugin}; +use bevy_app::{App, Plugin, PostUpdate}; use bevy_asset::{AddAsset, Assets, Handle}; use bevy_core::Name; use bevy_ecs::prelude::*; @@ -550,10 +550,9 @@ impl Plugin for AnimationPlugin { app.add_asset::() .register_asset_reflect::() .register_type::() - .add_system( - animation_player - .in_base_set(CoreSet::PostUpdate) - .before(TransformSystem::TransformPropagate), + .add_system_to( + PostUpdate, + animation_player.before(TransformSystem::TransformPropagate), ); } } diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 9ffc7a7c2305e..d7d0c964e0c2f 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1,7 +1,4 @@ -use crate::{ - CoreSchedule, CoreSet, IntoSystemAppConfig, IntoSystemAppConfigs, Plugin, PluginGroup, - StartupSet, SystemAppConfig, -}; +use crate::{First, Main, Plugin, PluginGroup, Startup, StateTransition, Update}; pub use bevy_derive::AppLabel; use bevy_ecs::{ prelude::*, @@ -73,10 +70,10 @@ pub struct App { /// /// This is initially set to [`CoreSchedule::Main`]. pub default_schedule_label: BoxedScheduleLabel, - /// The schedule that controls the outer loop of schedule execution. + /// The schedule that runs the main loop of schedule execution. /// - /// This is initially set to [`CoreSchedule::Outer`]. - pub outer_schedule_label: BoxedScheduleLabel, + /// This is initially set to [`Main`]. + pub main_schedule_label: BoxedScheduleLabel, sub_apps: HashMap, plugin_registry: Vec>, plugin_name_added: HashSet, @@ -166,7 +163,7 @@ impl SubApp { pub fn run(&mut self) { self.app .world - .run_schedule_ref(&*self.app.outer_schedule_label); + .run_schedule_ref(&*self.app.main_schedule_label); self.app.world.clear_trackers(); } @@ -192,7 +189,7 @@ impl Default for App { #[cfg(feature = "bevy_reflect")] app.init_resource::(); - app.add_default_schedules(); + Main::init(&mut app); app.add_event::(); @@ -226,8 +223,9 @@ impl App { sub_apps: HashMap::default(), plugin_registry: Vec::default(), plugin_name_added: Default::default(), - default_schedule_label: Box::new(CoreSchedule::Main), - outer_schedule_label: Box::new(CoreSchedule::Outer), + default_schedule_label: Box::new(Update), + // TODO: change this to Update? + main_schedule_label: Box::new(Main), is_building_plugin: false, } } @@ -248,7 +246,7 @@ impl App { { #[cfg(feature = "trace")] let _bevy_frame_update_span = info_span!("main app").entered(); - self.world.run_schedule_ref(&*self.outer_schedule_label); + self.world.run_schedule_ref(&*self.main_schedule_label); } for (_label, sub_app) in self.sub_apps.iter_mut() { #[cfg(feature = "trace")] @@ -334,26 +332,24 @@ impl App { let mut schedules = self.world.resource_mut::(); + if let Some(state_transition_schedule) = schedules.get_mut(&StateTransition) { + state_transition_schedule.add_systems( + ( + run_enter_schedule::.run_if(run_once_condition()), + apply_state_transition::, + ) + .chain(), + ); + } else { + panic!("{:?} schedule does not exist.", StateTransition) + } + let Some(default_schedule) = schedules.get_mut(&*self.default_schedule_label) else { - let schedule_label = &self.default_schedule_label; - panic!("Default schedule {schedule_label:?} does not exist.") + panic!("Default schedule {:?} does not exist.", self.default_schedule_label); }; - default_schedule.add_systems( - ( - run_enter_schedule::.run_if(run_once_condition()), - apply_state_transition::, - ) - .chain() - .in_base_set(CoreSet::StateTransitions), - ); - for variant in S::variants() { - default_schedule.configure_set( - OnUpdate(variant.clone()) - .in_base_set(CoreSet::Update) - .run_if(in_state(variant)), - ); + default_schedule.configure_set(OnUpdate(variant.clone()).run_if(in_state(variant))); } // These are different for loops to avoid conflicting access to self for variant in S::variants() { @@ -384,20 +380,10 @@ impl App { /// # /// app.add_system(my_system); /// ``` - pub fn add_system(&mut self, system: impl IntoSystemAppConfig) -> &mut Self { + pub fn add_system(&mut self, system: impl IntoSystemConfig) -> &mut Self { let mut schedules = self.world.resource_mut::(); - 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 { - let mut schedule = Schedule::new(); - schedule.add_system(system); - schedules.insert(schedule_label, schedule); - } - } else if let Some(default_schedule) = schedules.get_mut(&*self.default_schedule_label) { + 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; @@ -407,6 +393,38 @@ impl App { self } + /// Adds a system to the default system set and schedule of the app's [`Schedules`]. + /// + /// Refer to the [system module documentation](bevy_ecs::system) to see how a system + /// can be defined. + /// + /// # Examples + /// + /// ``` + /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; + /// # + /// # fn my_system() {} + /// # let mut app = App::new(); + /// # + /// app.add_system(my_system); + /// ``` + pub fn add_system_to( + &mut self, + schedule: impl ScheduleLabel, + system: impl IntoSystemConfig, + ) -> &mut Self { + let mut schedules = self.world.resource_mut::(); + + if let Some(schedule) = schedules.get_mut(&schedule) { + schedule.add_system(system); + } else { + panic!("Schedule {schedule:?} does not exist.") + } + + self + } + /// Adds a system to the default system set and schedule of the app's [`Schedules`]. /// /// # Examples @@ -422,29 +440,43 @@ impl App { /// # /// app.add_systems((system_a, system_b, system_c)); /// ``` - pub fn add_systems(&mut self, systems: impl IntoSystemAppConfigs) -> &mut Self { + pub fn add_systems(&mut self, systems: impl IntoSystemConfigs) -> &mut Self { let mut schedules = self.world.resource_mut::(); + let label = &*self.default_schedule_label; + let schedule = schedules + .get_mut(label) + .unwrap_or_else(|| panic!("Default schedule '{label:?}' does not exist.")); + schedule.add_systems(systems); + self + } - 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); - } - } - } + /// Adds a system to the default system set and schedule of the app's [`Schedules`]. + /// + /// # Examples + /// + /// ``` + /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; + /// # + /// # let mut app = App::new(); + /// # fn system_a() {} + /// # fn system_b() {} + /// # fn system_c() {} + /// # + /// app.add_systems((system_a, system_b, system_c)); + /// ``` + pub fn add_systems_to( + &mut self, + schedule: impl ScheduleLabel, + systems: impl IntoSystemConfigs, + ) -> &mut Self { + let mut schedules = self.world.resource_mut::(); + + let schedule = schedules + .get_mut(&schedule) + .unwrap_or_else(|| panic!("Schedule '{schedule:?}' does not exist.")); + + schedule.add_systems(systems); self } @@ -468,7 +500,7 @@ impl App { /// .add_startup_system(my_startup_system); /// ``` pub fn add_startup_system(&mut self, system: impl IntoSystemConfig) -> &mut Self { - self.add_system(system.in_schedule(CoreSchedule::Startup)) + self.add_system_to(Startup, system) } /// Adds a collection of systems to [`CoreSchedule::Startup`]. @@ -491,7 +523,7 @@ impl App { /// )); /// ``` pub fn add_startup_systems(&mut self, systems: impl IntoSystemConfigs) -> &mut Self { - self.add_systems(systems.into_configs().in_schedule(CoreSchedule::Startup)) + self.add_systems_to(Startup, systems.into_configs()) } /// Configures a system set in the default schedule, adding the set if it does not exist. @@ -504,6 +536,20 @@ impl App { self } + /// Configures a system set in the given schedule, adding the set if it does not exist. + pub fn configure_set_in( + &mut self, + schedule: impl ScheduleLabel, + set: impl IntoSystemSetConfig, + ) -> &mut Self { + self.world + .resource_mut::() + .get_mut(&schedule) + .unwrap() + .configure_set(set); + self + } + /// Configures a collection of system sets in the default schedule, adding any sets that do not exist. pub fn configure_sets(&mut self, sets: impl IntoSystemSetConfigs) -> &mut Self { self.world @@ -514,54 +560,6 @@ impl App { self } - /// Adds standardized schedules and labels to an [`App`]. - /// - /// Adding these schedules is necessary to make almost all core engine features work. - /// This is typically done implicitly by calling `App::default`, which is in turn called by - /// [`App::new`]. - /// - /// The schedules added are defined in the [`CoreSchedule`] enum, - /// and have a starting configuration defined by: - /// - /// - [`CoreSchedule::Outer`]: uses [`CoreSchedule::outer_schedule`] - /// - [`CoreSchedule::Startup`]: uses [`StartupSet::base_schedule`] - /// - [`CoreSchedule::Main`]: uses [`CoreSet::base_schedule`] - /// - [`CoreSchedule::FixedUpdate`]: no starting configuration - /// - /// # Examples - /// - /// ``` - /// use bevy_app::App; - /// use bevy_ecs::schedule::Schedules; - /// - /// let app = App::empty() - /// .init_resource::() - /// .add_default_schedules() - /// .update(); - /// ``` - pub fn add_default_schedules(&mut self) -> &mut Self { - self.add_schedule(CoreSchedule::Outer, CoreSchedule::outer_schedule()); - self.add_schedule(CoreSchedule::Startup, StartupSet::base_schedule()); - self.add_schedule(CoreSchedule::Main, CoreSet::base_schedule()); - self.init_schedule(CoreSchedule::FixedUpdate); - - self - } - - /// adds a single threaded outer schedule to the [`App`] that just runs the main schedule - pub fn add_simple_outer_schedule(&mut self) -> &mut Self { - fn run_main_schedule(world: &mut World) { - world.run_schedule(CoreSchedule::Main); - } - - self.edit_schedule(CoreSchedule::Outer, |schedule| { - schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded); - schedule.add_system(run_main_schedule); - }); - - self - } - /// Setup the application to manage events of type `T`. /// /// This is done by adding a [`Resource`] of type [`Events::`], @@ -586,7 +584,7 @@ impl App { { if !self.world.contains_resource::>() { self.init_resource::>() - .add_system(Events::::update_system.in_base_set(CoreSet::First)); + .add_system_to(First, Events::::update_system); } self } @@ -1024,7 +1022,7 @@ mod tests { system::Commands, }; - use crate::{App, IntoSystemAppConfig, IntoSystemAppConfigs, Plugin}; + use crate::{App, Plugin}; struct PluginA; impl Plugin for PluginA { @@ -1095,7 +1093,7 @@ mod tests { #[test] fn add_system_should_create_schedule_if_it_does_not_exist() { let mut app = App::new(); - app.add_system(foo.in_schedule(OnEnter(AppState::MainMenu))) + app.add_system_to(OnEnter(AppState::MainMenu), foo) .add_state::(); app.world.run_schedule(OnEnter(AppState::MainMenu)); @@ -1106,7 +1104,7 @@ mod tests { fn add_system_should_create_schedule_if_it_does_not_exist2() { let mut app = App::new(); app.add_state::() - .add_system(foo.in_schedule(OnEnter(AppState::MainMenu))); + .add_system_to(OnEnter(AppState::MainMenu), foo); app.world.run_schedule(OnEnter(AppState::MainMenu)); assert_eq!(app.world.entities().len(), 1); @@ -1116,7 +1114,7 @@ mod tests { fn add_systems_should_create_schedule_if_it_does_not_exist() { let mut app = App::new(); app.add_state::() - .add_systems((foo, bar).in_schedule(OnEnter(AppState::MainMenu))); + .add_systems_to(OnEnter(AppState::MainMenu), (foo, bar)); app.world.run_schedule(OnEnter(AppState::MainMenu)); assert_eq!(app.world.entities().len(), 2); @@ -1125,7 +1123,7 @@ mod tests { #[test] fn add_systems_should_create_schedule_if_it_does_not_exist2() { let mut app = App::new(); - app.add_systems((foo, bar).in_schedule(OnEnter(AppState::MainMenu))) + app.add_systems_to(OnEnter(AppState::MainMenu), (foo, bar)) .add_state::(); app.world.run_schedule(OnEnter(AppState::MainMenu)); diff --git a/crates/bevy_app/src/config.rs b/crates/bevy_app/src/config.rs deleted file mode 100644 index fb3a3fde1cd92..0000000000000 --- a/crates/bevy_app/src/config.rs +++ /dev/null @@ -1,294 +0,0 @@ -use bevy_ecs::{ - all_tuples, - schedule::{ - BaseSystemSet, BoxedScheduleLabel, Condition, FreeSystemSet, IntoSystemConfig, - IntoSystemSet, ScheduleLabel, SystemConfig, SystemConfigs, - }, -}; - -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 FreeSystemSet) -> Self { - let Self { system, schedule } = self; - Self { - system: system.in_set(set), - schedule, - } - } - - #[track_caller] - fn in_base_set(self, set: impl BaseSystemSet) -> 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 with specified label does not exist, it will be created. - /// - /// If a schedule with the specified label does not exist, an empty one will be created. - /// - /// - /// [`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 165e9ebd70e07..1cfadd58ef3a3 100644 --- a/crates/bevy_app/src/lib.rs +++ b/crates/bevy_app/src/lib.rs @@ -3,7 +3,6 @@ #![warn(missing_docs)] mod app; -mod config; mod plugin; mod plugin_group; mod schedule_runner; @@ -13,7 +12,6 @@ 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::*; @@ -25,198 +23,155 @@ pub mod prelude { pub use crate::AppTypeRegistry; #[doc(hidden)] pub use crate::{ - app::App, - config::{IntoSystemAppConfig, IntoSystemAppConfigs}, - CoreSchedule, CoreSet, DynamicPlugin, Plugin, PluginGroup, StartupSet, + app::App, DynamicPlugin, First, FixedUpdate, Last, Main, Plugin, PluginGroup, PostStartup, + PostUpdate, PreStartup, PreUpdate, Startup, StateTransition, Update, }; } use bevy_ecs::{ - schedule::{ - apply_system_buffers, IntoSystemConfig, IntoSystemSetConfigs, Schedule, ScheduleLabel, - SystemSet, - }, - system::Local, - world::World, + schedule::ScheduleLabel, + system::{Local, Resource}, + world::{Mut, World}, }; -/// The names of the default [`App`] schedules. -/// -/// The corresponding [`Schedule`](bevy_ecs::schedule::Schedule) objects are added by [`App::add_default_schedules`]. +// TODO: move schedules outside of bevy_app + +/// The schedule that contains the app logic that is evaluated each tick of [`App::update()`]. #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] -pub enum CoreSchedule { - /// The schedule that runs once when the app starts. - Startup, - /// The schedule that contains the app logic that is evaluated each tick of [`App::update()`]. - Main, - /// The schedule that controls which schedules run. - /// - /// This is typically created using the [`CoreSchedule::outer_schedule`] method, - /// and does not need to manipulated during ordinary use. - Outer, - /// The schedule that contains systems which only run after a fixed period of time has elapsed. - /// - /// The exclusive `run_fixed_update_schedule` system runs this schedule during the [`CoreSet::FixedUpdate`] system set. - FixedUpdate, -} +pub struct Main; -impl CoreSchedule { - /// An exclusive system that controls which schedule should be running. - /// - /// [`CoreSchedule::Main`] is always run. - /// - /// If this is the first time this system has been run, [`CoreSchedule::Startup`] will run before [`CoreSchedule::Main`]. - pub fn outer_loop(world: &mut World, mut run_at_least_once: Local) { - if !*run_at_least_once { - world.run_schedule(CoreSchedule::Startup); - *run_at_least_once = true; - } +/// The schedule that runs before [`Startup`]. +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct PreStartup; - world.run_schedule(CoreSchedule::Main); - } +/// The schedule that runs once when the app starts. +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Startup; - /// Initializes a single threaded schedule for [`CoreSchedule::Outer`] that contains the [`outer_loop`](CoreSchedule::outer_loop) system. - pub fn outer_schedule() -> Schedule { - let mut schedule = Schedule::new(); - schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded); - schedule.add_system(Self::outer_loop); - schedule - } -} +/// The schedule that runs once after [`Startup`]. +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct PostStartup; -/// The names of the default [`App`] system sets. -/// -/// These are ordered in the same order they are listed. -/// -/// The corresponding [`SystemSets`](bevy_ecs::schedule::SystemSet) are added by [`App::add_default_schedules`]. +/// The schedule that runs once when the app starts. +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct First; + +/// The schedule that contains work required to make [`Update`] logic. +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct PreUpdate; + +/// Runs state transitions. +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct StateTransition; + +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct FixedUpdateLoop; + +/// The schedule that contains systems which only run after a fixed period of time has elapsed. /// -/// The `*Flush` sets are assigned to the copy of [`apply_system_buffers`] -/// that runs immediately after the matching system set. -/// These can be useful for ordering, but you almost never want to add your systems to these sets. -#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] -#[system_set(base)] -pub enum CoreSet { - /// Runs before all other members of this set. - First, - /// The copy of [`apply_system_buffers`] that runs immediately after `First`. - FirstFlush, - /// Runs before [`CoreSet::Update`]. - PreUpdate, - /// The copy of [`apply_system_buffers`] that runs immediately after `PreUpdate`. - PreUpdateFlush, - /// Applies [`State`](bevy_ecs::schedule::State) transitions - StateTransitions, - /// Runs systems that should only occur after a fixed period of time. - /// - /// The `run_fixed_update_schedule` system runs the [`CoreSchedule::FixedUpdate`] system in this system set. - FixedUpdate, - /// Responsible for doing most app logic. Systems should be registered here by default. - Update, - /// The copy of [`apply_system_buffers`] that runs immediately after `Update`. - UpdateFlush, - /// Runs after [`CoreSet::Update`]. - PostUpdate, - /// The copy of [`apply_system_buffers`] that runs immediately after `PostUpdate`. - PostUpdateFlush, - /// Runs after all other members of this set. - Last, - /// The copy of [`apply_system_buffers`] that runs immediately after `Last`. - LastFlush, +/// The exclusive `run_fixed_update_schedule` system runs this schedule during the [`CoreSet::FixedUpdate`] system set. +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct FixedUpdate; + +/// The schedule that contains app logic. +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Update; + +/// The schedule that contains systems that respond to [`Update`]. +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct PostUpdate; + +/// Runs last in the schedule +#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Last; + +#[derive(Resource, Debug)] +pub struct MainScheduleOrder { + labels: Vec>, } -impl CoreSet { - /// Sets up the base structure of [`CoreSchedule::Main`]. - /// - /// The sets defined in this enum are configured to run in order, - /// and a copy of [`apply_system_buffers`] is inserted into each `*Flush` set. - pub fn base_schedule() -> Schedule { - use CoreSet::*; - let mut schedule = Schedule::new(); - - // Create "stage-like" structure using buffer flushes + ordering - schedule - .set_default_base_set(Update) - .add_systems(( - apply_system_buffers.in_base_set(FirstFlush), - apply_system_buffers.in_base_set(PreUpdateFlush), - apply_system_buffers.in_base_set(UpdateFlush), - apply_system_buffers.in_base_set(PostUpdateFlush), - apply_system_buffers.in_base_set(LastFlush), - )) - .configure_sets( - ( - First, - FirstFlush, - PreUpdate, - PreUpdateFlush, - StateTransitions, - FixedUpdate, - Update, - UpdateFlush, - PostUpdate, - PostUpdateFlush, - Last, - LastFlush, - ) - .chain(), - ); - schedule +impl Default for MainScheduleOrder { + fn default() -> Self { + Self { + labels: vec![ + Box::new(First), + Box::new(PreUpdate), + Box::new(StateTransition), + Box::new(FixedUpdateLoop), + Box::new(Update), + Box::new(PostUpdate), + Box::new(Last), + ], + } } } -/// The names of the default [`App`] startup sets, which live in [`CoreSchedule::Startup`]. -/// -/// The corresponding [`SystemSets`](bevy_ecs::schedule::SystemSet) are added by [`App::add_default_schedules`]. -/// -/// The `*Flush` sets are assigned to the copy of [`apply_system_buffers`] -/// that runs immediately after the matching system set. -/// These can be useful for ordering, but you almost never want to add your systems to these sets. -#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] -#[system_set(base)] -pub enum StartupSet { - /// Runs once before [`StartupSet::Startup`]. - PreStartup, - /// The copy of [`apply_system_buffers`] that runs immediately after `PreStartup`. - PreStartupFlush, - /// Runs once when an [`App`] starts up. - Startup, - /// The copy of [`apply_system_buffers`] that runs immediately after `Startup`. - StartupFlush, - /// Runs once after [`StartupSet::Startup`]. - PostStartup, - /// The copy of [`apply_system_buffers`] that runs immediately after `PostStartup`. - PostStartupFlush, +impl MainScheduleOrder { + pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) { + let index = self + .labels + .iter() + .position(|current| (&**current).eq(&after)) + .unwrap_or_else(|| panic!("Expected {:?} to exist", after)); + self.labels.insert(index + 1, Box::new(schedule)); + } } -impl StartupSet { - /// Sets up the base structure of [`CoreSchedule::Startup`]. +impl Main { + pub fn run_main(world: &mut World, mut run_at_least_once: Local) { + if !*run_at_least_once { + world.run_schedule(PreStartup); + world.run_schedule(Startup); + world.run_schedule(PostStartup); + *run_at_least_once = true; + } + + world.resource_scope(|world, order: Mut| { + for label in &order.labels { + world.run_schedule_ref(&**label); + } + }); + } + + /// Adds standardized schedules and labels to an [`App`]. + /// + /// Adding these schedules is necessary to make almost all core engine features work. + /// This is typically done implicitly by calling `App::default`, which is in turn called by + /// [`App::new`]. + /// + /// The schedules added are defined in the [`CoreSchedule`] enum, + /// and have a starting configuration defined by: + /// + /// - [`CoreSchedule::Outer`]: uses [`CoreSchedule::outer_schedule`] + /// - [`CoreSchedule::Startup`]: uses [`StartupSet::base_schedule`] + /// - [`CoreSchedule::Main`]: uses [`CoreSet::base_schedule`] + /// - [`CoreSchedule::FixedUpdate`]: no starting configuration + /// + /// # Examples + /// + /// ``` + /// use bevy_app::App; + /// use bevy_ecs::schedule::Schedules; /// - /// The sets defined in this enum are configured to run in order, - /// and a copy of [`apply_system_buffers`] is inserted into each `*Flush` set. - pub fn base_schedule() -> Schedule { - use StartupSet::*; - let mut schedule = Schedule::new(); - schedule.set_default_base_set(Startup); - - // Create "stage-like" structure using buffer flushes + ordering - schedule.add_systems(( - apply_system_buffers.in_base_set(PreStartupFlush), - apply_system_buffers.in_base_set(StartupFlush), - apply_system_buffers.in_base_set(PostStartupFlush), - )); - - schedule.configure_sets( - ( - PreStartup, - PreStartupFlush, - Startup, - StartupFlush, - PostStartup, - PostStartupFlush, - ) - .chain(), - ); - - schedule + /// let app = App::empty() + /// .init_resource::() + /// .add_default_schedules() + /// .update(); + /// ``` + pub fn init(app: &mut App) { + app.init_schedule(Main) + .init_schedule(PreStartup) + .init_schedule(Startup) + .init_schedule(PostStartup) + .init_schedule(First) + .init_schedule(PreUpdate) + .init_schedule(StateTransition) + .init_schedule(FixedUpdateLoop) + .init_schedule(FixedUpdate) + .init_schedule(Update) + .init_schedule(PostUpdate) + .init_schedule(Last) + .init_resource::() + .add_system_to(Main, Self::run_main); } } diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 40d390187f80d..330ebe709c336 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -1,8 +1,8 @@ use crate::{ - update_asset_storage_system, Asset, AssetLoader, AssetServer, AssetSet, Handle, HandleId, - RefChange, ReflectAsset, ReflectHandle, + update_asset_storage_system, Asset, AssetEvents, AssetLoader, AssetServer, Handle, HandleId, + LoadAssets, RefChange, ReflectAsset, ReflectHandle, }; -use bevy_app::{App, AppTypeRegistry}; +use bevy_app::{App, AppTypeRegistry, PostUpdate, PreUpdate}; use bevy_ecs::prelude::*; use bevy_reflect::{FromReflect, GetTypeRegistration, Reflect}; use bevy_utils::HashMap; @@ -331,10 +331,8 @@ impl AddAsset for App { }; self.insert_resource(assets) - .add_systems(( - Assets::::asset_event_system.in_base_set(AssetSet::AssetEvents), - update_asset_storage_system::.in_base_set(AssetSet::LoadAssets), - )) + .add_system_to(LoadAssets, update_asset_storage_system::) + .add_system_to(AssetEvents, Assets::::asset_event_system) .register_type::>() .add_event::>() } diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index 59b0b2cb327f3..cf1016f49a919 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -46,18 +46,17 @@ pub use loader::*; pub use path::*; pub use reflect::*; -use bevy_app::prelude::*; -use bevy_ecs::prelude::*; +use bevy_app::{prelude::*, MainScheduleOrder}; +use bevy_ecs::{prelude::*, schedule::ScheduleLabel}; -/// [`SystemSet`]s for asset loading in an [`App`] schedule. -#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] -#[system_set(base)] -pub enum AssetSet { - /// Asset storages are updated. - LoadAssets, - /// Asset events are generated. - AssetEvents, -} +// TODO: evaluate execution to allow these to be sets + +/// Asset storages are updated. +#[derive(Debug, Hash, PartialEq, Eq, Clone, ScheduleLabel)] +pub struct LoadAssets; +/// Asset events are generated. +#[derive(Debug, Hash, PartialEq, Eq, Clone, ScheduleLabel)] +pub struct AssetEvents; /// Adds support for [`Assets`] to an App. /// @@ -106,24 +105,29 @@ impl Plugin for AssetPlugin { app.insert_resource(asset_server); } - app.register_type::(); - - app.configure_set( - AssetSet::LoadAssets - .before(CoreSet::PreUpdate) - .after(CoreSet::First), - ) - .configure_set( - AssetSet::AssetEvents - .after(CoreSet::PostUpdate) - .before(CoreSet::Last), - ) - .add_system(asset_server::free_unused_assets_system.in_base_set(CoreSet::PreUpdate)); + app.register_type::() + .add_system_to(PreUpdate, asset_server::free_unused_assets_system); + app.init_schedule(LoadAssets); + app.init_schedule(AssetEvents); + // app.configure_set( + // AssetSet::LoadAssets + // .before(CoreSet::PreUpdate) + // .after(CoreSet::First), + // ) + // .configure_set( + // AssetSet::AssetEvents + // .after(CoreSet::PostUpdate) + // .before(CoreSet::Last), + // ) #[cfg(all( feature = "filesystem_watcher", all(not(target_arch = "wasm32"), not(target_os = "android")) ))] - app.add_system(io::filesystem_watcher_system.in_base_set(AssetSet::LoadAssets)); + app.add_system_to(LoadAssets, io::filesystem_watcher_system); + + let mut order = app.world.resource_mut::(); + order.insert_after(First, LoadAssets); + order.insert_after(PostUpdate, AssetEvents); } } diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index af751a8364c61..25b08c0f70984 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -47,7 +47,6 @@ pub use sinks::*; use bevy_app::prelude::*; use bevy_asset::{AddAsset, Asset}; -use bevy_ecs::prelude::*; /// Adds support for audio playback to a Bevy Application /// @@ -62,7 +61,7 @@ impl Plugin for AudioPlugin { .add_asset::() .add_asset::() .init_resource::>() - .add_system(play_queued_audio_system::.in_base_set(CoreSet::PostUpdate)); + .add_system_to(PostUpdate, play_queued_audio_system::); #[cfg(any(feature = "mp3", feature = "flac", feature = "wav", feature = "vorbis"))] app.init_asset_loader::(); @@ -78,6 +77,6 @@ impl AddAudioSource for App { self.add_asset::() .init_resource::>() .init_resource::>() - .add_system(play_queued_audio_system::.in_base_set(CoreSet::PostUpdate)) + .add_system_to(PostUpdate, play_queued_audio_system::) } } diff --git a/crates/bevy_core/src/lib.rs b/crates/bevy_core/src/lib.rs index 7e58685c9fe37..9afe337aa5a91 100644 --- a/crates/bevy_core/src/lib.rs +++ b/crates/bevy_core/src/lib.rs @@ -107,7 +107,7 @@ impl Plugin for TaskPoolPlugin { self.task_pool_options.create_default_pools(); #[cfg(not(target_arch = "wasm32"))] - app.add_system(tick_global_task_pools.in_base_set(bevy_app::CoreSet::Last)); + app.add_system_to(Last, tick_global_task_pools); } } /// A dummy type that is [`!Send`](Send), to force systems to run on the main thread. @@ -142,7 +142,7 @@ pub struct FrameCountPlugin; impl Plugin for FrameCountPlugin { fn build(&self, app: &mut App) { app.init_resource::(); - app.add_system(update_frame_count.in_base_set(CoreSet::Last)); + app.add_system_to(Last, update_frame_count); } } diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index a94da4d0b3651..05fc100551718 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -20,7 +20,7 @@ pub mod graph { pub use camera_2d::*; pub use main_pass_2d_node::*; -use bevy_app::{App, IntoSystemAppConfig, Plugin}; +use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use bevy_render::{ camera::Camera, @@ -52,13 +52,16 @@ impl Plugin for Core2dPlugin { render_app .init_resource::>() - .add_systems(( - extract_core_2d_camera_phases.in_schedule(ExtractSchedule), - sort_phase_system::.in_set(RenderSet::PhaseSort), - batch_phase_system:: - .after(sort_phase_system::) - .in_set(RenderSet::PhaseSort), - )); + .add_systems_to( + ExtractSchedule, + ( + extract_core_2d_camera_phases, + sort_phase_system::.in_set(RenderSet::PhaseSort), + batch_phase_system:: + .after(sort_phase_system::) + .in_set(RenderSet::PhaseSort), + ), + ); let pass_node_2d = MainPass2dNode::new(&mut render_app.world); let tonemapping = TonemappingNode::new(&mut render_app.world); diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index 166f6765e0ea2..4678ce7a2a10e 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -23,7 +23,7 @@ use std::cmp::Reverse; pub use camera_3d::*; pub use main_pass_3d_node::*; -use bevy_app::{App, IntoSystemAppConfig, Plugin}; +use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use bevy_render::{ camera::{Camera, ExtractedCamera}, @@ -68,8 +68,8 @@ impl Plugin for Core3dPlugin { .init_resource::>() .init_resource::>() .init_resource::>() + .add_system_to(ExtractSchedule, extract_core_3d_camera_phases) .add_systems(( - extract_core_3d_camera_phases.in_schedule(ExtractSchedule), prepare_core_3d_depth_textures .in_set(RenderSet::Prepare) .after(bevy_render::view::prepare_windows), diff --git a/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs b/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs index dd80c8c8f2024..cec27eefa8a09 100644 --- a/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs +++ b/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs @@ -37,9 +37,9 @@ impl Plugin for LogDiagnosticsPlugin { }); if self.debug { - app.add_system(Self::log_diagnostics_debug_system.in_base_set(CoreSet::PostUpdate)); + app.add_system_to(PostUpdate, Self::log_diagnostics_debug_system); } else { - app.add_system(Self::log_diagnostics_system.in_base_set(CoreSet::PostUpdate)); + app.add_system_to(PostUpdate, Self::log_diagnostics_system); } } } diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index dbafe0d9e3ead..0e3374f757c83 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -469,7 +469,7 @@ pub fn derive_schedule_label(input: TokenStream) -> TokenStream { } /// Derive macro generating an impl of the trait `SystemSet`. -#[proc_macro_derive(SystemSet, attributes(system_set))] +#[proc_macro_derive(SystemSet)] pub fn derive_system_set(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let mut trait_path = bevy_ecs_path(); diff --git a/crates/bevy_ecs/macros/src/set.rs b/crates/bevy_ecs/macros/src/set.rs index 054735c858653..66bfb601ecf35 100644 --- a/crates/bevy_ecs/macros/src/set.rs +++ b/crates/bevy_ecs/macros/src/set.rs @@ -1,9 +1,5 @@ use proc_macro::TokenStream; -use quote::{format_ident, quote, ToTokens}; -use syn::parse::{Parse, ParseStream}; - -pub static SYSTEM_SET_ATTRIBUTE_NAME: &str = "system_set"; -pub static BASE_ATTRIBUTE_NAME: &str = "base"; +use quote::quote; /// Derive a set trait /// @@ -12,55 +8,8 @@ pub static BASE_ATTRIBUTE_NAME: &str = "base"; /// - `input`: The [`syn::DeriveInput`] for the struct that we want to derive the set trait for /// - `trait_path`: The [`syn::Path`] to the set trait pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream { - let mut base_trait_path = trait_path.clone(); - let ident = &mut base_trait_path.segments.last_mut().unwrap().ident; - *ident = format_ident!("Base{ident}"); - - let mut free_trait_path = trait_path.clone(); - let ident = &mut free_trait_path.segments.last_mut().unwrap().ident; - *ident = format_ident!("Free{ident}"); - let ident = input.ident; - let mut is_base = false; - for attr in &input.attrs { - if !attr - .path - .get_ident() - .map_or(false, |ident| ident == SYSTEM_SET_ATTRIBUTE_NAME) - { - continue; - } - - attr.parse_args_with(|input: ParseStream| { - let meta = input.parse_terminated::(syn::Meta::parse)?; - for meta in meta { - let ident = meta.path().get_ident().unwrap_or_else(|| { - panic!( - "Unrecognized attribute: `{}`", - meta.path().to_token_stream() - ) - }); - if ident == BASE_ATTRIBUTE_NAME { - if let syn::Meta::Path(_) = meta { - is_base = true; - } else { - panic!( - "The `{BASE_ATTRIBUTE_NAME}` attribute is expected to have no value or arguments", - ); - } - } else { - panic!( - "Unrecognized attribute: `{}`", - meta.path().to_token_stream() - ); - } - } - Ok(()) - }) - .unwrap_or_else(|_| panic!("Invalid `{SYSTEM_SET_ATTRIBUTE_NAME}` attribute format")); - } - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause { where_token: Default::default(), @@ -73,28 +22,12 @@ pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStrea .unwrap(), ); - let marker_impl = if is_base { - quote! { - impl #impl_generics #base_trait_path for #ident #ty_generics #where_clause {} - } - } else { - quote! { - impl #impl_generics #free_trait_path for #ident #ty_generics #where_clause {} - } - }; - (quote! { impl #impl_generics #trait_path for #ident #ty_generics #where_clause { - fn is_base(&self) -> bool { - #is_base - } - fn dyn_clone(&self) -> std::boxed::Box { std::boxed::Box::new(std::clone::Clone::clone(self)) } } - - #marker_impl }) .into() } diff --git a/crates/bevy_ecs/src/schedule/config.rs b/crates/bevy_ecs/src/schedule/config.rs index 54eb9f863f5b7..b401abf629c42 100644 --- a/crates/bevy_ecs/src/schedule/config.rs +++ b/crates/bevy_ecs/src/schedule/config.rs @@ -9,8 +9,6 @@ use crate::{ system::{BoxedSystem, IntoSystem, System}, }; -use super::{BaseSystemSet, FreeSystemSet}; - /// A [`SystemSet`] with scheduling metadata. pub struct SystemSetConfig { pub(super) set: BoxedSystemSet, @@ -29,7 +27,7 @@ impl SystemSetConfig { Self { set, - graph_info: GraphInfo::system_set(), + graph_info: GraphInfo::default(), conditions: Vec::new(), } } @@ -46,7 +44,7 @@ impl SystemConfig { fn new(system: BoxedSystem) -> Self { // include system in its default sets let sets = system.default_system_sets().into_iter().collect(); - let mut graph_info = GraphInfo::system(); + let mut graph_info = GraphInfo::default(); graph_info.sets = sets; Self { system, @@ -88,18 +86,9 @@ pub trait IntoSystemSetConfig: Sized { fn into_config(self) -> SystemSetConfig; /// Add to the provided `set`. #[track_caller] - fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfig { + fn in_set(self, set: impl SystemSet) -> SystemSetConfig { self.into_config().in_set(set) } - /// 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 BaseSystemSet) -> SystemSetConfig { - self.into_config().in_base_set(set) - } - /// Add this set to the schedules's default base set. - fn in_default_base_set(self) -> SystemSetConfig { - self.into_config().in_default_base_set() - } /// Run before all systems in `set`. fn before(self, set: impl IntoSystemSet) -> SystemSetConfig { self.into_config().before(set) @@ -150,41 +139,10 @@ impl IntoSystemSetConfig for SystemSetConfig { set.system_type().is_none(), "adding arbitrary systems to a system type set is not allowed" ); - assert!( - !set.is_base(), - "Sets cannot be added to 'base' system sets using 'in_set'. Use 'in_base_set' instead." - ); - assert!( - !self.set.is_base(), - "Base system sets cannot be added to other sets." - ); self.graph_info.sets.push(Box::new(set)); self } - #[track_caller] - fn in_base_set(mut self, set: impl SystemSet) -> Self { - assert!( - set.system_type().is_none(), - "System type sets cannot be base sets." - ); - assert!( - set.is_base(), - "Sets cannot be added to normal sets using 'in_base_set'. Use 'in_set' instead." - ); - assert!( - !self.set.is_base(), - "Base system sets cannot be added to other sets." - ); - self.graph_info.set_base_set(Box::new(set)); - self - } - - fn in_default_base_set(mut self) -> SystemSetConfig { - self.graph_info.add_default_base_set = true; - self - } - fn before(mut self, set: impl IntoSystemSet) -> Self { self.graph_info.dependencies.push(Dependency::new( DependencyKind::Before, @@ -230,18 +188,9 @@ where fn into_config(self) -> Config; /// Add to `set` membership. #[track_caller] - fn in_set(self, set: impl FreeSystemSet) -> Config { + fn in_set(self, set: impl SystemSet) -> Config { self.into_config().in_set(set) } - /// 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 BaseSystemSet) -> Config { - self.into_config().in_base_set(set) - } - /// Don't add this system to the schedules's default set. - fn no_default_base_set(self) -> Config { - self.into_config().no_default_base_set() - } /// Run before all systems in `set`. fn before(self, set: impl IntoSystemSet) -> Config { self.into_config().before(set) @@ -295,33 +244,10 @@ impl IntoSystemConfig<()> for SystemConfig { set.system_type().is_none(), "adding arbitrary systems to a system type set is not allowed" ); - assert!( - !set.is_base(), - "Systems cannot be added to 'base' system sets using 'in_set'. Use 'in_base_set' instead." - ); self.graph_info.sets.push(Box::new(set)); self } - #[track_caller] - fn in_base_set(mut self, set: impl SystemSet) -> Self { - assert!( - set.system_type().is_none(), - "System type sets cannot be base sets." - ); - assert!( - set.is_base(), - "Systems cannot be added to normal sets using 'in_base_set'. Use 'in_set' instead." - ); - self.graph_info.set_base_set(Box::new(set)); - self - } - - fn no_default_base_set(mut self) -> SystemConfig { - self.graph_info.add_default_base_set = false; - self - } - fn before(mut self, set: impl IntoSystemSet) -> Self { self.graph_info.dependencies.push(Dependency::new( DependencyKind::Before, @@ -372,16 +298,10 @@ where /// Add these systems to the provided `set`. #[track_caller] - fn in_set(self, set: impl FreeSystemSet) -> SystemConfigs { + fn in_set(self, set: impl SystemSet) -> SystemConfigs { self.into_configs().in_set(set) } - /// Add these systems to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`]. - #[track_caller] - fn in_base_set(self, set: impl BaseSystemSet) -> SystemConfigs { - self.into_configs().in_base_set(set) - } - /// Run before all systems in `set`. fn before(self, set: impl IntoSystemSet) -> SystemConfigs { self.into_configs().before(set) @@ -457,10 +377,6 @@ impl IntoSystemConfigs<()> for SystemConfigs { set.system_type().is_none(), "adding arbitrary systems to a system type set is not allowed" ); - assert!( - !set.is_base(), - "Systems cannot be added to 'base' system sets using 'in_set'. Use 'in_base_set' instead." - ); for config in &mut self.systems { config.graph_info.sets.push(set.dyn_clone()); } @@ -468,23 +384,6 @@ impl IntoSystemConfigs<()> for SystemConfigs { self } - #[track_caller] - fn in_base_set(mut self, set: impl SystemSet) -> Self { - assert!( - set.system_type().is_none(), - "System type sets cannot be base sets." - ); - assert!( - set.is_base(), - "Systems cannot be added to normal sets using 'in_base_set'. Use 'in_set' instead." - ); - for config in &mut self.systems { - config.graph_info.set_base_set(set.dyn_clone()); - } - - self - } - fn before(mut self, set: impl IntoSystemSet) -> Self { let set = set.into_system_set(); for config in &mut self.systems { @@ -558,16 +457,10 @@ where /// Add these system sets to the provided `set`. #[track_caller] - fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfigs { + fn in_set(self, set: impl SystemSet) -> SystemSetConfigs { self.into_configs().in_set(set) } - /// Add these system sets to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`]. - #[track_caller] - fn in_base_set(self, set: impl BaseSystemSet) -> SystemSetConfigs { - self.into_configs().in_base_set(set) - } - /// Run before all systems in `set`. fn before(self, set: impl IntoSystemSet) -> SystemSetConfigs { self.into_configs().before(set) @@ -609,42 +502,13 @@ impl IntoSystemSetConfigs for SystemSetConfigs { set.system_type().is_none(), "adding arbitrary systems to a system type set is not allowed" ); - assert!( - !set.is_base(), - "Sets cannot be added to 'base' system sets using 'in_set'. Use 'in_base_set' instead." - ); for config in &mut self.sets { - assert!( - !config.set.is_base(), - "Base system sets cannot be added to other sets." - ); config.graph_info.sets.push(set.dyn_clone()); } self } - #[track_caller] - fn in_base_set(mut self, set: impl SystemSet) -> Self { - assert!( - set.system_type().is_none(), - "System type sets cannot be base sets." - ); - assert!( - set.is_base(), - "Sets cannot be added to normal sets using 'in_base_set'. Use 'in_set' instead." - ); - for config in &mut self.sets { - assert!( - !config.set.is_base(), - "Base system sets cannot be added to other sets." - ); - config.graph_info.set_base_set(set.dyn_clone()); - } - - self - } - fn before(mut self, set: impl IntoSystemSet) -> Self { let set = set.into_system_set(); for config in &mut self.sets { diff --git a/crates/bevy_ecs/src/schedule/graph_utils.rs b/crates/bevy_ecs/src/schedule/graph_utils.rs index f7e28e6bb5cd9..65de0f125e92d 100644 --- a/crates/bevy_ecs/src/schedule/graph_utils.rs +++ b/crates/bevy_ecs/src/schedule/graph_utils.rs @@ -72,7 +72,6 @@ pub(crate) struct GraphInfo { pub(crate) sets: Vec, pub(crate) dependencies: Vec, pub(crate) ambiguous_with: Ambiguity, - pub(crate) add_default_base_set: bool, pub(crate) base_set: Option, } @@ -83,36 +82,6 @@ impl Default for GraphInfo { base_set: None, dependencies: Vec::new(), ambiguous_with: Ambiguity::default(), - add_default_base_set: true, - } - } -} - -impl GraphInfo { - pub(crate) fn system() -> GraphInfo { - GraphInfo { - // systems get the default base set automatically - add_default_base_set: true, - ..Default::default() - } - } - - pub(crate) fn system_set() -> GraphInfo { - GraphInfo { - // sets do not get the default base set automatically - add_default_base_set: false, - ..Default::default() - } - } - - #[track_caller] - pub(crate) fn set_base_set(&mut self, set: BoxedSystemSet) { - if let Some(current) = &self.base_set { - panic!( - "Cannot set the base set because base set {current:?} has already been configured." - ); - } else { - self.base_set = Some(set); } } } diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 0a5f92a4ddb35..06da5d8232d19 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -664,140 +664,4 @@ mod tests { assert!(matches!(result, Err(ScheduleBuildError::Ambiguity))); } } - - mod base_sets { - use super::*; - - #[derive(SystemSet, Hash, Debug, Eq, PartialEq, Clone)] - #[system_set(base)] - enum Base { - A, - B, - } - - #[derive(SystemSet, Hash, Debug, Eq, PartialEq, Clone)] - enum Normal { - X, - Y, - } - - #[test] - #[should_panic] - fn disallow_adding_base_sets_to_sets() { - let mut schedule = Schedule::new(); - schedule.configure_set(Base::A.in_set(Normal::X)); - } - - #[test] - #[should_panic] - fn disallow_adding_base_sets_to_base_sets() { - let mut schedule = Schedule::new(); - schedule.configure_set(Base::A.in_base_set(Base::B)); - } - - #[test] - #[should_panic] - fn disallow_adding_set_to_multiple_base_sets() { - let mut schedule = Schedule::new(); - schedule.configure_set(Normal::X.in_base_set(Base::A).in_base_set(Base::B)); - } - - #[test] - #[should_panic] - fn disallow_adding_sets_to_multiple_base_sets() { - let mut schedule = Schedule::new(); - schedule.configure_sets( - (Normal::X, Normal::Y) - .in_base_set(Base::A) - .in_base_set(Base::B), - ); - } - - #[test] - #[should_panic] - fn disallow_adding_system_to_multiple_base_sets() { - let mut schedule = Schedule::new(); - schedule.add_system(named_system.in_base_set(Base::A).in_base_set(Base::B)); - } - - #[test] - #[should_panic] - fn disallow_adding_systems_to_multiple_base_sets() { - let mut schedule = Schedule::new(); - schedule.add_systems( - (make_function_system(0), make_function_system(1)) - .in_base_set(Base::A) - .in_base_set(Base::B), - ); - } - - #[test] - fn disallow_multiple_base_sets() { - let mut world = World::new(); - - let mut schedule = Schedule::new(); - schedule - .configure_set(Normal::X.in_base_set(Base::A)) - .configure_set(Normal::Y.in_base_set(Base::B)) - .add_system(named_system.in_set(Normal::X).in_set(Normal::Y)); - - let result = schedule.initialize(&mut world); - assert!(matches!( - result, - Err(ScheduleBuildError::SystemInMultipleBaseSets { .. }) - )); - - let mut schedule = Schedule::new(); - schedule - .configure_set(Normal::X.in_base_set(Base::A)) - .configure_set(Normal::Y.in_base_set(Base::B).in_set(Normal::X)); - - let result = schedule.initialize(&mut world); - assert!(matches!( - result, - Err(ScheduleBuildError::SetInMultipleBaseSets { .. }) - )); - } - - #[test] - fn allow_same_base_sets() { - let mut world = World::new(); - - let mut schedule = Schedule::new(); - schedule - .configure_set(Normal::X.in_base_set(Base::A)) - .configure_set(Normal::Y.in_base_set(Base::A)) - .add_system(named_system.in_set(Normal::X).in_set(Normal::Y)); - - let result = schedule.initialize(&mut world); - assert!(matches!(result, Ok(()))); - - let mut schedule = Schedule::new(); - schedule - .configure_set(Normal::X.in_base_set(Base::A)) - .configure_set(Normal::Y.in_base_set(Base::A).in_set(Normal::X)); - - let result = schedule.initialize(&mut world); - assert!(matches!(result, Ok(()))); - } - - #[test] - fn default_base_set_ordering() { - let mut world = World::default(); - let mut schedule = Schedule::default(); - - world.init_resource::(); - - schedule - .set_default_base_set(Base::A) - .configure_set(Base::A.before(Base::B)) - .add_systems(( - make_function_system(0).in_base_set(Base::B), - make_function_system(1), - )); - schedule.run(&mut world); - - assert_eq!(world.resource::().0, vec![1, 0]); - } - } } diff --git a/crates/bevy_ecs/src/schedule/schedule.rs b/crates/bevy_ecs/src/schedule/schedule.rs index 2f7521351076e..89d5675674d6d 100644 --- a/crates/bevy_ecs/src/schedule/schedule.rs +++ b/crates/bevy_ecs/src/schedule/schedule.rs @@ -183,12 +183,6 @@ impl Schedule { } } - pub fn set_default_base_set(&mut self, default_base_set: impl SystemSet) -> &mut Self { - self.graph - .set_default_base_set(Some(Box::new(default_base_set))); - self - } - /// Add a system to the schedule. pub fn add_system(&mut self, system: impl IntoSystemConfig) -> &mut Self { self.graph.add_system(system); @@ -360,15 +354,11 @@ pub enum BaseSetMembership { /// A [`SystemSet`] with metadata, stored in a [`ScheduleGraph`]. struct SystemSetNode { inner: BoxedSystemSet, - base_set_membership: BaseSetMembership, } impl SystemSetNode { pub fn new(set: BoxedSystemSet) -> Self { - Self { - inner: set, - base_set_membership: BaseSetMembership::Uncalculated, - } + Self { inner: set } } pub fn name(&self) -> String { @@ -401,10 +391,6 @@ impl SystemNode { pub fn get_mut(&mut self) -> Option<&mut BoxedSystem> { self.inner.as_mut() } - - pub fn name(&self) -> String { - format!("{:?}", &self.inner) - } } /// Metadata for a [`Schedule`]. @@ -416,7 +402,6 @@ pub struct ScheduleGraph { system_set_conditions: Vec>>, system_set_ids: HashMap, uninit: Vec<(NodeId, usize)>, - maybe_default_base_set: Vec, hierarchy: Dag, dependency: Dag, dependency_flattened: Dag, @@ -426,7 +411,6 @@ pub struct ScheduleGraph { conflicting_systems: Vec<(NodeId, NodeId, Vec)>, changed: bool, settings: ScheduleBuildSettings, - default_base_set: Option, } impl ScheduleGraph { @@ -437,7 +421,6 @@ impl ScheduleGraph { system_sets: Vec::new(), system_set_conditions: Vec::new(), system_set_ids: HashMap::new(), - maybe_default_base_set: Vec::new(), uninit: Vec::new(), hierarchy: Dag::new(), dependency: Dag::new(), @@ -448,7 +431,6 @@ impl ScheduleGraph { conflicting_systems: Vec::new(), changed: false, settings: default(), - default_base_set: None, } } @@ -518,17 +500,14 @@ impl ScheduleGraph { /// Returns an iterator over all system sets in this schedule. /// /// Note that the [`BaseSetMembership`] will only be initialized after [`ScheduleGraph::build_schedule`] is called. - pub fn system_sets( - &self, - ) -> impl Iterator { + pub fn system_sets(&self) -> impl Iterator { self.system_set_ids.iter().map(|(_, node_id)| { let set_node = &self.system_sets[node_id.index()]; let set = &*set_node.inner; - let base_set_membership = set_node.base_set_membership; let conditions = self.system_set_conditions[node_id.index()] .as_deref() .unwrap_or(&[]); - (*node_id, set, base_set_membership, conditions) + (*node_id, set, conditions) }) } @@ -591,7 +570,7 @@ impl ScheduleGraph { let id = NodeId::System(self.systems.len()); // graph updates are immediate - self.update_graphs(id, graph_info, false)?; + self.update_graphs(id, graph_info)?; // system init has to be deferred (need `&mut World`) self.uninit.push((id, 0)); @@ -639,7 +618,7 @@ impl ScheduleGraph { }; // graph updates are immediate - self.update_graphs(id, graph_info, set.is_base())?; + self.update_graphs(id, graph_info)?; // system init has to be deferred (need `&mut World`) let system_set_conditions = @@ -724,7 +703,6 @@ impl ScheduleGraph { &mut self, id: NodeId, graph_info: GraphInfo, - is_base_set: bool, ) -> Result<(), ScheduleBuildError> { self.check_sets(&id, &graph_info)?; self.check_edges(&id, &graph_info)?; @@ -734,8 +712,6 @@ impl ScheduleGraph { sets, dependencies, ambiguous_with, - base_set, - add_default_base_set, .. } = graph_info; @@ -749,30 +725,6 @@ impl ScheduleGraph { self.dependency.graph.add_node(set); } - // If the current node is not a base set, set the base set if it was configured - if !is_base_set { - if let Some(base_set) = base_set { - let set_id = self.system_set_ids[&base_set]; - self.hierarchy.graph.add_edge(set_id, id, ()); - } else if let Some(default_base_set) = &self.default_base_set { - if add_default_base_set { - match id { - NodeId::System(_) => { - // Queue the default base set. We queue systems instead of adding directly to allow - // sets to define base sets, which will override the default inheritance behavior - self.maybe_default_base_set.push(id); - } - NodeId::Set(_) => { - // Sets should be added automatically because developers explicitly called - // in_default_base_set() - let set_id = self.system_set_ids[default_base_set]; - self.hierarchy.graph.add_edge(set_id, id, ()); - } - } - } - } - } - if !self.dependency.graph.contains_node(id) { self.dependency.graph.add_node(id); } @@ -832,118 +784,6 @@ impl ScheduleGraph { } } - /// Calculates the base set for each node and caches the results on the node - fn calculate_base_sets_and_detect_cycles(&mut self) -> Result<(), ScheduleBuildError> { - let set_ids = (0..self.system_sets.len()).map(NodeId::Set); - let system_ids = (0..self.systems.len()).map(NodeId::System); - let mut visited_sets = vec![false; self.system_sets.len()]; - // reset base set membership, as this can change when the schedule updates - for system in &mut self.systems { - system.base_set_membership = BaseSetMembership::Uncalculated; - } - for system_set in &mut self.system_sets { - system_set.base_set_membership = BaseSetMembership::Uncalculated; - } - for node_id in set_ids.chain(system_ids) { - Self::calculate_base_set( - &self.hierarchy, - &mut self.system_sets, - &mut self.systems, - &mut visited_sets, - node_id, - )?; - } - Ok(()) - } - - fn calculate_base_set( - hierarchy: &Dag, - system_sets: &mut [SystemSetNode], - systems: &mut [SystemNode], - visited_sets: &mut [bool], - node_id: NodeId, - ) -> Result, ScheduleBuildError> { - let base_set_membership = match node_id { - // systems only have - NodeId::System(_) => BaseSetMembership::Uncalculated, - NodeId::Set(index) => { - let set_node = &mut system_sets[index]; - if set_node.inner.is_base() { - set_node.base_set_membership = BaseSetMembership::Some(node_id); - } - set_node.base_set_membership - } - }; - let base_set = match base_set_membership { - BaseSetMembership::None => None, - BaseSetMembership::Some(node_id) => Some(node_id), - BaseSetMembership::Uncalculated => { - let mut base_set: Option = None; - if let NodeId::Set(index) = node_id { - if visited_sets[index] { - return Err(ScheduleBuildError::HierarchyCycle); - } - visited_sets[index] = true; - } - for neighbor in hierarchy - .graph - .neighbors_directed(node_id, Direction::Incoming) - { - if let Some(calculated_base_set) = Self::calculate_base_set( - hierarchy, - system_sets, - systems, - visited_sets, - neighbor, - )? { - if let Some(first_set) = base_set { - if first_set != calculated_base_set { - return Err(match node_id { - NodeId::System(index) => { - ScheduleBuildError::SystemInMultipleBaseSets { - system: systems[index].name(), - first_set: system_sets[first_set.index()].name(), - second_set: system_sets[calculated_base_set.index()] - .name(), - } - } - NodeId::Set(index) => { - ScheduleBuildError::SetInMultipleBaseSets { - set: system_sets[index].name(), - first_set: system_sets[first_set.index()].name(), - second_set: system_sets[calculated_base_set.index()] - .name(), - } - } - }); - } - } - base_set = Some(calculated_base_set); - } - } - - match node_id { - NodeId::System(index) => { - systems[index].base_set_membership = if let Some(base_set) = base_set { - BaseSetMembership::Some(base_set) - } else { - BaseSetMembership::None - }; - } - NodeId::Set(index) => { - system_sets[index].base_set_membership = if let Some(base_set) = base_set { - BaseSetMembership::Some(base_set) - } else { - BaseSetMembership::None - }; - } - } - base_set - } - }; - Ok(base_set) - } - /// Build a [`SystemSchedule`] optimized for scheduler access from the [`ScheduleGraph`]. /// /// This method also @@ -954,27 +794,6 @@ impl ScheduleGraph { &mut self, components: &Components, ) -> Result { - self.calculate_base_sets_and_detect_cycles()?; - - // Add missing base set membership to systems that defaulted to using the - // default base set and weren't added to a set that belongs to a base set. - if let Some(default_base_set) = &self.default_base_set { - let default_set_id = self.system_set_ids[default_base_set]; - for system_id in std::mem::take(&mut self.maybe_default_base_set) { - let system_node = &mut self.systems[system_id.index()]; - if system_node.base_set_membership == BaseSetMembership::None { - self.hierarchy.graph.add_edge(default_set_id, system_id, ()); - system_node.base_set_membership = BaseSetMembership::Some(default_set_id); - } - - debug_assert_ne!( - system_node.base_set_membership, - BaseSetMembership::Uncalculated, - "base set membership should have been calculated" - ); - } - } - // check hierarchy for cycles self.hierarchy.topsort = self .topsort_graph(&self.hierarchy.graph, ReportCycles::Hierarchy) @@ -1340,17 +1159,6 @@ impl ScheduleGraph { Ok(()) } - - fn set_default_base_set(&mut self, set: Option) { - if let Some(set) = set { - self.default_base_set = Some(set.dyn_clone()); - if self.system_set_ids.get(&set).is_none() { - self.add_set(set); - } - } else { - self.default_base_set = None; - } - } } /// Used to select the appropriate reporting function. diff --git a/crates/bevy_ecs/src/schedule/set.rs b/crates/bevy_ecs/src/schedule/set.rs index 23058a3de9fbc..56deb5c398ae8 100644 --- a/crates/bevy_ecs/src/schedule/set.rs +++ b/crates/bevy_ecs/src/schedule/set.rs @@ -23,34 +23,10 @@ pub trait SystemSet: DynHash + Debug + Send + Sync + 'static { None } - /// Returns `true` if this set is a "base system set". Systems - /// can only belong to one base set at a time. Systems and Sets - /// can only be added to base sets using specialized `in_base_set` - /// APIs. This enables "mutually exclusive" behaviors. It also - /// enables schedules to have a "default base set", which can be used - /// to apply default configuration to systems. - fn is_base(&self) -> bool { - false - } - /// Creates a boxed clone of the label corresponding to this system set. fn dyn_clone(&self) -> Box; } -/// A marker trait for `SystemSet` types where [`is_base`] returns `true`. -/// This should only be implemented for types that satisfy this requirement. -/// It is automatically implemented for base set types by `#[derive(SystemSet)]`. -/// -/// [`is_base`]: SystemSet::is_base -pub trait BaseSystemSet: SystemSet {} - -/// A marker trait for `SystemSet` types where [`is_base`] returns `false`. -/// This should only be implemented for types that satisfy this requirement. -/// It is automatically implemented for non-base set types by `#[derive(SystemSet)]`. -/// -/// [`is_base`]: SystemSet::is_base -pub trait FreeSystemSet: SystemSet {} - impl PartialEq for dyn SystemSet { fn eq(&self, other: &Self) -> bool { self.dyn_eq(other.as_dyn_eq()) diff --git a/crates/bevy_gilrs/src/lib.rs b/crates/bevy_gilrs/src/lib.rs index f01171010034f..755b3987837d0 100644 --- a/crates/bevy_gilrs/src/lib.rs +++ b/crates/bevy_gilrs/src/lib.rs @@ -1,7 +1,7 @@ mod converter; mod gilrs_system; -use bevy_app::{App, CoreSet, Plugin, StartupSet}; +use bevy_app::{App, Plugin, PreStartup, PreUpdate}; use bevy_ecs::prelude::*; use bevy_input::InputSystem; use bevy_utils::tracing::error; @@ -20,14 +20,8 @@ impl Plugin for GilrsPlugin { { Ok(gilrs) => { app.insert_non_send_resource(gilrs) - .add_startup_system( - gilrs_event_startup_system.in_base_set(StartupSet::PreStartup), - ) - .add_system( - gilrs_event_system - .before(InputSystem) - .in_base_set(CoreSet::PreUpdate), - ); + .add_system_to(PreStartup, gilrs_event_startup_system) + .add_system_to(PreUpdate, gilrs_event_system.before(InputSystem)); } Err(err) => error!("Failed to start Gilrs. {}", err), } diff --git a/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs b/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs index 557450f9af39d..1281a70c52c4b 100644 --- a/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs +++ b/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use bevy_app::{App, CoreSet, Plugin}; +use bevy_app::{App, Last, Plugin}; use bevy_core::Name; use bevy_ecs::prelude::*; use bevy_log::warn; @@ -96,10 +96,11 @@ impl Default for ValidParentCheckPlugin { impl Plugin for ValidParentCheckPlugin { fn build(&self, app: &mut App) { - app.init_resource::>().add_system( - check_hierarchy_component_has_valid_parent:: - .run_if(resource_equals(ReportHierarchyIssue::::new(true))) - .in_base_set(CoreSet::Last), - ); + app.init_resource::>() + .add_system_to( + Last, + check_hierarchy_component_has_valid_parent:: + .run_if(resource_equals(ReportHierarchyIssue::::new(true))), + ); } } diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index 7fc988171cf56..ae0cb0a096fbd 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -53,18 +53,18 @@ pub struct InputSystem; impl Plugin for InputPlugin { fn build(&self, app: &mut App) { - app.configure_set(InputSystem.in_base_set(CoreSet::PreUpdate)) + app // keyboard .add_event::() .init_resource::>() .init_resource::>() - .add_system(keyboard_input_system.in_set(InputSystem)) + .add_system_to(PreUpdate, keyboard_input_system.in_set(InputSystem)) // mouse .add_event::() .add_event::() .add_event::() .init_resource::>() - .add_system(mouse_button_input_system.in_set(InputSystem)) + .add_system_to(PreUpdate, mouse_button_input_system.in_set(InputSystem)) // gamepad .add_event::() .add_event::() @@ -75,7 +75,8 @@ impl Plugin for InputPlugin { .init_resource::>() .init_resource::>() .init_resource::>() - .add_systems( + .add_systems_to( + PreUpdate, ( gamepad_event_system, gamepad_connection_system.after(gamepad_event_system), @@ -91,7 +92,7 @@ impl Plugin for InputPlugin { // touch .add_event::() .init_resource::() - .add_system(touch_screen_input_system.in_set(InputSystem)); + .add_system_to(PreUpdate, touch_screen_input_system.in_set(InputSystem)); // Register common types app.register_type::(); diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index a55458d802dac..81d227d175b51 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -174,60 +174,56 @@ impl Plugin for PbrPlugin { .init_resource::() .init_resource::() .add_plugin(ExtractResourcePlugin::::default()) - .configure_sets( - ( - SimulationLightSystems::AddClusters, - SimulationLightSystems::AddClustersFlush - .after(SimulationLightSystems::AddClusters) - .before(SimulationLightSystems::AssignLightsToClusters), - SimulationLightSystems::AssignLightsToClusters, - SimulationLightSystems::CheckLightVisibility, - SimulationLightSystems::UpdateDirectionalLightCascades, - SimulationLightSystems::UpdateLightFrusta, - ) - .in_base_set(CoreSet::PostUpdate), + .configure_set_in( + PostUpdate, + SimulationLightSystems::AddClustersFlush + .after(SimulationLightSystems::AddClusters) + .before(SimulationLightSystems::AssignLightsToClusters), ) .add_plugin(FogPlugin) - .add_systems(( - add_clusters.in_set(SimulationLightSystems::AddClusters), - apply_system_buffers.in_set(SimulationLightSystems::AddClustersFlush), - assign_lights_to_clusters - .in_set(SimulationLightSystems::AssignLightsToClusters) - .after(TransformSystem::TransformPropagate) - .after(VisibilitySystems::CheckVisibility) - .after(CameraUpdateSystem), - update_directional_light_cascades - .in_set(SimulationLightSystems::UpdateDirectionalLightCascades) - .after(TransformSystem::TransformPropagate) - .after(CameraUpdateSystem), - update_directional_light_frusta - .in_set(SimulationLightSystems::UpdateLightFrusta) - // This must run after CheckVisibility because it relies on ComputedVisibility::is_visible() - .after(VisibilitySystems::CheckVisibility) - .after(TransformSystem::TransformPropagate) - .after(SimulationLightSystems::UpdateDirectionalLightCascades) - // We assume that no entity will be both a directional light and a spot light, - // so these systems will run independently of one another. - // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. - .ambiguous_with(update_spot_light_frusta), - update_point_light_frusta - .in_set(SimulationLightSystems::UpdateLightFrusta) - .after(TransformSystem::TransformPropagate) - .after(SimulationLightSystems::AssignLightsToClusters), - update_spot_light_frusta - .in_set(SimulationLightSystems::UpdateLightFrusta) - .after(TransformSystem::TransformPropagate) - .after(SimulationLightSystems::AssignLightsToClusters), - check_light_mesh_visibility - .in_set(SimulationLightSystems::CheckLightVisibility) - .after(VisibilitySystems::CalculateBoundsFlush) - .after(TransformSystem::TransformPropagate) - .after(SimulationLightSystems::UpdateLightFrusta) - // NOTE: This MUST be scheduled AFTER the core renderer visibility check - // because that resets entity ComputedVisibility for the first view - // which would override any results from this otherwise - .after(VisibilitySystems::CheckVisibility), - )); + .add_systems_to( + PostUpdate, + ( + add_clusters.in_set(SimulationLightSystems::AddClusters), + apply_system_buffers.in_set(SimulationLightSystems::AddClustersFlush), + assign_lights_to_clusters + .in_set(SimulationLightSystems::AssignLightsToClusters) + .after(TransformSystem::TransformPropagate) + .after(VisibilitySystems::CheckVisibility) + .after(CameraUpdateSystem), + update_directional_light_cascades + .in_set(SimulationLightSystems::UpdateDirectionalLightCascades) + .after(TransformSystem::TransformPropagate) + .after(CameraUpdateSystem), + update_directional_light_frusta + .in_set(SimulationLightSystems::UpdateLightFrusta) + // This must run after CheckVisibility because it relies on ComputedVisibility::is_visible() + .after(VisibilitySystems::CheckVisibility) + .after(TransformSystem::TransformPropagate) + .after(SimulationLightSystems::UpdateDirectionalLightCascades) + // We assume that no entity will be both a directional light and a spot light, + // so these systems will run independently of one another. + // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. + .ambiguous_with(update_spot_light_frusta), + update_point_light_frusta + .in_set(SimulationLightSystems::UpdateLightFrusta) + .after(TransformSystem::TransformPropagate) + .after(SimulationLightSystems::AssignLightsToClusters), + update_spot_light_frusta + .in_set(SimulationLightSystems::UpdateLightFrusta) + .after(TransformSystem::TransformPropagate) + .after(SimulationLightSystems::AssignLightsToClusters), + check_light_mesh_visibility + .in_set(SimulationLightSystems::CheckLightVisibility) + .after(VisibilitySystems::CalculateBoundsFlush) + .after(TransformSystem::TransformPropagate) + .after(SimulationLightSystems::UpdateLightFrusta) + // NOTE: This MUST be scheduled AFTER the core renderer visibility check + // because that resets entity ComputedVisibility for the first view + // which would override any results from this otherwise + .after(VisibilitySystems::CheckVisibility), + ), + ); app.world .resource_mut::>() @@ -250,12 +246,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( + .add_systems_to( + ExtractSchedule, ( render::extract_clusters.in_set(RenderLightSystems::ExtractClusters), render::extract_lights.in_set(RenderLightSystems::ExtractLights), - ) - .in_schedule(ExtractSchedule), + ), ) .add_systems(( render::prepare_lights diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 0072474083164..e89d89650a70b 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -3,7 +3,7 @@ use crate::{ MeshUniform, PrepassPipelinePlugin, PrepassPlugin, RenderLightSystems, SetMeshBindGroup, SetMeshViewBindGroup, Shadow, }; -use bevy_app::{App, IntoSystemAppConfig, Plugin}; +use bevy_app::{App, Plugin}; use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}; use bevy_core_pipeline::{ core_3d::{AlphaMask3d, Opaque3d, Transparent3d}, @@ -199,8 +199,8 @@ where .init_resource::>() .init_resource::>() .init_resource::>>() + .add_system_to(ExtractSchedule, extract_materials::) .add_systems(( - extract_materials::.in_schedule(ExtractSchedule), prepare_materials:: .in_set(RenderSet::Prepare) .after(PrepareAssetSet::PreAssetPrepare), diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index b890de737de49..96c0af91b1621 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -1,4 +1,4 @@ -use bevy_app::{IntoSystemAppConfig, Plugin}; +use bevy_app::Plugin; use bevy_asset::{load_internal_asset, AssetServer, Handle, HandleUntyped}; use bevy_core_pipeline::{ prelude::Camera3d, @@ -129,8 +129,8 @@ where }; render_app + .add_system_to(ExtractSchedule, extract_camera_prepass_phase) .add_systems(( - extract_camera_prepass_phase.in_schedule(ExtractSchedule), prepare_prepass_textures .in_set(RenderSet::Prepare) .after(bevy_render::view::prepare_windows), diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 1faf66bc4c19f..8ad2f5b04e471 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -4,7 +4,7 @@ use crate::{ ViewClusterBindings, ViewFogUniformOffset, ViewLightsUniformOffset, ViewShadowBindings, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS, }; -use bevy_app::{IntoSystemAppConfigs, Plugin}; +use bevy_app::Plugin; use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped}; use bevy_core_pipeline::{ prepass::ViewPrepassTextures, @@ -107,7 +107,7 @@ impl Plugin for MeshRenderPlugin { render_app .init_resource::() .init_resource::() - .add_systems((extract_meshes, extract_skinned_meshes).in_schedule(ExtractSchedule)) + .add_systems_to(ExtractSchedule, (extract_meshes, extract_skinned_meshes)) .add_systems(( prepare_skinned_meshes.in_set(RenderSet::Prepare), queue_mesh_bind_group.in_set(RenderSet::Queue), diff --git a/crates/bevy_render/src/camera/mod.rs b/crates/bevy_render/src/camera/mod.rs index 91ea69d9417c7..c4cadf839d15c 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, RenderSet}; -use bevy_app::{App, IntoSystemAppConfig, Plugin}; +use bevy_app::{App, Plugin}; use bevy_ecs::schedule::IntoSystemConfig; #[derive(Default)] @@ -29,7 +29,7 @@ impl Plugin for CameraPlugin { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app .init_resource::() - .add_system(extract_cameras.in_schedule(ExtractSchedule)) + .add_system_to(ExtractSchedule, extract_cameras) .add_system(sort_cameras.in_set(RenderSet::Prepare)); let camera_driver_node = CameraDriverNode::new(&mut render_app.world); let mut render_graph = render_app.world.resource_mut::(); diff --git a/crates/bevy_render/src/camera/projection.rs b/crates/bevy_render/src/camera/projection.rs index fd82cd72da44e..9c661ff4d3189 100644 --- a/crates/bevy_render/src/camera/projection.rs +++ b/crates/bevy_render/src/camera/projection.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use bevy_app::{App, CoreSchedule, CoreSet, IntoSystemAppConfig, Plugin, StartupSet}; +use bevy_app::{App, Plugin, PostStartup, PostUpdate}; use bevy_ecs::{prelude::*, reflect::ReflectComponent}; use bevy_math::{Mat4, Rect, Vec2}; use bevy_reflect::{ @@ -27,25 +27,24 @@ pub struct CameraUpdateSystem; impl Plugin for CameraProjectionPlugin { fn build(&self, app: &mut App) { app.register_type::() - .edit_schedule(CoreSchedule::Startup, |schedule| { - schedule.configure_set(CameraUpdateSystem.in_base_set(StartupSet::PostStartup)); - }) - .configure_set(CameraUpdateSystem.in_base_set(CoreSet::PostUpdate)) - .add_systems(( + .add_system_to( + PostStartup, crate::camera::camera_system:: - .on_startup() .in_set(CameraUpdateSystem) // We assume that each camera will only have one projection, // so we can ignore ambiguities with all other monomorphizations. // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. .ambiguous_with(CameraUpdateSystem), + ) + .add_system_to( + PostUpdate, crate::camera::camera_system:: .in_set(CameraUpdateSystem) // We assume that each camera will only have one projection, // so we can ignore ambiguities with all other monomorphizations. // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. .ambiguous_with(CameraUpdateSystem), - )); + ); } } diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index 2b70a897a16fc..52b966ed6f662 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, IntoSystemAppConfig, Plugin}; +use bevy_app::{App, 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(extract_visible_components::.in_schedule(ExtractSchedule)); + render_app.add_system_to(ExtractSchedule, extract_visible_components::); } else { - render_app.add_system(extract_components::.in_schedule(ExtractSchedule)); + render_app.add_system_to(ExtractSchedule, extract_components::); } } } diff --git a/crates/bevy_render/src/extract_resource.rs b/crates/bevy_render/src/extract_resource.rs index a1e8b122f0857..f41834c616e5b 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, IntoSystemAppConfig, Plugin}; +use bevy_app::{App, 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(extract_resource::.in_schedule(ExtractSchedule)); + render_app.add_system_to(ExtractSchedule, extract_resource::); } } } diff --git a/crates/bevy_render/src/globals.rs b/crates/bevy_render/src/globals.rs index 6b9fbdbc7f3d2..ea3f021e75a37 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, IntoSystemAppConfigs, Plugin}; +use bevy_app::{App, 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::