134 lines
No EOL
3.6 KiB
Rust
134 lines
No EOL
3.6 KiB
Rust
use lyra_ecs::World;
|
|
use tracing::{debug_span, instrument};
|
|
|
|
use crate::Access;
|
|
|
|
use super::{Criteria, GraphExecutorError, IntoSystem, System};
|
|
|
|
/// A system that executes a batch of systems in order that they were given.
|
|
/// You can optionally add criteria that must pass before the systems are
|
|
/// executed.
|
|
#[derive(Default)]
|
|
pub struct BatchedSystem {
|
|
systems: Vec<Box<dyn System>>,
|
|
criteria: Vec<Box<dyn Criteria>>,
|
|
criteria_checks: u32,
|
|
did_run: bool,
|
|
}
|
|
|
|
impl BatchedSystem {
|
|
/// Create a new BatchedSystem
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
pub fn with_system<S>(&mut self, system: S) -> &mut Self
|
|
where
|
|
S: System + 'static
|
|
{
|
|
self.systems.push(Box::new(system));
|
|
self
|
|
}
|
|
|
|
pub fn with_criteria<C>(&mut self, criteria: C) -> &mut Self
|
|
where
|
|
C: Criteria + 'static
|
|
{
|
|
self.criteria.push(Box::new(criteria));
|
|
self
|
|
}
|
|
}
|
|
|
|
impl System for BatchedSystem {
|
|
fn world_access(&self) -> crate::Access {
|
|
if self.systems.iter().any(|s| s.world_access() == Access::Write) {
|
|
Access::Write
|
|
} else {
|
|
Access::Read
|
|
}
|
|
}
|
|
|
|
#[instrument(skip(self, world))]
|
|
fn execute(&mut self, world: std::ptr::NonNull<World>) -> anyhow::Result<()> {
|
|
let mut can_run = true;
|
|
let mut check_again = false;
|
|
|
|
for criteria in self.criteria.iter_mut() {
|
|
let crit_span = debug_span!("criteria");
|
|
let _e = crit_span.enter();
|
|
|
|
match criteria.can_run(world, self.criteria_checks) {
|
|
super::CriteriaSchedule::Yes => {},
|
|
super::CriteriaSchedule::No => can_run = false,
|
|
super::CriteriaSchedule::YesAndLoop => {
|
|
check_again = can_run;
|
|
},
|
|
super::CriteriaSchedule::NoAndLoop => {
|
|
can_run = false;
|
|
check_again = true;
|
|
},
|
|
}
|
|
}
|
|
|
|
if can_run {
|
|
for criteria in self.criteria.iter_mut() {
|
|
criteria.modify_world(world);
|
|
}
|
|
|
|
for (idx, system) in self.systems.iter_mut().enumerate() {
|
|
let span = debug_span!("batch", system=idx);
|
|
let _e = span.enter();
|
|
|
|
system.execute(world)?;
|
|
|
|
/* let deferred_span = debug_span!("deferred_exec");
|
|
let _e = deferred_span.enter();
|
|
|
|
if let Err(e) = system.execute_deferred(world)
|
|
.map_err(|e| GraphExecutorError::Command(e)) {
|
|
return Err(e.into());
|
|
} */
|
|
}
|
|
|
|
self.did_run = true;
|
|
}
|
|
|
|
if check_again {
|
|
self.criteria_checks += 1;
|
|
self.execute(world)?;
|
|
}
|
|
|
|
self.criteria_checks = 0;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[instrument(skip(self, world))]
|
|
fn execute_deferred(&mut self, world: std::ptr::NonNull<World>) -> anyhow::Result<()> {
|
|
if self.did_run {
|
|
for (idx, system) in self.systems.iter_mut().enumerate() {
|
|
let span = debug_span!("batch", system=idx);
|
|
let _e = span.enter();
|
|
|
|
system.execute_deferred(world)
|
|
.map_err(|e| GraphExecutorError::Command(e))?;
|
|
}
|
|
|
|
for criteria in self.criteria.iter_mut() {
|
|
criteria.undo_world_modifications(world);
|
|
}
|
|
}
|
|
|
|
self.did_run = false;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl IntoSystem<()> for BatchedSystem {
|
|
type System = Self;
|
|
|
|
fn into_system(self) -> Self::System {
|
|
self
|
|
}
|
|
} |