use amethyst_core::{
ecs::{Read, System, Write},
timing::Time,
};
use std::{ops::RangeInclusive, time::Duration};
const DEFAULT_SIM_FRAME_RATE: u32 = 30;
pub struct NetworkSimulationTimeSystem;
impl<'s> System<'s> for NetworkSimulationTimeSystem {
type SystemData = (Write<'s, NetworkSimulationTime>, Read<'s, Time>);
fn run(&mut self, (mut sim_time, game_time): Self::SystemData) {
sim_time.update_elapsed(game_time.delta_time());
sim_time.reset_frame_lag();
while sim_time.elapsed_duration() > sim_time.per_frame_duration() {
sim_time.increment_frame_number();
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct NetworkSimulationTime {
frame_number: u32,
elapsed_duration: Duration,
per_frame_duration: Duration,
message_send_rate: u8,
frame_lag: u32,
}
impl NetworkSimulationTime {
pub fn sim_frames_to_run(&self) -> RangeInclusive<u32> {
(self.frame_number + 1 - self.frame_lag)..=self.frame_number
}
pub fn should_send_message_now(&self) -> bool {
self.should_send_message(self.frame_number)
}
pub fn should_send_message(&self, frame: u32) -> bool {
frame % u32::from(self.message_send_rate) == 0
}
pub fn increment_frame_number(&mut self) {
self.frame_number += 1;
self.elapsed_duration -= self.per_frame_duration;
self.frame_lag += 1;
}
pub fn reset_frame_lag(&mut self) {
self.frame_lag = 0;
}
pub fn update_elapsed(&mut self, duration: Duration) {
self.elapsed_duration += duration;
}
pub fn frame_number(&self) -> u32 {
self.frame_number
}
pub fn set_frame_number(&mut self, new_frame: u32) {
self.frame_number = new_frame;
}
pub fn elapsed_duration(&self) -> Duration {
self.elapsed_duration
}
pub fn per_frame_duration(&self) -> Duration {
self.per_frame_duration
}
pub fn message_send_rate(&self) -> u8 {
self.message_send_rate
}
pub fn frame_lag(&self) -> u32 {
self.frame_lag
}
pub fn set_sim_frame_rate(&mut self, new_rate: u32) {
self.per_frame_duration = Duration::from_secs(1) / new_rate;
}
pub fn set_message_send_rate(&mut self, new_rate: u8) {
self.message_send_rate = new_rate;
}
}
impl Default for NetworkSimulationTime {
fn default() -> Self {
Self {
frame_number: 0,
elapsed_duration: Duration::from_secs(0),
per_frame_duration: Duration::from_secs(1) / DEFAULT_SIM_FRAME_RATE,
message_send_rate: 1,
frame_lag: 1,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[test]
fn test_calculated_properties_and_getters() {
let mut time = NetworkSimulationTime::default();
time.set_sim_frame_rate(20);
assert_eq!(time.frame_number(), 0);
assert_eq!(time.frame_lag(), 1);
assert_eq!(time.message_send_rate(), 1);
assert_eq!(time.per_frame_duration(), Duration::from_millis(50));
assert_eq!(time.elapsed_duration(), Duration::from_millis(0));
}
#[test]
fn test_message_send_rate_should_send_every_2_frames() {
let mut time = NetworkSimulationTime::default();
time.set_message_send_rate(2);
for i in 1..100 {
if i % 2 == 0 {
assert_eq!(time.should_send_message(i), true);
} else {
assert_eq!(time.should_send_message(i), false);
}
}
}
#[test]
fn test_elapsed_duration_gets_updated() {
let mut time = NetworkSimulationTime::default();
let elapsed_time = Duration::from_millis(500);
time.update_elapsed(elapsed_time);
assert_eq!(time.elapsed_duration(), elapsed_time)
}
}