diff --git a/src/graphics_worker.rs b/src/graphics_worker.rs index 3ece5ea..6bf207b 100644 --- a/src/graphics_worker.rs +++ b/src/graphics_worker.rs @@ -4,8 +4,7 @@ pub enum Instruction{ Render(crate::physics::PhysicsOutputState,integer::Time,glam::IVec2), //UpdateModel(crate::graphics::GraphicsModelUpdate), Resize(winit::dpi::PhysicalSize,crate::settings::UserSettings), - GenerateModels(strafesnet_common::map::CompleteMap), - ClearModels, + ChangeMap(strafesnet_common::map::CompleteMap), } //Ideally the graphics thread worker description is: @@ -27,11 +26,9 @@ pub fn new<'a>( let mut resize=None; crate::compat_worker::INWorker::new(move |ins:Instruction|{ match ins{ - Instruction::GenerateModels(map)=>{ - graphics.generate_models(&device,&queue,&map); - }, - Instruction::ClearModels=>{ + Instruction::ChangeMap(map)=>{ graphics.clear(); + graphics.generate_models(&device,&queue,&map); }, Instruction::Resize(size,user_settings)=>{ resize=Some((size,user_settings)); @@ -69,4 +66,4 @@ pub fn new<'a>( } } }) -} \ No newline at end of file +} diff --git a/src/physics.rs b/src/physics.rs index 09f0ad0..6658c1b 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -5,6 +5,7 @@ use strafesnet_common::map; use strafesnet_common::run; use strafesnet_common::aabb; use strafesnet_common::model::{MeshId,ModelId}; +use strafesnet_common::mouse::MouseState; use strafesnet_common::gameplay_attributes::{self,CollisionAttributesId}; use strafesnet_common::gameplay_modes::{self,StageId}; use strafesnet_common::gameplay_style::{self,StyleModifiers}; @@ -1008,25 +1009,6 @@ impl PhysicsContext{ pub fn clear(&mut self){ self.state.clear(); } - //TODO: remove non-standard interfaces to process_instruction - pub fn load_user_settings(&mut self,user_settings:&crate::settings::UserSettings){ - self.run_input_instruction(TimedInstruction{ - time:self.state.time, - instruction:PhysicsInputInstruction::SetSensitivity(user_settings.calculate_sensitivity()), - }); - } - pub fn restart(&mut self){ - self.run_input_instruction(TimedInstruction{ - time:self.state.time, - instruction:PhysicsInputInstruction::Restart, - }); - } - pub fn spawn(&mut self){ - self.run_input_instruction(TimedInstruction{ - time:self.state.time, - instruction:PhysicsInputInstruction::Spawn(gameplay_modes::ModeId::MAIN,StageId::FIRST), - }); - } pub const fn output(&self)->PhysicsOutputState{ PhysicsOutputState{ body:self.state.body, @@ -1038,7 +1020,7 @@ impl PhysicsContext{ pub const fn get_next_mouse(&self)->&MouseState{ self.state.input_state.get_next_mouse() } - pub fn generate_models(&mut self,map:&map::CompleteMap){ + fn generate_models(&mut self,map:&map::CompleteMap){ self.data.modes=map.modes.clone(); for mode in &mut self.data.modes.modes{ mode.denormalize_data(); diff --git a/src/physics_worker.rs b/src/physics_worker.rs index 11117f2..de12a03 100644 --- a/src/physics_worker.rs +++ b/src/physics_worker.rs @@ -1,7 +1,9 @@ -use crate::physics::{MouseState,PhysicsInputInstruction}; +use strafesnet_common::mouse::MouseState; +use strafesnet_common::physics::Instruction as PhysicsInputInstruction; use strafesnet_common::integer::Time; use strafesnet_common::instruction::TimedInstruction; use strafesnet_common::timer::{Scaled,Timer,TimerState}; +use mouse_interpolator::MouseInterpolator; #[derive(Debug)] pub enum InputInstruction{ @@ -22,19 +24,34 @@ pub enum Instruction{ Input(InputInstruction), Render, Resize(winit::dpi::PhysicalSize,crate::settings::UserSettings), - GenerateModels(strafesnet_common::map::CompleteMap), - ClearModels, + ChangeMap(strafesnet_common::map::CompleteMap), SetPaused(bool), //Graphics(crate::graphics_worker::Instruction), } +mod mouse_interpolator{ + use super::*; pub struct MouseInterpolator{ + //"PlayerController" timeline:std::collections::VecDeque>, last_mouse_time:Time,//this value is pre-transformed to simulation time mouse_blocking:bool, + //"Simulation" timer:Timer, + physics:crate::physics::PhysicsContext, } impl MouseInterpolator{ - fn push_mouse_instruction(&mut self,physics:&crate::physics::PhysicsContext,ins:&TimedInstruction,m:glam::IVec2){ + pub fn new( + physics:crate::physics::PhysicsContext, + )->Self{ + Self{ + mouse_blocking:true, + last_mouse_time:physics.get_next_mouse().time, + timeline:std::collections::VecDeque::new(), + timer:Timer::from_state(Scaled::identity(),false), + physics, + } + } + fn push_mouse_instruction(&mut self,ins:&TimedInstruction,m:glam::IVec2){ if self.mouse_blocking{ //tell the game state which is living in the past about its future self.timeline.push_front(TimedInstruction{ @@ -47,7 +64,7 @@ impl MouseInterpolator{ self.timeline.push_front(TimedInstruction{ time:self.last_mouse_time, instruction:PhysicsInputInstruction::ReplaceMouse( - MouseState{time:self.last_mouse_time,pos:physics.get_next_mouse().pos}, + MouseState{time:self.last_mouse_time,pos:self.physics.get_next_mouse().pos}, MouseState{time:self.timer.time(ins.time),pos:m} ), }); @@ -58,12 +75,12 @@ impl MouseInterpolator{ } /// returns the mapped physics input instruction /// may or may not mutate internal state XD! - fn map_instruction(&mut self,physics:&crate::physics::PhysicsContext,ins:&TimedInstruction)->Option{ + fn map_instruction(&mut self,ins:&TimedInstruction)->Option{ match &ins.instruction{ Instruction::Input(input_instruction)=>match input_instruction{ &InputInstruction::MoveMouse(m)=>{ if !self.timer.is_paused(){ - self.push_mouse_instruction(physics,ins,m); + self.push_mouse_instruction(ins,m); } None }, @@ -81,8 +98,7 @@ impl MouseInterpolator{ }, //do these really need to idle the physics? //sending None dumps the instruction queue - Instruction::GenerateModels(_)=>Some(PhysicsInputInstruction::Idle), - Instruction::ClearModels=>Some(PhysicsInputInstruction::Idle), + Instruction::ChangeMap(_)=>Some(PhysicsInputInstruction::Idle), Instruction::Resize(_,_)=>Some(PhysicsInputInstruction::Idle), Instruction::Render=>Some(PhysicsInputInstruction::Idle), &Instruction::SetPaused(paused)=>{ @@ -93,17 +109,17 @@ impl MouseInterpolator{ }, } } - fn update_mouse_blocking(&mut self,physics:&crate::physics::PhysicsContext,ins:&TimedInstruction)->bool{ + fn update_mouse_blocking(&mut self,ins:&TimedInstruction)->bool{ if self.mouse_blocking{ //assume the mouse has stopped moving after 10ms. //shitty mice are 125Hz which is 8ms so this should cover that. //setting this to 100us still doesn't print even though it's 10x lower than the polling rate, //so mouse events are probably not handled separately from drawing and fire right before it :( - if Time::from_millis(10),phys_input_option:Option)->bool{ + fn handle_physics_input(&mut self,ins:&TimedInstruction,phys_input_option:Option)->bool{ if let Some(phys_input)=phys_input_option{ //non-mouse event self.timeline.push_back(TimedInstruction{ @@ -129,44 +145,51 @@ impl MouseInterpolator{ }); //this returns the bool for us - self.update_mouse_blocking(physics,ins) + self.update_mouse_blocking(ins) }else{ //mouse event true } } - fn empty_queue(&mut self,physics:&mut crate::physics::PhysicsContext){ + fn empty_queue(&mut self,bot_worker:&crate::worker::QNWorker<'_,crate::bot_worker::Instruction>){ while let Some(instruction)=self.timeline.pop_front(){ - bot_worker.send(instruction.clone()).unwrap(); - physics.run_input_instruction(instruction); + //makeshift clone because requiring all TimedInstructions to be Clone is troublesome + bot_worker.send(crate::bot_worker::Instruction::Push{ + ins:TimedInstruction{ + time:instruction.time, + instruction:instruction.instruction.clone(), + } + }).unwrap(); + self.physics.run_input_instruction(instruction); } } - fn handle_instruction(&mut self,physics:&mut crate::physics::PhysicsContext,ins:&TimedInstruction){ - let physics_input_option=self.map_instruction(physics,ins); - let should_empty_queue=self.handle_physics_input(physics,ins,physics_input_option); + pub fn handle_instruction(&mut self,ins:&TimedInstruction,bot_worker:&crate::worker::QNWorker<'_,crate::bot_worker::Instruction>){ + let physics_input_option=self.map_instruction(ins); + let should_empty_queue=self.handle_physics_input(ins,physics_input_option); if should_empty_queue{ - self.empty_queue(physics); + self.empty_queue(bot_worker); } } + pub fn get_render_stuff(&self,time:Time)->(crate::physics::PhysicsOutputState,Time,glam::IVec2){ + (self.physics.output(),self.timer.time(time),self.physics.get_next_mouse().pos) + } +} } -pub fn new(mut physics:crate::physics::PhysicsContext,mut graphics_worker:crate::compat_worker::INWorker)->crate::compat_worker::QNWorker>{ - let mut interpolator=MouseInterpolator{ - mouse_blocking:true, - last_mouse_time:physics.get_next_mouse().time, - timeline:std::collections::VecDeque::new(), - timer:Timer::from_state(Scaled::identity(),false), - }; +pub fn new<'a>(physics:crate::physics::PhysicsContext,mut graphics_worker:crate::compat_worker::INWorker<'a,crate::graphics_worker::Instruction>,bot_worker:crate::worker::QNWorker<'a,crate::bot_worker::Instruction>)->crate::compat_worker::QNWorker<'a,TimedInstruction>{ + let mut interpolator=MouseInterpolator::new(physics); crate::compat_worker::QNWorker::new(move |ins:TimedInstruction|{ - interpolator.handle_instruction(&mut physics,&ins); + interpolator.handle_instruction(&ins,&bot_worker); match ins.instruction{ Instruction::Render=>{ - graphics_worker.send(crate::graphics_worker::Instruction::Render(physics.output(),interpolator.timer.time(ins.time),physics.get_next_mouse().pos)).unwrap(); + let (physics_output,time,mouse_pos)=interpolator.get_render_stuff(ins.time); + graphics_worker.send(crate::graphics_worker::Instruction::Render(physics_output,time,mouse_pos)).unwrap(); }, Instruction::Resize(size,user_settings)=>{ graphics_worker.send(crate::graphics_worker::Instruction::Resize(size,user_settings)).unwrap(); }, - Instruction::GenerateModels(map)=>{ + Instruction::ChangeMap(map)=>{ + physics.clear(); physics.generate_models(&map); //important! //bots will not work properly without this exact restart + spawn setup @@ -175,13 +198,10 @@ pub fn new(mut physics:crate::physics::PhysicsContext,mut graphics_worker:crate: //generate a spawn event so bots work properly on the first run //no run started so does not invalidate the run physics.spawn(); - graphics_worker.send(crate::graphics_worker::Instruction::GenerateModels(map)).unwrap(); + graphics_worker.send(crate::graphics_worker::Instruction::ChangeMap(map)).unwrap(); }, - Instruction::ClearModels=>{ - physics.clear(); - graphics_worker.send(crate::graphics_worker::Instruction::ClearModels).unwrap(); - }, - _=>(), + Instruction::Input(_)=>(), + Instruction::SetPaused(_)=>(), } }) } diff --git a/src/setup.rs b/src/setup.rs index 1e39d4e..305c71a 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -213,21 +213,22 @@ pub fn setup_and_start(title:String){ //dedicated thread to ping request redraw back and resize the window doesn't seem logical - let window=crate::window::WindowContextSetup::new(&setup_context,&window); - //the thread that spawns the physics thread - let mut window_thread=window.into_worker(setup_context); + std::thread::scope(|scope|{ + //the thread that spawns the physics thread + let mut window_thread=crate::window::worker(&window,setup_context,scope); - if let Some(arg)=std::env::args().nth(1){ - let path=std::path::PathBuf::from(arg); - window_thread.send(TimedInstruction{ - time:integer::Time::ZERO, - instruction:WindowInstruction::WindowEvent(winit::event::WindowEvent::DroppedFile(path)), - }).unwrap(); - }; + if let Some(arg)=std::env::args().nth(1){ + let path=std::path::PathBuf::from(arg); + window_thread.send(TimedInstruction{ + time:integer::Time::ZERO, + instruction:WindowInstruction::WindowEvent(winit::event::WindowEvent::DroppedFile(path)), + }).unwrap(); + }; - println!("Entering event loop..."); - let root_time=std::time::Instant::now(); - run_event_loop(event_loop,window_thread,root_time).unwrap(); + println!("Entering event loop..."); + let root_time=std::time::Instant::now(); + run_event_loop(event_loop,window_thread,root_time).unwrap(); + }); } fn run_event_loop( diff --git a/src/window.rs b/src/window.rs index 88d540a..633e2db 100644 --- a/src/window.rs +++ b/src/window.rs @@ -28,10 +28,7 @@ impl WindowContext<'_>{ match event { winit::event::WindowEvent::DroppedFile(path)=>{ match crate::file::load(path.as_path()){ - Ok(map)=>{ - self.physics_thread.send(TimedInstruction{time,instruction:crate::physics_worker::Instruction::ClearModels}).unwrap(); - self.physics_thread.send(TimedInstruction{time,instruction:crate::physics_worker::Instruction::GenerateModels(map)}).unwrap(); - }, + Ok(map)=>self.physics_thread.send(TimedInstruction{time,instruction:crate::physics_worker::Instruction::ChangeMap(map)}).unwrap(), Err(e)=>println!("Failed to load map: {e}"), } }, @@ -169,78 +166,59 @@ impl WindowContext<'_>{ } } } +pub fn worker<'a>(window:&'a winit::window::Window,setup_context:crate::setup::SetupContext<'a>,scope:&'a std::thread::Scope<'a,'_>)->crate::compat_worker::QNWorker<'a,TimedInstruction>{ + // WindowContextSetup::new + let user_settings=crate::settings::read_user_settings(); -pub struct WindowContextSetup<'a>{ - user_settings:crate::settings::UserSettings, - window:&'a winit::window::Window, - physics:crate::physics::PhysicsContext, - graphics:crate::graphics::GraphicsState, -} + let mut physics=crate::physics::PhysicsContext::default(); + physics.load_user_settings(&user_settings); -impl<'a> WindowContextSetup<'a>{ - pub fn new(context:&crate::setup::SetupContext,window:&'a winit::window::Window)->Self{ - let user_settings=crate::settings::read_user_settings(); + let mut graphics=crate::graphics::GraphicsState::new(&setup_context.device,&setup_context.queue,&setup_context.config); + graphics.load_user_settings(&user_settings); - let mut physics=crate::physics::PhysicsContext::default(); - physics.load_user_settings(&user_settings); + //WindowContextSetup::into_context + let screen_size=glam::uvec2(setup_context.config.width,setup_context.config.height); + let graphics_thread=crate::graphics_worker::new(graphics,setup_context.config,setup_context.surface,setup_context.device,setup_context.queue); + //this obviously doesn't belong here, do something about it pls + let bot_thread=crate::bot_worker::new(scope); + let mut window_context=WindowContext{ + manual_mouse_lock:false, + mouse:strafesnet_common::mouse::MouseState::default(), + //make sure to update this!!!!! + screen_size, + user_settings, + window, + physics_thread:crate::physics_worker::new(physics,graphics_thread,bot_thread), + }; - let mut graphics=crate::graphics::GraphicsState::new(&context.device,&context.queue,&context.config); - graphics.load_user_settings(&user_settings); - - Self{ - user_settings, - window, - graphics, - physics, - } - } - - fn into_context(self,setup_context:crate::setup::SetupContext<'a>)->WindowContext<'a>{ - let screen_size=glam::uvec2(setup_context.config.width,setup_context.config.height); - let graphics_thread=crate::graphics_worker::new(self.graphics,setup_context.config,setup_context.surface,setup_context.device,setup_context.queue); - //this obviously doesn't belong here, do something about it pls - let bot_thread=crate::bot_worker::new(scope); - WindowContext{ - manual_mouse_lock:false, - mouse:strafesnet_common::mouse::MouseState::default(), - //make sure to update this!!!!! - screen_size, - user_settings:self.user_settings, - window:self.window, - physics_thread:crate::physics_worker::new(self.physics,graphics_thread), - } - } - - pub fn into_worker(self,setup_context:crate::setup::SetupContext<'a>)->crate::compat_worker::QNWorker<'a,TimedInstruction>{ - let mut window_context=self.into_context(setup_context); - crate::compat_worker::QNWorker::new(move |ins:TimedInstruction|{ - match ins.instruction{ - WindowInstruction::RequestRedraw=>{ - window_context.window.request_redraw(); - } - WindowInstruction::WindowEvent(window_event)=>{ - window_context.window_event(ins.time,window_event); - }, - WindowInstruction::DeviceEvent(device_event)=>{ - window_context.device_event(ins.time,device_event); - }, - WindowInstruction::Resize(size)=>{ - window_context.physics_thread.send( - TimedInstruction{ - time:ins.time, - instruction:crate::physics_worker::Instruction::Resize(size,window_context.user_settings.clone()) - } - ).unwrap(); - } - WindowInstruction::Render=>{ - window_context.physics_thread.send( - TimedInstruction{ - time:ins.time, - instruction:crate::physics_worker::Instruction::Render - } - ).unwrap(); - } + //WindowContextSetup::into_worker + crate::compat_worker::QNWorker::new(move |ins:TimedInstruction|{ + match ins.instruction{ + WindowInstruction::RequestRedraw=>{ + window_context.window.request_redraw(); } - }) - } + WindowInstruction::WindowEvent(window_event)=>{ + window_context.window_event(ins.time,window_event); + }, + WindowInstruction::DeviceEvent(device_event)=>{ + window_context.device_event(ins.time,device_event); + }, + WindowInstruction::Resize(size)=>{ + window_context.physics_thread.send( + TimedInstruction{ + time:ins.time, + instruction:crate::physics_worker::Instruction::Resize(size,window_context.user_settings.clone()) + } + ).unwrap(); + } + WindowInstruction::Render=>{ + window_context.physics_thread.send( + TimedInstruction{ + time:ins.time, + instruction:crate::physics_worker::Instruction::Render + } + ).unwrap(); + } + } + }) } diff --git a/src/worker.rs b/src/worker.rs index 325a3b9..08287f6 100644 --- a/src/worker.rs +++ b/src/worker.rs @@ -190,7 +190,7 @@ mod test{ for _ in 0..5 { let task = instruction::TimedInstruction{ time:integer::Time::ZERO, - instruction:physics::PhysicsInputInstruction::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:physics::PhysicsInputInstruction::Idle, + instruction:strafesnet_common::physics::Instruction::Idle, }; worker.send(task).unwrap();