diff --git a/Cargo.lock b/Cargo.lock index 1b9abbaf38..f1ca5923c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5304,6 +5304,9 @@ name = "strum" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" +dependencies = [ + "strum_macros", +] [[package]] name = "strum_macros" diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 6adba43fcf..2f89539c4c 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -110,7 +110,7 @@ rayon = "1.5" rodio = {version = "0.14", default-features = false, features = ["vorbis"]} ron = {version = "0.6", default-features = false} serde = {version = "1.0", features = [ "rc", "derive" ]} -strum = "0.21" +strum = { version = "0.21", features = ["derive"] } strum_macros = "0.21" treeculler = "0.2" tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] } diff --git a/voxygen/src/controller.rs b/voxygen/src/controller.rs index 0fdbfcc2c4..f05b038d04 100644 --- a/voxygen/src/controller.rs +++ b/voxygen/src/controller.rs @@ -1,7 +1,7 @@ //! Module containing controller-specific abstractions allowing complex //! keybindings -use crate::window::{GameInput, MenuInput}; +use crate::{game_input::GameInput, window::MenuInput}; use gilrs::{ev::Code as GilCode, Axis as GilAxis, Button as GilButton}; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; diff --git a/voxygen/src/game_input.rs b/voxygen/src/game_input.rs new file mode 100644 index 0000000000..ca89d2c15a --- /dev/null +++ b/voxygen/src/game_input.rs @@ -0,0 +1,172 @@ +use serde::{Deserialize, Serialize}; +use std::convert::AsRef; +use strum::{AsRefStr, EnumIter}; + +/// Represents a key that the game recognises after input mapping. +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + AsRefStr, + EnumIter, +)] +pub enum GameInput { + #[strum(serialize = "gameinput.primary")] + Primary, + #[strum(serialize = "gameinput.secondary")] + Secondary, + #[strum(serialize = "gameinput.block")] + Block, + #[strum(serialize = "gameinput.slot1")] + Slot1, + #[strum(serialize = "gameinput.slot2")] + Slot2, + #[strum(serialize = "gameinput.slot3")] + Slot3, + #[strum(serialize = "gameinput.slot4")] + Slot4, + #[strum(serialize = "gameinput.slot5")] + Slot5, + #[strum(serialize = "gameinput.slot6")] + Slot6, + #[strum(serialize = "gameinput.slot7")] + Slot7, + #[strum(serialize = "gameinput.slot8")] + Slot8, + #[strum(serialize = "gameinput.slot9")] + Slot9, + #[strum(serialize = "gameinput.slot10")] + Slot10, + #[strum(serialize = "gameinput.togglecursor")] + ToggleCursor, + #[strum(serialize = "gameinput.moveforward")] + MoveForward, + #[strum(serialize = "gameinput.moveback")] + MoveBack, + #[strum(serialize = "gameinput.moveleft")] + MoveLeft, + #[strum(serialize = "gameinput.moveright")] + MoveRight, + #[strum(serialize = "gameinput.jump")] + Jump, + #[strum(serialize = "gameinput.sit")] + Sit, + #[strum(serialize = "gameinput.dance")] + Dance, + #[strum(serialize = "gameinput.greet")] + Greet, + #[strum(serialize = "gameinput.glide")] + Glide, + #[strum(serialize = "gameinput.climb")] + Climb, + #[strum(serialize = "gameinput.climbdown")] + ClimbDown, + #[strum(serialize = "gameinput.swimup")] + SwimUp, + #[strum(serialize = "gameinput.swimdown")] + SwimDown, + #[strum(serialize = "gameinput.fly")] + Fly, + #[strum(serialize = "gameinput.sneak")] + Sneak, + #[strum(serialize = "gameinput.togglelantern")] + ToggleLantern, + #[strum(serialize = "gameinput.mount")] + Mount, + #[strum(serialize = "gameinput.chat")] + Chat, + #[strum(serialize = "gameinput.command")] + Command, + #[strum(serialize = "gameinput.escape")] + Escape, + #[strum(serialize = "gameinput.map")] + Map, + #[strum(serialize = "gameinput.bag")] + Bag, + #[strum(serialize = "gameinput.trade")] + Trade, + #[strum(serialize = "gameinput.social")] + Social, + #[strum(serialize = "gameinput.crafting")] + Crafting, + #[strum(serialize = "gameinput.spellbook")] + Spellbook, + #[strum(serialize = "gameinput.settings")] + Settings, + #[strum(serialize = "gameinput.toggleinterface")] + ToggleInterface, + #[strum(serialize = "gameinput.help")] + Help, + #[strum(serialize = "gameinput.toggledebug")] + ToggleDebug, + #[strum(serialize = "gameinput.fullscreen")] + Fullscreen, + #[strum(serialize = "gameinput.screenshot")] + Screenshot, + #[strum(serialize = "gameinput.toggleingameui")] + ToggleIngameUi, + #[strum(serialize = "gameinput.roll")] + Roll, + #[strum(serialize = "gameinput.respawn")] + Respawn, + #[strum(serialize = "gameinput.interact")] + Interact, + #[strum(serialize = "gameinput.togglewield")] + ToggleWield, + #[strum(serialize = "gameinput.swaploadout")] + SwapLoadout, + #[strum(serialize = "gameinput.freelook")] + FreeLook, + #[strum(serialize = "gameinput.autowalk")] + AutoWalk, + #[strum(serialize = "gameinput.cameraclamp")] + CameraClamp, + #[strum(serialize = "gameinput.cyclecamera")] + CycleCamera, + #[strum(serialize = "gameinput.select")] + Select, + #[strum(serialize = "gameinput.acceptgroupinvite")] + AcceptGroupInvite, + #[strum(serialize = "gameinput.declinegroupinvite")] + DeclineGroupInvite, + #[strum(serialize = "gameinput.mapzoomin")] + MapZoomIn, + #[strum(serialize = "gameinput.mapzoomout")] + MapZoomOut, +} + +impl GameInput { + pub fn get_localization_key(&self) -> &str { self.as_ref() } + + /// Return true if `a` and `b` are able to be bound to the same key at the + /// same time without conflict. For example, the player can't jump and climb + /// at the same time, so these can be bound to the same key. + pub fn can_share_bindings(a: GameInput, b: GameInput) -> bool { + a.get_representative_binding() == b.get_representative_binding() + } + + /// If two GameInputs are able to be bound at the same time, then they will + /// return the same value from this function (the representative value for + /// that set). This models the Find operation of a disjoint-set data + /// structure. + fn get_representative_binding(&self) -> GameInput { + match self { + GameInput::Jump => GameInput::Jump, + GameInput::Climb => GameInput::Jump, + GameInput::SwimUp => GameInput::Jump, + GameInput::Respawn => GameInput::Jump, + + GameInput::FreeLook => GameInput::FreeLook, + GameInput::AutoWalk => GameInput::FreeLook, + + _ => *self, + } + } +} diff --git a/voxygen/src/hud/bag.rs b/voxygen/src/hud/bag.rs index 82a9870d4e..343df2f232 100644 --- a/voxygen/src/hud/bag.rs +++ b/voxygen/src/hud/bag.rs @@ -6,6 +6,7 @@ use super::{ Show, CRITICAL_HP_COLOR, LOW_HP_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, }; use crate::{ + game_input::GameInput, i18n::Localization, ui::{ fonts::Fonts, @@ -13,7 +14,6 @@ use crate::{ ImageFrame, ItemTooltip, ItemTooltipManager, ItemTooltipable, Tooltip, TooltipManager, Tooltipable, }, - window::GameInput, GlobalState, }; use client::Client; diff --git a/voxygen/src/hud/buttons.rs b/voxygen/src/hud/buttons.rs index 9cf52a0e8f..67384475b5 100644 --- a/voxygen/src/hud/buttons.rs +++ b/voxygen/src/hud/buttons.rs @@ -3,9 +3,10 @@ use super::{ BLACK, CRITICAL_HP_COLOR, LOW_HP_COLOR, QUALITY_LEGENDARY, TEXT_COLOR, }; use crate::{ + game_input::GameInput, i18n::Localization, ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable}, - window::{GameInput, KeyMouse}, + window::KeyMouse, GlobalState, }; use client::Client; diff --git a/voxygen/src/hud/group.rs b/voxygen/src/hud/group.rs index f14b629323..74ee3ed8b2 100644 --- a/voxygen/src/hud/group.rs +++ b/voxygen/src/hud/group.rs @@ -7,11 +7,11 @@ use super::{ }; use crate::{ + game_input::GameInput, hud, i18n::Localization, settings::Settings, ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable}, - window::GameInput, GlobalState, }; use client::{self, Client}; diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 6239cda5a5..7cfa7ee70f 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -53,6 +53,7 @@ use trade::Trade; use crate::{ ecs::{comp as vcomp, comp::HpFloaterList}, + game_input::GameInput, hud::{img_ids::ImgsRot, prompt_dialog::DialogOutcomeEvent}, i18n::Localization, render::UiDrawer, @@ -66,7 +67,7 @@ use crate::{ self, fonts::Fonts, img_ids::Rotations, slot, slot::SlotKey, Graphic, Ingameable, ScaleMode, Ui, }, - window::{Event as WinEvent, GameInput}, + window::Event as WinEvent, GlobalState, }; use client::Client; diff --git a/voxygen/src/hud/overitem.rs b/voxygen/src/hud/overitem.rs index 0b941ff9d8..368350389b 100644 --- a/voxygen/src/hud/overitem.rs +++ b/voxygen/src/hud/overitem.rs @@ -1,8 +1,8 @@ use crate::{ + game_input::GameInput, i18n::Localization, settings::ControlSettings, ui::{fonts::Fonts, Ingameable}, - window::GameInput, }; use conrod_core::{ color, diff --git a/voxygen/src/hud/prompt_dialog.rs b/voxygen/src/hud/prompt_dialog.rs index ae9ae15770..599eca1953 100644 --- a/voxygen/src/hud/prompt_dialog.rs +++ b/voxygen/src/hud/prompt_dialog.rs @@ -1,10 +1,10 @@ use super::{img_ids::Imgs, TEXT_COLOR, UI_HIGHLIGHT_0}; use crate::{ + game_input::GameInput, hud::{Event, PromptDialogSettings}, i18n::LocalizationHandle, settings::Settings, ui::fonts::Fonts, - window::GameInput, }; use conrod_core::{ widget::{self, Button, Image, Text}, diff --git a/voxygen/src/hud/settings_window/controls.rs b/voxygen/src/hud/settings_window/controls.rs index 9e6ee55769..ee9b129ecd 100644 --- a/voxygen/src/hud/settings_window/controls.rs +++ b/voxygen/src/hud/settings_window/controls.rs @@ -1,11 +1,11 @@ use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH}; use crate::{ + game_input::GameInput, hud::{img_ids::Imgs, ERROR_COLOR, TEXT_BIND_CONFLICT_COLOR, TEXT_COLOR}, i18n::Localization, session::settings_change::{Control as ControlChange, Control::*}, ui::fonts::Fonts, - window::GameInput, GlobalState, }; use conrod_core::{ @@ -14,6 +14,7 @@ use conrod_core::{ widget::{self, Button, Rectangle, Scrollbar, Text}, widget_ids, Borderable, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, }; +use strum::IntoEnumIterator; widget_ids! { struct Ids { @@ -94,7 +95,7 @@ impl<'a> Widget for Controls<'a> { // Used for sequential placement in a flow-down pattern let mut previous_element_id = None; - let mut keybindings_vec: Vec = GameInput::iterator().collect(); + let mut keybindings_vec: Vec = GameInput::iter().collect(); keybindings_vec.sort(); let controls = &self.global_state.settings.controls; diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index dc16f30237..fa367a3ab0 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -6,6 +6,7 @@ use super::{ QUALITY_EPIC, STAMINA_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, }; use crate::{ + game_input::GameInput, hud::ComboFloater, i18n::Localization, ui::{ @@ -14,7 +15,6 @@ use crate::{ ImageFrame, ItemTooltip, ItemTooltipManager, ItemTooltipable, Tooltip, TooltipManager, Tooltipable, }, - window::GameInput, GlobalState, }; diff --git a/voxygen/src/lib.rs b/voxygen/src/lib.rs index 8f1abe6a07..304710c011 100644 --- a/voxygen/src/lib.rs +++ b/voxygen/src/lib.rs @@ -18,6 +18,7 @@ pub mod audio; pub mod controller; mod ecs; pub mod error; +pub mod game_input; pub mod hud; pub mod key_state; pub mod menu; diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index b84f57fe0b..f64aed6221 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -35,13 +35,14 @@ use common_net::{ use crate::{ audio::sfx::SfxEvent, + game_input::GameInput, hud::{DebugInfo, Event as HudEvent, Hud, HudInfo, LootMessage, PromptDialogSettings}, key_state::KeyState, menu::char_selection::CharSelectionState, render::{Drawer, GlobalsBindGroup}, scene::{camera, terrain::Interaction, CameraMode, DebugShapeId, Scene, SceneData}, settings::Settings, - window::{AnalogGameInput, Event, GameInput}, + window::{AnalogGameInput, Event}, Direction, Error, GlobalState, PlayState, PlayStateResult, }; use hashbrown::HashMap; diff --git a/voxygen/src/session/settings_change.rs b/voxygen/src/session/settings_change.rs index 6069ed5642..6f8239c141 100644 --- a/voxygen/src/session/settings_change.rs +++ b/voxygen/src/session/settings_change.rs @@ -1,6 +1,7 @@ use super::SessionState; use crate::{ controller::ControllerSettings, + game_input::GameInput, hud::{ BarNumbers, BuffPosition, ChatTab, CrosshairType, Intro, PressBehavior, ScaleChange, ShortcutNumbers, XpBar, @@ -11,7 +12,7 @@ use crate::{ AudioSettings, ChatSettings, ControlSettings, Fps, GamepadSettings, GameplaySettings, GraphicsSettings, InterfaceSettings, }, - window::{FullScreenSettings, GameInput}, + window::FullScreenSettings, GlobalState, }; use vek::*; diff --git a/voxygen/src/settings/control.rs b/voxygen/src/settings/control.rs index 4b30c54adb..7e04983de5 100644 --- a/voxygen/src/settings/control.rs +++ b/voxygen/src/settings/control.rs @@ -1,6 +1,7 @@ -use crate::window::{GameInput, KeyMouse}; +use crate::{game_input::GameInput, window::KeyMouse}; use hashbrown::{HashMap, HashSet}; use serde::{Deserialize, Serialize}; +use strum::IntoEnumIterator; use winit::event::{MouseButton, VirtualKeyCode}; // ControlSetting-like struct used by Serde, to handle not serializing/building @@ -181,7 +182,7 @@ impl Default for ControlSettings { inverse_keybindings: HashMap::new(), }; // Sets the initial keybindings for those GameInputs. - for game_input in GameInput::iterator() { + for game_input in GameInput::iter() { new_settings.insert_binding(game_input, ControlSettings::default_binding(game_input)); } new_settings diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index a5609fd415..6df984ff32 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -1,5 +1,6 @@ use crate::{ controller::*, + game_input::GameInput, render::Renderer, settings::{ControlSettings, Settings}, ui, Error, @@ -15,233 +16,6 @@ use tracing::{error, warn}; use vek::*; use winit::monitor::VideoMode; -/// Represents a key that the game recognises after input mapping. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] -pub enum GameInput { - Primary, - Secondary, - Block, - Slot1, - Slot2, - Slot3, - Slot4, - Slot5, - Slot6, - Slot7, - Slot8, - Slot9, - Slot10, - ToggleCursor, - MoveForward, - MoveBack, - MoveLeft, - MoveRight, - Jump, - Sit, - Dance, - Greet, - Glide, - Climb, - ClimbDown, - SwimUp, - SwimDown, - Fly, - Sneak, - ToggleLantern, - Mount, - Chat, - Command, - Escape, - Map, - Bag, - Trade, - Social, - Crafting, - Spellbook, - Settings, - ToggleInterface, - Help, - ToggleDebug, - Fullscreen, - Screenshot, - ToggleIngameUi, - Roll, - Respawn, - Interact, - ToggleWield, - SwapLoadout, - FreeLook, - AutoWalk, - CameraClamp, - CycleCamera, - Select, - AcceptGroupInvite, - DeclineGroupInvite, - MapZoomIn, - MapZoomOut, -} - -impl GameInput { - pub fn get_localization_key(&self) -> &str { - match *self { - GameInput::Primary => "gameinput.primary", - GameInput::Secondary => "gameinput.secondary", - GameInput::Block => "gameinput.block", - GameInput::ToggleCursor => "gameinput.togglecursor", - GameInput::MoveForward => "gameinput.moveforward", - GameInput::MoveLeft => "gameinput.moveleft", - GameInput::MoveRight => "gameinput.moveright", - GameInput::MoveBack => "gameinput.moveback", - GameInput::Jump => "gameinput.jump", - GameInput::Sit => "gameinput.sit", - GameInput::Dance => "gameinput.dance", - GameInput::Greet => "gameinput.greet", - GameInput::Glide => "gameinput.glide", - GameInput::Climb => "gameinput.climb", - GameInput::ClimbDown => "gameinput.climbdown", - GameInput::SwimUp => "gameinput.swimup", - GameInput::SwimDown => "gameinput.swimdown", - GameInput::Fly => "gameinput.fly", - GameInput::Sneak => "gameinput.sneak", - GameInput::ToggleLantern => "gameinput.togglelantern", - GameInput::Mount => "gameinput.mount", - GameInput::Chat => "gameinput.chat", - GameInput::Command => "gameinput.command", - GameInput::CycleCamera => "gameinput.cyclecamera", - GameInput::Escape => "gameinput.escape", - GameInput::Map => "gameinput.map", - GameInput::Bag => "gameinput.bag", - GameInput::Trade => "gameinput.trade", - GameInput::Social => "gameinput.social", - GameInput::Crafting => "gameinput.crafting", - GameInput::Spellbook => "gameinput.spellbook", - GameInput::Settings => "gameinput.settings", - GameInput::ToggleInterface => "gameinput.toggleinterface", - GameInput::Help => "gameinput.help", - GameInput::ToggleDebug => "gameinput.toggledebug", - GameInput::Fullscreen => "gameinput.fullscreen", - GameInput::Screenshot => "gameinput.screenshot", - GameInput::ToggleIngameUi => "gameinput.toggleingameui", - GameInput::Roll => "gameinput.roll", - GameInput::Respawn => "gameinput.respawn", - GameInput::Interact => "gameinput.interact", - GameInput::ToggleWield => "gameinput.togglewield", - GameInput::FreeLook => "gameinput.freelook", - GameInput::AutoWalk => "gameinput.autowalk", - GameInput::CameraClamp => "gameinput.cameraclamp", - GameInput::Slot1 => "gameinput.slot1", - GameInput::Slot2 => "gameinput.slot2", - GameInput::Slot3 => "gameinput.slot3", - GameInput::Slot4 => "gameinput.slot4", - GameInput::Slot5 => "gameinput.slot5", - GameInput::Slot6 => "gameinput.slot6", - GameInput::Slot7 => "gameinput.slot7", - GameInput::Slot8 => "gameinput.slot8", - GameInput::Slot9 => "gameinput.slot9", - GameInput::Slot10 => "gameinput.slot10", - GameInput::SwapLoadout => "gameinput.swaploadout", - GameInput::Select => "gameinput.select", - GameInput::AcceptGroupInvite => "gameinput.acceptgroupinvite", - GameInput::DeclineGroupInvite => "gameinput.declinegroupinvite", - GameInput::MapZoomIn => "gameinput.mapzoomin", - GameInput::MapZoomOut => "gameinput.mapzoomout", - } - } - - pub fn iterator() -> impl Iterator { - [ - GameInput::Primary, - GameInput::Secondary, - GameInput::Block, - GameInput::ToggleCursor, - GameInput::MoveForward, - GameInput::MoveLeft, - GameInput::MoveRight, - GameInput::MoveBack, - GameInput::Jump, - GameInput::Sit, - GameInput::Dance, - GameInput::Greet, - GameInput::Glide, - GameInput::Climb, - GameInput::ClimbDown, - GameInput::SwimUp, - GameInput::SwimDown, - GameInput::Fly, - GameInput::Sneak, - GameInput::ToggleLantern, - GameInput::Mount, - GameInput::Chat, - GameInput::Command, - GameInput::Escape, - GameInput::Map, - GameInput::Bag, - GameInput::Trade, - GameInput::Social, - GameInput::Crafting, - GameInput::Spellbook, - GameInput::Settings, - GameInput::ToggleInterface, - GameInput::Help, - GameInput::ToggleDebug, - GameInput::Fullscreen, - GameInput::Screenshot, - GameInput::ToggleIngameUi, - GameInput::Roll, - GameInput::Respawn, - GameInput::Interact, - GameInput::ToggleWield, - GameInput::FreeLook, - GameInput::AutoWalk, - GameInput::CameraClamp, - GameInput::Slot1, - GameInput::Slot2, - GameInput::Slot3, - GameInput::Slot4, - GameInput::Slot5, - GameInput::Slot6, - GameInput::Slot7, - GameInput::Slot8, - GameInput::Slot9, - GameInput::Slot10, - GameInput::SwapLoadout, - GameInput::CycleCamera, - GameInput::Select, - GameInput::AcceptGroupInvite, - GameInput::DeclineGroupInvite, - GameInput::MapZoomIn, - GameInput::MapZoomOut, - ] - .iter() - .copied() - } - - /// Return true if `a` and `b` are able to be bound to the same key at the - /// same time without conflict. For example, the player can't jump and climb - /// at the same time, so these can be bound to the same key. - pub fn can_share_bindings(a: GameInput, b: GameInput) -> bool { - a.get_representative_binding() == b.get_representative_binding() - } - - /// If two GameInputs are able to be bound at the same time, then they will - /// return the same value from this function (the representative value for - /// that set). This models the Find operation of a disjoint-set data - /// structure. - fn get_representative_binding(&self) -> GameInput { - match self { - GameInput::Jump => GameInput::Jump, - GameInput::Climb => GameInput::Jump, - GameInput::SwimUp => GameInput::Jump, - GameInput::Respawn => GameInput::Jump, - - GameInput::FreeLook => GameInput::FreeLook, - GameInput::AutoWalk => GameInput::FreeLook, - - _ => *self, - } - } -} - /// Represents a key that the game menus recognise after input mapping #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] pub enum MenuInput {