From c2a427f1a38db6b1d9798e631a7da7a8507fe18c Mon Sep 17 00:00:00 2001 From: Alexander Sepity Date: Fri, 19 Feb 2021 00:20:37 +0300 Subject: [PATCH] Non-string labels (#1423 continued) (#1473) Non-string labels --- crates/bevy_app/src/app_builder.rs | 92 ++++++------- crates/bevy_app/src/lib.rs | 40 +++++- crates/bevy_app/src/stage.rs | 23 ---- crates/bevy_app/src/startup_stage.rs | 8 -- crates/bevy_asset/src/assets.rs | 7 +- crates/bevy_asset/src/lib.rs | 34 ++--- crates/bevy_audio/src/lib.rs | 10 +- crates/bevy_core/src/lib.rs | 11 +- .../src/log_diagnostics_plugin.rs | 4 +- crates/bevy_ecs/macros/src/lib.rs | 42 ++++++ crates/bevy_ecs/src/lib.rs | 5 +- crates/bevy_ecs/src/schedule/label.rs | 106 +++++++++++++++ crates/bevy_ecs/src/schedule/mod.rs | 113 ++++++++++------ crates/bevy_ecs/src/schedule/stage.rs | 127 +++++++++--------- .../bevy_ecs/src/schedule/system_container.rs | 49 +++---- .../src/schedule/system_descriptor.rs | 105 ++++++++------- crates/bevy_gilrs/src/lib.rs | 9 +- crates/bevy_input/src/lib.rs | 13 +- crates/bevy_pbr/src/lib.rs | 2 +- crates/bevy_render/src/lib.rs | 71 +++++----- crates/bevy_render/src/render_graph/graph.rs | 11 +- crates/bevy_scene/src/lib.rs | 18 ++- crates/bevy_sprite/src/lib.rs | 20 +-- crates/bevy_text/src/lib.rs | 8 +- crates/bevy_transform/src/lib.rs | 34 +++-- crates/bevy_ui/src/lib.rs | 39 +++--- crates/bevy_wgpu/src/lib.rs | 11 +- examples/2d/texture_atlas.rs | 11 +- examples/ecs/ecs_guide.rs | 37 +++-- examples/ecs/fixed_timestep.rs | 7 +- examples/ecs/removal_detection.rs | 4 +- examples/ecs/state.rs | 17 +-- examples/game/alien_cake_addict.rs | 46 +++++-- examples/input/gamepad_input.rs | 2 +- examples/shader/shader_defs.rs | 2 +- examples/window/multiple_windows.rs | 13 +- 36 files changed, 711 insertions(+), 440 deletions(-) delete mode 100644 crates/bevy_app/src/stage.rs delete mode 100644 crates/bevy_app/src/startup_stage.rs create mode 100644 crates/bevy_ecs/src/schedule/label.rs diff --git a/crates/bevy_app/src/app_builder.rs b/crates/bevy_app/src/app_builder.rs index 1d019696b673e..24a0c377cc96d 100644 --- a/crates/bevy_app/src/app_builder.rs +++ b/crates/bevy_app/src/app_builder.rs @@ -2,11 +2,11 @@ use crate::{ app::{App, AppExit}, event::Events, plugin::Plugin, - stage, startup_stage, PluginGroup, PluginGroupBuilder, + CoreStage, PluginGroup, PluginGroupBuilder, StartupStage, }; use bevy_ecs::{ clear_trackers_system, FromResources, IntoExclusiveSystem, IntoSystem, Resource, Resources, - RunOnce, Schedule, Stage, StateStage, SystemDescriptor, SystemStage, World, + RunOnce, Schedule, Stage, StageLabel, StateStage, SystemDescriptor, SystemStage, World, }; use bevy_utils::tracing::debug; @@ -24,7 +24,7 @@ impl Default for AppBuilder { app_builder .add_default_stages() .add_event::() - .add_system_to_stage(stage::LAST, clear_trackers_system.exclusive_system()); + .add_system_to_stage(CoreStage::Last, clear_trackers_system.exclusive_system()); app_builder } } @@ -54,110 +54,110 @@ impl AppBuilder { self } - pub fn add_stage(&mut self, name: &'static str, stage: S) -> &mut Self { - self.app.schedule.add_stage(name, stage); + pub fn add_stage(&mut self, label: impl StageLabel, stage: S) -> &mut Self { + self.app.schedule.add_stage(label, stage); self } pub fn add_stage_after( &mut self, - target: &'static str, - name: &'static str, + target: impl StageLabel, + label: impl StageLabel, stage: S, ) -> &mut Self { - self.app.schedule.add_stage_after(target, name, stage); + self.app.schedule.add_stage_after(target, label, stage); self } pub fn add_stage_before( &mut self, - target: &'static str, - name: &'static str, + target: impl StageLabel, + label: impl StageLabel, stage: S, ) -> &mut Self { - self.app.schedule.add_stage_before(target, name, stage); + self.app.schedule.add_stage_before(target, label, stage); self } - pub fn add_startup_stage(&mut self, name: &'static str, stage: S) -> &mut Self { + pub fn add_startup_stage(&mut self, label: impl StageLabel, stage: S) -> &mut Self { self.app .schedule - .stage(stage::STARTUP, |schedule: &mut Schedule| { - schedule.add_stage(name, stage) + .stage(CoreStage::Startup, |schedule: &mut Schedule| { + schedule.add_stage(label, stage) }); self } pub fn add_startup_stage_after( &mut self, - target: &'static str, - name: &'static str, + target: impl StageLabel, + label: impl StageLabel, stage: S, ) -> &mut Self { self.app .schedule - .stage(stage::STARTUP, |schedule: &mut Schedule| { - schedule.add_stage_after(target, name, stage) + .stage(CoreStage::Startup, |schedule: &mut Schedule| { + schedule.add_stage_after(target, label, stage) }); self } pub fn add_startup_stage_before( &mut self, - target: &'static str, - name: &'static str, + target: impl StageLabel, + label: impl StageLabel, stage: S, ) -> &mut Self { self.app .schedule - .stage(stage::STARTUP, |schedule: &mut Schedule| { - schedule.add_stage_before(target, name, stage) + .stage(CoreStage::Startup, |schedule: &mut Schedule| { + schedule.add_stage_before(target, label, stage) }); self } pub fn stage &mut T>( &mut self, - name: &str, + label: impl StageLabel, func: F, ) -> &mut Self { - self.app.schedule.stage(name, func); + self.app.schedule.stage(label, func); self } pub fn add_system(&mut self, system: impl Into) -> &mut Self { - self.add_system_to_stage(stage::UPDATE, system) + self.add_system_to_stage(CoreStage::Update, system) } pub fn add_system_to_stage( &mut self, - stage_name: &'static str, + stage_label: impl StageLabel, system: impl Into, ) -> &mut Self { - self.app.schedule.add_system_to_stage(stage_name, system); + self.app.schedule.add_system_to_stage(stage_label, system); self } pub fn add_startup_system(&mut self, system: impl Into) -> &mut Self { - self.add_startup_system_to_stage(startup_stage::STARTUP, system) + self.add_startup_system_to_stage(StartupStage::Startup, system) } pub fn add_startup_system_to_stage( &mut self, - stage_name: &'static str, + stage_label: impl StageLabel, system: impl Into, ) -> &mut Self { self.app .schedule - .stage(stage::STARTUP, |schedule: &mut Schedule| { - schedule.add_system_to_stage(stage_name, system) + .stage(CoreStage::Startup, |schedule: &mut Schedule| { + schedule.add_system_to_stage(stage_label, system) }); self } pub fn on_state_enter( &mut self, - stage: &str, + stage: impl StageLabel, state: T, system: impl Into, ) -> &mut Self { @@ -168,7 +168,7 @@ impl AppBuilder { pub fn on_state_update( &mut self, - stage: &str, + stage: impl StageLabel, state: T, system: impl Into, ) -> &mut Self { @@ -179,7 +179,7 @@ impl AppBuilder { pub fn on_state_exit( &mut self, - stage: &str, + stage: impl StageLabel, state: T, system: impl Into, ) -> &mut Self { @@ -190,20 +190,20 @@ impl AppBuilder { pub fn add_default_stages(&mut self) -> &mut Self { self.add_stage( - stage::STARTUP, + CoreStage::Startup, Schedule::default() .with_run_criteria(RunOnce::default()) - .with_stage(startup_stage::PRE_STARTUP, SystemStage::parallel()) - .with_stage(startup_stage::STARTUP, SystemStage::parallel()) - .with_stage(startup_stage::POST_STARTUP, SystemStage::parallel()), + .with_stage(StartupStage::PreStartup, SystemStage::parallel()) + .with_stage(StartupStage::Startup, SystemStage::parallel()) + .with_stage(StartupStage::PostStartup, SystemStage::parallel()), ) - .add_stage(stage::FIRST, SystemStage::parallel()) - .add_stage(stage::PRE_EVENT, SystemStage::parallel()) - .add_stage(stage::EVENT, SystemStage::parallel()) - .add_stage(stage::PRE_UPDATE, SystemStage::parallel()) - .add_stage(stage::UPDATE, SystemStage::parallel()) - .add_stage(stage::POST_UPDATE, SystemStage::parallel()) - .add_stage(stage::LAST, SystemStage::parallel()) + .add_stage(CoreStage::First, SystemStage::parallel()) + .add_stage(CoreStage::PreEvent, SystemStage::parallel()) + .add_stage(CoreStage::Event, SystemStage::parallel()) + .add_stage(CoreStage::PreUpdate, SystemStage::parallel()) + .add_stage(CoreStage::Update, SystemStage::parallel()) + .add_stage(CoreStage::PostUpdate, SystemStage::parallel()) + .add_stage(CoreStage::Last, SystemStage::parallel()) } pub fn add_event(&mut self) -> &mut Self @@ -211,7 +211,7 @@ impl AppBuilder { T: Send + Sync + 'static, { self.insert_resource(Events::::default()) - .add_system_to_stage(stage::EVENT, Events::::update_system.system()) + .add_system_to_stage(CoreStage::Event, Events::::update_system.system()) } /// 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 3d82bab5b09ba..e278ae119d9f2 100644 --- a/crates/bevy_app/src/lib.rs +++ b/crates/bevy_app/src/lib.rs @@ -1,8 +1,3 @@ -/// The names of the default App stages -pub mod stage; -/// The names of the default App startup stages -pub mod startup_stage; - mod app; mod app_builder; mod event; @@ -23,6 +18,39 @@ pub mod prelude { app::App, app_builder::AppBuilder, event::{EventReader, Events}, - stage, DynamicPlugin, Plugin, PluginGroup, + CoreStage, DynamicPlugin, Plugin, PluginGroup, StartupStage, }; } + +use bevy_ecs::StageLabel; + +/// The names of the default App stages +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +pub enum CoreStage { + /// Runs once at the beginning of the app. + Startup, + /// Name of app stage that runs before all other app stages + First, + /// Name of app stage that runs before EVENT + PreEvent, + /// Name of app stage that updates events. Runs before UPDATE + Event, + /// Name of app stage responsible for performing setup before an update. Runs before UPDATE. + PreUpdate, + /// Name of app stage responsible for doing most app logic. Systems should be registered here by default. + Update, + /// Name of app stage responsible for processing the results of UPDATE. Runs after UPDATE. + PostUpdate, + /// Name of app stage that runs after all other app stages + Last, +} +/// The names of the default App startup stages +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +pub enum StartupStage { + /// Name of app stage that runs once before the startup stage + PreStartup, + /// Name of app stage that runs once when an app starts up + Startup, + /// Name of app stage that runs once after the startup stage + PostStartup, +} diff --git a/crates/bevy_app/src/stage.rs b/crates/bevy_app/src/stage.rs deleted file mode 100644 index fb8eb416307ee..0000000000000 --- a/crates/bevy_app/src/stage.rs +++ /dev/null @@ -1,23 +0,0 @@ -/// Name of the app stage that runs once at the beginning of the app -pub const STARTUP: &str = "startup"; - -/// Name of app stage that runs before all other app stages -pub const FIRST: &str = "first"; - -/// Name of app stage that runs before EVENT -pub const PRE_EVENT: &str = "pre_event"; - -/// Name of app stage that updates events. Runs before UPDATE -pub const EVENT: &str = "event"; - -/// Name of app stage responsible for performing setup before an update. Runs before UPDATE. -pub const PRE_UPDATE: &str = "pre_update"; - -/// Name of app stage responsible for doing most app logic. Systems should be registered here by default. -pub const UPDATE: &str = "update"; - -/// Name of app stage responsible for processing the results of UPDATE. Runs after UPDATE. -pub const POST_UPDATE: &str = "post_update"; - -/// Name of app stage that runs after all other app stages -pub const LAST: &str = "last"; diff --git a/crates/bevy_app/src/startup_stage.rs b/crates/bevy_app/src/startup_stage.rs deleted file mode 100644 index 54804904bdbf9..0000000000000 --- a/crates/bevy_app/src/startup_stage.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Name of app stage that runs once before the startup stage -pub const PRE_STARTUP: &str = "pre_startup"; - -/// Name of app stage that runs once when an app starts up -pub const STARTUP: &str = "startup"; - -/// Name of app stage that runs once after the startup stage -pub const POST_STARTUP: &str = "post_startup"; diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index a9a41117acec2..ba28afb781d34 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -1,5 +1,6 @@ use crate::{ - update_asset_storage_system, Asset, AssetLoader, AssetServer, Handle, HandleId, RefChange, + update_asset_storage_system, Asset, AssetLoader, AssetServer, AssetStage, Handle, HandleId, + RefChange, }; use bevy_app::{prelude::Events, AppBuilder}; use bevy_ecs::{FromResources, IntoSystem, ResMut}; @@ -219,11 +220,11 @@ impl AddAsset for AppBuilder { self.insert_resource(assets) .add_system_to_stage( - super::stage::ASSET_EVENTS, + AssetStage::AssetEvents, Assets::::asset_event_system.system(), ) .add_system_to_stage( - crate::stage::LOAD_ASSETS, + AssetStage::LoadAssets, update_asset_storage_system::.system(), ) .register_type::>() diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index b8f4adbc371ef..3208a5efbee40 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -14,26 +14,27 @@ mod path; pub use asset_server::*; pub use assets::*; -use bevy_ecs::{IntoSystem, SystemStage}; -use bevy_reflect::RegisterTypeBuilder; -use bevy_tasks::IoTaskPool; pub use handle::*; pub use info::*; pub use io::*; pub use loader::*; pub use path::*; -/// The names of asset stages in an App Schedule -pub mod stage { - pub const LOAD_ASSETS: &str = "load_assets"; - pub const ASSET_EVENTS: &str = "asset_events"; -} - pub mod prelude { pub use crate::{AddAsset, AssetEvent, AssetServer, Assets, Handle, HandleUntyped}; } use bevy_app::{prelude::Plugin, AppBuilder}; +use bevy_ecs::{IntoSystem, StageLabel, SystemStage}; +use bevy_reflect::RegisterTypeBuilder; +use bevy_tasks::IoTaskPool; + +/// The names of asset stages in an App Schedule +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +pub enum AssetStage { + LoadAssets, + AssetEvents, +} /// Adds support for Assets to an App. Assets are typed collections with change tracking, which are added as App Resources. /// Examples of assets: textures, sounds, 3d models, maps, scenes @@ -89,18 +90,18 @@ impl Plugin for AssetPlugin { } app.add_stage_before( - bevy_app::stage::PRE_UPDATE, - stage::LOAD_ASSETS, + bevy_app::CoreStage::PreUpdate, + AssetStage::LoadAssets, SystemStage::parallel(), ) .add_stage_after( - bevy_app::stage::POST_UPDATE, - stage::ASSET_EVENTS, + bevy_app::CoreStage::PostUpdate, + AssetStage::AssetEvents, SystemStage::parallel(), ) .register_type::() .add_system_to_stage( - bevy_app::stage::PRE_UPDATE, + bevy_app::CoreStage::PreUpdate, asset_server::free_unused_assets_system.system(), ); @@ -108,6 +109,9 @@ impl Plugin for AssetPlugin { feature = "filesystem_watcher", all(not(target_arch = "wasm32"), not(target_os = "android")) ))] - app.add_system_to_stage(stage::LOAD_ASSETS, io::filesystem_watcher_system.system()); + app.add_system_to_stage( + AssetStage::LoadAssets, + io::filesystem_watcher_system.system(), + ); } } diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index 594c2c78b65ab..c72a43ce02bea 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -2,14 +2,14 @@ mod audio; mod audio_output; mod audio_source; -pub use audio::*; -pub use audio_output::*; -pub use audio_source::*; - pub mod prelude { pub use crate::{Audio, AudioOutput, AudioSource, Decodable}; } +pub use audio::*; +pub use audio_output::*; +pub use audio_source::*; + use bevy_app::prelude::*; use bevy_asset::AddAsset; use bevy_ecs::IntoExclusiveSystem; @@ -25,7 +25,7 @@ impl Plugin for AudioPlugin { .init_asset_loader::() .init_resource::>() .add_system_to_stage( - stage::POST_UPDATE, + CoreStage::PostUpdate, play_queued_audio_system::.exclusive_system(), ); } diff --git a/crates/bevy_core/src/lib.rs b/crates/bevy_core/src/lib.rs index 368889cb6c3b4..12c7b1377cc6d 100644 --- a/crates/bevy_core/src/lib.rs +++ b/crates/bevy_core/src/lib.rs @@ -5,8 +5,6 @@ mod name; mod task_pool_options; mod time; -use std::ops::Range; - use bevy_ecs::IntoSystem; use bevy_reflect::RegisterTypeBuilder; pub use bytes::*; @@ -20,7 +18,8 @@ pub mod prelude { pub use crate::{DefaultTaskPoolOptions, EntityLabels, Labels, Name, Time, Timer}; } -use bevy_app::{prelude::*, startup_stage}; +use bevy_app::prelude::*; +use std::ops::Range; /// Adds core functionality to Apps. #[derive(Default)] @@ -42,8 +41,8 @@ impl Plugin for CorePlugin { .register_type::() .register_type::>() .register_type::() - .add_system_to_stage(stage::FIRST, time_system.system()) - .add_startup_system_to_stage(startup_stage::POST_STARTUP, entity_labels_system.system()) - .add_system_to_stage(stage::POST_UPDATE, entity_labels_system.system()); + .add_system_to_stage(CoreStage::First, time_system.system()) + .add_startup_system_to_stage(StartupStage::PostStartup, entity_labels_system.system()) + .add_system_to_stage(CoreStage::PostUpdate, entity_labels_system.system()); } } diff --git a/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs b/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs index aa09229d03d1b..7b3b3b91757f1 100644 --- a/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs +++ b/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs @@ -37,11 +37,11 @@ impl Plugin for LogDiagnosticsPlugin { if self.debug { app.add_system_to_stage( - stage::POST_UPDATE, + CoreStage::PostUpdate, Self::log_diagnostics_debug_system.system(), ); } else { - app.add_system_to_stage(stage::POST_UPDATE, Self::log_diagnostics_system.system()); + app.add_system_to_stage(CoreStage::PostUpdate, Self::log_diagnostics_system.system()); } } } diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index cbe6e4a1fd053..66a764c0ecc6d 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -466,3 +466,45 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { } }) } + +#[proc_macro_derive(SystemLabel)] +pub fn derive_system_label(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + derive_label(input, Ident::new("SystemLabel", Span::call_site())).into() +} + +#[proc_macro_derive(StageLabel)] +pub fn derive_stage_label(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + derive_label(input, Ident::new("StageLabel", Span::call_site())).into() +} + +#[proc_macro_derive(AmbiguitySetLabel)] +pub fn derive_ambiguity_set_label(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + derive_label(input, Ident::new("AmbiguitySetLabel", Span::call_site())).into() +} + +fn derive_label(input: DeriveInput, label_type: Ident) -> TokenStream2 { + let ident = input.ident; + + let manifest = Manifest::new().unwrap(); + let path_str = if let Some(package) = manifest.find(|name| name == "bevy") { + format!("{}::ecs", package.name) + } else if let Some(package) = manifest.find(|name| name == "bevy_internal") { + format!("{}::ecs", package.name) + } else if let Some(package) = manifest.find(|name| name == "bevy_ecs") { + package.name + } else { + "bevy_ecs".to_string() + }; + let crate_path: Path = syn::parse(path_str.parse::().unwrap()).unwrap(); + + quote! { + impl #crate_path::#label_type for #ident { + fn dyn_clone(&self) -> Box { + Box::new(self.clone()) + } + } + } +} diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index a2aa0aa2d278d..be73d6c0638ab 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -20,7 +20,8 @@ pub mod prelude { SystemSet, SystemStage, }, system::{Commands, ExclusiveSystem, IntoExclusiveSystem, IntoSystem, Query, System}, - Added, Bundle, Changed, Component, Entity, Flags, In, IntoChainSystem, Mut, Mutated, Or, - QuerySet, Ref, RefMut, ShouldRun, With, Without, World, + Added, AmbiguitySetLabel, Bundle, Changed, Component, Entity, Flags, In, IntoChainSystem, + Mut, Mutated, Or, QuerySet, Ref, RefMut, ShouldRun, StageLabel, SystemLabel, With, Without, + World, }; } diff --git a/crates/bevy_ecs/src/schedule/label.rs b/crates/bevy_ecs/src/schedule/label.rs new file mode 100644 index 0000000000000..725c3f80977b5 --- /dev/null +++ b/crates/bevy_ecs/src/schedule/label.rs @@ -0,0 +1,106 @@ +use std::{ + any::Any, + borrow::Cow, + fmt::Debug, + hash::{Hash, Hasher}, +}; + +pub trait DynEq: Any { + fn as_any(&self) -> &dyn Any; + + fn dyn_eq(&self, other: &dyn DynEq) -> bool; +} + +impl DynEq for T +where + T: Any + Eq, +{ + fn as_any(&self) -> &dyn Any { + self + } + + fn dyn_eq(&self, other: &dyn DynEq) -> bool { + if let Some(other) = other.as_any().downcast_ref::() { + return self == other; + } + false + } +} + +pub trait DynHash: DynEq { + fn as_dyn_eq(&self) -> &dyn DynEq; + + fn dyn_hash(&self, state: &mut dyn Hasher); +} + +impl DynHash for T +where + T: DynEq + Hash, +{ + fn as_dyn_eq(&self) -> &dyn DynEq { + self + } + + fn dyn_hash(&self, mut state: &mut dyn Hasher) { + T::hash(self, &mut state); + self.type_id().hash(&mut state); + } +} + +pub trait StageLabel: DynHash + Debug + Send + Sync + 'static { + #[doc(hidden)] + fn dyn_clone(&self) -> Box; +} +pub(crate) type BoxedStageLabel = Box; + +pub trait SystemLabel: DynHash + Debug + Send + Sync + 'static { + #[doc(hidden)] + fn dyn_clone(&self) -> Box; +} +pub(crate) type BoxedSystemLabel = Box; + +pub trait AmbiguitySetLabel: DynHash + Debug + Send + Sync + 'static { + #[doc(hidden)] + fn dyn_clone(&self) -> Box; +} +pub(crate) type BoxedAmbiguitySetLabel = Box; + +macro_rules! impl_label { + ($trait_name:ident) => { + impl PartialEq for dyn $trait_name { + fn eq(&self, other: &Self) -> bool { + self.dyn_eq(other.as_dyn_eq()) + } + } + + impl Eq for dyn $trait_name {} + + impl Hash for dyn $trait_name { + fn hash(&self, state: &mut H) { + self.dyn_hash(state); + } + } + + impl Clone for Box { + fn clone(&self) -> Self { + self.dyn_clone() + } + } + + impl $trait_name for Cow<'static, str> { + fn dyn_clone(&self) -> Box { + Box::new(self.clone()) + } + } + + impl $trait_name for &'static str { + fn dyn_clone(&self) -> Box { + Box::new(<&str>::clone(self)) + } + } + }; +} + +impl_label!(StageLabel); +impl_label!(SystemLabel); +impl_label!(AmbiguitySetLabel); diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 5532c0f4d5c14..81ed8c35d41ff 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -1,6 +1,8 @@ mod executor; mod executor_parallel; +mod label; mod stage; +//mod stageless; mod state; mod system_container; mod system_descriptor; @@ -8,6 +10,7 @@ mod system_set; pub use executor::*; pub use executor_parallel::*; +pub use label::*; pub use stage::*; pub use state::*; pub use system_container::*; @@ -22,24 +25,34 @@ use std::{any::TypeId, borrow::Cow}; #[derive(Default)] pub struct Schedule { - stages: HashMap>, - stage_order: Vec, + stages: HashMap>, + stage_order: Vec, run_criteria: RunCriteria, } impl Schedule { - pub fn with_stage(mut self, name: &str, stage: S) -> Self { - self.add_stage(name, stage); + pub fn with_stage(mut self, label: impl StageLabel, stage: S) -> Self { + self.add_stage(label, stage); self } - pub fn with_stage_after(mut self, target: &str, name: &str, stage: S) -> Self { - self.add_stage_after(target, name, stage); + pub fn with_stage_after( + mut self, + target: impl StageLabel, + label: impl StageLabel, + stage: S, + ) -> Self { + self.add_stage_after(target, label, stage); self } - pub fn with_stage_before(mut self, target: &str, name: &str, stage: S) -> Self { - self.add_stage_before(target, name, stage); + pub fn with_stage_before( + mut self, + target: impl StageLabel, + label: impl StageLabel, + stage: S, + ) -> Self { + self.add_stage_before(target, label, stage); self } @@ -50,10 +63,10 @@ impl Schedule { pub fn with_system_in_stage( mut self, - stage_name: &'static str, + stage_label: impl StageLabel, system: impl Into, ) -> Self { - self.add_system_to_stage(stage_name, system); + self.add_system_to_stage(stage_label, system); self } @@ -65,60 +78,75 @@ impl Schedule { self } - pub fn add_stage(&mut self, name: &str, stage: S) -> &mut Self { - self.stage_order.push(name.to_string()); - let prev = self.stages.insert(name.to_string(), Box::new(stage)); + pub fn add_stage(&mut self, label: impl StageLabel, stage: S) -> &mut Self { + let label: Box = Box::new(label); + self.stage_order.push(label.clone()); + let prev = self.stages.insert(label.clone(), Box::new(stage)); if prev.is_some() { - panic!("Stage already exists: {}.", name); + panic!("Stage already exists: {:?}.", label); } self } - pub fn add_stage_after(&mut self, target: &str, name: &str, stage: S) -> &mut Self { + pub fn add_stage_after( + &mut self, + target: impl StageLabel, + label: impl StageLabel, + stage: S, + ) -> &mut Self { + let label: Box = Box::new(label); + let target = &target as &dyn StageLabel; let target_index = self .stage_order .iter() .enumerate() - .find(|(_i, stage_name)| *stage_name == target) + .find(|(_i, stage_label)| &***stage_label == target) .map(|(i, _)| i) - .unwrap_or_else(|| panic!("Target stage does not exist: {}.", target)); + .unwrap_or_else(|| panic!("Target stage does not exist: {:?}.", target)); - self.stage_order.insert(target_index + 1, name.to_string()); - let prev = self.stages.insert(name.to_string(), Box::new(stage)); + self.stage_order.insert(target_index + 1, label.clone()); + let prev = self.stages.insert(label.clone(), Box::new(stage)); if prev.is_some() { - panic!("Stage already exists: {}.", name); + panic!("Stage already exists: {:?}.", label); } self } - pub fn add_stage_before(&mut self, target: &str, name: &str, stage: S) -> &mut Self { + pub fn add_stage_before( + &mut self, + target: impl StageLabel, + label: impl StageLabel, + stage: S, + ) -> &mut Self { + let label: Box = Box::new(label); + let target = &target as &dyn StageLabel; let target_index = self .stage_order .iter() .enumerate() - .find(|(_i, stage_name)| *stage_name == target) + .find(|(_i, stage_label)| &***stage_label == target) .map(|(i, _)| i) - .unwrap_or_else(|| panic!("Target stage does not exist: {}.", target)); + .unwrap_or_else(|| panic!("Target stage does not exist: {:?}.", target)); - self.stage_order.insert(target_index, name.to_string()); - let prev = self.stages.insert(name.to_string(), Box::new(stage)); + self.stage_order.insert(target_index, label.clone()); + let prev = self.stages.insert(label.clone(), Box::new(stage)); if prev.is_some() { - panic!("Stage already exists: {}.", name); + panic!("Stage already exists: {:?}.", label); } self } pub fn add_system_to_stage( &mut self, - stage_name: &'static str, + stage_label: impl StageLabel, system: impl Into, ) -> &mut Self { let stage = self - .get_stage_mut::(stage_name) - .unwrap_or_else(|| { + .get_stage_mut::(&stage_label) + .unwrap_or_else(move || { panic!( - "Stage '{}' does not exist or is not a SystemStage", - stage_name + "Stage '{:?}' does not exist or is not a SystemStage", + stage_label ) }); stage.add_system(system); @@ -127,35 +155,36 @@ impl Schedule { pub fn stage &mut T>( &mut self, - name: &str, + label: impl StageLabel, func: F, ) -> &mut Self { - let stage = self - .get_stage_mut::(name) - .unwrap_or_else(|| panic!("stage '{}' does not exist or is the wrong type", name)); + let stage = self.get_stage_mut::(&label).unwrap_or_else(move || { + panic!("stage '{:?}' does not exist or is the wrong type", label) + }); func(stage); self } - pub fn get_stage(&self, name: &str) -> Option<&T> { + pub fn get_stage(&self, label: &dyn StageLabel) -> Option<&T> { self.stages - .get(name) + .get(label) .and_then(|stage| stage.downcast_ref::()) } - pub fn get_stage_mut(&mut self, name: &str) -> Option<&mut T> { + pub fn get_stage_mut(&mut self, label: &dyn StageLabel) -> Option<&mut T> { self.stages - .get_mut(name) + .get_mut(label) .and_then(|stage| stage.downcast_mut::()) } pub fn run_once(&mut self, world: &mut World, resources: &mut Resources) { - for name in self.stage_order.iter() { + for label in self.stage_order.iter() { #[cfg(feature = "trace")] - let stage_span = bevy_utils::tracing::info_span!("stage", name = name.as_str()); + let stage_span = + bevy_utils::tracing::info_span!("stage", name = &format!("{:?}", label) as &str); #[cfg(feature = "trace")] let _stage_guard = stage_span.enter(); - let stage = self.stages.get_mut(name).unwrap(); + let stage = self.stages.get_mut(label).unwrap(); stage.run(world, resources); } } diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index cd596ca51c545..c81382636825c 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -8,9 +8,9 @@ use super::{ SingleThreadedExecutor, SystemContainer, }; use crate::{ - InsertionPoint, Resources, RunCriteria, + BoxedSystemLabel, InsertionPoint, Resources, RunCriteria, ShouldRun::{self, *}, - System, SystemDescriptor, SystemSet, World, + System, SystemDescriptor, SystemLabel, SystemSet, World, }; pub trait Stage: Downcast + Send + Sync { @@ -363,8 +363,8 @@ impl SystemStage { } enum DependencyGraphError { - LabelNotFound(Cow<'static, str>), - DuplicateLabel(Cow<'static, str>), + LabelNotFound(Box), + DuplicateLabel(Box), GraphCycles(Vec>), } @@ -394,7 +394,7 @@ fn sort_systems(systems: &mut Vec) -> Result<(), Dependenc fn build_dependency_graph( systems: &[impl SystemContainer], ) -> Result>, DependencyGraphError> { - let mut labels = HashMap::, usize>::default(); + let mut labels = HashMap::::default(); for (label, index) in systems.iter().enumerate().filter_map(|(index, container)| { container .label() @@ -637,7 +637,7 @@ impl Stage for SystemStage { #[cfg(test)] mod tests { - use crate::{prelude::*, SingleThreadedExecutor}; + use crate::{prelude::*, BoxedSystemLabel, SingleThreadedExecutor}; fn make_exclusive(tag: usize) -> impl FnMut(&mut Resources) { move |resources| resources.get_mut::>().unwrap().push(tag) @@ -1130,17 +1130,16 @@ mod tests { #[test] fn ambiguity_detection() { use super::{find_ambiguities, SystemContainer}; - use std::borrow::Cow; fn find_ambiguities_labels( systems: &[impl SystemContainer], - ) -> Vec<(Cow<'static, str>, Cow<'static, str>)> { + ) -> Vec<(BoxedSystemLabel, BoxedSystemLabel)> { find_ambiguities(systems) .drain(..) .map(|(index_a, index_b)| { ( - systems[index_a].display_name(), - systems[index_b].display_name(), + systems[index_a].label().clone().unwrap(), + systems[index_b].label().clone().unwrap(), ) }) .collect() @@ -1173,8 +1172,8 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("1".into(), "4".into())) - || ambiguities.contains(&("4".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("1"))) ); assert_eq!(ambiguities.len(), 1); @@ -1188,8 +1187,8 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("1".into(), "4".into())) - || ambiguities.contains(&("4".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("1"))) ); assert_eq!(ambiguities.len(), 1); @@ -1213,12 +1212,12 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("0".into(), "3".into())) - || ambiguities.contains(&("3".into(), "0".into())) + ambiguities.contains(&(Box::new("0"), Box::new("3"))) + || ambiguities.contains(&(Box::new("3"), Box::new("0"))) ); assert!( - ambiguities.contains(&("1".into(), "4".into())) - || ambiguities.contains(&("4".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("1"))) ); assert_eq!(ambiguities.len(), 2); @@ -1238,8 +1237,8 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("0".into(), "3".into())) - || ambiguities.contains(&("3".into(), "0".into())) + ambiguities.contains(&(Box::new("0"), Box::new("3"))) + || ambiguities.contains(&(Box::new("3"), Box::new("0"))) ); assert_eq!(ambiguities.len(), 1); @@ -1251,8 +1250,8 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("0".into(), "1".into())) - || ambiguities.contains(&("1".into(), "0".into())) + ambiguities.contains(&(Box::new("0"), Box::new("1"))) + || ambiguities.contains(&(Box::new("1"), Box::new("0"))) ); assert_eq!(ambiguities.len(), 1); @@ -1264,8 +1263,8 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("1".into(), "2".into())) - || ambiguities.contains(&("2".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("2"))) + || ambiguities.contains(&(Box::new("2"), Box::new("1"))) ); assert_eq!(ambiguities.len(), 1); @@ -1278,8 +1277,8 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("1".into(), "2".into())) - || ambiguities.contains(&("2".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("2"))) + || ambiguities.contains(&(Box::new("2"), Box::new("1"))) ); assert_eq!(ambiguities.len(), 1); @@ -1302,8 +1301,8 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("1".into(), "2".into())) - || ambiguities.contains(&("2".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("2"))) + || ambiguities.contains(&(Box::new("2"), Box::new("1"))) ); assert_eq!(ambiguities.len(), 1); @@ -1334,28 +1333,28 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("1".into(), "2".into())) - || ambiguities.contains(&("2".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("2"))) + || ambiguities.contains(&(Box::new("2"), Box::new("1"))) ); assert!( - ambiguities.contains(&("1".into(), "3".into())) - || ambiguities.contains(&("3".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("3"))) + || ambiguities.contains(&(Box::new("3"), Box::new("1"))) ); assert!( - ambiguities.contains(&("1".into(), "4".into())) - || ambiguities.contains(&("4".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("1"))) ); assert!( - ambiguities.contains(&("2".into(), "3".into())) - || ambiguities.contains(&("3".into(), "2".into())) + ambiguities.contains(&(Box::new("2"), Box::new("3"))) + || ambiguities.contains(&(Box::new("3"), Box::new("2"))) ); assert!( - ambiguities.contains(&("2".into(), "4".into())) - || ambiguities.contains(&("4".into(), "2".into())) + ambiguities.contains(&(Box::new("2"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("2"))) ); assert!( - ambiguities.contains(&("3".into(), "4".into())) - || ambiguities.contains(&("4".into(), "3".into())) + ambiguities.contains(&(Box::new("3"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("3"))) ); assert_eq!(ambiguities.len(), 6); @@ -1420,12 +1419,12 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.parallel); assert!( - ambiguities.contains(&("1".into(), "4".into())) - || ambiguities.contains(&("4".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("1"))) ); assert!( - ambiguities.contains(&("2".into(), "4".into())) - || ambiguities.contains(&("4".into(), "2".into())) + ambiguities.contains(&(Box::new("2"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("2"))) ); assert_eq!(ambiguities.len(), 2); @@ -1454,28 +1453,28 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.exclusive_at_start); assert!( - ambiguities.contains(&("1".into(), "3".into())) - || ambiguities.contains(&("3".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("3"))) + || ambiguities.contains(&(Box::new("3"), Box::new("1"))) ); assert!( - ambiguities.contains(&("2".into(), "3".into())) - || ambiguities.contains(&("3".into(), "2".into())) + ambiguities.contains(&(Box::new("2"), Box::new("3"))) + || ambiguities.contains(&(Box::new("3"), Box::new("2"))) ); assert!( - ambiguities.contains(&("1".into(), "4".into())) - || ambiguities.contains(&("4".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("1"))) ); assert!( - ambiguities.contains(&("2".into(), "4".into())) - || ambiguities.contains(&("4".into(), "2".into())) + ambiguities.contains(&(Box::new("2"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("2"))) ); assert!( - ambiguities.contains(&("1".into(), "5".into())) - || ambiguities.contains(&("5".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("5"))) + || ambiguities.contains(&(Box::new("5"), Box::new("1"))) ); assert!( - ambiguities.contains(&("2".into(), "5".into())) - || ambiguities.contains(&("5".into(), "2".into())) + ambiguities.contains(&(Box::new("2"), Box::new("5"))) + || ambiguities.contains(&(Box::new("5"), Box::new("2"))) ); assert_eq!(ambiguities.len(), 6); @@ -1491,20 +1490,20 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_labels(&stage.exclusive_at_start); assert!( - ambiguities.contains(&("2".into(), "3".into())) - || ambiguities.contains(&("3".into(), "2".into())) + ambiguities.contains(&(Box::new("2"), Box::new("3"))) + || ambiguities.contains(&(Box::new("3"), Box::new("2"))) ); assert!( - ambiguities.contains(&("1".into(), "4".into())) - || ambiguities.contains(&("4".into(), "1".into())) + ambiguities.contains(&(Box::new("1"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("1"))) ); assert!( - ambiguities.contains(&("2".into(), "4".into())) - || ambiguities.contains(&("4".into(), "2".into())) + ambiguities.contains(&(Box::new("2"), Box::new("4"))) + || ambiguities.contains(&(Box::new("4"), Box::new("2"))) ); assert!( - ambiguities.contains(&("2".into(), "5".into())) - || ambiguities.contains(&("5".into(), "2".into())) + ambiguities.contains(&(Box::new("2"), Box::new("5"))) + || ambiguities.contains(&(Box::new("5"), Box::new("2"))) ); assert_eq!(ambiguities.len(), 4); diff --git a/crates/bevy_ecs/src/schedule/system_container.rs b/crates/bevy_ecs/src/schedule/system_container.rs index a6aa1d3b3cb04..1335639b5db04 100644 --- a/crates/bevy_ecs/src/schedule/system_container.rs +++ b/crates/bevy_ecs/src/schedule/system_container.rs @@ -1,16 +1,19 @@ use std::{borrow::Cow, ptr::NonNull}; -use crate::{ExclusiveSystem, ExclusiveSystemDescriptor, ParallelSystemDescriptor, System}; +use crate::{ + BoxedAmbiguitySetLabel, BoxedSystemLabel, ExclusiveSystem, ExclusiveSystemDescriptor, + ParallelSystemDescriptor, System, +}; pub(super) trait SystemContainer { fn display_name(&self) -> Cow<'static, str>; fn dependencies(&self) -> &[usize]; fn set_dependencies(&mut self, dependencies: impl IntoIterator); fn system_set(&self) -> usize; - fn label(&self) -> &Option>; - fn before(&self) -> &[Cow<'static, str>]; - fn after(&self) -> &[Cow<'static, str>]; - fn ambiguity_sets(&self) -> &[Cow<'static, str>]; + fn label(&self) -> &Option; + fn before(&self) -> &[BoxedSystemLabel]; + fn after(&self) -> &[BoxedSystemLabel]; + fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel]; fn is_compatible(&self, other: &Self) -> bool; } @@ -18,10 +21,10 @@ pub(super) struct ExclusiveSystemContainer { system: Box, dependencies: Vec, set: usize, - label: Option>, - before: Vec>, - after: Vec>, - ambiguity_sets: Vec>, + label: Option, + before: Vec, + after: Vec, + ambiguity_sets: Vec, } impl ExclusiveSystemContainer { @@ -46,7 +49,7 @@ impl SystemContainer for ExclusiveSystemContainer { fn display_name(&self) -> Cow<'static, str> { self.label .as_ref() - .cloned() + .map(|l| Cow::Owned(format!("{:?}", l))) .unwrap_or_else(|| self.system.name()) } @@ -63,19 +66,19 @@ impl SystemContainer for ExclusiveSystemContainer { self.set } - fn label(&self) -> &Option> { + fn label(&self) -> &Option { &self.label } - fn before(&self) -> &[Cow<'static, str>] { + fn before(&self) -> &[BoxedSystemLabel] { &self.before } - fn after(&self) -> &[Cow<'static, str>] { + fn after(&self) -> &[BoxedSystemLabel] { &self.after } - fn ambiguity_sets(&self) -> &[Cow<'static, str>] { + fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] { &self.ambiguity_sets } @@ -89,17 +92,17 @@ pub struct ParallelSystemContainer { pub(crate) should_run: bool, dependencies: Vec, set: usize, - label: Option>, - before: Vec>, - after: Vec>, - ambiguity_sets: Vec>, + label: Option, + before: Vec, + after: Vec, + ambiguity_sets: Vec, } impl SystemContainer for ParallelSystemContainer { fn display_name(&self) -> Cow<'static, str> { self.label .as_ref() - .cloned() + .map(|l| Cow::Owned(format!("{:?}", l))) .unwrap_or_else(|| self.system().name()) } @@ -116,19 +119,19 @@ impl SystemContainer for ParallelSystemContainer { self.set } - fn label(&self) -> &Option> { + fn label(&self) -> &Option { &self.label } - fn before(&self) -> &[Cow<'static, str>] { + fn before(&self) -> &[BoxedSystemLabel] { &self.before } - fn after(&self) -> &[Cow<'static, str>] { + fn after(&self) -> &[BoxedSystemLabel] { &self.after } - fn ambiguity_sets(&self) -> &[Cow<'static, str>] { + fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] { &self.ambiguity_sets } diff --git a/crates/bevy_ecs/src/schedule/system_descriptor.rs b/crates/bevy_ecs/src/schedule/system_descriptor.rs index 39a40a352050e..205033737982b 100644 --- a/crates/bevy_ecs/src/schedule/system_descriptor.rs +++ b/crates/bevy_ecs/src/schedule/system_descriptor.rs @@ -1,5 +1,7 @@ -use crate::{BoxedSystem, ExclusiveSystem, ExclusiveSystemCoerced, ExclusiveSystemFn, System}; -use std::borrow::Cow; +use crate::{ + AmbiguitySetLabel, BoxedAmbiguitySetLabel, BoxedSystem, BoxedSystemLabel, ExclusiveSystem, + ExclusiveSystemCoerced, ExclusiveSystemFn, System, SystemLabel, +}; /// Encapsulates a system and information on when it run in a `SystemStage`. /// @@ -15,14 +17,17 @@ use std::borrow::Cow; /// that they have to run before or after the system with that label using the `before` and `after` methods. /// /// # Example -/// ```rust +/// ``` /// # use bevy_ecs::prelude::*; /// # fn do_something() {} /// # fn do_the_other_thing() {} /// # fn do_something_else() {} +/// #[derive(SystemLabel, Debug, Clone, PartialEq, Eq, Hash)] +/// struct Something; +/// /// SystemStage::parallel() -/// .with_system(do_something.system().label("something")) -/// .with_system(do_the_other_thing.system().after("something")) +/// .with_system(do_something.system().label(Something)) +/// .with_system(do_the_other_thing.system().after(Something)) /// .with_system(do_something_else.exclusive_system().at_end()); /// ``` pub enum SystemDescriptor { @@ -30,6 +35,8 @@ pub enum SystemDescriptor { Exclusive(ExclusiveSystemDescriptor), } +pub struct SystemLabelMarker; + impl From for SystemDescriptor { fn from(descriptor: ParallelSystemDescriptor) -> Self { SystemDescriptor::Parallel(descriptor) @@ -72,10 +79,10 @@ impl From for SystemDescriptor { /// Encapsulates a parallel system and information on when it run in a `SystemStage`. pub struct ParallelSystemDescriptor { pub(crate) system: BoxedSystem<(), ()>, - pub(crate) label: Option>, - pub(crate) before: Vec>, - pub(crate) after: Vec>, - pub(crate) ambiguity_sets: Vec>, + pub(crate) label: Option, + pub(crate) before: Vec, + pub(crate) after: Vec, + pub(crate) ambiguity_sets: Vec, } fn new_parallel_descriptor(system: BoxedSystem<(), ()>) -> ParallelSystemDescriptor { @@ -90,37 +97,37 @@ fn new_parallel_descriptor(system: BoxedSystem<(), ()>) -> ParallelSystemDescrip pub trait ParallelSystemDescriptorCoercion { /// Assigns a label to the system. - fn label(self, label: impl Into>) -> ParallelSystemDescriptor; + fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor; /// Specifies that the system should run before the system with given label. - fn before(self, label: impl Into>) -> ParallelSystemDescriptor; + fn before(self, label: impl SystemLabel) -> ParallelSystemDescriptor; /// Specifies that the system should run after the system with given label. - fn after(self, label: impl Into>) -> ParallelSystemDescriptor; + fn after(self, label: impl SystemLabel) -> ParallelSystemDescriptor; /// Specifies that the system is exempt from execution order ambiguity detection /// with other systems in this set. - fn in_ambiguity_set(self, set: impl Into>) -> ParallelSystemDescriptor; + fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ParallelSystemDescriptor; } impl ParallelSystemDescriptorCoercion for ParallelSystemDescriptor { - fn label(mut self, label: impl Into>) -> ParallelSystemDescriptor { - self.label = Some(label.into()); + fn label(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor { + self.label = Some(Box::new(label)); self } - fn before(mut self, label: impl Into>) -> ParallelSystemDescriptor { - self.before.push(label.into()); + fn before(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor { + self.before.push(Box::new(label)); self } - fn after(mut self, label: impl Into>) -> ParallelSystemDescriptor { - self.after.push(label.into()); + fn after(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor { + self.after.push(Box::new(label)); self } - fn in_ambiguity_set(mut self, set: impl Into>) -> ParallelSystemDescriptor { - self.ambiguity_sets.push(set.into()); + fn in_ambiguity_set(mut self, set: impl AmbiguitySetLabel) -> ParallelSystemDescriptor { + self.ambiguity_sets.push(Box::new(set)); self } } @@ -129,37 +136,37 @@ impl ParallelSystemDescriptorCoercion for S where S: System, { - fn label(self, label: impl Into>) -> ParallelSystemDescriptor { + fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor { new_parallel_descriptor(Box::new(self)).label(label) } - fn before(self, label: impl Into>) -> ParallelSystemDescriptor { + fn before(self, label: impl SystemLabel) -> ParallelSystemDescriptor { new_parallel_descriptor(Box::new(self)).before(label) } - fn after(self, label: impl Into>) -> ParallelSystemDescriptor { + fn after(self, label: impl SystemLabel) -> ParallelSystemDescriptor { new_parallel_descriptor(Box::new(self)).after(label) } - fn in_ambiguity_set(self, set: impl Into>) -> ParallelSystemDescriptor { + fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ParallelSystemDescriptor { new_parallel_descriptor(Box::new(self)).in_ambiguity_set(set) } } impl ParallelSystemDescriptorCoercion for BoxedSystem<(), ()> { - fn label(self, label: impl Into>) -> ParallelSystemDescriptor { + fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor { new_parallel_descriptor(self).label(label) } - fn before(self, label: impl Into>) -> ParallelSystemDescriptor { + fn before(self, label: impl SystemLabel) -> ParallelSystemDescriptor { new_parallel_descriptor(self).before(label) } - fn after(self, label: impl Into>) -> ParallelSystemDescriptor { + fn after(self, label: impl SystemLabel) -> ParallelSystemDescriptor { new_parallel_descriptor(self).after(label) } - fn in_ambiguity_set(self, set: impl Into>) -> ParallelSystemDescriptor { + fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ParallelSystemDescriptor { new_parallel_descriptor(self).in_ambiguity_set(set) } } @@ -174,10 +181,10 @@ pub(crate) enum InsertionPoint { /// Encapsulates an exclusive system and information on when it run in a `SystemStage`. pub struct ExclusiveSystemDescriptor { pub(crate) system: Box, - pub(crate) label: Option>, - pub(crate) before: Vec>, - pub(crate) after: Vec>, - pub(crate) ambiguity_sets: Vec>, + pub(crate) label: Option, + pub(crate) before: Vec, + pub(crate) after: Vec, + pub(crate) ambiguity_sets: Vec, pub(crate) insertion_point: InsertionPoint, } @@ -194,17 +201,17 @@ fn new_exclusive_descriptor(system: Box) -> ExclusiveSystem pub trait ExclusiveSystemDescriptorCoercion { /// Assigns a label to the system. - fn label(self, label: impl Into>) -> ExclusiveSystemDescriptor; + fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor; /// Specifies that the system should run before the system with given label. - fn before(self, label: impl Into>) -> ExclusiveSystemDescriptor; + fn before(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor; /// Specifies that the system should run after the system with given label. - fn after(self, label: impl Into>) -> ExclusiveSystemDescriptor; + fn after(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor; /// Specifies that the system is exempt from execution order ambiguity detection /// with other systems in this set. - fn in_ambiguity_set(self, set: impl Into>) -> ExclusiveSystemDescriptor; + fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ExclusiveSystemDescriptor; /// Specifies that the system should run with other exclusive systems at the start of stage. fn at_start(self) -> ExclusiveSystemDescriptor; @@ -218,23 +225,23 @@ pub trait ExclusiveSystemDescriptorCoercion { } impl ExclusiveSystemDescriptorCoercion for ExclusiveSystemDescriptor { - fn label(mut self, label: impl Into>) -> ExclusiveSystemDescriptor { - self.label = Some(label.into()); + fn label(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor { + self.label = Some(Box::new(label)); self } - fn before(mut self, label: impl Into>) -> ExclusiveSystemDescriptor { - self.before.push(label.into()); + fn before(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor { + self.before.push(Box::new(label)); self } - fn after(mut self, label: impl Into>) -> ExclusiveSystemDescriptor { - self.after.push(label.into()); + fn after(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor { + self.after.push(Box::new(label)); self } - fn in_ambiguity_set(mut self, set: impl Into>) -> ExclusiveSystemDescriptor { - self.ambiguity_sets.push(set.into()); + fn in_ambiguity_set(mut self, set: impl AmbiguitySetLabel) -> ExclusiveSystemDescriptor { + self.ambiguity_sets.push(Box::new(set)); self } @@ -258,19 +265,19 @@ impl ExclusiveSystemDescriptorCoercion for T where T: ExclusiveSystem + 'static, { - fn label(self, label: impl Into>) -> ExclusiveSystemDescriptor { + fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor { new_exclusive_descriptor(Box::new(self)).label(label) } - fn before(self, label: impl Into>) -> ExclusiveSystemDescriptor { + fn before(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor { new_exclusive_descriptor(Box::new(self)).before(label) } - fn after(self, label: impl Into>) -> ExclusiveSystemDescriptor { + fn after(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor { new_exclusive_descriptor(Box::new(self)).after(label) } - fn in_ambiguity_set(self, set: impl Into>) -> ExclusiveSystemDescriptor { + fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ExclusiveSystemDescriptor { new_exclusive_descriptor(Box::new(self)).in_ambiguity_set(set) } diff --git a/crates/bevy_gilrs/src/lib.rs b/crates/bevy_gilrs/src/lib.rs index 6391cfd071f5d..5cf74c9d28516 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::{prelude::*, startup_stage::PRE_STARTUP}; +use bevy_app::prelude::*; use bevy_ecs::IntoExclusiveSystem; use bevy_utils::tracing::error; use gilrs::GilrsBuilder; @@ -20,10 +20,13 @@ impl Plugin for GilrsPlugin { Ok(gilrs) => { app.insert_non_send_resource(gilrs) .add_startup_system_to_stage( - PRE_STARTUP, + StartupStage::PreStartup, gilrs_event_startup_system.exclusive_system(), ) - .add_system_to_stage(stage::PRE_EVENT, gilrs_event_system.exclusive_system()); + .add_system_to_stage( + CoreStage::PreEvent, + gilrs_event_system.exclusive_system(), + ); } Err(err) => error!("Failed to start Gilrs. {}", err), } diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index 776aff8bd168f..bdf91df42d741 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -44,23 +44,20 @@ impl Plugin for InputPlugin { .add_event::() .add_event::() .init_resource::>() - .add_system_to_stage(bevy_app::stage::EVENT, keyboard_input_system.system()) + .add_system_to_stage(CoreStage::Event, keyboard_input_system.system()) .init_resource::>() - .add_system_to_stage(bevy_app::stage::EVENT, mouse_button_input_system.system()) + .add_system_to_stage(CoreStage::Event, mouse_button_input_system.system()) .add_event::() .add_event::() .init_resource::() .init_resource::>() .init_resource::>() .init_resource::>() - .add_system_to_stage(bevy_app::stage::EVENT, gamepad_event_system.system()) - .add_startup_system_to_stage( - bevy_app::startup_stage::STARTUP, - gamepad_event_system.system(), - ) + .add_system_to_stage(CoreStage::Event, gamepad_event_system.system()) + .add_startup_system_to_stage(StartupStage::Startup, gamepad_event_system.system()) .add_event::() .init_resource::() - .add_system_to_stage(bevy_app::stage::EVENT, touch_screen_input_system.system()); + .add_system_to_stage(CoreStage::Event, touch_screen_input_system.system()); } } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 4d217367b7a00..060761b71c102 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -29,7 +29,7 @@ impl Plugin for PbrPlugin { app.add_asset::() .register_type::() .add_system_to_stage( - stage::POST_UPDATE, + CoreStage::PostUpdate, shader::asset_shader_defs_system::.system(), ) .init_resource::(); diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 9248b5358302f..8097cfefd6860 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -33,7 +33,8 @@ pub mod prelude { use crate::prelude::*; use base::Msaa; use bevy_app::prelude::*; -use bevy_asset::AddAsset; +use bevy_asset::{AddAsset, AssetStage}; +use bevy_ecs::StageLabel; use camera::{ ActiveCameras, Camera, OrthographicProjection, PerspectiveProjection, VisibleEntities, }; @@ -53,15 +54,16 @@ use texture::HdrTextureLoader; use texture::ImageTextureLoader; /// The names of "render" App stages -pub mod stage { +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +pub enum RenderStage { /// Stage where render resources are set up - pub const RENDER_RESOURCE: &str = "render_resource"; + RenderResource, /// Stage where Render Graph systems are run. In general you shouldn't add systems to this stage manually. - pub const RENDER_GRAPH_SYSTEMS: &str = "render_graph_systems"; + RenderGraphSystems, // Stage where draw systems are executed. This is generally where Draw components are setup - pub const DRAW: &str = "draw"; - pub const RENDER: &str = "render"; - pub const POST_RENDER: &str = "post_render"; + Draw, + Render, + PostRender, } /// Adds core render types and systems to an App @@ -96,22 +98,30 @@ impl Plugin for RenderPlugin { } app.add_stage_after( - bevy_asset::stage::ASSET_EVENTS, - stage::RENDER_RESOURCE, + AssetStage::AssetEvents, + RenderStage::RenderResource, SystemStage::parallel(), ) .add_stage_after( - stage::RENDER_RESOURCE, - stage::RENDER_GRAPH_SYSTEMS, + RenderStage::RenderResource, + RenderStage::RenderGraphSystems, SystemStage::parallel(), ) .add_stage_after( - stage::RENDER_GRAPH_SYSTEMS, - stage::DRAW, + RenderStage::RenderGraphSystems, + RenderStage::Draw, + SystemStage::parallel(), + ) + .add_stage_after( + RenderStage::Draw, + RenderStage::Render, + SystemStage::parallel(), + ) + .add_stage_after( + RenderStage::Render, + RenderStage::PostRender, SystemStage::parallel(), ) - .add_stage_after(stage::DRAW, stage::RENDER, SystemStage::parallel()) - .add_stage_after(stage::RENDER, stage::POST_RENDER, SystemStage::parallel()) .add_asset::() .add_asset::() .add_asset::() @@ -131,54 +141,53 @@ impl Plugin for RenderPlugin { .register_type::() .init_resource::() .init_resource::() + .init_resource::() .init_resource::() .init_resource::() .init_resource::() + .add_system_to_stage(CoreStage::PreUpdate, draw::clear_draw_system.system()) .add_system_to_stage( - bevy_app::stage::PRE_UPDATE, - draw::clear_draw_system.system(), - ) - .add_system_to_stage( - bevy_app::stage::POST_UPDATE, + CoreStage::PostUpdate, camera::active_cameras_system.system(), ) .add_system_to_stage( - bevy_app::stage::POST_UPDATE, + CoreStage::PostUpdate, camera::camera_system::.system(), ) .add_system_to_stage( - bevy_app::stage::POST_UPDATE, + CoreStage::PostUpdate, camera::camera_system::.system(), ) // registration order matters here. this must come after all camera_system:: systems .add_system_to_stage( - bevy_app::stage::POST_UPDATE, + CoreStage::PostUpdate, camera::visible_entities_system.system(), ) .add_system_to_stage( - stage::RENDER_RESOURCE, + RenderStage::RenderResource, shader::shader_update_system.system(), ) .add_system_to_stage( - stage::RENDER_RESOURCE, + RenderStage::RenderResource, mesh::mesh_resource_provider_system.system(), ) .add_system_to_stage( - stage::RENDER_RESOURCE, + RenderStage::RenderResource, Texture::texture_resource_system.system(), ) .add_system_to_stage( - stage::RENDER_GRAPH_SYSTEMS, + RenderStage::RenderGraphSystems, render_graph::render_graph_schedule_executor_system.exclusive_system(), ) - .add_system_to_stage(stage::DRAW, pipeline::draw_render_pipelines_system.system()) .add_system_to_stage( - stage::POST_RENDER, + RenderStage::Draw, + pipeline::draw_render_pipelines_system.system(), + ) + .add_system_to_stage( + RenderStage::PostRender, shader::clear_shader_defs_system.system(), ); - app.init_resource::(); - if let Some(ref config) = self.base_render_graph_config { let resources = app.resources(); let mut render_graph = resources.get_mut::().unwrap(); diff --git a/crates/bevy_render/src/render_graph/graph.rs b/crates/bevy_render/src/render_graph/graph.rs index 49317c77df243..6a1e14ef7036b 100644 --- a/crates/bevy_render/src/render_graph/graph.rs +++ b/crates/bevy_render/src/render_graph/graph.rs @@ -1,5 +1,5 @@ use super::{Edge, Node, NodeId, NodeLabel, NodeState, RenderGraphError, SlotLabel, SystemNode}; -use bevy_ecs::{Commands, Schedule, SystemStage}; +use bevy_ecs::{Commands, Schedule, StageLabel, SystemStage}; use bevy_utils::HashMap; use std::{borrow::Cow, fmt::Debug}; pub struct RenderGraph { @@ -9,10 +9,13 @@ pub struct RenderGraph { commands: Commands, } +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +struct RenderGraphUpdate; + impl Default for RenderGraph { fn default() -> Self { let mut schedule = Schedule::default(); - schedule.add_stage("update", SystemStage::parallel()); + schedule.add_stage(RenderGraphUpdate, SystemStage::parallel()); Self { nodes: Default::default(), node_names: Default::default(), @@ -41,7 +44,9 @@ impl RenderGraph { T: SystemNode + 'static, { let schedule = self.system_node_schedule.as_mut().unwrap(); - let stage = schedule.get_stage_mut::("update").unwrap(); + let stage = schedule + .get_stage_mut::(&RenderGraphUpdate) + .unwrap(); stage.add_system(node.get_system(&mut self.commands)); self.add_node(name, node) } diff --git a/crates/bevy_scene/src/lib.rs b/crates/bevy_scene/src/lib.rs index c80b0e4ddd6d0..b6e6ffdd5f770 100644 --- a/crates/bevy_scene/src/lib.rs +++ b/crates/bevy_scene/src/lib.rs @@ -5,7 +5,6 @@ mod scene_loader; mod scene_spawner; pub mod serde; -use bevy_ecs::{IntoExclusiveSystem, SystemStage}; pub use command::*; pub use dynamic_scene::*; pub use scene::*; @@ -20,11 +19,15 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_asset::AddAsset; +use bevy_ecs::{IntoExclusiveSystem, StageLabel, SystemStage}; #[derive(Default)] pub struct ScenePlugin; -pub const SCENE_STAGE: &str = "scene"; +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +enum SceneStage { + SceneStage, +} impl Plugin for ScenePlugin { fn build(&self, app: &mut AppBuilder) { @@ -32,7 +35,14 @@ impl Plugin for ScenePlugin { .add_asset::() .init_asset_loader::() .init_resource::() - .add_stage_after(stage::EVENT, SCENE_STAGE, SystemStage::parallel()) - .add_system_to_stage(SCENE_STAGE, scene_spawner_system.exclusive_system()); + .add_stage_after( + CoreStage::Event, + SceneStage::SceneStage, + SystemStage::parallel(), + ) + .add_system_to_stage( + SceneStage::SceneStage, + scene_spawner_system.exclusive_system(), + ); } } diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index bc574243a4bf5..e0ea01cb2a1f3 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -9,7 +9,13 @@ mod sprite; mod texture_atlas; mod texture_atlas_builder; -use bevy_ecs::IntoSystem; +pub mod prelude { + pub use crate::{ + entity::{SpriteBundle, SpriteSheetBundle}, + ColorMaterial, Sprite, SpriteResizeMode, TextureAtlas, TextureAtlasSprite, + }; +} + pub use color_material::*; pub use dynamic_texture_atlas_builder::*; pub use rect::*; @@ -18,15 +24,9 @@ pub use sprite::*; pub use texture_atlas::*; pub use texture_atlas_builder::*; -pub mod prelude { - pub use crate::{ - entity::{SpriteBundle, SpriteSheetBundle}, - ColorMaterial, Sprite, SpriteResizeMode, TextureAtlas, TextureAtlasSprite, - }; -} - use bevy_app::prelude::*; use bevy_asset::{AddAsset, Assets, Handle, HandleUntyped}; +use bevy_ecs::IntoSystem; use bevy_math::Vec2; use bevy_reflect::{RegisterTypeBuilder, TypeUuid}; use bevy_render::{ @@ -47,9 +47,9 @@ impl Plugin for SpritePlugin { app.add_asset::() .add_asset::() .register_type::() - .add_system_to_stage(stage::POST_UPDATE, sprite_system.system()) + .add_system_to_stage(CoreStage::PostUpdate, sprite_system.system()) .add_system_to_stage( - stage::POST_UPDATE, + CoreStage::PostUpdate, asset_shader_defs_system::.system(), ); diff --git a/crates/bevy_text/src/lib.rs b/crates/bevy_text/src/lib.rs index 6a9f2e09a227c..166c80e1c7849 100644 --- a/crates/bevy_text/src/lib.rs +++ b/crates/bevy_text/src/lib.rs @@ -28,6 +28,7 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_asset::AddAsset; use bevy_ecs::{Entity, IntoSystem}; +use bevy_render::RenderStage; pub type DefaultTextPipeline = TextPipeline; @@ -40,10 +41,7 @@ impl Plugin for TextPlugin { .add_asset::() .init_asset_loader::() .insert_resource(DefaultTextPipeline::default()) - .add_system_to_stage(bevy_app::stage::POST_UPDATE, text2d_system.system()) - .add_system_to_stage( - bevy_render::stage::DRAW, - text2d::draw_text2d_system.system(), - ); + .add_system_to_stage(CoreStage::PostUpdate, text2d_system.system()) + .add_system_to_stage(RenderStage::Draw, text2d::draw_text2d_system.system()); } } diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index ce318a5492887..2b23d25eb7b86 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -6,14 +6,20 @@ pub mod prelude { pub use crate::{components::*, hierarchy::*, TransformPlugin}; } -use bevy_app::{prelude::*, startup_stage}; -use bevy_ecs::{IntoSystem, ParallelSystemDescriptorCoercion}; +use bevy_app::prelude::*; +use bevy_ecs::{IntoSystem, ParallelSystemDescriptorCoercion, SystemLabel}; use bevy_reflect::RegisterTypeBuilder; use prelude::{parent_update_system, Children, GlobalTransform, Parent, PreviousParent, Transform}; #[derive(Default)] pub struct TransformPlugin; +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] +pub enum TransformSystem { + TransformPropagate, + ParentUpdate, +} + impl Plugin for TransformPlugin { fn build(&self, app: &mut AppBuilder) { app.register_type::() @@ -23,26 +29,30 @@ impl Plugin for TransformPlugin { .register_type::() // add transform systems to startup so the first update is "correct" .add_startup_system_to_stage( - startup_stage::POST_STARTUP, - parent_update_system.system().label("parent_update_system"), + StartupStage::PostStartup, + parent_update_system + .system() + .label(TransformSystem::ParentUpdate), ) .add_startup_system_to_stage( - startup_stage::POST_STARTUP, + StartupStage::PostStartup, transform_propagate_system::transform_propagate_system .system() - .label("transform_propagate_system") - .after("parent_update_system"), + .label(TransformSystem::TransformPropagate) + .after(TransformSystem::ParentUpdate), ) .add_system_to_stage( - stage::POST_UPDATE, - parent_update_system.system().label("parent_update_system"), + CoreStage::PostUpdate, + parent_update_system + .system() + .label(TransformSystem::ParentUpdate), ) .add_system_to_stage( - stage::POST_UPDATE, + CoreStage::PostUpdate, transform_propagate_system::transform_propagate_system .system() - .label("transform_propagate_system") - .after("parent_update_system"), + .label(TransformSystem::TransformPropagate) + .after(TransformSystem::ParentUpdate), ); } } diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index b066e1d29ea7b..3a32cfb6807dc 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -20,15 +20,23 @@ pub mod prelude { } use bevy_app::prelude::*; -use bevy_ecs::{IntoSystem, ParallelSystemDescriptorCoercion, SystemStage}; -use bevy_render::render_graph::RenderGraph; +use bevy_ecs::{ + IntoSystem, ParallelSystemDescriptorCoercion, StageLabel, SystemLabel, SystemStage, +}; +use bevy_render::{render_graph::RenderGraph, RenderStage}; use update::ui_z_system; #[derive(Default)] pub struct UiPlugin; -pub mod stage { - pub const UI: &str = "ui"; +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +pub enum UiStage { + Ui, +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] +pub enum UiSystem { + Flex, } pub mod system { @@ -38,21 +46,20 @@ pub mod system { impl Plugin for UiPlugin { fn build(&self, app: &mut AppBuilder) { app.init_resource::() - .add_stage_before( - bevy_app::stage::POST_UPDATE, - stage::UI, - SystemStage::parallel(), - ) - .add_system_to_stage(bevy_app::stage::PRE_UPDATE, ui_focus_system.system()) + .add_stage_before(CoreStage::PostUpdate, UiStage::Ui, SystemStage::parallel()) + .add_system_to_stage(CoreStage::PreUpdate, ui_focus_system.system()) // add these stages to front because these must run before transform update systems - .add_system_to_stage(stage::UI, widget::text_system.system().before(system::FLEX)) .add_system_to_stage( - stage::UI, - widget::image_node_system.system().before(system::FLEX), + UiStage::Ui, + widget::text_system.system().before(UiSystem::Flex), + ) + .add_system_to_stage( + UiStage::Ui, + widget::image_node_system.system().before(UiSystem::Flex), ) - .add_system_to_stage(stage::UI, flex_node_system.system().label(system::FLEX)) - .add_system_to_stage(stage::UI, ui_z_system.system()) - .add_system_to_stage(bevy_render::stage::DRAW, widget::draw_text_system.system()); + .add_system_to_stage(UiStage::Ui, flex_node_system.system().label(UiSystem::Flex)) + .add_system_to_stage(UiStage::Ui, ui_z_system.system()) + .add_system_to_stage(RenderStage::Draw, widget::draw_text_system.system()); let resources = app.resources(); let mut render_graph = resources.get_mut::().unwrap(); diff --git a/crates/bevy_wgpu/src/lib.rs b/crates/bevy_wgpu/src/lib.rs index 25e6ff7e54133..f7883483f8ade 100644 --- a/crates/bevy_wgpu/src/lib.rs +++ b/crates/bevy_wgpu/src/lib.rs @@ -5,14 +5,17 @@ mod wgpu_renderer; mod wgpu_resources; mod wgpu_type_converter; -use futures_lite::future; pub use wgpu_render_pass::*; pub use wgpu_renderer::*; pub use wgpu_resources::*; use bevy_app::prelude::*; use bevy_ecs::{IntoExclusiveSystem, IntoSystem, Resources, World}; -use bevy_render::renderer::{shared_buffers_update_system, RenderResourceContext, SharedBuffers}; +use bevy_render::{ + renderer::{shared_buffers_update_system, RenderResourceContext, SharedBuffers}, + RenderStage, +}; +use futures_lite::future; use renderer::WgpuRenderResourceContext; #[derive(Default)] @@ -21,9 +24,9 @@ pub struct WgpuPlugin; impl Plugin for WgpuPlugin { fn build(&self, app: &mut AppBuilder) { let render_system = get_wgpu_render_system(app.resources_mut()); - app.add_system_to_stage(bevy_render::stage::RENDER, render_system.exclusive_system()) + app.add_system_to_stage(RenderStage::Render, render_system.exclusive_system()) .add_system_to_stage( - bevy_render::stage::POST_RENDER, + RenderStage::PostRender, shared_buffers_update_system.system(), ); } diff --git a/examples/2d/texture_atlas.rs b/examples/2d/texture_atlas.rs index 3a3ef5c3cdf2a..ed5bdd1ea00fa 100644 --- a/examples/2d/texture_atlas.rs +++ b/examples/2d/texture_atlas.rs @@ -6,14 +6,15 @@ fn main() { .init_resource::() .add_plugins(DefaultPlugins) .insert_resource(State::new(AppState::Setup)) - .add_stage_after(stage::UPDATE, STAGE, StateStage::::default()) - .on_state_enter(STAGE, AppState::Setup, load_textures.system()) - .on_state_update(STAGE, AppState::Setup, check_textures.system()) - .on_state_enter(STAGE, AppState::Finished, setup.system()) + .add_stage_after(CoreStage::Update, Stage, StateStage::::default()) + .on_state_enter(Stage, AppState::Setup, load_textures.system()) + .on_state_update(Stage, AppState::Setup, check_textures.system()) + .on_state_enter(Stage, AppState::Finished, setup.system()) .run(); } -const STAGE: &str = "app_state"; +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +struct Stage; #[derive(Clone)] enum AppState { diff --git a/examples/ecs/ecs_guide.rs b/examples/ecs/ecs_guide.rs index 677cc0f9b75f0..030bcf0c6d1fe 100644 --- a/examples/ecs/ecs_guide.rs +++ b/examples/ecs/ecs_guide.rs @@ -239,6 +239,17 @@ fn local_state_system(mut state: Local, query: Query<(&Player, &Score)>) state.counter += 1; } +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +enum MyStage { + BeforeRound, + AfterRound, +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] +enum MyLabels { + ScoreCheck, +} + // Our Bevy app's entry point fn main() { // Bevy apps are created using the builder pattern. We use the builder to add systems, resources, and plugins to our app @@ -286,25 +297,33 @@ fn main() { // // add_system(system) adds systems to the UPDATE stage by default // However we can manually specify the stage if we want to. The following is equivalent to add_system(score_system) - .add_system_to_stage(stage::UPDATE, score_system.system()) + .add_system_to_stage(CoreStage::Update, score_system.system()) // We can also create new stages. Here is what our games stage order will look like: // "before_round": new_player_system, new_round_system // "update": print_message_system, score_system // "after_round": score_check_system, game_over_system - .add_stage_before(stage::UPDATE, "before_round", SystemStage::parallel()) - .add_stage_after(stage::UPDATE, "after_round", SystemStage::parallel()) - .add_system_to_stage("before_round", new_round_system.system()) - .add_system_to_stage("before_round", new_player_system.system()) + .add_stage_before( + CoreStage::Update, + MyStage::BeforeRound, + SystemStage::parallel(), + ) + .add_stage_after( + CoreStage::Update, + MyStage::AfterRound, + SystemStage::parallel(), + ) + .add_system_to_stage(MyStage::BeforeRound, new_round_system.system()) + .add_system_to_stage(MyStage::BeforeRound, new_player_system.system()) // We can ensure that game_over system runs after score_check_system using explicit ordering constraints // First, we label the system we want to refer to using `.label` // Then, we use either `.before` or `.after` to describe the order we want the relationship .add_system_to_stage( - "after_round", - score_check_system.system().label("score_check"), + MyStage::AfterRound, + score_check_system.system().label(MyLabels::ScoreCheck), ) .add_system_to_stage( - "after_round", - game_over_system.system().after("score_check"), + MyStage::AfterRound, + game_over_system.system().after(MyLabels::ScoreCheck), ) // We can check our systems for execution order ambiguities by examining the output produced in the console // by adding the following Resource to our App :) diff --git a/examples/ecs/fixed_timestep.rs b/examples/ecs/fixed_timestep.rs index cd97079d0d790..beef7ad70ab76 100644 --- a/examples/ecs/fixed_timestep.rs +++ b/examples/ecs/fixed_timestep.rs @@ -5,6 +5,9 @@ use bevy::{ const LABEL: &str = "my_fixed_timestep"; +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +struct FixedUpdateStage; + fn main() { App::build() .add_plugins(DefaultPlugins) @@ -12,8 +15,8 @@ fn main() { .add_system(update.system()) // add a new stage that runs every two seconds .add_stage_after( - stage::UPDATE, - "fixed_update", + CoreStage::Update, + FixedUpdateStage, SystemStage::parallel() .with_run_criteria( FixedTimestep::step(2.0) diff --git a/examples/ecs/removal_detection.rs b/examples/ecs/removal_detection.rs index 80c430ff833d4..424fbf3baecb9 100644 --- a/examples/ecs/removal_detection.rs +++ b/examples/ecs/removal_detection.rs @@ -16,8 +16,8 @@ fn main() { App::build() .add_plugins(DefaultPlugins) .add_startup_system(setup.system()) - .add_system_to_stage(stage::UPDATE, remove_component.system()) - .add_system_to_stage(stage::POST_UPDATE, react_on_removal.system()) + .add_system_to_stage(CoreStage::Update, remove_component.system()) + .add_system_to_stage(CoreStage::PostUpdate, react_on_removal.system()) .run(); } diff --git a/examples/ecs/state.rs b/examples/ecs/state.rs index c446a60f37971..e3124f7b5dbf9 100644 --- a/examples/ecs/state.rs +++ b/examples/ecs/state.rs @@ -6,17 +6,18 @@ fn main() { .add_plugins(DefaultPlugins) .init_resource::() .insert_resource(State::new(AppState::Menu)) - .add_stage_after(stage::UPDATE, STAGE, StateStage::::default()) - .on_state_enter(STAGE, AppState::Menu, setup_menu.system()) - .on_state_update(STAGE, AppState::Menu, menu.system()) - .on_state_exit(STAGE, AppState::Menu, cleanup_menu.system()) - .on_state_enter(STAGE, AppState::InGame, setup_game.system()) - .on_state_update(STAGE, AppState::InGame, movement.system()) - .on_state_update(STAGE, AppState::InGame, change_color.system()) + .add_stage_after(CoreStage::Update, Stage, StateStage::::default()) + .on_state_enter(Stage, AppState::Menu, setup_menu.system()) + .on_state_update(Stage, AppState::Menu, menu.system()) + .on_state_exit(Stage, AppState::Menu, cleanup_menu.system()) + .on_state_enter(Stage, AppState::InGame, setup_game.system()) + .on_state_update(Stage, AppState::InGame, movement.system()) + .on_state_update(Stage, AppState::InGame, change_color.system()) .run(); } -const STAGE: &str = "app_state"; +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +struct Stage; #[derive(Clone)] enum AppState { diff --git a/examples/game/alien_cake_addict.rs b/examples/game/alien_cake_addict.rs index a9077f1b77503..dfa34bd448a18 100644 --- a/examples/game/alien_cake_addict.rs +++ b/examples/game/alien_cake_addict.rs @@ -5,7 +5,11 @@ use bevy::{ }; use rand::Rng; -const STAGE: &str = "game"; +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +enum GameStage { + InGame, + BonusUpdate, +} #[derive(Clone, PartialEq, Debug)] enum GameState { @@ -20,19 +24,35 @@ fn main() { .add_plugins(DefaultPlugins) .insert_resource(State::new(GameState::Playing)) .add_startup_system(setup_cameras.system()) - .add_stage_after(stage::UPDATE, STAGE, StateStage::::default()) - .on_state_enter(STAGE, GameState::Playing, setup.system()) - .on_state_update(STAGE, GameState::Playing, move_player.system()) - .on_state_update(STAGE, GameState::Playing, focus_camera.system()) - .on_state_update(STAGE, GameState::Playing, rotate_bonus.system()) - .on_state_update(STAGE, GameState::Playing, scoreboard_system.system()) - .on_state_exit(STAGE, GameState::Playing, teardown.system()) - .on_state_enter(STAGE, GameState::GameOver, display_score.system()) - .on_state_update(STAGE, GameState::GameOver, gameover_keyboard.system()) - .on_state_exit(STAGE, GameState::GameOver, teardown.system()) .add_stage_after( - stage::UPDATE, - "bonus_update", + CoreStage::Update, + GameStage::InGame, + StateStage::::default(), + ) + .on_state_enter(GameStage::InGame, GameState::Playing, setup.system()) + .on_state_update(GameStage::InGame, GameState::Playing, move_player.system()) + .on_state_update(GameStage::InGame, GameState::Playing, focus_camera.system()) + .on_state_update(GameStage::InGame, GameState::Playing, rotate_bonus.system()) + .on_state_update( + GameStage::InGame, + GameState::Playing, + scoreboard_system.system(), + ) + .on_state_exit(GameStage::InGame, GameState::Playing, teardown.system()) + .on_state_enter( + GameStage::InGame, + GameState::GameOver, + display_score.system(), + ) + .on_state_update( + GameStage::InGame, + GameState::GameOver, + gameover_keyboard.system(), + ) + .on_state_exit(GameStage::InGame, GameState::GameOver, teardown.system()) + .add_stage_after( + CoreStage::Update, + GameStage::BonusUpdate, SystemStage::parallel() .with_run_criteria(FixedTimestep::step(5.0)) .with_system(spawn_bonus.system()), diff --git a/examples/input/gamepad_input.rs b/examples/input/gamepad_input.rs index 7b3c9d4b07e30..b712c82032f77 100644 --- a/examples/input/gamepad_input.rs +++ b/examples/input/gamepad_input.rs @@ -8,7 +8,7 @@ fn main() { App::build() .add_plugins(DefaultPlugins) .init_resource::() - .add_system_to_stage(stage::PRE_UPDATE, connection_system.system()) + .add_system_to_stage(CoreStage::PreUpdate, connection_system.system()) .add_system(gamepad_system.system()) .run(); } diff --git a/examples/shader/shader_defs.rs b/examples/shader/shader_defs.rs index 552db2f9b9c54..383ffd04e2229 100644 --- a/examples/shader/shader_defs.rs +++ b/examples/shader/shader_defs.rs @@ -18,7 +18,7 @@ fn main() { .add_asset::() .add_startup_system(setup.system()) .add_system_to_stage( - stage::POST_UPDATE, + CoreStage::PostUpdate, asset_shader_defs_system::.system(), ) .run(); diff --git a/examples/window/multiple_windows.rs b/examples/window/multiple_windows.rs index 6ea12ceab43a5..34c868f128734 100644 --- a/examples/window/multiple_windows.rs +++ b/examples/window/multiple_windows.rs @@ -18,17 +18,14 @@ fn main() { .insert_resource(Msaa { samples: 4 }) .insert_resource(State::new(AppState::CreateWindow)) .add_plugins(DefaultPlugins) - .add_stage_after( - stage::UPDATE, - STATE_STAGE, - StateStage::::default(), - ) - .on_state_update(STATE_STAGE, AppState::CreateWindow, setup_window.system()) - .on_state_enter(STATE_STAGE, AppState::Setup, setup_pipeline.system()) + .add_stage_after(CoreStage::Update, Stage, StateStage::::default()) + .on_state_update(Stage, AppState::CreateWindow, setup_window.system()) + .on_state_enter(Stage, AppState::Setup, setup_pipeline.system()) .run(); } -const STATE_STAGE: &str = "state"; +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +pub struct Stage; // NOTE: this "state based" approach to multiple windows is a short term workaround. // Future Bevy releases shouldn't require such a strict order of operations.