use crate::context::{ResourceContext, ServiceContext};
use crate::event::EventBus;
use crate::system::System;
use async_trait::async_trait;
use std::any::Any;
use super::events::{AdvanceTimeRequested, DayChanged};
use super::resources::GameTimer;
#[derive(Default)]
pub struct TimerSystem;
impl TimerSystem {
pub async fn update(&mut self, _services: &ServiceContext, resources: &mut ResourceContext) {
let advance_requested = if let Some(mut bus) = resources.get_mut::<EventBus>().await {
let reader = bus.reader::<AdvanceTimeRequested>();
let has_events = reader.iter().count() > 0;
has_events
} else {
false
};
if !advance_requested {
return;
}
let new_day = if let Some(mut timer) = resources.get_mut::<GameTimer>().await {
timer.increment_day()
} else {
return;
};
if let Some(mut bus) = resources.get_mut::<EventBus>().await {
bus.publish(DayChanged { day: new_day });
}
}
}
#[async_trait]
impl System for TimerSystem {
fn name(&self) -> &'static str {
"timer"
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::context::{ResourceContext, ServiceContext};
use crate::event::EventBus;
#[tokio::test]
async fn test_timer_system_advances_day() {
let mut resources = ResourceContext::new();
resources.insert(GameTimer::new());
resources.insert(EventBus::new());
let services = ServiceContext::new();
let mut system = TimerSystem;
{
let mut bus = resources.get_mut::<EventBus>().await.unwrap();
bus.publish(AdvanceTimeRequested);
bus.dispatch(); }
system.update(&services, &mut resources).await;
{
let mut bus = resources.get_mut::<EventBus>().await.unwrap();
bus.dispatch();
}
let timer = resources.get::<GameTimer>().await.unwrap();
assert_eq!(timer.day, 2);
let mut bus = resources.get_mut::<EventBus>().await.unwrap();
let reader = bus.reader::<DayChanged>();
let events: Vec<_> = reader.iter().collect();
assert_eq!(events.len(), 1);
assert_eq!(events[0].day, 2);
}
#[tokio::test]
async fn test_timer_system_no_advancement_without_request() {
let mut resources = ResourceContext::new();
resources.insert(GameTimer::new());
resources.insert(EventBus::new());
let services = ServiceContext::new();
let mut system = TimerSystem;
system.update(&services, &mut resources).await;
let timer = resources.get::<GameTimer>().await.unwrap();
assert_eq!(timer.day, 1);
let mut bus = resources.get_mut::<EventBus>().await.unwrap();
let reader = bus.reader::<DayChanged>();
let events: Vec<_> = reader.iter().collect();
assert_eq!(events.len(), 0);
}
#[tokio::test]
async fn test_timer_system_multiple_requests() {
let mut resources = ResourceContext::new();
resources.insert(GameTimer::new());
resources.insert(EventBus::new());
let services = ServiceContext::new();
let mut system = TimerSystem;
{
let mut bus = resources.get_mut::<EventBus>().await.unwrap();
bus.publish(AdvanceTimeRequested);
bus.publish(AdvanceTimeRequested);
bus.dispatch(); }
system.update(&services, &mut resources).await;
{
let mut bus = resources.get_mut::<EventBus>().await.unwrap();
bus.dispatch();
}
let timer = resources.get::<GameTimer>().await.unwrap();
assert_eq!(timer.day, 2); drop(timer);
{
let mut bus = resources.get_mut::<EventBus>().await.unwrap();
bus.publish(AdvanceTimeRequested);
bus.dispatch(); }
system.update(&services, &mut resources).await;
{
let mut bus = resources.get_mut::<EventBus>().await.unwrap();
bus.dispatch();
}
let timer = resources.get::<GameTimer>().await.unwrap();
assert_eq!(timer.day, 3);
}
}