From d3e020a1e7ed035b59b2f91833d86e252ab22ada Mon Sep 17 00:00:00 2001 From: Alexander Sepity Date: Wed, 24 Mar 2021 20:11:55 +0000 Subject: [PATCH] System sets and run criteria v2 (#1675) I'm opening this prematurely; consider this an RFC that predates RFCs and therefore not super-RFC-like. This PR does two "big" things: decouple run criteria from system sets, reimagine system sets as weapons of mass system description. ### What it lets us do: * Reuse run criteria within a stage. * Pipe output of one run criteria as input to another. * Assign labels, dependencies, run criteria, and ambiguity sets to many systems at the same time. ### Things already done: * Decoupled run criteria from system sets. * Mass system description superpowers to `SystemSet`. * Implemented `RunCriteriaDescriptor`. * Removed `VirtualSystemSet`. * Centralized all run criteria of `SystemStage`. * Extended system descriptors with per-system run criteria. * `.before()` and `.after()` for run criteria. * Explicit order between state driver and related run criteria. Fixes #1672. * Opt-in run criteria deduplication; default behavior is to panic. * Labels (not exposed) for state run criteria; state run criteria are deduplicated. ### API issues that need discussion: * [`FixedTimestep::step(1.0).label("my label")`](https://github.com/Ratysz/bevy/blob/eaccf857cdaeb5a5632b6e75feab5c1ad6267d1d/crates/bevy_ecs/src/schedule/run_criteria.rs#L120-L122) and [`FixedTimestep::step(1.0).with_label("my label")`](https://github.com/Ratysz/bevy/blob/eaccf857cdaeb5a5632b6e75feab5c1ad6267d1d/crates/bevy_core/src/time/fixed_timestep.rs#L86-L89) are both valid but do very different things. --- I will try to maintain this post up-to-date as things change. Do check the diffs in "edited" thingy from time to time. Co-authored-by: Carter Anderson --- crates/bevy_app/src/app_builder.rs | 15 +- crates/bevy_ecs/macros/src/lib.rs | 6 + crates/bevy_ecs/src/lib.rs | 1 + crates/bevy_ecs/src/schedule/graph_utils.rs | 125 +++ crates/bevy_ecs/src/schedule/label.rs | 9 +- crates/bevy_ecs/src/schedule/mod.rs | 119 +-- crates/bevy_ecs/src/schedule/run_criteria.rs | 397 +++++++++ crates/bevy_ecs/src/schedule/stage.rs | 832 ++++++++++++------ crates/bevy_ecs/src/schedule/state.rs | 111 ++- .../bevy_ecs/src/schedule/system_container.rs | 98 ++- .../src/schedule/system_descriptor.rs | 66 +- crates/bevy_ecs/src/schedule/system_set.rs | 134 ++- examples/2d/texture_atlas.rs | 2 +- examples/ecs/state.rs | 2 +- examples/game/alien_cake_addict.rs | 2 +- examples/window/multiple_windows.rs | 2 +- 16 files changed, 1429 insertions(+), 492 deletions(-) create mode 100644 crates/bevy_ecs/src/schedule/graph_utils.rs create mode 100644 crates/bevy_ecs/src/schedule/run_criteria.rs diff --git a/crates/bevy_app/src/app_builder.rs b/crates/bevy_app/src/app_builder.rs index fe7b5fb3d70fd..18f12f036596a 100644 --- a/crates/bevy_app/src/app_builder.rs +++ b/crates/bevy_app/src/app_builder.rs @@ -13,6 +13,7 @@ use bevy_ecs::{ world::{FromWorld, World}, }; use bevy_utils::tracing::debug; +use std::{fmt::Debug, hash::Hash}; /// Configure [App]s using the builder pattern pub struct AppBuilder { @@ -177,16 +178,18 @@ impl AppBuilder { self } - pub fn add_state(&mut self, initial: T) -> &mut Self { + pub fn add_state(&mut self, initial: T) -> &mut Self + where + T: Component + Debug + Clone + Eq + Hash, + { self.insert_resource(State::new(initial)) .add_system_set(State::::make_driver()) } - pub fn add_state_to_stage( - &mut self, - stage: impl StageLabel, - initial: T, - ) -> &mut Self { + pub fn add_state_to_stage(&mut self, stage: impl StageLabel, initial: T) -> &mut Self + where + T: Component + Debug + Clone + Eq + Hash, + { self.insert_resource(State::new(initial)) .add_system_set_to_stage(stage, State::::make_driver()) } diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index b35d8c054711c..07108b59de432 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -433,6 +433,12 @@ pub fn derive_ambiguity_set_label(input: TokenStream) -> TokenStream { derive_label(input, Ident::new("AmbiguitySetLabel", Span::call_site())).into() } +#[proc_macro_derive(RunCriteriaLabel)] +pub fn derive_run_criteria_label(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + derive_label(input, Ident::new("RunCriteriaLabel", Span::call_site())).into() +} + fn derive_label(input: DeriveInput, label_type: Ident) -> TokenStream2 { let ident = input.ident; let ecs_path: Path = bevy_ecs_path(); diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index aa1be8d483bb5..c3061d1580e4a 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -19,6 +19,7 @@ pub mod prelude { query::{Added, ChangeTrackers, Changed, Or, QueryState, With, WithBundle, Without}, schedule::{ AmbiguitySetLabel, ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion, + RunCriteria, RunCriteriaDescriptorCoercion, RunCriteriaLabel, RunCriteriaPiping, Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, SystemStage, }, system::{ diff --git a/crates/bevy_ecs/src/schedule/graph_utils.rs b/crates/bevy_ecs/src/schedule/graph_utils.rs new file mode 100644 index 0000000000000..ea5e2a2a58362 --- /dev/null +++ b/crates/bevy_ecs/src/schedule/graph_utils.rs @@ -0,0 +1,125 @@ +use bevy_utils::{tracing::warn, HashMap, HashSet}; +use fixedbitset::FixedBitSet; +use std::{borrow::Cow, fmt::Debug, hash::Hash}; + +pub enum DependencyGraphError { + GraphCycles(Vec<(usize, Labels)>), +} + +pub trait GraphNode