use crate::entity::EntityId;
use crate::world::World;
pub struct WorldInspector;
impl WorldInspector {
pub fn entity_count(world: &World) -> usize {
world.entity_count() as usize
}
pub fn archetype_summary(world: &World) -> Vec<ArchetypeInfo> {
let mut infos = Vec::new();
for (id, archetype) in world.archetypes().iter().enumerate() {
let signature: Vec<String> = archetype
.signature()
.iter()
.map(|type_id| format!("{type_id:?}"))
.collect();
infos.push(ArchetypeInfo {
id,
signature,
entity_count: archetype.len(),
component_count: archetype.signature().len(),
});
}
infos
}
pub fn print_summary(world: &World) {
println!("=== World Summary ===");
println!("Entities: {}", Self::entity_count(world));
println!("Archetypes: {}", world.archetype_count());
println!("\n=== Archetypes ===");
for info in Self::archetype_summary(world) {
println!(
"Archetype {}: {} entities, {} components",
info.id, info.entity_count, info.component_count
);
}
}
pub fn print_entity(world: &World, entity: EntityId) {
if let Some(location) = world.get_entity_location(entity) {
println!("=== Entity {entity:?} ===");
println!("Archetype: {}", location.archetype_id);
println!("Row: {}", location.archetype_row);
if let Some(archetype) = world.archetypes().get(location.archetype_id) {
println!("Components: {} types", archetype.signature().len());
}
} else {
println!("Entity {entity:?} not found");
}
}
}
#[derive(Clone, Debug)]
pub struct ArchetypeInfo {
pub id: usize,
pub signature: Vec<String>,
pub entity_count: usize,
pub component_count: usize,
}
use std::collections::VecDeque;
#[derive(Clone, Debug, Default)]
pub struct Diagnostics {
frame_times: VecDeque<f32>,
max_samples: usize,
}
impl Diagnostics {
pub fn new() -> Self {
Self {
frame_times: VecDeque::new(),
max_samples: 60,
}
}
pub fn record_frame_time(&mut self, time_ms: f32) {
self.frame_times.push_back(time_ms);
if self.frame_times.len() > self.max_samples {
self.frame_times.pop_front();
}
}
pub fn fps(&self) -> f32 {
if self.frame_times.is_empty() {
return 0.0;
}
let avg_ms: f32 = self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32;
if avg_ms > 0.0 {
1000.0 / avg_ms
} else {
0.0
}
}
pub fn avg_frame_time(&self) -> f32 {
if self.frame_times.is_empty() {
return 0.0;
}
self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32
}
pub fn min_frame_time(&self) -> f32 {
self.frame_times
.iter()
.copied()
.fold(f32::INFINITY, f32::min)
}
pub fn max_frame_time(&self) -> f32 {
self.frame_times
.iter()
.copied()
.fold(f32::NEG_INFINITY, f32::max)
}
pub fn print(&self) {
println!("=== Diagnostics ===");
println!("FPS: {:.1}", self.fps());
println!("Avg Frame Time: {:.2}ms", self.avg_frame_time());
println!("Min Frame Time: {:.2}ms", self.min_frame_time());
println!("Max Frame Time: {:.2}ms", self.max_frame_time());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_diagnostics() {
let mut diag = Diagnostics::new();
for _ in 0..10 {
diag.record_frame_time(16.67);
}
assert!((diag.fps() - 60.0).abs() < 1.0);
assert!((diag.avg_frame_time() - 16.67).abs() < 0.1);
}
#[test]
fn test_world_inspector() {
let world = World::new();
assert_eq!(WorldInspector::entity_count(&world), 0);
}
}