194 lines
7.3 KiB
Rust
194 lines
7.3 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>){
|
||
|
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,
|
||
|
},
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
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))));
|
||
|
},
|
||
|
};
|
||
|
// run all buffered instruction produced
|
||
|
self.process_exhaustive(ins.time);
|
||
|
}
|
||
|
}
|
||
|
impl InstructionConsumer<StepInstruction> for Session{
|
||
|
type TimeInner=SessionTimeInner;
|
||
|
fn process_instruction(&mut self,ins:TimedInstruction<StepInstruction,Self::TimeInner>){
|
||
|
// ins.time ignored???
|
||
|
let ins_retimed=TimedInstruction{
|
||
|
time:self.simulation.timer.time(ins.time),
|
||
|
instruction:ins.instruction,
|
||
|
};
|
||
|
if let Some(instruction)=self.mouse_interpolator.pop_buffered_instruction(ins_retimed){
|
||
|
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)
|
||
|
}
|
||
|
}
|