From 7c0a091a6159600023f5b2f0d1e11ef2f46cf97d Mon Sep 17 00:00:00 2001 From: RobDavenport Date: Thu, 29 Sep 2022 21:21:39 +0900 Subject: [PATCH 1/7] add configurable controls --- .gitignore | 1 + Cargo.lock | 3 + gamercade_console/Cargo.toml | 5 +- .../src/console/input/key_bindings.rs | 105 +++++++++++------- .../src/console/input/key_types.rs | 18 +-- .../src/console/input/local_input_manager.rs | 6 +- gamercade_core/src/input/input_code.rs | 3 +- 7 files changed, 90 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index ea8c4bf7..9d8e4df1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/input.json \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 34eed740..0a3f8815 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1714,6 +1714,7 @@ dependencies = [ "pixels", "rfd", "serde", + "serde_json", "wasmtime", "winit 0.26.1", "winit_input_helper", @@ -2128,6 +2129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash 0.7.6", + "serde", ] [[package]] @@ -4822,6 +4824,7 @@ dependencies = [ "parking_lot 0.11.2", "percent-encoding", "raw-window-handle 0.4.3", + "serde", "smithay-client-toolkit 0.15.4", "wasm-bindgen", "wayland-client", diff --git a/gamercade_console/Cargo.toml b/gamercade_console/Cargo.toml index b4411ce6..369040ae 100644 --- a/gamercade_console/Cargo.toml +++ b/gamercade_console/Cargo.toml @@ -17,11 +17,11 @@ gamercade_audio = { path = "../gamercade_audio" } gamercade_sound_engine = { path = "../gamercade_sound_engine" } # General Improvements -hashbrown = "0.12.3" +hashbrown = { version = "0.12.3", features = ["serde"] } parking_lot = "0.12.1" # Windowing & Graphics -winit = "0.26.1" +winit = { version = "0.26.1", features = ["serde"] } pixels = "0.9.0" winit_input_helper = "0.12.0" @@ -35,6 +35,7 @@ paste = "1.0.8" # Serialization / File Loading etc serde = { version = "1.0.144", features = ["derive"] } +serde_json = "1.0.85" bytemuck = "1.12.1" # Scripting diff --git a/gamercade_console/src/console/input/key_bindings.rs b/gamercade_console/src/console/input/key_bindings.rs index 5b489b1f..37cfc88b 100644 --- a/gamercade_console/src/console/input/key_bindings.rs +++ b/gamercade_console/src/console/input/key_bindings.rs @@ -1,10 +1,15 @@ +use std::path::PathBuf; + use gamercade_core::{ButtonCode, InputState}; use hashbrown::HashMap; +use serde::{Deserialize, Serialize}; use winit::event::VirtualKeyCode; use super::key_types::{Analog, AnalogAxis, AnalogDirection, AnalogSide, KeyType}; +const INPUT_FILE_NAME: &str = "input.json"; + impl Analog { pub(crate) fn adjust_input_state(self, input_state: &mut InputState) { let value = match self.direction { @@ -24,56 +29,80 @@ impl Analog { } } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] +#[serde(transparent)] pub(crate) struct KeyBindings { pub buttons: HashMap, } +impl KeyBindings { + pub fn load() -> Self { + let path = PathBuf::from(INPUT_FILE_NAME); + if path.exists() { + match std::fs::read(INPUT_FILE_NAME) { + Ok(file) => match serde_json::from_slice::(&file) { + Ok(key_bindings) => { + println!("Successfully loaded key bindings from: {}", INPUT_FILE_NAME); + return key_bindings; + } + Err(e) => { + println!("{} found, but unable to parse: {}", INPUT_FILE_NAME, e); + } + }, + Err(e) => println!("{} found, but unable to read: {}", INPUT_FILE_NAME, e), + }; + + println!("Using default config."); + Self::default() + } else { + println!( + "{} not found. Generating default input file.", + INPUT_FILE_NAME + ); + let bindings = Self::default(); + + let json = serde_json::to_string_pretty(&bindings).unwrap(); + + match std::fs::write(path, json) { + Ok(()) => println!("Successfully generated default {}", INPUT_FILE_NAME), + Err(e) => println!("Error writing {}: {}", INPUT_FILE_NAME, e), + }; + + bindings + } + } +} + impl Default for KeyBindings { fn default() -> Self { let buttons = [ //Sticks - ( - VirtualKeyCode::X, - KeyType::ButtonCode(ButtonCode::LeftStick), - ), - ( - VirtualKeyCode::B, - KeyType::ButtonCode(ButtonCode::RightStick), - ), + (VirtualKeyCode::X, KeyType::Button(ButtonCode::LeftStick)), + (VirtualKeyCode::B, KeyType::Button(ButtonCode::RightStick)), //Shoulders - ( - VirtualKeyCode::E, - KeyType::ButtonCode(ButtonCode::LeftShoulder), - ), + (VirtualKeyCode::E, KeyType::Button(ButtonCode::LeftShoulder)), (VirtualKeyCode::Q, KeyType::Trigger(AnalogSide::Left)), ( VirtualKeyCode::R, - KeyType::ButtonCode(ButtonCode::RightShoulder), + KeyType::Button(ButtonCode::RightShoulder), ), (VirtualKeyCode::Y, KeyType::Trigger(AnalogSide::Right)), //DPad: - (VirtualKeyCode::Up, KeyType::ButtonCode(ButtonCode::Up)), - (VirtualKeyCode::Down, KeyType::ButtonCode(ButtonCode::Down)), - (VirtualKeyCode::Left, KeyType::ButtonCode(ButtonCode::Left)), - ( - VirtualKeyCode::Right, - KeyType::ButtonCode(ButtonCode::Right), - ), + (VirtualKeyCode::Up, KeyType::Button(ButtonCode::Up)), + (VirtualKeyCode::Down, KeyType::Button(ButtonCode::Down)), + (VirtualKeyCode::Left, KeyType::Button(ButtonCode::Left)), + (VirtualKeyCode::Right, KeyType::Button(ButtonCode::Right)), //Buttons: - (VirtualKeyCode::U, KeyType::ButtonCode(ButtonCode::A)), - (VirtualKeyCode::I, KeyType::ButtonCode(ButtonCode::B)), - (VirtualKeyCode::J, KeyType::ButtonCode(ButtonCode::C)), - (VirtualKeyCode::K, KeyType::ButtonCode(ButtonCode::D)), - (VirtualKeyCode::Key5, KeyType::ButtonCode(ButtonCode::Start)), - ( - VirtualKeyCode::Key6, - KeyType::ButtonCode(ButtonCode::Select), - ), + (VirtualKeyCode::U, KeyType::Button(ButtonCode::A)), + (VirtualKeyCode::I, KeyType::Button(ButtonCode::B)), + (VirtualKeyCode::J, KeyType::Button(ButtonCode::C)), + (VirtualKeyCode::K, KeyType::Button(ButtonCode::D)), + (VirtualKeyCode::Key5, KeyType::Button(ButtonCode::Start)), + (VirtualKeyCode::Key6, KeyType::Button(ButtonCode::Select)), //Left Stick Axis ( VirtualKeyCode::W, - KeyType::Analog(Analog { + KeyType::AnalogStick(Analog { side: AnalogSide::Left, axis: AnalogAxis::Y, direction: AnalogDirection::Positive, @@ -81,7 +110,7 @@ impl Default for KeyBindings { ), ( VirtualKeyCode::S, - KeyType::Analog(Analog { + KeyType::AnalogStick(Analog { side: AnalogSide::Left, axis: AnalogAxis::Y, direction: AnalogDirection::Negative, @@ -89,7 +118,7 @@ impl Default for KeyBindings { ), ( VirtualKeyCode::A, - KeyType::Analog(Analog { + KeyType::AnalogStick(Analog { side: AnalogSide::Left, axis: AnalogAxis::X, direction: AnalogDirection::Negative, @@ -97,7 +126,7 @@ impl Default for KeyBindings { ), ( VirtualKeyCode::D, - KeyType::Analog(Analog { + KeyType::AnalogStick(Analog { side: AnalogSide::Left, axis: AnalogAxis::X, direction: AnalogDirection::Positive, @@ -106,7 +135,7 @@ impl Default for KeyBindings { //Right Stick Axis, ( VirtualKeyCode::T, - KeyType::Analog(Analog { + KeyType::AnalogStick(Analog { side: AnalogSide::Right, axis: AnalogAxis::Y, direction: AnalogDirection::Positive, @@ -114,7 +143,7 @@ impl Default for KeyBindings { ), ( VirtualKeyCode::G, - KeyType::Analog(Analog { + KeyType::AnalogStick(Analog { side: AnalogSide::Right, axis: AnalogAxis::Y, direction: AnalogDirection::Negative, @@ -122,7 +151,7 @@ impl Default for KeyBindings { ), ( VirtualKeyCode::F, - KeyType::Analog(Analog { + KeyType::AnalogStick(Analog { side: AnalogSide::Right, axis: AnalogAxis::X, direction: AnalogDirection::Negative, @@ -130,7 +159,7 @@ impl Default for KeyBindings { ), ( VirtualKeyCode::H, - KeyType::Analog(Analog { + KeyType::AnalogStick(Analog { side: AnalogSide::Right, axis: AnalogAxis::X, direction: AnalogDirection::Positive, diff --git a/gamercade_console/src/console/input/key_types.rs b/gamercade_console/src/console/input/key_types.rs index e851a5c6..97a49953 100644 --- a/gamercade_console/src/console/input/key_types.rs +++ b/gamercade_console/src/console/input/key_types.rs @@ -1,30 +1,34 @@ use gamercade_core::ButtonCode; +use serde::{Deserialize, Serialize}; -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub(crate) enum KeyType { - ButtonCode(ButtonCode), - Analog(Analog), + Button(ButtonCode), + AnalogStick(Analog), Trigger(AnalogSide), } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] + pub(crate) struct Analog { pub(crate) side: AnalogSide, pub(crate) axis: AnalogAxis, pub(crate) direction: AnalogDirection, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub(crate) enum AnalogSide { Left, Right, } -#[derive(Debug, Clone, Copy)] + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub(crate) enum AnalogAxis { X, Y, } -#[derive(Debug, Clone, Copy)] + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub(crate) enum AnalogDirection { Positive, Negative, diff --git a/gamercade_console/src/console/input/local_input_manager.rs b/gamercade_console/src/console/input/local_input_manager.rs index 05486684..aee08506 100644 --- a/gamercade_console/src/console/input/local_input_manager.rs +++ b/gamercade_console/src/console/input/local_input_manager.rs @@ -31,7 +31,7 @@ pub struct LocalInputManager { impl LocalInputManager { pub fn new(input_mode: InputMode) -> Self { Self { - keybinds: KeyBindings::default(), + keybinds: KeyBindings::load(), gamepad_binds: GamepadBindings::default(), input_mode, } @@ -113,8 +113,8 @@ fn generate_emulated_state( binds.buttons.iter().for_each(|(code, input)| { if input_helper.key_held(*code) { match input { - KeyType::ButtonCode(code) => output.buttons.enable_button(*code), - KeyType::Analog(emulated) => emulated.adjust_input_state(&mut output), + KeyType::Button(code) => output.buttons.enable_button(*code), + KeyType::AnalogStick(emulated) => emulated.adjust_input_state(&mut output), KeyType::Trigger(side) => match side { AnalogSide::Left => { output.buttons.enable_button(ButtonCode::LeftTrigger); diff --git a/gamercade_core/src/input/input_code.rs b/gamercade_core/src/input/input_code.rs index 8c8ec39f..7d9e71e0 100644 --- a/gamercade_core/src/input/input_code.rs +++ b/gamercade_core/src/input/input_code.rs @@ -1,8 +1,9 @@ +use serde::{Deserialize, Serialize}; use strum::EnumIter; use super::AsApiCode; -#[derive(Debug, Copy, Clone, EnumIter)] +#[derive(Debug, Copy, Clone, EnumIter, Serialize, Deserialize, Eq, PartialEq, Hash)] pub enum ButtonCode { // DPad Up, From 97510fd5cb676db2cdb34890a09fed3320b5fe15 Mon Sep 17 00:00:00 2001 From: RobDavenport Date: Thu, 29 Sep 2022 21:49:29 +0900 Subject: [PATCH 2/7] support multiple local players --- .../src/console/input/key_bindings.rs | 12 +++- .../src/console/input/local_input_manager.rs | 58 ++++++++++++------- gamercade_console/src/console/input/mod.rs | 4 ++ gamercade_console/src/main.rs | 2 +- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/gamercade_console/src/console/input/key_bindings.rs b/gamercade_console/src/console/input/key_bindings.rs index 37cfc88b..f9379bd5 100644 --- a/gamercade_console/src/console/input/key_bindings.rs +++ b/gamercade_console/src/console/input/key_bindings.rs @@ -6,7 +6,10 @@ use hashbrown::HashMap; use serde::{Deserialize, Serialize}; use winit::event::VirtualKeyCode; -use super::key_types::{Analog, AnalogAxis, AnalogDirection, AnalogSide, KeyType}; +use super::{ + key_types::{Analog, AnalogAxis, AnalogDirection, AnalogSide, KeyType}, + LocalControllerId, +}; const INPUT_FILE_NAME: &str = "input.json"; @@ -32,7 +35,7 @@ impl Analog { #[derive(Debug, Serialize, Deserialize)] #[serde(transparent)] pub(crate) struct KeyBindings { - pub buttons: HashMap, + pub buttons: HashMap>, } impl KeyBindings { @@ -75,7 +78,7 @@ impl KeyBindings { impl Default for KeyBindings { fn default() -> Self { - let buttons = [ + let p0 = [ //Sticks (VirtualKeyCode::X, KeyType::Button(ButtonCode::LeftStick)), (VirtualKeyCode::B, KeyType::Button(ButtonCode::RightStick)), @@ -169,6 +172,9 @@ impl Default for KeyBindings { .into_iter() .collect::>(); + let mut buttons = HashMap::new(); + buttons.insert(LocalControllerId(0), p0); + Self { buttons } } } diff --git a/gamercade_console/src/console/input/local_input_manager.rs b/gamercade_console/src/console/input/local_input_manager.rs index aee08506..78057ce8 100644 --- a/gamercade_console/src/console/input/local_input_manager.rs +++ b/gamercade_console/src/console/input/local_input_manager.rs @@ -1,5 +1,7 @@ use gamercade_core::{ButtonCode, InputState, MouseState}; +use ggrs::PlayerHandle; use gilrs::{Axis, Button, Gamepad, GamepadId, Gilrs}; +use hashbrown::HashMap; use pixels::Pixels; use winit_input_helper::WinitInputHelper; @@ -8,7 +10,7 @@ use crate::console::network::NetworkInputState; use super::{ gamepad_bindings::GamepadBindings, key_types::{AnalogSide, KeyType}, - InputMode, KeyBindings, + InputMode, KeyBindings, LocalControllerId, }; #[derive(Default)] @@ -26,6 +28,7 @@ pub struct LocalInputManager { keybinds: KeyBindings, gamepad_binds: GamepadBindings, pub(crate) input_mode: InputMode, + network_to_local: HashMap, } impl LocalInputManager { @@ -33,19 +36,21 @@ impl LocalInputManager { Self { keybinds: KeyBindings::load(), gamepad_binds: GamepadBindings::default(), + network_to_local: HashMap::default(), input_mode, } } pub fn generate_input_state( &self, + player_handle: PlayerHandle, pixels: &Pixels, mouse_events: &MouseEventCollector, helper: &winit_input_helper::WinitInputHelper, gilrs: &Gilrs, ) -> NetworkInputState { let input_state = match self.input_mode { - InputMode::Emulated => self.new_emulated_state(helper), + InputMode::Emulated => self.new_emulated_state(player_handle, helper), InputMode::Gamepad(id) => self.new_gamepad_state(id, gilrs), }; @@ -57,8 +62,16 @@ impl LocalInputManager { } } - fn new_emulated_state(&self, helper: &winit_input_helper::WinitInputHelper) -> InputState { - generate_emulated_state(&self.keybinds, helper) + fn new_emulated_state( + &self, + player_handle: PlayerHandle, + helper: &winit_input_helper::WinitInputHelper, + ) -> InputState { + if let Some(local_controller) = self.network_to_local.get(&player_handle) { + generate_emulated_state(*local_controller, &self.keybinds, helper) + } else { + InputState::default() + } } //TODO: This @@ -105,29 +118,32 @@ fn generate_gamepad_state(binds: &GamepadBindings, gamepad: &Gamepad) -> InputSt } fn generate_emulated_state( + player_id: LocalControllerId, binds: &KeyBindings, input_helper: &winit_input_helper::WinitInputHelper, ) -> InputState { let mut output = InputState::default(); - binds.buttons.iter().for_each(|(code, input)| { - if input_helper.key_held(*code) { - match input { - KeyType::Button(code) => output.buttons.enable_button(*code), - KeyType::AnalogStick(emulated) => emulated.adjust_input_state(&mut output), - KeyType::Trigger(side) => match side { - AnalogSide::Left => { - output.buttons.enable_button(ButtonCode::LeftTrigger); - output.left_trigger.set_value(1.0); - } - AnalogSide::Right => { - output.buttons.enable_button(ButtonCode::RightTrigger); - output.right_trigger.set_value(1.0) - } - }, + if let Some(buttons) = binds.buttons.get(&player_id) { + buttons.iter().for_each(|(code, input)| { + if input_helper.key_held(*code) { + match input { + KeyType::Button(code) => output.buttons.enable_button(*code), + KeyType::AnalogStick(emulated) => emulated.adjust_input_state(&mut output), + KeyType::Trigger(side) => match side { + AnalogSide::Left => { + output.buttons.enable_button(ButtonCode::LeftTrigger); + output.left_trigger.set_value(1.0); + } + AnalogSide::Right => { + output.buttons.enable_button(ButtonCode::RightTrigger); + output.right_trigger.set_value(1.0) + } + }, + } } - } - }); + }); + } output } diff --git a/gamercade_console/src/console/input/mod.rs b/gamercade_console/src/console/input/mod.rs index 5d62dce6..21fd6f19 100644 --- a/gamercade_console/src/console/input/mod.rs +++ b/gamercade_console/src/console/input/mod.rs @@ -21,3 +21,7 @@ impl Default for InputMode { Self::Emulated } } + +use serde::{Deserialize, Serialize}; +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)] +pub(crate) struct LocalControllerId(pub(crate) usize); diff --git a/gamercade_console/src/main.rs b/gamercade_console/src/main.rs index e2d516ee..41201f17 100644 --- a/gamercade_console/src/main.rs +++ b/gamercade_console/src/main.rs @@ -171,12 +171,12 @@ fn main() -> Result<(), Box> { let shared_mouse = std::mem::take(&mut mouse_events); // Generate all local inputs - // TODO: Refactor this to handle multiple local players correctly for handle in session.local_player_handles() { session .add_local_input( handle, input_manager.generate_input_state( + handle, &pixels, &shared_mouse, &input, From b18fce89349fced58075199418e86d5c2430b07c Mon Sep 17 00:00:00 2001 From: RobDavenport Date: Thu, 29 Sep 2022 22:40:35 +0900 Subject: [PATCH 3/7] add local controller mapping --- .../console/contexts/multiplayer_context.rs | 2 +- .../src/console/input/local_input_manager.rs | 17 +++-------- gamercade_console/src/console/input/mod.rs | 2 +- gamercade_console/src/gui/mod.rs | 28 ++++++++----------- gamercade_console/src/main.rs | 10 ++++--- 5 files changed, 24 insertions(+), 35 deletions(-) diff --git a/gamercade_console/src/console/contexts/multiplayer_context.rs b/gamercade_console/src/console/contexts/multiplayer_context.rs index 515b52af..ac2f158d 100644 --- a/gamercade_console/src/console/contexts/multiplayer_context.rs +++ b/gamercade_console/src/console/contexts/multiplayer_context.rs @@ -4,7 +4,7 @@ use crate::{api::MultiplayerApi, console::SessionDescriptor}; #[derive(Clone)] pub struct MultiplayerContext { - session: SessionDescriptor, + pub(crate) session: SessionDescriptor, } impl MultiplayerContext { diff --git a/gamercade_console/src/console/input/local_input_manager.rs b/gamercade_console/src/console/input/local_input_manager.rs index 78057ce8..e3251e77 100644 --- a/gamercade_console/src/console/input/local_input_manager.rs +++ b/gamercade_console/src/console/input/local_input_manager.rs @@ -1,7 +1,5 @@ use gamercade_core::{ButtonCode, InputState, MouseState}; -use ggrs::PlayerHandle; use gilrs::{Axis, Button, Gamepad, GamepadId, Gilrs}; -use hashbrown::HashMap; use pixels::Pixels; use winit_input_helper::WinitInputHelper; @@ -28,7 +26,6 @@ pub struct LocalInputManager { keybinds: KeyBindings, gamepad_binds: GamepadBindings, pub(crate) input_mode: InputMode, - network_to_local: HashMap, } impl LocalInputManager { @@ -36,21 +33,20 @@ impl LocalInputManager { Self { keybinds: KeyBindings::load(), gamepad_binds: GamepadBindings::default(), - network_to_local: HashMap::default(), input_mode, } } pub fn generate_input_state( &self, - player_handle: PlayerHandle, + local_controller: LocalControllerId, pixels: &Pixels, mouse_events: &MouseEventCollector, helper: &winit_input_helper::WinitInputHelper, gilrs: &Gilrs, ) -> NetworkInputState { let input_state = match self.input_mode { - InputMode::Emulated => self.new_emulated_state(player_handle, helper), + InputMode::Emulated => self.new_emulated_state(local_controller, helper), InputMode::Gamepad(id) => self.new_gamepad_state(id, gilrs), }; @@ -64,17 +60,12 @@ impl LocalInputManager { fn new_emulated_state( &self, - player_handle: PlayerHandle, + local_controller: LocalControllerId, helper: &winit_input_helper::WinitInputHelper, ) -> InputState { - if let Some(local_controller) = self.network_to_local.get(&player_handle) { - generate_emulated_state(*local_controller, &self.keybinds, helper) - } else { - InputState::default() - } + generate_emulated_state(local_controller, &self.keybinds, helper) } - //TODO: This fn new_gamepad_state(&self, id: GamepadId, gilrs: &Gilrs) -> InputState { if let Some(gamepad) = gilrs.connected_gamepad(id) { generate_gamepad_state(&self.gamepad_binds, &gamepad) diff --git a/gamercade_console/src/console/input/mod.rs b/gamercade_console/src/console/input/mod.rs index 21fd6f19..05cf3d89 100644 --- a/gamercade_console/src/console/input/mod.rs +++ b/gamercade_console/src/console/input/mod.rs @@ -24,4 +24,4 @@ impl Default for InputMode { use serde::{Deserialize, Serialize}; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)] -pub(crate) struct LocalControllerId(pub(crate) usize); +pub struct LocalControllerId(pub usize); diff --git a/gamercade_console/src/gui/mod.rs b/gamercade_console/src/gui/mod.rs index d7b21e33..51499f5e 100644 --- a/gamercade_console/src/gui/mod.rs +++ b/gamercade_console/src/gui/mod.rs @@ -166,7 +166,7 @@ impl Gui { .add_enabled(self.game_file.is_some() && session.is_none(), launch_game) .clicked() { - self.try_launch_game(pixels, window, session) + *session = self.try_launch_game(pixels, window); } let buttons_enabled = self.game_file.is_some() && session.is_some(); @@ -197,12 +197,11 @@ impl Gui { seed: u64, pixels: &mut Pixels, window: &Window, - session: &mut Option>, - ) { + ) -> Option> { let rom = match Rom::try_load(&game_path) { Err(e) => { println!("{}", e); - return; + return None; } Ok(rom) => rom, }; @@ -215,7 +214,7 @@ impl Gui { port: 8000, }; - self.init_with_console(seed, rom, pixels, window, session_descriptor, session); + Some(self.init_with_console(seed, rom, pixels, window, session_descriptor)) } fn init_with_console( @@ -225,8 +224,7 @@ impl Gui { pixels: &mut Pixels, window: &Window, session_descriptor: SessionDescriptor, - session: &mut Option>, - ) { + ) -> P2PSession { pixels.resize_buffer(rom.width() as u32, rom.height() as u32); window.set_inner_size(PhysicalSize::new( rom.width().max(DEFAULT_WINDOW_RESOLUTION.width()), @@ -242,8 +240,6 @@ impl Gui { (new_session.max_prediction(), new_session) }; - *session = Some(new_session); - self.window_open = false; let (mut console, reset) = WasmConsole::new(rom, seed, session_descriptor, max_prediction); @@ -251,14 +247,14 @@ impl Gui { self.wasm_console = Some(console); self.initial_state = Some(reset); + new_session } pub(crate) fn try_launch_game( &mut self, pixels: &mut Pixels, window: &Window, - session: &mut Option>, - ) { + ) -> Option> { let path = self.game_file.as_ref().unwrap(); let (players, port) = match self.play_mode { PlayMode::SinglePlayer => (vec![PlayerType::Local], 8000), @@ -268,10 +264,10 @@ impl Gui { if remote_addr.is_err() { println!("Remote Addr is invalid"); - return; + return None; } else if port.is_err() { println!("Port is invalid"); - return; + return None; } let player_num = self.player_num; @@ -284,7 +280,7 @@ impl Gui { vec![PlayerType::Remote(remote_addr), PlayerType::Local] } else { println!("Player # should be 1 or 2"); - return; + return None; }; (players, port) @@ -296,7 +292,7 @@ impl Gui { let rom = match Rom::try_load(path) { Err(e) => { println!("{}", e); - return; + return None; } Ok(rom) => rom, }; @@ -315,7 +311,7 @@ impl Gui { let seed = u64::from_str_radix(&self.seed, 16).unwrap(); - self.init_with_console(seed, rom, pixels, window, session_descriptor, session); + Some(self.init_with_console(seed, rom, pixels, window, session_descriptor)) } } diff --git a/gamercade_console/src/main.rs b/gamercade_console/src/main.rs index 41201f17..a840df43 100644 --- a/gamercade_console/src/main.rs +++ b/gamercade_console/src/main.rs @@ -25,7 +25,7 @@ use crate::{ console::LocalInputManager, gui::{framework::Framework, Gui}, }; -use console::{Console, InputMode, MouseEventCollector, WasmConsole}; +use console::{Console, InputMode, LocalControllerId, MouseEventCollector, WasmConsole}; #[derive(Parser, Debug)] struct Cli { @@ -63,9 +63,9 @@ fn main() -> Result<(), Box> { if let Some(game_path) = &cli.game { let seed = fastrand::u64(0..u64::MAX); - framework + session = framework .gui - .fast_launch_game(game_path.clone(), seed, &mut pixels, &window, &mut session); + .fast_launch_game(game_path.clone(), seed, &mut pixels, &window); } let mut mouse_events = MouseEventCollector::default(); @@ -171,12 +171,13 @@ fn main() -> Result<(), Box> { let shared_mouse = std::mem::take(&mut mouse_events); // Generate all local inputs + let mut local_player_id = LocalControllerId(0); for handle in session.local_player_handles() { session .add_local_input( handle, input_manager.generate_input_state( - handle, + local_player_id, &pixels, &shared_mouse, &input, @@ -184,6 +185,7 @@ fn main() -> Result<(), Box> { ), ) .unwrap(); + local_player_id.0 += 1; } // Update internal state From 6938d8fe38080c789f30cf4cec2a7ef46aee53d8 Mon Sep 17 00:00:00 2001 From: RobDavenport Date: Thu, 29 Sep 2022 23:53:30 +0900 Subject: [PATCH 4/7] add support for multiple local controllers --- gamercade_console/src/gui/controller_gui.rs | 32 +++++ gamercade_console/src/gui/mod.rs | 126 +++-------------- gamercade_console/src/gui/play_mode_gui.rs | 149 ++++++++++++++++++++ 3 files changed, 197 insertions(+), 110 deletions(-) create mode 100644 gamercade_console/src/gui/controller_gui.rs create mode 100644 gamercade_console/src/gui/play_mode_gui.rs diff --git a/gamercade_console/src/gui/controller_gui.rs b/gamercade_console/src/gui/controller_gui.rs new file mode 100644 index 00000000..a027a472 --- /dev/null +++ b/gamercade_console/src/gui/controller_gui.rs @@ -0,0 +1,32 @@ +use egui::{ComboBox, Ui}; +use gilrs::Gilrs; + +use crate::console::{InputMode, LocalInputManager}; + +#[derive(Default)] +pub struct ControllerGui {} + +impl ControllerGui { + pub(crate) fn draw(&self, ui: &mut Ui, input: &mut LocalInputManager, gilrs: &Gilrs) { + ui.group(|ui| { + ui.label("Controller Settings:"); + let combo_text = match input.input_mode { + InputMode::Emulated => String::from("Keyboard"), + InputMode::Gamepad(id) => format!("Gamepad: {}", id), + }; + ComboBox::from_label("Select Controller") + .selected_text(combo_text) + .show_ui(ui, |ui| { + ui.selectable_value(&mut input.input_mode, InputMode::Emulated, "Keyboard"); + + gilrs.gamepads().for_each(|(id, name)| { + ui.selectable_value( + &mut input.input_mode, + InputMode::Gamepad(id), + name.name(), + ); + }); + }); + }); + } +} diff --git a/gamercade_console/src/gui/mod.rs b/gamercade_console/src/gui/mod.rs index 51499f5e..585cd6b9 100644 --- a/gamercade_console/src/gui/mod.rs +++ b/gamercade_console/src/gui/mod.rs @@ -1,6 +1,6 @@ use std::{net::SocketAddr, path::PathBuf}; -use egui::{Button, ComboBox, Context, Slider}; +use egui::{Button, Context}; use gamercade_fs::Rom; use ggrs::{P2PSession, PlayerType, SessionBuilder, SessionState, UdpNonBlockingSocket}; @@ -10,23 +10,26 @@ use rfd::FileDialog; use winit::{dpi::PhysicalSize, window::Window}; use crate::{ - console::{InputMode, LocalInputManager, SessionDescriptor, WasmConsole, WasmConsoleState}, + console::{LocalInputManager, SessionDescriptor, WasmConsole, WasmConsoleState}, DEFAULT_WINDOW_RESOLUTION, }; +use self::{controller_gui::ControllerGui, play_mode_gui::PlayModeGui}; +pub mod controller_gui; pub mod framework; +pub mod play_mode_gui; pub struct Gui { pub window_open: bool, pub game_file: Option, - pub play_mode: PlayMode, - pub remote_addr: String, - pub player_num: usize, - pub port: String, + pub seed: String, pub wasm_console: Option, pub initial_state: Option, + + pub play_mode_gui: PlayModeGui, + pub controller_gui: ControllerGui, } const DEFAULT_SEED: &str = "a12cade"; @@ -37,22 +40,16 @@ impl Default for Gui { seed: DEFAULT_SEED.to_string(), window_open: true, game_file: None, - play_mode: PlayMode::SinglePlayer, - remote_addr: String::new(), - player_num: 1, - port: String::new(), + wasm_console: None, initial_state: None, + + play_mode_gui: PlayModeGui::default(), + controller_gui: ControllerGui::default(), } } } -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum PlayMode { - SinglePlayer, - Networked, -} - impl Gui { fn ui( &mut self, @@ -95,58 +92,9 @@ impl Gui { }) }); - ui.group(|ui| { - ui.label("Controller Settings:"); - let combo_text = match input.input_mode { - InputMode::Emulated => String::from("Keyboard"), - InputMode::Gamepad(id) => format!("Gamepad: {}", id), - }; - ComboBox::from_label("Select Controller") - .selected_text(combo_text) - .show_ui(ui, |ui| { - ui.selectable_value( - &mut input.input_mode, - InputMode::Emulated, - "Keyboard", - ); - - gilrs.gamepads().for_each(|(id, name)| { - ui.selectable_value( - &mut input.input_mode, - InputMode::Gamepad(id), - name.name(), - ); - }); - }); - }); - - ui.group(|ui| { - ui.label("Play Mode:"); - ui.horizontal(|ui| { - ui.selectable_value( - &mut self.play_mode, - PlayMode::SinglePlayer, - "Single Player", - ); - ui.selectable_value(&mut self.play_mode, PlayMode::Networked, "Networked"); - }); - - let enabled = self.play_mode == PlayMode::Networked; - - if enabled { - ui.horizontal(|ui| { - ui.label("Remote Address:"); - ui.text_edit_singleline(&mut self.remote_addr); - }); + self.controller_gui.draw(ui, input, gilrs); - ui.add(Slider::new(&mut self.player_num, 1..=2).text("Player Number")); - - ui.horizontal(|ui| { - ui.label("Local Port: "); - ui.text_edit_singleline(&mut self.port); - }); - } - }); + self.play_mode_gui.draw(ui); let launch_game_text = if let Some(session) = session { if session.current_state() == SessionState::Synchronizing { @@ -256,38 +204,8 @@ impl Gui { window: &Window, ) -> Option> { let path = self.game_file.as_ref().unwrap(); - let (players, port) = match self.play_mode { - PlayMode::SinglePlayer => (vec![PlayerType::Local], 8000), - PlayMode::Networked => { - let remote_addr = self.remote_addr.parse::(); - let port = self.port.parse::(); - - if remote_addr.is_err() { - println!("Remote Addr is invalid"); - return None; - } else if port.is_err() { - println!("Port is invalid"); - return None; - } - - let player_num = self.player_num; - let remote_addr = remote_addr.unwrap(); - let port = port.unwrap(); - - let players = if player_num == 1 { - vec![PlayerType::Local, PlayerType::Remote(remote_addr)] - } else if player_num == 2 { - vec![PlayerType::Remote(remote_addr), PlayerType::Local] - } else { - println!("Player # should be 1 or 2"); - return None; - }; - (players, port) - } - }; - - let players = players.into_boxed_slice(); + let session_descriptor = self.play_mode_gui.generate_session_descriptor()?; let rom = match Rom::try_load(path) { Err(e) => { @@ -297,18 +215,6 @@ impl Gui { Ok(rom) => rom, }; - let num_players = if self.play_mode == PlayMode::SinglePlayer { - 1 - } else { - 2 - }; - - let session_descriptor = SessionDescriptor { - num_players, - player_types: players, - port, - }; - let seed = u64::from_str_radix(&self.seed, 16).unwrap(); Some(self.init_with_console(seed, rom, pixels, window, session_descriptor)) diff --git a/gamercade_console/src/gui/play_mode_gui.rs b/gamercade_console/src/gui/play_mode_gui.rs new file mode 100644 index 00000000..39a22c0a --- /dev/null +++ b/gamercade_console/src/gui/play_mode_gui.rs @@ -0,0 +1,149 @@ +use std::net::SocketAddr; + +use egui::{Slider, Ui}; +use ggrs::PlayerType; + +use crate::console::SessionDescriptor; + +#[derive(Eq, PartialEq)] +pub(crate) enum PlayMode { + Local, + Networked(Networked), +} + +#[derive(PartialEq, Eq)] +pub(crate) struct Networked { + pub(crate) remote_addr: String, + pub(crate) instance_id: usize, + pub(crate) remote_player_count: usize, + pub(crate) port: String, +} + +impl Default for Networked { + fn default() -> Self { + Self { + remote_addr: Default::default(), + instance_id: 1, + remote_player_count: 1, + port: Default::default(), + } + } +} + +impl Default for PlayModeGui { + fn default() -> Self { + Self { + play_mode: PlayMode::Local, + local_player_count: 1, + } + } +} + +pub struct PlayModeGui { + pub(crate) play_mode: PlayMode, + pub(crate) local_player_count: usize, +} + +impl PlayModeGui { + pub(crate) fn draw(&mut self, ui: &mut Ui) { + ui.group(|ui| { + ui.label("Play Mode:"); + ui.horizontal(|ui| { + if ui + .selectable_label(matches!(self.play_mode, PlayMode::Local), "Local") + .clicked() + { + self.play_mode = PlayMode::Local + } + if ui + .selectable_label( + matches!(self.play_mode, PlayMode::Networked(..)), + "Networked", + ) + .clicked() + { + self.play_mode = PlayMode::Networked(Networked::default()) + }; + }); + + ui.add(Slider::new(&mut self.local_player_count, 1..=4).text("Local Player Count")); + + if let PlayMode::Networked(networked) = &mut self.play_mode { + ui.horizontal(|ui| { + ui.label("Local Port: "); + ui.text_edit_singleline(&mut networked.port); + }); + + ui.add(Slider::new(&mut networked.instance_id, 1..=2).text("Unique Instance Id")); + + ui.separator(); + + ui.horizontal(|ui| { + ui.label("Remote Address:"); + ui.text_edit_singleline(&mut networked.remote_addr); + }); + + ui.add( + Slider::new(&mut networked.remote_player_count, 1..=4) + .text("Remote Player Count"), + ); + } + }); + } + + pub(crate) fn generate_session_descriptor(&self) -> Option { + let mut player_types = Vec::new(); + + let port = match &self.play_mode { + PlayMode::Local => { + player_types + .extend(std::iter::repeat(PlayerType::Local).take(self.local_player_count)); + 8000 + } + PlayMode::Networked(networked) => { + let remote_addr = networked.remote_addr.parse::(); + let port = networked.port.parse::(); + + if remote_addr.is_err() { + println!("Remote Addr is invalid"); + return None; + } else if port.is_err() { + println!("Port is invalid"); + return None; + } + + let remote_addr = remote_addr.unwrap(); + let port = port.unwrap(); + + if networked.instance_id == 1 { + player_types + .extend(std::iter::repeat(PlayerType::Local).take(self.local_player_count)); + player_types.extend( + std::iter::repeat(PlayerType::Remote(remote_addr)) + .take(networked.remote_player_count), + ); + } else if networked.instance_id == 2 { + player_types.extend( + std::iter::repeat(PlayerType::Remote(remote_addr)) + .take(networked.remote_player_count), + ); + player_types + .extend(std::iter::repeat(PlayerType::Local).take(self.local_player_count)); + } else { + println!("Player # should be 1 or 2"); + return None; + }; + + port + } + }; + + let player_types = player_types.into_boxed_slice(); + + Some(SessionDescriptor { + num_players: player_types.len(), + player_types, + port, + }) + } +} From 7929562b98bcbaf7d1306274c6a92c4a0771829d Mon Sep 17 00:00:00 2001 From: RobDavenport Date: Fri, 30 Sep 2022 01:19:54 +0900 Subject: [PATCH 5/7] add multiple controller support --- .../src/console/input/key_bindings.rs | 14 +--- .../src/console/input/local_input_manager.rs | 29 +++---- gamercade_console/src/console/input/mod.rs | 15 ++-- gamercade_console/src/gui/controller_gui.rs | 76 ++++++++++++++----- gamercade_console/src/gui/mod.rs | 7 +- gamercade_console/src/gui/play_mode_gui.rs | 16 ++-- gamercade_console/src/main.rs | 6 +- 7 files changed, 97 insertions(+), 66 deletions(-) diff --git a/gamercade_console/src/console/input/key_bindings.rs b/gamercade_console/src/console/input/key_bindings.rs index f9379bd5..21755eef 100644 --- a/gamercade_console/src/console/input/key_bindings.rs +++ b/gamercade_console/src/console/input/key_bindings.rs @@ -6,10 +6,7 @@ use hashbrown::HashMap; use serde::{Deserialize, Serialize}; use winit::event::VirtualKeyCode; -use super::{ - key_types::{Analog, AnalogAxis, AnalogDirection, AnalogSide, KeyType}, - LocalControllerId, -}; +use super::key_types::{Analog, AnalogAxis, AnalogDirection, AnalogSide, KeyType}; const INPUT_FILE_NAME: &str = "input.json"; @@ -35,7 +32,7 @@ impl Analog { #[derive(Debug, Serialize, Deserialize)] #[serde(transparent)] pub(crate) struct KeyBindings { - pub buttons: HashMap>, + pub buttons: Vec>, } impl KeyBindings { @@ -78,7 +75,7 @@ impl KeyBindings { impl Default for KeyBindings { fn default() -> Self { - let p0 = [ + let buttons = vec![[ //Sticks (VirtualKeyCode::X, KeyType::Button(ButtonCode::LeftStick)), (VirtualKeyCode::B, KeyType::Button(ButtonCode::RightStick)), @@ -170,10 +167,7 @@ impl Default for KeyBindings { ), ] .into_iter() - .collect::>(); - - let mut buttons = HashMap::new(); - buttons.insert(LocalControllerId(0), p0); + .collect::>()]; Self { buttons } } diff --git a/gamercade_console/src/console/input/local_input_manager.rs b/gamercade_console/src/console/input/local_input_manager.rs index e3251e77..4ac53f94 100644 --- a/gamercade_console/src/console/input/local_input_manager.rs +++ b/gamercade_console/src/console/input/local_input_manager.rs @@ -8,7 +8,7 @@ use crate::console::network::NetworkInputState; use super::{ gamepad_bindings::GamepadBindings, key_types::{AnalogSide, KeyType}, - InputMode, KeyBindings, LocalControllerId, + InputMode, KeyBindings, LocalKeyboardId, LocalPlayerId, }; #[derive(Default)] @@ -23,31 +23,32 @@ pub struct MouseEventCollector { #[derive(Debug)] pub struct LocalInputManager { - keybinds: KeyBindings, + pub(crate) keyboard_bindings: KeyBindings, gamepad_binds: GamepadBindings, - pub(crate) input_mode: InputMode, + pub(crate) player_bindings: Vec, } impl LocalInputManager { - pub fn new(input_mode: InputMode) -> Self { + pub fn new() -> Self { Self { - keybinds: KeyBindings::load(), + keyboard_bindings: KeyBindings::load(), gamepad_binds: GamepadBindings::default(), - input_mode, + player_bindings: vec![InputMode::Emulated(LocalKeyboardId(0))], } } pub fn generate_input_state( &self, - local_controller: LocalControllerId, + local_player: LocalPlayerId, pixels: &Pixels, mouse_events: &MouseEventCollector, helper: &winit_input_helper::WinitInputHelper, gilrs: &Gilrs, ) -> NetworkInputState { - let input_state = match self.input_mode { - InputMode::Emulated => self.new_emulated_state(local_controller, helper), - InputMode::Gamepad(id) => self.new_gamepad_state(id, gilrs), + let input_state = match self.player_bindings.get(local_player.0) { + Some(InputMode::Emulated(keyboard_id)) => self.new_emulated_state(*keyboard_id, helper), + Some(InputMode::Gamepad(gamepad_id)) => self.new_gamepad_state(*gamepad_id, gilrs), + None => InputState::default(), }; let mouse_state = generate_mouse_state(pixels, mouse_events, helper); @@ -60,10 +61,10 @@ impl LocalInputManager { fn new_emulated_state( &self, - local_controller: LocalControllerId, + keyboard_id: LocalKeyboardId, helper: &winit_input_helper::WinitInputHelper, ) -> InputState { - generate_emulated_state(local_controller, &self.keybinds, helper) + generate_emulated_state(keyboard_id, &self.keyboard_bindings, helper) } fn new_gamepad_state(&self, id: GamepadId, gilrs: &Gilrs) -> InputState { @@ -109,13 +110,13 @@ fn generate_gamepad_state(binds: &GamepadBindings, gamepad: &Gamepad) -> InputSt } fn generate_emulated_state( - player_id: LocalControllerId, + player_id: LocalKeyboardId, binds: &KeyBindings, input_helper: &winit_input_helper::WinitInputHelper, ) -> InputState { let mut output = InputState::default(); - if let Some(buttons) = binds.buttons.get(&player_id) { + if let Some(buttons) = binds.buttons.get(player_id.0) { buttons.iter().for_each(|(code, input)| { if input_helper.key_held(*code) { match input { diff --git a/gamercade_console/src/console/input/mod.rs b/gamercade_console/src/console/input/mod.rs index 05cf3d89..2c0f7b34 100644 --- a/gamercade_console/src/console/input/mod.rs +++ b/gamercade_console/src/console/input/mod.rs @@ -9,19 +9,16 @@ use key_bindings::*; pub use local_input_manager::*; pub use player_input_entry::*; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone)] #[allow(dead_code)] pub enum InputMode { - Emulated, + Emulated(LocalKeyboardId), Gamepad(GamepadId), } -impl Default for InputMode { - fn default() -> Self { - Self::Emulated - } -} - use serde::{Deserialize, Serialize}; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)] -pub struct LocalControllerId(pub usize); +pub struct LocalKeyboardId(pub usize); + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)] +pub struct LocalPlayerId(pub usize); diff --git a/gamercade_console/src/gui/controller_gui.rs b/gamercade_console/src/gui/controller_gui.rs index a027a472..76022211 100644 --- a/gamercade_console/src/gui/controller_gui.rs +++ b/gamercade_console/src/gui/controller_gui.rs @@ -1,31 +1,69 @@ -use egui::{ComboBox, Ui}; +use egui::{ComboBox, Slider, Ui}; use gilrs::Gilrs; -use crate::console::{InputMode, LocalInputManager}; +use crate::console::{InputMode, LocalInputManager, LocalKeyboardId}; -#[derive(Default)] -pub struct ControllerGui {} +pub struct ControllerGui { + pub local_player_count: usize, +} + +impl Default for ControllerGui { + fn default() -> Self { + Self { + local_player_count: 1, + } + } +} impl ControllerGui { - pub(crate) fn draw(&self, ui: &mut Ui, input: &mut LocalInputManager, gilrs: &Gilrs) { + pub(crate) fn draw( + &mut self, + ui: &mut Ui, + can_adjust_player_count: bool, + input: &mut LocalInputManager, + gilrs: &Gilrs, + ) { ui.group(|ui| { ui.label("Controller Settings:"); - let combo_text = match input.input_mode { - InputMode::Emulated => String::from("Keyboard"), - InputMode::Gamepad(id) => format!("Gamepad: {}", id), + + if ui + .add_enabled( + can_adjust_player_count, + Slider::new(&mut self.local_player_count, 1..=4).text("Local Player Count"), + ) + .changed() + { + input.player_bindings.resize( + self.local_player_count, + InputMode::Emulated(LocalKeyboardId(0)), + ); }; - ComboBox::from_label("Select Controller") - .selected_text(combo_text) - .show_ui(ui, |ui| { - ui.selectable_value(&mut input.input_mode, InputMode::Emulated, "Keyboard"); - gilrs.gamepads().for_each(|(id, name)| { - ui.selectable_value( - &mut input.input_mode, - InputMode::Gamepad(id), - name.name(), - ); - }); + input + .player_bindings + .iter_mut() + .enumerate() + .for_each(|(player_id, input_mode)| { + let combo_text = format!("{:?}", input_mode); + ComboBox::from_label(format!("Player {} Settings:", player_id)) + .selected_text(combo_text) + .show_ui(ui, |ui| { + (0..input.keyboard_bindings.buttons.len()).for_each(|keyboard_index| { + ui.selectable_value( + input_mode, + InputMode::Emulated(LocalKeyboardId(keyboard_index)), + format!("Keyboard {}", keyboard_index), + ); + }); + + gilrs.gamepads().for_each(|(id, name)| { + ui.selectable_value( + input_mode, + InputMode::Gamepad(id), + name.name(), + ); + }); + }); }); }); } diff --git a/gamercade_console/src/gui/mod.rs b/gamercade_console/src/gui/mod.rs index 585cd6b9..a64153c6 100644 --- a/gamercade_console/src/gui/mod.rs +++ b/gamercade_console/src/gui/mod.rs @@ -92,7 +92,8 @@ impl Gui { }) }); - self.controller_gui.draw(ui, input, gilrs); + self.controller_gui + .draw(ui, session.is_none(), input, gilrs); self.play_mode_gui.draw(ui); @@ -205,7 +206,9 @@ impl Gui { ) -> Option> { let path = self.game_file.as_ref().unwrap(); - let session_descriptor = self.play_mode_gui.generate_session_descriptor()?; + let session_descriptor = self + .play_mode_gui + .generate_session_descriptor(self.controller_gui.local_player_count)?; let rom = match Rom::try_load(path) { Err(e) => { diff --git a/gamercade_console/src/gui/play_mode_gui.rs b/gamercade_console/src/gui/play_mode_gui.rs index 39a22c0a..b5da78b8 100644 --- a/gamercade_console/src/gui/play_mode_gui.rs +++ b/gamercade_console/src/gui/play_mode_gui.rs @@ -34,14 +34,12 @@ impl Default for PlayModeGui { fn default() -> Self { Self { play_mode: PlayMode::Local, - local_player_count: 1, } } } pub struct PlayModeGui { pub(crate) play_mode: PlayMode, - pub(crate) local_player_count: usize, } impl PlayModeGui { @@ -66,8 +64,6 @@ impl PlayModeGui { }; }); - ui.add(Slider::new(&mut self.local_player_count, 1..=4).text("Local Player Count")); - if let PlayMode::Networked(networked) = &mut self.play_mode { ui.horizontal(|ui| { ui.label("Local Port: "); @@ -91,13 +87,15 @@ impl PlayModeGui { }); } - pub(crate) fn generate_session_descriptor(&self) -> Option { + pub(crate) fn generate_session_descriptor( + &self, + local_player_count: usize, + ) -> Option { let mut player_types = Vec::new(); let port = match &self.play_mode { PlayMode::Local => { - player_types - .extend(std::iter::repeat(PlayerType::Local).take(self.local_player_count)); + player_types.extend(std::iter::repeat(PlayerType::Local).take(local_player_count)); 8000 } PlayMode::Networked(networked) => { @@ -117,7 +115,7 @@ impl PlayModeGui { if networked.instance_id == 1 { player_types - .extend(std::iter::repeat(PlayerType::Local).take(self.local_player_count)); + .extend(std::iter::repeat(PlayerType::Local).take(local_player_count)); player_types.extend( std::iter::repeat(PlayerType::Remote(remote_addr)) .take(networked.remote_player_count), @@ -128,7 +126,7 @@ impl PlayModeGui { .take(networked.remote_player_count), ); player_types - .extend(std::iter::repeat(PlayerType::Local).take(self.local_player_count)); + .extend(std::iter::repeat(PlayerType::Local).take(local_player_count)); } else { println!("Player # should be 1 or 2"); return None; diff --git a/gamercade_console/src/main.rs b/gamercade_console/src/main.rs index a840df43..3d2c0f6a 100644 --- a/gamercade_console/src/main.rs +++ b/gamercade_console/src/main.rs @@ -25,7 +25,7 @@ use crate::{ console::LocalInputManager, gui::{framework::Framework, Gui}, }; -use console::{Console, InputMode, LocalControllerId, MouseEventCollector, WasmConsole}; +use console::{Console, LocalPlayerId, MouseEventCollector, WasmConsole}; #[derive(Parser, Debug)] struct Cli { @@ -49,7 +49,7 @@ fn main() -> Result<(), Box> { let mut gilrs = Gilrs::new().unwrap(); let mut input = WinitInputHelper::new(); - let mut input_manager = LocalInputManager::new(InputMode::default()); + let mut input_manager = LocalInputManager::new(); let mut last_update = Instant::now(); let mut accumulator = Duration::ZERO; @@ -171,7 +171,7 @@ fn main() -> Result<(), Box> { let shared_mouse = std::mem::take(&mut mouse_events); // Generate all local inputs - let mut local_player_id = LocalControllerId(0); + let mut local_player_id = LocalPlayerId(0); for handle in session.local_player_handles() { session .add_local_input( From 603d3ce61e737a50ada249b92a74884326f5bcb5 Mon Sep 17 00:00:00 2001 From: RobDavenport Date: Fri, 30 Sep 2022 03:30:09 +0900 Subject: [PATCH 6/7] improve input config file clarity --- .gitignore | 2 +- .../src/console/contexts/input_context.rs | 8 +- .../src/console/input/gamepad_bindings.rs | 8 +- .../src/console/input/key_bindings.rs | 91 +++++-------------- .../src/console/input/key_types.rs | 39 ++++---- .../src/console/input/local_input_manager.rs | 63 ++++++++++++- gamercade_core/src/input/input_code.rs | 32 +++---- 7 files changed, 122 insertions(+), 121 deletions(-) diff --git a/.gitignore b/.gitignore index 9d8e4df1..46424056 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ /target -/input.json \ No newline at end of file +/keyboardInput.json \ No newline at end of file diff --git a/gamercade_console/src/console/contexts/input_context.rs b/gamercade_console/src/console/contexts/input_context.rs index 9d6a4382..aff84620 100644 --- a/gamercade_console/src/console/contexts/input_context.rs +++ b/gamercade_console/src/console/contexts/input_context.rs @@ -187,10 +187,10 @@ macro_rules! derive_generate_input_api { derive_generate_input_api! { Buttons { - a: A, - b: B, - c: C, - d: D, + a: ButtonA, + b: ButtonB, + c: ButtonC, + d: ButtonD, up: Up, down: Down, left: Left, diff --git a/gamercade_console/src/console/input/gamepad_bindings.rs b/gamercade_console/src/console/input/gamepad_bindings.rs index 22d41496..e58aac71 100644 --- a/gamercade_console/src/console/input/gamepad_bindings.rs +++ b/gamercade_console/src/console/input/gamepad_bindings.rs @@ -14,10 +14,10 @@ impl Default for GamepadBindings { (Button::DPadDown, ButtonCode::Down), (Button::DPadLeft, ButtonCode::Left), (Button::DPadRight, ButtonCode::Right), - (Button::East, ButtonCode::A), - (Button::South, ButtonCode::B), - (Button::West, ButtonCode::C), - (Button::North, ButtonCode::D), + (Button::East, ButtonCode::ButtonA), + (Button::South, ButtonCode::ButtonB), + (Button::West, ButtonCode::ButtonC), + (Button::North, ButtonCode::ButtonD), (Button::Start, ButtonCode::Start), (Button::Select, ButtonCode::Select), (Button::LeftTrigger, ButtonCode::LeftShoulder), diff --git a/gamercade_console/src/console/input/key_bindings.rs b/gamercade_console/src/console/input/key_bindings.rs index 21755eef..0a49f83c 100644 --- a/gamercade_console/src/console/input/key_bindings.rs +++ b/gamercade_console/src/console/input/key_bindings.rs @@ -1,33 +1,14 @@ use std::path::PathBuf; -use gamercade_core::{ButtonCode, InputState}; +use gamercade_core::ButtonCode; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; use winit::event::VirtualKeyCode; -use super::key_types::{Analog, AnalogAxis, AnalogDirection, AnalogSide, KeyType}; +use super::key_types::{AnalogStick, KeyType, TriggerSide}; -const INPUT_FILE_NAME: &str = "input.json"; - -impl Analog { - pub(crate) fn adjust_input_state(self, input_state: &mut InputState) { - let value = match self.direction { - AnalogDirection::Positive => 1.0, - AnalogDirection::Negative => -1.0, - }; - - let stick = match self.side { - AnalogSide::Left => &mut input_state.left_stick, - AnalogSide::Right => &mut input_state.right_stick, - }; - - match self.axis { - AnalogAxis::X => stick.set_x_axis(value), - AnalogAxis::Y => stick.set_y_axis(value), - }; - } -} +const INPUT_FILE_NAME: &str = "keyboardInput.json"; #[derive(Debug, Serialize, Deserialize)] #[serde(transparent)] @@ -81,89 +62,63 @@ impl Default for KeyBindings { (VirtualKeyCode::B, KeyType::Button(ButtonCode::RightStick)), //Shoulders (VirtualKeyCode::E, KeyType::Button(ButtonCode::LeftShoulder)), - (VirtualKeyCode::Q, KeyType::Trigger(AnalogSide::Left)), + ( + VirtualKeyCode::Q, + KeyType::Trigger(TriggerSide::LeftTrigger), + ), ( VirtualKeyCode::R, KeyType::Button(ButtonCode::RightShoulder), ), - (VirtualKeyCode::Y, KeyType::Trigger(AnalogSide::Right)), + ( + VirtualKeyCode::Y, + KeyType::Trigger(TriggerSide::RightTrigger), + ), //DPad: (VirtualKeyCode::Up, KeyType::Button(ButtonCode::Up)), (VirtualKeyCode::Down, KeyType::Button(ButtonCode::Down)), (VirtualKeyCode::Left, KeyType::Button(ButtonCode::Left)), (VirtualKeyCode::Right, KeyType::Button(ButtonCode::Right)), //Buttons: - (VirtualKeyCode::U, KeyType::Button(ButtonCode::A)), - (VirtualKeyCode::I, KeyType::Button(ButtonCode::B)), - (VirtualKeyCode::J, KeyType::Button(ButtonCode::C)), - (VirtualKeyCode::K, KeyType::Button(ButtonCode::D)), + (VirtualKeyCode::U, KeyType::Button(ButtonCode::ButtonA)), + (VirtualKeyCode::I, KeyType::Button(ButtonCode::ButtonB)), + (VirtualKeyCode::J, KeyType::Button(ButtonCode::ButtonC)), + (VirtualKeyCode::K, KeyType::Button(ButtonCode::ButtonD)), (VirtualKeyCode::Key5, KeyType::Button(ButtonCode::Start)), (VirtualKeyCode::Key6, KeyType::Button(ButtonCode::Select)), //Left Stick Axis ( VirtualKeyCode::W, - KeyType::AnalogStick(Analog { - side: AnalogSide::Left, - axis: AnalogAxis::Y, - direction: AnalogDirection::Positive, - }), + KeyType::AnalogStick(AnalogStick::LeftYPositive), ), ( VirtualKeyCode::S, - KeyType::AnalogStick(Analog { - side: AnalogSide::Left, - axis: AnalogAxis::Y, - direction: AnalogDirection::Negative, - }), + KeyType::AnalogStick(AnalogStick::LeftYNegative), ), ( VirtualKeyCode::A, - KeyType::AnalogStick(Analog { - side: AnalogSide::Left, - axis: AnalogAxis::X, - direction: AnalogDirection::Negative, - }), + KeyType::AnalogStick(AnalogStick::LeftXNegative), ), ( VirtualKeyCode::D, - KeyType::AnalogStick(Analog { - side: AnalogSide::Left, - axis: AnalogAxis::X, - direction: AnalogDirection::Positive, - }), + KeyType::AnalogStick(AnalogStick::LeftXPositive), ), //Right Stick Axis, ( VirtualKeyCode::T, - KeyType::AnalogStick(Analog { - side: AnalogSide::Right, - axis: AnalogAxis::Y, - direction: AnalogDirection::Positive, - }), + KeyType::AnalogStick(AnalogStick::RightYPositive), ), ( VirtualKeyCode::G, - KeyType::AnalogStick(Analog { - side: AnalogSide::Right, - axis: AnalogAxis::Y, - direction: AnalogDirection::Negative, - }), + KeyType::AnalogStick(AnalogStick::RightYNegative), ), ( VirtualKeyCode::F, - KeyType::AnalogStick(Analog { - side: AnalogSide::Right, - axis: AnalogAxis::X, - direction: AnalogDirection::Negative, - }), + KeyType::AnalogStick(AnalogStick::RightXNegative), ), ( VirtualKeyCode::H, - KeyType::AnalogStick(Analog { - side: AnalogSide::Right, - axis: AnalogAxis::X, - direction: AnalogDirection::Positive, - }), + KeyType::AnalogStick(AnalogStick::RightXPositive), ), ] .into_iter() diff --git a/gamercade_console/src/console/input/key_types.rs b/gamercade_console/src/console/input/key_types.rs index 97a49953..8cbdb3d7 100644 --- a/gamercade_console/src/console/input/key_types.rs +++ b/gamercade_console/src/console/input/key_types.rs @@ -1,35 +1,28 @@ use gamercade_core::ButtonCode; use serde::{Deserialize, Serialize}; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone, Copy)] +#[serde(untagged)] pub(crate) enum KeyType { Button(ButtonCode), - AnalogStick(Analog), - Trigger(AnalogSide), + AnalogStick(AnalogStick), + Trigger(TriggerSide), } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] - -pub(crate) struct Analog { - pub(crate) side: AnalogSide, - pub(crate) axis: AnalogAxis, - pub(crate) direction: AnalogDirection, -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub(crate) enum AnalogSide { - Left, - Right, -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub(crate) enum AnalogAxis { - X, - Y, +pub(crate) enum AnalogStick { + LeftXPositive, + LeftXNegative, + LeftYPositive, + LeftYNegative, + RightXPositive, + RightXNegative, + RightYPositive, + RightYNegative, } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub(crate) enum AnalogDirection { - Positive, - Negative, +pub(crate) enum TriggerSide { + LeftTrigger, + RightTrigger, } diff --git a/gamercade_console/src/console/input/local_input_manager.rs b/gamercade_console/src/console/input/local_input_manager.rs index 4ac53f94..5a34a012 100644 --- a/gamercade_console/src/console/input/local_input_manager.rs +++ b/gamercade_console/src/console/input/local_input_manager.rs @@ -1,4 +1,4 @@ -use gamercade_core::{ButtonCode, InputState, MouseState}; +use gamercade_core::{AnalogStick as AS, ButtonCode, InputState, MouseState}; use gilrs::{Axis, Button, Gamepad, GamepadId, Gilrs}; use pixels::Pixels; use winit_input_helper::WinitInputHelper; @@ -7,7 +7,7 @@ use crate::console::network::NetworkInputState; use super::{ gamepad_bindings::GamepadBindings, - key_types::{AnalogSide, KeyType}, + key_types::{AnalogStick, KeyType, TriggerSide}, InputMode, KeyBindings, LocalKeyboardId, LocalPlayerId, }; @@ -121,13 +121,15 @@ fn generate_emulated_state( if input_helper.key_held(*code) { match input { KeyType::Button(code) => output.buttons.enable_button(*code), - KeyType::AnalogStick(emulated) => emulated.adjust_input_state(&mut output), + KeyType::AnalogStick(analog_stick) => { + adjust_input_state(analog_stick, &mut output) + } KeyType::Trigger(side) => match side { - AnalogSide::Left => { + TriggerSide::LeftTrigger => { output.buttons.enable_button(ButtonCode::LeftTrigger); output.left_trigger.set_value(1.0); } - AnalogSide::Right => { + TriggerSide::RightTrigger => { output.buttons.enable_button(ButtonCode::RightTrigger); output.right_trigger.set_value(1.0) } @@ -175,3 +177,54 @@ fn generate_mouse_state( out } + +fn adjust_input_state(analog_stick: &AnalogStick, input_state: &mut InputState) { + let value; + let stick; + let func: fn(&mut AS, f32); + + match analog_stick { + AnalogStick::LeftXPositive => { + value = 1.0; + stick = &mut input_state.left_stick; + func = AS::set_x_axis; + } + AnalogStick::LeftXNegative => { + value = -1.0; + stick = &mut input_state.left_stick; + func = AS::set_x_axis; + } + AnalogStick::LeftYPositive => { + value = 1.0; + stick = &mut input_state.left_stick; + func = AS::set_y_axis; + } + AnalogStick::LeftYNegative => { + value = -1.0; + stick = &mut input_state.left_stick; + func = AS::set_y_axis; + } + AnalogStick::RightXPositive => { + value = 1.0; + stick = &mut input_state.right_stick; + func = AS::set_x_axis; + } + AnalogStick::RightXNegative => { + value = -1.0; + stick = &mut input_state.right_stick; + func = AS::set_x_axis; + } + AnalogStick::RightYPositive => { + value = 1.0; + stick = &mut input_state.right_stick; + func = AS::set_y_axis; + } + AnalogStick::RightYNegative => { + value = -1.0; + stick = &mut input_state.right_stick; + func = AS::set_y_axis; + } + } + + func(stick, value) +} diff --git a/gamercade_core/src/input/input_code.rs b/gamercade_core/src/input/input_code.rs index 7d9e71e0..231c362b 100644 --- a/gamercade_core/src/input/input_code.rs +++ b/gamercade_core/src/input/input_code.rs @@ -12,10 +12,10 @@ pub enum ButtonCode { Right, // Buttons - A, - B, - C, - D, + ButtonA, + ButtonB, + ButtonC, + ButtonD, Start, Select, LeftShoulder, @@ -54,10 +54,10 @@ impl AsApiCode for ButtonCode { Self::Down => Self::API_DOWN, Self::Left => Self::API_LEFT, Self::Right => Self::API_RIGHT, - Self::A => Self::API_A, - Self::B => Self::API_B, - Self::C => Self::API_C, - Self::D => Self::API_D, + Self::ButtonA => Self::API_A, + Self::ButtonB => Self::API_B, + Self::ButtonC => Self::API_C, + Self::ButtonD => Self::API_D, Self::Start => Self::API_START, Self::Select => Self::API_SELECT, Self::LeftShoulder => Self::API_LEFT_SHOULDER, @@ -75,10 +75,10 @@ impl AsApiCode for ButtonCode { Self::API_DOWN => Some(Self::Down), Self::API_LEFT => Some(Self::Left), Self::API_RIGHT => Some(Self::Right), - Self::API_A => Some(Self::A), - Self::API_B => Some(Self::B), - Self::API_C => Some(Self::C), - Self::API_D => Some(Self::D), + Self::API_A => Some(Self::ButtonA), + Self::API_B => Some(Self::ButtonB), + Self::API_C => Some(Self::ButtonC), + Self::API_D => Some(Self::ButtonD), Self::API_START => Some(Self::Start), Self::API_SELECT => Some(Self::Select), Self::API_LEFT_SHOULDER => Some(Self::LeftShoulder), @@ -99,10 +99,10 @@ impl ToBitMask for ButtonCode { Self::Down => 0b1000_0000, Self::Left => 0b1_0000_0000, Self::Right => 0b10_0000_0000, - Self::A => 0b1, - Self::B => 0b10, - Self::C => 0b100, - Self::D => 0b1000, + Self::ButtonA => 0b1, + Self::ButtonB => 0b10, + Self::ButtonC => 0b100, + Self::ButtonD => 0b1000, Self::Start => 0b1_0000, Self::Select => 0b10_0000, Self::LeftShoulder => 0b100_0000_0000, From 966e74daddd44cdcda7e7823c4b840be5d2aaff0 Mon Sep 17 00:00:00 2001 From: RobDavenport Date: Fri, 30 Sep 2022 03:39:34 +0900 Subject: [PATCH 7/7] improve controller menu ui --- gamercade_console/src/gui/controller_gui.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/gamercade_console/src/gui/controller_gui.rs b/gamercade_console/src/gui/controller_gui.rs index 76022211..9f71d1a8 100644 --- a/gamercade_console/src/gui/controller_gui.rs +++ b/gamercade_console/src/gui/controller_gui.rs @@ -44,7 +44,15 @@ impl ControllerGui { .iter_mut() .enumerate() .for_each(|(player_id, input_mode)| { - let combo_text = format!("{:?}", input_mode); + let combo_text = match &input_mode { + InputMode::Emulated(keyboard_index) => { + format!("Keyboard {}", keyboard_index.0) + } + InputMode::Gamepad(gamepad_id) => { + format!("{} [{}]", gilrs.gamepad(*gamepad_id).name(), gamepad_id) + } + }; + ComboBox::from_label(format!("Player {} Settings:", player_id)) .selected_text(combo_text) .show_ui(ui, |ui| { @@ -56,11 +64,11 @@ impl ControllerGui { ); }); - gilrs.gamepads().for_each(|(id, name)| { + gilrs.gamepads().for_each(|(id, gamepad)| { ui.selectable_value( input_mode, InputMode::Gamepad(id), - name.name(), + format!("{} [{}]", gamepad.name(), id), ); }); });