diff --git a/strafe-client/src/physics_worker.rs b/strafe-client/src/physics_worker.rs index 084d164..3acc292 100644 --- a/strafe-client/src/physics_worker.rs +++ b/strafe-client/src/physics_worker.rs @@ -57,8 +57,9 @@ pub fn new<'a>( }, Instruction::Render=>{ run_session_instruction!(ins.time,SESSION_INSTRUCTION_IDLE); - let frame_state=session.get_frame_state(ins.time); - run_graphics_worker_instruction!(GraphicsInstruction::Render(frame_state)); + if let Some(frame_state)=session.get_frame_state(ins.time){ + run_graphics_worker_instruction!(GraphicsInstruction::Render(frame_state)); + } }, Instruction::Resize(physical_size)=>{ run_session_instruction!(ins.time,SESSION_INSTRUCTION_IDLE); diff --git a/strafe-client/src/session.rs b/strafe-client/src/session.rs index dc0b17a..137adbb 100644 --- a/strafe-client/src/session.rs +++ b/strafe-client/src/session.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use strafesnet_common::gameplay_modes::{ModeId,StageId}; use strafesnet_common::instruction::{InstructionConsumer,InstructionEmitter,InstructionFeedback,TimedInstruction}; // session represents the non-hardware state of the client. @@ -105,14 +107,27 @@ impl Replay{ } } +#[derive(Clone,Copy,Hash,PartialEq,Eq)] +struct BotId(u32); +//#[derive(Clone,Copy,Hash,PartialEq,Eq)] +//struct PlayerId(u32); + +enum ViewState{ + Play, + //Spectate(PlayerId), + Replay(BotId), +} + pub struct Session{ user_settings:UserSettings, mouse_interpolator:crate::mouse_interpolator::MouseInterpolator, + view_state:ViewState, //gui:GuiState simulation:Simulation, // below fields not included in lite session recording:Recording, - replays:Vec, + //players:HashMap, + replays:HashMap, } impl Session{ pub fn new( @@ -123,8 +138,9 @@ impl Session{ user_settings, mouse_interpolator:MouseInterpolator::new(), simulation, + view_state:ViewState::Play, recording:Default::default(), - replays:Vec::new(), + replays:HashMap::new(), } } fn clear_recording(&mut self){ @@ -133,8 +149,13 @@ impl Session{ 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 get_frame_state(&self,time:SessionTime)->Option{ + match &self.view_state{ + ViewState::Play=>Some(self.simulation.get_frame_state(time)), + ViewState::Replay(bot_id)=>self.replays.get(bot_id).map(|replay| + replay.simulation.get_frame_state(time) + ), + } } pub fn user_settings(&self)->&UserSettings{ &self.user_settings @@ -197,13 +218,37 @@ impl InstructionConsumer> for Session{ _=self.simulation.timer.set_paused(ins.time,paused); }, Instruction::Control(SessionControlInstruction::CopyRecordingIntoReplayAndSpectate)=>{ - todo!(); + // Bind: B + + // pause simulation + _=self.simulation.timer.set_paused(ins.time,true); + + // create recording + let mut recording=Recording::default(); + recording.instructions.extend(self.recording.instructions.iter().cloned()); + + // create timer starting at first instruction (or zero if the list is empty) + let timer=Timer::unpaused(ins.time,recording.instructions.first().map_or(PhysicsTime::ZERO,|ins|ins.time)); + + // create default physics state + let simulation=Simulation::new(timer,Default::default()); + + // invent a new bot id and insert the replay + let bot_id=BotId(self.replays.len() as u32); + self.replays.insert(bot_id,Replay::new( + recording, + simulation, + )); + + // begin spectate + self.view_state=ViewState::Replay(bot_id); }, Instruction::Control(SessionControlInstruction::StopSpectate)=>{ - todo!(); + _=self.simulation.timer.set_paused(ins.time,false); + self.view_state=ViewState::Play; }, Instruction::Playback(_)=>{ - todo!(); + println!("[session] todo: Playback instructions"); }, Instruction::ChangeMap(complete_map)=>{ self.clear_recording();