Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
6a12d213e8 | |||
4e4adcb934 |
@ -1,6 +1,5 @@
|
||||
pub mod bvh;
|
||||
pub mod map;
|
||||
pub mod run;
|
||||
pub mod aabb;
|
||||
pub mod model;
|
||||
pub mod timer;
|
||||
|
103
src/run.rs
103
src/run.rs
@ -1,103 +0,0 @@
|
||||
use crate::timer::{TimerFixed,Realtime,Paused,Unpaused};
|
||||
use crate::integer::Time;
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub enum FlagReason{
|
||||
Anticheat,
|
||||
StyleChange,
|
||||
Clock,
|
||||
Pause,
|
||||
Flying,
|
||||
Gravity,
|
||||
Timescale,
|
||||
TimeTravel,
|
||||
Teleport,
|
||||
}
|
||||
impl ToString for FlagReason{
|
||||
fn to_string(&self)->String{
|
||||
match self{
|
||||
FlagReason::Anticheat=>"Passed through anticheat zone.",
|
||||
FlagReason::StyleChange=>"Changed style.",
|
||||
FlagReason::Clock=>"Incorrect clock. (This can be caused by internet hiccups)",
|
||||
FlagReason::Pause=>"Pausing is not allowed in this style.",
|
||||
FlagReason::Flying=>"Flying is not allowed in this style.",
|
||||
FlagReason::Gravity=>"Gravity modification is not allowed in this style.",
|
||||
FlagReason::Timescale=>"Timescale is not allowed in this style.",
|
||||
FlagReason::TimeTravel=>"Time travel is not allowed in this style.",
|
||||
FlagReason::Teleport=>"Illegal teleport.",
|
||||
}.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
NotStarted,
|
||||
AlreadyStarted,
|
||||
AlreadyFinished,
|
||||
}
|
||||
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{}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
enum RunState{
|
||||
Created,
|
||||
Started{timer:TimerFixed<Realtime,Unpaused>},
|
||||
Finished{timer:TimerFixed<Realtime,Paused>},
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct Run{
|
||||
state:RunState,
|
||||
flagged:Option<FlagReason>,
|
||||
}
|
||||
|
||||
impl Run{
|
||||
pub fn new()->Self{
|
||||
Self{
|
||||
state:RunState::Created,
|
||||
flagged:None,
|
||||
}
|
||||
}
|
||||
pub fn time(&self,time:Time)->Time{
|
||||
match &self.state{
|
||||
RunState::Created=>Time::ZERO,
|
||||
RunState::Started{timer}=>timer.time(time),
|
||||
RunState::Finished{timer}=>timer.time(time),
|
||||
}
|
||||
}
|
||||
pub fn start(&mut self,time:Time)->Result<(),Error>{
|
||||
match &self.state{
|
||||
RunState::Created=>{
|
||||
self.state=RunState::Started{
|
||||
timer:TimerFixed::new(time,Time::ZERO),
|
||||
};
|
||||
Ok(())
|
||||
},
|
||||
RunState::Started{..}=>Err(Error::AlreadyStarted),
|
||||
RunState::Finished{..}=>Err(Error::AlreadyFinished),
|
||||
}
|
||||
}
|
||||
pub fn finish(&mut self,time:Time)->Result<(),Error>{
|
||||
//this uses Copy
|
||||
match &self.state{
|
||||
RunState::Created=>Err(Error::NotStarted),
|
||||
RunState::Started{timer}=>{
|
||||
self.state=RunState::Finished{
|
||||
timer:timer.into_paused(time),
|
||||
};
|
||||
Ok(())
|
||||
},
|
||||
RunState::Finished{..}=>Err(Error::AlreadyFinished),
|
||||
}
|
||||
}
|
||||
pub fn flag(&mut self,flag_reason:FlagReason){
|
||||
//don't replace the first reason the run was flagged
|
||||
if self.flagged.is_none(){
|
||||
self.flagged=Some(flag_reason);
|
||||
}
|
||||
}
|
||||
}
|
301
src/timer.rs
301
src/timer.rs
@ -1,35 +1,15 @@
|
||||
use crate::integer::{Time,Ratio64};
|
||||
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct Paused;
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct Unpaused;
|
||||
//this could be about half as long if I only had
|
||||
//scaled timers and just used a scale of 1
|
||||
//but I thought the concept of a timer that could
|
||||
//only be paused and not scaled was cool
|
||||
|
||||
pub trait PauseState:Copy+std::fmt::Debug{
|
||||
const IS_PAUSED:bool;
|
||||
fn new()->Self;
|
||||
}
|
||||
impl PauseState for Paused{
|
||||
const IS_PAUSED:bool=true;
|
||||
fn new()->Self{
|
||||
Self
|
||||
}
|
||||
}
|
||||
impl PauseState for Unpaused{
|
||||
const IS_PAUSED:bool=false;
|
||||
fn new()->Self{
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct Realtime{
|
||||
offset:Time,
|
||||
}
|
||||
impl Realtime{
|
||||
const fn new(offset:Time)->Self{
|
||||
Self{offset}
|
||||
}
|
||||
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)]
|
||||
@ -38,8 +18,8 @@ pub struct Scaled{
|
||||
offset:Time,
|
||||
}
|
||||
impl Scaled{
|
||||
const fn new(scale:Ratio64,offset:Time)->Self{
|
||||
Self{scale,offset}
|
||||
const fn identity()->Self{
|
||||
Self{scale:Ratio64::ONE,offset:Time::ZERO}
|
||||
}
|
||||
const fn with_scale(scale:Ratio64)->Self{
|
||||
Self{scale,offset:Time::ZERO}
|
||||
@ -56,35 +36,7 @@ impl Scaled{
|
||||
self.set_time(time,new_time);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TimerState:Copy+std::fmt::Debug{
|
||||
fn identity()->Self;
|
||||
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);
|
||||
}
|
||||
impl TimerState for Realtime{
|
||||
fn identity()->Self{
|
||||
Self{offset:Time::ZERO}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
impl TimerState for Scaled{
|
||||
fn identity()->Self{
|
||||
Self{scale:Ratio64::ONE,offset:Time::ZERO}
|
||||
}
|
||||
fn get_time(&self,time:Time)->Time{
|
||||
self.scale(time)+self.offset
|
||||
}
|
||||
@ -100,82 +52,48 @@ impl TimerState for Scaled{
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct TimerFixed<T:TimerState,P:PauseState>{
|
||||
pub struct Realtime{
|
||||
offset:Time,
|
||||
}
|
||||
impl Realtime{
|
||||
const fn identity()->Self{
|
||||
Self{offset:Time::ZERO}
|
||||
}
|
||||
}
|
||||
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<T>{
|
||||
state:T,
|
||||
_paused:P,
|
||||
paused:bool,
|
||||
}
|
||||
|
||||
//scaled timer methods are generic across PauseState
|
||||
impl<P:PauseState> TimerFixed<Scaled,P>{
|
||||
pub fn scaled(time:Time,new_time:Time,scale:Ratio64)->Self{
|
||||
impl Timer<Realtime>{
|
||||
pub fn realtime(time:Time,new_time:Time)->Self{
|
||||
let mut timer=Self{
|
||||
state:Scaled::with_scale(scale),
|
||||
_paused:P::new(),
|
||||
state:Realtime::identity(),
|
||||
paused:false,
|
||||
};
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
pub const fn get_scale(&self)->Ratio64{
|
||||
self.state.get_scale()
|
||||
}
|
||||
pub fn set_scale(&mut self,time:Time,new_scale:Ratio64){
|
||||
self.state.set_scale(time,new_scale)
|
||||
}
|
||||
}
|
||||
|
||||
//pause and unpause is generic across TimerState
|
||||
impl<T:TimerState> TimerFixed<T,Paused>{
|
||||
pub fn into_unpaused(self,time:Time)->TimerFixed<T,Unpaused>{
|
||||
let new_time=self.time(time);
|
||||
let mut timer=TimerFixed{
|
||||
state:self.state,
|
||||
_paused:Unpaused,
|
||||
};
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
}
|
||||
impl<T:TimerState> TimerFixed<T,Unpaused>{
|
||||
pub fn into_paused(self,time:Time)->TimerFixed<T,Paused>{
|
||||
let new_time=self.time(time);
|
||||
let mut timer=TimerFixed{
|
||||
state:self.state,
|
||||
_paused:Paused,
|
||||
};
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
}
|
||||
|
||||
//the new constructor and time queries are generic across both
|
||||
impl<T:TimerState,P:PauseState> TimerFixed<T,P>{
|
||||
pub fn new(time:Time,new_time:Time)->Self{
|
||||
let mut timer=Self{
|
||||
state:T::identity(),
|
||||
_paused:P::new(),
|
||||
};
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
pub fn from_state(state:T)->Self{
|
||||
pub fn realtime_paused(offset:Time)->Self{
|
||||
Self{
|
||||
state,
|
||||
_paused:P::new(),
|
||||
}
|
||||
}
|
||||
pub fn into_state(self)->T{
|
||||
self.state
|
||||
}
|
||||
pub fn time(&self,time:Time)->Time{
|
||||
match P::IS_PAUSED{
|
||||
true=>self.state.get_offset(),
|
||||
false=>self.state.get_time(time),
|
||||
}
|
||||
}
|
||||
pub fn set_time(&mut self,time:Time,new_time:Time){
|
||||
match P::IS_PAUSED{
|
||||
true=>self.state.set_offset(new_time),
|
||||
false=>self.state.set_time(time,new_time),
|
||||
state:Realtime{offset},
|
||||
paused:true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,88 +110,87 @@ impl std::fmt::Display for Error{
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
//wrapper type which holds type state internally
|
||||
#[derive(Clone,Debug)]
|
||||
pub enum Timer<T:TimerState>{
|
||||
Paused(TimerFixed<T,Paused>),
|
||||
Unpaused(TimerFixed<T,Unpaused>),
|
||||
}
|
||||
impl<T:TimerState> Timer<T>{
|
||||
pub fn from_state(state:T,paused:bool)->Self{
|
||||
match paused{
|
||||
true=>Self::Paused(TimerFixed::from_state(state)),
|
||||
false=>Self::Unpaused(TimerFixed::from_state(state)),
|
||||
}
|
||||
}
|
||||
pub fn into_state(self)->(T,bool){
|
||||
match self{
|
||||
Self::Paused(timer)=>(timer.into_state(),true),
|
||||
Self::Unpaused(timer)=>(timer.into_state(),false),
|
||||
}
|
||||
}
|
||||
pub fn paused(time:Time,new_time:Time)->Self{
|
||||
Self::Paused(TimerFixed::new(time,new_time))
|
||||
}
|
||||
pub fn unpaused(time:Time,new_time:Time)->Self{
|
||||
Self::Unpaused(TimerFixed::new(time,new_time))
|
||||
}
|
||||
pub fn time(&self,time:Time)->Time{
|
||||
match self{
|
||||
Self::Paused(timer)=>timer.time(time),
|
||||
Self::Unpaused(timer)=>timer.time(time),
|
||||
}
|
||||
}
|
||||
pub fn set_time(&mut self,time:Time,new_time:Time){
|
||||
match self{
|
||||
Self::Paused(timer)=>timer.set_time(time,new_time),
|
||||
Self::Unpaused(timer)=>timer.set_time(time,new_time),
|
||||
}
|
||||
}
|
||||
pub fn pause(&mut self,time:Time)->Result<(),Error>{
|
||||
*self=match *self{
|
||||
Self::Paused(_)=>return Err(Error::AlreadyPaused),
|
||||
Self::Unpaused(timer)=>Self::Paused(timer.into_paused(time)),
|
||||
impl Timer<Scaled>{
|
||||
pub fn new(time:Time,new_time:Time,scale:Ratio64,paused:bool)->Self{
|
||||
let mut timer=Self{
|
||||
state:Scaled::with_scale(scale),
|
||||
paused,
|
||||
};
|
||||
Ok(())
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
pub fn unpause(&mut self,time:Time)->Result<(),Error>{
|
||||
*self=match *self{
|
||||
Self::Paused(timer)=>Self::Unpaused(timer.into_unpaused(time)),
|
||||
Self::Unpaused(_)=>return Err(Error::AlreadyUnpaused),
|
||||
pub fn scaled(time:Time,new_time:Time,scale:Ratio64)->Self{
|
||||
let mut timer=Self{
|
||||
state:Scaled::with_scale(scale),
|
||||
paused:false,
|
||||
};
|
||||
Ok(())
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
pub fn scaled_paused(time:Time,new_time:Time,scale:Ratio64)->Self{
|
||||
let mut timer=Self{
|
||||
state:Scaled::with_scale(scale),
|
||||
paused:true,
|
||||
};
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
pub const fn get_scale(&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<T:TimerState> Timer<T>{
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod test{
|
||||
use super::{Time,Timer,TimerFixed,Error,Realtime,Scaled,Paused};
|
||||
use super::{Time,Timer,Error};
|
||||
macro_rules! sec {
|
||||
($s: expr) => {
|
||||
Time::from_secs($s)
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn test_timerfixed_scaled(){
|
||||
//create a paused timer that reads 0s
|
||||
let timer=TimerFixed::<Scaled,Paused>::new(sec!(0),sec!(0));
|
||||
//the paused timer at 1 second should read 0s
|
||||
assert_eq!(timer.time(sec!(1)),sec!(0));
|
||||
|
||||
//unpause it after one second
|
||||
let timer=timer.into_unpaused(sec!(1));
|
||||
//the timer at 6 seconds should read 5s
|
||||
assert_eq!(timer.time(sec!(6)),sec!(5));
|
||||
|
||||
//pause the timer after 11 seconds
|
||||
let timer=timer.into_paused(sec!(11));
|
||||
//the paused timer at 20 seconds should read 10s
|
||||
assert_eq!(timer.time(sec!(20)),sec!(10));
|
||||
}
|
||||
#[test]
|
||||
fn test_timer()->Result<(),Error>{
|
||||
//create a paused timer that reads 0s
|
||||
let mut timer=Timer::<Realtime>::paused(sec!(0),sec!(0));
|
||||
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));
|
||||
|
||||
|
Reference in New Issue
Block a user