#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use core::time::Duration;
use log::debug;
use crate::{real::Real, time::Time};
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Clone))]
pub struct Virtual {
max_delta: Duration,
paused: bool,
relative_speed: f64,
effective_speed: f64,
}
impl Time<Virtual> {
const DEFAULT_MAX_DELTA: Duration = Duration::from_millis(250);
pub fn from_max_delta(max_delta: Duration) -> Self {
let mut ret = Self::default();
ret.set_max_delta(max_delta);
ret
}
#[inline]
pub fn max_delta(&self) -> Duration {
self.context().max_delta
}
#[inline]
pub fn set_max_delta(&mut self, max_delta: Duration) {
assert_ne!(max_delta, Duration::ZERO, "tried to set max delta to zero");
self.context_mut().max_delta = max_delta;
}
#[inline]
pub fn relative_speed(&self) -> f32 {
self.relative_speed_f64() as f32
}
#[inline]
pub fn relative_speed_f64(&self) -> f64 {
self.context().relative_speed
}
#[inline]
pub fn effective_speed(&self) -> f32 {
self.context().effective_speed as f32
}
#[inline]
pub fn effective_speed_f64(&self) -> f64 {
self.context().effective_speed
}
#[inline]
pub fn set_relative_speed(&mut self, ratio: f32) {
self.set_relative_speed_f64(ratio as f64);
}
#[inline]
pub fn set_relative_speed_f64(&mut self, ratio: f64) {
assert!(ratio.is_finite(), "tried to go infinitely fast");
assert!(ratio >= 0.0, "tried to go back in time");
self.context_mut().relative_speed = ratio;
}
#[inline]
pub fn pause(&mut self) {
self.context_mut().paused = true;
}
#[inline]
pub fn unpause(&mut self) {
self.context_mut().paused = false;
}
#[inline]
pub fn is_paused(&self) -> bool {
self.context().paused
}
#[inline]
pub fn was_paused(&self) -> bool {
self.context().effective_speed == 0.0
}
fn advance_with_raw_delta(&mut self, raw_delta: Duration) {
let max_delta = self.context().max_delta;
let clamped_delta = if raw_delta > max_delta {
debug!(
"delta time larger than maximum delta, clamping delta to {:?} and skipping {:?}",
max_delta,
raw_delta - max_delta
);
max_delta
} else {
raw_delta
};
let effective_speed = if self.context().paused {
0.0
} else {
self.context().relative_speed
};
let delta = if effective_speed != 1.0 {
clamped_delta.mul_f64(effective_speed)
} else {
clamped_delta
};
self.context_mut().effective_speed = effective_speed;
self.advance_by(delta);
}
}
impl Default for Virtual {
fn default() -> Self {
Self {
max_delta: Time::<Virtual>::DEFAULT_MAX_DELTA,
paused: false,
relative_speed: 1.0,
effective_speed: 1.0,
}
}
}
pub fn update_virtual_time(current: &mut Time, virt: &mut Time<Virtual>, real: &Time<Real>) {
let raw_delta = real.delta();
virt.advance_with_raw_delta(raw_delta);
*current = virt.as_generic();
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_default() {
let time = Time::<Virtual>::default();
assert!(!time.is_paused()); assert_eq!(time.relative_speed(), 1.0);
assert_eq!(time.max_delta(), Time::<Virtual>::DEFAULT_MAX_DELTA);
assert_eq!(time.delta(), Duration::ZERO);
assert_eq!(time.elapsed(), Duration::ZERO);
}
#[test]
fn test_advance() {
let mut time = Time::<Virtual>::default();
time.advance_with_raw_delta(Duration::from_millis(125));
assert_eq!(time.delta(), Duration::from_millis(125));
assert_eq!(time.elapsed(), Duration::from_millis(125));
time.advance_with_raw_delta(Duration::from_millis(125));
assert_eq!(time.delta(), Duration::from_millis(125));
assert_eq!(time.elapsed(), Duration::from_millis(250));
time.advance_with_raw_delta(Duration::from_millis(125));
assert_eq!(time.delta(), Duration::from_millis(125));
assert_eq!(time.elapsed(), Duration::from_millis(375));
time.advance_with_raw_delta(Duration::from_millis(125));
assert_eq!(time.delta(), Duration::from_millis(125));
assert_eq!(time.elapsed(), Duration::from_millis(500));
}
#[test]
fn test_relative_speed() {
let mut time = Time::<Virtual>::default();
time.advance_with_raw_delta(Duration::from_millis(250));
assert_eq!(time.relative_speed(), 1.0);
assert_eq!(time.effective_speed(), 1.0);
assert_eq!(time.delta(), Duration::from_millis(250));
assert_eq!(time.elapsed(), Duration::from_millis(250));
time.set_relative_speed_f64(2.0);
assert_eq!(time.relative_speed(), 2.0);
assert_eq!(time.effective_speed(), 1.0);
time.advance_with_raw_delta(Duration::from_millis(250));
assert_eq!(time.relative_speed(), 2.0);
assert_eq!(time.effective_speed(), 2.0);
assert_eq!(time.delta(), Duration::from_millis(500));
assert_eq!(time.elapsed(), Duration::from_millis(750));
time.set_relative_speed_f64(0.5);
assert_eq!(time.relative_speed(), 0.5);
assert_eq!(time.effective_speed(), 2.0);
time.advance_with_raw_delta(Duration::from_millis(250));
assert_eq!(time.relative_speed(), 0.5);
assert_eq!(time.effective_speed(), 0.5);
assert_eq!(time.delta(), Duration::from_millis(125));
assert_eq!(time.elapsed(), Duration::from_millis(875));
}
#[test]
fn test_pause() {
let mut time = Time::<Virtual>::default();
time.advance_with_raw_delta(Duration::from_millis(250));
assert!(!time.is_paused()); assert!(!time.was_paused()); assert_eq!(time.relative_speed(), 1.0);
assert_eq!(time.effective_speed(), 1.0);
assert_eq!(time.delta(), Duration::from_millis(250));
assert_eq!(time.elapsed(), Duration::from_millis(250));
time.pause();
assert!(time.is_paused()); assert!(!time.was_paused()); assert_eq!(time.relative_speed(), 1.0);
assert_eq!(time.effective_speed(), 1.0);
time.advance_with_raw_delta(Duration::from_millis(250));
assert!(time.is_paused()); assert!(time.was_paused()); assert_eq!(time.relative_speed(), 1.0);
assert_eq!(time.effective_speed(), 0.0);
assert_eq!(time.delta(), Duration::ZERO);
assert_eq!(time.elapsed(), Duration::from_millis(250));
time.unpause();
assert!(!time.is_paused()); assert!(time.was_paused()); assert_eq!(time.relative_speed(), 1.0);
assert_eq!(time.effective_speed(), 0.0);
time.advance_with_raw_delta(Duration::from_millis(250));
assert!(!time.is_paused()); assert!(!time.was_paused()); assert_eq!(time.relative_speed(), 1.0);
assert_eq!(time.effective_speed(), 1.0);
assert_eq!(time.delta(), Duration::from_millis(250));
assert_eq!(time.elapsed(), Duration::from_millis(500));
}
#[test]
fn test_max_delta() {
let mut time = Time::<Virtual>::default();
time.set_max_delta(Duration::from_millis(500));
time.advance_with_raw_delta(Duration::from_millis(250));
assert_eq!(time.delta(), Duration::from_millis(250));
assert_eq!(time.elapsed(), Duration::from_millis(250));
time.advance_with_raw_delta(Duration::from_millis(500));
assert_eq!(time.delta(), Duration::from_millis(500));
assert_eq!(time.elapsed(), Duration::from_millis(750));
time.advance_with_raw_delta(Duration::from_millis(750));
assert_eq!(time.delta(), Duration::from_millis(500));
assert_eq!(time.elapsed(), Duration::from_millis(1250));
time.set_max_delta(Duration::from_secs(1));
assert_eq!(time.max_delta(), Duration::from_secs(1));
time.advance_with_raw_delta(Duration::from_millis(750));
assert_eq!(time.delta(), Duration::from_millis(750));
assert_eq!(time.elapsed(), Duration::from_millis(2000));
time.advance_with_raw_delta(Duration::from_millis(1250));
assert_eq!(time.delta(), Duration::from_millis(1000));
assert_eq!(time.elapsed(), Duration::from_millis(3000));
}
}