lyra-engine/crates/lyra-ecs/src/system/batched.rs

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
}
}