Add a options/pause menu (Closes #4)

This commit is contained in:
TheUnnamedDude 2016-04-09 10:56:55 +02:00 committed by Matthew Collins
parent 2acfa47491
commit 4c590f8184
9 changed files with 505 additions and 26 deletions

View File

@ -38,6 +38,42 @@ pub struct CVar<T: Sized + Any + 'static> {
pub default: &'static Fn() -> T,
}
impl Var for CVar<i64> {
fn serialize(&self, val: &Box<Any>) -> String {
val.downcast_ref::<i64>().unwrap().to_string()
}
fn deserialize(&self, input: &str) -> Box<Any> {
Box::new(input.parse::<i64>().unwrap())
}
fn description(&self) -> &'static str {
self.description
}
fn can_serialize(&self) -> bool {
self.serializable
}
}
impl Var for CVar<bool> {
fn serialize(&self, val: &Box<Any>) -> String {
val.downcast_ref::<bool>().unwrap().to_string()
}
fn deserialize(&self, input: &str) -> Box<Any> {
Box::new(input.parse::<bool>().unwrap())
}
fn description(&self) -> &'static str {
self.description
}
fn can_serialize(&self) -> bool {
self.serializable
}
}
impl Var for CVar<String> {
fn serialize(&self, val: &Box<Any>) -> String {
format!("\"{}\"", val.downcast_ref::<String>().unwrap())

View File

@ -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<Keycode, bool, BuildHasherDefault<FNVHash>>,
pub pressed_keys: HashMap<Stevenkey, bool, BuildHasherDefault<FNVHash>>,
}
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 {

View File

@ -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);
}

View File

@ -177,4 +177,8 @@ impl super::Screen for EditServerEntry {
elements.logo.tick(renderer, ui_container);
None
}
fn is_closable(&self) -> bool {
true
}
}

View File

@ -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,

View File

@ -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));

291
src/screen/settings_menu.rs Normal file
View File

@ -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::Button>, ui::ElementRef<ui::Text>) {
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::Button>, ui::ElementRef<ui::Text>) {
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<Mutex<console::Console>>,
elements: Option<UIElement>,
show_disconnect_button: bool
}
impl SettingsMenu {
pub fn new(console: Arc<Mutex<console::Console>>, 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<Box<super::Screen>> {
None
}
// Events
fn on_scroll(&mut self, x: f64, y: f64) {
}
fn is_closable(&self) -> bool {
true
}
}
pub struct VideoSettingsMenu {
console: Arc<Mutex<console::Console>>,
elements: Option<UIElement>,
fps_bounds: Vec<i64>
}
impl VideoSettingsMenu {
pub fn new(console: Arc<Mutex<console::Console>>) -> 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<Box<super::Screen>> {
None
}
// Events
fn on_scroll(&mut self, x: f64, y: f64) {
}
fn is_closable(&self) -> bool {
true
}
}
pub struct AudioSettingsMenu {
console: Arc<Mutex<console::Console>>,
elements: Option<UIElement>
}
impl AudioSettingsMenu {
pub fn new(console: Arc<Mutex<console::Console>>) -> 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<Box<super::Screen>> {
None
}
// Events
fn on_scroll(&mut self, x: f64, y: f64) {
}
fn is_closable(&self) -> bool {
true
}
}

View File

@ -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<i32, ecs::Entity, BuildHasherDefault<FNVHash>>,
players: HashMap<protocol::UUID, PlayerInfo, BuildHasherDefault<FNVHash>>,
pressed_keys: HashMap<Keycode, bool, BuildHasherDefault<FNVHash>>,
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<T: protocol::PacketType>(&mut self, p: T) {
let _ = self.conn.as_mut().unwrap().write_packet(p); // TODO handle errors
}

117
src/settings.rs Normal file
View File

@ -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<i64> = 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<i64> = 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<bool> = 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<i64> = 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<i64> = create_keybind!(W, "cl_keybind_forward", "Keybinding for moving forward");
pub const CL_KEYBIND_BACKWARD: console::CVar<i64> = create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward");
pub const CL_KEYBIND_LEFT: console::CVar<i64> = create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left");
pub const CL_KEYBIND_RIGHT: console::CVar<i64> = create_keybind!(D, "cl_keybind_right", "Keybinding for moving to the right");
pub const CL_KEYBIND_OPEN_INV: console::CVar<i64> = create_keybind!(E, "cl_keybind_open_inv", "Keybinding for opening the inventory");
pub const CL_KEYBIND_SNEAK: console::CVar<i64> = create_keybind!(LShift, "cl_keybind_sneak", "Keybinding for sneaking");
pub const CL_KEYBIND_SPRINT: console::CVar<i64> = create_keybind!(LCtrl, "cl_keybind_sprint", "Keybinding for sprinting");
pub const CL_KEYBIND_JUMP: console::CVar<i64> = 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<Stevenkey> {
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<Stevenkey> {
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<i64> {
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
}
}
}