use std::{ collections::HashMap, fmt::Debug, sync::{Arc, RwLock}, }; use game::GameWindow; use input::InputWindow; use winit::{ application::ApplicationHandler, event::{Event, WindowEvent}, event_loop::{ActiveEventLoop, EventLoopProxy}, window::WindowId, }; use crate::{ controller::ControllerState, emulator::{EmulatorClient, EmulatorCommand, SimId}, input::InputMapper, }; mod common; mod game; mod input; pub struct App { windows: HashMap>, client: EmulatorClient, input_mapper: Arc>, controller: ControllerState, proxy: EventLoopProxy, player_2_window: Option, } impl App { pub fn new(client: EmulatorClient, proxy: EventLoopProxy) -> Self { let input_mapper = Arc::new(RwLock::new(InputMapper::new())); let controller = ControllerState::new(input_mapper.clone()); Self { windows: HashMap::new(), client, input_mapper, controller, proxy, player_2_window: None, } } } impl ApplicationHandler for App { fn resumed(&mut self, event_loop: &ActiveEventLoop) { let window = GameWindow::new( event_loop, SimId::Player1, self.client.clone(), self.proxy.clone(), ); self.windows.insert(window.id(), Box::new(window)); } fn window_event( &mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent, ) { if let WindowEvent::KeyboardInput { event, .. } = &event { if let Some((sim_id, pressed)) = self.controller.key_event(event) { self.client .send_command(EmulatorCommand::SetKeys(sim_id, pressed)); } } let Some(window) = self.windows.get_mut(&window_id) else { return; }; window.handle_event(event_loop, &Event::WindowEvent { window_id, event }); } fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) { match event { UserEvent::OpenInputWindow => { let window = InputWindow::new(event_loop, self.input_mapper.clone(), self.proxy.clone()); self.windows.insert(window.id(), Box::new(window)); } UserEvent::OpenPlayer2Window => { if self.player_2_window.is_some() { return; } let window = GameWindow::new( event_loop, SimId::Player2, self.client.clone(), self.proxy.clone(), ); self.player_2_window = Some(window.id()); self.windows.insert(window.id(), Box::new(window)); } UserEvent::Close(window_id) => { if self.player_2_window == Some(window_id) { self.player_2_window.take(); } self.windows.remove(&window_id); } } } fn device_event( &mut self, event_loop: &ActiveEventLoop, device_id: winit::event::DeviceId, event: winit::event::DeviceEvent, ) { for window in self.windows.values_mut() { window.handle_event( event_loop, &Event::DeviceEvent { device_id, event: event.clone(), }, ); } } fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) { for window in self.windows.values_mut() { window.handle_event(event_loop, &Event::AboutToWait); } } } pub trait AppWindow { fn id(&self) -> WindowId; fn handle_event(&mut self, event_loop: &ActiveEventLoop, event: &Event); } #[derive(Debug)] pub enum UserEvent { OpenInputWindow, OpenPlayer2Window, Close(WindowId), }