diff --git a/benches/benches/bevy_ecs/scheduling/run_criteria.rs b/benches/benches/bevy_ecs/scheduling/run_criteria.rs index 52c5fade22e53..a4902ce504872 100644 --- a/benches/benches/bevy_ecs/scheduling/run_criteria.rs +++ b/benches/benches/bevy_ecs/scheduling/run_criteria.rs @@ -1,6 +1,6 @@ use bevy_ecs::{ component::Component, - prelude::{ParallelSystemDescriptorCoercion, Res, RunCriteriaDescriptorCoercion}, + prelude::{IntoSystemDescriptor, Res, RunCriteriaDescriptorCoercion}, schedule::{ShouldRun, Stage, SystemStage}, system::Query, world::World, diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index ee70d801ef952..8dbf71e7faadc 100644 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -12,7 +12,7 @@ use bevy_ecs::{ entity::Entity, prelude::Component, reflect::ReflectComponent, - schedule::ParallelSystemDescriptorCoercion, + schedule::IntoSystemDescriptor, system::{Query, Res}, }; use bevy_hierarchy::Children; diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index ebdd2ee0df54a..10c9b97ee64d4 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -2,7 +2,7 @@ use crate::{CoreStage, Plugin, PluginGroup, PluginGroupBuilder, StartupSchedule, pub use bevy_derive::AppLabel; use bevy_ecs::{ event::{Event, Events}, - prelude::{FromWorld, IntoExclusiveSystem}, + prelude::FromWorld, schedule::{ IntoSystemDescriptor, Schedule, ShouldRun, Stage, StageLabel, State, StateData, SystemSet, SystemStage, @@ -78,7 +78,7 @@ impl Default for App { app.add_default_stages() .add_event::() - .add_system_to_stage(CoreStage::Last, World::clear_trackers.exclusive_system()); + .add_system_to_stage(CoreStage::Last, World::clear_trackers.at_end()); #[cfg(feature = "bevy_ci_testing")] { diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index 1f1d171f174bf..0ef36b034a1b0 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -27,6 +27,10 @@ fxhash = "0.2" downcast-rs = "1.2" serde = "1" +petgraph = "0.6" +bitvec = "1" +thiserror = "1" + [dev-dependencies] rand = "0.8" diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 68023e315ddb0..50431da54f4ad 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -254,6 +254,30 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { fn apply(&mut self, world: &mut World) { self.0.apply(world) } + + fn world_access_level() -> WorldAccessLevel { + let mut exclusive = false; + let mut shared = false; + #( + match #param_fetch::world_access_level() { + WorldAccessLevel::Exclusive => { + exclusive = true; + } + WorldAccessLevel::Shared => { + shared = true; + } + WorldAccessLevel::None => (), + } + )* + + if exclusive { + WorldAccessLevel::Exclusive + } else if shared { + WorldAccessLevel::Shared + } else { + WorldAccessLevel::None + } + } } @@ -266,7 +290,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { unsafe fn get_param( state: &'s mut Self, system_meta: &SystemMeta, - world: &'w World, + world: MaybeUnsafeCell<'w, World>, change_tick: u32, ) -> Self::Item { ParamSet { @@ -404,6 +428,10 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { fn apply(&mut self, world: &mut #path::world::World) { self.state.apply(world) } + + fn world_access_level() -> #path::system::WorldAccessLevel { + TSystemParamState::world_access_level() + } } impl #impl_generics #path::system::SystemParamFetch<'w, 's> for FetchState <(#(<#field_types as #path::system::SystemParam>::Fetch,)*), #punctuated_generic_idents> #where_clause { @@ -411,7 +439,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { unsafe fn get_param( state: &'s mut Self, system_meta: &#path::system::SystemMeta, - world: &'w #path::world::World, + world: #path::system::MaybeUnsafeCell<'w, #path::world::World>, change_tick: u32, ) -> Self::Item { #struct_name { diff --git a/crates/bevy_ecs/src/entity/mod.rs b/crates/bevy_ecs/src/entity/mod.rs index e022483fa836c..da2d6266363b7 100644 --- a/crates/bevy_ecs/src/entity/mod.rs +++ b/crates/bevy_ecs/src/entity/mod.rs @@ -72,7 +72,7 @@ use std::{ /// } /// # /// # bevy_ecs::system::assert_is_system(setup); -/// # bevy_ecs::system::IntoExclusiveSystem::exclusive_system(exclusive_system); +/// # bevy_ecs::system::assert_is_system(exclusive_system); /// ``` /// /// It can be used to refer to a specific entity to apply [`EntityCommands`], or to call [`Query::get`] (or similar methods) to access its components. diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index cafacc2a2d929..07b2bfdddfdba 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -14,6 +14,7 @@ pub mod query; #[cfg(feature = "bevy_reflect")] pub mod reflect; pub mod schedule; +pub mod schedule_v3; pub mod storage; pub mod system; pub mod world; @@ -34,13 +35,13 @@ pub mod prelude { event::{EventReader, EventWriter, Events}, query::{Added, AnyOf, ChangeTrackers, Changed, Or, QueryState, With, Without}, schedule::{ - AmbiguitySetLabel, ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion, - RunCriteria, RunCriteriaDescriptorCoercion, RunCriteriaLabel, Schedule, Stage, - StageLabel, State, SystemLabel, SystemSet, SystemStage, + AmbiguitySetLabel, IntoSystemDescriptor, RunCriteria, RunCriteriaDescriptorCoercion, + RunCriteriaLabel, Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, + SystemStage, }, system::{ - Commands, In, IntoChainSystem, IntoExclusiveSystem, IntoSystem, Local, NonSend, - NonSendMut, ParallelCommands, ParamSet, Query, RemovedComponents, Res, ResMut, System, + Commands, In, IntoChainSystem, IntoSystem, Local, NonSend, NonSendMut, + ParallelCommands, ParamSet, Query, RemovedComponents, Res, ResMut, System, SystemParamFunction, }, world::{FromWorld, Mut, World}, diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index d9580bd4eb507..7f57c264e1095 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -13,9 +13,12 @@ pub struct Access { reads_and_writes: FixedBitSet, /// The exclusively-accessed elements. writes: FixedBitSet, - /// Is `true` if this has access to all elements in the collection? + /// Is `true` if this has access to all elements in the collection. /// This field is a performance optimization for `&World` (also harder to mess up for soundness). reads_all: bool, + /// Is `true` if this has exclusive access to all elements in the collection. + /// This field is a performance optimization for `&mut World` (also harder to mess up for soundness). + writes_all: bool, marker: PhantomData, } @@ -23,6 +26,7 @@ impl Default for Access { fn default() -> Self { Self { reads_all: false, + writes_all: false, reads_and_writes: Default::default(), writes: Default::default(), marker: PhantomData, @@ -64,7 +68,11 @@ impl Access { /// Returns `true` if this can exclusively access the element given by `index`. pub fn has_write(&self, index: T) -> bool { - self.writes.contains(index.sparse_set_index()) + if self.writes_all { + true + } else { + self.writes.contains(index.sparse_set_index()) + } } /// Sets this as having access to all indexed elements (i.e. `&World`). @@ -77,9 +85,21 @@ impl Access { self.reads_all } + /// Sets this as having exclusive access to all indexed elements (i.e. `&mut World`). + pub fn write_all(&mut self) { + self.reads_all = true; + self.writes_all = true; + } + + /// Returns `true` if this has exclusive access to all indexed elements (i.e. `&mut World`). + pub fn has_write_all(&self) -> bool { + self.writes_all + } + /// Removes all accesses. pub fn clear(&mut self) { self.reads_all = false; + self.writes_all = false; self.reads_and_writes.clear(); self.writes.clear(); } @@ -87,6 +107,7 @@ impl Access { /// Adds all access from `other`. pub fn extend(&mut self, other: &Access) { self.reads_all = self.reads_all || other.reads_all; + self.writes_all = self.writes_all || other.writes_all; self.reads_and_writes.union_with(&other.reads_and_writes); self.writes.union_with(&other.writes); } @@ -96,6 +117,12 @@ impl Access { /// `Access` instances are incompatible if one can write /// an element that the other can read or write. pub fn is_compatible(&self, other: &Access) -> bool { + // All systems make a `&World` reference before running to update change detection info. + // Since exclusive systems produce a `&mut World`, we cannot let other systems run. + if self.writes_all || other.writes_all { + return false; + } + // Only systems that do not write data are compatible with systems that operate on `&World`. if self.reads_all { return other.writes.count_ones(..) == 0; @@ -112,15 +139,31 @@ impl Access { /// Returns a vector of elements that the access and `other` cannot access at the same time. pub fn get_conflicts(&self, other: &Access) -> Vec { let mut conflicts = FixedBitSet::default(); - if self.reads_all { - conflicts.extend(other.writes.ones()); + + if self.writes_all { + conflicts.extend(other.reads_and_writes.ones()); } - if other.reads_all { - conflicts.extend(self.writes.ones()); + if other.writes_all { + conflicts.extend(self.reads_and_writes.ones()); + } + + if !(self.writes_all || other.writes_all) { + match (self.reads_all, other.reads_all) { + (false, false) => { + conflicts.extend(self.writes.intersection(&other.reads_and_writes)); + conflicts.extend(self.reads_and_writes.intersection(&other.writes)); + } + (false, true) => { + conflicts.extend(self.writes.ones()); + } + (true, false) => { + conflicts.extend(other.writes.ones()); + } + (true, true) => (), + } } - conflicts.extend(self.writes.intersection(&other.reads_and_writes)); - conflicts.extend(self.reads_and_writes.intersection(&other.writes)); + conflicts .ones() .map(SparseSetIndex::get_sparse_set_index) @@ -143,6 +186,11 @@ impl Access { pub fn writes(&self) -> impl Iterator + '_ { self.writes.ones().map(T::get_sparse_set_index) } + + /// Returns `true` if this does not have access to any elements in the collection. + pub fn is_empty(&self) -> bool { + self.reads_and_writes.count_ones(..) == 0 && !self.reads_all && !self.writes_all + } } /// An [`Access`] that has been filtered to include and exclude certain combinations of elements. @@ -266,6 +314,16 @@ impl FilteredAccess { pub fn read_all(&mut self) { self.access.read_all(); } + + /// Sets the underlying unfiltered access as having exclusive access to all indexed elements. + pub fn write_all(&mut self) { + self.access.write_all(); + } + + /// Returns `true` if this does not have access to any elements in the collection. + pub fn is_empty(&self) -> bool { + self.access.is_empty() + } } /// A collection of [`FilteredAccess`] instances. @@ -306,6 +364,20 @@ impl FilteredAccessSet { true } + /// Returns `true` if this and `filtered_access` can be active at the same time. + pub fn is_compatible_single(&self, filtered_access: &FilteredAccess) -> bool { + if self.combined_access.is_compatible(filtered_access.access()) { + return true; + } + for filtered in &self.filtered_accesses { + if !filtered.is_compatible(filtered_access) { + return false; + } + } + + true + } + /// Returns a vector of elements that this set and `other` cannot access at the same time. pub fn get_conflicts(&self, other: &FilteredAccessSet) -> Vec { // if the unfiltered access is incompatible, must check each pair @@ -320,7 +392,7 @@ impl FilteredAccessSet { conflicts.into_iter().collect() } - /// Returns a vector of elements that this set and `other` cannot access at the same time. + /// Returns a vector of elements that this set and `filtered_access` cannot access at the same time. pub fn get_conflicts_single(&self, filtered_access: &FilteredAccess) -> Vec { // if the unfiltered access is incompatible, must check each pair let mut conflicts = HashSet::new(); @@ -349,6 +421,11 @@ impl FilteredAccessSet { self.combined_access.clear(); self.filtered_accesses.clear(); } + + /// Returns `true` if this does not have access to any elements in the collection. + pub fn is_empty(&self) -> bool { + self.combined_access.is_empty() + } } impl Default for FilteredAccessSet { diff --git a/crates/bevy_ecs/src/schedule/executor.rs b/crates/bevy_ecs/src/schedule/executor.rs index 06db889ec2d6c..edf6fcf5c6ab3 100644 --- a/crates/bevy_ecs/src/schedule/executor.rs +++ b/crates/bevy_ecs/src/schedule/executor.rs @@ -1,11 +1,11 @@ -use crate::{schedule::ParallelSystemContainer, world::World}; +use crate::{schedule::FunctionSystemContainer, world::World}; use downcast_rs::{impl_downcast, Downcast}; pub trait ParallelSystemExecutor: Downcast + Send + Sync { /// Called by `SystemStage` whenever `systems` have been changed. - fn rebuild_cached_data(&mut self, systems: &[ParallelSystemContainer]); + fn rebuild_cached_data(&mut self, systems: &[FunctionSystemContainer]); - fn run_systems(&mut self, systems: &mut [ParallelSystemContainer], world: &mut World); + fn run_systems(&mut self, systems: &mut [FunctionSystemContainer], world: &mut World); } impl_downcast!(ParallelSystemExecutor); @@ -14,9 +14,9 @@ impl_downcast!(ParallelSystemExecutor); pub struct SingleThreadedExecutor; impl ParallelSystemExecutor for SingleThreadedExecutor { - fn rebuild_cached_data(&mut self, _: &[ParallelSystemContainer]) {} + fn rebuild_cached_data(&mut self, _: &[FunctionSystemContainer]) {} - fn run_systems(&mut self, systems: &mut [ParallelSystemContainer], world: &mut World) { + fn run_systems(&mut self, systems: &mut [FunctionSystemContainer], world: &mut World) { for system in systems { if system.should_run() { #[cfg(feature = "trace")] diff --git a/crates/bevy_ecs/src/schedule/executor_parallel.rs b/crates/bevy_ecs/src/schedule/executor_parallel.rs index 4bf36da141de0..98eb675e900e9 100644 --- a/crates/bevy_ecs/src/schedule/executor_parallel.rs +++ b/crates/bevy_ecs/src/schedule/executor_parallel.rs @@ -1,7 +1,8 @@ use crate::{ archetype::ArchetypeComponentId, query::Access, - schedule::{ParallelSystemContainer, ParallelSystemExecutor}, + schedule::{FunctionSystemContainer, ParallelSystemExecutor}, + system::MaybeUnsafeCell, world::World, }; use async_channel::{Receiver, Sender}; @@ -74,7 +75,7 @@ impl Default for ParallelExecutor { } impl ParallelSystemExecutor for ParallelExecutor { - fn rebuild_cached_data(&mut self, systems: &[ParallelSystemContainer]) { + fn rebuild_cached_data(&mut self, systems: &[FunctionSystemContainer]) { self.system_metadata.clear(); self.queued.grow(systems.len()); self.running.grow(systems.len()); @@ -82,6 +83,10 @@ impl ParallelSystemExecutor for ParallelExecutor { // Construct scheduling data for systems. for container in systems { + if container.system().is_exclusive() { + panic!("executor cannot run exclusive systems"); + } + let dependencies_total = container.dependencies().len(); let system = container.system(); let (start_sender, start_receiver) = async_channel::bounded(1); @@ -103,7 +108,7 @@ impl ParallelSystemExecutor for ParallelExecutor { } } - fn run_systems(&mut self, systems: &mut [ParallelSystemContainer], world: &mut World) { + fn run_systems(&mut self, systems: &mut [FunctionSystemContainer], world: &mut World) { #[cfg(test)] if self.events_sender.is_none() { let (sender, receiver) = async_channel::unbounded::(); @@ -162,8 +167,8 @@ impl ParallelExecutor { /// queues systems with no dependencies to run (or skip) at next opportunity. fn prepare_systems<'scope>( &mut self, - scope: &mut Scope<'scope, ()>, - systems: &'scope mut [ParallelSystemContainer], + scope: &Scope<'_, 'scope, ()>, + systems: &'scope mut [FunctionSystemContainer], world: &'scope World, ) { #[cfg(feature = "trace")] @@ -191,7 +196,7 @@ impl ParallelExecutor { #[cfg(feature = "trace")] let system_guard = system_span.enter(); // SAFETY: the executor prevents two systems with conflicting access from running simultaneously. - unsafe { system.run_unsafe((), world) }; + unsafe { system.run_unsafe((), MaybeUnsafeCell::from_ref(world)) }; #[cfg(feature = "trace")] drop(system_guard); finish_sender @@ -205,7 +210,7 @@ impl ParallelExecutor { if system_data.is_send { scope.spawn(task); } else { - scope.spawn_local(task); + scope.spawn_on_scope(task); } } // Queue the system if it has no dependencies, otherwise reset its dependency counter. diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index a14a5db7be32a..50cce0bc22d30 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -4,11 +4,11 @@ use crate::{ prelude::IntoSystem, schedule::{ graph_utils::{self, DependencyGraphError}, - BoxedRunCriteria, DuplicateLabelStrategy, ExclusiveSystemContainer, GraphNode, - InsertionPoint, ParallelExecutor, ParallelSystemContainer, ParallelSystemExecutor, - RunCriteriaContainer, RunCriteriaDescriptor, RunCriteriaDescriptorOrLabel, - RunCriteriaInner, RunCriteriaLabelId, ShouldRun, SingleThreadedExecutor, SystemContainer, - SystemDescriptor, SystemLabelId, SystemSet, + BoxedRunCriteria, DuplicateLabelStrategy, FunctionSystemContainer, GraphNode, + InsertionPoint, ParallelExecutor, ParallelSystemExecutor, RunCriteriaContainer, + RunCriteriaDescriptor, RunCriteriaDescriptorOrLabel, RunCriteriaInner, RunCriteriaLabelId, + ShouldRun, SingleThreadedExecutor, SystemContainer, SystemDescriptor, SystemLabelId, + SystemSet, SystemType, }, world::{World, WorldId}, }; @@ -16,6 +16,7 @@ use bevy_utils::{ tracing::{info, warn}, HashMap, HashSet, }; +use core::panic; use downcast_rs::{impl_downcast, Downcast}; use fixedbitset::FixedBitSet; use std::fmt::Debug; @@ -65,14 +66,14 @@ pub struct SystemStage { /// Topologically sorted run criteria of systems. run_criteria: Vec, /// Topologically sorted exclusive systems that want to be run at the start of the stage. - exclusive_at_start: Vec, + exclusive_at_start: Vec, /// Topologically sorted exclusive systems that want to be run after parallel systems but /// before the application of their command buffers. - exclusive_before_commands: Vec, + exclusive_before_commands: Vec, /// Topologically sorted exclusive systems that want to be run at the end of the stage. - exclusive_at_end: Vec, + exclusive_at_end: Vec, /// Topologically sorted parallel systems. - parallel: Vec, + parallel: Vec, /// Determines if the stage was modified and needs to rebuild its graphs and orders. systems_modified: bool, /// Determines if the stage's executor was changed. @@ -80,13 +81,7 @@ pub struct SystemStage { /// Newly inserted run criteria that will be initialized at the next opportunity. uninitialized_run_criteria: Vec<(usize, DuplicateLabelStrategy)>, /// Newly inserted systems that will be initialized at the next opportunity. - uninitialized_at_start: Vec, - /// Newly inserted systems that will be initialized at the next opportunity. - uninitialized_before_commands: Vec, - /// Newly inserted systems that will be initialized at the next opportunity. - uninitialized_at_end: Vec, - /// Newly inserted systems that will be initialized at the next opportunity. - uninitialized_parallel: Vec, + uninitialized_systems: Vec<(FunctionSystemContainer, SystemType)>, /// Saves the value of the World change_tick during the last tick check last_tick_check: u32, /// If true, buffers will be automatically applied at the end of the stage. If false, buffers must be manually applied. @@ -102,16 +97,13 @@ impl SystemStage { stage_run_criteria: Default::default(), run_criteria: vec![], uninitialized_run_criteria: vec![], + uninitialized_systems: vec![], exclusive_at_start: Default::default(), exclusive_before_commands: Default::default(), exclusive_at_end: Default::default(), parallel: vec![], systems_modified: true, executor_modified: true, - uninitialized_parallel: vec![], - uninitialized_at_start: vec![], - uninitialized_before_commands: vec![], - uninitialized_at_end: vec![], last_tick_check: Default::default(), apply_buffers: true, must_read_resource: None, @@ -159,64 +151,29 @@ impl SystemStage { self } - fn add_system_inner(&mut self, system: SystemDescriptor, default_run_criteria: Option) { + fn add_system_inner( + &mut self, + mut descriptor: SystemDescriptor, + 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; - 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 system_type = descriptor.system_type; + let criteria = descriptor.run_criteria.take(); + let mut container = FunctionSystemContainer::from_descriptor(descriptor); + match criteria { + 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; - 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; + container.run_criteria_index = + Some(self.add_run_criteria_internal(criteria_descriptor)); + } + None => { + container.run_criteria_index = default_run_criteria; } } + self.uninitialized_systems.push((container, system_type)); } pub fn apply_buffers(&mut self, world: &mut World) { @@ -270,53 +227,41 @@ impl SystemStage { pub fn add_system_set(&mut self, system_set: SystemSet) -> &mut Self { self.systems_modified = true; - let (run_criteria, mut systems) = system_set.bake(); - let set_run_criteria_index = run_criteria.and_then(|criteria| { - // validate that no systems have criteria - for system in &mut systems { - 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()), - } { - 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 \ - different `SystemSet` or calling `add_system()` instead.", - name - ) - } + let (run_criteria, mut descriptors) = system_set.bake(); + // verify that none of the systems in the set have their own run criteria + for descriptor in &descriptors { + if let Some(name) = descriptor + .run_criteria + .as_ref() + .map(|_| descriptor.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 \ + different `SystemSet` or calling `add_system()` instead.", + name + ) } - match criteria { - RunCriteriaDescriptorOrLabel::Descriptor(descriptor) => { - Some(self.add_run_criteria_internal(descriptor)) - } - RunCriteriaDescriptorOrLabel::Label(label) => { - for system in &mut systems { - match system { - SystemDescriptor::Exclusive(descriptor) => { - descriptor.run_criteria = - Some(RunCriteriaDescriptorOrLabel::Label(label)); - } - SystemDescriptor::Parallel(descriptor) => { - descriptor.run_criteria = - Some(RunCriteriaDescriptorOrLabel::Label(label)); - } - } - } + } - None + // add system set run criteria + let set_run_criteria_index = run_criteria.and_then(|criteria| match criteria { + RunCriteriaDescriptorOrLabel::Descriptor(descriptor) => { + Some(self.add_run_criteria_internal(descriptor)) + } + RunCriteriaDescriptorOrLabel::Label(label) => { + for descriptor in &mut descriptors { + descriptor.run_criteria = Some(RunCriteriaDescriptorOrLabel::Label(label)); } + None } }); - for system in systems.drain(..) { - self.add_system_inner(system, set_run_criteria_index); + + // set every system to use the set's run criteria + for descriptor in descriptors.drain(..) { + self.add_system_inner(descriptor, set_run_criteria_index); } + self } @@ -363,11 +308,11 @@ impl SystemStage { let mut criteria_labels = HashMap::default(); let uninitialized_criteria: HashMap<_, _> = self.uninitialized_run_criteria.drain(..).collect(); - // track the number of filtered criteria to correct run criteria indices + + // remove duplicate run criteria and point systems to the corrected run criteria indices let mut filtered_criteria = 0; let mut new_indices = Vec::new(); - self.run_criteria = self - .run_criteria + self.run_criteria = self.run_criteria .drain(..) .enumerate() .filter_map(|(index, mut container)| { @@ -378,9 +323,8 @@ impl SystemStage { if let Some(duplicate_index) = criteria_labels.get(label) { match strategy { DuplicateLabelStrategy::Panic => panic!( - "Run criteria {} is labelled with {:?}, which \ - is already in use. Consider using \ - `RunCriteriaDescriptorCoercion::label_discard_if_duplicate().", + "Run criteria {} has label {:?}, which is already in use. \ + Consider using `RunCriteriaDescriptorCoercion::label_discard_if_duplicate().", container.name(), container.label ), @@ -402,33 +346,31 @@ impl SystemStage { }) .collect(); - for index in self.uninitialized_at_start.drain(..) { - let container = &mut self.exclusive_at_start[index]; - if let Some(index) = container.run_criteria() { - container.set_run_criteria(new_indices[index]); - } + // initialize the systems and sort them into the appropriate vectors + for (mut container, system_type) in self.uninitialized_systems.drain(..) { container.system_mut().initialize(world); - } - for index in self.uninitialized_before_commands.drain(..) { - let container = &mut self.exclusive_before_commands[index]; - if let Some(index) = container.run_criteria() { - container.set_run_criteria(new_indices[index]); - } - container.system_mut().initialize(world); - } - for index in self.uninitialized_at_end.drain(..) { - let container = &mut self.exclusive_at_end[index]; + if let Some(index) = container.run_criteria() { container.set_run_criteria(new_indices[index]); } - container.system_mut().initialize(world); - } - for index in self.uninitialized_parallel.drain(..) { - let container = &mut self.parallel[index]; - if let Some(index) = container.run_criteria() { - container.set_run_criteria(new_indices[index]); + + match system_type { + SystemType::Parallel => { + assert!(!container.system().is_exclusive()); + self.parallel.push(container); + } + SystemType::Exclusive(insertion_point) => match insertion_point { + InsertionPoint::AtStart => { + self.exclusive_at_start.push(container); + } + InsertionPoint::BeforeCommands => { + self.exclusive_before_commands.push(container); + } + InsertionPoint::AtEnd => { + self.exclusive_at_end.push(container); + } + }, } - container.system_mut().initialize(world); } } @@ -445,11 +387,7 @@ impl SystemStage { < (CHECK_TICK_THRESHOLD as usize) ); debug_assert!( - self.uninitialized_run_criteria.is_empty() - && self.uninitialized_parallel.is_empty() - && self.uninitialized_at_start.is_empty() - && self.uninitialized_before_commands.is_empty() - && self.uninitialized_at_end.is_empty() + self.uninitialized_run_criteria.is_empty() && self.uninitialized_systems.is_empty() ); fn unwrap_dependency_cycle_error( result: Result>, @@ -769,8 +707,8 @@ fn find_ambiguities(systems: &[impl SystemContainer]) -> Vec<(usize, usize, Vec< let a_access = systems[index_a].component_access(); let b_access = systems[index_b].component_access(); if let (Some(a), Some(b)) = (a_access, b_access) { - let conflicts = a.get_conflicts(b); - if !conflicts.is_empty() { + if !a.is_compatible(b) { + let conflicts = a.get_conflicts(b); ambiguities.push((index_a, index_b, conflicts)); } } else { @@ -865,13 +803,25 @@ impl Stage for SystemStage { // Run systems that want to be at the start of stage. for container in &mut self.exclusive_at_start { if should_run(container, &self.run_criteria, default_should_run) { - #[cfg(feature = "trace")] - let _system_span = bevy_utils::tracing::info_span!( - "exclusive_system", - name = &*container.name() - ) - .entered(); - container.system_mut().run(world); + { + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "exclusive_system", + name = &*container.name() + ) + .entered(); + container.system_mut().run((), world); + } + + { + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "system_commands", + name = &*container.name() + ) + .entered(); + container.system_mut().apply_buffers(world); + } } } @@ -886,13 +836,25 @@ impl Stage for SystemStage { // Run systems that want to be between parallel systems and their command buffers. for container in &mut self.exclusive_before_commands { if should_run(container, &self.run_criteria, default_should_run) { - #[cfg(feature = "trace")] - let _system_span = bevy_utils::tracing::info_span!( - "exclusive_system", - name = &*container.name() - ) - .entered(); - container.system_mut().run(world); + { + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "exclusive_system", + name = &*container.name() + ) + .entered(); + container.system_mut().run((), world); + } + + { + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "system_commands", + name = &*container.name() + ) + .entered(); + container.system_mut().apply_buffers(world); + } } } @@ -914,13 +876,25 @@ impl Stage for SystemStage { // Run systems that want to be at the end of stage. for container in &mut self.exclusive_at_end { if should_run(container, &self.run_criteria, default_should_run) { - #[cfg(feature = "trace")] - let _system_span = bevy_utils::tracing::info_span!( - "exclusive_system", - name = &*container.name() - ) - .entered(); - container.system_mut().run(world); + { + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "exclusive_system", + name = &*container.name() + ) + .entered(); + container.system_mut().run((), world); + } + + { + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "system_commands", + name = &*container.name() + ) + .entered(); + container.system_mut().apply_buffers(world); + } } } @@ -972,11 +946,10 @@ impl Stage for SystemStage { mod tests { use crate::{ schedule::{ - ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion, RunCriteria, - RunCriteriaDescriptorCoercion, ShouldRun, SingleThreadedExecutor, Stage, SystemLabel, - SystemLabelId, SystemSet, SystemStage, + IntoSystemDescriptor, RunCriteria, RunCriteriaDescriptorCoercion, ShouldRun, + SingleThreadedExecutor, Stage, SystemLabel, SystemLabelId, SystemSet, SystemStage, }, - system::{In, IntoExclusiveSystem, Local, Query, ResMut}, + system::{In, Local, Query, ResMut}, world::World, }; @@ -1007,10 +980,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_system(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_system(make_exclusive(2).before_commands()) + .with_system(make_exclusive(3).at_end()); stage.run(&mut world); assert_eq!(*world.resource_mut::>(), vec![0, 1, 2, 3]); stage.set_executor(Box::new(SingleThreadedExecutor::default())); @@ -1022,10 +995,10 @@ mod tests { world.resource_mut::>().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_system(make_exclusive(2).before_commands()) + .with_system(make_exclusive(3).at_end()) .with_system(make_parallel(1)) - .with_system(make_exclusive(0).exclusive_system().at_start()); + .with_system(make_exclusive(0).at_start()); stage.run(&mut world); assert_eq!(*world.resource::>(), vec![0, 1, 2, 3]); stage.set_executor(Box::new(SingleThreadedExecutor::default())); @@ -1037,10 +1010,10 @@ mod tests { world.resource_mut::>().clear(); let mut stage = SystemStage::parallel() - .with_system(make_parallel(2).exclusive_system().before_commands()) - .with_system(make_parallel(3).exclusive_system().at_end()) + .with_system(make_parallel(2).before_commands()) + .with_system(make_parallel(3).at_end()) .with_system(make_parallel(1)) - .with_system(make_parallel(0).exclusive_system().at_start()); + .with_system(make_parallel(0).at_start()); stage.run(&mut world); assert_eq!(*world.resource::>(), vec![0, 1, 2, 3]); stage.set_executor(Box::new(SingleThreadedExecutor::default())); @@ -1056,9 +1029,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_system(make_exclusive(1).label("1").after("0")) + .with_system(make_exclusive(2).after("1")) + .with_system(make_exclusive(0).label("0")); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); @@ -1070,9 +1043,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").before("2")) - .with_system(make_exclusive(2).exclusive_system().label("2")) - .with_system(make_exclusive(0).exclusive_system().before("1")); + .with_system(make_exclusive(1).label("1").before("2")) + .with_system(make_exclusive(2).label("2")) + .with_system(make_exclusive(0).before("1")); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); @@ -1084,11 +1057,11 @@ mod tests { let mut world = World::new(); world.insert_resource(Vec::::new()); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(2).exclusive_system().label("2")) - .with_system(make_exclusive(1).exclusive_system().after("0").before("2")) - .with_system(make_exclusive(0).exclusive_system().label("0")) - .with_system(make_exclusive(4).exclusive_system().label("4")) - .with_system(make_exclusive(3).exclusive_system().after("2").before("4")); + .with_system(make_exclusive(2).label("2")) + .with_system(make_exclusive(1).after("0").before("2")) + .with_system(make_exclusive(0).label("0")) + .with_system(make_exclusive(4).label("4")) + .with_system(make_exclusive(3).after("2").before("4")); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); @@ -1103,19 +1076,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("first") - .after("0"), - ) - .with_system(make_exclusive(2).exclusive_system().after("first")) - .with_system( - make_exclusive(0) - .exclusive_system() - .label("first") - .label("0"), - ); + .with_system(make_exclusive(1).label("first").after("0")) + .with_system(make_exclusive(2).after("first")) + .with_system(make_exclusive(0).label("first").label("0")); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); @@ -1123,11 +1086,11 @@ mod tests { world.resource_mut::>().clear(); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(2).exclusive_system().after("01").label("2")) - .with_system(make_exclusive(1).exclusive_system().label("01").after("0")) - .with_system(make_exclusive(0).exclusive_system().label("01").label("0")) - .with_system(make_exclusive(4).exclusive_system().label("4")) - .with_system(make_exclusive(3).exclusive_system().after("2").before("4")); + .with_system(make_exclusive(2).after("01").label("2")) + .with_system(make_exclusive(1).label("01").after("0")) + .with_system(make_exclusive(0).label("01").label("0")) + .with_system(make_exclusive(4).label("4")) + .with_system(make_exclusive(3).after("2").before("4")); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); @@ -1138,22 +1101,11 @@ mod tests { world.resource_mut::>().clear(); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(2).exclusive_system().label("234").label("2")) - .with_system( - make_exclusive(1) - .exclusive_system() - .before("234") - .after("0"), - ) - .with_system(make_exclusive(0).exclusive_system().label("0")) - .with_system(make_exclusive(4).exclusive_system().label("234").label("4")) - .with_system( - make_exclusive(3) - .exclusive_system() - .label("234") - .after("2") - .before("4"), - ); + .with_system(make_exclusive(2).label("234").label("2")) + .with_system(make_exclusive(1).before("234").after("0")) + .with_system(make_exclusive(0).label("0")) + .with_system(make_exclusive(4).label("234").label("4")) + .with_system(make_exclusive(3).label("234").after("2").before("4")); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); @@ -1170,7 +1122,6 @@ mod tests { let mut stage = SystemStage::parallel() .with_system( make_exclusive(2) - .exclusive_system() .label("2") .after("1") .before("3") @@ -1178,21 +1129,14 @@ mod tests { ) .with_system( make_exclusive(1) - .exclusive_system() .label("1") .after("0") .after("0") .before("2"), ) - .with_system(make_exclusive(0).exclusive_system().label("0").before("1")) - .with_system(make_exclusive(4).exclusive_system().label("4").after("3")) - .with_system( - make_exclusive(3) - .exclusive_system() - .label("3") - .after("2") - .before("4"), - ); + .with_system(make_exclusive(0).label("0").before("1")) + .with_system(make_exclusive(4).label("4").after("3")) + .with_system(make_exclusive(3).label("3").after("2").before("4")); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); @@ -1207,14 +1151,14 @@ mod tests { let mut world = World::new(); world.insert_resource(Vec::::new()); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(2).exclusive_system().label("2")) + .with_system(make_exclusive(2).label("2")) .with_system_set( SystemSet::new() - .with_system(make_exclusive(0).exclusive_system().label("0")) - .with_system(make_exclusive(4).exclusive_system().label("4")) - .with_system(make_exclusive(3).exclusive_system().after("2").before("4")), + .with_system(make_exclusive(0).label("0")) + .with_system(make_exclusive(4).label("4")) + .with_system(make_exclusive(3).after("2").before("4")), ) - .with_system(make_exclusive(1).exclusive_system().after("0").before("2")); + .with_system(make_exclusive(1).after("0").before("2")); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); @@ -1229,13 +1173,13 @@ mod tests { let mut world = World::new(); world.insert_resource(Vec::::new()); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(0).exclusive_system().before("1")) + .with_system(make_exclusive(0).before("1")) .with_system_set( SystemSet::new() .with_run_criteria(every_other_time) - .with_system(make_exclusive(1).exclusive_system().label("1")), + .with_system(make_exclusive(1).label("1")), ) - .with_system(make_exclusive(2).exclusive_system().after("1")); + .with_system(make_exclusive(2).after("1")); stage.run(&mut world); stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); @@ -1252,8 +1196,8 @@ mod tests { fn exclusive_cycle_1() { let mut world = World::new(); world.insert_resource(Vec::::new()); - let mut stage = SystemStage::parallel() - .with_system(make_exclusive(0).exclusive_system().label("0").after("0")); + let mut stage = + SystemStage::parallel().with_system(make_exclusive(0).label("0").after("0")); stage.run(&mut world); } @@ -1263,8 +1207,8 @@ mod tests { let mut world = World::new(); world.insert_resource(Vec::::new()); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(0).exclusive_system().label("0").after("1")) - .with_system(make_exclusive(1).exclusive_system().label("1").after("0")); + .with_system(make_exclusive(0).label("0").after("1")) + .with_system(make_exclusive(1).label("1").after("0")); stage.run(&mut world); } @@ -1274,9 +1218,9 @@ mod tests { let mut world = World::new(); world.insert_resource(Vec::::new()); let mut stage = SystemStage::parallel() - .with_system(make_exclusive(0).exclusive_system().label("0")) - .with_system(make_exclusive(1).exclusive_system().after("0").before("2")) - .with_system(make_exclusive(2).exclusive_system().label("2").before("0")); + .with_system(make_exclusive(0).label("0")) + .with_system(make_exclusive(1).after("0").before("2")) + .with_system(make_exclusive(2).label("2").before("0")); stage.run(&mut world); } @@ -1630,6 +1574,7 @@ mod tests { fn empty() {} fn resource(_: ResMut) {} fn component(_: Query<&mut W>) {} + fn exclusive(_: &mut World) {} let mut world = World::new(); @@ -1897,26 +1842,26 @@ mod tests { assert_eq!(ambiguities.len(), 2); let mut stage = SystemStage::parallel() - .with_system(empty.exclusive_system().label("0")) - .with_system(empty.exclusive_system().label("1").after("0")) - .with_system(empty.exclusive_system().label("2").after("1")) - .with_system(empty.exclusive_system().label("3").after("2")) - .with_system(empty.exclusive_system().label("4").after("3")) - .with_system(empty.exclusive_system().label("5").after("4")) - .with_system(empty.exclusive_system().label("6").after("5")) - .with_system(empty.exclusive_system().label("7").after("6")); + .with_system(exclusive.label("0")) + .with_system(exclusive.label("1").after("0")) + .with_system(exclusive.label("2").after("1")) + .with_system(exclusive.label("3").after("2")) + .with_system(exclusive.label("4").after("3")) + .with_system(exclusive.label("5").after("4")) + .with_system(exclusive.label("6").after("5")) + .with_system(exclusive.label("7").after("6")); stage.initialize_systems(&mut world); stage.rebuild_orders_and_dependencies(); assert_eq!(find_ambiguities(&stage.exclusive_at_start).len(), 0); let mut stage = SystemStage::parallel() - .with_system(empty.exclusive_system().label("0").before("1").before("3")) - .with_system(empty.exclusive_system().label("1")) - .with_system(empty.exclusive_system().label("2").after("1")) - .with_system(empty.exclusive_system().label("3")) - .with_system(empty.exclusive_system().label("4").after("3").before("5")) - .with_system(empty.exclusive_system().label("5")) - .with_system(empty.exclusive_system().label("6").after("2").after("5")); + .with_system(exclusive.label("0").before("1").before("3")) + .with_system(exclusive.label("1")) + .with_system(exclusive.label("2").after("1")) + .with_system(exclusive.label("3")) + .with_system(exclusive.label("4").after("3").before("5")) + .with_system(exclusive.label("5")) + .with_system(exclusive.label("6").after("2").after("5")); stage.initialize_systems(&mut world); stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_first_str_labels(&stage.exclusive_at_start); @@ -1947,13 +1892,13 @@ mod tests { assert_eq!(ambiguities.len(), 6); let mut stage = SystemStage::parallel() - .with_system(empty.exclusive_system().label("0").before("1").before("3")) - .with_system(empty.exclusive_system().label("1").in_ambiguity_set("a")) - .with_system(empty.exclusive_system().label("2").after("1")) - .with_system(empty.exclusive_system().label("3").in_ambiguity_set("a")) - .with_system(empty.exclusive_system().label("4").after("3").before("5")) - .with_system(empty.exclusive_system().label("5").in_ambiguity_set("a")) - .with_system(empty.exclusive_system().label("6").after("2").after("5")); + .with_system(exclusive.label("0").before("1").before("3")) + .with_system(exclusive.label("1").in_ambiguity_set("a")) + .with_system(exclusive.label("2").after("1")) + .with_system(exclusive.label("3").in_ambiguity_set("a")) + .with_system(exclusive.label("4").after("3").before("5")) + .with_system(exclusive.label("5").in_ambiguity_set("a")) + .with_system(exclusive.label("6").after("2").after("5")); stage.initialize_systems(&mut world); stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_first_str_labels(&stage.exclusive_at_start); @@ -1976,10 +1921,10 @@ mod tests { assert_eq!(ambiguities.len(), 4); let mut stage = SystemStage::parallel() - .with_system(empty.exclusive_system().label("0").in_ambiguity_set("a")) - .with_system(empty.exclusive_system().label("1").in_ambiguity_set("a")) - .with_system(empty.exclusive_system().label("2").in_ambiguity_set("a")) - .with_system(empty.exclusive_system().label("3").in_ambiguity_set("a")); + .with_system(exclusive.label("0").in_ambiguity_set("a")) + .with_system(exclusive.label("1").in_ambiguity_set("a")) + .with_system(exclusive.label("2").in_ambiguity_set("a")) + .with_system(exclusive.label("3").in_ambiguity_set("a")); stage.initialize_systems(&mut world); stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_first_str_labels(&stage.exclusive_at_start); diff --git a/crates/bevy_ecs/src/schedule/system_container.rs b/crates/bevy_ecs/src/schedule/system_container.rs index 51d0962489143..5c9319df2788d 100644 --- a/crates/bevy_ecs/src/schedule/system_container.rs +++ b/crates/bevy_ecs/src/schedule/system_container.rs @@ -2,10 +2,9 @@ use crate::{ component::ComponentId, query::Access, schedule::{ - AmbiguitySetLabelId, ExclusiveSystemDescriptor, GraphNode, ParallelSystemDescriptor, - RunCriteriaLabelId, SystemLabelId, + AmbiguitySetLabelId, GraphNode, RunCriteriaLabelId, SystemDescriptor, SystemLabelId, }, - system::{ExclusiveSystem, System}, + system::System, }; use std::borrow::Cow; @@ -24,88 +23,7 @@ pub trait SystemContainer: GraphNode