mirror of
https://github.com/bevyengine/bevy
synced 2024-12-21 18:43:07 +00:00
d51130d4ab
* Systems can now have more than one label attached to them. * System labels no longer have to be unique in the stage. Code like this is now possible: ```rust SystemStage::parallel() .with_system(system_0.system().label("group one").label("first")) .with_system(system_1.system().label("group one").after("first")) .with_system(system_2.system().after("group one")) ``` I've opted to use only the system name in ambiguity reporting, which previously was only a fallback; this, obviously, is because labels aren't one-to-one with systems anymore. We could allow users to name systems to improve this; we'll then have to think about whether or not we want to allow using the name as a label (this would, effectively, introduce implicit labelling, not all implications of which are clear to me yet wrt many-to-many labels). Dependency cycle errors are reported using the system names and only the labels that form the cycle, with each system-system "edge" in the cycle represented as one or several labels. Slightly unrelated: `.before()` and `.after()` with a label not attached to any system no longer crashes, and logs a warning instead. This is necessary to, for example, allow plugins to specify execution order with systems of potentially missing other plugins.
296 lines
9.9 KiB
Rust
296 lines
9.9 KiB
Rust
use crate::{
|
|
schedule::{AmbiguitySetLabel, BoxedAmbiguitySetLabel, BoxedSystemLabel, SystemLabel},
|
|
system::{BoxedSystem, ExclusiveSystem, ExclusiveSystemCoerced, ExclusiveSystemFn, System},
|
|
};
|
|
|
|
/// Encapsulates a system and information on when it run in a `SystemStage`.
|
|
///
|
|
/// Systems can be inserted into 4 different groups within the stage:
|
|
/// * Parallel, accepts non-exclusive systems.
|
|
/// * At start, accepts exclusive systems; runs before parallel systems.
|
|
/// * Before commands, accepts exclusive systems; runs after parallel systems, but before their
|
|
/// command buffers are applied.
|
|
/// * At end, accepts exclusive systems; runs after parallel systems' command buffers have
|
|
/// been applied.
|
|
///
|
|
/// Systems can have one or more labels attached to them; other systems in the same group
|
|
/// can then specify that they have to run before or after systems with that label using the
|
|
/// `before` and `after` methods.
|
|
///
|
|
/// # Example
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # fn do_something() {}
|
|
/// # fn do_the_other_thing() {}
|
|
/// # fn do_something_else() {}
|
|
/// #[derive(SystemLabel, Debug, Clone, PartialEq, Eq, Hash)]
|
|
/// struct Something;
|
|
///
|
|
/// SystemStage::parallel()
|
|
/// .with_system(do_something.system().label(Something))
|
|
/// .with_system(do_the_other_thing.system().after(Something))
|
|
/// .with_system(do_something_else.exclusive_system().at_end());
|
|
/// ```
|
|
pub enum SystemDescriptor {
|
|
Parallel(ParallelSystemDescriptor),
|
|
Exclusive(ExclusiveSystemDescriptor),
|
|
}
|
|
|
|
pub struct SystemLabelMarker;
|
|
|
|
impl From<ParallelSystemDescriptor> for SystemDescriptor {
|
|
fn from(descriptor: ParallelSystemDescriptor) -> Self {
|
|
SystemDescriptor::Parallel(descriptor)
|
|
}
|
|
}
|
|
|
|
impl<S> From<S> for SystemDescriptor
|
|
where
|
|
S: System<In = (), Out = ()>,
|
|
{
|
|
fn from(system: S) -> Self {
|
|
new_parallel_descriptor(Box::new(system)).into()
|
|
}
|
|
}
|
|
|
|
impl From<BoxedSystem<(), ()>> for SystemDescriptor {
|
|
fn from(system: BoxedSystem<(), ()>) -> Self {
|
|
new_parallel_descriptor(system).into()
|
|
}
|
|
}
|
|
|
|
impl From<ExclusiveSystemDescriptor> for SystemDescriptor {
|
|
fn from(descriptor: ExclusiveSystemDescriptor) -> Self {
|
|
SystemDescriptor::Exclusive(descriptor)
|
|
}
|
|
}
|
|
|
|
impl From<ExclusiveSystemFn> for SystemDescriptor {
|
|
fn from(system: ExclusiveSystemFn) -> Self {
|
|
new_exclusive_descriptor(Box::new(system)).into()
|
|
}
|
|
}
|
|
|
|
impl From<ExclusiveSystemCoerced> for SystemDescriptor {
|
|
fn from(system: ExclusiveSystemCoerced) -> Self {
|
|
new_exclusive_descriptor(Box::new(system)).into()
|
|
}
|
|
}
|
|
|
|
/// Encapsulates a parallel system and information on when it run in a `SystemStage`.
|
|
pub struct ParallelSystemDescriptor {
|
|
pub(crate) system: BoxedSystem<(), ()>,
|
|
pub(crate) labels: Vec<BoxedSystemLabel>,
|
|
pub(crate) before: Vec<BoxedSystemLabel>,
|
|
pub(crate) after: Vec<BoxedSystemLabel>,
|
|
pub(crate) ambiguity_sets: Vec<BoxedAmbiguitySetLabel>,
|
|
}
|
|
|
|
fn new_parallel_descriptor(system: BoxedSystem<(), ()>) -> ParallelSystemDescriptor {
|
|
ParallelSystemDescriptor {
|
|
system,
|
|
labels: Vec::new(),
|
|
before: Vec::new(),
|
|
after: Vec::new(),
|
|
ambiguity_sets: Vec::new(),
|
|
}
|
|
}
|
|
|
|
pub trait ParallelSystemDescriptorCoercion {
|
|
/// 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;
|
|
|
|
/// Specifies that the system should run before systems with the given label.
|
|
fn before(self, label: impl SystemLabel) -> ParallelSystemDescriptor;
|
|
|
|
/// Specifies that the system should run after systems with the given label.
|
|
fn after(self, label: impl SystemLabel) -> ParallelSystemDescriptor;
|
|
|
|
/// Specifies that the system is exempt from execution order ambiguity detection
|
|
/// with other systems in this set.
|
|
fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ParallelSystemDescriptor;
|
|
}
|
|
|
|
impl ParallelSystemDescriptorCoercion for ParallelSystemDescriptor {
|
|
fn label(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
|
self.labels.push(Box::new(label));
|
|
self
|
|
}
|
|
|
|
fn before(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
|
self.before.push(Box::new(label));
|
|
self
|
|
}
|
|
|
|
fn after(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
|
self.after.push(Box::new(label));
|
|
self
|
|
}
|
|
|
|
fn in_ambiguity_set(mut self, set: impl AmbiguitySetLabel) -> ParallelSystemDescriptor {
|
|
self.ambiguity_sets.push(Box::new(set));
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<S> ParallelSystemDescriptorCoercion for S
|
|
where
|
|
S: System<In = (), Out = ()>,
|
|
{
|
|
fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
|
new_parallel_descriptor(Box::new(self)).label(label)
|
|
}
|
|
|
|
fn before(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
|
new_parallel_descriptor(Box::new(self)).before(label)
|
|
}
|
|
|
|
fn after(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
|
new_parallel_descriptor(Box::new(self)).after(label)
|
|
}
|
|
|
|
fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ParallelSystemDescriptor {
|
|
new_parallel_descriptor(Box::new(self)).in_ambiguity_set(set)
|
|
}
|
|
}
|
|
|
|
impl ParallelSystemDescriptorCoercion for BoxedSystem<(), ()> {
|
|
fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
|
new_parallel_descriptor(self).label(label)
|
|
}
|
|
|
|
fn before(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
|
new_parallel_descriptor(self).before(label)
|
|
}
|
|
|
|
fn after(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
|
|
new_parallel_descriptor(self).after(label)
|
|
}
|
|
|
|
fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ParallelSystemDescriptor {
|
|
new_parallel_descriptor(self).in_ambiguity_set(set)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub(crate) enum InsertionPoint {
|
|
AtStart,
|
|
BeforeCommands,
|
|
AtEnd,
|
|
}
|
|
|
|
/// Encapsulates an exclusive system and information on when it run in a `SystemStage`.
|
|
pub struct ExclusiveSystemDescriptor {
|
|
pub(crate) system: Box<dyn ExclusiveSystem>,
|
|
pub(crate) labels: Vec<BoxedSystemLabel>,
|
|
pub(crate) before: Vec<BoxedSystemLabel>,
|
|
pub(crate) after: Vec<BoxedSystemLabel>,
|
|
pub(crate) ambiguity_sets: Vec<BoxedAmbiguitySetLabel>,
|
|
pub(crate) insertion_point: InsertionPoint,
|
|
}
|
|
|
|
fn new_exclusive_descriptor(system: Box<dyn ExclusiveSystem>) -> ExclusiveSystemDescriptor {
|
|
ExclusiveSystemDescriptor {
|
|
system,
|
|
labels: Vec::new(),
|
|
before: Vec::new(),
|
|
after: Vec::new(),
|
|
ambiguity_sets: Vec::new(),
|
|
insertion_point: InsertionPoint::AtStart,
|
|
}
|
|
}
|
|
|
|
pub trait ExclusiveSystemDescriptorCoercion {
|
|
/// 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;
|
|
|
|
/// Specifies that the system should run before systems with the given label.
|
|
fn before(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor;
|
|
|
|
/// Specifies that the system should run after systems with the given label.
|
|
fn after(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor;
|
|
|
|
/// Specifies that the system is exempt from execution order ambiguity detection
|
|
/// with other systems in this set.
|
|
fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ExclusiveSystemDescriptor;
|
|
|
|
/// Specifies that the system should run with other exclusive systems at the start of stage.
|
|
fn at_start(self) -> ExclusiveSystemDescriptor;
|
|
|
|
/// Specifies that the system should run with other exclusive systems after the parallel
|
|
/// systems and before command buffer application.
|
|
fn before_commands(self) -> ExclusiveSystemDescriptor;
|
|
|
|
/// Specifies that the system should run with other exclusive systems at the end of stage.
|
|
fn at_end(self) -> ExclusiveSystemDescriptor;
|
|
}
|
|
|
|
impl ExclusiveSystemDescriptorCoercion for ExclusiveSystemDescriptor {
|
|
fn label(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
|
self.labels.push(Box::new(label));
|
|
self
|
|
}
|
|
|
|
fn before(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
|
self.before.push(Box::new(label));
|
|
self
|
|
}
|
|
|
|
fn after(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
|
self.after.push(Box::new(label));
|
|
self
|
|
}
|
|
|
|
fn in_ambiguity_set(mut self, set: impl AmbiguitySetLabel) -> ExclusiveSystemDescriptor {
|
|
self.ambiguity_sets.push(Box::new(set));
|
|
self
|
|
}
|
|
|
|
fn at_start(mut self) -> ExclusiveSystemDescriptor {
|
|
self.insertion_point = InsertionPoint::AtStart;
|
|
self
|
|
}
|
|
|
|
fn before_commands(mut self) -> ExclusiveSystemDescriptor {
|
|
self.insertion_point = InsertionPoint::BeforeCommands;
|
|
self
|
|
}
|
|
|
|
fn at_end(mut self) -> ExclusiveSystemDescriptor {
|
|
self.insertion_point = InsertionPoint::AtEnd;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<T> ExclusiveSystemDescriptorCoercion for T
|
|
where
|
|
T: ExclusiveSystem + 'static,
|
|
{
|
|
fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
|
new_exclusive_descriptor(Box::new(self)).label(label)
|
|
}
|
|
|
|
fn before(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
|
new_exclusive_descriptor(Box::new(self)).before(label)
|
|
}
|
|
|
|
fn after(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
|
|
new_exclusive_descriptor(Box::new(self)).after(label)
|
|
}
|
|
|
|
fn in_ambiguity_set(self, set: impl AmbiguitySetLabel) -> ExclusiveSystemDescriptor {
|
|
new_exclusive_descriptor(Box::new(self)).in_ambiguity_set(set)
|
|
}
|
|
|
|
fn at_start(self) -> ExclusiveSystemDescriptor {
|
|
new_exclusive_descriptor(Box::new(self)).at_start()
|
|
}
|
|
|
|
fn before_commands(self) -> ExclusiveSystemDescriptor {
|
|
new_exclusive_descriptor(Box::new(self)).before_commands()
|
|
}
|
|
|
|
fn at_end(self) -> ExclusiveSystemDescriptor {
|
|
new_exclusive_descriptor(Box::new(self)).at_end()
|
|
}
|
|
}
|