From 0c6a83715bb78d16dd8681bb72f33daf008a001a Mon Sep 17 00:00:00 2001 From: Keval Kapdee Date: Fri, 27 Aug 2021 14:00:22 +0100 Subject: [PATCH 01/38] Add SystemConfig and some basic options --- crates/bevy_core/src/time/fixed_timestep.rs | 15 +++-- crates/bevy_ecs/src/schedule/run_criteria.rs | 8 ++- crates/bevy_ecs/src/system/function_system.rs | 8 +++ crates/bevy_ecs/src/system/mod.rs | 2 + crates/bevy_ecs/src/system/system.rs | 4 ++ crates/bevy_ecs/src/system/system_chaining.rs | 8 +++ crates/bevy_ecs/src/system/system_config.rs | 61 +++++++++++++++++++ 7 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 crates/bevy_ecs/src/system/system_config.rs diff --git a/crates/bevy_core/src/time/fixed_timestep.rs b/crates/bevy_core/src/time/fixed_timestep.rs index 3655da70db419..d867443644abb 100644 --- a/crates/bevy_core/src/time/fixed_timestep.rs +++ b/crates/bevy_core/src/time/fixed_timestep.rs @@ -1,12 +1,5 @@ use crate::Time; -use bevy_ecs::{ - archetype::{Archetype, ArchetypeComponentId}, - component::ComponentId, - query::Access, - schedule::ShouldRun, - system::{ConfigurableSystem, IntoSystem, Local, Res, ResMut, System, SystemId}, - world::World, -}; +use bevy_ecs::{archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, schedule::ShouldRun, system::{ConfigurableSystem, IntoSystem, Local, Res, ResMut, System, SystemConfig, SystemId}, world::World}; use bevy_utils::HashMap; use std::borrow::Cow; @@ -51,6 +44,7 @@ impl FixedTimesteps { pub struct FixedTimestep { state: State, internal_system: Box>, + config: SystemConfig, } impl Default for FixedTimestep { @@ -58,6 +52,7 @@ impl Default for FixedTimestep { Self { state: State::default(), internal_system: Box::new(Self::prepare_system.system()), + config: SystemConfig::default(), } } } @@ -197,4 +192,8 @@ impl System for FixedTimestep { fn check_change_tick(&mut self, change_tick: u32) { self.internal_system.check_change_tick(change_tick); } + + fn config(&mut self) -> &mut SystemConfig { + &mut self.config + } } diff --git a/crates/bevy_ecs/src/schedule/run_criteria.rs b/crates/bevy_ecs/src/schedule/run_criteria.rs index 56c43452d3e60..7b9e961ed0978 100644 --- a/crates/bevy_ecs/src/schedule/run_criteria.rs +++ b/crates/bevy_ecs/src/schedule/run_criteria.rs @@ -3,7 +3,7 @@ use crate::{ component::ComponentId, query::Access, schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel}, - system::{BoxedSystem, IntoSystem, System, SystemId}, + system::{BoxedSystem, IntoSystem, System, SystemConfig, SystemId}, world::World, }; use std::borrow::Cow; @@ -399,6 +399,7 @@ where pub struct RunOnce { ran: bool, system_id: SystemId, + system_config: SystemConfig, archetype_component_access: Access, component_access: Access, } @@ -408,6 +409,7 @@ impl Default for RunOnce { Self { ran: false, system_id: SystemId::new(), + system_config: SystemConfig::default(), archetype_component_access: Default::default(), component_access: Default::default(), } @@ -454,4 +456,8 @@ impl System for RunOnce { fn initialize(&mut self, _world: &mut World) {} fn check_change_tick(&mut self, _change_tick: u32) {} + + fn config(&mut self) -> &mut SystemConfig { + &mut self.system_config + } } diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index c37653c078567..c6e28727cdb2f 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -11,10 +11,13 @@ use crate::{ use bevy_ecs_macros::all_tuples; use std::{borrow::Cow, marker::PhantomData}; +use super::SystemConfig; + /// The metadata of a [`System`]. pub struct SystemMeta { pub(crate) id: SystemId, pub(crate) name: Cow<'static, str>, + pub(crate) config: SystemConfig, pub(crate) component_access_set: FilteredAccessSet, pub(crate) archetype_component_access: Access, // NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent @@ -27,6 +30,7 @@ impl SystemMeta { fn new() -> Self { Self { name: std::any::type_name::().into(), + config: SystemConfig::default(), archetype_component_access: Access::default(), component_access_set: FilteredAccessSet::default(), is_send: true, @@ -403,6 +407,10 @@ where self.system_meta.name.as_ref(), ); } + + fn config(&mut self) -> &mut SystemConfig { + &mut self.system_meta.config + } } /// A trait implemented for all functions that can be used as [`System`]s. diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index 8f0172af97a59..ebc90b80a1ff6 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -4,6 +4,7 @@ mod function_system; mod query; #[allow(clippy::module_inception)] mod system; +mod system_config; mod system_chaining; mod system_param; @@ -12,6 +13,7 @@ pub use exclusive_system::*; pub use function_system::*; pub use query::*; pub use system::*; +pub use system_config::*; pub use system_chaining::*; pub use system_param::*; diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index eabf476730340..34b8c2933b824 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -8,6 +8,8 @@ use crate::{ }; use std::borrow::Cow; +use super::system_config::SystemConfig; + /// A [`System`] identifier. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct SystemId(pub usize); @@ -69,6 +71,8 @@ pub trait System: Send + Sync + 'static { /// Initialize the system. fn initialize(&mut self, _world: &mut World); fn check_change_tick(&mut self, change_tick: u32); + + fn config(&mut self) -> &mut SystemConfig; } /// A convenience type alias for a boxed [`System`] trait object. diff --git a/crates/bevy_ecs/src/system/system_chaining.rs b/crates/bevy_ecs/src/system/system_chaining.rs index 736bf066331ea..5b88b846b5e68 100644 --- a/crates/bevy_ecs/src/system/system_chaining.rs +++ b/crates/bevy_ecs/src/system/system_chaining.rs @@ -7,6 +7,8 @@ use crate::{ }; use std::borrow::Cow; +use super::SystemConfig; + /// A [`System`] that chains two systems together, creating a new system that routes the output of /// the first system into the input of the second system, yielding the output of the second system. /// @@ -49,6 +51,7 @@ pub struct ChainSystem { system_b: SystemB, name: Cow<'static, str>, id: SystemId, + config: SystemConfig, component_access: Access, archetype_component_access: Access, } @@ -110,6 +113,10 @@ impl> System for ChainSystem self.system_a.check_change_tick(change_tick); self.system_b.check_change_tick(change_tick); } + + fn config(&mut self) -> &mut SystemConfig { + &mut self.config + } } /// An extension trait providing the [`IntoChainSystem::chain`] method for convenient [`System`] @@ -139,6 +146,7 @@ where let system_b = system.system(); ChainSystem { name: Cow::Owned(format!("Chain({}, {})", system_a.name(), system_b.name())), + config: SystemConfig::default(), system_a, system_b, archetype_component_access: Default::default(), diff --git a/crates/bevy_ecs/src/system/system_config.rs b/crates/bevy_ecs/src/system/system_config.rs new file mode 100644 index 0000000000000..5b0e22fa0471a --- /dev/null +++ b/crates/bevy_ecs/src/system/system_config.rs @@ -0,0 +1,61 @@ +use crate::schedule::BoxedStageLabel; +use crate::schedule::BoxedSystemLabel; +use crate::schedule::StageLabel; +use crate::schedule::SystemLabel; + +use super::System; + +#[derive(Default)] +pub struct SystemConfig { + labels: Vec, + before: Vec, + after: Vec, + stages: Vec, +} + +impl SystemConfig { + pub(crate) fn add_label(&mut self, label: impl SystemLabel) { + self.labels.push(Box::new(label)); + } + pub(crate) fn add_before(&mut self, label: impl SystemLabel) { + self.before.push(Box::new(label)); + } + pub(crate) fn add_after(&mut self, label: impl SystemLabel) { + self.after.push(Box::new(label)); + } + pub(crate) fn add_to_stage(&mut self, label: impl StageLabel) { + self.stages.push(Box::new(label)); + } +} + +trait ScheduleSystem { + fn label(&mut self, label: impl SystemLabel) -> &mut Self; + fn before(&mut self, label: impl SystemLabel) -> &mut Self; + fn after(&mut self, label: impl SystemLabel) -> &mut Self; +} + +impl ScheduleSystem for T { + fn label(&mut self, label: impl SystemLabel) -> &mut Self { + self.config().add_label(label); + self + } + fn before(&mut self, label: impl SystemLabel) -> &mut Self { + self.config().add_before(label); + self + } + fn after(&mut self, label: impl SystemLabel) -> &mut Self { + self.config().add_after(label); + self + } +} + +pub trait StageSystem { + fn add_to_stage(&mut self, label: impl StageLabel) -> &mut Self; +} + +impl StageSystem for T { + fn add_to_stage(&mut self, label: impl StageLabel) -> &mut Self { + self.config().add_to_stage(label); + self + } +} From 569513cf836549a19cc4fb7545f1e688076dd942 Mon Sep 17 00:00:00 2001 From: Keval Kapdee Date: Fri, 27 Aug 2021 14:28:46 +0100 Subject: [PATCH 02/38] Cargo format --- crates/bevy_core/src/time/fixed_timestep.rs | 9 ++++++++- crates/bevy_ecs/src/system/mod.rs | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/bevy_core/src/time/fixed_timestep.rs b/crates/bevy_core/src/time/fixed_timestep.rs index d867443644abb..8bcb45f28db24 100644 --- a/crates/bevy_core/src/time/fixed_timestep.rs +++ b/crates/bevy_core/src/time/fixed_timestep.rs @@ -1,5 +1,12 @@ use crate::Time; -use bevy_ecs::{archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, schedule::ShouldRun, system::{ConfigurableSystem, IntoSystem, Local, Res, ResMut, System, SystemConfig, SystemId}, world::World}; +use bevy_ecs::{ + archetype::{Archetype, ArchetypeComponentId}, + component::ComponentId, + query::Access, + schedule::ShouldRun, + system::{ConfigurableSystem, IntoSystem, Local, Res, ResMut, System, SystemConfig, SystemId}, + world::World, +}; use bevy_utils::HashMap; use std::borrow::Cow; diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index ebc90b80a1ff6..ea5f77a3c5596 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -4,8 +4,8 @@ mod function_system; mod query; #[allow(clippy::module_inception)] mod system; -mod system_config; mod system_chaining; +mod system_config; mod system_param; pub use commands::*; @@ -13,8 +13,8 @@ pub use exclusive_system::*; pub use function_system::*; pub use query::*; pub use system::*; -pub use system_config::*; pub use system_chaining::*; +pub use system_config::*; pub use system_param::*; #[cfg(test)] From 983a2be32b13e302299c5c9b5313532bd2549aaf Mon Sep 17 00:00:00 2001 From: Keval Kapdee Date: Sat, 28 Aug 2021 21:20:11 +0100 Subject: [PATCH 03/38] System Builder Rework - In Progress --- crates/bevy_app/src/app.rs | 100 +---- crates/bevy_app/src/lib.rs | 2 + crates/bevy_app/src/startup_system.rs | 22 ++ crates/bevy_core/src/lib.rs | 6 +- crates/bevy_ecs/src/lib.rs | 14 +- crates/bevy_ecs/src/schedule/mod.rs | 86 +++-- crates/bevy_ecs/src/schedule/run_criteria.rs | 11 +- crates/bevy_ecs/src/schedule/stage.rs | 231 ++++++----- crates/bevy_ecs/src/schedule/state.rs | 2 +- .../bevy_ecs/src/schedule/system_container.rs | 49 +-- .../src/schedule/system_descriptor.rs | 364 ------------------ crates/bevy_ecs/src/schedule/system_set.rs | 113 ++---- .../bevy_ecs/src/system/exclusive_system.rs | 55 ++- crates/bevy_ecs/src/system/function_system.rs | 7 +- crates/bevy_ecs/src/system/mod.rs | 6 +- crates/bevy_ecs/src/system/system.rs | 4 +- crates/bevy_ecs/src/system/system_chaining.rs | 13 +- crates/bevy_ecs/src/system/system_config.rs | 182 +++++++-- 18 files changed, 531 insertions(+), 736 deletions(-) create mode 100644 crates/bevy_app/src/startup_system.rs delete mode 100644 crates/bevy_ecs/src/schedule/system_descriptor.rs diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 4b9a71812f083..31913a7bcc745 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1,10 +1,9 @@ use crate::{CoreStage, Events, Plugin, PluginGroup, PluginGroupBuilder, StartupStage}; use bevy_ecs::{ component::{Component, ComponentDescriptor}, - prelude::{FromWorld, IntoExclusiveSystem}, - schedule::{ - IntoSystemDescriptor, RunOnce, Schedule, Stage, StageLabel, State, SystemSet, SystemStage, - }, + prelude::{FromWorld, IntoExclusiveSystem, System}, + schedule::{RunOnce, Schedule, Stage, StageLabel, State, SystemSet, SystemStage}, + system::IntoSystem, world::World, }; use bevy_utils::tracing::debug; @@ -50,7 +49,7 @@ impl Default for App { app.add_default_stages() .add_event::() - .add_system_to_stage(CoreStage::Last, World::clear_trackers.exclusive_system()); + .add_exclusive(World::clear_trackers.stage(CoreStage::Last)); #[cfg(feature = "bevy_ci_testing")] { @@ -203,86 +202,27 @@ impl App { /// App::new() /// .add_system(my_system); /// ``` - pub fn add_system(&mut self, system: impl IntoSystemDescriptor) -> &mut Self { - self.add_system_to_stage(CoreStage::Update, system) - } - - pub fn add_system_set(&mut self, system_set: SystemSet) -> &mut Self { - self.add_system_set_to_stage(CoreStage::Update, system_set) - } - - pub fn add_system_to_stage( - &mut self, - stage_label: impl StageLabel, - system: impl IntoSystemDescriptor, - ) -> &mut Self { - self.schedule.add_system_to_stage(stage_label, system); - self - } - - pub fn add_system_set_to_stage( - &mut self, - stage_label: impl StageLabel, - system_set: SystemSet, - ) -> &mut Self { + pub fn add_system(&mut self, system: impl IntoSystem<(), (), Param>) -> &mut Self { self.schedule - .add_system_set_to_stage(stage_label, system_set); - self - } - - /// Adds a system that is run once at application startup - /// - /// Startup systems run exactly once BEFORE all other systems. These are generally used for - /// app initialization code (ex: adding entities and resources). - /// - /// * For adding a system that runs for every frame, see [`App::add_system`]. - /// * For adding a system to specific stage, see [`App::add_system_to_stage`]. - /// - /// ## Example - /// ``` - /// # use bevy_app::prelude::*; - /// # use bevy_ecs::prelude::*; - /// # - /// fn my_startup_system(_commands: Commands) { - /// println!("My startup system"); - /// } - /// - /// App::new() - /// .add_startup_system(my_startup_system); - /// ``` - pub fn add_startup_system( - &mut self, - system: impl IntoSystemDescriptor, - ) -> &mut Self { - self.add_startup_system_to_stage(StartupStage::Startup, system) - } - - pub fn add_startup_system_set(&mut self, system_set: SystemSet) -> &mut Self { - self.add_startup_system_set_to_stage(StartupStage::Startup, system_set) + .add_system(if let Some(_) = system.system().config().stage { + system + } else { + system.stage(CoreStage::Update) + }); + &mut self } - pub fn add_startup_system_to_stage( - &mut self, - stage_label: impl StageLabel, - system: impl IntoSystemDescriptor, - ) -> &mut Self { - self.schedule - .stage(CoreStage::Startup, |schedule: &mut Schedule| { - schedule.add_system_to_stage(stage_label, system) - }); - self + pub fn add_system_set(&mut self, system_set: SystemSet) -> &mut Self { + self.schedule.add_system_set(system_set); + &mut self } - pub fn add_startup_system_set_to_stage( + pub fn add_exclusive( &mut self, - stage_label: impl StageLabel, - system_set: SystemSet, + system: impl IntoExclusiveSystem, ) -> &mut Self { - self.schedule - .stage(CoreStage::Startup, |schedule: &mut Schedule| { - schedule.add_system_set_to_stage(stage_label, system_set) - }); - self + self.schedule.add_exclusive(system); + &mut self } /// Adds a new [State] with the given `initial` value. @@ -307,7 +247,7 @@ impl App { T: Component + Debug + Clone + Eq + Hash, { self.insert_resource(State::new(initial)) - .add_system_set_to_stage(stage, State::::get_driver()) + .add_system_set(State::::get_driver().stage(stage)) } pub fn add_default_stages(&mut self) -> &mut Self { @@ -335,7 +275,7 @@ impl App { T: Component, { self.insert_resource(Events::::default()) - .add_system_to_stage(CoreStage::First, Events::::update_system) + .add_system(Events::::update_system.stage(CoreStage::First)) } /// Inserts a resource to the current [App] and overwrites any resource previously added of the same type. diff --git a/crates/bevy_app/src/lib.rs b/crates/bevy_app/src/lib.rs index 7349ce86b1055..ead8be00dcf58 100644 --- a/crates/bevy_app/src/lib.rs +++ b/crates/bevy_app/src/lib.rs @@ -2,6 +2,7 @@ mod app; mod plugin; mod plugin_group; mod schedule_runner; +mod startup_system; #[cfg(feature = "bevy_ci_testing")] mod ci_testing; @@ -12,6 +13,7 @@ pub use bevy_ecs::event::*; pub use plugin::*; pub use plugin_group::*; pub use schedule_runner::*; +pub use startup_system::*; pub mod prelude { #[doc(hidden)] diff --git a/crates/bevy_app/src/startup_system.rs b/crates/bevy_app/src/startup_system.rs new file mode 100644 index 0000000000000..2bf0335fa362c --- /dev/null +++ b/crates/bevy_app/src/startup_system.rs @@ -0,0 +1,22 @@ +use bevy_ecs::{ + prelude::{ExclusiveSystem, System}, + system::{ExclusiveSystemKind, ParallelSystemKind, StageConfig}, +}; + +use crate::StartupStage; + +trait StartupSystem { + fn startup(self) -> Self; +} + +impl StartupSystem for T { + fn startup(mut self) -> Self { + self.stage(StartupStage::Startup) + } +} + +impl StartupSystem for T { + fn startup(mut self) -> Self { + self.stage(StartupStage::Startup) + } +} diff --git a/crates/bevy_core/src/lib.rs b/crates/bevy_core/src/lib.rs index 5af6bc88f297e..4c473e414a484 100644 --- a/crates/bevy_core/src/lib.rs +++ b/crates/bevy_core/src/lib.rs @@ -18,11 +18,7 @@ pub mod prelude { } use bevy_app::prelude::*; -use bevy_ecs::{ - entity::Entity, - schedule::{ExclusiveSystemDescriptorCoercion, SystemLabel}, - system::IntoExclusiveSystem, -}; +use bevy_ecs::{entity::Entity, schedule::SystemLabel, system::IntoExclusiveSystem}; use bevy_utils::HashSet; use std::ops::Range; diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index c51925b710569..5bfe52255002a 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + pub mod archetype; pub mod bundle; pub mod change_detection; @@ -24,13 +26,15 @@ pub mod prelude { event::{EventReader, EventWriter}, query::{Added, ChangeTrackers, Changed, Or, QueryState, With, Without}, schedule::{ - AmbiguitySetLabel, ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion, - RunCriteria, RunCriteriaDescriptorCoercion, RunCriteriaLabel, RunCriteriaPiping, - Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, SystemStage, + AmbiguitySetLabel, RunCriteria, RunCriteriaDescriptorCoercion, RunCriteriaLabel, + RunCriteriaPiping, Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, + SystemStage, }, system::{ - Commands, ConfigurableSystem, In, IntoChainSystem, IntoExclusiveSystem, IntoSystem, - Local, NonSend, NonSendMut, Query, QuerySet, RemovedComponents, Res, ResMut, System, + AmbiguityConfig, Commands, ConfigurableSystem, ExclusiveSystem, In, IntoChainSystem, + IntoExclusiveSystem, IntoSystem, Local, NonSend, NonSendMut, Query, QuerySet, + RemovedComponents, Res, ResMut, RunCriteraConfig, ScheduleConfig, StageConfig, System, + SystemConfig, }, world::{FromWorld, Mut, World}, }; diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index a1c386446c5d0..d573615d16156 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -6,7 +6,6 @@ mod run_criteria; mod stage; mod state; mod system_container; -mod system_descriptor; mod system_set; pub use executor::*; @@ -17,12 +16,15 @@ pub use run_criteria::*; pub use stage::*; pub use state::*; pub use system_container::*; -pub use system_descriptor::*; pub use system_set::*; use std::fmt::Debug; -use crate::{system::System, world::World}; +use crate::{ + prelude::{ExclusiveSystem, IntoExclusiveSystem, IntoSystem}, + system::System, + world::World, +}; use bevy_utils::HashMap; #[derive(Default)] @@ -63,14 +65,14 @@ impl Schedule { self } - pub fn with_system_in_stage( - mut self, - stage_label: impl StageLabel, - system: impl IntoSystemDescriptor, - ) -> Self { - self.add_system_to_stage(stage_label, system); - self - } + // pub fn with_system_in_stage( + // mut self, + // stage_label: impl StageLabel, + // system: impl IntoSystem<(), (), Param> + StageSystem, + // ) -> Self { + // self.add_system(system.stage(stage_label)); + // self + // } pub fn set_run_criteria>( &mut self, @@ -138,11 +140,10 @@ impl Schedule { self } - pub fn add_system_to_stage( - &mut self, - stage_label: impl StageLabel, - system: impl IntoSystemDescriptor, - ) -> &mut Self { + pub fn add_system(&mut self, system: impl IntoSystem<(), (), Param>) -> &mut Self { + let system = system.system(); + let stage_label = system.config().stage.clone().expect("test"); + // Use a function instead of a closure to ensure that it is codegend inside bevy_ecs instead // of the game. Closures inherit generic parameters from their enclosing function. #[cold] @@ -154,20 +155,57 @@ impl Schedule { } let stage = self - .get_stage_mut::(&stage_label) + .get_stage_mut::(stage_label.as_ref()) .unwrap_or_else(move || stage_not_found(&stage_label)); stage.add_system(system); self } - pub fn add_system_set_to_stage( + pub fn add_system_set(&mut self, system_set: SystemSet) -> &mut Self { + let stage_label = system_set.config().stage.clone().expect("test"); + + // Use a function instead of a closure to ensure that it is codegend inside bevy_ecs instead + // of the game. Closures inherit generic parameters from their enclosing function. + #[cold] + fn stage_not_found(stage_label: &dyn Debug) -> ! { + panic!( + "Stage '{:?}' does not exist or is not a SystemStage", + stage_label + ) + } + + let stage = self + .get_stage_mut::(stage_label.as_ref()) + .unwrap_or_else(move || stage_not_found(&stage_label)); + stage.add_system_set(system_set); + self + } + + pub fn add_exclusive( &mut self, - stage_label: impl StageLabel, - system_set: SystemSet, - ) -> &mut Self { - self.stage(stage_label, |stage: &mut SystemStage| { - stage.add_system_set(system_set) - }) + system: impl IntoExclusiveSystem, + ) -> &mut Self + where + SystemType: ExclusiveSystem, + { + let system = system.exclusive_system(); + let stage_label = system.config().stage.clone().expect("test"); + + // Use a function instead of a closure to ensure that it is codegend inside bevy_ecs instead + // of the game. Closures inherit generic parameters from their enclosing function. + #[cold] + fn stage_not_found(stage_label: &dyn Debug) -> ! { + panic!( + "Stage '{:?}' does not exist or is not a SystemStage", + stage_label + ) + } + + let stage = self + .get_stage_mut::(stage_label.as_ref()) + .unwrap_or_else(move || stage_not_found(&stage_label)); + stage.add_exclusive(system); + self } pub fn stage &mut T>( diff --git a/crates/bevy_ecs/src/schedule/run_criteria.rs b/crates/bevy_ecs/src/schedule/run_criteria.rs index 7b9e961ed0978..bfd15a8f965de 100644 --- a/crates/bevy_ecs/src/schedule/run_criteria.rs +++ b/crates/bevy_ecs/src/schedule/run_criteria.rs @@ -457,7 +457,16 @@ impl System for RunOnce { fn check_change_tick(&mut self, _change_tick: u32) {} - fn config(&mut self) -> &mut SystemConfig { + fn run(&mut self, input: Self::In, world: &mut World) -> Self::Out { + // SAFE: world and resources are exclusively borrowed + unsafe { self.run_unsafe(input, world) } + } + + fn config(&self) -> &SystemConfig { + &self.system_config + } + + fn config_mut(&mut self) -> &mut SystemConfig { &mut self.system_config } } diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index 9d5dda4bdf385..0ba9c6f7b9bd2 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -1,22 +1,26 @@ use crate::{ component::ComponentId, - prelude::IntoSystem, + prelude::{ExclusiveSystem, IntoExclusiveSystem, IntoSystem}, schedule::{ graph_utils::{self, DependencyGraphError}, BoxedRunCriteria, BoxedRunCriteriaLabel, BoxedSystemLabel, DuplicateLabelStrategy, - ExclusiveSystemContainer, GraphNode, InsertionPoint, ParallelExecutor, - ParallelSystemContainer, ParallelSystemExecutor, RunCriteriaContainer, - RunCriteriaDescriptor, RunCriteriaDescriptorOrLabel, RunCriteriaInner, ShouldRun, - SingleThreadedExecutor, SystemContainer, SystemDescriptor, SystemSet, + GraphNode, ParallelExecutor, ParallelSystemContainer, ParallelSystemExecutor, + RunCriteriaContainer, RunCriteriaDescriptor, RunCriteriaDescriptorOrLabel, + RunCriteriaInner, ShouldRun, SingleThreadedExecutor, SystemSet, }, + system::{BoxedExclusiveSystem, BoxedSystem, InsertionPoint}, world::{World, WorldId}, }; -use bevy_utils::{tracing::info, HashMap, HashSet}; +use bevy_utils::{ + tracing::{info, warn}, + HashMap, HashSet, +}; use downcast_rs::{impl_downcast, Downcast}; use fixedbitset::FixedBitSet; use std::fmt::Debug; -use super::IntoSystemDescriptor; +use super::system_container::SystemContainer; +use super::ExclusiveSystemContainer; pub trait Stage: Downcast + Send + Sync { /// Runs the stage; this happens once per update. @@ -107,10 +111,19 @@ impl SystemStage { } } - pub fn single(system: impl IntoSystemDescriptor) -> Self { + pub fn single(system: impl IntoSystem<(), (), Param>) -> Self { Self::single_threaded().with_system(system) } + pub fn single_exclusive( + system: impl IntoExclusiveSystem, + ) -> Self + where + SystemType: ExclusiveSystem, + { + Self::single_threaded().with_exclusive(system) + } + pub fn single_threaded() -> Self { Self::new(Box::new(SingleThreadedExecutor::default())) } @@ -133,72 +146,106 @@ impl SystemStage { self.executor = executor; } - pub fn with_system(mut self, system: impl IntoSystemDescriptor) -> Self { + pub fn with_system(mut self, system: impl IntoSystem<(), (), Param>) -> Self { self.add_system(system); self } - pub fn add_system(&mut self, system: impl IntoSystemDescriptor) -> &mut Self { - self.add_system_inner(system.into_descriptor(), None); + pub fn with_exclusive( + mut self, + system: impl IntoExclusiveSystem, + ) -> Self + where + SystemType: ExclusiveSystem, + { + self.add_exclusive(system); + self + } + + pub fn add_system(&mut self, system: impl IntoSystem<(), (), Param>) -> &mut Self { + self.add_system_inner(Box::new(system.system()), None); + self + } + + pub fn add_exclusive( + &mut self, + system: impl IntoExclusiveSystem, + ) -> &mut Self + where + SystemType: ExclusiveSystem, + { + self.add_exclusive_inner(Box::new(system.exclusive_system()), None); self } - fn add_system_inner(&mut self, system: SystemDescriptor, default_run_criteria: Option) { + fn add_system_inner( + &mut self, + system: BoxedSystem<(), ()>, + default_run_criteria: Option, + ) { self.systems_modified = true; - match system { - SystemDescriptor::Exclusive(mut descriptor) => { - let insertion_point = descriptor.insertion_point; - let criteria = descriptor.run_criteria.take(); - let mut container = ExclusiveSystemContainer::from_descriptor(descriptor); - match criteria { - Some(RunCriteriaDescriptorOrLabel::Label(label)) => { - container.run_criteria_label = Some(label); - } - Some(RunCriteriaDescriptorOrLabel::Descriptor(criteria_descriptor)) => { - container.run_criteria_label = criteria_descriptor.label.clone(); - container.run_criteria_index = - Some(self.add_run_criteria_internal(criteria_descriptor)); - } - None => { - container.run_criteria_index = default_run_criteria; - } - } - match insertion_point { - InsertionPoint::AtStart => { - let index = self.exclusive_at_start.len(); - self.uninitialized_at_start.push(index); - self.exclusive_at_start.push(container); - } - InsertionPoint::BeforeCommands => { - let index = self.exclusive_before_commands.len(); - self.uninitialized_before_commands.push(index); - self.exclusive_before_commands.push(container); - } - InsertionPoint::AtEnd => { - let index = self.exclusive_at_end.len(); - self.uninitialized_at_end.push(index); - self.exclusive_at_end.push(container); - } - } + let mut container = ParallelSystemContainer::from_system(system); + match container.system_mut().config_mut().run_criteria.take() { + Some(RunCriteriaDescriptorOrLabel::Label(label)) => { + container.run_criteria_label = Some(label); } - SystemDescriptor::Parallel(mut descriptor) => { - let criteria = descriptor.run_criteria.take(); - let mut container = ParallelSystemContainer::from_descriptor(descriptor); - match criteria { - Some(RunCriteriaDescriptorOrLabel::Label(label)) => { - container.run_criteria_label = Some(label); - } - Some(RunCriteriaDescriptorOrLabel::Descriptor(criteria_descriptor)) => { - container.run_criteria_label = criteria_descriptor.label.clone(); - container.run_criteria_index = - Some(self.add_run_criteria_internal(criteria_descriptor)); - } - None => { - container.run_criteria_index = default_run_criteria; - } - } - self.uninitialized_parallel.push(self.parallel.len()); - self.parallel.push(container); + Some(RunCriteriaDescriptorOrLabel::Descriptor(criteria_descriptor)) => { + container.run_criteria_label = criteria_descriptor.label.clone(); + container.run_criteria_index = + Some(self.add_run_criteria_internal(criteria_descriptor)); + } + None => { + container.run_criteria_index = default_run_criteria; + } + } + if let Some(_) = container.system_mut().config_mut().insertion_point { + warn!("An exclusive system was passed in place of a regular one"); + } + self.uninitialized_parallel.push(self.parallel.len()); + self.parallel.push(container); + } + + fn add_exclusive_inner( + &mut self, + system: BoxedExclusiveSystem, + default_run_criteria: Option, + ) { + self.systems_modified = true; + let mut container = ExclusiveSystemContainer::from_system(system); + match container.system_mut().config_mut().run_criteria.take() { + Some(RunCriteriaDescriptorOrLabel::Label(label)) => { + container.run_criteria_label = Some(label); + } + Some(RunCriteriaDescriptorOrLabel::Descriptor(criteria_descriptor)) => { + container.run_criteria_label = criteria_descriptor.label.clone(); + container.run_criteria_index = + Some(self.add_run_criteria_internal(criteria_descriptor)); + } + None => { + container.run_criteria_index = default_run_criteria; + } + } + + match container + .system_mut() + .config_mut() + .insertion_point + .expect("A regular system was passed in place of an exclusive one") + { + InsertionPoint::AtStart => { + let index = self.exclusive_at_start.len(); + self.uninitialized_at_start.push(index); + self.exclusive_at_start.push(container); + } + InsertionPoint::BeforeCommands => { + let index = self.exclusive_before_commands.len(); + self.uninitialized_before_commands.push(index); + self.exclusive_before_commands.push(container); + } + InsertionPoint::AtEnd => { + let index = self.exclusive_at_end.len(); + self.uninitialized_at_end.push(index); + self.exclusive_at_end.push(container); } } } @@ -243,16 +290,12 @@ impl SystemStage { let set_run_criteria_index = run_criteria.and_then(|criteria| { // validate that no systems have criteria for system in systems.iter_mut() { - if let Some(name) = match system { - SystemDescriptor::Exclusive(descriptor) => descriptor - .run_criteria - .is_some() - .then(|| descriptor.system.name()), - SystemDescriptor::Parallel(descriptor) => descriptor - .run_criteria - .is_some() - .then(|| descriptor.system.name()), - } { + if let Some(name) = system + .config() + .run_criteria + .is_some() + .then(|| system.name()) + { panic!( "The system {} has a run criteria, but its `SystemSet` also has a run \ criteria. This is not supported. Consider moving the system into a \ @@ -267,18 +310,9 @@ impl SystemStage { } RunCriteriaDescriptorOrLabel::Label(label) => { for system in systems.iter_mut() { - match system { - SystemDescriptor::Exclusive(descriptor) => { - descriptor.run_criteria = - Some(RunCriteriaDescriptorOrLabel::Label(label.clone())) - } - SystemDescriptor::Parallel(descriptor) => { - descriptor.run_criteria = - Some(RunCriteriaDescriptorOrLabel::Label(label.clone())) - } - } + system.config_mut().run_criteria = + Some(RunCriteriaDescriptorOrLabel::Label(label.clone())) } - None } } @@ -896,11 +930,10 @@ mod tests { entity::Entity, query::{ChangeTrackers, Changed}, schedule::{ - BoxedSystemLabel, ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion, - RunCriteria, RunCriteriaDescriptorCoercion, RunCriteriaPiping, ShouldRun, - SingleThreadedExecutor, Stage, SystemSet, SystemStage, + BoxedSystemLabel, RunCriteria, RunCriteriaDescriptorCoercion, RunCriteriaPiping, + ShouldRun, SingleThreadedExecutor, Stage, SystemSet, SystemStage, }, - system::{In, IntoExclusiveSystem, IntoSystem, Local, Query, ResMut}, + system::{ExclusiveConfig, In, IntoExclusiveSystem, IntoSystem, Local, Query, ResMut}, world::World, }; @@ -926,10 +959,10 @@ mod tests { let mut world = World::new(); world.insert_resource(Vec::::new()); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(0).exclusive_system().at_start()) + .with_exclusive(make_exclusive(0).at_start()) .with_system(make_parallel(1)) - .with_system(make_exclusive(2).exclusive_system().before_commands()) - .with_system(make_exclusive(3).exclusive_system().at_end()); + .with_exclusive(make_exclusive(2).before_commands()) + .with_exclusive(make_exclusive(3).at_end()); stage.run(&mut world); assert_eq!( *world.get_resource_mut::>().unwrap(), @@ -944,10 +977,10 @@ mod tests { world.get_resource_mut::>().unwrap().clear(); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(2).exclusive_system().before_commands()) - .with_system(make_exclusive(3).exclusive_system().at_end()) + .with_exclusive(make_exclusive(2).before_commands()) + .with_exclusive(make_exclusive(3).at_end()) .with_system(make_parallel(1)) - .with_system(make_exclusive(0).exclusive_system().at_start()); + .with_exclusive(make_exclusive(0).at_start()); stage.run(&mut world); assert_eq!( *world.get_resource::>().unwrap(), @@ -984,9 +1017,9 @@ mod tests { let mut world = World::new(); world.insert_resource(Vec::::new()); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(1).exclusive_system().label("1").after("0")) - .with_system(make_exclusive(2).exclusive_system().after("1")) - .with_system(make_exclusive(0).exclusive_system().label("0")); + .with_exclusive(make_exclusive(1).label("1").after("0")) + .with_exclusive(make_exclusive(2).after("1")) + .with_exclusive(make_exclusive(0).label("0")); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); diff --git a/crates/bevy_ecs/src/schedule/state.rs b/crates/bevy_ecs/src/schedule/state.rs index c18b6fecdb202..777afc10e53bd 100644 --- a/crates/bevy_ecs/src/schedule/state.rs +++ b/crates/bevy_ecs/src/schedule/state.rs @@ -4,7 +4,7 @@ use crate::{ RunCriteriaDescriptor, RunCriteriaDescriptorCoercion, RunCriteriaLabel, ShouldRun, SystemSet, }, - system::{ConfigurableSystem, In, IntoChainSystem, Local, Res, ResMut}, + system::{ConfigurableSystem, In, IntoChainSystem, Local, Res, ResMut, RunCriteraConfig}, }; use std::{any::TypeId, fmt::Debug, hash::Hash}; use thiserror::Error; diff --git a/crates/bevy_ecs/src/schedule/system_container.rs b/crates/bevy_ecs/src/schedule/system_container.rs index 68e493da714b5..db07eddc83d91 100644 --- a/crates/bevy_ecs/src/schedule/system_container.rs +++ b/crates/bevy_ecs/src/schedule/system_container.rs @@ -1,11 +1,8 @@ use crate::{ component::ComponentId, query::Access, - schedule::{ - BoxedAmbiguitySetLabel, BoxedRunCriteriaLabel, BoxedSystemLabel, ExclusiveSystemDescriptor, - GraphNode, ParallelSystemDescriptor, - }, - system::{ExclusiveSystem, System}, + schedule::{BoxedAmbiguitySetLabel, BoxedRunCriteriaLabel, BoxedSystemLabel, GraphNode}, + system::{BoxedExclusiveSystem, BoxedSystem, ExclusiveSystem, System}, }; use std::{borrow::Cow, cell::UnsafeCell}; @@ -25,27 +22,19 @@ pub trait SystemContainer: GraphNode