use super::config::GenerationConfig;
use super::hook_ecs::GenerationHookECS;
use super::service::GenerationService;
use super::state_ecs::{GenerationEventECS, GenerationStateECS};
use super::types::*;
use crate::system::System;
use async_trait::async_trait;
use std::any::Any;
use std::sync::Arc;
use std::time::{Instant, SystemTime};
#[derive(Clone)]
#[allow(dead_code)]
pub struct GenerationSystemECS {
hook: Arc<dyn GenerationHookECS>,
}
#[async_trait]
impl System for GenerationSystemECS {
fn name(&self) -> &'static str {
"issun:generation_system_ecs"
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl GenerationSystemECS {
pub fn new(hook: Arc<dyn GenerationHookECS>) -> Self {
Self { hook }
}
pub async fn update_generation(
&mut self,
state: &mut GenerationStateECS,
config: &GenerationConfig,
delta_time: f32,
) {
use rayon::prelude::*;
let start = Instant::now();
let mut processed = 0;
let mut total_progress = 0.0;
let changes: Vec<_> = state
.world
.query_mut::<(
&mut Generation,
&GenerationEnvironment,
&GenerationConditions,
&mut EntityTimestamp,
)>()
.into_iter()
.par_bridge() .filter_map(
|(entity, (generation, environment, conditions, timestamp))| {
if generation.paused {
return None;
}
if !GenerationService::check_conditions(
conditions,
environment.temperature,
&[], ) {
return None;
}
let modifiers = config
.environment_modifiers
.get(&generation.generation_type)
.cloned()
.unwrap_or(super::config::EnvironmentModifiers {
temperature_factor: 0.0,
fertility_factor: 0.0,
resource_factor: 0.0,
light_factor: 0.0,
});
let progress_amount = GenerationService::calculate_generation(
generation.generation_rate,
&generation.generation_type,
environment,
&modifiers,
config.global_generation_multiplier,
delta_time,
);
let old_value = generation.current;
let old_status = generation.status.clone();
generation.current = (generation.current + progress_amount).min(generation.max);
generation.update_status();
timestamp.last_updated = SystemTime::now();
let status_changed = old_status != generation.status;
let completed = generation.is_completed();
Some((
entity,
old_value,
generation.current,
progress_amount,
status_changed,
completed,
))
},
)
.collect();
for (entity, old_value, new_value, progress_amount, status_changed, completed) in changes {
processed += 1;
total_progress += progress_amount;
if status_changed {
state.generation_events.push(GenerationEventECS {
entity: Some(entity),
old_generation: old_value,
new_generation: new_value,
progress_amount,
timestamp: SystemTime::now(),
status_changed: true,
});
self.hook
.on_generation_status_changed(entity, new_value)
.await;
}
if completed {
self.hook.on_generation_completed(entity, state).await;
if config.auto_remove_on_complete {
state.completed_queue.push(entity);
}
}
}
state.trim_generation_events(config.max_generation_events);
state.metrics.entities_processed = processed;
state.metrics.entities_completed += state.completed_queue.len();
state.metrics.total_progress_applied = total_progress;
state.metrics.last_update_duration_us = start.elapsed().as_micros() as u64;
}
pub fn cleanup_completed(&self, state: &mut GenerationStateECS) {
state.cleanup_completed();
}
pub async fn reduce_entity(
&mut self,
entity: hecs::Entity,
reduction_amount: f32,
state: &mut GenerationStateECS,
) -> Result<f32, String> {
let mut generation = state
.world
.get::<&mut Generation>(entity)
.map_err(|_| "Entity not found or missing Generation component")?;
let mut history = state
.world
.get::<&mut GenerationHistory>(entity)
.map_err(|_| "Entity missing GenerationHistory component")?;
let reduced = GenerationService::reduce_generation(&mut generation, reduction_amount);
history.total_resources_consumed += reduced;
Ok(reduced)
}
pub async fn pause_entity(
&mut self,
entity: hecs::Entity,
state: &mut GenerationStateECS,
) -> Result<(), String> {
let mut generation = state
.world
.get::<&mut Generation>(entity)
.map_err(|_| "Entity not found or missing Generation component")?;
if !generation.paused {
generation.pause();
self.hook.on_generation_paused(entity).await;
}
Ok(())
}
pub async fn resume_entity(
&mut self,
entity: hecs::Entity,
state: &mut GenerationStateECS,
) -> Result<(), String> {
let mut generation = state
.world
.get::<&mut Generation>(entity)
.map_err(|_| "Entity not found or missing Generation component")?;
if generation.paused {
generation.resume();
self.hook.on_generation_resumed(entity).await;
}
Ok(())
}
pub fn metrics<'a>(&self, state: &'a GenerationStateECS) -> &'a GenerationMetrics {
state.metrics()
}
}
#[cfg(test)]
mod tests {
use super::super::hook_ecs::DefaultGenerationHookECS;
use super::*;
#[tokio::test]
async fn test_update_generation_basic() {
let hook = Arc::new(DefaultGenerationHookECS);
let mut system = GenerationSystemECS::new(hook);
let mut state = GenerationStateECS::new();
let config = GenerationConfig::default();
let entity = state.spawn_entity(
Generation::new(100.0, 1.0, GenerationType::Organic),
GenerationEnvironment::default(),
);
system.update_generation(&mut state, &config, 1.0).await;
let generation = state.world.get::<&Generation>(entity).unwrap();
assert!(generation.current > 0.0);
assert_eq!(state.metrics.entities_processed, 1);
}
#[tokio::test]
async fn test_update_generation_multiple_entities() {
let hook = Arc::new(DefaultGenerationHookECS);
let mut system = GenerationSystemECS::new(hook);
let mut state = GenerationStateECS::new();
let config = GenerationConfig::default();
for _ in 0..100 {
state.spawn_entity(
Generation::new(100.0, 1.0, GenerationType::Production),
GenerationEnvironment::default(),
);
}
system.update_generation(&mut state, &config, 1.0).await;
assert_eq!(state.metrics.entities_processed, 100);
}
#[tokio::test]
async fn test_paused_entities_skipped() {
let hook = Arc::new(DefaultGenerationHookECS);
let mut system = GenerationSystemECS::new(hook);
let mut state = GenerationStateECS::new();
let config = GenerationConfig::default();
let mut gen = Generation::new(100.0, 1.0, GenerationType::Construction);
gen.pause();
let entity = state.spawn_entity(gen, GenerationEnvironment::default());
system.update_generation(&mut state, &config, 1.0).await;
assert_eq!(state.metrics.entities_processed, 0);
let generation = state.world.get::<&Generation>(entity).unwrap();
assert_eq!(generation.current, 0.0); }
#[tokio::test]
async fn test_auto_remove_on_complete() {
let hook = Arc::new(DefaultGenerationHookECS);
let mut system = GenerationSystemECS::new(hook);
let mut state = GenerationStateECS::new();
let config = GenerationConfig {
auto_remove_on_complete: true,
..Default::default()
};
let _entity = state.spawn_entity(
Generation {
current: 100.0,
max: 100.0,
generation_rate: 0.0,
generation_type: GenerationType::Recovery,
status: GenerationStatus::Completed,
paused: false,
},
GenerationEnvironment::default(),
);
assert_eq!(state.entity_count(), 1);
system.update_generation(&mut state, &config, 1.0).await;
assert_eq!(state.completed_queue.len(), 1);
system.cleanup_completed(&mut state);
assert_eq!(state.entity_count(), 0);
}
#[tokio::test]
async fn test_reduce_entity() {
let hook = Arc::new(DefaultGenerationHookECS);
let mut system = GenerationSystemECS::new(hook);
let mut state = GenerationStateECS::new();
let entity = state.spawn_entity(
Generation {
current: 50.0,
max: 100.0,
generation_rate: 1.0,
generation_type: GenerationType::Construction,
status: GenerationStatus::Generating,
paused: false,
},
GenerationEnvironment::default(),
);
let reduced = system
.reduce_entity(entity, 20.0, &mut state)
.await
.unwrap();
assert_eq!(reduced, 20.0);
let generation = state.world.get::<&Generation>(entity).unwrap();
assert_eq!(generation.current, 30.0);
}
#[tokio::test]
async fn test_pause_resume() {
let hook = Arc::new(DefaultGenerationHookECS);
let mut system = GenerationSystemECS::new(hook);
let mut state = GenerationStateECS::new();
let entity = state.spawn_entity(
Generation::new(100.0, 1.0, GenerationType::Organic),
GenerationEnvironment::default(),
);
system.pause_entity(entity, &mut state).await.unwrap();
{
let generation = state.world.get::<&Generation>(entity).unwrap();
assert!(generation.paused);
}
system.resume_entity(entity, &mut state).await.unwrap();
{
let generation = state.world.get::<&Generation>(entity).unwrap();
assert!(!generation.paused);
}
}
#[tokio::test]
async fn test_parallel_performance() {
let hook = Arc::new(DefaultGenerationHookECS);
let mut system = GenerationSystemECS::new(hook);
let mut state = GenerationStateECS::new();
let config = GenerationConfig::default();
for _ in 0..10_000 {
state.spawn_entity(
Generation::new(100.0, 1.0, GenerationType::Production),
GenerationEnvironment::default(),
);
}
let start = Instant::now();
system.update_generation(&mut state, &config, 1.0).await;
let elapsed = start.elapsed();
println!("10,000 entities processed in {:?}", elapsed);
assert_eq!(state.metrics.entities_processed, 10_000);
assert!(elapsed.as_millis() < 1000); }
}