use strafesnet_common::instruction::TimedInstruction; use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner}; use strafesnet_common::physics::{MiscInstruction,SetControlInstruction}; use crate::file::Format2; use crate::physics_worker::Instruction as PhysicsWorkerInstruction; use crate::session::{SessionInputInstruction,SessionControlInstruction,SessionPlaybackInstruction}; pub enum Instruction{ Resize(winit::dpi::PhysicalSize), WindowEvent(winit::event::WindowEvent), DeviceEvent(winit::event::DeviceEvent), RequestRedraw, Render, } //holds thread handles to dispatch to struct WindowContext<'a>{ manual_mouse_lock:bool, mouse_pos:glam::DVec2, screen_size:glam::UVec2, window:&'a winit::window::Window, physics_thread:crate::compat_worker::QNWorker<'a,TimedInstruction>, } impl WindowContext<'_>{ fn get_middle_of_screen(&self)->winit::dpi::PhysicalPosition{ winit::dpi::PhysicalPosition::new(self.screen_size.x/2,self.screen_size.y/2) } fn window_event(&mut self,time:SessionTime,event:winit::event::WindowEvent){ match event{ winit::event::WindowEvent::DroppedFile(path)=>{ match crate::file::load(path.as_path()){ Ok(Format2::Map(map))=>self.physics_thread.send(TimedInstruction{time,instruction:PhysicsWorkerInstruction::ChangeMap(map)}).unwrap(), Ok(Format2::Bot(bot))=>self.physics_thread.send(TimedInstruction{time,instruction:PhysicsWorkerInstruction::LoadReplay(bot)}).unwrap(), Err(e)=>println!("Failed to load file: {e}"), } }, winit::event::WindowEvent::Focused(state)=>{ //pause unpause self.physics_thread.send(TimedInstruction{ time, instruction:PhysicsWorkerInstruction::SessionControl(SessionControlInstruction::SetPaused(!state)), }).unwrap(); //recalculate pressed keys on focus }, winit::event::WindowEvent::KeyboardInput{ event:winit::event::KeyEvent{state,logical_key,repeat:false,..}, .. }=>{ match (logical_key,state){ (winit::keyboard::Key::Named(winit::keyboard::NamedKey::Tab),winit::event::ElementState::Pressed)=>{ self.manual_mouse_lock=false; match self.window.set_cursor_position(self.get_middle_of_screen()){ Ok(())=>(), Err(e)=>println!("Could not set cursor position: {:?}",e), } match self.window.set_cursor_grab(winit::window::CursorGrabMode::None){ Ok(())=>(), Err(e)=>println!("Could not release cursor: {:?}",e), } self.window.set_cursor_visible(state.is_pressed()); }, (winit::keyboard::Key::Named(winit::keyboard::NamedKey::Tab),winit::event::ElementState::Released)=>{ //if cursor is outside window don't lock but apparently there's no get pos function //let pos=window.get_cursor_pos(); match self.window.set_cursor_grab(winit::window::CursorGrabMode::Locked){ Ok(())=>(), Err(_)=>{ match self.window.set_cursor_grab(winit::window::CursorGrabMode::Confined){ Ok(())=>(), Err(e)=>{ self.manual_mouse_lock=true; println!("Could not confine cursor: {:?}",e) }, } } } self.window.set_cursor_visible(state.is_pressed()); }, (winit::keyboard::Key::Named(winit::keyboard::NamedKey::F11),winit::event::ElementState::Pressed)=>{ if self.window.fullscreen().is_some(){ self.window.set_fullscreen(None); }else{ self.window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(None))); } }, (winit::keyboard::Key::Named(winit::keyboard::NamedKey::Escape),winit::event::ElementState::Pressed)=>{ self.manual_mouse_lock=false; match self.window.set_cursor_grab(winit::window::CursorGrabMode::None){ Ok(())=>(), Err(e)=>println!("Could not release cursor: {:?}",e), } self.window.set_cursor_visible(true); }, (keycode,state)=>{ let s=state.is_pressed(); // internal variants for this scope enum SessionInstructionSubset{ Input(SessionInputInstruction), Control(SessionControlInstruction), Playback(SessionPlaybackInstruction), } macro_rules! input_ctrl{ ($variant:ident,$state:expr)=>{ Some(SessionInstructionSubset::Input(SessionInputInstruction::SetControl(SetControlInstruction::$variant($state)))) }; } macro_rules! input_misc{ ($variant:ident,$state:expr)=>{ s.then_some(SessionInstructionSubset::Input(SessionInputInstruction::Misc(MiscInstruction::$variant))) }; } macro_rules! session_ctrl{ ($variant:ident,$state:expr)=>{ s.then_some(SessionInstructionSubset::Control(SessionControlInstruction::$variant)) }; } macro_rules! session_playback{ ($variant:ident,$state:expr)=>{ s.then_some(SessionInstructionSubset::Playback(SessionPlaybackInstruction::$variant)) }; } impl From for PhysicsWorkerInstruction{ fn from(value:SessionInstructionSubset)->Self{ match value{ SessionInstructionSubset::Input(session_input_instruction)=>PhysicsWorkerInstruction::SessionInput(session_input_instruction), SessionInstructionSubset::Control(session_control_instruction)=>PhysicsWorkerInstruction::SessionControl(session_control_instruction), SessionInstructionSubset::Playback(session_playback_instruction)=>PhysicsWorkerInstruction::SessionPlayback(session_playback_instruction), } } } if let Some(session_instruction)=match keycode{ winit::keyboard::Key::Named(winit::keyboard::NamedKey::Space)=>input_ctrl!(SetJump,s), // TODO: bind system so playback pausing can use spacebar winit::keyboard::Key::Named(winit::keyboard::NamedKey::Enter)=>session_playback!(TogglePaused,s), winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowUp)=>session_playback!(IncreaseTimescale,s), winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowDown)=>session_playback!(DecreaseTimescale,s), winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowLeft)=>session_playback!(SkipBack,s), winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowRight)=>session_playback!(SkipForward,s), winit::keyboard::Key::Character(key)=>match key.as_str(){ "W"|"w"=>input_ctrl!(SetMoveForward,s), "A"|"a"=>input_ctrl!(SetMoveLeft,s), "S"|"s"=>input_ctrl!(SetMoveBack,s), "D"|"d"=>input_ctrl!(SetMoveRight,s), "E"|"e"=>input_ctrl!(SetMoveUp,s), "Q"|"q"=>input_ctrl!(SetMoveDown,s), "Z"|"z"=>input_ctrl!(SetZoom,s), "R"|"r"=>s.then(||{ //mouse needs to be reset since the position is absolute self.mouse_pos=glam::DVec2::ZERO; SessionInstructionSubset::Input(SessionInputInstruction::Mode(crate::session::ImplicitModeInstruction::ResetAndRestart)) }), "F"|"f"=>input_misc!(PracticeFly,s), "B"|"b"=>session_ctrl!(CopyRecordingIntoReplayAndSpectate,s), "X"|"x"=>session_ctrl!(StopSpectate,s), "N"|"n"=>session_ctrl!(SaveReplay,s), "J"|"j"=>session_ctrl!(LoadIntoReplayState,s), _=>None, }, _=>None, }{ self.physics_thread.send(TimedInstruction{ time, instruction:session_instruction.into(), }).unwrap(); } }, } }, _=>(), } } fn device_event(&mut self,time:SessionTime,event: winit::event::DeviceEvent){ match event{ winit::event::DeviceEvent::MouseMotion{ delta, }=>{ if self.manual_mouse_lock{ match self.window.set_cursor_position(self.get_middle_of_screen()){ Ok(())=>(), Err(e)=>println!("Could not set cursor position: {:?}",e), } } self.mouse_pos+=glam::dvec2(delta.0,delta.1); self.physics_thread.send(TimedInstruction{ time, instruction:PhysicsWorkerInstruction::SessionInput(SessionInputInstruction::Mouse(self.mouse_pos.as_ivec2())), }).unwrap(); }, winit::event::DeviceEvent::MouseWheel { delta, }=>{ println!("mousewheel {:?}",delta); if false{//self.physics.style.use_scroll{ self.physics_thread.send(TimedInstruction{ time, instruction:PhysicsWorkerInstruction::SessionInput(SessionInputInstruction::SetControl(SetControlInstruction::SetJump(true))),//activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump }).unwrap(); } }, _=>(), } } } pub fn worker<'a>( window:&'a winit::window::Window, setup_context:crate::setup::SetupContext<'a>, )->crate::compat_worker::QNWorker<'a,TimedInstruction>{ // WindowContextSetup::new 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); //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); let mut window_context=WindowContext{ manual_mouse_lock:false, mouse_pos:glam::DVec2::ZERO, //make sure to update this!!!!! screen_size, window, physics_thread:crate::physics_worker::new( graphics_thread, user_settings, ), }; //WindowContextSetup::into_worker crate::compat_worker::QNWorker::new(move |ins:TimedInstruction|{ match ins.instruction{ Instruction::RequestRedraw=>{ window_context.window.request_redraw(); } Instruction::WindowEvent(window_event)=>{ window_context.window_event(ins.time,window_event); }, Instruction::DeviceEvent(device_event)=>{ window_context.device_event(ins.time,device_event); }, Instruction::Resize(size)=>{ window_context.physics_thread.send( TimedInstruction{ time:ins.time, instruction:PhysicsWorkerInstruction::Resize(size) } ).unwrap(); } Instruction::Render=>{ window_context.physics_thread.send( TimedInstruction{ time:ins.time, instruction:PhysicsWorkerInstruction::Render } ).unwrap(); } } }) }