diff options
Diffstat (limited to 'src/gamepad.rs')
-rw-r--r-- | src/gamepad.rs | 168 |
1 files changed, 150 insertions, 18 deletions
diff --git a/src/gamepad.rs b/src/gamepad.rs index 4ea82f7..f59577a 100644 --- a/src/gamepad.rs +++ b/src/gamepad.rs @@ -1,5 +1,8 @@ -use crate::display::Display; +use crate::state; use gilrs::{Button, GamepadId, Gilrs}; +use state::GBState; +use std::fs::File; +use std::io::{Write, Read, ErrorKind}; use minifb::Key; pub struct Gamepad { @@ -8,7 +11,7 @@ pub struct Gamepad { } pub trait Input { - fn update_events(&mut self); + fn update_events(&mut self, cycles: u128, state: &GBState); fn get_action_gamepad_reg(&self) -> u8; fn get_direction_gamepad_reg(&self) -> u8; } @@ -38,7 +41,7 @@ impl Gamepad { } impl Input for Gamepad { - fn update_events(&mut self) { + fn update_events(&mut self, _cycles: u128, _state: &GBState) { while let Some(_) = self.gilrs.next_event() {} } @@ -95,50 +98,179 @@ impl Input for Gamepad { } } -impl Input for Display { - fn update_events(&mut self) {} +pub struct Keyboard { + action_reg: u8, + direction_reg: u8, +} - fn get_action_gamepad_reg(&self) -> u8 { +impl Keyboard { + pub fn new() -> Self { + Self { + action_reg: 0, + direction_reg: 0 + } + } +} + +impl Input for Keyboard { + fn update_events(&mut self, _cycles: u128, state: &GBState) { let mut res = 0xf; - if self.window.is_key_down(Key::A) { + if state.mem.display.window.is_key_down(Key::A) { res &= 0b1110; } - if self.window.is_key_down(Key::B) { + if state.mem.display.window.is_key_down(Key::B) { res &= 0b1101; } - if self.window.is_key_down(Key::Backspace) { + if state.mem.display.window.is_key_down(Key::Backspace) { res &= 0b1011; } - if self.window.is_key_down(Key::Enter) { + if state.mem.display.window.is_key_down(Key::Enter) { res &= 0b0111; } - res - } + self.action_reg = res; - fn get_direction_gamepad_reg(&self) -> u8 { let mut res = 0xf; - if self.window.is_key_down(Key::Right) { + if state.mem.display.window.is_key_down(Key::Right) { res &= 0b1110; } - if self.window.is_key_down(Key::Left) { + if state.mem.display.window.is_key_down(Key::Left) { res &= 0b1101; } - if self.window.is_key_down(Key::Up) { + if state.mem.display.window.is_key_down(Key::Up) { res &= 0b1011; } - if self.window.is_key_down(Key::Down) { + if state.mem.display.window.is_key_down(Key::Down) { res &= 0b0111; } - res + self.direction_reg = res; + } + + fn get_action_gamepad_reg(&self) -> u8 { + self.action_reg + } + + fn get_direction_gamepad_reg(&self) -> u8 { + self.direction_reg + } +} + +pub struct GamepadRecorder { + input: Box<dyn Input>, + record_file: File, + action_reg: u8, + direction_reg: u8, +} + +impl GamepadRecorder { + pub fn new(input: Box<dyn Input>, record_file: String) -> Self { + Self { + input, + record_file: File::create(record_file).expect("Couldn't create gamepad record file"), + action_reg: 0xff, + direction_reg: 0xff, + } + } +} + +impl Input for GamepadRecorder { + fn update_events(&mut self, cycles: u128, state: &GBState) { + self.input.update_events(cycles, state); + + let new_action_reg = self.input.get_action_gamepad_reg(); + let new_direction_reg = self.input.get_direction_gamepad_reg(); + + if self.action_reg != new_action_reg || self.direction_reg != new_direction_reg { + println!("input update on cycle {} ! 0x{:02x} 0x{:02x}", cycles, new_action_reg, new_direction_reg); + if let Err(err) = self.record_file.write_all(&cycles.to_le_bytes()) { + eprintln!("Failed to write to record file: {}", err); + }; + if let Err(err) = self.record_file.write_all(&[new_action_reg, new_direction_reg]) { + eprintln!("Failed to write to record file: {}", err); + } + if let Err(err) = self.record_file.flush() { + eprintln!("Failed to flush record file writes: {}", err); + } + } + + self.action_reg = new_action_reg; + self.direction_reg = new_direction_reg; + } + + fn get_action_gamepad_reg(&self) -> u8 { + self.action_reg + } + + fn get_direction_gamepad_reg(&self) -> u8 { + self.direction_reg + } +} + +pub struct GamepadReplay { + record_file: File, + action_reg: u8, + direction_reg: u8, + next_cycle_update: Option<u128>, +} + +impl GamepadReplay { + pub fn new(record_file: String) -> Self { + let mut file = File::open(record_file).expect("Couldn't open gamepad record file"); + + let mut cycles_le: [u8; 16] = [0; 16]; + + let next_cycle_update = match file.read_exact(&mut cycles_le) { + Err(err) if err.kind() == ErrorKind::UnexpectedEof => None, + Err(err) => panic!("{}", err), + Ok(_) => Some(u128::from_le_bytes(cycles_le)), + }; + + Self { + record_file: file, + action_reg: 0xff, + direction_reg: 0xff, + next_cycle_update, + } } } + +impl Input for GamepadReplay { + fn update_events(&mut self, cycles: u128, _state: &GBState) { + if let Some(next_cycle_update) = self.next_cycle_update { + if cycles > next_cycle_update { + let mut inputs: [u8; 2] = [0; 2]; + + self.record_file.read_exact(&mut inputs).expect("Unexpected EOF after cycle but before input"); + + self.action_reg = inputs[0]; + self.direction_reg = inputs[1]; + + let mut cycles_le: [u8; 16] = [0; 16]; + + self.next_cycle_update = match self.record_file.read_exact(&mut cycles_le) { + Err(err) if err.kind() == ErrorKind::UnexpectedEof => None, + Err(err) => panic!("{}", err), + Ok(_) => Some(u128::from_le_bytes(cycles_le)), + }; + } + } + } + + fn get_action_gamepad_reg(&self) -> u8 { + self.action_reg + } + + fn get_direction_gamepad_reg(&self) -> u8 { + self.direction_reg + } +} + |