ecs: fix BatchedSystem, implement ways for `Criteria`s to modify the world before and after execution

This commit is contained in:
SeanOMik 2024-04-24 00:28:01 -04:00
parent e2c6b557bb
commit 53837d469b
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
2 changed files with 52 additions and 16 deletions

View File

@ -1,9 +1,9 @@
use lyra_ecs::World;
use tracing::debug_span;
use tracing::{debug_span, instrument};
use crate::Access;
use super::{System, Criteria, IntoSystem};
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
@ -13,6 +13,7 @@ pub struct BatchedSystem {
systems: Vec<Box<dyn System>>,
criteria: Vec<Box<dyn Criteria>>,
criteria_checks: u32,
did_run: bool,
}
impl BatchedSystem {
@ -47,6 +48,7 @@ impl System for BatchedSystem {
}
}
#[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;
@ -69,13 +71,26 @@ impl System for BatchedSystem {
}
if can_run {
for criteria in self.criteria.iter_mut() {
criteria.modify_world(world);
}
for (idx, system) in self.systems.iter_mut().enumerate() {
let sys_span = debug_span!("batch", system=tracing::field::Empty);
sys_span.record("system", idx);
let _e = sys_span.enter();
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 {
@ -87,9 +102,26 @@ impl System for BatchedSystem {
Ok(())
}
fn execute_deferred(&mut self, _: std::ptr::NonNull<World>) -> anyhow::Result<()> {
todo!()
#[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(())
}
}

View File

@ -26,13 +26,17 @@ pub trait Criteria {
/// * `world` - The ecs world.
/// * `check_count` - The amount of times the Criteria has been checked this tick.
fn can_run(&mut self, world: NonNull<World>, check_count: u32) -> CriteriaSchedule;
}
impl<F> Criteria for F
where F: FnMut(&mut World, u32) -> CriteriaSchedule
{
fn can_run(&mut self, mut world: NonNull<World>, check_count: u32) -> CriteriaSchedule {
let world_mut = unsafe { world.as_mut() };
self(world_mut, check_count)
}
/// Modify the world after the [`Criteria`] in the system batch allows the systems to run.
///
/// This can be great if this Criteria limits the execution of systems based off of resources.
/// A `FixedTimestep` criteria would use this to replace the [`DeltaTime`] resource in the
/// world to match the timestep time.
fn modify_world(&mut self, world: NonNull<World>);
/// Undo modifications to the world after the systems in the batch have been executed.
///
/// The `FixedTimestep` criteria (see docs for [`Criteria::modify_world`]) uses this
/// to replace the [`DeltaTime`] resource with its original value before it was replaced.
fn undo_world_modifications(&mut self, world: NonNull<World>);
}