196 lines
7.4 KiB
Rust
196 lines
7.4 KiB
Rust
use strafesnet_common::gameplay_modes::{ModeId,StageId};
|
|
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::{
|
|
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,Instruction as MouseInterpolatorInstruction};
|
|
use crate::settings::UserSettings;
|
|
|
|
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,
|
|
pub time:PhysicsTime,
|
|
}
|
|
|
|
pub struct Simulation{
|
|
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
|
|
physics:crate::physics::PhysicsContext,
|
|
}
|
|
impl Simulation{
|
|
pub const fn new(
|
|
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
|
|
physics:crate::physics::PhysicsContext,
|
|
)->Self{
|
|
Self{
|
|
timer,
|
|
physics,
|
|
}
|
|
}
|
|
pub fn get_frame_state(&self,time:SessionTime)->FrameState{
|
|
FrameState{
|
|
body:self.physics.camera_body(),
|
|
camera:self.physics.camera(),
|
|
time:self.timer.time(time),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Replay{
|
|
last_instruction_id:usize,
|
|
instructions:Vec<PhysicsInputInstruction>,
|
|
simulation:Simulation,
|
|
}
|
|
impl Replay{
|
|
pub const fn new(
|
|
instructions:Vec<PhysicsInputInstruction>,
|
|
simulation:Simulation,
|
|
)->Self{
|
|
Self{
|
|
last_instruction_id:0,
|
|
instructions,
|
|
simulation,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Session{
|
|
user_settings:UserSettings,
|
|
mouse_interpolator:crate::mouse_interpolator::MouseInterpolator,
|
|
//gui:GuiState
|
|
simulation:Simulation,
|
|
replays:Vec<Replay>,
|
|
}
|
|
impl Session{
|
|
pub fn new(
|
|
user_settings:UserSettings,
|
|
simulation:Simulation,
|
|
)->Self{
|
|
Self{
|
|
user_settings,
|
|
mouse_interpolator:MouseInterpolator::new(),
|
|
simulation,
|
|
replays:Vec::new(),
|
|
}
|
|
}
|
|
fn change_map(&mut self,map:&strafesnet_common::map::CompleteMap){
|
|
self.simulation.physics.generate_models(map);
|
|
}
|
|
pub fn get_frame_state(&self,time:SessionTime)->FrameState{
|
|
self.simulation.get_frame_state(time)
|
|
}
|
|
pub fn user_settings(&self)->&UserSettings{
|
|
&self.user_settings
|
|
}
|
|
}
|
|
|
|
// mouseinterpolator consumes RawInputInstruction
|
|
// mouseinterpolator emits PhysicsInputInstruction
|
|
// mouseinterpolator consumes DoStep to move on to the next emitted instruction
|
|
// Session comsumes SessionInstruction -> forwards RawInputInstruction to mouseinterpolator
|
|
// Session consumes DoStep -> forwards DoStep to mouseinterpolator
|
|
// Session emits DoStep
|
|
|
|
impl InstructionConsumer<Instruction<'_>> for Session{
|
|
type TimeInner=SessionTimeInner;
|
|
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,Self::TimeInner>){
|
|
// repetitive procedure macro
|
|
macro_rules! run_mouse_interpolator_instruction{
|
|
($instruction:expr)=>{
|
|
self.mouse_interpolator.process_instruction(TimedInstruction{
|
|
time:ins.time,
|
|
instruction:TimedInstruction{
|
|
time:self.simulation.timer.time(ins.time),
|
|
instruction:$instruction,
|
|
},
|
|
});
|
|
};
|
|
}
|
|
|
|
// process any timeouts that occured since the last instruction
|
|
self.process_exhaustive(ins.time);
|
|
|
|
match ins.instruction{
|
|
// send it down to MouseInterpolator with two timestamps, SessionTime and PhysicsTime
|
|
Instruction::Input(SessionInputInstruction::Mouse(pos))=>{
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::MoveMouse(pos));
|
|
},
|
|
Instruction::Input(SessionInputInstruction::SetControl(set_control_instruction))=>{
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::SetControl(set_control_instruction)));
|
|
},
|
|
Instruction::Input(SessionInputInstruction::Mode(ImplicitModeInstruction::ResetAndRestart))=>{
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Reset)));
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(self.user_settings().calculate_sensitivity()))));
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Restart)));
|
|
},
|
|
Instruction::Input(SessionInputInstruction::Mode(ImplicitModeInstruction::ResetAndSpawn(mode_id,spawn_id)))=>{
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Reset)));
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(self.user_settings().calculate_sensitivity()))));
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Spawn(mode_id,spawn_id))));
|
|
},
|
|
Instruction::Input(SessionInputInstruction::Other(other_other_instruction))=>{
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Other(other_other_instruction)));
|
|
},
|
|
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);
|
|
}
|
|
Instruction::ChangeMap(complete_map)=>{
|
|
self.change_map(complete_map);
|
|
// ResetAndSpawn
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Reset)));
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(self.user_settings().calculate_sensitivity()))));
|
|
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Spawn(ModeId::MAIN,StageId::FIRST))));
|
|
},
|
|
};
|
|
|
|
// process all emitted output instructions
|
|
self.process_exhaustive(ins.time);
|
|
}
|
|
}
|
|
impl InstructionConsumer<StepInstruction> for Session{
|
|
type TimeInner=SessionTimeInner;
|
|
fn process_instruction(&mut self,ins:TimedInstruction<StepInstruction,Self::TimeInner>){
|
|
let time=self.simulation.timer.time(ins.time);
|
|
if let Some(instruction)=self.mouse_interpolator.pop_buffered_instruction(ins.set_time(time)){
|
|
self.simulation.physics.run_input_instruction(instruction);
|
|
}
|
|
}
|
|
}
|
|
impl InstructionEmitter<StepInstruction> for Session{
|
|
type TimeInner=SessionTimeInner;
|
|
fn next_instruction(&self,time_limit:SessionTime)->Option<TimedInstruction<StepInstruction,Self::TimeInner>>{
|
|
self.mouse_interpolator.next_instruction(time_limit)
|
|
}
|
|
}
|