rewrite enums again

This commit is contained in:
Quaternions 2025-01-14 20:44:17 -08:00
parent 08bd57ffe1
commit a6a242175b
7 changed files with 117 additions and 59 deletions

View File

@ -4,17 +4,20 @@ use crate::mouse::MouseState;
pub enum TimeInner{}
pub type Time=crate::integer::Time<TimeInner>;
#[derive(Clone,Debug)]
pub enum UnbufferedInstruction{
MoveMouse(glam::IVec2),
Other(OtherInstruction),
}
#[derive(Clone,Debug)]
pub enum Instruction{
Mouse(MouseInstruction),
Other(OtherInstruction),
}
impl Instruction{
pub const IDLE:Self=Self::Other(OtherInstruction::Other(OtherOtherInstruction::Idle));
}
#[derive(Clone,Debug)]
pub enum OtherInstruction{
SetControl(SetControlInstruction),
Mode(ModeInstruction),
Other(OtherOtherInstruction),
}
#[derive(Clone,Debug)]
pub enum MouseInstruction{
/// Replace the entire interpolation state to avoid dividing by zero when replacing twice
@ -25,7 +28,7 @@ pub enum MouseInstruction{
SetNextMouse(MouseState<TimeInner>),
}
#[derive(Clone,Debug)]
pub enum OtherInstruction{
pub enum SetControlInstruction{
SetMoveRight(bool),
SetMoveUp(bool),
SetMoveBack(bool),
@ -34,6 +37,9 @@ pub enum OtherInstruction{
SetMoveForward(bool),
SetJump(bool),
SetZoom(bool),
}
#[derive(Clone,Debug)]
pub enum ModeInstruction{
/// Reset: fully replace the physics state.
/// This forgets all inputs and settings which need to be reapplied.
Reset,
@ -42,10 +48,11 @@ pub enum OtherInstruction{
/// Spawn: Teleport to a specific mode's spawn
/// Sets current mode & spawn
Spawn(crate::gameplay_modes::ModeId,crate::gameplay_modes::StageId),
}
#[derive(Clone,Debug)]
pub enum OtherOtherInstruction{
/// Idle: there were no input events, but the simulation is safe to advance to this timestep
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
//to be 1 instruction ahead to generate the next state for interpolation.
PracticeFly,
SetSensitivity(crate::integer::Ratio64Vec2),
}

View File

@ -1,6 +1,5 @@
use strafesnet_common::mouse::MouseState;
use strafesnet_common::physics::{
UnbufferedInstruction as PhysicsUnbufferedInstruction,
Instruction as PhysicsInputInstruction,
Time as PhysicsTime,
TimeInner as PhysicsTimeInner,
@ -11,11 +10,18 @@ use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInn
use strafesnet_common::instruction::{InstructionConsumer,InstructionEmitter,TimedInstruction};
type TimedPhysicsInstruction=TimedInstruction<PhysicsInputInstruction,PhysicsTimeInner>;
type PhysicsTimedUnbufferedInstruction=TimedInstruction<PhysicsUnbufferedInstruction,PhysicsTimeInner>;
type DoubleTimedUnbufferedInstruction=TimedInstruction<PhysicsTimedUnbufferedInstruction,SessionTimeInner>;
type TimedUnbufferedInstruction=TimedInstruction<Instruction,PhysicsTimeInner>;
type DoubleTimedUnbufferedInstruction=TimedInstruction<TimedUnbufferedInstruction,SessionTimeInner>;
const MOUSE_TIMEOUT:SessionTime=SessionTime::from_millis(10);
/// To be fed into MouseInterpolator
#[derive(Clone,Debug)]
pub enum Instruction{
MoveMouse(glam::IVec2),
Other(OtherInstruction),
}
pub enum StepInstruction{
Pop,
Timeout,
@ -35,7 +41,7 @@ pub struct MouseInterpolator{
}
// Maybe MouseInterpolator manipulation is better expressed using impls
// and called from Instruction trait impls in session
impl InstructionConsumer<PhysicsTimedUnbufferedInstruction> for MouseInterpolator{
impl InstructionConsumer<TimedUnbufferedInstruction> for MouseInterpolator{
type TimeInner=SessionTimeInner;
fn process_instruction(&mut self,ins:DoubleTimedUnbufferedInstruction){
self.push_unbuffered_input(ins)
@ -69,7 +75,7 @@ impl MouseInterpolator{
let (ins_mouse,ins_other)=replace_with::replace_with_or_abort_and_return(&mut self.buffer_state,|buffer_state|{
let next_state=match buffer_state{
BufferState::Unbuffered=>{
if let PhysicsUnbufferedInstruction::MoveMouse(pos)=ins.instruction.instruction{
if let Instruction::MoveMouse(pos)=ins.instruction.instruction{
return ((None,None),BufferState::Initializing(ins.time,MouseState{pos,time:ins.instruction.time}));
}
BufferState::Unbuffered
@ -87,7 +93,7 @@ impl MouseInterpolator{
};
return ((Some(ins_mouse),None),BufferState::Unbuffered);
}
if let PhysicsUnbufferedInstruction::MoveMouse(pos)=ins.instruction.instruction{
if let Instruction::MoveMouse(pos)=ins.instruction.instruction{
let next_mouse_state=MouseState{pos,time:ins.instruction.time};
let ins_mouse=TimedInstruction{
time:mouse_state.time,
@ -114,7 +120,7 @@ impl MouseInterpolator{
};
return ((Some(ins_mouse),None),BufferState::Unbuffered);
}
if let PhysicsUnbufferedInstruction::MoveMouse(pos)=ins.instruction.instruction{
if let Instruction::MoveMouse(pos)=ins.instruction.instruction{
let next_mouse_state=MouseState{pos,time:ins.instruction.time};
let ins_mouse=TimedInstruction{
time:ins.instruction.time,
@ -126,8 +132,8 @@ impl MouseInterpolator{
},
};
let ins_other=match ins.instruction.instruction{
PhysicsUnbufferedInstruction::MoveMouse(_)=>None,
PhysicsUnbufferedInstruction::Other(other_instruction)=>Some(TimedInstruction{
Instruction::MoveMouse(_)=>None,
Instruction::Other(other_instruction)=>Some(TimedInstruction{
time:ins.instruction.time,
instruction:other_instruction,
}),
@ -208,6 +214,7 @@ impl MouseInterpolator{
// This should be simulation_timer.time(timeout)
// but the timer is not accessible from this scope
// and it's just here to say that the mouse isn't moving anyways.
// I think this is a divide by zero bug, two identical mouse_states will occupy the interpolation state
time:mouse_state.time,
instruction:PhysicsInputInstruction::Mouse(
MouseInstruction::SetNextMouse(mouse_state)

View File

@ -884,9 +884,7 @@ impl PhysicsState{
self.touching.clear();
}
fn reset_to_default(&mut self){
let mut new_state=Self::default();
new_state.camera.sensitivity=self.camera.sensitivity;
*self=new_state;
*self=Self::default();
}
fn next_move_instruction(&self)->Option<TimedInstruction<PhysicsInternalInstruction,TimeInner>>{
self.move_state.next_move_instruction(&self.style.strafe,self.time)
@ -1837,6 +1835,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
state.set_move_state(data,MoveState::Air);
b_refresh_walk_target=false;
}
// Spawn does not necessarily imply reset
PhysicsInputInstruction::Other(PhysicsOtherInstruction::Spawn(mode_id,stage_id))=>{
//spawn at a particular stage
if let Some(mode)=data.modes.get_mode(mode_id){

View File

@ -1,19 +1,19 @@
use crate::graphics_worker::Instruction as GraphicsInstruction;
use crate::session::{ExternalInstruction as SessionInstruction,Session, Simulation};
use crate::session::{SessionInputInstruction,Instruction as SessionInstruction,Session,Simulation};
use strafesnet_common::instruction::{TimedInstruction,InstructionConsumer};
use strafesnet_common::physics::Time as PhysicsTime;
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
use strafesnet_common::timer::Timer;
pub enum Instruction{
Input(strafesnet_common::physics::UnbufferedInstruction),
Input(SessionInputInstruction),
SetPaused(bool),
Render,
Resize(winit::dpi::PhysicalSize<u32>),
ChangeMap(strafesnet_common::map::CompleteMap),
}
const SESSION_INSTRUCTION_IDLE:SessionInstruction=SessionInstruction::Input(strafesnet_common::physics::UnbufferedInstruction::Other(strafesnet_common::physics::OtherInstruction::Idle));
const SESSION_INSTRUCTION_IDLE:SessionInstruction=SessionInstruction::Input(SessionInputInstruction::Other(strafesnet_common::physics::OtherOtherInstruction::Idle));
pub fn new<'a>(
mut graphics_worker:crate::compat_worker::INWorker<'a,crate::graphics_worker::Instruction>,

View File

@ -1,20 +1,39 @@
use strafesnet_common::instruction::{InstructionConsumer,InstructionEmitter,InstructionFeedback,TimedInstruction};
// session represents the non-hardware state of the client.
// Ideally it is a deterministic state which is atomically updated by instructions, same as the simulation state.
use strafesnet_common::physics::{UnbufferedInstruction as PhysicsUnbufferedInstruction,Instruction as PhysicsInputInstruction,TimeInner as PhysicsTimeInner,Time as PhysicsTime};
use strafesnet_common::physics::{
ModeInstruction,OtherInstruction,OtherOtherInstruction,
Instruction as PhysicsInputInstruction,
TimeInner as PhysicsTimeInner,
Time as PhysicsTime
};
use strafesnet_common::timer::{Scaled,Timer};
use strafesnet_common::session::{TimeInner as SessionTimeInner,Time as SessionTime};
use crate::mouse_interpolator::{MouseInterpolator,StepInstruction};
use crate::mouse_interpolator::{MouseInterpolator,StepInstruction,Instruction as MouseInterpolatorInstruction};
use crate::settings::UserSettings;
pub enum ExternalInstruction<'a>{
Input(PhysicsUnbufferedInstruction),
pub enum Instruction<'a>{
Input(SessionInputInstruction),
SetPaused(bool),
ChangeMap(&'a strafesnet_common::map::CompleteMap),
//Graphics(crate::graphics_worker::Instruction),
}
pub enum SessionInputInstruction{
Mouse(glam::IVec2),
SetControl(strafesnet_common::physics::SetControlInstruction),
Mode(ImplicitModeInstruction),
Other(strafesnet_common::physics::OtherOtherInstruction),
}
/// Implicit mode instruction are fed separately to session.
/// Session generates the explicit mode instructions interlaced with a SetSensitivity instruction
#[derive(Clone,Debug)]
pub enum ImplicitModeInstruction{
ResetAndRestart,
ResetAndSpawn(strafesnet_common::gameplay_modes::ModeId,strafesnet_common::gameplay_modes::StageId),
}
pub struct FrameState{
pub body:crate::physics::Body,
pub camera:crate::physics::PhysicsCamera,
@ -99,25 +118,50 @@ impl Session{
// Session consumes DoStep -> forwards DoStep to mouseinterpolator
// Session emits DoStep
impl InstructionConsumer<ExternalInstruction<'_>> for Session{
impl InstructionConsumer<Instruction<'_>> for Session{
type TimeInner=SessionTimeInner;
fn process_instruction(&mut self,ins:TimedInstruction<ExternalInstruction,Self::TimeInner>){
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,Self::TimeInner>){
match ins.instruction{
// send it down to MouseInterpolator with two timestamps, SessionTime and PhysicsTime
ExternalInstruction::Input(instruction)=>self.mouse_interpolator.process_instruction(TimedInstruction{
time:ins.time,
instruction:TimedInstruction{
time:self.simulation.timer.time(ins.time),
instruction,
},
}),
ExternalInstruction::SetPaused(paused)=>{
Instruction::Input(instruction)=>{
let instructions:&[MouseInterpolatorInstruction]=match instruction{
SessionInputInstruction::Mouse(pos)=>&[
MouseInterpolatorInstruction::MoveMouse(pos)
],
SessionInputInstruction::SetControl(set_control_instruction)=>&[
MouseInterpolatorInstruction::Other(OtherInstruction::SetControl(set_control_instruction))
],
SessionInputInstruction::Mode(ImplicitModeInstruction::ResetAndRestart)=>&[
MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Reset)),
MouseInterpolatorInstruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(self.user_settings().calculate_sensitivity()))),
MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Restart)),
],
SessionInputInstruction::Mode(ImplicitModeInstruction::ResetAndSpawn(mode_id,spawn_id))=>&[
MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Reset)),
MouseInterpolatorInstruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(self.user_settings().calculate_sensitivity()))),
MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Spawn(mode_id,spawn_id))),
],
SessionInputInstruction::Other(other_other_instruction)=>&[
MouseInterpolatorInstruction::Other(OtherInstruction::Other(other_other_instruction))
],
};
for ins_interpolator in (*instructions).into_iter(){
self.mouse_interpolator.process_instruction(TimedInstruction{
time:ins.time,
instruction:TimedInstruction{
time:self.simulation.timer.time(ins.time),
instruction:ins_interpolator,
},
});
}
},
Instruction::SetPaused(paused)=>{
// don't flush the buffered instructions in the mouse interpolator
// until the mouse is confirmed to be not moving at a later time
// what if they pause for 5ms lmao
_=self.simulation.timer.set_paused(ins.time,paused);
}
ExternalInstruction::ChangeMap(complete_map)=>self.change_map(complete_map),
Instruction::ChangeMap(complete_map)=>self.change_map(complete_map),
};
// run all buffered instruction produced
self.process_exhaustive(ins.time);

View File

@ -1,7 +1,8 @@
use strafesnet_common::instruction::TimedInstruction;
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
use strafesnet_common::physics::{OtherInstruction,UnbufferedInstruction};
use strafesnet_common::physics::{OtherInstruction,OtherOtherInstruction,SetControlInstruction};
use crate::physics_worker::Instruction as PhysicsWorkerInstruction;
use crate::session::SessionInputInstruction;
pub enum Instruction{
Resize(winit::dpi::PhysicalSize<u32>),
@ -91,29 +92,29 @@ impl WindowContext<'_>{
},
(keycode,state)=>{
let s=state.is_pressed();
if let Some(input_instruction)=match keycode{
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Space)=>Some(OtherInstruction::SetJump(s)),
if let Some(session_input_instruction)=match keycode{
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Space)=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetJump(s))),
winit::keyboard::Key::Character(key)=>match key.as_str(){
"W"|"w"=>Some(OtherInstruction::SetMoveForward(s)),
"A"|"a"=>Some(OtherInstruction::SetMoveLeft(s)),
"S"|"s"=>Some(OtherInstruction::SetMoveBack(s)),
"D"|"d"=>Some(OtherInstruction::SetMoveRight(s)),
"E"|"e"=>Some(OtherInstruction::SetMoveUp(s)),
"Q"|"q"=>Some(OtherInstruction::SetMoveDown(s)),
"Z"|"z"=>Some(OtherInstruction::SetZoom(s)),
"R"|"r"=>if s{
"W"|"w"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveForward(s))),
"A"|"a"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveLeft(s))),
"S"|"s"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveBack(s))),
"D"|"d"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveRight(s))),
"E"|"e"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveUp(s))),
"Q"|"q"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveDown(s))),
"Z"|"z"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetZoom(s))),
"R"|"r"=>s.then(||{
//mouse needs to be reset since the position is absolute
self.mouse_pos=glam::DVec2::ZERO;
Some(OtherInstruction::ResetAndRestart)
}else{None},
"F"|"f"=>if s{Some(OtherInstruction::PracticeFly)}else{None},
SessionInputInstruction::Mode(crate::session::ImplicitModeInstruction::ResetAndRestart)
}),
"F"|"f"=>s.then_some(SessionInputInstruction::Other(OtherOtherInstruction::PracticeFly)),
_=>None,
},
_=>None,
}{
self.physics_thread.send(TimedInstruction{
time,
instruction:PhysicsWorkerInstruction::Input(UnbufferedInstruction::Other(input_instruction)),
instruction:PhysicsWorkerInstruction::Input(session_input_instruction),
}).unwrap();
}
},
@ -137,7 +138,7 @@ impl WindowContext<'_>{
self.mouse_pos+=glam::dvec2(delta.0,delta.1);
self.physics_thread.send(TimedInstruction{
time,
instruction:PhysicsWorkerInstruction::Input(UnbufferedInstruction::MoveMouse(self.mouse_pos.as_ivec2())),
instruction:PhysicsWorkerInstruction::Input(SessionInputInstruction::Mouse(self.mouse_pos.as_ivec2())),
}).unwrap();
},
winit::event::DeviceEvent::MouseWheel {
@ -147,7 +148,7 @@ impl WindowContext<'_>{
if false{//self.physics.style.use_scroll{
self.physics_thread.send(TimedInstruction{
time,
instruction:PhysicsWorkerInstruction::Input(UnbufferedInstruction::Other(OtherInstruction::SetJump(true))),//activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump
instruction:PhysicsWorkerInstruction::Input(SessionInputInstruction::SetControl(SetControlInstruction::SetJump(true))),//activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump
}).unwrap();
}
},

View File

@ -190,7 +190,7 @@ mod test{
for _ in 0..5 {
let task = instruction::TimedInstruction{
time:strafesnet_common::physics::Time::ZERO,
instruction:strafesnet_common::physics::Instruction::Other(strafesnet_common::physics::OtherInstruction::Idle),
instruction:strafesnet_common::physics::Instruction::IDLE,
};
worker.send(task).unwrap();
}
@ -204,7 +204,7 @@ mod test{
// Send a new task
let task = instruction::TimedInstruction{
time:integer::Time::ZERO,
instruction:strafesnet_common::physics::Instruction::Other(strafesnet_common::physics::OtherInstruction::Idle),
instruction:strafesnet_common::physics::Instruction::IDLE,
};
worker.send(task).unwrap();