From cfd590c9f9a57dc0624dfb3f369618fe4ae06d41 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Mon, 19 Jul 2021 20:57:51 +0200 Subject: [PATCH 01/17] Add ScheduleCommands --- crates/bevy_core/src/time/fixed_timestep.rs | 6 +- crates/bevy_ecs/src/schedule/commands.rs | 121 ++++++++++++++++++ crates/bevy_ecs/src/schedule/mod.rs | 12 ++ crates/bevy_ecs/src/schedule/run_criteria.rs | 3 +- crates/bevy_ecs/src/schedule/stage.rs | 41 ++++-- .../bevy_ecs/src/system/exclusive_system.rs | 11 ++ crates/bevy_ecs/src/system/function_system.rs | 6 + crates/bevy_ecs/src/system/system.rs | 8 +- crates/bevy_ecs/src/system/system_chaining.rs | 14 ++ crates/bevy_ecs/src/system/system_param.rs | 60 +++++++++ 10 files changed, 266 insertions(+), 16 deletions(-) create mode 100644 crates/bevy_ecs/src/schedule/commands.rs diff --git a/crates/bevy_core/src/time/fixed_timestep.rs b/crates/bevy_core/src/time/fixed_timestep.rs index c03d87296fa50..b7bd520696c4e 100644 --- a/crates/bevy_core/src/time/fixed_timestep.rs +++ b/crates/bevy_core/src/time/fixed_timestep.rs @@ -3,7 +3,7 @@ use bevy_ecs::{ archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, - schedule::ShouldRun, + schedule::{ScheduleCommandQueue, ShouldRun}, system::{IntoSystem, Local, Res, ResMut, System, SystemId}, world::World, }; @@ -178,6 +178,10 @@ impl System for FixedTimestep { self.internal_system.apply_buffers(world) } + fn schedule_commands(&mut self) -> Option { + self.internal_system.schedule_commands() + } + fn initialize(&mut self, world: &mut World) { self.internal_system = Box::new( Self::prepare_system diff --git a/crates/bevy_ecs/src/schedule/commands.rs b/crates/bevy_ecs/src/schedule/commands.rs new file mode 100644 index 0000000000000..1ec578d1c2914 --- /dev/null +++ b/crates/bevy_ecs/src/schedule/commands.rs @@ -0,0 +1,121 @@ +use std::marker::PhantomData; + +use super::{IntoSystemDescriptor, Schedule, StageLabel}; + +#[derive(Default)] +pub struct ScheduleCommandQueue { + items: Vec> +} + +impl ScheduleCommandQueue { + pub fn push(&mut self, command: C) + where + C: ScheduleCommand, + { + self.items.push(Box::new(command)); + } + + pub fn apply(&mut self, schedule: &mut Schedule) { + for command in self.items.drain(..) { + command.write(schedule); + } + } + + pub fn transfer(&mut self, queue: &mut ScheduleCommandQueue) { + queue.items.extend(self.items.drain(..)); + } + + pub fn is_empty(&self) -> bool { + self.items.is_empty() + } +} + +/// A [`Schedule`] mutation. +pub trait ScheduleCommand: Send + Sync + 'static { + fn write(self: Box, schedule: &mut Schedule); +} + +pub struct ScheduleCommands<'a> { + queue: &'a mut ScheduleCommandQueue +} + +impl<'a> ScheduleCommands<'a> { + pub fn new(queue: &'a mut ScheduleCommandQueue) -> Self { + Self { + queue + } + } + + pub fn insert_system(&mut self, system: T, stage_label: S) + where + T: IntoSystemDescriptor + Send + Sync, + S: StageLabel + { + self.queue.push(InsertSystem { + system: system, + stage_label: stage_label, + phantom: Default::default(), + }); + } +} + +pub struct InsertSystem +where + T: IntoSystemDescriptor, + S: StageLabel +{ + pub system: T, + pub stage_label: S, + phantom: PhantomData Params>, +} + +impl ScheduleCommand for InsertSystem +where + T: IntoSystemDescriptor + Send + Sync, + S: StageLabel +{ + fn write(self: Box, schedule: &mut Schedule) { + schedule.add_system_to_stage(self.stage_label, self.system); + } +} + +#[cfg(test)] +mod tests { + use crate::{ + schedule::{Schedule, ScheduleCommands, ScheduleCommandQueue, SystemStage}, + system::Commands, + world::World, + }; + + #[test] + fn insert_system() { + fn sample_system(mut _commands: Commands) { + + } + let mut schedule = Schedule::default(); + schedule.add_stage("test", SystemStage::parallel()); + let mut queue = ScheduleCommandQueue::default(); + let mut schedule_commands = ScheduleCommands::new(&mut queue); + schedule_commands.insert_system(sample_system, "test"); + queue.apply(&mut schedule); + + let stage = schedule.get_stage::(&"test").unwrap(); + assert_eq!(stage.parallel_systems().len(), 1); + } + + #[test] + fn insert_system_from_system() { + fn sample_system(mut schedule_commands: ScheduleCommands) { + schedule_commands.insert_system(|| {}, "test"); + } + + let mut world = World::default(); + let mut schedule = Schedule::default(); + schedule.add_stage("test", SystemStage::parallel()); + schedule.add_system_to_stage("test", sample_system); + schedule.run_once(&mut world); + + let stage = schedule.get_stage::(&"test").unwrap(); + assert_eq!(stage.parallel_systems().len(), 2); + } +} diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 67f21025cf0bf..65a660d91c627 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -8,6 +8,7 @@ mod state; mod system_container; mod system_descriptor; mod system_set; +mod commands; pub use executor::*; pub use executor_parallel::*; @@ -19,6 +20,7 @@ pub use state::*; pub use system_container::*; pub use system_descriptor::*; pub use system_set::*; +pub use commands::*; use std::fmt::Debug; @@ -198,6 +200,7 @@ impl Schedule { } pub fn run_once(&mut self, world: &mut World) { + let mut commands = ScheduleCommandQueue::default(); for label in self.stage_order.iter() { #[cfg(feature = "trace")] let stage_span = @@ -206,7 +209,12 @@ impl Schedule { let _stage_guard = stage_span.enter(); let stage = self.stages.get_mut(label).unwrap(); stage.run(world); + if let Some(mut stage_commands) = stage.commands() { + stage_commands.transfer(&mut commands); + } } + + commands.apply(self); } /// Iterates over all of schedule's stages and their labels, in execution order. @@ -235,4 +243,8 @@ impl Stage for Schedule { } } } + + fn commands(&mut self) -> Option { + None + } } diff --git a/crates/bevy_ecs/src/schedule/run_criteria.rs b/crates/bevy_ecs/src/schedule/run_criteria.rs index 7e3da8a5f3b3f..366b83dbd5dc8 100644 --- a/crates/bevy_ecs/src/schedule/run_criteria.rs +++ b/crates/bevy_ecs/src/schedule/run_criteria.rs @@ -2,7 +2,7 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration}, component::ComponentId, query::Access, - schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel}, + schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel, ScheduleCommandQueue}, system::{BoxedSystem, IntoSystem, System, SystemId}, world::World, }; @@ -450,6 +450,7 @@ impl System for RunOnce { } fn apply_buffers(&mut self, _world: &mut World) {} + fn schedule_commands(&mut self) -> Option { None } fn initialize(&mut self, _world: &mut World) {} diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index 8eed39d3aa8e7..98787efbf61dc 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -5,10 +5,10 @@ use crate::{ BoxedRunCriteria, BoxedRunCriteriaLabel, BoxedSystemLabel, DuplicateLabelStrategy, ExclusiveSystemContainer, GraphNode, InsertionPoint, ParallelExecutor, ParallelSystemContainer, ParallelSystemExecutor, RunCriteriaContainer, - RunCriteriaDescriptor, RunCriteriaDescriptorOrLabel, RunCriteriaInner, ShouldRun, - SingleThreadedExecutor, SystemContainer, SystemDescriptor, SystemSet, + RunCriteriaDescriptor, RunCriteriaDescriptorOrLabel, RunCriteriaInner, + ShouldRun, SingleThreadedExecutor, SystemContainer, SystemDescriptor, SystemSet, }, - system::System, + system::{System, ExclusiveSystem}, world::{World, WorldId}, }; use bevy_utils::{tracing::info, HashMap, HashSet}; @@ -16,12 +16,13 @@ use downcast_rs::{impl_downcast, Downcast}; use fixedbitset::FixedBitSet; use std::fmt::Debug; -use super::IntoSystemDescriptor; +use super::{IntoSystemDescriptor, ScheduleCommandQueue}; pub trait Stage: Downcast + Send + Sync { /// Runs the stage; this happens once per update. /// Implementors must initialize all of their state and systems before running the first time. fn run(&mut self, world: &mut World); + fn commands(&mut self) -> Option; } impl_downcast!(Stage); @@ -83,6 +84,8 @@ pub struct SystemStage { uninitialized_parallel: Vec, /// Saves the value of the World change_tick during the last tick check last_tick_check: u32, + // Contains commands for the schedule + schedule_commands: ScheduleCommandQueue, } impl SystemStage { @@ -104,6 +107,7 @@ impl SystemStage { uninitialized_before_commands: vec![], uninitialized_at_end: vec![], last_tick_check: Default::default(), + schedule_commands: Default::default(), } } @@ -805,10 +809,17 @@ impl Stage for SystemStage { ) } + fn run_exclusive(world: &mut World, system: &mut Box, commands: &mut ScheduleCommandQueue) { + system.run(world); + if let Some(mut c) = system.schedule_commands() { + c.transfer(commands); + } + } + // 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) { - container.system_mut().run(world); + run_exclusive(world, container.system_mut(), &mut self.schedule_commands); } } @@ -823,21 +834,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) { - container.system_mut().run(world); + run_exclusive(world, container.system_mut(), &mut self.schedule_commands); } } // Apply parallel systems' buffers. for container in &mut self.parallel { if container.should_run { - container.system_mut().apply_buffers(world); + let system = container.system_mut(); + system.apply_buffers(world); + if let Some(mut commands) = system.schedule_commands() { + commands.transfer(&mut self.schedule_commands); + } } } // 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) { - container.system_mut().run(world); + run_exclusive(world, container.system_mut(), &mut self.schedule_commands); } } @@ -885,6 +900,16 @@ impl Stage for SystemStage { } } } + + fn commands(&mut self) -> Option { + if self.schedule_commands.is_empty() { + return None; + } + + let mut commands = Default::default(); + self.schedule_commands.transfer(&mut commands); + Some(commands) + } } #[cfg(test)] diff --git a/crates/bevy_ecs/src/system/exclusive_system.rs b/crates/bevy_ecs/src/system/exclusive_system.rs index 10364375f71ef..46b254511b72e 100644 --- a/crates/bevy_ecs/src/system/exclusive_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_system.rs @@ -1,5 +1,6 @@ use crate::{ archetype::ArchetypeGeneration, + schedule::ScheduleCommandQueue, system::{check_system_change_tick, BoxedSystem, IntoSystem, SystemId}, world::World, }; @@ -12,6 +13,8 @@ pub trait ExclusiveSystem: Send + Sync + 'static { fn run(&mut self, world: &mut World); + fn schedule_commands(&mut self) -> Option; + fn initialize(&mut self, world: &mut World); fn check_change_tick(&mut self, change_tick: u32); @@ -48,6 +51,10 @@ impl ExclusiveSystem for ExclusiveSystemFn { world.last_change_tick = saved_last_tick; } + fn schedule_commands(&mut self) -> Option { + None + } + fn initialize(&mut self, _: &mut World) {} fn check_change_tick(&mut self, change_tick: u32) { @@ -101,6 +108,10 @@ impl ExclusiveSystem for ExclusiveSystemCoerced { self.system.apply_buffers(world); } + fn schedule_commands(&mut self) -> Option { + self.system.schedule_commands() + } + fn initialize(&mut self, world: &mut World) { self.system.initialize(world); } diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index a8de42abf54f9..3c658f5a3c15f 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -7,6 +7,7 @@ use crate::{ SystemParamFetch, SystemParamState, }, world::{World, WorldId}, + schedule::ScheduleCommandQueue, }; use bevy_ecs_macros::all_tuples; use std::{borrow::Cow, marker::PhantomData}; @@ -383,6 +384,11 @@ where param_state.apply(world); } + fn schedule_commands(&mut self) -> Option { + let param_state = self.param_state.as_mut().unwrap(); + param_state.schedule_commands() + } + #[inline] fn initialize(&mut self, world: &mut World) { self.param_state = Some(::init( diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index 12b77135a14c2..58c5a1f89a14f 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -1,11 +1,6 @@ use bevy_utils::tracing::warn; -use crate::{ - archetype::{Archetype, ArchetypeComponentId}, - component::ComponentId, - query::Access, - world::World, -}; +use crate::{archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, schedule::ScheduleCommandQueue, world::World}; use std::borrow::Cow; /// A [`System`] identifier. @@ -66,6 +61,7 @@ pub trait System: Send + Sync + 'static { unsafe { self.run_unsafe(input, world) } } fn apply_buffers(&mut self, world: &mut World); + fn schedule_commands(&mut self) -> Option; /// Initialize the system. fn initialize(&mut self, _world: &mut World); fn check_change_tick(&mut self, change_tick: u32); diff --git a/crates/bevy_ecs/src/system/system_chaining.rs b/crates/bevy_ecs/src/system/system_chaining.rs index 736bf066331ea..7d9f13f469d16 100644 --- a/crates/bevy_ecs/src/system/system_chaining.rs +++ b/crates/bevy_ecs/src/system/system_chaining.rs @@ -2,6 +2,7 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, + schedule::ScheduleCommandQueue, system::{IntoSystem, System, SystemId}, world::World, }; @@ -97,6 +98,19 @@ impl> System for ChainSystem self.system_b.apply_buffers(world); } + fn schedule_commands(&mut self) -> Option { + let mut commands = self.system_a.schedule_commands(); + if let Some(commands) = &mut commands { + if let Some(mut c) = self.system_b.schedule_commands() { + c.transfer(commands); + } + } else { + commands = self.system_b.schedule_commands(); + } + + commands + } + fn initialize(&mut self, world: &mut World) { self.system_a.initialize(world); self.system_b.initialize(world); diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 632501a56917f..46326f91c88de 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -8,6 +8,7 @@ use crate::{ query::{ FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch, WorldQuery, }, + schedule::{ScheduleCommandQueue, ScheduleCommands}, system::{CommandQueue, Commands, Query, SystemMeta}, world::{FromWorld, World}, }; @@ -71,6 +72,7 @@ pub unsafe trait SystemParamState: Send + Sync + 'static { fn new_archetype(&mut self, _archetype: &Archetype, _system_meta: &mut SystemMeta) {} #[inline] fn apply(&mut self, _world: &mut World) {} + fn schedule_commands(&mut self) -> Option { None } fn default_config() -> Self::Config; } @@ -506,6 +508,48 @@ impl<'a> SystemParamFetch<'a> for CommandQueue { } } +impl<'a> SystemParam for ScheduleCommands<'a> { + type Fetch = ScheduleCommandQueue; +} + +// SAFE: ScheduleCommands only accesses internal state +unsafe impl ReadOnlySystemParamFetch for ScheduleCommandQueue {} + +// SAFE: only local state is accessed +unsafe impl SystemParamState for ScheduleCommandQueue { + type Config = (); + + fn init(_world: &mut World, _system_meta: &mut SystemMeta, _config: Self::Config) -> Self { + Default::default() + } + + fn schedule_commands(&mut self) -> Option { + if self.is_empty() { + return None; + } + + let mut commands = Default::default(); + self.transfer(&mut commands); + Some(commands) + } + + fn default_config() {} +} + +impl<'a> SystemParamFetch<'a> for ScheduleCommandQueue { + type Item = ScheduleCommands<'a>; + + #[inline] + unsafe fn get_param( + state: &'a mut Self, + _system_meta: &SystemMeta, + _world: &'a World, + _change_tick: u32, + ) -> Self::Item { + ScheduleCommands::new(state) + } +} + /// A system local [`SystemParam`]. /// /// A local may only be accessed by the system itself and is therefore not visible to other systems. @@ -1192,6 +1236,22 @@ macro_rules! impl_system_param_tuple { $($param.apply(_world);)* } + #[allow(unused_mut)] // needed for zero parameters + fn schedule_commands(&mut self) -> Option { + let ($($param,)*) = self; + let mut commands = ScheduleCommandQueue::default(); + $( + if let Some(mut c) = $param.schedule_commands() { + c.transfer(&mut commands); + } + )* + if commands.is_empty() { + None + } else { + Some(commands) + } + } + fn default_config() -> ($(<$param as SystemParamState>::Config,)*) { ($(<$param as SystemParamState>::default_config(),)*) } From e5ffab93c1563a39e2b72319c1a8342e1868f31d Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Tue, 20 Jul 2021 20:50:18 +0200 Subject: [PATCH 02/17] Fix formatting --- crates/bevy_ecs/src/schedule/commands.rs | 26 ++++++++----------- crates/bevy_ecs/src/schedule/mod.rs | 4 +-- crates/bevy_ecs/src/schedule/run_criteria.rs | 4 ++- crates/bevy_ecs/src/schedule/stage.rs | 12 ++++++--- crates/bevy_ecs/src/system/function_system.rs | 2 +- crates/bevy_ecs/src/system/system.rs | 8 +++++- crates/bevy_ecs/src/system/system_param.rs | 4 ++- 7 files changed, 35 insertions(+), 25 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/commands.rs b/crates/bevy_ecs/src/schedule/commands.rs index 1ec578d1c2914..a415930bdf913 100644 --- a/crates/bevy_ecs/src/schedule/commands.rs +++ b/crates/bevy_ecs/src/schedule/commands.rs @@ -4,12 +4,12 @@ use super::{IntoSystemDescriptor, Schedule, StageLabel}; #[derive(Default)] pub struct ScheduleCommandQueue { - items: Vec> + items: Vec>, } impl ScheduleCommandQueue { pub fn push(&mut self, command: C) - where + where C: ScheduleCommand, { self.items.push(Box::new(command)); @@ -36,24 +36,22 @@ pub trait ScheduleCommand: Send + Sync + 'static { } pub struct ScheduleCommands<'a> { - queue: &'a mut ScheduleCommandQueue + queue: &'a mut ScheduleCommandQueue, } impl<'a> ScheduleCommands<'a> { pub fn new(queue: &'a mut ScheduleCommandQueue) -> Self { - Self { - queue - } + Self { queue } } pub fn insert_system(&mut self, system: T, stage_label: S) where T: IntoSystemDescriptor + Send + Sync, - S: StageLabel + S: StageLabel, { self.queue.push(InsertSystem { - system: system, - stage_label: stage_label, + system, + stage_label, phantom: Default::default(), }); } @@ -62,7 +60,7 @@ impl<'a> ScheduleCommands<'a> { pub struct InsertSystem where T: IntoSystemDescriptor, - S: StageLabel + S: StageLabel, { pub system: T, pub stage_label: S, @@ -72,7 +70,7 @@ where impl ScheduleCommand for InsertSystem where T: IntoSystemDescriptor + Send + Sync, - S: StageLabel + S: StageLabel, { fn write(self: Box, schedule: &mut Schedule) { schedule.add_system_to_stage(self.stage_label, self.system); @@ -82,16 +80,14 @@ where #[cfg(test)] mod tests { use crate::{ - schedule::{Schedule, ScheduleCommands, ScheduleCommandQueue, SystemStage}, + schedule::{Schedule, ScheduleCommandQueue, ScheduleCommands, SystemStage}, system::Commands, world::World, }; #[test] fn insert_system() { - fn sample_system(mut _commands: Commands) { - - } + fn sample_system(mut _commands: Commands) {} let mut schedule = Schedule::default(); schedule.add_stage("test", SystemStage::parallel()); let mut queue = ScheduleCommandQueue::default(); diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 65a660d91c627..5b0c19eca595b 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -1,3 +1,4 @@ +mod commands; mod executor; mod executor_parallel; pub mod graph_utils; @@ -8,8 +9,8 @@ mod state; mod system_container; mod system_descriptor; mod system_set; -mod commands; +pub use commands::*; pub use executor::*; pub use executor_parallel::*; pub use graph_utils::GraphNode; @@ -20,7 +21,6 @@ pub use state::*; pub use system_container::*; pub use system_descriptor::*; pub use system_set::*; -pub use commands::*; use std::fmt::Debug; diff --git a/crates/bevy_ecs/src/schedule/run_criteria.rs b/crates/bevy_ecs/src/schedule/run_criteria.rs index 366b83dbd5dc8..2a5eafdea89c9 100644 --- a/crates/bevy_ecs/src/schedule/run_criteria.rs +++ b/crates/bevy_ecs/src/schedule/run_criteria.rs @@ -450,7 +450,9 @@ impl System for RunOnce { } fn apply_buffers(&mut self, _world: &mut World) {} - fn schedule_commands(&mut self) -> Option { None } + fn schedule_commands(&mut self) -> Option { + None + } fn initialize(&mut self, _world: &mut World) {} diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index 98787efbf61dc..b7b0d03e30d3c 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -5,10 +5,10 @@ use crate::{ BoxedRunCriteria, BoxedRunCriteriaLabel, BoxedSystemLabel, DuplicateLabelStrategy, ExclusiveSystemContainer, GraphNode, InsertionPoint, ParallelExecutor, ParallelSystemContainer, ParallelSystemExecutor, RunCriteriaContainer, - RunCriteriaDescriptor, RunCriteriaDescriptorOrLabel, RunCriteriaInner, - ShouldRun, SingleThreadedExecutor, SystemContainer, SystemDescriptor, SystemSet, + RunCriteriaDescriptor, RunCriteriaDescriptorOrLabel, RunCriteriaInner, ShouldRun, + SingleThreadedExecutor, SystemContainer, SystemDescriptor, SystemSet, }, - system::{System, ExclusiveSystem}, + system::{ExclusiveSystem, System}, world::{World, WorldId}, }; use bevy_utils::{tracing::info, HashMap, HashSet}; @@ -809,7 +809,11 @@ impl Stage for SystemStage { ) } - fn run_exclusive(world: &mut World, system: &mut Box, commands: &mut ScheduleCommandQueue) { + fn run_exclusive( + world: &mut World, + system: &mut Box, + commands: &mut ScheduleCommandQueue, + ) { system.run(world); if let Some(mut c) = system.schedule_commands() { c.transfer(commands); diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 3c658f5a3c15f..7038d411b38f8 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -2,12 +2,12 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration, ArchetypeId}, component::ComponentId, query::{Access, FilteredAccessSet}, + schedule::ScheduleCommandQueue, system::{ check_system_change_tick, ReadOnlySystemParamFetch, System, SystemId, SystemParam, SystemParamFetch, SystemParamState, }, world::{World, WorldId}, - schedule::ScheduleCommandQueue, }; use bevy_ecs_macros::all_tuples; use std::{borrow::Cow, marker::PhantomData}; diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index 58c5a1f89a14f..7ac7ea4cd818e 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -1,6 +1,12 @@ use bevy_utils::tracing::warn; -use crate::{archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, schedule::ScheduleCommandQueue, world::World}; +use crate::{ + archetype::{Archetype, ArchetypeComponentId}, + component::ComponentId, + query::Access, + schedule::ScheduleCommandQueue, + world::World, +}; use std::borrow::Cow; /// A [`System`] identifier. diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 46326f91c88de..75ab6bae2ae02 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -72,7 +72,9 @@ pub unsafe trait SystemParamState: Send + Sync + 'static { fn new_archetype(&mut self, _archetype: &Archetype, _system_meta: &mut SystemMeta) {} #[inline] fn apply(&mut self, _world: &mut World) {} - fn schedule_commands(&mut self) -> Option { None } + fn schedule_commands(&mut self) -> Option { + None + } fn default_config() -> Self::Config; } From 0f471819a872e73c897f971a74453a58a896b56d Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Tue, 20 Jul 2021 22:20:05 +0200 Subject: [PATCH 03/17] Remove warning in impl_system_param_tuple --- crates/bevy_ecs/src/system/system_param.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 75ab6bae2ae02..c1285762f71c2 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -1238,11 +1238,11 @@ macro_rules! impl_system_param_tuple { $($param.apply(_world);)* } - #[allow(unused_mut)] // needed for zero parameters fn schedule_commands(&mut self) -> Option { let ($($param,)*) = self; - let mut commands = ScheduleCommandQueue::default(); + let commands = ScheduleCommandQueue::default(); $( + let mut commands = commands; if let Some(mut c) = $param.schedule_commands() { c.transfer(&mut commands); } From 037ade3d0b9648db33bc1980c2970d952d81b1c1 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Tue, 20 Jul 2021 22:49:33 +0200 Subject: [PATCH 04/17] Impl IntoSystemDescriptor for SystemDescriptor --- crates/bevy_ecs/src/schedule/system_descriptor.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/bevy_ecs/src/schedule/system_descriptor.rs b/crates/bevy_ecs/src/schedule/system_descriptor.rs index b75fbcb89f3db..f20e57d4908df 100644 --- a/crates/bevy_ecs/src/schedule/system_descriptor.rs +++ b/crates/bevy_ecs/src/schedule/system_descriptor.rs @@ -45,6 +45,12 @@ pub trait IntoSystemDescriptor { pub struct SystemLabelMarker; +impl IntoSystemDescriptor<()> for SystemDescriptor { + fn into_descriptor(self) -> SystemDescriptor { + self + } +} + impl IntoSystemDescriptor<()> for ParallelSystemDescriptor { fn into_descriptor(self) -> SystemDescriptor { SystemDescriptor::Parallel(self) From 35df1784dfcf7d524f1d66667f87e8286db857d2 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Tue, 20 Jul 2021 22:50:01 +0200 Subject: [PATCH 05/17] Store SystemDescriptor in InsertSystem --- crates/bevy_ecs/src/schedule/commands.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/commands.rs b/crates/bevy_ecs/src/schedule/commands.rs index a415930bdf913..3eceeb463622e 100644 --- a/crates/bevy_ecs/src/schedule/commands.rs +++ b/crates/bevy_ecs/src/schedule/commands.rs @@ -1,6 +1,4 @@ -use std::marker::PhantomData; - -use super::{IntoSystemDescriptor, Schedule, StageLabel}; +use super::{IntoSystemDescriptor, Schedule, StageLabel, SystemDescriptor}; #[derive(Default)] pub struct ScheduleCommandQueue { @@ -44,32 +42,28 @@ impl<'a> ScheduleCommands<'a> { Self { queue } } - pub fn insert_system(&mut self, system: T, stage_label: S) + pub fn insert_system(&mut self, system: T, stage_label: S) where - T: IntoSystemDescriptor + Send + Sync, + T: IntoSystemDescriptor, S: StageLabel, { self.queue.push(InsertSystem { - system, + system: system.into_descriptor(), stage_label, - phantom: Default::default(), }); } } -pub struct InsertSystem +pub struct InsertSystem where - T: IntoSystemDescriptor, S: StageLabel, { - pub system: T, + pub system: SystemDescriptor, pub stage_label: S, - phantom: PhantomData Params>, } -impl ScheduleCommand for InsertSystem +impl ScheduleCommand for InsertSystem where - T: IntoSystemDescriptor + Send + Sync, S: StageLabel, { fn write(self: Box, schedule: &mut Schedule) { From be001945fd545570c3fe6d7c3d720e32419e00c0 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Tue, 20 Jul 2021 22:58:11 +0200 Subject: [PATCH 06/17] Rename ScheduleCommand to SchedulerCommand --- crates/bevy_core/src/time/fixed_timestep.rs | 6 ++-- crates/bevy_ecs/src/schedule/commands.rs | 34 +++++++++---------- crates/bevy_ecs/src/schedule/mod.rs | 4 +-- crates/bevy_ecs/src/schedule/run_criteria.rs | 4 +-- crates/bevy_ecs/src/schedule/stage.rs | 28 +++++++-------- .../bevy_ecs/src/system/exclusive_system.rs | 10 +++--- crates/bevy_ecs/src/system/function_system.rs | 6 ++-- crates/bevy_ecs/src/system/system.rs | 4 +-- crates/bevy_ecs/src/system/system_chaining.rs | 10 +++--- crates/bevy_ecs/src/system/system_param.rs | 28 +++++++-------- 10 files changed, 67 insertions(+), 67 deletions(-) diff --git a/crates/bevy_core/src/time/fixed_timestep.rs b/crates/bevy_core/src/time/fixed_timestep.rs index b7bd520696c4e..08645ad1ea1f1 100644 --- a/crates/bevy_core/src/time/fixed_timestep.rs +++ b/crates/bevy_core/src/time/fixed_timestep.rs @@ -3,7 +3,7 @@ use bevy_ecs::{ archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, - schedule::{ScheduleCommandQueue, ShouldRun}, + schedule::{SchedulerCommandQueue, ShouldRun}, system::{IntoSystem, Local, Res, ResMut, System, SystemId}, world::World, }; @@ -178,8 +178,8 @@ impl System for FixedTimestep { self.internal_system.apply_buffers(world) } - fn schedule_commands(&mut self) -> Option { - self.internal_system.schedule_commands() + fn scheduler_commands(&mut self) -> Option { + self.internal_system.scheduler_commands() } fn initialize(&mut self, world: &mut World) { diff --git a/crates/bevy_ecs/src/schedule/commands.rs b/crates/bevy_ecs/src/schedule/commands.rs index 3eceeb463622e..5b81586f28238 100644 --- a/crates/bevy_ecs/src/schedule/commands.rs +++ b/crates/bevy_ecs/src/schedule/commands.rs @@ -1,14 +1,14 @@ use super::{IntoSystemDescriptor, Schedule, StageLabel, SystemDescriptor}; #[derive(Default)] -pub struct ScheduleCommandQueue { - items: Vec>, +pub struct SchedulerCommandQueue { + items: Vec>, } -impl ScheduleCommandQueue { +impl SchedulerCommandQueue { pub fn push(&mut self, command: C) where - C: ScheduleCommand, + C: SchedulerCommand, { self.items.push(Box::new(command)); } @@ -19,7 +19,7 @@ impl ScheduleCommandQueue { } } - pub fn transfer(&mut self, queue: &mut ScheduleCommandQueue) { + pub fn transfer(&mut self, queue: &mut SchedulerCommandQueue) { queue.items.extend(self.items.drain(..)); } @@ -29,16 +29,16 @@ impl ScheduleCommandQueue { } /// A [`Schedule`] mutation. -pub trait ScheduleCommand: Send + Sync + 'static { +pub trait SchedulerCommand: Send + Sync + 'static { fn write(self: Box, schedule: &mut Schedule); } -pub struct ScheduleCommands<'a> { - queue: &'a mut ScheduleCommandQueue, +pub struct SchedulerCommands<'a> { + queue: &'a mut SchedulerCommandQueue, } -impl<'a> ScheduleCommands<'a> { - pub fn new(queue: &'a mut ScheduleCommandQueue) -> Self { +impl<'a> SchedulerCommands<'a> { + pub fn new(queue: &'a mut SchedulerCommandQueue) -> Self { Self { queue } } @@ -62,7 +62,7 @@ where pub stage_label: S, } -impl ScheduleCommand for InsertSystem +impl SchedulerCommand for InsertSystem where S: StageLabel, { @@ -74,7 +74,7 @@ where #[cfg(test)] mod tests { use crate::{ - schedule::{Schedule, ScheduleCommandQueue, ScheduleCommands, SystemStage}, + schedule::{Schedule, SchedulerCommandQueue, SchedulerCommands, SystemStage}, system::Commands, world::World, }; @@ -84,9 +84,9 @@ mod tests { fn sample_system(mut _commands: Commands) {} let mut schedule = Schedule::default(); schedule.add_stage("test", SystemStage::parallel()); - let mut queue = ScheduleCommandQueue::default(); - let mut schedule_commands = ScheduleCommands::new(&mut queue); - schedule_commands.insert_system(sample_system, "test"); + let mut queue = SchedulerCommandQueue::default(); + let mut scheduler_commands = SchedulerCommands::new(&mut queue); + scheduler_commands.insert_system(sample_system, "test"); queue.apply(&mut schedule); let stage = schedule.get_stage::(&"test").unwrap(); @@ -95,8 +95,8 @@ mod tests { #[test] fn insert_system_from_system() { - fn sample_system(mut schedule_commands: ScheduleCommands) { - schedule_commands.insert_system(|| {}, "test"); + fn sample_system(mut scheduler_commands: SchedulerCommands) { + scheduler_commands.insert_system(|| {}, "test"); } let mut world = World::default(); diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 5b0c19eca595b..61c131c273edb 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -200,7 +200,7 @@ impl Schedule { } pub fn run_once(&mut self, world: &mut World) { - let mut commands = ScheduleCommandQueue::default(); + let mut commands = SchedulerCommandQueue::default(); for label in self.stage_order.iter() { #[cfg(feature = "trace")] let stage_span = @@ -244,7 +244,7 @@ impl Stage for Schedule { } } - fn commands(&mut self) -> Option { + fn commands(&mut self) -> Option { None } } diff --git a/crates/bevy_ecs/src/schedule/run_criteria.rs b/crates/bevy_ecs/src/schedule/run_criteria.rs index 2a5eafdea89c9..ef0b9e552150f 100644 --- a/crates/bevy_ecs/src/schedule/run_criteria.rs +++ b/crates/bevy_ecs/src/schedule/run_criteria.rs @@ -2,7 +2,7 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration}, component::ComponentId, query::Access, - schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel, ScheduleCommandQueue}, + schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel, SchedulerCommandQueue}, system::{BoxedSystem, IntoSystem, System, SystemId}, world::World, }; @@ -450,7 +450,7 @@ impl System for RunOnce { } fn apply_buffers(&mut self, _world: &mut World) {} - fn schedule_commands(&mut self) -> Option { + fn scheduler_commands(&mut self) -> Option { None } diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index b7b0d03e30d3c..66945678f4597 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -16,13 +16,13 @@ use downcast_rs::{impl_downcast, Downcast}; use fixedbitset::FixedBitSet; use std::fmt::Debug; -use super::{IntoSystemDescriptor, ScheduleCommandQueue}; +use super::{IntoSystemDescriptor, SchedulerCommandQueue}; pub trait Stage: Downcast + Send + Sync { /// Runs the stage; this happens once per update. /// Implementors must initialize all of their state and systems before running the first time. fn run(&mut self, world: &mut World); - fn commands(&mut self) -> Option; + fn commands(&mut self) -> Option; } impl_downcast!(Stage); @@ -85,7 +85,7 @@ pub struct SystemStage { /// Saves the value of the World change_tick during the last tick check last_tick_check: u32, // Contains commands for the schedule - schedule_commands: ScheduleCommandQueue, + scheduler_commands: SchedulerCommandQueue, } impl SystemStage { @@ -107,7 +107,7 @@ impl SystemStage { uninitialized_before_commands: vec![], uninitialized_at_end: vec![], last_tick_check: Default::default(), - schedule_commands: Default::default(), + scheduler_commands: Default::default(), } } @@ -812,10 +812,10 @@ impl Stage for SystemStage { fn run_exclusive( world: &mut World, system: &mut Box, - commands: &mut ScheduleCommandQueue, + commands: &mut SchedulerCommandQueue, ) { system.run(world); - if let Some(mut c) = system.schedule_commands() { + if let Some(mut c) = system.scheduler_commands() { c.transfer(commands); } } @@ -823,7 +823,7 @@ 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) { - run_exclusive(world, container.system_mut(), &mut self.schedule_commands); + run_exclusive(world, container.system_mut(), &mut self.scheduler_commands); } } @@ -838,7 +838,7 @@ 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) { - run_exclusive(world, container.system_mut(), &mut self.schedule_commands); + run_exclusive(world, container.system_mut(), &mut self.scheduler_commands); } } @@ -847,8 +847,8 @@ impl Stage for SystemStage { if container.should_run { let system = container.system_mut(); system.apply_buffers(world); - if let Some(mut commands) = system.schedule_commands() { - commands.transfer(&mut self.schedule_commands); + if let Some(mut commands) = system.scheduler_commands() { + commands.transfer(&mut self.scheduler_commands); } } } @@ -856,7 +856,7 @@ 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) { - run_exclusive(world, container.system_mut(), &mut self.schedule_commands); + run_exclusive(world, container.system_mut(), &mut self.scheduler_commands); } } @@ -905,13 +905,13 @@ impl Stage for SystemStage { } } - fn commands(&mut self) -> Option { - if self.schedule_commands.is_empty() { + fn commands(&mut self) -> Option { + if self.scheduler_commands.is_empty() { return None; } let mut commands = Default::default(); - self.schedule_commands.transfer(&mut commands); + self.scheduler_commands.transfer(&mut commands); Some(commands) } } diff --git a/crates/bevy_ecs/src/system/exclusive_system.rs b/crates/bevy_ecs/src/system/exclusive_system.rs index 46b254511b72e..02a6c3201bc5a 100644 --- a/crates/bevy_ecs/src/system/exclusive_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_system.rs @@ -1,6 +1,6 @@ use crate::{ archetype::ArchetypeGeneration, - schedule::ScheduleCommandQueue, + schedule::SchedulerCommandQueue, system::{check_system_change_tick, BoxedSystem, IntoSystem, SystemId}, world::World, }; @@ -13,7 +13,7 @@ pub trait ExclusiveSystem: Send + Sync + 'static { fn run(&mut self, world: &mut World); - fn schedule_commands(&mut self) -> Option; + fn scheduler_commands(&mut self) -> Option; fn initialize(&mut self, world: &mut World); @@ -51,7 +51,7 @@ impl ExclusiveSystem for ExclusiveSystemFn { world.last_change_tick = saved_last_tick; } - fn schedule_commands(&mut self) -> Option { + fn scheduler_commands(&mut self) -> Option { None } @@ -108,8 +108,8 @@ impl ExclusiveSystem for ExclusiveSystemCoerced { self.system.apply_buffers(world); } - fn schedule_commands(&mut self) -> Option { - self.system.schedule_commands() + fn scheduler_commands(&mut self) -> Option { + self.system.scheduler_commands() } fn initialize(&mut self, world: &mut World) { diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 7038d411b38f8..0e88689648931 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -2,7 +2,7 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration, ArchetypeId}, component::ComponentId, query::{Access, FilteredAccessSet}, - schedule::ScheduleCommandQueue, + schedule::SchedulerCommandQueue, system::{ check_system_change_tick, ReadOnlySystemParamFetch, System, SystemId, SystemParam, SystemParamFetch, SystemParamState, @@ -384,9 +384,9 @@ where param_state.apply(world); } - fn schedule_commands(&mut self) -> Option { + fn scheduler_commands(&mut self) -> Option { let param_state = self.param_state.as_mut().unwrap(); - param_state.schedule_commands() + param_state.scheduler_commands() } #[inline] diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index 7ac7ea4cd818e..44ad6b9773334 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -4,7 +4,7 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, - schedule::ScheduleCommandQueue, + schedule::SchedulerCommandQueue, world::World, }; use std::borrow::Cow; @@ -67,7 +67,7 @@ pub trait System: Send + Sync + 'static { unsafe { self.run_unsafe(input, world) } } fn apply_buffers(&mut self, world: &mut World); - fn schedule_commands(&mut self) -> Option; + fn scheduler_commands(&mut self) -> Option; /// Initialize the system. fn initialize(&mut self, _world: &mut World); fn check_change_tick(&mut self, change_tick: u32); diff --git a/crates/bevy_ecs/src/system/system_chaining.rs b/crates/bevy_ecs/src/system/system_chaining.rs index 7d9f13f469d16..860e253bcf7da 100644 --- a/crates/bevy_ecs/src/system/system_chaining.rs +++ b/crates/bevy_ecs/src/system/system_chaining.rs @@ -2,7 +2,7 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, - schedule::ScheduleCommandQueue, + schedule::SchedulerCommandQueue, system::{IntoSystem, System, SystemId}, world::World, }; @@ -98,14 +98,14 @@ impl> System for ChainSystem self.system_b.apply_buffers(world); } - fn schedule_commands(&mut self) -> Option { - let mut commands = self.system_a.schedule_commands(); + fn scheduler_commands(&mut self) -> Option { + let mut commands = self.system_a.scheduler_commands(); if let Some(commands) = &mut commands { - if let Some(mut c) = self.system_b.schedule_commands() { + if let Some(mut c) = self.system_b.scheduler_commands() { c.transfer(commands); } } else { - commands = self.system_b.schedule_commands(); + commands = self.system_b.scheduler_commands(); } commands diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index c1285762f71c2..4b787c3b0f4b4 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -8,7 +8,7 @@ use crate::{ query::{ FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch, WorldQuery, }, - schedule::{ScheduleCommandQueue, ScheduleCommands}, + schedule::{SchedulerCommandQueue, SchedulerCommands}, system::{CommandQueue, Commands, Query, SystemMeta}, world::{FromWorld, World}, }; @@ -72,7 +72,7 @@ pub unsafe trait SystemParamState: Send + Sync + 'static { fn new_archetype(&mut self, _archetype: &Archetype, _system_meta: &mut SystemMeta) {} #[inline] fn apply(&mut self, _world: &mut World) {} - fn schedule_commands(&mut self) -> Option { + fn scheduler_commands(&mut self) -> Option { None } fn default_config() -> Self::Config; @@ -510,22 +510,22 @@ impl<'a> SystemParamFetch<'a> for CommandQueue { } } -impl<'a> SystemParam for ScheduleCommands<'a> { - type Fetch = ScheduleCommandQueue; +impl<'a> SystemParam for SchedulerCommands<'a> { + type Fetch = SchedulerCommandQueue; } -// SAFE: ScheduleCommands only accesses internal state -unsafe impl ReadOnlySystemParamFetch for ScheduleCommandQueue {} +// SAFE: SchedulerCommands only accesses internal state +unsafe impl ReadOnlySystemParamFetch for SchedulerCommandQueue {} // SAFE: only local state is accessed -unsafe impl SystemParamState for ScheduleCommandQueue { +unsafe impl SystemParamState for SchedulerCommandQueue { type Config = (); fn init(_world: &mut World, _system_meta: &mut SystemMeta, _config: Self::Config) -> Self { Default::default() } - fn schedule_commands(&mut self) -> Option { + fn scheduler_commands(&mut self) -> Option { if self.is_empty() { return None; } @@ -538,8 +538,8 @@ unsafe impl SystemParamState for ScheduleCommandQueue { fn default_config() {} } -impl<'a> SystemParamFetch<'a> for ScheduleCommandQueue { - type Item = ScheduleCommands<'a>; +impl<'a> SystemParamFetch<'a> for SchedulerCommandQueue { + type Item = SchedulerCommands<'a>; #[inline] unsafe fn get_param( @@ -548,7 +548,7 @@ impl<'a> SystemParamFetch<'a> for ScheduleCommandQueue { _world: &'a World, _change_tick: u32, ) -> Self::Item { - ScheduleCommands::new(state) + SchedulerCommands::new(state) } } @@ -1238,12 +1238,12 @@ macro_rules! impl_system_param_tuple { $($param.apply(_world);)* } - fn schedule_commands(&mut self) -> Option { + fn scheduler_commands(&mut self) -> Option { let ($($param,)*) = self; - let commands = ScheduleCommandQueue::default(); + let commands = SchedulerCommandQueue::default(); $( let mut commands = commands; - if let Some(mut c) = $param.schedule_commands() { + if let Some(mut c) = $param.scheduler_commands() { c.transfer(&mut commands); } )* From 78bcd914d4c78efe0f4d53d4ad12d3997d4c2b81 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Wed, 21 Jul 2021 17:36:47 +0200 Subject: [PATCH 07/17] Use world to store scheduler commands --- crates/bevy_core/src/time/fixed_timestep.rs | 6 +- crates/bevy_ecs/src/schedule/commands.rs | 42 ++++++------- crates/bevy_ecs/src/schedule/mod.rs | 8 +-- crates/bevy_ecs/src/schedule/run_criteria.rs | 5 +- crates/bevy_ecs/src/schedule/stage.rs | 41 ++---------- crates/bevy_ecs/src/system/commands/mod.rs | 13 ++++ .../bevy_ecs/src/system/exclusive_system.rs | 11 ---- crates/bevy_ecs/src/system/function_system.rs | 6 -- crates/bevy_ecs/src/system/system.rs | 2 - crates/bevy_ecs/src/system/system_chaining.rs | 14 ----- crates/bevy_ecs/src/system/system_param.rs | 62 ------------------- crates/bevy_ecs/src/world/mod.rs | 3 + 12 files changed, 43 insertions(+), 170 deletions(-) diff --git a/crates/bevy_core/src/time/fixed_timestep.rs b/crates/bevy_core/src/time/fixed_timestep.rs index 08645ad1ea1f1..c03d87296fa50 100644 --- a/crates/bevy_core/src/time/fixed_timestep.rs +++ b/crates/bevy_core/src/time/fixed_timestep.rs @@ -3,7 +3,7 @@ use bevy_ecs::{ archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, - schedule::{SchedulerCommandQueue, ShouldRun}, + schedule::ShouldRun, system::{IntoSystem, Local, Res, ResMut, System, SystemId}, world::World, }; @@ -178,10 +178,6 @@ impl System for FixedTimestep { self.internal_system.apply_buffers(world) } - fn scheduler_commands(&mut self) -> Option { - self.internal_system.scheduler_commands() - } - fn initialize(&mut self, world: &mut World) { self.internal_system = Box::new( Self::prepare_system diff --git a/crates/bevy_ecs/src/schedule/commands.rs b/crates/bevy_ecs/src/schedule/commands.rs index 5b81586f28238..72e8101dbc4a9 100644 --- a/crates/bevy_ecs/src/schedule/commands.rs +++ b/crates/bevy_ecs/src/schedule/commands.rs @@ -1,4 +1,6 @@ -use super::{IntoSystemDescriptor, Schedule, StageLabel, SystemDescriptor}; +use super::{Schedule, StageLabel, SystemDescriptor}; +use crate::system::Command; +use crate::world::World; #[derive(Default)] pub struct SchedulerCommandQueue { @@ -33,24 +35,12 @@ pub trait SchedulerCommand: Send + Sync + 'static { fn write(self: Box, schedule: &mut Schedule); } -pub struct SchedulerCommands<'a> { - queue: &'a mut SchedulerCommandQueue, -} - -impl<'a> SchedulerCommands<'a> { - pub fn new(queue: &'a mut SchedulerCommandQueue) -> Self { - Self { queue } - } - - pub fn insert_system(&mut self, system: T, stage_label: S) - where - T: IntoSystemDescriptor, - S: StageLabel, - { - self.queue.push(InsertSystem { - system: system.into_descriptor(), - stage_label, - }); +impl Command for T +where + T: SchedulerCommand, +{ + fn write(self, world: &mut World) { + world.scheduler_commands.push(self); } } @@ -74,7 +64,9 @@ where #[cfg(test)] mod tests { use crate::{ - schedule::{Schedule, SchedulerCommandQueue, SchedulerCommands, SystemStage}, + schedule::{ + InsertSystem, IntoSystemDescriptor, Schedule, SchedulerCommandQueue, SystemStage, + }, system::Commands, world::World, }; @@ -85,8 +77,10 @@ mod tests { let mut schedule = Schedule::default(); schedule.add_stage("test", SystemStage::parallel()); let mut queue = SchedulerCommandQueue::default(); - let mut scheduler_commands = SchedulerCommands::new(&mut queue); - scheduler_commands.insert_system(sample_system, "test"); + queue.push(InsertSystem { + system: sample_system.into_descriptor(), + stage_label: "test", + }); queue.apply(&mut schedule); let stage = schedule.get_stage::(&"test").unwrap(); @@ -95,8 +89,8 @@ mod tests { #[test] fn insert_system_from_system() { - fn sample_system(mut scheduler_commands: SchedulerCommands) { - scheduler_commands.insert_system(|| {}, "test"); + fn sample_system(mut commands: Commands) { + commands.insert_system(|| {}, "test"); } let mut world = World::default(); diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 61c131c273edb..c6285f5789301 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -209,9 +209,7 @@ impl Schedule { let _stage_guard = stage_span.enter(); let stage = self.stages.get_mut(label).unwrap(); stage.run(world); - if let Some(mut stage_commands) = stage.commands() { - stage_commands.transfer(&mut commands); - } + world.scheduler_commands.transfer(&mut commands); } commands.apply(self); @@ -243,8 +241,4 @@ impl Stage for Schedule { } } } - - fn commands(&mut self) -> Option { - None - } } diff --git a/crates/bevy_ecs/src/schedule/run_criteria.rs b/crates/bevy_ecs/src/schedule/run_criteria.rs index ef0b9e552150f..7e3da8a5f3b3f 100644 --- a/crates/bevy_ecs/src/schedule/run_criteria.rs +++ b/crates/bevy_ecs/src/schedule/run_criteria.rs @@ -2,7 +2,7 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration}, component::ComponentId, query::Access, - schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel, SchedulerCommandQueue}, + schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel}, system::{BoxedSystem, IntoSystem, System, SystemId}, world::World, }; @@ -450,9 +450,6 @@ impl System for RunOnce { } fn apply_buffers(&mut self, _world: &mut World) {} - fn scheduler_commands(&mut self) -> Option { - None - } fn initialize(&mut self, _world: &mut World) {} diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index 66945678f4597..8eed39d3aa8e7 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -8,7 +8,7 @@ use crate::{ RunCriteriaDescriptor, RunCriteriaDescriptorOrLabel, RunCriteriaInner, ShouldRun, SingleThreadedExecutor, SystemContainer, SystemDescriptor, SystemSet, }, - system::{ExclusiveSystem, System}, + system::System, world::{World, WorldId}, }; use bevy_utils::{tracing::info, HashMap, HashSet}; @@ -16,13 +16,12 @@ use downcast_rs::{impl_downcast, Downcast}; use fixedbitset::FixedBitSet; use std::fmt::Debug; -use super::{IntoSystemDescriptor, SchedulerCommandQueue}; +use super::IntoSystemDescriptor; pub trait Stage: Downcast + Send + Sync { /// Runs the stage; this happens once per update. /// Implementors must initialize all of their state and systems before running the first time. fn run(&mut self, world: &mut World); - fn commands(&mut self) -> Option; } impl_downcast!(Stage); @@ -84,8 +83,6 @@ pub struct SystemStage { uninitialized_parallel: Vec, /// Saves the value of the World change_tick during the last tick check last_tick_check: u32, - // Contains commands for the schedule - scheduler_commands: SchedulerCommandQueue, } impl SystemStage { @@ -107,7 +104,6 @@ impl SystemStage { uninitialized_before_commands: vec![], uninitialized_at_end: vec![], last_tick_check: Default::default(), - scheduler_commands: Default::default(), } } @@ -809,21 +805,10 @@ impl Stage for SystemStage { ) } - fn run_exclusive( - world: &mut World, - system: &mut Box, - commands: &mut SchedulerCommandQueue, - ) { - system.run(world); - if let Some(mut c) = system.scheduler_commands() { - c.transfer(commands); - } - } - // 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) { - run_exclusive(world, container.system_mut(), &mut self.scheduler_commands); + container.system_mut().run(world); } } @@ -838,25 +823,21 @@ 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) { - run_exclusive(world, container.system_mut(), &mut self.scheduler_commands); + container.system_mut().run(world); } } // Apply parallel systems' buffers. for container in &mut self.parallel { if container.should_run { - let system = container.system_mut(); - system.apply_buffers(world); - if let Some(mut commands) = system.scheduler_commands() { - commands.transfer(&mut self.scheduler_commands); - } + container.system_mut().apply_buffers(world); } } // 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) { - run_exclusive(world, container.system_mut(), &mut self.scheduler_commands); + container.system_mut().run(world); } } @@ -904,16 +885,6 @@ impl Stage for SystemStage { } } } - - fn commands(&mut self) -> Option { - if self.scheduler_commands.is_empty() { - return None; - } - - let mut commands = Default::default(); - self.scheduler_commands.transfer(&mut commands); - Some(commands) - } } #[cfg(test)] diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 0488b09e4f770..e81541a88cb91 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -4,6 +4,7 @@ use crate::{ bundle::Bundle, component::Component, entity::{Entities, Entity}, + schedule::{InsertSystem, IntoSystemDescriptor, StageLabel}, world::World, }; use bevy_utils::tracing::debug; @@ -152,6 +153,18 @@ impl<'a> Commands<'a> { }); } + // Insert a system into a stage. + pub fn insert_system(&mut self, system: T, stage_label: S) + where + T: IntoSystemDescriptor, + S: StageLabel, + { + self.queue.push(InsertSystem { + system: system.into_descriptor(), + stage_label, + }); + } + /// Adds a command directly to the command list. pub fn add(&mut self, command: C) { self.queue.push(command); diff --git a/crates/bevy_ecs/src/system/exclusive_system.rs b/crates/bevy_ecs/src/system/exclusive_system.rs index 02a6c3201bc5a..10364375f71ef 100644 --- a/crates/bevy_ecs/src/system/exclusive_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_system.rs @@ -1,6 +1,5 @@ use crate::{ archetype::ArchetypeGeneration, - schedule::SchedulerCommandQueue, system::{check_system_change_tick, BoxedSystem, IntoSystem, SystemId}, world::World, }; @@ -13,8 +12,6 @@ pub trait ExclusiveSystem: Send + Sync + 'static { fn run(&mut self, world: &mut World); - fn scheduler_commands(&mut self) -> Option; - fn initialize(&mut self, world: &mut World); fn check_change_tick(&mut self, change_tick: u32); @@ -51,10 +48,6 @@ impl ExclusiveSystem for ExclusiveSystemFn { world.last_change_tick = saved_last_tick; } - fn scheduler_commands(&mut self) -> Option { - None - } - fn initialize(&mut self, _: &mut World) {} fn check_change_tick(&mut self, change_tick: u32) { @@ -108,10 +101,6 @@ impl ExclusiveSystem for ExclusiveSystemCoerced { self.system.apply_buffers(world); } - fn scheduler_commands(&mut self) -> Option { - self.system.scheduler_commands() - } - fn initialize(&mut self, world: &mut World) { self.system.initialize(world); } diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 0e88689648931..a8de42abf54f9 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -2,7 +2,6 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration, ArchetypeId}, component::ComponentId, query::{Access, FilteredAccessSet}, - schedule::SchedulerCommandQueue, system::{ check_system_change_tick, ReadOnlySystemParamFetch, System, SystemId, SystemParam, SystemParamFetch, SystemParamState, @@ -384,11 +383,6 @@ where param_state.apply(world); } - fn scheduler_commands(&mut self) -> Option { - let param_state = self.param_state.as_mut().unwrap(); - param_state.scheduler_commands() - } - #[inline] fn initialize(&mut self, world: &mut World) { self.param_state = Some(::init( diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index 44ad6b9773334..12b77135a14c2 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -4,7 +4,6 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, - schedule::SchedulerCommandQueue, world::World, }; use std::borrow::Cow; @@ -67,7 +66,6 @@ pub trait System: Send + Sync + 'static { unsafe { self.run_unsafe(input, world) } } fn apply_buffers(&mut self, world: &mut World); - fn scheduler_commands(&mut self) -> Option; /// Initialize the system. fn initialize(&mut self, _world: &mut World); fn check_change_tick(&mut self, change_tick: u32); diff --git a/crates/bevy_ecs/src/system/system_chaining.rs b/crates/bevy_ecs/src/system/system_chaining.rs index 860e253bcf7da..736bf066331ea 100644 --- a/crates/bevy_ecs/src/system/system_chaining.rs +++ b/crates/bevy_ecs/src/system/system_chaining.rs @@ -2,7 +2,6 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId}, component::ComponentId, query::Access, - schedule::SchedulerCommandQueue, system::{IntoSystem, System, SystemId}, world::World, }; @@ -98,19 +97,6 @@ impl> System for ChainSystem self.system_b.apply_buffers(world); } - fn scheduler_commands(&mut self) -> Option { - let mut commands = self.system_a.scheduler_commands(); - if let Some(commands) = &mut commands { - if let Some(mut c) = self.system_b.scheduler_commands() { - c.transfer(commands); - } - } else { - commands = self.system_b.scheduler_commands(); - } - - commands - } - fn initialize(&mut self, world: &mut World) { self.system_a.initialize(world); self.system_b.initialize(world); diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 4b787c3b0f4b4..632501a56917f 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -8,7 +8,6 @@ use crate::{ query::{ FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch, WorldQuery, }, - schedule::{SchedulerCommandQueue, SchedulerCommands}, system::{CommandQueue, Commands, Query, SystemMeta}, world::{FromWorld, World}, }; @@ -72,9 +71,6 @@ pub unsafe trait SystemParamState: Send + Sync + 'static { fn new_archetype(&mut self, _archetype: &Archetype, _system_meta: &mut SystemMeta) {} #[inline] fn apply(&mut self, _world: &mut World) {} - fn scheduler_commands(&mut self) -> Option { - None - } fn default_config() -> Self::Config; } @@ -510,48 +506,6 @@ impl<'a> SystemParamFetch<'a> for CommandQueue { } } -impl<'a> SystemParam for SchedulerCommands<'a> { - type Fetch = SchedulerCommandQueue; -} - -// SAFE: SchedulerCommands only accesses internal state -unsafe impl ReadOnlySystemParamFetch for SchedulerCommandQueue {} - -// SAFE: only local state is accessed -unsafe impl SystemParamState for SchedulerCommandQueue { - type Config = (); - - fn init(_world: &mut World, _system_meta: &mut SystemMeta, _config: Self::Config) -> Self { - Default::default() - } - - fn scheduler_commands(&mut self) -> Option { - if self.is_empty() { - return None; - } - - let mut commands = Default::default(); - self.transfer(&mut commands); - Some(commands) - } - - fn default_config() {} -} - -impl<'a> SystemParamFetch<'a> for SchedulerCommandQueue { - type Item = SchedulerCommands<'a>; - - #[inline] - unsafe fn get_param( - state: &'a mut Self, - _system_meta: &SystemMeta, - _world: &'a World, - _change_tick: u32, - ) -> Self::Item { - SchedulerCommands::new(state) - } -} - /// A system local [`SystemParam`]. /// /// A local may only be accessed by the system itself and is therefore not visible to other systems. @@ -1238,22 +1192,6 @@ macro_rules! impl_system_param_tuple { $($param.apply(_world);)* } - fn scheduler_commands(&mut self) -> Option { - let ($($param,)*) = self; - let commands = SchedulerCommandQueue::default(); - $( - let mut commands = commands; - if let Some(mut c) = $param.scheduler_commands() { - c.transfer(&mut commands); - } - )* - if commands.is_empty() { - None - } else { - Some(commands) - } - } - fn default_config() -> ($(<$param as SystemParamState>::Config,)*) { ($(<$param as SystemParamState>::default_config(),)*) } diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 5068fdc4e5074..c0a579a854ae4 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -18,6 +18,7 @@ use crate::{ }, entity::{Entities, Entity}, query::{FilterFetch, QueryState, WorldQuery}, + schedule::SchedulerCommandQueue, storage::{Column, SparseSet, Storages}, }; use std::{ @@ -53,6 +54,7 @@ pub struct World { main_thread_validator: MainThreadValidator, pub(crate) change_tick: AtomicU32, pub(crate) last_change_tick: u32, + pub(crate) scheduler_commands: SchedulerCommandQueue, } impl Default for World { @@ -71,6 +73,7 @@ impl Default for World { // are detected on first system runs and for direct world queries. change_tick: AtomicU32::new(1), last_change_tick: 0, + scheduler_commands: Default::default(), } } } From 1c355bbed21c14682611b8207c73e89df9541f15 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Wed, 21 Jul 2021 17:59:02 +0200 Subject: [PATCH 08/17] Improve system insertion test --- crates/bevy_ecs/src/schedule/commands.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/schedule/commands.rs b/crates/bevy_ecs/src/schedule/commands.rs index 72e8101dbc4a9..c4a2d9d759f31 100644 --- a/crates/bevy_ecs/src/schedule/commands.rs +++ b/crates/bevy_ecs/src/schedule/commands.rs @@ -64,6 +64,7 @@ where #[cfg(test)] mod tests { use crate::{ + prelude::ResMut, schedule::{ InsertSystem, IntoSystemDescriptor, Schedule, SchedulerCommandQueue, SystemStage, }, @@ -87,13 +88,23 @@ mod tests { assert_eq!(stage.parallel_systems().len(), 1); } + #[derive(Debug, Default, PartialEq)] + struct TestResource(Option<()>); + #[test] fn insert_system_from_system() { fn sample_system(mut commands: Commands) { - commands.insert_system(|| {}, "test"); + commands.insert_system( + |mut res: ResMut| { + res.0 = Some(()); + }, + "test", + ); } let mut world = World::default(); + world.insert_resource(TestResource(None)); + let mut schedule = Schedule::default(); schedule.add_stage("test", SystemStage::parallel()); schedule.add_system_to_stage("test", sample_system); @@ -101,5 +112,11 @@ mod tests { let stage = schedule.get_stage::(&"test").unwrap(); assert_eq!(stage.parallel_systems().len(), 2); + + schedule.run_once(&mut world); + assert_eq!( + world.get_resource::(), + Some(&TestResource(Some(()))) + ); } } From 7ec846832346c4ca2b16f8cbcf7a604f94138405 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Wed, 21 Jul 2021 18:18:26 +0200 Subject: [PATCH 09/17] Add doc string for insert_system --- crates/bevy_ecs/src/system/commands/mod.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index e81541a88cb91..1ca5f80062c09 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -153,7 +153,21 @@ impl<'a> Commands<'a> { }); } - // Insert a system into a stage. + /// Inserts a [`crate::system::System`] into a [`crate::schedule::Stage`] + /// + /// # Example + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// + /// fn another_system() { + /// // A normal system like any other + /// } + /// + /// fn example_system(mut commands: Commands) { + /// commands.insert_system(another_system, "some stage"); + /// } + /// ``` pub fn insert_system(&mut self, system: T, stage_label: S) where T: IntoSystemDescriptor, From 48c293cc2db092db766b1c270bf4473acf0602dd Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Wed, 21 Jul 2021 18:24:31 +0200 Subject: [PATCH 10/17] Ignore existing scheduler commands on World --- crates/bevy_ecs/src/schedule/commands.rs | 8 ++++++-- crates/bevy_ecs/src/schedule/mod.rs | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/commands.rs b/crates/bevy_ecs/src/schedule/commands.rs index c4a2d9d759f31..7e819f6adfdeb 100644 --- a/crates/bevy_ecs/src/schedule/commands.rs +++ b/crates/bevy_ecs/src/schedule/commands.rs @@ -21,8 +21,12 @@ impl SchedulerCommandQueue { } } - pub fn transfer(&mut self, queue: &mut SchedulerCommandQueue) { - queue.items.extend(self.items.drain(..)); + pub fn transfer(&mut self, queue: &mut SchedulerCommandQueue, offset: usize) { + queue.items.extend(self.items.drain(offset..)); + } + + pub fn len(&self) -> usize { + self.items.len() } pub fn is_empty(&self) -> bool { diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index c6285f5789301..fa73d94c457d2 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -201,6 +201,7 @@ impl Schedule { pub fn run_once(&mut self, world: &mut World) { let mut commands = SchedulerCommandQueue::default(); + let existing_commands = world.scheduler_commands.len(); for label in self.stage_order.iter() { #[cfg(feature = "trace")] let stage_span = @@ -209,7 +210,9 @@ impl Schedule { let _stage_guard = stage_span.enter(); let stage = self.stages.get_mut(label).unwrap(); stage.run(world); - world.scheduler_commands.transfer(&mut commands); + world + .scheduler_commands + .transfer(&mut commands, existing_commands); } commands.apply(self); From 9511e21499bc6d9a17b126530d4db0695bd11885 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Thu, 22 Jul 2021 11:42:29 +0200 Subject: [PATCH 11/17] Simplify scheduler command application --- crates/bevy_ecs/src/schedule/commands.rs | 33 ++++++++++++++++-------- crates/bevy_ecs/src/schedule/mod.rs | 7 ++--- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/commands.rs b/crates/bevy_ecs/src/schedule/commands.rs index 7e819f6adfdeb..4f80adedee29e 100644 --- a/crates/bevy_ecs/src/schedule/commands.rs +++ b/crates/bevy_ecs/src/schedule/commands.rs @@ -15,23 +15,15 @@ impl SchedulerCommandQueue { self.items.push(Box::new(command)); } - pub fn apply(&mut self, schedule: &mut Schedule) { - for command in self.items.drain(..) { + pub fn apply(&mut self, schedule: &mut Schedule, offset: usize) { + for command in self.items.drain(offset..) { command.write(schedule); } } - pub fn transfer(&mut self, queue: &mut SchedulerCommandQueue, offset: usize) { - queue.items.extend(self.items.drain(offset..)); - } - pub fn len(&self) -> usize { self.items.len() } - - pub fn is_empty(&self) -> bool { - self.items.is_empty() - } } /// A [`Schedule`] mutation. @@ -86,7 +78,7 @@ mod tests { system: sample_system.into_descriptor(), stage_label: "test", }); - queue.apply(&mut schedule); + queue.apply(&mut schedule, 0); let stage = schedule.get_stage::(&"test").unwrap(); assert_eq!(stage.parallel_systems().len(), 1); @@ -123,4 +115,23 @@ mod tests { Some(&TestResource(Some(()))) ); } + + #[test] + fn insert_with_nested_schedule() { + fn sample_system(mut commands: Commands) { + commands.insert_system(|| {}, "test"); + } + + let mut world = World::default(); + + let nested_schedule = Schedule::default(); + let mut schedule = Schedule::default(); + schedule.add_stage("test", SystemStage::parallel()); + schedule.add_system_to_stage("test", sample_system); + schedule.add_stage("nested", nested_schedule); + schedule.run_once(&mut world); + + let stage = schedule.get_stage::(&"test").unwrap(); + assert_eq!(stage.parallel_systems().len(), 2); + } } diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index fa73d94c457d2..739eb170f2d27 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -200,8 +200,8 @@ impl Schedule { } pub fn run_once(&mut self, world: &mut World) { - let mut commands = SchedulerCommandQueue::default(); let existing_commands = world.scheduler_commands.len(); + for label in self.stage_order.iter() { #[cfg(feature = "trace")] let stage_span = @@ -210,12 +210,9 @@ impl Schedule { let _stage_guard = stage_span.enter(); let stage = self.stages.get_mut(label).unwrap(); stage.run(world); - world - .scheduler_commands - .transfer(&mut commands, existing_commands); } - commands.apply(self); + world.scheduler_commands.apply(self, existing_commands); } /// Iterates over all of schedule's stages and their labels, in execution order. From 8d4f86bef80f35f97885c83c154a665557dd110d Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Thu, 22 Jul 2021 11:53:16 +0200 Subject: [PATCH 12/17] Improve doctest for insert_system --- crates/bevy_ecs/src/system/commands/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 1ca5f80062c09..2fbe7b7920708 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -167,6 +167,16 @@ impl<'a> Commands<'a> { /// fn example_system(mut commands: Commands) { /// commands.insert_system(another_system, "some stage"); /// } + /// + /// let mut world = World::default(); + /// let mut schedule = Schedule::default(); + /// schedule.add_stage("some stage", SystemStage::parallel()); + /// schedule.add_system_to_stage("some stage", example_system); + /// // When we run the schedule + /// schedule.run_once(&mut world); + /// // We should now have 2 systems in "test", the initial system and the inserted system + /// let stage = schedule.get_stage::(&"some stage").unwrap(); + /// assert_eq!(stage.parallel_systems().len(), 2); /// ``` pub fn insert_system(&mut self, system: T, stage_label: S) where From 8f76330dbb6bd76adf32c52dc25a6c04fddd579a Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Thu, 22 Jul 2021 13:39:29 +0200 Subject: [PATCH 13/17] Add dynamic schedule example --- Cargo.toml | 4 ++++ examples/README.md | 1 + examples/ecs/dynamic_schedule.rs | 38 ++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 examples/ecs/dynamic_schedule.rs diff --git a/Cargo.toml b/Cargo.toml index 7feb450cc82be..6c635312bb456 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -317,6 +317,10 @@ path = "examples/ecs/timers.rs" name = "query_bundle" path = "examples/ecs/query_bundle.rs" +[[example]] +name = "dynamic_schedule" +path = "examples/ecs/dynamic_schedule.rs" + # Games [[example]] name = "alien_cake_addict" diff --git a/examples/README.md b/examples/README.md index 37b76a3a34830..222073d3644f7 100644 --- a/examples/README.md +++ b/examples/README.md @@ -170,6 +170,7 @@ Example | File | Description `system_param` | [`ecs/system_param.rs`](./ecs/system_param.rs) | Illustrates creating custom system parameters with `SystemParam` `system_sets` | [`ecs/system_sets.rs`](./ecs/system_sets.rs) | Shows `SystemSet` use along with run criterion `timers` | [`ecs/timers.rs`](./ecs/timers.rs) | Illustrates ticking `Timer` resources inside systems and handling their state +`dynamic_schedule` | [`ecs/dynamic_schedule.rs`](./ecs/dynamic_schedule.rs) | Shows how to modify the schedule from systems ## Games diff --git a/examples/ecs/dynamic_schedule.rs b/examples/ecs/dynamic_schedule.rs new file mode 100644 index 0000000000000..4fabea5299998 --- /dev/null +++ b/examples/ecs/dynamic_schedule.rs @@ -0,0 +1,38 @@ +use bevy::{core::FixedTimestep, prelude::*}; +use rand::Rng; + +fn main() { + App::build() + .add_plugins(DefaultPlugins) + .add_stage_after( + CoreStage::Update, + "slow", + SystemStage::parallel().with_run_criteria(FixedTimestep::step(1.0)), + ) + .add_startup_system(setup) + .add_system(dynamic.with_run_criteria(FixedTimestep::step(1.0))) + .run(); +} + +fn setup(mut commands: Commands) { + commands.spawn_bundle(OrthographicCameraBundle::new_2d()); +} + +fn dynamic(mut commands: Commands, mut system_counter: Local) { + let count = system_counter.clone(); + *system_counter += 1; + let closure = move |mut commands: Commands, + asset_server: Res, + mut materials: ResMut>| { + info!("Hello from system {}", count); + + let mut rng = rand::thread_rng(); + let texture_handle = asset_server.load("branding/icon.png"); + commands.spawn_bundle(SpriteBundle { + material: materials.add(texture_handle.into()), + transform: Transform::from_xyz(rng.gen_range(-400f32..400f32), rng.gen_range(-400f32..400f32), 0.0), + ..Default::default() + }); + }; + commands.insert_system(closure, "slow"); +} From b67050b78e56c314d55e046b21b1aa717aacf96c Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Thu, 22 Jul 2021 17:53:33 +0200 Subject: [PATCH 14/17] Fix formatting --- examples/ecs/dynamic_schedule.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/ecs/dynamic_schedule.rs b/examples/ecs/dynamic_schedule.rs index 4fabea5299998..e9d469f23e570 100644 --- a/examples/ecs/dynamic_schedule.rs +++ b/examples/ecs/dynamic_schedule.rs @@ -30,7 +30,11 @@ fn dynamic(mut commands: Commands, mut system_counter: Local) { let texture_handle = asset_server.load("branding/icon.png"); commands.spawn_bundle(SpriteBundle { material: materials.add(texture_handle.into()), - transform: Transform::from_xyz(rng.gen_range(-400f32..400f32), rng.gen_range(-400f32..400f32), 0.0), + transform: Transform::from_xyz( + rng.gen_range(-400f32..400f32), + rng.gen_range(-400f32..400f32), + 0.0, + ), ..Default::default() }); }; From 98cb61711a4234608aac86850712eeed8b9cd7a9 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Thu, 22 Jul 2021 18:32:18 +0200 Subject: [PATCH 15/17] Satisfy clippy --- crates/bevy_ecs/src/schedule/commands.rs | 4 ++++ examples/ecs/dynamic_schedule.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/schedule/commands.rs b/crates/bevy_ecs/src/schedule/commands.rs index 4f80adedee29e..29d574d972eb5 100644 --- a/crates/bevy_ecs/src/schedule/commands.rs +++ b/crates/bevy_ecs/src/schedule/commands.rs @@ -24,6 +24,10 @@ impl SchedulerCommandQueue { pub fn len(&self) -> usize { self.items.len() } + + pub fn is_empty(&self) -> bool { + self.items.is_empty() + } } /// A [`Schedule`] mutation. diff --git a/examples/ecs/dynamic_schedule.rs b/examples/ecs/dynamic_schedule.rs index e9d469f23e570..a61c5507041aa 100644 --- a/examples/ecs/dynamic_schedule.rs +++ b/examples/ecs/dynamic_schedule.rs @@ -19,7 +19,7 @@ fn setup(mut commands: Commands) { } fn dynamic(mut commands: Commands, mut system_counter: Local) { - let count = system_counter.clone(); + let count = *system_counter; *system_counter += 1; let closure = move |mut commands: Commands, asset_server: Res, From b896bcdd2092518f24ac838a969a20263701d90c Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Sun, 25 Jul 2021 13:07:54 +0200 Subject: [PATCH 16/17] Reuse material in dynamic_schedule example --- examples/ecs/dynamic_schedule.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/examples/ecs/dynamic_schedule.rs b/examples/ecs/dynamic_schedule.rs index a61c5507041aa..732cfe853135a 100644 --- a/examples/ecs/dynamic_schedule.rs +++ b/examples/ecs/dynamic_schedule.rs @@ -1,6 +1,9 @@ use bevy::{core::FixedTimestep, prelude::*}; use rand::Rng; +#[derive(Default)] +struct BevyMaterial(Option>); + fn main() { App::build() .add_plugins(DefaultPlugins) @@ -11,25 +14,33 @@ fn main() { ) .add_startup_system(setup) .add_system(dynamic.with_run_criteria(FixedTimestep::step(1.0))) + .init_resource::() .run(); } -fn setup(mut commands: Commands) { +fn setup( + mut commands: Commands, + asset_server: Res, + mut materials: ResMut>, + mut bevy_material: ResMut, +) { commands.spawn_bundle(OrthographicCameraBundle::new_2d()); + + let texture_handle = asset_server.load("branding/icon.png"); + let material = materials.add(texture_handle.into()); + bevy_material.0 = Some(material); } fn dynamic(mut commands: Commands, mut system_counter: Local) { let count = *system_counter; *system_counter += 1; - let closure = move |mut commands: Commands, - asset_server: Res, - mut materials: ResMut>| { + let closure = move |mut commands: Commands, bevy_material: Res| { info!("Hello from system {}", count); let mut rng = rand::thread_rng(); - let texture_handle = asset_server.load("branding/icon.png"); + commands.spawn_bundle(SpriteBundle { - material: materials.add(texture_handle.into()), + material: bevy_material.0.clone().unwrap(), transform: Transform::from_xyz( rng.gen_range(-400f32..400f32), rng.gen_range(-400f32..400f32), From c3d1be2aeb8ae773570a456f506f29ba3294a7f2 Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Sun, 25 Jul 2021 14:18:58 +0200 Subject: [PATCH 17/17] Improve insert_system example --- crates/bevy_ecs/src/system/commands/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 2fbe7b7920708..711e2578d0ed6 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -160,8 +160,9 @@ impl<'a> Commands<'a> { /// ``` /// use bevy_ecs::prelude::*; /// - /// fn another_system() { - /// // A normal system like any other + /// // A system like any other + /// fn another_system(mut commands: Commands) { + /// let entity = commands.spawn().id(); /// } /// /// fn example_system(mut commands: Commands) {