this is very cool but it won't work because mouse timestamps will be identical while paused

This commit is contained in:
Quaternions 2023-10-10 15:30:49 -07:00
parent ad862ae8c9
commit 64e1e762a1
2 changed files with 95 additions and 8 deletions

View File

@ -42,6 +42,7 @@ pub enum InputInstruction {
Jump(bool),
Zoom(bool),
Reset,
SetPaused(bool),
Idle,
//Idle: there were no input events, but the simulation is safe to advance to this timestep
//for interpolation / networking / playback reasons, most playback heads will always want
@ -453,6 +454,7 @@ impl PhysicsState {
pub fn into_worker(mut self)->crate::worker::CompatWorker<TimedInstruction<InputInstruction>,PhysicsOutputState,Box<dyn FnMut(TimedInstruction<InputInstruction>)->PhysicsOutputState>>{
let mut mouse_blocking=true;
let mut last_mouse_time=self.next_mouse.time;
let mut simulation_timer=crate::timers::UnscaledTimer::unpaused();
let mut timeline=std::collections::VecDeque::new();
crate::worker::CompatWorker::new(self.output(),Box::new(move |ins:TimedInstruction<InputInstruction>|{
if if let Some(phys_input)=match ins.instruction{
@ -460,17 +462,17 @@ impl PhysicsState {
if mouse_blocking{
//tell the game state which is living in the past about its future
timeline.push_front(TimedInstruction{
time:last_mouse_time,
time:simulation_timer.time(last_mouse_time),
instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:m}),
});
}else{
//mouse has just started moving again after being still for longer than 10ms.
//replace the entire mouse interpolation state to avoid an intermediate state with identical m0.t m1.t timestamps which will divide by zero
timeline.push_front(TimedInstruction{
time:last_mouse_time,
time:simulation_timer.time(last_mouse_time),
instruction:PhysicsInputInstruction::ReplaceMouse(
MouseState{time:last_mouse_time,pos:self.next_mouse.pos},
MouseState{time:ins.time,pos:m}
MouseState{time:simulation_timer.time(last_mouse_time),pos:self.next_mouse.pos},
MouseState{time:simulation_timer.time(ins.time),pos:m}
),
});
//delay physics execution until we have an interpolation target
@ -479,6 +481,14 @@ impl PhysicsState {
last_mouse_time=ins.time;
None
},
InputInstruction::SetPaused(s)=>{
if s{
simulation_timer.pause(ins.time);
}else{
simulation_timer.unpause(ins.time);
}
Some(PhysicsInputInstruction::Idle)
}
InputInstruction::MoveForward(s)=>Some(PhysicsInputInstruction::SetMoveForward(s)),
InputInstruction::MoveLeft(s)=>Some(PhysicsInputInstruction::SetMoveLeft(s)),
InputInstruction::MoveBack(s)=>Some(PhysicsInputInstruction::SetMoveBack(s)),
@ -492,7 +502,7 @@ impl PhysicsState {
}{
//non-mouse event
timeline.push_back(TimedInstruction{
time:ins.time,
time:simulation_timer.time(ins.time),
instruction:phys_input,
});
@ -504,7 +514,7 @@ impl PhysicsState {
if 10_000_000<ins.time-self.next_mouse.time{
//push an event to extrapolate no movement from
timeline.push_front(TimedInstruction{
time:last_mouse_time,
time:simulation_timer.time(last_mouse_time),
instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:self.next_mouse.pos}),
});
last_mouse_time=ins.time;
@ -526,9 +536,10 @@ impl PhysicsState {
}{
//empty queue
while let Some(instruction)=timeline.pop_front(){
self.run(instruction.time);
let simulation_time=simulation_timer.time(instruction.time);
self.run(simulation_time);
self.process_instruction(TimedInstruction{
time:instruction.time,
time:simulation_time,
instruction:PhysicsInstruction::Input(instruction.instruction),
});
}

View File

@ -1,13 +1,18 @@
type TIME=crate::physics::TIME;
#[derive(Clone)]
pub struct Timescale{
num:i64,
den:std::num::NonZeroU64,
}
#[derive(Clone)]
pub struct Paused{}
#[derive(Clone)]
pub struct Unpaused{}
#[derive(Clone)]
pub struct PausedScaled{scale:Timescale}
#[derive(Clone)]
pub struct UnpausedScaled{scale:Timescale}
pub trait TimerState{}
@ -32,10 +37,81 @@ pub trait IsUnscaled{}
impl IsUnscaled for Paused{}
impl IsUnscaled for Unpaused{}
//scaled timer wrapper
enum Scaled{
Paused(Timer<PausedScaled>),
Unpaused(Timer<UnpausedScaled>),
}
pub struct ScaledTimer{
timer:Scaled,
}
impl ScaledTimer{
pub fn unpaused()->Self{
Self{
timer:Scaled::Unpaused(unpaused_scaled(Timescale{num:1,den:std::num::NonZeroU64::new(1).unwrap()}))
}
}
pub fn time(&self,time:TIME)->TIME{
match &self.timer{
Scaled::Paused(timer)=>timer.time(),
Scaled::Unpaused(timer)=>timer.time(time),
}
}
pub fn pause(&mut self,time:TIME){
match &self.timer{
Scaled::Paused(_)=>(),
Scaled::Unpaused(timer)=>self.timer=Scaled::Paused(timer.clone().pause(time)),
};
}
pub fn unpause(&mut self,time:TIME){
match &self.timer{
Scaled::Paused(timer)=>self.timer=Scaled::Unpaused(timer.clone().unpause(time)),
Scaled::Unpaused(_)=>(),
};
}
}
//unscaled timer wrapper
enum Unscaled{
Paused(Timer<Paused>),
Unpaused(Timer<Unpaused>),
}
pub struct UnscaledTimer{
timer:Unscaled,
}
impl UnscaledTimer{
pub fn unpaused()->Self{
Self{
timer:Unscaled::Unpaused(unpaused())
}
}
pub fn time(&self,time:TIME)->TIME{
match &self.timer{
Unscaled::Paused(timer)=>timer.time(),
Unscaled::Unpaused(timer)=>timer.time(time),
}
}
pub fn pause(&mut self,time:TIME){
match &self.timer{
Unscaled::Paused(_)=>(),
Unscaled::Unpaused(timer)=>self.timer=Unscaled::Paused(timer.clone().pause(time)),
};
}
pub fn unpause(&mut self,time:TIME){
match &self.timer{
Unscaled::Paused(timer)=>self.timer=Unscaled::Unpaused(timer.clone().unpause(time)),
Unscaled::Unpaused(_)=>(),
};
}
}
#[derive(Clone)]
pub struct Timer<State:TimerState>{
offset:crate::physics::TIME,
state:State,
}
fn get_offset(time:TIME,write_time:TIME)->TIME{
write_time-time
}