From 007621dd5d93ecb58d62889e2afe7def416eb5cf Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 10 Oct 2023 02:40:24 -0700 Subject: [PATCH] timers --- src/main.rs | 1 + src/timer.rs | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/timer.rs diff --git a/src/main.rs b/src/main.rs index 337ba79..765d81c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod file; mod setup; +mod timer; mod window; mod worker; mod physics; diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..6eeed72 --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,177 @@ +use strafesnet_common::integer::{Time,Ratio64}; + +pub trait TimerState:Copy{ + fn get_time(&self,time:Time)->Time; + fn set_time(&mut self,time:Time,new_time:Time); + fn get_offset(&self)->Time; + fn set_offset(&mut self,offset:Time); +} + +#[derive(Clone,Copy,Debug)] +struct Scaled{ + scale:Ratio64, + offset:Time, +} +impl Scaled{ + fn scale(&self,time:Time)->Time{ + Time::raw(self.scale.mul_int(time.get())) + } + fn get_scale(&self)->Ratio64{ + self.scale + } + fn set_scale(&mut self,time:Time,new_scale:Ratio64){ + let new_time=self.get_time(time); + self.scale=new_scale; + self.set_time(time,new_time); + } +} +impl TimerState for Scaled{ + fn get_time(&self,time:Time)->Time{ + self.scale(time)+self.offset + } + fn set_time(&mut self,time:Time,new_time:Time){ + self.offset=new_time-self.scale(time); + } + fn get_offset(&self)->Time{ + self.offset + } + fn set_offset(&mut self,offset:Time){ + self.offset=offset; + } +} + +#[derive(Clone,Copy,Debug)] +struct Realtime{ + offset:Time, +} +impl TimerState for Realtime{ + fn get_time(&self,time:Time)->Time{ + time+self.offset + } + fn set_time(&mut self,time:Time,new_time:Time){ + self.offset=new_time-time; + } + fn get_offset(&self)->Time{ + self.offset + } + fn set_offset(&mut self,offset:Time){ + self.offset=offset; + } +} + +#[derive(Clone,Debug)] +pub struct Timer{ + state:T, + paused:bool, +} + +impl Timer{ + pub fn realtime(offset:Time)->Self{ + Self{ + state:Realtime{offset}, + paused:false, + } + } + pub fn realtime_paused(offset:Time)->Self{ + Self{ + state:Realtime{offset}, + paused:true, + } + } +} + +#[derive(Debug)] +pub enum Error{ + AlreadyPaused, + AlreadyUnpaused, +} +impl std::fmt::Display for Error{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for Error{} + +impl Timer{ + pub fn scaled(scale:Ratio64,offset:Time)->Self{ + Self{ + state:Scaled{scale,offset}, + paused:false, + } + } + pub fn scaled_paused(scale:Ratio64,offset:Time)->Self{ + Self{ + state:Scaled{scale,offset}, + paused:true, + } + } + pub fn get_scale(&mut self)->Ratio64{ + self.state.get_scale() + } + pub fn set_scale(&mut self,time:Time,new_scale:Ratio64){ + self.state.set_scale(time,new_scale) + } +} + +impl Timer{ + pub fn time(&self,time:Time)->Time{ + match self.paused{ + true=>self.state.get_offset(), + false=>self.state.get_time(time), + } + } + pub fn set_time(&mut self,time:Time,new_time:Time){ + match self.paused{ + true=>self.state.set_offset(new_time), + false=>self.state.set_time(time,new_time), + } + } + pub fn pause(&mut self,time:Time)->Result<(),Error>{ + match self.paused{ + true=>Err(Error::AlreadyPaused), + false=>{ + let new_time=self.time(time); + self.state.set_offset(new_time); + self.paused=true; + Ok(()) + }, + } + } + pub fn unpause(&mut self,time:Time)->Result<(),Error>{ + match self.paused{ + true=>{ + let new_time=self.time(time); + self.state.set_time(time,new_time); + self.paused=false; + Ok(()) + }, + false=>Err(Error::AlreadyUnpaused), + } + } +} + +#[test] +fn test_timer()->Result<(),Error>{ + macro_rules! sec { + ($s: expr) => { + Time::from_secs($s) + }; + } + + //create a paused timer that reads 0s + let mut timer=Timer::realtime_paused(sec!(0)); + //the paused timer at 1 second should read 0s + assert_eq!(timer.time(sec!(1)),sec!(0)); + + //unpause it after one second + timer.unpause(sec!(1))?; + //the timer at 6 seconds should read 5s + assert_eq!(timer.time(sec!(6)),sec!(5)); + + //pause the timer after 11 seconds + timer.pause(sec!(11))?; + //the paused timer at 20 seconds should read 10s + assert_eq!(timer.time(sec!(20)),sec!(10)); + + Ok(()) +}