diff --git a/src/console/mod.rs b/src/console/mod.rs index 24df3f5..ea8ef73 100644 --- a/src/console/mod.rs +++ b/src/console/mod.rs @@ -38,6 +38,42 @@ pub struct CVar { pub default: &'static Fn() -> T, } +impl Var for CVar { + fn serialize(&self, val: &Box) -> String { + val.downcast_ref::().unwrap().to_string() + } + + fn deserialize(&self, input: &str) -> Box { + Box::new(input.parse::().unwrap()) + } + + fn description(&self) -> &'static str { + self.description + } + + fn can_serialize(&self) -> bool { + self.serializable + } +} + +impl Var for CVar { + fn serialize(&self, val: &Box) -> String { + val.downcast_ref::().unwrap().to_string() + } + + fn deserialize(&self, input: &str) -> Box { + Box::new(input.parse::().unwrap()) + } + + fn description(&self) -> &'static str { + self.description + } + + fn can_serialize(&self) -> bool { + self.serializable + } +} + impl Var for CVar { fn serialize(&self, val: &Box) -> String { format!("\"{}\"", val.downcast_ref::().unwrap()) diff --git a/src/entity/player.rs b/src/entity/player.rs index 06640d5..b7a9580 100644 --- a/src/entity/player.rs +++ b/src/entity/player.rs @@ -20,7 +20,7 @@ use cgmath::{self, Point3, Vector3, Matrix4, Decomposed, Rotation3, Rad, Angle, use std::collections::HashMap; use std::hash::BuildHasherDefault; use types::hash::FNVHash; -use sdl2::keyboard::Keycode; +use settings::Stevenkey; use shared::Position as BPosition; use format; @@ -441,7 +441,7 @@ impl ecs::System for PlayerRenderer { pub struct PlayerMovement { pub flying: bool, pub did_touch_ground: bool, - pub pressed_keys: HashMap>, + pub pressed_keys: HashMap>, } impl PlayerMovement { @@ -457,23 +457,23 @@ impl PlayerMovement { use std::f64::consts::PI; let mut forward = 0.0f64; let mut yaw = player_yaw - (PI/2.0); - if self.is_key_pressed(Keycode::W) || self.is_key_pressed(Keycode::S) { + if self.is_key_pressed(Stevenkey::Forward) || self.is_key_pressed(Stevenkey::Backward) { forward = 1.0; - if self.is_key_pressed(Keycode::S) { + if self.is_key_pressed(Stevenkey::Backward) { yaw += PI; } } let mut change = 0.0; - if self.is_key_pressed(Keycode::A) { + if self.is_key_pressed(Stevenkey::Left) { change = (PI / 2.0) / (forward.abs() + 1.0); } - if self.is_key_pressed(Keycode::D) { + if self.is_key_pressed(Stevenkey::Right) { change = -(PI / 2.0) / (forward.abs() + 1.0); } - if self.is_key_pressed(Keycode::A) || self.is_key_pressed(Keycode::D) { + if self.is_key_pressed(Stevenkey::Left) || self.is_key_pressed(Stevenkey::Right) { forward = 1.0; } - if self.is_key_pressed(Keycode::S) { + if self.is_key_pressed(Stevenkey::Backward) { yaw -= change; } else { yaw += change; @@ -482,7 +482,7 @@ impl PlayerMovement { (forward, yaw) } - fn is_key_pressed(&self, key: Keycode) -> bool { + fn is_key_pressed(&self, key: Stevenkey) -> bool { self.pressed_keys.get(&key).map_or(false, |v| *v) } } @@ -554,20 +554,20 @@ impl ecs::System for MovementHandler { if world.is_chunk_loaded((position.position.x as i32) >> 4, (position.position.z as i32) >> 4) { let (forward, yaw) = movement.calculate_movement(rotation.yaw); let mut speed = 0.21585; - if movement.is_key_pressed(Keycode::LShift) { + if movement.is_key_pressed(Stevenkey::Sprint) { speed = 0.2806; } if movement.flying { speed *= 2.5; - if movement.is_key_pressed(Keycode::Space) { + if movement.is_key_pressed(Stevenkey::Jump) { position.position.y += speed; } - if movement.is_key_pressed(Keycode::LCtrl) { + if movement.is_key_pressed(Stevenkey::Sneak) { position.position.y -= speed; } } else if gravity.as_ref().map_or(false, |v| v.on_ground) { - if movement.is_key_pressed(Keycode::Space) && velocity.velocity.y.abs() < 0.001 { + if movement.is_key_pressed(Stevenkey::Jump) && velocity.velocity.y.abs() < 0.001 { velocity.velocity.y = 0.42; } } else { diff --git a/src/main.rs b/src/main.rs index a407c4d..af89815 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,6 +48,7 @@ pub mod resources; pub mod render; pub mod ui; pub mod screen; +pub mod settings; #[macro_use] pub mod console; pub mod server; @@ -154,6 +155,7 @@ fn main() { let mut con = con.lock().unwrap(); con.register(CL_BRAND); auth::register_vars(&mut con); + settings::register_vars(&mut con); con.load_config(); con.save_config(); } @@ -297,7 +299,7 @@ fn handle_window_event(window: &sdl2::video::Window, Event::MouseButtonUp{mouse_btn: Mouse::Left, x, y, ..} => { let (width, height) = window.size(); - if game.server.is_connected() && !game.focused { + if game.server.is_connected() && !game.focused && !game.screen_sys.is_current_closable() { game.focused = true; if !mouse.relative_mouse_mode() { mouse.set_relative_mouse_mode(true); @@ -318,6 +320,11 @@ fn handle_window_event(window: &sdl2::video::Window, if game.focused { mouse.set_relative_mouse_mode(false); game.focused = false; + game.screen_sys.replace_screen(Box::new(screen::SettingsMenu::new(game.console.clone(), true))); + } else if game.screen_sys.is_current_closable() { + mouse.set_relative_mouse_mode(true); + game.focused = true; + game.screen_sys.pop_screen(); } } Event::KeyDown{keycode: Some(Keycode::Backquote), ..} => { @@ -325,14 +332,20 @@ fn handle_window_event(window: &sdl2::video::Window, } Event::KeyDown{keycode: Some(key), ..} => { if game.focused { - game.server.key_press(true, key); + let console = game.console.lock().unwrap(); + if let Some(steven_key) = settings::Stevenkey::get_by_keycode(key, &console) { + game.server.key_press(true, steven_key); + } } else { ui_container.key_press(game, key, true); } } Event::KeyUp{keycode: Some(key), ..} => { if game.focused { - game.server.key_press(false, key); + let console = game.console.lock().unwrap(); + if let Some(steven_key) = settings::Stevenkey::get_by_keycode(key, &console) { + game.server.key_press(false, steven_key); + } } else { ui_container.key_press(game, key, false); } diff --git a/src/screen/edit_server.rs b/src/screen/edit_server.rs index b29b706..5d903ec 100644 --- a/src/screen/edit_server.rs +++ b/src/screen/edit_server.rs @@ -177,4 +177,8 @@ impl super::Screen for EditServerEntry { elements.logo.tick(renderer, ui_container); None } + + fn is_closable(&self) -> bool { + true + } } diff --git a/src/screen/mod.rs b/src/screen/mod.rs index 1bd2b60..ecfe142 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -15,9 +15,12 @@ mod server_list; pub use self::server_list::*; mod login; +pub mod settings_menu; + pub use self::login::*; pub mod connecting; pub mod edit_server; +pub use self::settings_menu::{SettingsMenu, VideoSettingsMenu, AudioSettingsMenu}; use render; use ui; @@ -43,6 +46,10 @@ pub trait Screen { // Events fn on_scroll(&mut self, x: f64, y: f64) { } + + fn is_closable(&self) -> bool { + false + } } struct ScreenInfo { @@ -83,6 +90,14 @@ impl ScreenSystem { self.add_screen(screen); } + pub fn is_current_closable(&self) -> bool { + if let Some(last) = self.screens.last() { + last.screen.is_closable() + } else { + true + } + } + pub fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, diff --git a/src/screen/server_list.rs b/src/screen/server_list.rs index 7235792..900403b 100644 --- a/src/screen/server_list.rs +++ b/src/screen/server_list.rs @@ -387,7 +387,9 @@ impl super::Screen for ServerList { cog.set_parent(&re); cog.set_v_attach(ui::VAttach::Middle); cog.set_h_attach(ui::HAttach::Center); - super::button_action(ui_container, re.clone(), None, |_, _| {}); + super::button_action(ui_container, re.clone(), None, | game, _ | { + game.screen_sys.add_screen(Box::new(super::SettingsMenu::new(game.console.clone(), false))); + }); elements.add(re); elements.add(ui_container.add(cog)); diff --git a/src/screen/settings_menu.rs b/src/screen/settings_menu.rs new file mode 100644 index 0000000..f6c9185 --- /dev/null +++ b/src/screen/settings_menu.rs @@ -0,0 +1,291 @@ +use console; +use render; +use ui; +use settings; + +use std::sync::{Arc, Mutex}; + +pub fn new_submenu_button(text: &str, renderer: &mut render::Renderer, ui_container: &mut ui::Container, x: f64, y: f64) -> (ui::ElementRef, ui::ElementRef) { + let (mut btn, mut txt) = super::new_button_text(renderer, text, x, y, 300.0, 40.0); + btn.set_v_attach(ui::VAttach::Middle); + btn.set_h_attach(ui::HAttach::Center); + let ui_btn = ui_container.add(btn); + txt.set_parent(&ui_btn); + (ui_btn, ui_container.add(txt)) +} + +pub fn new_centered_button(text: &str, renderer: &mut render::Renderer, ui_container: &mut ui::Container, y: f64, vertical_attach: ui::VAttach) -> (ui::ElementRef, ui::ElementRef) { + let (mut btn, mut txt) = super::new_button_text(renderer, text, 0.0, y, 400.0, 40.0); + btn.set_v_attach(vertical_attach); + btn.set_h_attach(ui::HAttach::Center); + let ui_btn = ui_container.add(btn); + txt.set_parent(&ui_btn); + (ui_btn, ui_container.add(txt)) +} + +macro_rules! get_bool_str { + ($fmt:expr, $val:expr, $val_true:expr, $val_false:expr) => (format!($fmt, if $val { + $val_true + } else { + $val_false + }).as_ref()); + ($fmt:expr, $val:expr) => (get_bool_string!($fmt, $val, "true", "false")); +} + +macro_rules! get_matched_str { + ($fmt:expr, $val:expr, $($to_match:expr => $result:expr),*) => ( + format!($fmt, match $val { + $($to_match => $result.to_owned(), )* + _ => $val.to_string(), + }).as_ref() + ) +} + +pub struct UIElement { + elements: ui::Collection + // TODO: Add background of some sort +} + +pub struct SettingsMenu { + console: Arc>, + elements: Option, + show_disconnect_button: bool +} + +impl SettingsMenu { + pub fn new(console: Arc>, show_disconnect_button: bool) -> SettingsMenu { + SettingsMenu { + console: console, + elements: None, + show_disconnect_button: show_disconnect_button + } + } +} + +impl super::Screen for SettingsMenu { + fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + let mut elements = ui::Collection::new(); + + // From top and down + let (btn_audio_settings, txt_audio_settings) = new_submenu_button("Audio settings...", renderer, ui_container, -160.0, -50.0); + super::button_action(ui_container, btn_audio_settings.clone(), Some(txt_audio_settings.clone()), move | game, _ | { + game.screen_sys.add_screen(Box::new(AudioSettingsMenu::new(game.console.clone()))); + }); + elements.add(btn_audio_settings); + elements.add(txt_audio_settings); + + let (btn_video_settings, txt_video_settings) = new_submenu_button("Video settings...", renderer, ui_container, 160.0, -50.0); + super::button_action(ui_container, btn_video_settings.clone(), Some(txt_video_settings.clone()), move | game, _ | { + game.screen_sys.add_screen(Box::new(VideoSettingsMenu::new(game.console.clone()))); + }); + elements.add(btn_video_settings); + elements.add(txt_video_settings); + + let (btn_controls_settings, txt_controls_settings) = new_submenu_button("Controls...", renderer, ui_container, 160.0, 0.0); + super::button_action(ui_container, btn_controls_settings.clone(), Some(txt_controls_settings.clone()), move | game, _ | { + // TODO: Implement this... + }); + elements.add(btn_controls_settings); + elements.add(txt_controls_settings); + + let (btn_locale_settings, txt_locale_settings) = new_submenu_button("Language...", renderer, ui_container, -160.0, 0.0); + super::button_action(ui_container, btn_locale_settings.clone(), Some(txt_locale_settings.clone()), move | game, _ | { + // TODO: Implement this... + }); + elements.add(btn_locale_settings); + elements.add(txt_locale_settings); + + // Center bottom items + let (mut btn_back_to_game, mut txt_back_to_game) = new_centered_button("Done", renderer, ui_container, 50.0, ui::VAttach::Bottom); + super::button_action(ui_container, btn_back_to_game.clone(), Some(txt_back_to_game.clone()), move | game, _ | { + game.screen_sys.pop_screen(); + game.focused = true; + }); + elements.add(btn_back_to_game); + elements.add(txt_back_to_game); + + if self.show_disconnect_button { + let (mut btn_exit_game, mut txt_exit_game) = new_centered_button("Disconnect", renderer, ui_container, 100.0, ui::VAttach::Bottom); + super::button_action(ui_container, btn_exit_game.clone(), Some(txt_exit_game.clone()), move | game, _ | { + game.server.disconnect(); + game.screen_sys.replace_screen(Box::new(super::ServerList::new(None))); + }); + elements.add(btn_exit_game); + elements.add(txt_exit_game); + } + + self.elements = Some(UIElement { + elements: elements + }); + + } + fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + { + let elements = self.elements.as_mut().unwrap(); + elements.elements.remove_all(ui_container); + } + self.elements = None; + } + + // Called every frame the screen is active + fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Option> { + None + } + + // Events + fn on_scroll(&mut self, x: f64, y: f64) { + + } + + fn is_closable(&self) -> bool { + true + } +} + +pub struct VideoSettingsMenu { + console: Arc>, + elements: Option, + fps_bounds: Vec +} + +impl VideoSettingsMenu { + pub fn new(console: Arc>) -> VideoSettingsMenu { + VideoSettingsMenu { + console: console, + elements: None, + fps_bounds: vec!(60, 120, 144, -1) + } + } +} + +impl super::Screen for VideoSettingsMenu { + fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + let mut elements = ui::Collection::new(); + + // Load defaults + let (r_max_fps, r_fov, r_vsync) = { + let console = self.console.lock().unwrap(); + ( + console.get(settings::R_MAX_FPS).clone(), + console.get(settings::R_FOV).clone(), + console.get(settings::R_VSYNC).clone() + ) + }; + + // Setting buttons + // TODO: Slider + let (btn_fov, txt_fov) = new_submenu_button(get_matched_str!("FOV: {}", r_fov, 90 => "Normal", 110 => "Quake pro"), renderer, ui_container, -160.0, -50.0); + elements.add(btn_fov); + elements.add(txt_fov); + + let (btn_vsync, txt_vsync) = new_submenu_button(get_bool_str!("VSync: {}", r_vsync, "Enabled", "Disabled"), renderer, ui_container, -160.0, 0.0); + elements.add(txt_vsync.clone()); + super::button_action(ui_container, btn_vsync.clone(), Some(txt_vsync.clone()), move | game, ui_container | { + let mut console = game.console.lock().unwrap(); + let r_vsync = !console.get(settings::R_VSYNC); + let txt_vsync = ui_container.get_mut(&txt_vsync); + txt_vsync.set_text(&game.renderer, get_bool_str!("VSync: {}", r_vsync, "Enabled", "Disabled")); + console.set(settings::R_VSYNC, r_vsync); + }); + elements.add(btn_vsync); + + // TODO: Slider + let (btn_fps_cap, txt_fps_cap) = new_submenu_button(get_matched_str!("FPS cap: {}", r_max_fps, 0 => "Unlimited", 15 => "Potato"), renderer, ui_container, 160.0, 0.0); + elements.add(btn_fps_cap); + elements.add(txt_fps_cap); + + let (mut btn_done, mut txt_done) = new_centered_button("Done", renderer, ui_container, 50.0, ui::VAttach::Bottom); + super::button_action(ui_container, btn_done.clone(), Some(txt_done.clone()), move | game, _ | { + game.screen_sys.pop_screen(); + }); + elements.add(btn_done); + elements.add(txt_done); + self.elements = Some(UIElement { + elements: elements + }); + + } + fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + { + let elements = self.elements.as_mut().unwrap(); + elements.elements.remove_all(ui_container); + } + self.elements = None; + } + + // Called every frame the screen is active + fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Option> { + None + } + + // Events + fn on_scroll(&mut self, x: f64, y: f64) { + + } + + fn is_closable(&self) -> bool { + true + } +} + +pub struct AudioSettingsMenu { + console: Arc>, + elements: Option +} + +impl AudioSettingsMenu { + pub fn new(console: Arc>) -> AudioSettingsMenu { + AudioSettingsMenu { + console: console, + elements: None + } + } +} + +impl super::Screen for AudioSettingsMenu { + fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + let mut elements = ui::Collection::new(); + + let master_volume = { + let console = self.console.lock().unwrap(); + (console.get(settings::CL_MASTER_VOLUME).clone()) + }; + + let (mut btn_master_volume, mut txt_master_volume) = new_centered_button(master_volume.to_string().as_ref(), renderer, ui_container, -150.0, ui::VAttach::Middle); + elements.add(btn_master_volume); + elements.add(txt_master_volume); + + let (mut btn_done, mut txt_done) = new_centered_button("Done", renderer, ui_container, 50.0, ui::VAttach::Bottom); + super::button_action(ui_container, btn_done.clone(), Some(txt_done.clone()), move | game, _ | { + game.screen_sys.pop_screen(); + }); + elements.add(btn_done); + elements.add(txt_done); + + self.elements = Some(UIElement { + elements: elements + }); + + } + fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + { + let elements = self.elements.as_mut().unwrap(); + elements.elements.remove_all(ui_container); + } + self.elements = None; + } + + // Called every frame the screen is active + fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Option> { + None + } + + // Events + fn on_scroll(&mut self, x: f64, y: f64) { + + } + + fn is_closable(&self) -> bool { + true + } +} diff --git a/src/server/mod.rs b/src/server/mod.rs index ddc5c4d..87aa094 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -25,6 +25,7 @@ use types::hash::FNVHash; use resources; use console; use render; +use settings::Stevenkey; use auth; use ecs; use entity; @@ -72,7 +73,6 @@ pub struct Server { entity_map: HashMap>, players: HashMap>, - pressed_keys: HashMap>, tick_timer: f64, entity_tick_timer: f64, @@ -285,8 +285,6 @@ impl Server { resources: resources, console: console, - pressed_keys: HashMap::with_hasher(BuildHasherDefault::default()), - // Entity accessors game_info: game_info, player_movement: entities.get_key(), @@ -310,6 +308,14 @@ impl Server { } } + pub fn disconnect(&mut self) { + self.conn = None; + self.disconnect_reason = None; + if let Some(player) = self.player.take() { + self.entities.remove_entity(player); + } + } + pub fn is_connected(&self) -> bool { self.conn.is_some() } @@ -487,8 +493,7 @@ impl Server { } } - pub fn key_press(&mut self, down: bool, key: Keycode) { - self.pressed_keys.insert(key, down); + pub fn key_press(&mut self, down: bool, key: Stevenkey) { if let Some(player) = self.player { if let Some(movement) = self.entities.get_component_mut(player, self.player_movement) { movement.pressed_keys.insert(key, down); @@ -496,10 +501,6 @@ impl Server { } } - fn is_key_pressed(&self, key: Keycode) -> bool { - self.pressed_keys.get(&key).map_or(false, |v| *v) - } - pub fn write_packet(&mut self, p: T) { let _ = self.conn.as_mut().unwrap().write_packet(p); // TODO handle errors } diff --git a/src/settings.rs b/src/settings.rs new file mode 100644 index 0000000..8a9b532 --- /dev/null +++ b/src/settings.rs @@ -0,0 +1,117 @@ +use console; +use std::marker::PhantomData; +use sdl2::keyboard::Keycode; +// Might just rename this to settings.rs + +pub const R_MAX_FPS: console::CVar = console::CVar { + ty: PhantomData, + name: "r_max_fps", + description: "fps_max caps the maximum FPS for the rendering engine", + mutable: true, + serializable: true, + default: &|| 60, +}; + +pub const R_FOV: console::CVar = console::CVar { + ty: PhantomData, + name: "r_fov", + description: "Setting for controlling the client field of view", + mutable: true, + serializable: true, + default: &|| 90, +}; + +pub const R_VSYNC: console::CVar = console::CVar { + ty: PhantomData, + name: "r_vsync", + description: "Toggle to enable/disable vsync", + mutable: true, + serializable: true, + default: &|| true, +}; + +pub const CL_MASTER_VOLUME: console::CVar = console::CVar { + ty: PhantomData, + name: "cl_master_volume", + description: "Main volume control", + mutable: true, + serializable: true, + default: &|| 100, +}; + +macro_rules! create_keybind { + ($keycode:ident, $name:expr, $description:expr) => (console::CVar { + ty: PhantomData, + name: $name, + description: $description, + mutable: true, + serializable: true, + default: &|| Keycode::$keycode as i64 + }) +} + +pub const CL_KEYBIND_FORWARD: console::CVar = create_keybind!(W, "cl_keybind_forward", "Keybinding for moving forward"); +pub const CL_KEYBIND_BACKWARD: console::CVar = create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward"); +pub const CL_KEYBIND_LEFT: console::CVar = create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left"); +pub const CL_KEYBIND_RIGHT: console::CVar = create_keybind!(D, "cl_keybind_right", "Keybinding for moving to the right"); +pub const CL_KEYBIND_OPEN_INV: console::CVar = create_keybind!(E, "cl_keybind_open_inv", "Keybinding for opening the inventory"); +pub const CL_KEYBIND_SNEAK: console::CVar = create_keybind!(LShift, "cl_keybind_sneak", "Keybinding for sneaking"); +pub const CL_KEYBIND_SPRINT: console::CVar = create_keybind!(LCtrl, "cl_keybind_sprint", "Keybinding for sprinting"); +pub const CL_KEYBIND_JUMP: console::CVar = create_keybind!(Space, "cl_keybind_jump", "Keybinding for jumping"); + +pub fn register_vars(console: &mut console::Console) { + console.register(R_MAX_FPS); + console.register(R_FOV); + console.register(R_VSYNC); + console.register(CL_MASTER_VOLUME); + console.register(CL_KEYBIND_FORWARD); + console.register(CL_KEYBIND_BACKWARD); + console.register(CL_KEYBIND_LEFT); + console.register(CL_KEYBIND_RIGHT); + console.register(CL_KEYBIND_OPEN_INV); + console.register(CL_KEYBIND_SNEAK); + console.register(CL_KEYBIND_SPRINT); + console.register(CL_KEYBIND_JUMP); +} + +#[derive(Hash, PartialEq, Eq)] +pub enum Stevenkey { + Forward, + Backward, + Left, + Right, + OpenInv, + Sneak, + Sprint, + Jump, +} + +impl Stevenkey { + pub fn values() -> Vec { + vec!(Stevenkey::Forward, Stevenkey::Backward, Stevenkey::Left, + Stevenkey::Right, Stevenkey::OpenInv, Stevenkey::Sneak, + Stevenkey::Sprint, Stevenkey::Jump) + } + + pub fn get_by_keycode(keycode: Keycode, console: &console::Console) -> Option { + for steven_key in Stevenkey::values() { + if keycode as i64 == *console.get(steven_key.get_cvar()) { + return Some(steven_key) + } + } + None + } + + pub fn get_cvar(&self) -> console::CVar { + match *self { + Stevenkey::Forward => CL_KEYBIND_FORWARD, + Stevenkey::Backward => CL_KEYBIND_BACKWARD, + Stevenkey::Left => CL_KEYBIND_LEFT, + Stevenkey::Right => CL_KEYBIND_RIGHT, + Stevenkey::OpenInv => CL_KEYBIND_OPEN_INV, + Stevenkey::Sneak => CL_KEYBIND_SNEAK, + Stevenkey::Sprint => CL_KEYBIND_SPRINT, + Stevenkey::Jump => CL_KEYBIND_JUMP + } + } +}