#[cfg(debug_assertions)]
mod alloc_guard;
mod fixed_timestep;
#[cfg(test)]
mod headless_world_tests;
#[cfg(test)]
mod run_tests;
use crate::ecs::{StepResult, SystemTable, World};
use crate::result::CnResult;
use fixed_timestep::FixedTimestep;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum AppStatus {
Created,
Started,
}
pub struct App {
world: World,
table: &'static SystemTable,
status: AppStatus,
sim: FixedTimestep,
#[cfg(debug_assertions)]
allocs: alloc_guard::AllocGuard,
}
impl core::fmt::Debug for App {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("App")
.field("ticks", &self.sim.ticks())
.field("status", &self.status)
.finish_non_exhaustive()
}
}
impl App {
pub fn from_world(world: World) -> Self {
Self::with_systems(world, &SystemTable::EMPTY)
}
pub fn with_systems(world: World, table: &'static SystemTable) -> Self {
Self {
world,
table,
status: AppStatus::Created,
sim: FixedTimestep::default(),
#[cfg(debug_assertions)]
allocs: alloc_guard::AllocGuard::new(),
}
}
pub fn world(&self) -> &World {
&self.world
}
pub fn ticks(&self) -> u64 {
self.sim.ticks()
}
pub fn start(&mut self) -> Result<(), CnResult> {
if self.status != AppStatus::Created {
return Err(CnResult::InvalidState);
}
self.world.start(self.table)?;
self.status = AppStatus::Started;
Ok(())
}
pub fn run(&mut self) -> Result<StepResult, CnResult> {
self.start_if_created()?;
loop {
let result = self.tick();
if result != StepResult::Continue {
return Ok(result);
}
}
}
pub fn run_for(&mut self, ticks: u64) -> Result<StepResult, CnResult> {
self.start_if_created()?;
let mut result = StepResult::Continue;
for _ in 0..ticks {
result = self.tick();
if result != StepResult::Continue {
break;
}
}
Ok(result)
}
fn start_if_created(&mut self) -> Result<(), CnResult> {
if self.status == AppStatus::Created {
self.start()?;
}
Ok(())
}
fn tick(&mut self) -> StepResult {
#[cfg(debug_assertions)]
self.allocs.begin_tick();
self.world.insert_resource(self.sim.advance());
let result = self.world.step();
#[cfg(debug_assertions)]
self.allocs.end_tick();
result
}
}