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>, physics:crate::physics::PhysicsContext, } impl Simulation{ pub const fn new( timer:Timer>, 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, simulation:Simulation, } impl Replay{ pub const fn new( instructions:Vec, 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, } 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> for Session{ type TimeInner=SessionTimeInner; fn process_instruction(&mut self,ins:TimedInstruction){ // 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 for Session{ type TimeInner=SessionTimeInner; fn process_instruction(&mut self,ins:TimedInstruction){ 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 for Session{ type TimeInner=SessionTimeInner; fn next_instruction(&self,time_limit:SessionTime)->Option>{ self.mouse_interpolator.next_instruction(time_limit) } }