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")`](eaccf857cd/crates/bevy_ecs/src/schedule/run_criteria.rs (L120-L122)) and [`FixedTimestep::step(1.0).with_label("my label")`](eaccf857cd/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 <mcanders1@gmail.com>
This commit is contained in:
parent
10ef750899
commit
d3e020a1e7
@ -13,6 +13,7 @@ use bevy_ecs::{
|
|||||||
world::{FromWorld, World},
|
world::{FromWorld, World},
|
||||||
};
|
};
|
||||||
use bevy_utils::tracing::debug;
|
use bevy_utils::tracing::debug;
|
||||||
|
use std::{fmt::Debug, hash::Hash};
|
||||||
|
|
||||||
/// Configure [App]s using the builder pattern
|
/// Configure [App]s using the builder pattern
|
||||||
pub struct AppBuilder {
|
pub struct AppBuilder {
|
||||||
@ -177,16 +178,18 @@ impl AppBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_state<T: Component + Clone + Eq>(&mut self, initial: T) -> &mut Self {
|
pub fn add_state<T>(&mut self, initial: T) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
self.insert_resource(State::new(initial))
|
self.insert_resource(State::new(initial))
|
||||||
.add_system_set(State::<T>::make_driver())
|
.add_system_set(State::<T>::make_driver())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_state_to_stage<T: Component + Clone + Eq>(
|
pub fn add_state_to_stage<T>(&mut self, stage: impl StageLabel, initial: T) -> &mut Self
|
||||||
&mut self,
|
where
|
||||||
stage: impl StageLabel,
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
initial: T,
|
{
|
||||||
) -> &mut Self {
|
|
||||||
self.insert_resource(State::new(initial))
|
self.insert_resource(State::new(initial))
|
||||||
.add_system_set_to_stage(stage, State::<T>::make_driver())
|
.add_system_set_to_stage(stage, State::<T>::make_driver())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -433,6 +433,12 @@ pub fn derive_ambiguity_set_label(input: TokenStream) -> TokenStream {
|
|||||||
derive_label(input, Ident::new("AmbiguitySetLabel", Span::call_site())).into()
|
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 {
|
fn derive_label(input: DeriveInput, label_type: Ident) -> TokenStream2 {
|
||||||
let ident = input.ident;
|
let ident = input.ident;
|
||||||
let ecs_path: Path = bevy_ecs_path();
|
let ecs_path: Path = bevy_ecs_path();
|
||||||
|
|||||||
@ -19,6 +19,7 @@ pub mod prelude {
|
|||||||
query::{Added, ChangeTrackers, Changed, Or, QueryState, With, WithBundle, Without},
|
query::{Added, ChangeTrackers, Changed, Or, QueryState, With, WithBundle, Without},
|
||||||
schedule::{
|
schedule::{
|
||||||
AmbiguitySetLabel, ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion,
|
AmbiguitySetLabel, ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion,
|
||||||
|
RunCriteria, RunCriteriaDescriptorCoercion, RunCriteriaLabel, RunCriteriaPiping,
|
||||||
Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, SystemStage,
|
Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, SystemStage,
|
||||||
},
|
},
|
||||||
system::{
|
system::{
|
||||||
|
|||||||
125
crates/bevy_ecs/src/schedule/graph_utils.rs
Normal file
125
crates/bevy_ecs/src/schedule/graph_utils.rs
Normal file
@ -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<Labels> {
|
||||||
|
GraphCycles(Vec<(usize, Labels)>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GraphNode<Label> {
|
||||||
|
fn name(&self) -> Cow<'static, str>;
|
||||||
|
fn labels(&self) -> &[Label];
|
||||||
|
fn before(&self) -> &[Label];
|
||||||
|
fn after(&self) -> &[Label];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a dependency graph of given nodes.
|
||||||
|
pub fn build_dependency_graph<Node, Label>(
|
||||||
|
nodes: &[Node],
|
||||||
|
) -> HashMap<usize, HashMap<usize, HashSet<Label>>>
|
||||||
|
where
|
||||||
|
Node: GraphNode<Label>,
|
||||||
|
Label: Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
|
let mut labels = HashMap::<Label, FixedBitSet>::default();
|
||||||
|
for (label, index) in nodes.iter().enumerate().flat_map(|(index, container)| {
|
||||||
|
container
|
||||||
|
.labels()
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(move |label| (label, index))
|
||||||
|
}) {
|
||||||
|
labels
|
||||||
|
.entry(label)
|
||||||
|
.or_insert_with(|| FixedBitSet::with_capacity(nodes.len()))
|
||||||
|
.insert(index);
|
||||||
|
}
|
||||||
|
let mut graph = HashMap::with_capacity_and_hasher(nodes.len(), Default::default());
|
||||||
|
for (index, node) in nodes.iter().enumerate() {
|
||||||
|
let dependencies = graph.entry(index).or_insert_with(HashMap::default);
|
||||||
|
for label in node.after() {
|
||||||
|
match labels.get(label) {
|
||||||
|
Some(new_dependencies) => {
|
||||||
|
for dependency in new_dependencies.ones() {
|
||||||
|
dependencies
|
||||||
|
.entry(dependency)
|
||||||
|
.or_insert_with(HashSet::default)
|
||||||
|
.insert(label.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => warn!(
|
||||||
|
// TODO: plumb this as proper output?
|
||||||
|
"{} wants to be after unknown label: {:?}",
|
||||||
|
nodes[index].name(),
|
||||||
|
label
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for label in node.before() {
|
||||||
|
match labels.get(label) {
|
||||||
|
Some(dependants) => {
|
||||||
|
for dependant in dependants.ones() {
|
||||||
|
graph
|
||||||
|
.entry(dependant)
|
||||||
|
.or_insert_with(HashMap::default)
|
||||||
|
.entry(index)
|
||||||
|
.or_insert_with(HashSet::default)
|
||||||
|
.insert(label.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => warn!(
|
||||||
|
"{} wants to be before unknown label: {:?}",
|
||||||
|
nodes[index].name(),
|
||||||
|
label
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
graph
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a topological order for the given graph.
|
||||||
|
pub fn topological_order<Labels: Clone>(
|
||||||
|
graph: &HashMap<usize, HashMap<usize, Labels>>,
|
||||||
|
) -> Result<Vec<usize>, DependencyGraphError<Labels>> {
|
||||||
|
fn check_if_cycles_and_visit<L>(
|
||||||
|
node: &usize,
|
||||||
|
graph: &HashMap<usize, HashMap<usize, L>>,
|
||||||
|
sorted: &mut Vec<usize>,
|
||||||
|
unvisited: &mut HashSet<usize>,
|
||||||
|
current: &mut Vec<usize>,
|
||||||
|
) -> bool {
|
||||||
|
if current.contains(node) {
|
||||||
|
return true;
|
||||||
|
} else if !unvisited.remove(node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
current.push(*node);
|
||||||
|
for dependency in graph.get(node).unwrap().keys() {
|
||||||
|
if check_if_cycles_and_visit(dependency, &graph, sorted, unvisited, current) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sorted.push(*node);
|
||||||
|
current.pop();
|
||||||
|
false
|
||||||
|
}
|
||||||
|
let mut sorted = Vec::with_capacity(graph.len());
|
||||||
|
let mut current = Vec::with_capacity(graph.len());
|
||||||
|
let mut unvisited = HashSet::with_capacity_and_hasher(graph.len(), Default::default());
|
||||||
|
unvisited.extend(graph.keys().cloned());
|
||||||
|
while let Some(node) = unvisited.iter().next().cloned() {
|
||||||
|
if check_if_cycles_and_visit(&node, graph, &mut sorted, &mut unvisited, &mut current) {
|
||||||
|
let mut cycle = Vec::new();
|
||||||
|
let last_window = [*current.last().unwrap(), current[0]];
|
||||||
|
let mut windows = current
|
||||||
|
.windows(2)
|
||||||
|
.chain(std::iter::once(&last_window as &[usize]));
|
||||||
|
while let Some(&[dependant, dependency]) = windows.next() {
|
||||||
|
cycle.push((dependant, graph[&dependant][&dependency].clone()));
|
||||||
|
}
|
||||||
|
return Err(DependencyGraphError::GraphCycles(cycle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(sorted)
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
pub use bevy_ecs_macros::{AmbiguitySetLabel, StageLabel, SystemLabel};
|
pub use bevy_ecs_macros::{AmbiguitySetLabel, RunCriteriaLabel, StageLabel, SystemLabel};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
@ -67,6 +67,12 @@ pub trait AmbiguitySetLabel: DynHash + Debug + Send + Sync + 'static {
|
|||||||
}
|
}
|
||||||
pub(crate) type BoxedAmbiguitySetLabel = Box<dyn AmbiguitySetLabel>;
|
pub(crate) type BoxedAmbiguitySetLabel = Box<dyn AmbiguitySetLabel>;
|
||||||
|
|
||||||
|
pub trait RunCriteriaLabel: DynHash + Debug + Send + Sync + 'static {
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn dyn_clone(&self) -> Box<dyn RunCriteriaLabel>;
|
||||||
|
}
|
||||||
|
pub(crate) type BoxedRunCriteriaLabel = Box<dyn RunCriteriaLabel>;
|
||||||
|
|
||||||
macro_rules! impl_label {
|
macro_rules! impl_label {
|
||||||
($trait_name:ident) => {
|
($trait_name:ident) => {
|
||||||
impl PartialEq for dyn $trait_name {
|
impl PartialEq for dyn $trait_name {
|
||||||
@ -106,3 +112,4 @@ macro_rules! impl_label {
|
|||||||
impl_label!(StageLabel);
|
impl_label!(StageLabel);
|
||||||
impl_label!(SystemLabel);
|
impl_label!(SystemLabel);
|
||||||
impl_label!(AmbiguitySetLabel);
|
impl_label!(AmbiguitySetLabel);
|
||||||
|
impl_label!(RunCriteriaLabel);
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
mod executor;
|
mod executor;
|
||||||
mod executor_parallel;
|
mod executor_parallel;
|
||||||
|
pub mod graph_utils;
|
||||||
mod label;
|
mod label;
|
||||||
|
mod run_criteria;
|
||||||
mod stage;
|
mod stage;
|
||||||
mod state;
|
mod state;
|
||||||
mod system_container;
|
mod system_container;
|
||||||
@ -9,7 +11,9 @@ mod system_set;
|
|||||||
|
|
||||||
pub use executor::*;
|
pub use executor::*;
|
||||||
pub use executor_parallel::*;
|
pub use executor_parallel::*;
|
||||||
|
pub use graph_utils::GraphNode;
|
||||||
pub use label::*;
|
pub use label::*;
|
||||||
|
pub use run_criteria::*;
|
||||||
pub use stage::*;
|
pub use stage::*;
|
||||||
pub use state::*;
|
pub use state::*;
|
||||||
pub use system_container::*;
|
pub use system_container::*;
|
||||||
@ -17,20 +21,16 @@ pub use system_descriptor::*;
|
|||||||
pub use system_set::*;
|
pub use system_set::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::{Archetype, ArchetypeComponentId},
|
system::{IntoSystem, System},
|
||||||
component::ComponentId,
|
|
||||||
query::Access,
|
|
||||||
system::{BoxedSystem, IntoSystem, System, SystemId},
|
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Schedule {
|
pub struct Schedule {
|
||||||
stages: HashMap<BoxedStageLabel, Box<dyn Stage>>,
|
stages: HashMap<BoxedStageLabel, Box<dyn Stage>>,
|
||||||
stage_order: Vec<BoxedStageLabel>,
|
stage_order: Vec<BoxedStageLabel>,
|
||||||
run_criteria: RunCriteria,
|
run_criteria: BoxedRunCriteria,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Schedule {
|
impl Schedule {
|
||||||
@ -229,110 +229,3 @@ impl Stage for Schedule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum ShouldRun {
|
|
||||||
/// Yes, the system should run.
|
|
||||||
Yes,
|
|
||||||
/// No, the system should not run.
|
|
||||||
No,
|
|
||||||
/// Yes, the system should run, and afterwards the criteria should be checked again.
|
|
||||||
YesAndCheckAgain,
|
|
||||||
/// No, the system should not run right now, but the criteria should be checked again later.
|
|
||||||
NoAndCheckAgain,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RunCriteria {
|
|
||||||
criteria_system: Option<BoxedSystem<(), ShouldRun>>,
|
|
||||||
initialized: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for RunCriteria {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
criteria_system: None,
|
|
||||||
initialized: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RunCriteria {
|
|
||||||
pub fn set(&mut self, criteria_system: BoxedSystem<(), ShouldRun>) {
|
|
||||||
self.criteria_system = Some(criteria_system);
|
|
||||||
self.initialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn should_run(&mut self, world: &mut World) -> ShouldRun {
|
|
||||||
if let Some(ref mut run_criteria) = self.criteria_system {
|
|
||||||
if !self.initialized {
|
|
||||||
run_criteria.initialize(world);
|
|
||||||
self.initialized = true;
|
|
||||||
}
|
|
||||||
let should_run = run_criteria.run((), world);
|
|
||||||
run_criteria.apply_buffers(world);
|
|
||||||
should_run
|
|
||||||
} else {
|
|
||||||
ShouldRun::Yes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RunOnce {
|
|
||||||
ran: bool,
|
|
||||||
system_id: SystemId,
|
|
||||||
archetype_component_access: Access<ArchetypeComponentId>,
|
|
||||||
component_access: Access<ComponentId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for RunOnce {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
ran: false,
|
|
||||||
system_id: SystemId::new(),
|
|
||||||
archetype_component_access: Default::default(),
|
|
||||||
component_access: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl System for RunOnce {
|
|
||||||
type In = ();
|
|
||||||
type Out = ShouldRun;
|
|
||||||
|
|
||||||
fn name(&self) -> Cow<'static, str> {
|
|
||||||
Cow::Borrowed(std::any::type_name::<RunOnce>())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id(&self) -> SystemId {
|
|
||||||
self.system_id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_archetype(&mut self, _archetype: &Archetype) {}
|
|
||||||
|
|
||||||
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
|
|
||||||
&self.archetype_component_access
|
|
||||||
}
|
|
||||||
|
|
||||||
fn component_access(&self) -> &Access<ComponentId> {
|
|
||||||
&self.component_access
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_send(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn run_unsafe(&mut self, _input: Self::In, _world: &World) -> Self::Out {
|
|
||||||
if self.ran {
|
|
||||||
ShouldRun::No
|
|
||||||
} else {
|
|
||||||
self.ran = true;
|
|
||||||
ShouldRun::Yes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply_buffers(&mut self, _world: &mut World) {}
|
|
||||||
|
|
||||||
fn initialize(&mut self, _world: &mut World) {}
|
|
||||||
|
|
||||||
fn check_change_tick(&mut self, _change_tick: u32) {}
|
|
||||||
}
|
|
||||||
|
|||||||
397
crates/bevy_ecs/src/schedule/run_criteria.rs
Normal file
397
crates/bevy_ecs/src/schedule/run_criteria.rs
Normal file
@ -0,0 +1,397 @@
|
|||||||
|
use crate::{
|
||||||
|
archetype::{Archetype, ArchetypeComponentId},
|
||||||
|
component::ComponentId,
|
||||||
|
query::Access,
|
||||||
|
schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel},
|
||||||
|
system::{BoxedSystem, System, SystemId},
|
||||||
|
world::World,
|
||||||
|
};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ShouldRun {
|
||||||
|
/// Yes, the system should run.
|
||||||
|
Yes,
|
||||||
|
/// No, the system should not run.
|
||||||
|
No,
|
||||||
|
/// Yes, the system should run, and afterwards the criteria should be checked again.
|
||||||
|
YesAndCheckAgain,
|
||||||
|
/// No, the system should not run right now, but the criteria should be checked again later.
|
||||||
|
NoAndCheckAgain,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct BoxedRunCriteria {
|
||||||
|
criteria_system: Option<BoxedSystem<(), ShouldRun>>,
|
||||||
|
initialized: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BoxedRunCriteria {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
criteria_system: None,
|
||||||
|
initialized: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoxedRunCriteria {
|
||||||
|
pub fn set(&mut self, criteria_system: BoxedSystem<(), ShouldRun>) {
|
||||||
|
self.criteria_system = Some(criteria_system);
|
||||||
|
self.initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_run(&mut self, world: &mut World) -> ShouldRun {
|
||||||
|
if let Some(ref mut run_criteria) = self.criteria_system {
|
||||||
|
if !self.initialized {
|
||||||
|
run_criteria.initialize(world);
|
||||||
|
self.initialized = true;
|
||||||
|
}
|
||||||
|
let should_run = run_criteria.run((), world);
|
||||||
|
run_criteria.apply_buffers(world);
|
||||||
|
should_run
|
||||||
|
} else {
|
||||||
|
ShouldRun::Yes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum RunCriteriaInner {
|
||||||
|
Single(BoxedSystem<(), ShouldRun>),
|
||||||
|
Piped {
|
||||||
|
input: usize,
|
||||||
|
system: BoxedSystem<ShouldRun, ShouldRun>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct RunCriteriaContainer {
|
||||||
|
pub should_run: ShouldRun,
|
||||||
|
pub inner: RunCriteriaInner,
|
||||||
|
pub label: Option<BoxedRunCriteriaLabel>,
|
||||||
|
pub before: Vec<BoxedRunCriteriaLabel>,
|
||||||
|
pub after: Vec<BoxedRunCriteriaLabel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunCriteriaContainer {
|
||||||
|
pub fn from_descriptor(descriptor: RunCriteriaDescriptor) -> Self {
|
||||||
|
Self {
|
||||||
|
should_run: ShouldRun::Yes,
|
||||||
|
inner: match descriptor.system {
|
||||||
|
RunCriteriaSystem::Single(system) => RunCriteriaInner::Single(system),
|
||||||
|
RunCriteriaSystem::Piped(system) => RunCriteriaInner::Piped { input: 0, system },
|
||||||
|
},
|
||||||
|
label: descriptor.label,
|
||||||
|
before: descriptor.before,
|
||||||
|
after: descriptor.after,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Cow<'static, str> {
|
||||||
|
match &self.inner {
|
||||||
|
RunCriteriaInner::Single(system) => system.name(),
|
||||||
|
RunCriteriaInner::Piped { system, .. } => system.name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initialize(&mut self, world: &mut World) {
|
||||||
|
match &mut self.inner {
|
||||||
|
RunCriteriaInner::Single(system) => system.initialize(world),
|
||||||
|
RunCriteriaInner::Piped { system, .. } => system.initialize(world),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GraphNode<BoxedRunCriteriaLabel> for RunCriteriaContainer {
|
||||||
|
fn name(&self) -> Cow<'static, str> {
|
||||||
|
match &self.inner {
|
||||||
|
RunCriteriaInner::Single(system) => system.name(),
|
||||||
|
RunCriteriaInner::Piped { system, .. } => system.name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn labels(&self) -> &[BoxedRunCriteriaLabel] {
|
||||||
|
if let Some(ref label) = self.label {
|
||||||
|
std::slice::from_ref(label)
|
||||||
|
} else {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before(&self) -> &[BoxedRunCriteriaLabel] {
|
||||||
|
&self.before
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after(&self) -> &[BoxedRunCriteriaLabel] {
|
||||||
|
&self.after
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum RunCriteriaDescriptorOrLabel {
|
||||||
|
Descriptor(RunCriteriaDescriptor),
|
||||||
|
Label(BoxedRunCriteriaLabel),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(crate) enum DuplicateLabelStrategy {
|
||||||
|
Panic,
|
||||||
|
Discard,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RunCriteriaDescriptor {
|
||||||
|
pub(crate) system: RunCriteriaSystem,
|
||||||
|
pub(crate) label: Option<BoxedRunCriteriaLabel>,
|
||||||
|
pub(crate) duplicate_label_strategy: DuplicateLabelStrategy,
|
||||||
|
pub(crate) before: Vec<BoxedRunCriteriaLabel>,
|
||||||
|
pub(crate) after: Vec<BoxedRunCriteriaLabel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum RunCriteriaSystem {
|
||||||
|
Single(BoxedSystem<(), ShouldRun>),
|
||||||
|
Piped(BoxedSystem<ShouldRun, ShouldRun>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoRunCriteria<Marker> {
|
||||||
|
fn into(self) -> RunCriteriaDescriptorOrLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoRunCriteria<RunCriteriaDescriptor> for RunCriteriaDescriptorOrLabel {
|
||||||
|
fn into(self) -> RunCriteriaDescriptorOrLabel {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoRunCriteria<RunCriteriaDescriptorOrLabel> for RunCriteriaDescriptor {
|
||||||
|
fn into(self) -> RunCriteriaDescriptorOrLabel {
|
||||||
|
RunCriteriaDescriptorOrLabel::Descriptor(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoRunCriteria<BoxedSystem<(), ShouldRun>> for BoxedSystem<(), ShouldRun> {
|
||||||
|
fn into(self) -> RunCriteriaDescriptorOrLabel {
|
||||||
|
RunCriteriaDescriptorOrLabel::Descriptor(new_run_criteria_descriptor(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> IntoRunCriteria<BoxedSystem<(), ShouldRun>> for S
|
||||||
|
where
|
||||||
|
S: System<In = (), Out = ShouldRun>,
|
||||||
|
{
|
||||||
|
fn into(self) -> RunCriteriaDescriptorOrLabel {
|
||||||
|
RunCriteriaDescriptorOrLabel::Descriptor(new_run_criteria_descriptor(Box::new(self)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoRunCriteria<BoxedRunCriteriaLabel> for BoxedRunCriteriaLabel {
|
||||||
|
fn into(self) -> RunCriteriaDescriptorOrLabel {
|
||||||
|
RunCriteriaDescriptorOrLabel::Label(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L> IntoRunCriteria<BoxedRunCriteriaLabel> for L
|
||||||
|
where
|
||||||
|
L: RunCriteriaLabel,
|
||||||
|
{
|
||||||
|
fn into(self) -> RunCriteriaDescriptorOrLabel {
|
||||||
|
RunCriteriaDescriptorOrLabel::Label(Box::new(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoRunCriteria<RunCriteria> for RunCriteria {
|
||||||
|
fn into(self) -> RunCriteriaDescriptorOrLabel {
|
||||||
|
RunCriteriaDescriptorOrLabel::Label(self.label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RunCriteriaDescriptorCoercion {
|
||||||
|
/// Assigns a label to the criteria. Must be unique.
|
||||||
|
fn label(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor;
|
||||||
|
|
||||||
|
/// Assigns a label to the criteria. If the given label is already in use,
|
||||||
|
/// this criteria will be discarded before initialization.
|
||||||
|
fn label_discard_if_duplicate(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor;
|
||||||
|
|
||||||
|
/// Specifies that this criteria must be evaluated before a criteria with the given label.
|
||||||
|
fn before(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor;
|
||||||
|
|
||||||
|
/// Specifies that this criteria must be evaluated after a criteria with the given label.
|
||||||
|
fn after(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunCriteriaDescriptorCoercion for RunCriteriaDescriptor {
|
||||||
|
fn label(mut self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
self.label = Some(Box::new(label));
|
||||||
|
self.duplicate_label_strategy = DuplicateLabelStrategy::Panic;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn label_discard_if_duplicate(mut self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
self.label = Some(Box::new(label));
|
||||||
|
self.duplicate_label_strategy = DuplicateLabelStrategy::Discard;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before(mut self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
self.before.push(Box::new(label));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after(mut self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
self.after.push(Box::new(label));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_run_criteria_descriptor(system: BoxedSystem<(), ShouldRun>) -> RunCriteriaDescriptor {
|
||||||
|
RunCriteriaDescriptor {
|
||||||
|
system: RunCriteriaSystem::Single(system),
|
||||||
|
label: None,
|
||||||
|
duplicate_label_strategy: DuplicateLabelStrategy::Panic,
|
||||||
|
before: vec![],
|
||||||
|
after: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunCriteriaDescriptorCoercion for BoxedSystem<(), ShouldRun> {
|
||||||
|
fn label(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
new_run_criteria_descriptor(self).label(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn label_discard_if_duplicate(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
new_run_criteria_descriptor(self).label_discard_if_duplicate(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
new_run_criteria_descriptor(self).before(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
new_run_criteria_descriptor(self).after(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> RunCriteriaDescriptorCoercion for S
|
||||||
|
where
|
||||||
|
S: System<In = (), Out = ShouldRun>,
|
||||||
|
{
|
||||||
|
fn label(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
new_run_criteria_descriptor(Box::new(self)).label(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn label_discard_if_duplicate(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
new_run_criteria_descriptor(Box::new(self)).label_discard_if_duplicate(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
new_run_criteria_descriptor(Box::new(self)).before(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
|
||||||
|
new_run_criteria_descriptor(Box::new(self)).after(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RunCriteria {
|
||||||
|
label: BoxedRunCriteriaLabel,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunCriteria {
|
||||||
|
/// Constructs a new run criteria that will retrieve the result of the criteria `label`
|
||||||
|
/// and pipe it as input to `system`.
|
||||||
|
pub fn pipe(
|
||||||
|
label: impl RunCriteriaLabel,
|
||||||
|
system: impl System<In = ShouldRun, Out = ShouldRun>,
|
||||||
|
) -> RunCriteriaDescriptor {
|
||||||
|
label.pipe(system)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RunCriteriaPiping {
|
||||||
|
/// See [`RunCriteria::pipe()`].
|
||||||
|
fn pipe(self, system: impl System<In = ShouldRun, Out = ShouldRun>) -> RunCriteriaDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunCriteriaPiping for BoxedRunCriteriaLabel {
|
||||||
|
fn pipe(self, system: impl System<In = ShouldRun, Out = ShouldRun>) -> RunCriteriaDescriptor {
|
||||||
|
RunCriteriaDescriptor {
|
||||||
|
system: RunCriteriaSystem::Piped(Box::new(system)),
|
||||||
|
label: None,
|
||||||
|
duplicate_label_strategy: DuplicateLabelStrategy::Panic,
|
||||||
|
before: vec![],
|
||||||
|
after: vec![self],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L> RunCriteriaPiping for L
|
||||||
|
where
|
||||||
|
L: RunCriteriaLabel,
|
||||||
|
{
|
||||||
|
fn pipe(self, system: impl System<In = ShouldRun, Out = ShouldRun>) -> RunCriteriaDescriptor {
|
||||||
|
RunCriteriaDescriptor {
|
||||||
|
system: RunCriteriaSystem::Piped(Box::new(system)),
|
||||||
|
label: None,
|
||||||
|
duplicate_label_strategy: DuplicateLabelStrategy::Panic,
|
||||||
|
before: vec![],
|
||||||
|
after: vec![Box::new(self)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RunOnce {
|
||||||
|
ran: bool,
|
||||||
|
system_id: SystemId,
|
||||||
|
archetype_component_access: Access<ArchetypeComponentId>,
|
||||||
|
component_access: Access<ComponentId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RunOnce {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
ran: false,
|
||||||
|
system_id: SystemId::new(),
|
||||||
|
archetype_component_access: Default::default(),
|
||||||
|
component_access: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System for RunOnce {
|
||||||
|
type In = ();
|
||||||
|
type Out = ShouldRun;
|
||||||
|
|
||||||
|
fn name(&self) -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed(std::any::type_name::<RunOnce>())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> SystemId {
|
||||||
|
self.system_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_archetype(&mut self, _archetype: &Archetype) {}
|
||||||
|
|
||||||
|
fn component_access(&self) -> &Access<ComponentId> {
|
||||||
|
&self.component_access
|
||||||
|
}
|
||||||
|
|
||||||
|
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
|
||||||
|
&self.archetype_component_access
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_send(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn run_unsafe(&mut self, _input: Self::In, _world: &World) -> Self::Out {
|
||||||
|
if self.ran {
|
||||||
|
ShouldRun::No
|
||||||
|
} else {
|
||||||
|
self.ran = true;
|
||||||
|
ShouldRun::Yes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_buffers(&mut self, _world: &mut World) {}
|
||||||
|
|
||||||
|
fn initialize(&mut self, _world: &mut World) {}
|
||||||
|
|
||||||
|
fn check_change_tick(&mut self, _change_tick: u32) {}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,12 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
component::Component,
|
component::Component,
|
||||||
schedule::{ShouldRun, SystemSet},
|
schedule::{
|
||||||
system::{In, IntoChainSystem, IntoSystem, Local, Res, ResMut, System},
|
RunCriteriaDescriptor, RunCriteriaDescriptorCoercion, RunCriteriaLabel, ShouldRun,
|
||||||
|
SystemSet,
|
||||||
|
},
|
||||||
|
system::{In, IntoChainSystem, IntoSystem, Local, Res, ResMut},
|
||||||
};
|
};
|
||||||
|
use std::{any::TypeId, fmt::Debug, hash::Hash};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// ### Stack based state machine
|
/// ### Stack based state machine
|
||||||
@ -12,7 +16,7 @@ use thiserror::Error;
|
|||||||
/// * Pop removes the current state, and unpauses the last paused state.
|
/// * Pop removes the current state, and unpauses the last paused state.
|
||||||
/// * Next unwinds the state stack, and replaces the entire stack with a single new state
|
/// * Next unwinds the state stack, and replaces the entire stack with a single new state
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct State<T: Component + Clone + Eq> {
|
pub struct State<T> {
|
||||||
transition: Option<StateTransition<T>>,
|
transition: Option<StateTransition<T>>,
|
||||||
stack: Vec<T>,
|
stack: Vec<T>,
|
||||||
scheduled: Option<ScheduledOperation<T>>,
|
scheduled: Option<ScheduledOperation<T>>,
|
||||||
@ -20,7 +24,7 @@ pub struct State<T: Component + Clone + Eq> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum StateTransition<T: Component + Clone + Eq> {
|
enum StateTransition<T> {
|
||||||
PreStartup,
|
PreStartup,
|
||||||
Startup,
|
Startup,
|
||||||
// The parameter order is always (leaving, entering)
|
// The parameter order is always (leaving, entering)
|
||||||
@ -32,23 +36,73 @@ enum StateTransition<T: Component + Clone + Eq> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ScheduledOperation<T: Component + Clone + Eq> {
|
enum ScheduledOperation<T> {
|
||||||
Next(T),
|
Next(T),
|
||||||
Pop,
|
Pop,
|
||||||
Push(T),
|
Push(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Component + Clone + Eq> State<T> {
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
pub fn on_update(s: T) -> impl System<In = (), Out = ShouldRun> {
|
enum StateCallback {
|
||||||
|
Update,
|
||||||
|
InactiveUpdate,
|
||||||
|
InStackUpdate,
|
||||||
|
Enter,
|
||||||
|
Exit,
|
||||||
|
Pause,
|
||||||
|
Resume,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StateCallback {
|
||||||
|
fn into_label<T>(self, state: T) -> StateRunCriteriaLabel<T>
|
||||||
|
where
|
||||||
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
|
StateRunCriteriaLabel(state, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
|
struct StateRunCriteriaLabel<T>(T, StateCallback);
|
||||||
|
impl<T> RunCriteriaLabel for StateRunCriteriaLabel<T>
|
||||||
|
where
|
||||||
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
|
fn dyn_clone(&self) -> Box<dyn RunCriteriaLabel> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
|
struct DriverLabel(TypeId);
|
||||||
|
impl RunCriteriaLabel for DriverLabel {
|
||||||
|
fn dyn_clone(&self) -> Box<dyn RunCriteriaLabel> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DriverLabel {
|
||||||
|
fn of<T: 'static>() -> Self {
|
||||||
|
Self(TypeId::of::<T>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> State<T>
|
||||||
|
where
|
||||||
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
|
pub fn on_update(s: T) -> RunCriteriaDescriptor {
|
||||||
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
||||||
state.stack.last().unwrap() == pred.as_ref().unwrap() && state.transition.is_none()
|
state.stack.last().unwrap() == pred.as_ref().unwrap() && state.transition.is_none()
|
||||||
})
|
})
|
||||||
.system()
|
.system()
|
||||||
.config(|(_, pred)| *pred = Some(Some(s)))
|
.config(|(_, pred)| *pred = Some(Some(s.clone())))
|
||||||
.chain(should_run_adapter::<T>.system())
|
.chain(should_run_adapter::<T>.system())
|
||||||
|
.after(DriverLabel::of::<T>())
|
||||||
|
.label_discard_if_duplicate(StateCallback::Update.into_label(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_inactive_update(s: T) -> impl System<In = (), Out = ShouldRun> {
|
pub fn on_inactive_update(s: T) -> RunCriteriaDescriptor {
|
||||||
(|state: Res<State<T>>, mut is_inactive: Local<bool>, pred: Local<Option<T>>| match &state
|
(|state: Res<State<T>>, mut is_inactive: Local<bool>, pred: Local<Option<T>>| match &state
|
||||||
.transition
|
.transition
|
||||||
{
|
{
|
||||||
@ -63,11 +117,13 @@ impl<T: Component + Clone + Eq> State<T> {
|
|||||||
None => *is_inactive,
|
None => *is_inactive,
|
||||||
})
|
})
|
||||||
.system()
|
.system()
|
||||||
.config(|(_, _, pred)| *pred = Some(Some(s)))
|
.config(|(_, _, pred)| *pred = Some(Some(s.clone())))
|
||||||
.chain(should_run_adapter::<T>.system())
|
.chain(should_run_adapter::<T>.system())
|
||||||
|
.after(DriverLabel::of::<T>())
|
||||||
|
.label_discard_if_duplicate(StateCallback::InactiveUpdate.into_label(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_in_stack_update(s: T) -> impl System<In = (), Out = ShouldRun> {
|
pub fn on_in_stack_update(s: T) -> RunCriteriaDescriptor {
|
||||||
(|state: Res<State<T>>, mut is_in_stack: Local<bool>, pred: Local<Option<T>>| match &state
|
(|state: Res<State<T>>, mut is_in_stack: Local<bool>, pred: Local<Option<T>>| match &state
|
||||||
.transition
|
.transition
|
||||||
{
|
{
|
||||||
@ -94,11 +150,13 @@ impl<T: Component + Clone + Eq> State<T> {
|
|||||||
None => *is_in_stack,
|
None => *is_in_stack,
|
||||||
})
|
})
|
||||||
.system()
|
.system()
|
||||||
.config(|(_, _, pred)| *pred = Some(Some(s)))
|
.config(|(_, _, pred)| *pred = Some(Some(s.clone())))
|
||||||
.chain(should_run_adapter::<T>.system())
|
.chain(should_run_adapter::<T>.system())
|
||||||
|
.after(DriverLabel::of::<T>())
|
||||||
|
.label_discard_if_duplicate(StateCallback::InStackUpdate.into_label(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_enter(s: T) -> impl System<In = (), Out = ShouldRun> {
|
pub fn on_enter(s: T) -> RunCriteriaDescriptor {
|
||||||
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
||||||
state
|
state
|
||||||
.transition
|
.transition
|
||||||
@ -112,11 +170,13 @@ impl<T: Component + Clone + Eq> State<T> {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.system()
|
.system()
|
||||||
.config(|(_, pred)| *pred = Some(Some(s)))
|
.config(|(_, pred)| *pred = Some(Some(s.clone())))
|
||||||
.chain(should_run_adapter::<T>.system())
|
.chain(should_run_adapter::<T>.system())
|
||||||
|
.after(DriverLabel::of::<T>())
|
||||||
|
.label_discard_if_duplicate(StateCallback::Enter.into_label(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_exit(s: T) -> impl System<In = (), Out = ShouldRun> {
|
pub fn on_exit(s: T) -> RunCriteriaDescriptor {
|
||||||
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
||||||
state
|
state
|
||||||
.transition
|
.transition
|
||||||
@ -128,11 +188,13 @@ impl<T: Component + Clone + Eq> State<T> {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.system()
|
.system()
|
||||||
.config(|(_, pred)| *pred = Some(Some(s)))
|
.config(|(_, pred)| *pred = Some(Some(s.clone())))
|
||||||
.chain(should_run_adapter::<T>.system())
|
.chain(should_run_adapter::<T>.system())
|
||||||
|
.after(DriverLabel::of::<T>())
|
||||||
|
.label_discard_if_duplicate(StateCallback::Exit.into_label(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_pause(s: T) -> impl System<In = (), Out = ShouldRun> {
|
pub fn on_pause(s: T) -> RunCriteriaDescriptor {
|
||||||
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
||||||
state
|
state
|
||||||
.transition
|
.transition
|
||||||
@ -143,11 +205,13 @@ impl<T: Component + Clone + Eq> State<T> {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.system()
|
.system()
|
||||||
.config(|(_, pred)| *pred = Some(Some(s)))
|
.config(|(_, pred)| *pred = Some(Some(s.clone())))
|
||||||
.chain(should_run_adapter::<T>.system())
|
.chain(should_run_adapter::<T>.system())
|
||||||
|
.after(DriverLabel::of::<T>())
|
||||||
|
.label_discard_if_duplicate(StateCallback::Pause.into_label(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_resume(s: T) -> impl System<In = (), Out = ShouldRun> {
|
pub fn on_resume(s: T) -> RunCriteriaDescriptor {
|
||||||
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
(|state: Res<State<T>>, pred: Local<Option<T>>| {
|
||||||
state
|
state
|
||||||
.transition
|
.transition
|
||||||
@ -158,8 +222,10 @@ impl<T: Component + Clone + Eq> State<T> {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.system()
|
.system()
|
||||||
.config(|(_, pred)| *pred = Some(Some(s)))
|
.config(|(_, pred)| *pred = Some(Some(s.clone())))
|
||||||
.chain(should_run_adapter::<T>.system())
|
.chain(should_run_adapter::<T>.system())
|
||||||
|
.after(DriverLabel::of::<T>())
|
||||||
|
.label_discard_if_duplicate(StateCallback::Resume.into_label(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_update_set(s: T) -> SystemSet {
|
pub fn on_update_set(s: T) -> SystemSet {
|
||||||
@ -191,7 +257,8 @@ impl<T: Component + Clone + Eq> State<T> {
|
|||||||
/// Important note: this set must be inserted **before** all other state-dependant sets to work
|
/// Important note: this set must be inserted **before** all other state-dependant sets to work
|
||||||
/// properly!
|
/// properly!
|
||||||
pub fn make_driver() -> SystemSet {
|
pub fn make_driver() -> SystemSet {
|
||||||
SystemSet::default().with_run_criteria(state_cleaner::<T>.system())
|
SystemSet::default()
|
||||||
|
.with_run_criteria(state_cleaner::<T>.system().label(DriverLabel::of::<T>()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(initial: T) -> Self {
|
pub fn new(initial: T) -> Self {
|
||||||
@ -390,7 +457,7 @@ mod test {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
enum MyState {
|
enum MyState {
|
||||||
S1,
|
S1,
|
||||||
S2,
|
S2,
|
||||||
|
|||||||
@ -2,32 +2,33 @@ use crate::{
|
|||||||
component::ComponentId,
|
component::ComponentId,
|
||||||
query::Access,
|
query::Access,
|
||||||
schedule::{
|
schedule::{
|
||||||
BoxedAmbiguitySetLabel, BoxedSystemLabel, ExclusiveSystemDescriptor,
|
BoxedAmbiguitySetLabel, BoxedRunCriteriaLabel, BoxedSystemLabel, ExclusiveSystemDescriptor,
|
||||||
ParallelSystemDescriptor,
|
GraphNode, ParallelSystemDescriptor,
|
||||||
},
|
},
|
||||||
system::{ExclusiveSystem, System},
|
system::{ExclusiveSystem, System},
|
||||||
};
|
};
|
||||||
use std::{borrow::Cow, ptr::NonNull};
|
use std::{borrow::Cow, ptr::NonNull};
|
||||||
|
|
||||||
/// System metadata like its name, labels, order requirements and component access.
|
/// System metadata like its name, labels, order requirements and component access.
|
||||||
pub trait SystemContainer {
|
pub trait SystemContainer: GraphNode<BoxedSystemLabel> {
|
||||||
fn name(&self) -> Cow<'static, str>;
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn dependencies(&self) -> &[usize];
|
fn dependencies(&self) -> &[usize];
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>);
|
fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>);
|
||||||
fn system_set(&self) -> usize;
|
#[doc(hidden)]
|
||||||
fn labels(&self) -> &[BoxedSystemLabel];
|
fn run_criteria(&self) -> Option<usize>;
|
||||||
fn before(&self) -> &[BoxedSystemLabel];
|
#[doc(hidden)]
|
||||||
fn after(&self) -> &[BoxedSystemLabel];
|
fn set_run_criteria(&mut self, index: usize);
|
||||||
|
fn run_criteria_label(&self) -> Option<&BoxedRunCriteriaLabel>;
|
||||||
fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel];
|
fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel];
|
||||||
fn component_access(&self) -> Option<&Access<ComponentId>>;
|
fn component_access(&self) -> Option<&Access<ComponentId>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct ExclusiveSystemContainer {
|
pub(super) struct ExclusiveSystemContainer {
|
||||||
system: Box<dyn ExclusiveSystem>,
|
system: Box<dyn ExclusiveSystem>,
|
||||||
|
pub(super) run_criteria_index: Option<usize>,
|
||||||
|
pub(super) run_criteria_label: Option<BoxedRunCriteriaLabel>,
|
||||||
dependencies: Vec<usize>,
|
dependencies: Vec<usize>,
|
||||||
set: usize,
|
|
||||||
labels: Vec<BoxedSystemLabel>,
|
labels: Vec<BoxedSystemLabel>,
|
||||||
before: Vec<BoxedSystemLabel>,
|
before: Vec<BoxedSystemLabel>,
|
||||||
after: Vec<BoxedSystemLabel>,
|
after: Vec<BoxedSystemLabel>,
|
||||||
@ -35,11 +36,12 @@ pub(super) struct ExclusiveSystemContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExclusiveSystemContainer {
|
impl ExclusiveSystemContainer {
|
||||||
pub fn from_descriptor(descriptor: ExclusiveSystemDescriptor, set: usize) -> Self {
|
pub fn from_descriptor(descriptor: ExclusiveSystemDescriptor) -> Self {
|
||||||
ExclusiveSystemContainer {
|
ExclusiveSystemContainer {
|
||||||
system: descriptor.system,
|
system: descriptor.system,
|
||||||
|
run_criteria_index: None,
|
||||||
|
run_criteria_label: None,
|
||||||
dependencies: Vec::new(),
|
dependencies: Vec::new(),
|
||||||
set,
|
|
||||||
labels: descriptor.labels,
|
labels: descriptor.labels,
|
||||||
before: descriptor.before,
|
before: descriptor.before,
|
||||||
after: descriptor.after,
|
after: descriptor.after,
|
||||||
@ -52,24 +54,11 @@ impl ExclusiveSystemContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemContainer for ExclusiveSystemContainer {
|
impl GraphNode<BoxedSystemLabel> for ExclusiveSystemContainer {
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> Cow<'static, str> {
|
||||||
self.system.name()
|
self.system.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dependencies(&self) -> &[usize] {
|
|
||||||
&self.dependencies
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>) {
|
|
||||||
self.dependencies.clear();
|
|
||||||
self.dependencies.extend(dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn system_set(&self) -> usize {
|
|
||||||
self.set
|
|
||||||
}
|
|
||||||
|
|
||||||
fn labels(&self) -> &[BoxedSystemLabel] {
|
fn labels(&self) -> &[BoxedSystemLabel] {
|
||||||
&self.labels
|
&self.labels
|
||||||
}
|
}
|
||||||
@ -81,6 +70,29 @@ impl SystemContainer for ExclusiveSystemContainer {
|
|||||||
fn after(&self) -> &[BoxedSystemLabel] {
|
fn after(&self) -> &[BoxedSystemLabel] {
|
||||||
&self.after
|
&self.after
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemContainer for ExclusiveSystemContainer {
|
||||||
|
fn dependencies(&self) -> &[usize] {
|
||||||
|
&self.dependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>) {
|
||||||
|
self.dependencies.clear();
|
||||||
|
self.dependencies.extend(dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_criteria(&self) -> Option<usize> {
|
||||||
|
self.run_criteria_index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_run_criteria(&mut self, index: usize) {
|
||||||
|
self.run_criteria_index = Some(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_criteria_label(&self) -> Option<&BoxedRunCriteriaLabel> {
|
||||||
|
self.run_criteria_label.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] {
|
fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] {
|
||||||
&self.ambiguity_sets
|
&self.ambiguity_sets
|
||||||
@ -93,9 +105,10 @@ impl SystemContainer for ExclusiveSystemContainer {
|
|||||||
|
|
||||||
pub struct ParallelSystemContainer {
|
pub struct ParallelSystemContainer {
|
||||||
system: NonNull<dyn System<In = (), Out = ()>>,
|
system: NonNull<dyn System<In = (), Out = ()>>,
|
||||||
|
pub(crate) run_criteria_index: Option<usize>,
|
||||||
|
pub(crate) run_criteria_label: Option<BoxedRunCriteriaLabel>,
|
||||||
pub(crate) should_run: bool,
|
pub(crate) should_run: bool,
|
||||||
dependencies: Vec<usize>,
|
dependencies: Vec<usize>,
|
||||||
set: usize,
|
|
||||||
labels: Vec<BoxedSystemLabel>,
|
labels: Vec<BoxedSystemLabel>,
|
||||||
before: Vec<BoxedSystemLabel>,
|
before: Vec<BoxedSystemLabel>,
|
||||||
after: Vec<BoxedSystemLabel>,
|
after: Vec<BoxedSystemLabel>,
|
||||||
@ -106,11 +119,12 @@ unsafe impl Send for ParallelSystemContainer {}
|
|||||||
unsafe impl Sync for ParallelSystemContainer {}
|
unsafe impl Sync for ParallelSystemContainer {}
|
||||||
|
|
||||||
impl ParallelSystemContainer {
|
impl ParallelSystemContainer {
|
||||||
pub(crate) fn from_descriptor(descriptor: ParallelSystemDescriptor, set: usize) -> Self {
|
pub(crate) fn from_descriptor(descriptor: ParallelSystemDescriptor) -> Self {
|
||||||
ParallelSystemContainer {
|
ParallelSystemContainer {
|
||||||
system: unsafe { NonNull::new_unchecked(Box::into_raw(descriptor.system)) },
|
system: unsafe { NonNull::new_unchecked(Box::into_raw(descriptor.system)) },
|
||||||
should_run: false,
|
should_run: false,
|
||||||
set,
|
run_criteria_index: None,
|
||||||
|
run_criteria_label: None,
|
||||||
dependencies: Vec::new(),
|
dependencies: Vec::new(),
|
||||||
labels: descriptor.labels,
|
labels: descriptor.labels,
|
||||||
before: descriptor.before,
|
before: descriptor.before,
|
||||||
@ -120,7 +134,7 @@ impl ParallelSystemContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> Cow<'static, str> {
|
pub fn name(&self) -> Cow<'static, str> {
|
||||||
SystemContainer::name(self)
|
GraphNode::name(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn system(&self) -> &dyn System<In = (), Out = ()> {
|
pub fn system(&self) -> &dyn System<In = (), Out = ()> {
|
||||||
@ -149,24 +163,11 @@ impl ParallelSystemContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemContainer for ParallelSystemContainer {
|
impl GraphNode<BoxedSystemLabel> for ParallelSystemContainer {
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> Cow<'static, str> {
|
||||||
self.system().name()
|
self.system().name()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dependencies(&self) -> &[usize] {
|
|
||||||
&self.dependencies
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>) {
|
|
||||||
self.dependencies.clear();
|
|
||||||
self.dependencies.extend(dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn system_set(&self) -> usize {
|
|
||||||
self.set
|
|
||||||
}
|
|
||||||
|
|
||||||
fn labels(&self) -> &[BoxedSystemLabel] {
|
fn labels(&self) -> &[BoxedSystemLabel] {
|
||||||
&self.labels
|
&self.labels
|
||||||
}
|
}
|
||||||
@ -178,6 +179,29 @@ impl SystemContainer for ParallelSystemContainer {
|
|||||||
fn after(&self) -> &[BoxedSystemLabel] {
|
fn after(&self) -> &[BoxedSystemLabel] {
|
||||||
&self.after
|
&self.after
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemContainer for ParallelSystemContainer {
|
||||||
|
fn dependencies(&self) -> &[usize] {
|
||||||
|
&self.dependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>) {
|
||||||
|
self.dependencies.clear();
|
||||||
|
self.dependencies.extend(dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_criteria(&self) -> Option<usize> {
|
||||||
|
self.run_criteria_index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_run_criteria(&mut self, index: usize) {
|
||||||
|
self.run_criteria_index = Some(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_criteria_label(&self) -> Option<&BoxedRunCriteriaLabel> {
|
||||||
|
self.run_criteria_label.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] {
|
fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] {
|
||||||
&self.ambiguity_sets
|
&self.ambiguity_sets
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
schedule::{AmbiguitySetLabel, BoxedAmbiguitySetLabel, BoxedSystemLabel, SystemLabel},
|
schedule::{
|
||||||
|
AmbiguitySetLabel, BoxedAmbiguitySetLabel, BoxedSystemLabel, IntoRunCriteria,
|
||||||
|
RunCriteriaDescriptorOrLabel, SystemLabel,
|
||||||
|
},
|
||||||
system::{BoxedSystem, ExclusiveSystem, ExclusiveSystemCoerced, ExclusiveSystemFn, System},
|
system::{BoxedSystem, ExclusiveSystem, ExclusiveSystemCoerced, ExclusiveSystemFn, System},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -77,9 +80,10 @@ impl From<ExclusiveSystemCoerced> for SystemDescriptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encapsulates a parallel system and information on when it run in a `SystemStage`.
|
/// Encapsulates a parallel system and information on when it runs in a `SystemStage`.
|
||||||
pub struct ParallelSystemDescriptor {
|
pub struct ParallelSystemDescriptor {
|
||||||
pub(crate) system: BoxedSystem<(), ()>,
|
pub(crate) system: BoxedSystem<(), ()>,
|
||||||
|
pub(crate) run_criteria: Option<RunCriteriaDescriptorOrLabel>,
|
||||||
pub(crate) labels: Vec<BoxedSystemLabel>,
|
pub(crate) labels: Vec<BoxedSystemLabel>,
|
||||||
pub(crate) before: Vec<BoxedSystemLabel>,
|
pub(crate) before: Vec<BoxedSystemLabel>,
|
||||||
pub(crate) after: Vec<BoxedSystemLabel>,
|
pub(crate) after: Vec<BoxedSystemLabel>,
|
||||||
@ -89,6 +93,7 @@ pub struct ParallelSystemDescriptor {
|
|||||||
fn new_parallel_descriptor(system: BoxedSystem<(), ()>) -> ParallelSystemDescriptor {
|
fn new_parallel_descriptor(system: BoxedSystem<(), ()>) -> ParallelSystemDescriptor {
|
||||||
ParallelSystemDescriptor {
|
ParallelSystemDescriptor {
|
||||||
system,
|
system,
|
||||||
|
run_criteria: None,
|
||||||
labels: Vec::new(),
|
labels: Vec::new(),
|
||||||
before: Vec::new(),
|
before: Vec::new(),
|
||||||
after: Vec::new(),
|
after: Vec::new(),
|
||||||
@ -97,6 +102,13 @@ fn new_parallel_descriptor(system: BoxedSystem<(), ()>) -> ParallelSystemDescrip
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait ParallelSystemDescriptorCoercion {
|
pub trait ParallelSystemDescriptorCoercion {
|
||||||
|
/// Assigns a run criteria to the system. Can be a new descriptor or a label of a
|
||||||
|
/// run criteria defined elsewhere.
|
||||||
|
fn with_run_criteria<Marker>(
|
||||||
|
self,
|
||||||
|
run_criteria: impl IntoRunCriteria<Marker>,
|
||||||
|
) -> ParallelSystemDescriptor;
|
||||||
|
|
||||||
/// Assigns a label to the system; there can be more than one, and it doesn't have to be unique.
|
/// Assigns a label to the system; there can be more than one, and it doesn't have to be unique.
|
||||||
fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor;
|
fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor;
|
||||||
|
|
||||||
@ -112,6 +124,14 @@ pub trait ParallelSystemDescriptorCoercion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ParallelSystemDescriptorCoercion for ParallelSystemDescriptor {
|
impl ParallelSystemDescriptorCoercion for ParallelSystemDescriptor {
|
||||||
|
fn with_run_criteria<Marker>(
|
||||||
|
mut self,
|
||||||
|
run_criteria: impl IntoRunCriteria<Marker>,
|
||||||
|
) -> ParallelSystemDescriptor {
|
||||||
|
self.run_criteria = Some(run_criteria.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn label(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
fn label(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
||||||
self.labels.push(Box::new(label));
|
self.labels.push(Box::new(label));
|
||||||
self
|
self
|
||||||
@ -137,6 +157,13 @@ impl<S> ParallelSystemDescriptorCoercion for S
|
|||||||
where
|
where
|
||||||
S: System<In = (), Out = ()>,
|
S: System<In = (), Out = ()>,
|
||||||
{
|
{
|
||||||
|
fn with_run_criteria<Marker>(
|
||||||
|
self,
|
||||||
|
run_criteria: impl IntoRunCriteria<Marker>,
|
||||||
|
) -> ParallelSystemDescriptor {
|
||||||
|
new_parallel_descriptor(Box::new(self)).with_run_criteria(run_criteria)
|
||||||
|
}
|
||||||
|
|
||||||
fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
||||||
new_parallel_descriptor(Box::new(self)).label(label)
|
new_parallel_descriptor(Box::new(self)).label(label)
|
||||||
}
|
}
|
||||||
@ -155,6 +182,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ParallelSystemDescriptorCoercion for BoxedSystem<(), ()> {
|
impl ParallelSystemDescriptorCoercion for BoxedSystem<(), ()> {
|
||||||
|
fn with_run_criteria<Marker>(
|
||||||
|
self,
|
||||||
|
run_criteria: impl IntoRunCriteria<Marker>,
|
||||||
|
) -> ParallelSystemDescriptor {
|
||||||
|
new_parallel_descriptor(self).with_run_criteria(run_criteria)
|
||||||
|
}
|
||||||
|
|
||||||
fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
||||||
new_parallel_descriptor(self).label(label)
|
new_parallel_descriptor(self).label(label)
|
||||||
}
|
}
|
||||||
@ -179,9 +213,10 @@ pub(crate) enum InsertionPoint {
|
|||||||
AtEnd,
|
AtEnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encapsulates an exclusive system and information on when it run in a `SystemStage`.
|
/// Encapsulates an exclusive system and information on when it runs in a `SystemStage`.
|
||||||
pub struct ExclusiveSystemDescriptor {
|
pub struct ExclusiveSystemDescriptor {
|
||||||
pub(crate) system: Box<dyn ExclusiveSystem>,
|
pub(crate) system: Box<dyn ExclusiveSystem>,
|
||||||
|
pub(crate) run_criteria: Option<RunCriteriaDescriptorOrLabel>,
|
||||||
pub(crate) labels: Vec<BoxedSystemLabel>,
|
pub(crate) labels: Vec<BoxedSystemLabel>,
|
||||||
pub(crate) before: Vec<BoxedSystemLabel>,
|
pub(crate) before: Vec<BoxedSystemLabel>,
|
||||||
pub(crate) after: Vec<BoxedSystemLabel>,
|
pub(crate) after: Vec<BoxedSystemLabel>,
|
||||||
@ -192,6 +227,7 @@ pub struct ExclusiveSystemDescriptor {
|
|||||||
fn new_exclusive_descriptor(system: Box<dyn ExclusiveSystem>) -> ExclusiveSystemDescriptor {
|
fn new_exclusive_descriptor(system: Box<dyn ExclusiveSystem>) -> ExclusiveSystemDescriptor {
|
||||||
ExclusiveSystemDescriptor {
|
ExclusiveSystemDescriptor {
|
||||||
system,
|
system,
|
||||||
|
run_criteria: None,
|
||||||
labels: Vec::new(),
|
labels: Vec::new(),
|
||||||
before: Vec::new(),
|
before: Vec::new(),
|
||||||
after: Vec::new(),
|
after: Vec::new(),
|
||||||
@ -201,6 +237,13 @@ fn new_exclusive_descriptor(system: Box<dyn ExclusiveSystem>) -> ExclusiveSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait ExclusiveSystemDescriptorCoercion {
|
pub trait ExclusiveSystemDescriptorCoercion {
|
||||||
|
/// Assigns a run criteria to the system. Can be a new descriptor or a label of a
|
||||||
|
/// run criteria defined elsewhere.
|
||||||
|
fn with_run_criteria<Marker>(
|
||||||
|
self,
|
||||||
|
run_criteria: impl IntoRunCriteria<Marker>,
|
||||||
|
) -> ExclusiveSystemDescriptor;
|
||||||
|
|
||||||
/// Assigns a label to the system; there can be more than one, and it doesn't have to be unique.
|
/// Assigns a label to the system; there can be more than one, and it doesn't have to be unique.
|
||||||
fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor;
|
fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor;
|
||||||
|
|
||||||
@ -226,6 +269,14 @@ pub trait ExclusiveSystemDescriptorCoercion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExclusiveSystemDescriptorCoercion for ExclusiveSystemDescriptor {
|
impl ExclusiveSystemDescriptorCoercion for ExclusiveSystemDescriptor {
|
||||||
|
fn with_run_criteria<Marker>(
|
||||||
|
mut self,
|
||||||
|
run_criteria: impl IntoRunCriteria<Marker>,
|
||||||
|
) -> ExclusiveSystemDescriptor {
|
||||||
|
self.run_criteria = Some(run_criteria.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn label(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
fn label(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
||||||
self.labels.push(Box::new(label));
|
self.labels.push(Box::new(label));
|
||||||
self
|
self
|
||||||
@ -266,6 +317,13 @@ impl<T> ExclusiveSystemDescriptorCoercion for T
|
|||||||
where
|
where
|
||||||
T: ExclusiveSystem + 'static,
|
T: ExclusiveSystem + 'static,
|
||||||
{
|
{
|
||||||
|
fn with_run_criteria<Marker>(
|
||||||
|
self,
|
||||||
|
run_criteria: impl IntoRunCriteria<Marker>,
|
||||||
|
) -> ExclusiveSystemDescriptor {
|
||||||
|
new_exclusive_descriptor(Box::new(self)).with_run_criteria(run_criteria)
|
||||||
|
}
|
||||||
|
|
||||||
fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
||||||
new_exclusive_descriptor(Box::new(self)).label(label)
|
new_exclusive_descriptor(Box::new(self)).label(label)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,31 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
component::Component,
|
component::Component,
|
||||||
schedule::{RunCriteria, ShouldRun, State, SystemDescriptor},
|
schedule::{
|
||||||
system::System,
|
AmbiguitySetLabel, BoxedAmbiguitySetLabel, BoxedSystemLabel, IntoRunCriteria,
|
||||||
|
RunCriteriaDescriptorOrLabel, State, SystemDescriptor, SystemLabel,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
use std::{fmt::Debug, hash::Hash};
|
||||||
|
|
||||||
/// Describes a group of systems sharing one run criterion.
|
/// A builder for describing several systems at the same time.
|
||||||
pub struct SystemSet {
|
pub struct SystemSet {
|
||||||
pub(crate) run_criteria: RunCriteria,
|
pub(crate) systems: Vec<SystemDescriptor>,
|
||||||
pub(crate) descriptors: Vec<SystemDescriptor>,
|
pub(crate) run_criteria: Option<RunCriteriaDescriptorOrLabel>,
|
||||||
|
pub(crate) labels: Vec<BoxedSystemLabel>,
|
||||||
|
pub(crate) before: Vec<BoxedSystemLabel>,
|
||||||
|
pub(crate) after: Vec<BoxedSystemLabel>,
|
||||||
|
pub(crate) ambiguity_sets: Vec<BoxedAmbiguitySetLabel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SystemSet {
|
impl Default for SystemSet {
|
||||||
fn default() -> SystemSet {
|
fn default() -> SystemSet {
|
||||||
SystemSet {
|
SystemSet {
|
||||||
run_criteria: Default::default(),
|
systems: Vec::new(),
|
||||||
descriptors: vec![],
|
run_criteria: None,
|
||||||
|
labels: Vec::new(),
|
||||||
|
before: Vec::new(),
|
||||||
|
after: Vec::new(),
|
||||||
|
ambiguity_sets: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,50 +35,107 @@ impl SystemSet {
|
|||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_run_criteria<S: System<In = (), Out = ShouldRun>>(mut self, system: S) -> Self {
|
pub fn on_update<T>(s: T) -> SystemSet
|
||||||
self.add_run_criteria(system);
|
where
|
||||||
self
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
|
Self::new().with_run_criteria(State::<T>::on_update(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_run_criteria<S: System<In = (), Out = ShouldRun>>(
|
pub fn on_inactive_update<T>(s: T) -> SystemSet
|
||||||
&mut self,
|
where
|
||||||
system: S,
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
) -> &mut Self {
|
{
|
||||||
self.run_criteria.set(Box::new(system));
|
Self::new().with_run_criteria(State::<T>::on_inactive_update(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_enter<T>(s: T) -> SystemSet
|
||||||
|
where
|
||||||
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
|
Self::new().with_run_criteria(State::<T>::on_enter(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_exit<T>(s: T) -> SystemSet
|
||||||
|
where
|
||||||
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
|
Self::new().with_run_criteria(State::<T>::on_exit(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_pause<T>(s: T) -> SystemSet
|
||||||
|
where
|
||||||
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
|
Self::new().with_run_criteria(State::<T>::on_pause(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_resume<T>(s: T) -> SystemSet
|
||||||
|
where
|
||||||
|
T: Component + Debug + Clone + Eq + Hash,
|
||||||
|
{
|
||||||
|
Self::new().with_run_criteria(State::<T>::on_resume(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn in_ambiguity_set(mut self, set: impl AmbiguitySetLabel) -> Self {
|
||||||
|
self.ambiguity_sets.push(Box::new(set));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_system(mut self, system: impl Into<SystemDescriptor>) -> Self {
|
pub fn with_system(mut self, system: impl Into<SystemDescriptor>) -> Self {
|
||||||
self.add_system(system);
|
self.systems.push(system.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
|
pub fn with_run_criteria<Marker>(mut self, run_criteria: impl IntoRunCriteria<Marker>) -> Self {
|
||||||
self.descriptors.push(system.into());
|
self.run_criteria = Some(run_criteria.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_update<T: Component + Clone + Eq>(s: T) -> SystemSet {
|
pub fn label(mut self, label: impl SystemLabel) -> Self {
|
||||||
Self::new().with_run_criteria(State::<T>::on_update(s))
|
self.labels.push(Box::new(label));
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_inactive_update<T: Component + Clone + Eq>(s: T) -> SystemSet {
|
pub fn before(mut self, label: impl SystemLabel) -> Self {
|
||||||
Self::new().with_run_criteria(State::<T>::on_inactive_update(s))
|
self.before.push(Box::new(label));
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_enter<T: Component + Clone + Eq>(s: T) -> SystemSet {
|
pub fn after(mut self, label: impl SystemLabel) -> Self {
|
||||||
Self::new().with_run_criteria(State::<T>::on_enter(s))
|
self.after.push(Box::new(label));
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_exit<T: Component + Clone + Eq>(s: T) -> SystemSet {
|
pub(crate) fn bake(self) -> (Option<RunCriteriaDescriptorOrLabel>, Vec<SystemDescriptor>) {
|
||||||
Self::new().with_run_criteria(State::<T>::on_exit(s))
|
let SystemSet {
|
||||||
|
mut systems,
|
||||||
|
run_criteria,
|
||||||
|
labels,
|
||||||
|
before,
|
||||||
|
after,
|
||||||
|
ambiguity_sets,
|
||||||
|
} = self;
|
||||||
|
for descriptor in &mut systems {
|
||||||
|
match descriptor {
|
||||||
|
SystemDescriptor::Parallel(descriptor) => {
|
||||||
|
descriptor.labels.extend(labels.iter().cloned());
|
||||||
|
descriptor.before.extend(before.iter().cloned());
|
||||||
|
descriptor.after.extend(after.iter().cloned());
|
||||||
|
descriptor
|
||||||
|
.ambiguity_sets
|
||||||
|
.extend(ambiguity_sets.iter().cloned());
|
||||||
}
|
}
|
||||||
|
SystemDescriptor::Exclusive(descriptor) => {
|
||||||
pub fn on_pause<T: Component + Clone + Eq>(s: T) -> SystemSet {
|
descriptor.labels.extend(labels.iter().cloned());
|
||||||
Self::new().with_run_criteria(State::<T>::on_pause(s))
|
descriptor.before.extend(before.iter().cloned());
|
||||||
|
descriptor.after.extend(after.iter().cloned());
|
||||||
|
descriptor
|
||||||
|
.ambiguity_sets
|
||||||
|
.extend(ambiguity_sets.iter().cloned());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub fn on_resume<T: Component + Clone + Eq>(s: T) -> SystemSet {
|
}
|
||||||
Self::new().with_run_criteria(State::<T>::on_resume(s))
|
(run_criteria, systems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ fn main() {
|
|||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
enum AppState {
|
enum AppState {
|
||||||
Setup,
|
Setup,
|
||||||
Finished,
|
Finished,
|
||||||
|
|||||||
@ -19,7 +19,7 @@ fn main() {
|
|||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
enum AppState {
|
enum AppState {
|
||||||
Menu,
|
Menu,
|
||||||
InGame,
|
InGame,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use bevy::{
|
|||||||
};
|
};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
|
||||||
enum GameState {
|
enum GameState {
|
||||||
Playing,
|
Playing,
|
||||||
GameOver,
|
GameOver,
|
||||||
|
|||||||
@ -27,7 +27,7 @@ fn main() {
|
|||||||
|
|
||||||
// NOTE: this "state based" approach to multiple windows is a short term workaround.
|
// NOTE: this "state based" approach to multiple windows is a short term workaround.
|
||||||
// Future Bevy releases shouldn't require such a strict order of operations.
|
// Future Bevy releases shouldn't require such a strict order of operations.
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
enum AppState {
|
enum AppState {
|
||||||
CreateWindow,
|
CreateWindow,
|
||||||
Setup,
|
Setup,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user