From fa6b21a15b415cd82dce6896b94a5341b7dd76f0 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 14 May 2016 16:25:57 +0200 Subject: Tell irrlicht if we handle a key or not. We can remove the function in MtNativeActivity now as it serves precisely that purpose: to tell irrlicht that we handled the esc key. TODO for later: * Perhaps try to find a more performant container than KeyList --- src/game.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/game.h') diff --git a/src/game.h b/src/game.h index e1f4e9346..5465ecdc6 100644 --- a/src/game.h +++ b/src/game.h @@ -110,6 +110,9 @@ public: virtual bool isKeyDown(const KeyPress &keyCode) = 0; virtual bool wasKeyDown(const KeyPress &keyCode) = 0; + virtual void listenForKey(const KeyPress &keyCode) {} + virtual void dontListenForKeys() {} + virtual v2s32 getMousePos() = 0; virtual void setMousePos(s32 x, s32 y) = 0; -- cgit v1.2.3 From 1e86c89f3614cf298916149a8f13d44ea671da64 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 25 May 2016 09:22:20 +0200 Subject: Input related generalisations * Move key types into own file * Use Generalized input methods in game.cpp --- src/client/keys.h | 79 +++++++++++++++ src/game.cpp | 293 ++++++++++++++++++++++++++---------------------------- src/game.h | 1 + 3 files changed, 223 insertions(+), 150 deletions(-) create mode 100644 src/client/keys.h (limited to 'src/game.h') diff --git a/src/client/keys.h b/src/client/keys.h new file mode 100644 index 000000000..08b1c4123 --- /dev/null +++ b/src/client/keys.h @@ -0,0 +1,79 @@ +/* +Minetest +Copyright (C) 2016 est31, + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef KEYS_HEADER +#define KEYS_HEADER + +#include + +class KeyType { +public: + enum T { + // Player movement + FORWARD, + BACKWARD, + LEFT, + RIGHT, + JUMP, + SPECIAL1, + SNEAK, + AUTORUN, + + ESC, + + // Other + DROP, + INVENTORY, + CHAT, + CMD, + CONSOLE, + MINIMAP, + FREEMOVE, + FASTMOVE, + NOCLIP, + CINEMATIC, + SCREENSHOT, + TOGGLE_HUD, + TOGGLE_CHAT, + TOGGLE_FORCE_FOG_OFF, + TOGGLE_UPDATE_CAMERA, + TOGGLE_DEBUG, + TOGGLE_PROFILER, + CAMERA_MODE, + INCREASE_VIEWING_RANGE, + DECREASE_VIEWING_RANGE, + RANGESELECT, + + QUICKTUNE_NEXT, + QUICKTUNE_PREV, + QUICKTUNE_INC, + QUICKTUNE_DEC, + + DEBUG_STACKS, + + // Fake keycode for array size and internal checks + INTERNAL_ENUM_COUNT + + }; +}; + +typedef KeyType::T GameKeyType; + + +#endif diff --git a/src/game.cpp b/src/game.cpp index def202fe5..ac1c0fe6b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "camera.h" #include "client.h" #include "client/tile.h" // For TextureSource +#include "client/keys.h" #include "clientmap.h" #include "clouds.h" #include "config.h" @@ -1306,114 +1307,76 @@ struct KeyCache { { handler = NULL; populate(); + populate_nonchanging(); } - enum { - // Player movement - KEYMAP_ID_FORWARD, - KEYMAP_ID_BACKWARD, - KEYMAP_ID_LEFT, - KEYMAP_ID_RIGHT, - KEYMAP_ID_JUMP, - KEYMAP_ID_SPECIAL1, - KEYMAP_ID_SNEAK, - KEYMAP_ID_AUTORUN, - - // Other - KEYMAP_ID_DROP, - KEYMAP_ID_INVENTORY, - KEYMAP_ID_CHAT, - KEYMAP_ID_CMD, - KEYMAP_ID_CONSOLE, - KEYMAP_ID_MINIMAP, - KEYMAP_ID_FREEMOVE, - KEYMAP_ID_FASTMOVE, - KEYMAP_ID_NOCLIP, - KEYMAP_ID_CINEMATIC, - KEYMAP_ID_SCREENSHOT, - KEYMAP_ID_TOGGLE_HUD, - KEYMAP_ID_TOGGLE_CHAT, - KEYMAP_ID_TOGGLE_FORCE_FOG_OFF, - KEYMAP_ID_TOGGLE_UPDATE_CAMERA, - KEYMAP_ID_TOGGLE_DEBUG, - KEYMAP_ID_TOGGLE_PROFILER, - KEYMAP_ID_CAMERA_MODE, - KEYMAP_ID_INCREASE_VIEWING_RANGE, - KEYMAP_ID_DECREASE_VIEWING_RANGE, - KEYMAP_ID_RANGESELECT, - - KEYMAP_ID_QUICKTUNE_NEXT, - KEYMAP_ID_QUICKTUNE_PREV, - KEYMAP_ID_QUICKTUNE_INC, - KEYMAP_ID_QUICKTUNE_DEC, - - KEYMAP_ID_DEBUG_STACKS, - - // Fake keycode for array size and internal checks - KEYMAP_INTERNAL_ENUM_COUNT - - - }; - void populate(); - KeyPress key[KEYMAP_INTERNAL_ENUM_COUNT]; + // Keys that are not settings dependent + void populate_nonchanging(); + + KeyPress key[KeyType::INTERNAL_ENUM_COUNT]; InputHandler *handler; }; +void KeyCache::populate_nonchanging() +{ + key[KeyType::ESC] = EscapeKey; +} + void KeyCache::populate() { - key[KEYMAP_ID_FORWARD] = getKeySetting("keymap_forward"); - key[KEYMAP_ID_BACKWARD] = getKeySetting("keymap_backward"); - key[KEYMAP_ID_LEFT] = getKeySetting("keymap_left"); - key[KEYMAP_ID_RIGHT] = getKeySetting("keymap_right"); - key[KEYMAP_ID_JUMP] = getKeySetting("keymap_jump"); - key[KEYMAP_ID_SPECIAL1] = getKeySetting("keymap_special1"); - key[KEYMAP_ID_SNEAK] = getKeySetting("keymap_sneak"); - - key[KEYMAP_ID_AUTORUN] = getKeySetting("keymap_autorun"); - - key[KEYMAP_ID_DROP] = getKeySetting("keymap_drop"); - key[KEYMAP_ID_INVENTORY] = getKeySetting("keymap_inventory"); - key[KEYMAP_ID_CHAT] = getKeySetting("keymap_chat"); - key[KEYMAP_ID_CMD] = getKeySetting("keymap_cmd"); - key[KEYMAP_ID_CONSOLE] = getKeySetting("keymap_console"); - key[KEYMAP_ID_MINIMAP] = getKeySetting("keymap_minimap"); - key[KEYMAP_ID_FREEMOVE] = getKeySetting("keymap_freemove"); - key[KEYMAP_ID_FASTMOVE] = getKeySetting("keymap_fastmove"); - key[KEYMAP_ID_NOCLIP] = getKeySetting("keymap_noclip"); - key[KEYMAP_ID_CINEMATIC] = getKeySetting("keymap_cinematic"); - key[KEYMAP_ID_SCREENSHOT] = getKeySetting("keymap_screenshot"); - key[KEYMAP_ID_TOGGLE_HUD] = getKeySetting("keymap_toggle_hud"); - key[KEYMAP_ID_TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat"); - key[KEYMAP_ID_TOGGLE_FORCE_FOG_OFF] + key[KeyType::FORWARD] = getKeySetting("keymap_forward"); + key[KeyType::BACKWARD] = getKeySetting("keymap_backward"); + key[KeyType::LEFT] = getKeySetting("keymap_left"); + key[KeyType::RIGHT] = getKeySetting("keymap_right"); + key[KeyType::JUMP] = getKeySetting("keymap_jump"); + key[KeyType::SPECIAL1] = getKeySetting("keymap_special1"); + key[KeyType::SNEAK] = getKeySetting("keymap_sneak"); + + key[KeyType::AUTORUN] = getKeySetting("keymap_autorun"); + + key[KeyType::DROP] = getKeySetting("keymap_drop"); + key[KeyType::INVENTORY] = getKeySetting("keymap_inventory"); + key[KeyType::CHAT] = getKeySetting("keymap_chat"); + key[KeyType::CMD] = getKeySetting("keymap_cmd"); + key[KeyType::CONSOLE] = getKeySetting("keymap_console"); + key[KeyType::MINIMAP] = getKeySetting("keymap_minimap"); + key[KeyType::FREEMOVE] = getKeySetting("keymap_freemove"); + key[KeyType::FASTMOVE] = getKeySetting("keymap_fastmove"); + key[KeyType::NOCLIP] = getKeySetting("keymap_noclip"); + key[KeyType::CINEMATIC] = getKeySetting("keymap_cinematic"); + key[KeyType::SCREENSHOT] = getKeySetting("keymap_screenshot"); + key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud"); + key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat"); + key[KeyType::TOGGLE_FORCE_FOG_OFF] = getKeySetting("keymap_toggle_force_fog_off"); - key[KEYMAP_ID_TOGGLE_UPDATE_CAMERA] + key[KeyType::TOGGLE_UPDATE_CAMERA] = getKeySetting("keymap_toggle_update_camera"); - key[KEYMAP_ID_TOGGLE_DEBUG] + key[KeyType::TOGGLE_DEBUG] = getKeySetting("keymap_toggle_debug"); - key[KEYMAP_ID_TOGGLE_PROFILER] + key[KeyType::TOGGLE_PROFILER] = getKeySetting("keymap_toggle_profiler"); - key[KEYMAP_ID_CAMERA_MODE] + key[KeyType::CAMERA_MODE] = getKeySetting("keymap_camera_mode"); - key[KEYMAP_ID_INCREASE_VIEWING_RANGE] + key[KeyType::INCREASE_VIEWING_RANGE] = getKeySetting("keymap_increase_viewing_range_min"); - key[KEYMAP_ID_DECREASE_VIEWING_RANGE] + key[KeyType::DECREASE_VIEWING_RANGE] = getKeySetting("keymap_decrease_viewing_range_min"); - key[KEYMAP_ID_RANGESELECT] + key[KeyType::RANGESELECT] = getKeySetting("keymap_rangeselect"); - key[KEYMAP_ID_QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next"); - key[KEYMAP_ID_QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev"); - key[KEYMAP_ID_QUICKTUNE_INC] = getKeySetting("keymap_quicktune_inc"); - key[KEYMAP_ID_QUICKTUNE_DEC] = getKeySetting("keymap_quicktune_dec"); + key[KeyType::QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next"); + key[KeyType::QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev"); + key[KeyType::QUICKTUNE_INC] = getKeySetting("keymap_quicktune_inc"); + key[KeyType::QUICKTUNE_DEC] = getKeySetting("keymap_quicktune_dec"); - key[KEYMAP_ID_DEBUG_STACKS] = getKeySetting("keymap_print_debug_stacks"); + key[KeyType::DEBUG_STACKS] = getKeySetting("keymap_print_debug_stacks"); if (handler) { // First clear all keys, then re-add the ones we listen for handler->dontListenForKeys(); - for (size_t i = 0; i < KEYMAP_INTERNAL_ENUM_COUNT; i++) { + for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) { handler->listenForKey(key[i]); } handler->listenForKey(EscapeKey); @@ -1575,9 +1538,10 @@ protected: f32 dtime); void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime); + // Input related void processUserInput(VolatileRunFlags *flags, GameRunData *runData, f32 dtime); - void processKeyboardInput(VolatileRunFlags *flags, + void processKeyInput(VolatileRunFlags *flags, float *statustext_time, float *jump_timer, bool *reset_jump_timer, @@ -1647,6 +1611,36 @@ protected: static void settingChangedCallback(const std::string &setting_name, void *data); void readSettings(); + bool getLeftClicked() + { + return input->getLeftClicked(); + } + bool getRightClicked() + { + return input->getRightClicked(); + } + bool isLeftPressed() + { + return input->getLeftState(); + } + bool isRightPressed() + { + return input->getRightState(); + } + bool getLeftReleased() + { + return input->getLeftReleased(); + } + + bool isKeyDown(GameKeyType k) + { + return input->isKeyDown(keycache.key[k]); + } + bool wasKeyDown(GameKeyType k) + { + return input->wasKeyDown(keycache.key[k]); + } + #ifdef __ANDROID__ void handleAndroidChatInput(); #endif @@ -2379,7 +2373,7 @@ bool Game::connectToServer(const std::string &playername, break; } - if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) { + if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) { *aborted = true; infostream << "Connect aborted [Escape]" << std::endl; break; @@ -2440,7 +2434,7 @@ bool Game::getServerContent(bool *aborted) return false; } - if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) { + if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) { *aborted = true; infostream << "Connect aborted [Escape]" << std::endl; return false; @@ -2702,7 +2696,7 @@ void Game::processUserInput(VolatileRunFlags *flags, if (m_cache_doubletap_jump && runData->jump_timer <= 0.2) runData->jump_timer += dtime; - processKeyboardInput( + processKeyInput( flags, &runData->statustext_time, &runData->jump_timer, @@ -2714,7 +2708,7 @@ void Game::processUserInput(VolatileRunFlags *flags, } -void Game::processKeyboardInput(VolatileRunFlags *flags, +void Game::processKeyInput(VolatileRunFlags *flags, float *statustext_time, float *jump_timer, bool *reset_jump_timer, @@ -2724,66 +2718,66 @@ void Game::processKeyboardInput(VolatileRunFlags *flags, //TimeTaker tt("process kybd input", NULL, PRECISION_NANO); - if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DROP])) { + if (wasKeyDown(KeyType::DROP)) { dropSelectedItem(); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_AUTORUN])) { + } else if (wasKeyDown(KeyType::AUTORUN)) { toggleAutorun(statustext_time); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INVENTORY])) { + } else if (wasKeyDown(KeyType::INVENTORY)) { openInventory(); - } else if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) { + } else if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) { if (!gui_chat_console->isOpenInhibited()) { show_pause_menu(¤t_formspec, client, gamedef, texture_src, device, simple_singleplayer_mode); } - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CHAT])) { + } else if (wasKeyDown(KeyType::CHAT)) { openConsole(0.2, L""); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CMD])) { + } else if (wasKeyDown(KeyType::CMD)) { openConsole(0.2, L"/"); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CONSOLE])) { + } else if (wasKeyDown(KeyType::CONSOLE)) { openConsole(1); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FREEMOVE])) { + } else if (wasKeyDown(KeyType::FREEMOVE)) { toggleFreeMove(statustext_time); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP])) { + } else if (wasKeyDown(KeyType::JUMP)) { toggleFreeMoveAlt(statustext_time, jump_timer); *reset_jump_timer = true; - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FASTMOVE])) { + } else if (wasKeyDown(KeyType::FASTMOVE)) { toggleFast(statustext_time); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_NOCLIP])) { + } else if (wasKeyDown(KeyType::NOCLIP)) { toggleNoClip(statustext_time); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CINEMATIC])) { + } else if (wasKeyDown(KeyType::CINEMATIC)) { toggleCinematic(statustext_time); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_SCREENSHOT])) { + } else if (wasKeyDown(KeyType::SCREENSHOT)) { client->makeScreenshot(device); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_HUD])) { + } else if (wasKeyDown(KeyType::TOGGLE_HUD)) { toggleHud(statustext_time, &flags->show_hud); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_MINIMAP])) { + } else if (wasKeyDown(KeyType::MINIMAP)) { toggleMinimap(statustext_time, &flags->show_minimap, flags->show_hud, - input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SNEAK])); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_CHAT])) { + isKeyDown(KeyType::SNEAK)); + } else if (wasKeyDown(KeyType::TOGGLE_CHAT)) { toggleChat(statustext_time, &flags->show_chat); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_FORCE_FOG_OFF])) { + } else if (wasKeyDown(KeyType::TOGGLE_FORCE_FOG_OFF)) { toggleFog(statustext_time, &flags->force_fog_off); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_UPDATE_CAMERA])) { + } else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) { toggleUpdateCamera(statustext_time, &flags->disable_camera_update); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_DEBUG])) { + } else if (wasKeyDown(KeyType::TOGGLE_DEBUG)) { toggleDebug(statustext_time, &flags->show_debug, &flags->show_profiler_graph); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_PROFILER])) { + } else if (wasKeyDown(KeyType::TOGGLE_PROFILER)) { toggleProfiler(statustext_time, profiler_current_page, profiler_max_page); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INCREASE_VIEWING_RANGE])) { + } else if (wasKeyDown(KeyType::INCREASE_VIEWING_RANGE)) { increaseViewRange(statustext_time); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DECREASE_VIEWING_RANGE])) { + } else if (wasKeyDown(KeyType::DECREASE_VIEWING_RANGE)) { decreaseViewRange(statustext_time); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_RANGESELECT])) { + } else if (wasKeyDown(KeyType::RANGESELECT)) { toggleFullViewRange(statustext_time); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_NEXT])) { + } else if (wasKeyDown(KeyType::QUICKTUNE_NEXT)) { quicktune->next(); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_PREV])) { + } else if (wasKeyDown(KeyType::QUICKTUNE_PREV)) { quicktune->prev(); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_INC])) { + } else if (wasKeyDown(KeyType::QUICKTUNE_INC)) { quicktune->inc(); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_DEC])) { + } else if (wasKeyDown(KeyType::QUICKTUNE_DEC)) { quicktune->dec(); - } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DEBUG_STACKS])) { + } else if (wasKeyDown(KeyType::DEBUG_STACKS)) { // Print debug stacks dstream << "-----------------------------------------" << std::endl; @@ -2793,7 +2787,7 @@ void Game::processKeyboardInput(VolatileRunFlags *flags, debug_stacks_print(); } - if (!input->isKeyDown(getKeySetting("keymap_jump")) && *reset_jump_timer) { + if (!isKeyDown(KeyType::JUMP) && *reset_jump_timer) { *reset_jump_timer = false; *jump_timer = 0.0; } @@ -2807,7 +2801,6 @@ void Game::processKeyboardInput(VolatileRunFlags *flags, } } - void Game::processItemSelection(u16 *new_playeritem) { LocalPlayer *player = client->getEnv().getLocalPlayer(); @@ -3228,13 +3221,13 @@ void Game::updatePlayerControl(const CameraOrientation &cam) //TimeTaker tt("update player control", NULL, PRECISION_NANO); PlayerControl control( - input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_FORWARD]), - input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_BACKWARD]), - input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_LEFT]), - input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_RIGHT]), - input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP]), - input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SPECIAL1]), - input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SNEAK]), + input->isKeyDown(keycache.key[KeyType::FORWARD]), + input->isKeyDown(keycache.key[KeyType::BACKWARD]), + input->isKeyDown(keycache.key[KeyType::LEFT]), + input->isKeyDown(keycache.key[KeyType::RIGHT]), + input->isKeyDown(keycache.key[KeyType::JUMP]), + input->isKeyDown(keycache.key[KeyType::SPECIAL1]), + input->isKeyDown(keycache.key[KeyType::SNEAK]), input->getLeftState(), input->getRightState(), cam.camera_pitch, @@ -3242,13 +3235,13 @@ void Game::updatePlayerControl(const CameraOrientation &cam) ); u32 keypress_bits = - ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_FORWARD]) & 0x1) << 0) | - ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_BACKWARD]) & 0x1) << 1) | - ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_LEFT]) & 0x1) << 2) | - ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_RIGHT]) & 0x1) << 3) | - ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP]) & 0x1) << 4) | - ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SPECIAL1]) & 0x1) << 5) | - ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SNEAK]) & 0x1) << 6) | + ( (u32)(input->isKeyDown(keycache.key[KeyType::FORWARD]) & 0x1) << 0) | + ( (u32)(input->isKeyDown(keycache.key[KeyType::BACKWARD]) & 0x1) << 1) | + ( (u32)(input->isKeyDown(keycache.key[KeyType::LEFT]) & 0x1) << 2) | + ( (u32)(input->isKeyDown(keycache.key[KeyType::RIGHT]) & 0x1) << 3) | + ( (u32)(input->isKeyDown(keycache.key[KeyType::JUMP]) & 0x1) << 4) | + ( (u32)(input->isKeyDown(keycache.key[KeyType::SPECIAL1]) & 0x1) << 5) | + ( (u32)(input->isKeyDown(keycache.key[KeyType::SNEAK]) & 0x1) << 6) | ( (u32)(input->getLeftState() & 0x1) << 7) | ( (u32)(input->getRightState() & 0x1) << 8 ); @@ -3522,7 +3515,7 @@ void Game::updateCamera(VolatileRunFlags *flags, u32 busy_time, v3s16 old_camera_offset = camera->getOffset(); - if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CAMERA_MODE])) { + if (wasKeyDown(KeyType::CAMERA_MODE)) { GenericCAO *playercao = player->getCAO(); // If playercao not loaded, don't change camera @@ -3665,7 +3658,7 @@ void Game::processPlayerInteraction(GameRunData *runData, - pointing away from node */ if (runData->digging) { - if (input->getLeftReleased()) { + if (getLeftReleased()) { infostream << "Left button released" << " (stopped digging)" << std::endl; runData->digging = false; @@ -3691,7 +3684,7 @@ void Game::processPlayerInteraction(GameRunData *runData, } } - if (!runData->digging && runData->ldown_for_dig && !input->getLeftState()) { + if (!runData->digging && runData->ldown_for_dig && !isLeftPressed()) { runData->ldown_for_dig = false; } @@ -3699,13 +3692,13 @@ void Game::processPlayerInteraction(GameRunData *runData, soundmaker->m_player_leftpunch_sound.name = ""; - if (input->getRightState()) + if (isRightPressed()) runData->repeat_rightclick_timer += dtime; else runData->repeat_rightclick_timer = 0; - if (playeritem_def.usable && input->getLeftState()) { - if (input->getLeftClicked()) + if (playeritem_def.usable && isLeftPressed()) { + if (getLeftClicked()) client->interact(4, pointed); } else if (pointed.type == POINTEDTHING_NODE) { ToolCapabilities playeritem_toolcap = @@ -3715,16 +3708,16 @@ void Game::processPlayerInteraction(GameRunData *runData, } else if (pointed.type == POINTEDTHING_OBJECT) { handlePointingAtObject(runData, pointed, playeritem, player_position, show_debug); - } else if (input->getLeftState()) { + } else if (isLeftPressed()) { // When button is held down in air, show continuous animation runData->left_punch = true; - } else if (input->getRightClicked()) { + } else if (getRightClicked()) { handlePointingAtNothing(runData, playeritem); } runData->pointed_old = pointed; - if (runData->left_punch || input->getLeftClicked()) + if (runData->left_punch || getLeftClicked()) camera->setDigging(0); // left click animation input->resetLeftClicked(); @@ -3769,19 +3762,19 @@ void Game::handlePointingAtNode(GameRunData *runData, } } - if (runData->nodig_delay_timer <= 0.0 && input->getLeftState() + if (runData->nodig_delay_timer <= 0.0 && isLeftPressed() && client->checkPrivilege("interact")) { handleDigging(runData, pointed, nodepos, playeritem_toolcap, dtime); } - if ((input->getRightClicked() || + if ((getRightClicked() || runData->repeat_rightclick_timer >= m_repeat_right_click_time) && client->checkPrivilege("interact")) { runData->repeat_rightclick_timer = 0; infostream << "Ground right-clicked" << std::endl; if (meta && meta->getString("formspec") != "" && !random_input - && !input->isKeyDown(getKeySetting("keymap_sneak"))) { + && !isKeyDown(KeyType::SNEAK)) { infostream << "Launching custom inventory view" << std::endl; InventoryLocation inventoryloc; @@ -3846,7 +3839,7 @@ void Game::handlePointingAtObject(GameRunData *runData, runData->selected_object->debugInfoText())); } - if (input->getLeftState()) { + if (isLeftPressed()) { bool do_punch = false; bool do_punch_damage = false; @@ -3856,7 +3849,7 @@ void Game::handlePointingAtObject(GameRunData *runData, runData->object_hit_delay_timer = object_hit_delay; } - if (input->getLeftClicked()) + if (getLeftClicked()) do_punch = true; if (do_punch) { @@ -3876,7 +3869,7 @@ void Game::handlePointingAtObject(GameRunData *runData, if (!disable_send) client->interact(0, pointed); } - } else if (input->getRightClicked()) { + } else if (getRightClicked()) { infostream << "Right-clicked object" << std::endl; client->interact(3, pointed); // place } diff --git a/src/game.h b/src/game.h index 5465ecdc6..d8c2f78fc 100644 --- a/src/game.h +++ b/src/game.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes_extrabloated.h" #include +#include "client/keys.h" #include "keycode.h" #include -- cgit v1.2.3 From 2060fd9cbe587d7e8ffe0cecdd67925f13a56c05 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 27 May 2016 08:35:07 +0200 Subject: Initial Gamepad support Adds initial ingame gamepad support to minetest. Full Formspec support is not implemented yet and can be added by a later change. --- builtin/settingtypes.txt | 11 +++ src/client/CMakeLists.txt | 1 + src/client/clientlauncher.cpp | 20 ++++- src/client/inputhandler.h | 13 +++ src/client/joystick_controller.cpp | 179 +++++++++++++++++++++++++++++++++++++ src/client/joystick_controller.h | 163 +++++++++++++++++++++++++++++++++ src/client/keys.h | 6 ++ src/content_cao.cpp | 4 +- src/defaultsettings.cpp | 3 + src/game.cpp | 165 ++++++++++++++++++++++------------ src/game.h | 3 + src/guiEngine.cpp | 2 + src/guiEngine.h | 3 +- src/guiFormSpecMenu.cpp | 42 +++++++-- src/guiFormSpecMenu.h | 13 ++- src/localplayer.cpp | 17 ++-- src/player.h | 10 ++- 17 files changed, 576 insertions(+), 79 deletions(-) create mode 100644 src/client/joystick_controller.cpp create mode 100644 src/client/joystick_controller.h (limited to 'src/game.h') diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 538a04f33..b53e35a85 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -104,6 +104,17 @@ random_input (Random input) bool false # Continuous forward movement (only used for testing). continuous_forward (Continuous forward) bool false +# Enable Joysticks +enable_joysticks (Enable Joysticks) bool true + +# The time in seconds it takes between repeated events +# when holding down a joystick button combination. +repeat_joystick_button_time (Joystick button repetition invterval) float 0.17 + +# The sensitivity of the joystick axes for moving the +# ingame view frustum around. +joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170 + # Key for moving the player forward. # See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3 keymap_forward (Forward key) key KEY_KEY_W diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index a1ec37fe3..5faa186a7 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -1,6 +1,7 @@ set(client_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/joystick_controller.cpp PARENT_SCOPE ) diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 404a16310..ee8662ed6 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "guiEngine.h" #include "player.h" #include "fontengine.h" +#include "joystick_controller.h" #include "clientlauncher.h" /* mainmenumanager.h @@ -499,7 +500,8 @@ void ClientLauncher::main_menu(MainMenuData *menudata) #endif /* show main menu */ - GUIEngine mymenu(device, guiroot, &g_menumgr, smgr, menudata, *kill); + GUIEngine mymenu(device, &input->joystick, guiroot, + &g_menumgr, smgr, menudata, *kill); smgr->clear(); /* leave scene manager in a clean state */ } @@ -558,6 +560,22 @@ bool ClientLauncher::create_engine_device() device = createDeviceEx(params); if (device) { + if (g_settings->getBool("enable_joysticks")) { + irr::core::array infos; + std::vector joystick_infos; + // Make sure this is called maximum once per + // irrlicht device, otherwise it will give you + // multiple events for the same joystick. + if (device->activateJoysticks(infos)) { + infostream << "Joystick support enabled" << std::endl; + joystick_infos.reserve(infos.size()); + for (u32 i = 0; i < infos.size(); i++) { + joystick_infos.push_back(infos[i]); + } + } else { + errorstream << "Could not activate joystick support." << std::endl; + } + } porting::initIrrlicht(device); } diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h index 73e507fdc..824b0da2e 100644 --- a/src/client/inputhandler.h +++ b/src/client/inputhandler.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define INPUT_HANDLER_H #include "irrlichttypes_extrabloated.h" +#include "joystick_controller.h" class MyEventReceiver : public IEventReceiver { @@ -62,6 +63,14 @@ public: return true; } #endif + + if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) { + /* TODO add a check like: + if (event.JoystickEvent != joystick_we_listen_for) + return false; + */ + return joystick->handleEvent(event.JoystickEvent); + } // handle mouse events if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) { if (noMenuActive() == false) { @@ -172,6 +181,8 @@ public: s32 mouse_wheel; + JoystickController *joystick; + #ifdef HAVE_TOUCHSCREENGUI TouchScreenGUI* m_touchscreengui; #endif @@ -202,6 +213,7 @@ public: m_receiver(receiver), m_mousepos(0,0) { + m_receiver->joystick = &joystick; } virtual bool isKeyDown(const KeyPress &keyCode) { @@ -288,6 +300,7 @@ public: void clear() { + joystick.clear(); m_receiver->clearInput(); } private: diff --git a/src/client/joystick_controller.cpp b/src/client/joystick_controller.cpp new file mode 100644 index 000000000..ef8d18ab0 --- /dev/null +++ b/src/client/joystick_controller.cpp @@ -0,0 +1,179 @@ +/* +Minetest +Copyright (C) 2016 est31, + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "joystick_controller.h" +#include "irrlichttypes_extrabloated.h" +#include "keys.h" +#include "settings.h" +#include "gettime.h" + +bool JoystickButtonCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const +{ + u32 buttons = ev.ButtonStates; + + buttons &= filter_mask; + return buttons == compare_mask; +} + +bool JoystickAxisCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const +{ + s16 ax_val = ev.Axis[axis_to_compare]; + + return (ax_val * direction < 0) && (thresh * direction > ax_val * direction); +} + +// spares many characters +#define JLO_B_PB(A, B, C) jlo.button_keys.push_back(JoystickButtonCmb(A, B, C)) +#define JLO_A_PB(A, B, C, D) jlo.axis_keys.push_back(JoystickAxisCmb(A, B, C, D)) + +static JoystickLayout create_default_layout() +{ + JoystickLayout jlo; + + jlo.axes_dead_border = 1024; + + const JoystickAxisLayout axes[JA_COUNT] = { + {0, 1}, // JA_SIDEWARD_MOVE + {1, 1}, // JA_FORWARD_MOVE + {3, 1}, // JA_FRUSTUM_HORIZONTAL + {4, 1}, // JA_FRUSTUM_VERTICAL + }; + memcpy(jlo.axes, axes, sizeof(jlo.axes)); + + u32 sb = 1 << 7; // START button mask + u32 fb = 1 << 3; // FOUR button mask + u32 bm = sb | fb; // Mask for Both Modifiers + + // The back button means "ESC". + JLO_B_PB(KeyType::ESC, 1 << 6, 1 << 6); + + // The start button counts as modifier as well as use key. + // JLO_B_PB(KeyType::USE, sb, sb)); + + // Accessible without start modifier button pressed + // regardless whether four is pressed or not + JLO_B_PB(KeyType::SNEAK, sb | 1 << 2, 1 << 2); + + // Accessible without four modifier button pressed + // regardless whether start is pressed or not + JLO_B_PB(KeyType::MOUSE_L, fb | 1 << 4, 1 << 4); + JLO_B_PB(KeyType::MOUSE_R, fb | 1 << 5, 1 << 5); + + // Accessible without any modifier pressed + JLO_B_PB(KeyType::JUMP, bm | 1 << 0, 1 << 0); + JLO_B_PB(KeyType::SPECIAL1, bm | 1 << 1, 1 << 1); + + // Accessible with start button not pressed, but four pressed + // TODO find usage for button 0 + JLO_B_PB(KeyType::DROP, bm | 1 << 1, fb | 1 << 1); + JLO_B_PB(KeyType::SCROLL_UP, bm | 1 << 4, fb | 1 << 4); + JLO_B_PB(KeyType::SCROLL_DOWN,bm | 1 << 5, fb | 1 << 5); + + // Accessible with start button and four pressed + // TODO find usage for buttons 0, 1 and 4, 5 + + // Now about the buttons simulated by the axes + + // Movement buttons, important for vessels + JLO_A_PB(KeyType::FORWARD, 1, 1, 1024); + JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024); + JLO_A_PB(KeyType::LEFT, 0, 1, 1024); + JLO_A_PB(KeyType::RIGHT, 0, -1, 1024); + + // Scroll buttons + JLO_A_PB(KeyType::SCROLL_UP, 2, -1, 1024); + JLO_A_PB(KeyType::SCROLL_DOWN, 5, -1, 1024); + + return jlo; +} + +static const JoystickLayout default_layout = create_default_layout(); + +JoystickController::JoystickController() +{ + m_layout = &default_layout; + doubling_dtime = g_settings->getFloat("repeat_joystick_button_time"); + + for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) { + m_past_pressed_time[i] = 0; + } + clear(); +} + +bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev) +{ + m_internal_time = getTimeMs() / 1000.f; + + std::bitset keys_pressed; + + // First generate a list of keys pressed + + for (size_t i = 0; i < m_layout->button_keys.size(); i++) { + if (m_layout->button_keys[i].isTriggered(ev)) { + keys_pressed.set(m_layout->button_keys[i].key); + } + } + + for (size_t i = 0; i < m_layout->axis_keys.size(); i++) { + if (m_layout->axis_keys[i].isTriggered(ev)) { + keys_pressed.set(m_layout->axis_keys[i].key); + } + } + + // Then update the values + + for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) { + if (keys_pressed[i]) { + if (!m_past_pressed_keys[i] && + m_past_pressed_time[i] < m_internal_time - doubling_dtime) { + m_past_pressed_keys[i] = true; + m_past_pressed_time[i] = m_internal_time; + } + } else if (m_pressed_keys[i]) { + m_past_released_keys[i] = true; + } + + m_pressed_keys[i] = keys_pressed[i]; + } + + for (size_t i = 0; i < JA_COUNT; i++) { + const JoystickAxisLayout &ax_la = m_layout->axes[i]; + m_axes_vals[i] = ax_la.invert * ev.Axis[ax_la.axis_id]; + } + + + return true; +} + +void JoystickController::clear() +{ + m_pressed_keys.reset(); + m_past_pressed_keys.reset(); + m_past_released_keys.reset(); + memset(m_axes_vals, 0, sizeof(m_axes_vals)); +} + +s16 JoystickController::getAxisWithoutDead(JoystickAxis axis) +{ + s16 v = m_axes_vals[axis]; + if (((v > 0) && (v < m_layout->axes_dead_border)) || + ((v < 0) && (v > -m_layout->axes_dead_border))) + return 0; + return v; +} diff --git a/src/client/joystick_controller.h b/src/client/joystick_controller.h new file mode 100644 index 000000000..ed0ee4068 --- /dev/null +++ b/src/client/joystick_controller.h @@ -0,0 +1,163 @@ +/* +Minetest +Copyright (C) 2016 est31, + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef JOYSTICK_HEADER +#define JOYSTICK_HEADER + +#include "irrlichttypes_extrabloated.h" +#include "keys.h" +#include +#include + +enum JoystickAxis { + JA_SIDEWARD_MOVE, + JA_FORWARD_MOVE, + + JA_FRUSTUM_HORIZONTAL, + JA_FRUSTUM_VERTICAL, + + // To know the count of enum values + JA_COUNT, +}; + +struct JoystickAxisLayout { + u16 axis_id; + // -1 if to invert, 1 if to keep it. + int invert; +}; + + +struct JoystickCombination { + + virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const=0; + + GameKeyType key; +}; + +struct JoystickButtonCmb : public JoystickCombination { + + JoystickButtonCmb() {} + JoystickButtonCmb(GameKeyType key, u32 filter_mask, u32 compare_mask) : + filter_mask(filter_mask), + compare_mask(compare_mask) + { + this->key = key; + } + + virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const; + + u32 filter_mask; + u32 compare_mask; +}; + +struct JoystickAxisCmb : public JoystickCombination { + + JoystickAxisCmb() {} + JoystickAxisCmb(GameKeyType key, u16 axis_to_compare, int direction, s16 thresh) : + axis_to_compare(axis_to_compare), + direction(direction), + thresh(thresh) + { + this->key = key; + } + + virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const; + + u16 axis_to_compare; + + // if -1, thresh must be smaller than the axis value in order to trigger + // if 1, thresh must be bigger than the axis value in order to trigger + int direction; + s16 thresh; +}; + +struct JoystickLayout { + std::vector button_keys; + std::vector axis_keys; + JoystickAxisLayout axes[JA_COUNT]; + s16 axes_dead_border; +}; + +class JoystickController { + +public: + JoystickController(); + bool handleEvent(const irr::SEvent::SJoystickEvent &ev); + void clear(); + + bool wasKeyDown(GameKeyType b) + { + bool r = m_past_pressed_keys[b]; + m_past_pressed_keys[b] = false; + return r; + } + bool getWasKeyDown(GameKeyType b) + { + return m_past_pressed_keys[b]; + } + void clearWasKeyDown(GameKeyType b) + { + m_past_pressed_keys[b] = false; + } + + bool wasKeyReleased(GameKeyType b) + { + bool r = m_past_released_keys[b]; + m_past_released_keys[b] = false; + return r; + } + bool getWasKeyReleased(GameKeyType b) + { + return m_past_pressed_keys[b]; + } + void clearWasKeyReleased(GameKeyType b) + { + m_past_pressed_keys[b] = false; + } + + bool isKeyDown(GameKeyType b) + { + return m_pressed_keys[b]; + } + + s16 getAxis(JoystickAxis axis) + { + return m_axes_vals[axis]; + } + + s16 getAxisWithoutDead(JoystickAxis axis); + + f32 doubling_dtime; + +private: + const JoystickLayout *m_layout; + + s16 m_axes_vals[JA_COUNT]; + + std::bitset m_pressed_keys; + + f32 m_internal_time; + + f32 m_past_pressed_time[KeyType::INTERNAL_ENUM_COUNT]; + + std::bitset m_past_pressed_keys; + std::bitset m_past_released_keys; +}; + +#endif diff --git a/src/client/keys.h b/src/client/keys.h index 08b1c4123..0921bc166 100644 --- a/src/client/keys.h +++ b/src/client/keys.h @@ -67,6 +67,12 @@ public: DEBUG_STACKS, + // joystick specific keys + MOUSE_L, + MOUSE_R, + SCROLL_UP, + SCROLL_DOWN, + // Fake keycode for array size and internal checks INTERNAL_ENUM_COUNT diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 35ab1c508..eeb85c8a6 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -1056,7 +1056,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) PlayerControl controls = player->getPlayerControl(); bool walking = false; - if(controls.up || controls.down || controls.left || controls.right) + if (controls.up || controls.down || controls.left || controls.right || + controls.forw_move_joystick_axis != 0.f || + controls.sidew_move_joystick_axis != 0.f) walking = true; f32 new_speed = player->local_animation_speed; diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 632ec0df9..43a7a7c00 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -116,6 +116,9 @@ void set_default_settings(Settings *settings) settings->setDefault("free_move", "false"); settings->setDefault("noclip", "false"); settings->setDefault("continuous_forward", "false"); + settings->setDefault("enable_joysticks", "true"); + settings->setDefault("repeat_joystick_button_time", "0.17"); + settings->setDefault("joystick_frustum_sensitivity", "170"); settings->setDefault("cinematic", "false"); settings->setDefault("camera_smoothing", "0"); settings->setDefault("cinematic_camera_smoothing", "0.7"); diff --git a/src/game.cpp b/src/game.cpp index ac1c0fe6b..ba77d299a 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client.h" #include "client/tile.h" // For TextureSource #include "client/keys.h" +#include "client/joystick_controller.h" #include "clientmap.h" #include "clouds.h" #include "config.h" @@ -1108,12 +1109,14 @@ bool nodePlacementPrediction(Client &client, static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec, InventoryManager *invmgr, IGameDef *gamedef, IWritableTextureSource *tsrc, IrrlichtDevice *device, + JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest, Client *client) { if (*cur_formspec == 0) { - *cur_formspec = new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr, - invmgr, gamedef, tsrc, fs_src, txt_dest, client); + *cur_formspec = new GUIFormSpecMenu(device, joystick, + guiroot, -1, &g_menumgr, invmgr, gamedef, tsrc, + fs_src, txt_dest, client); (*cur_formspec)->doPause = false; /* @@ -1138,7 +1141,8 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec, static void show_deathscreen(GUIFormSpecMenu **cur_formspec, InventoryManager *invmgr, IGameDef *gamedef, - IWritableTextureSource *tsrc, IrrlichtDevice *device, Client *client) + IWritableTextureSource *tsrc, IrrlichtDevice *device, + JoystickController *joystick, Client *client) { std::string formspec = std::string(FORMSPEC_VERSION_STRING) + @@ -1154,14 +1158,15 @@ static void show_deathscreen(GUIFormSpecMenu **cur_formspec, FormspecFormSource *fs_src = new FormspecFormSource(formspec); LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client); - create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, fs_src, txt_dst, NULL); + create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, + joystick, fs_src, txt_dst, NULL); } /******************************************************************************/ static void show_pause_menu(GUIFormSpecMenu **cur_formspec, InventoryManager *invmgr, IGameDef *gamedef, IWritableTextureSource *tsrc, IrrlichtDevice *device, - bool singleplayermode) + JoystickController *joystick, bool singleplayermode) { #ifdef __ANDROID__ std::string control_text = strgettext("Default Controls:\n" @@ -1226,7 +1231,8 @@ static void show_pause_menu(GUIFormSpecMenu **cur_formspec, FormspecFormSource *fs_src = new FormspecFormSource(os.str()); LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU"); - create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, fs_src, txt_dst, NULL); + create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, + joystick, fs_src, txt_dst, NULL); std::string con("btn_continue"); (*cur_formspec)->setFocus(con); (*cur_formspec)->doPause = true; @@ -1574,9 +1580,10 @@ protected: void decreaseViewRange(float *statustext_time); void toggleFullViewRange(float *statustext_time); - void updateCameraDirection(CameraOrientation *cam, VolatileRunFlags *flags); + void updateCameraDirection(CameraOrientation *cam, VolatileRunFlags *flags, + float dtime); void updateCameraOrientation(CameraOrientation *cam, - const VolatileRunFlags &flags); + const VolatileRunFlags &flags, float dtime); void updatePlayerControl(const CameraOrientation &cam); void step(f32 *dtime); void processClientEvents(CameraOrientation *cam, float *damage_flash); @@ -1611,34 +1618,39 @@ protected: static void settingChangedCallback(const std::string &setting_name, void *data); void readSettings(); - bool getLeftClicked() + inline bool getLeftClicked() { - return input->getLeftClicked(); + return input->getLeftClicked() || + input->joystick.getWasKeyDown(KeyType::MOUSE_L); } - bool getRightClicked() + inline bool getRightClicked() { - return input->getRightClicked(); + return input->getRightClicked() || + input->joystick.getWasKeyDown(KeyType::MOUSE_R); } - bool isLeftPressed() + inline bool isLeftPressed() { - return input->getLeftState(); + return input->getLeftState() || + input->joystick.isKeyDown(KeyType::MOUSE_L); } - bool isRightPressed() + inline bool isRightPressed() { - return input->getRightState(); + return input->getRightState() || + input->joystick.isKeyDown(KeyType::MOUSE_R); } - bool getLeftReleased() + inline bool getLeftReleased() { - return input->getLeftReleased(); + return input->getLeftReleased() || + input->joystick.wasKeyReleased(KeyType::MOUSE_L); } - bool isKeyDown(GameKeyType k) + inline bool isKeyDown(GameKeyType k) { - return input->isKeyDown(keycache.key[k]); + return input->isKeyDown(keycache.key[k]) || input->joystick.isKeyDown(k); } - bool wasKeyDown(GameKeyType k) + inline bool wasKeyDown(GameKeyType k) { - return input->wasKeyDown(keycache.key[k]); + return input->wasKeyDown(keycache.key[k]) || input->joystick.wasKeyDown(k); } #ifdef __ANDROID__ @@ -1724,9 +1736,11 @@ private: */ bool m_cache_doubletap_jump; bool m_cache_enable_clouds; + bool m_cache_enable_joysticks; bool m_cache_enable_particles; bool m_cache_enable_fog; f32 m_cache_mouse_sensitivity; + f32 m_cache_joystick_frustum_sensitivity; f32 m_repeat_right_click_time; #ifdef __ANDROID__ @@ -1762,12 +1776,16 @@ Game::Game() : &settingChangedCallback, this); g_settings->registerChangedCallback("enable_clouds", &settingChangedCallback, this); + g_settings->registerChangedCallback("doubletap_joysticks", + &settingChangedCallback, this); g_settings->registerChangedCallback("enable_particles", &settingChangedCallback, this); g_settings->registerChangedCallback("enable_fog", &settingChangedCallback, this); g_settings->registerChangedCallback("mouse_sensitivity", &settingChangedCallback, this); + g_settings->registerChangedCallback("joystick_frustum_sensitivity", + &settingChangedCallback, this); g_settings->registerChangedCallback("repeat_rightclick_time", &settingChangedCallback, this); @@ -1930,7 +1948,7 @@ void Game::run() updateProfilers(runData, stats, draw_times, dtime); processUserInput(&flags, &runData, dtime); // Update camera before player movement to avoid camera lag of one frame - updateCameraDirection(&cam_view_target, &flags); + updateCameraDirection(&cam_view_target, &flags, dtime); float cam_smoothing = 0; if (g_settings->getBool("cinematic")) cam_smoothing = 1 - g_settings->getFloat("cinematic_camera_smoothing"); @@ -2727,7 +2745,8 @@ void Game::processKeyInput(VolatileRunFlags *flags, } else if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) { if (!gui_chat_console->isOpenInhibited()) { show_pause_menu(¤t_formspec, client, gamedef, - texture_src, device, simple_singleplayer_mode); + texture_src, device, &input->joystick, + simple_singleplayer_mode); } } else if (wasKeyDown(KeyType::CHAT)) { openConsole(0.2, L""); @@ -2813,12 +2832,21 @@ void Game::processItemSelection(u16 *new_playeritem) u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1, player->hud_hotbar_itemcount - 1); - if (wheel < 0) + s32 dir = wheel; + + if (input->joystick.wasKeyDown(KeyType::SCROLL_DOWN)) { + dir = -1; + } + + if (input->joystick.wasKeyDown(KeyType::SCROLL_UP)) { + dir = 1; + } + + if (dir < 0) *new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : 0; - else if (wheel > 0) + else if (dir > 0) *new_playeritem = *new_playeritem > 0 ? *new_playeritem - 1 : max_item; - // else wheel == 0 - + // else dir == 0 /* Item selection using keyboard */ @@ -2868,7 +2896,7 @@ void Game::openInventory() TextDest *txt_dst = new TextDestPlayerInventory(client); create_formspec_menu(¤t_formspec, client, gamedef, texture_src, - device, fs_src, txt_dst, client); + device, &input->joystick, fs_src, txt_dst, client); InventoryLocation inventoryloc; inventoryloc.setCurrentPlayer(); @@ -3154,7 +3182,7 @@ void Game::toggleFullViewRange(float *statustext_time) void Game::updateCameraDirection(CameraOrientation *cam, - VolatileRunFlags *flags) + VolatileRunFlags *flags, float dtime) { if ((device->isWindowActive() && noMenuActive()) || random_input) { @@ -3169,7 +3197,7 @@ void Game::updateCameraDirection(CameraOrientation *cam, if (flags->first_loop_after_window_activation) flags->first_loop_after_window_activation = false; else - updateCameraOrientation(cam, *flags); + updateCameraOrientation(cam, *flags, dtime); input->setMousePos((driver->getScreenSize().Width / 2), (driver->getScreenSize().Height / 2)); @@ -3187,9 +3215,8 @@ void Game::updateCameraDirection(CameraOrientation *cam, } } - void Game::updateCameraOrientation(CameraOrientation *cam, - const VolatileRunFlags &flags) + const VolatileRunFlags &flags, float dtime) { #ifdef HAVE_TOUCHSCREENGUI if (g_touchscreengui) { @@ -3197,6 +3224,7 @@ void Game::updateCameraOrientation(CameraOrientation *cam, cam->camera_pitch = g_touchscreengui->getPitch(); } else { #endif + s32 dx = input->getMousePos().X - (driver->getScreenSize().Width / 2); s32 dy = input->getMousePos().Y - (driver->getScreenSize().Height / 2); @@ -3212,6 +3240,14 @@ void Game::updateCameraOrientation(CameraOrientation *cam, } #endif + if (m_cache_enable_joysticks) { + f32 c = m_cache_joystick_frustum_sensitivity * (1.f / 32767.f) * dtime; + cam->camera_yaw -= input->joystick.getAxisWithoutDead(JA_FRUSTUM_HORIZONTAL) * + c; + cam->camera_pitch += input->joystick.getAxisWithoutDead(JA_FRUSTUM_VERTICAL) * + c; + } + cam->camera_pitch = rangelim(cam->camera_pitch, -89.5, 89.5); } @@ -3220,30 +3256,36 @@ void Game::updatePlayerControl(const CameraOrientation &cam) { //TimeTaker tt("update player control", NULL, PRECISION_NANO); + // DO NOT use the isKeyDown method for the forward, backward, left, right + // buttons, as the code that uses the controls needs to be able to + // distinguish between the two in order to know when to use joysticks. + PlayerControl control( input->isKeyDown(keycache.key[KeyType::FORWARD]), input->isKeyDown(keycache.key[KeyType::BACKWARD]), input->isKeyDown(keycache.key[KeyType::LEFT]), input->isKeyDown(keycache.key[KeyType::RIGHT]), - input->isKeyDown(keycache.key[KeyType::JUMP]), - input->isKeyDown(keycache.key[KeyType::SPECIAL1]), - input->isKeyDown(keycache.key[KeyType::SNEAK]), - input->getLeftState(), - input->getRightState(), + isKeyDown(KeyType::JUMP), + isKeyDown(KeyType::SPECIAL1), + isKeyDown(KeyType::SNEAK), + isLeftPressed(), + isRightPressed(), cam.camera_pitch, - cam.camera_yaw + cam.camera_yaw, + input->joystick.getAxisWithoutDead(JA_SIDEWARD_MOVE), + input->joystick.getAxisWithoutDead(JA_FORWARD_MOVE) ); u32 keypress_bits = - ( (u32)(input->isKeyDown(keycache.key[KeyType::FORWARD]) & 0x1) << 0) | - ( (u32)(input->isKeyDown(keycache.key[KeyType::BACKWARD]) & 0x1) << 1) | - ( (u32)(input->isKeyDown(keycache.key[KeyType::LEFT]) & 0x1) << 2) | - ( (u32)(input->isKeyDown(keycache.key[KeyType::RIGHT]) & 0x1) << 3) | - ( (u32)(input->isKeyDown(keycache.key[KeyType::JUMP]) & 0x1) << 4) | - ( (u32)(input->isKeyDown(keycache.key[KeyType::SPECIAL1]) & 0x1) << 5) | - ( (u32)(input->isKeyDown(keycache.key[KeyType::SNEAK]) & 0x1) << 6) | - ( (u32)(input->getLeftState() & 0x1) << 7) | - ( (u32)(input->getRightState() & 0x1) << 8 + ( (u32)(isKeyDown(KeyType::FORWARD) & 0x1) << 0) | + ( (u32)(isKeyDown(KeyType::BACKWARD) & 0x1) << 1) | + ( (u32)(isKeyDown(KeyType::LEFT) & 0x1) << 2) | + ( (u32)(isKeyDown(KeyType::RIGHT) & 0x1) << 3) | + ( (u32)(isKeyDown(KeyType::JUMP) & 0x1) << 4) | + ( (u32)(isKeyDown(KeyType::SPECIAL1) & 0x1) << 5) | + ( (u32)(isKeyDown(KeyType::SNEAK) & 0x1) << 6) | + ( (u32)(isLeftPressed() & 0x1) << 7) | + ( (u32)(isRightPressed() & 0x1) << 8 ); #ifdef ANDROID @@ -3312,7 +3354,7 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) cam->camera_pitch = event.player_force_move.pitch; } else if (event.type == CE_DEATHSCREEN) { show_deathscreen(¤t_formspec, client, gamedef, texture_src, - device, client); + device, &input->joystick, client); chat_backend->addMessage(L"", L"You died."); @@ -3328,7 +3370,8 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) new TextDestPlayerInventory(client, *(event.show_formspec.formname)); create_formspec_menu(¤t_formspec, client, gamedef, - texture_src, device, fs_src, txt_dst, client); + texture_src, device, &input->joystick, + fs_src, txt_dst, client); delete(event.show_formspec.formspec); delete(event.show_formspec.formname); @@ -3723,8 +3766,14 @@ void Game::processPlayerInteraction(GameRunData *runData, input->resetLeftClicked(); input->resetRightClicked(); + input->joystick.clearWasKeyDown(KeyType::MOUSE_L); + input->joystick.clearWasKeyDown(KeyType::MOUSE_R); + input->resetLeftReleased(); input->resetRightReleased(); + + input->joystick.clearWasKeyReleased(KeyType::MOUSE_L); + input->joystick.clearWasKeyReleased(KeyType::MOUSE_R); } @@ -3785,7 +3834,7 @@ void Game::handlePointingAtNode(GameRunData *runData, TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client); create_formspec_menu(¤t_formspec, client, gamedef, - texture_src, device, fs_src, txt_dst, client); + texture_src, device, &input->joystick, fs_src, txt_dst, client); current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc); } else { @@ -4468,12 +4517,14 @@ void Game::settingChangedCallback(const std::string &setting_name, void *data) void Game::readSettings() { - m_cache_doubletap_jump = g_settings->getBool("doubletap_jump"); - m_cache_enable_clouds = g_settings->getBool("enable_clouds"); - m_cache_enable_particles = g_settings->getBool("enable_particles"); - m_cache_enable_fog = g_settings->getBool("enable_fog"); - m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity"); - m_repeat_right_click_time = g_settings->getFloat("repeat_rightclick_time"); + m_cache_doubletap_jump = g_settings->getBool("doubletap_jump"); + m_cache_enable_clouds = g_settings->getBool("enable_clouds"); + m_cache_enable_joysticks = g_settings->getBool("enable_joysticks"); + m_cache_enable_particles = g_settings->getBool("enable_particles"); + m_cache_enable_fog = g_settings->getBool("enable_fog"); + m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity"); + m_cache_joystick_frustum_sensitivity = g_settings->getFloat("joystick_frustum_sensitivity"); + m_repeat_right_click_time = g_settings->getFloat("repeat_rightclick_time"); m_cache_mouse_sensitivity = rangelim(m_cache_mouse_sensitivity, 0.001, 100.0); } diff --git a/src/game.h b/src/game.h index d8c2f78fc..df32e3397 100644 --- a/src/game.h +++ b/src/game.h @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes_extrabloated.h" #include #include "client/keys.h" +#include "client/joystick_controller.h" #include "keycode.h" #include @@ -135,6 +136,8 @@ public: virtual void step(float dtime) {} virtual void clear() {} + + JoystickController joystick; }; class ChatBackend; /* to avoid having to include chat.h */ diff --git a/src/guiEngine.cpp b/src/guiEngine.cpp index 96de7a4f7..b9d796ccb 100644 --- a/src/guiEngine.cpp +++ b/src/guiEngine.cpp @@ -131,6 +131,7 @@ void MenuMusicFetcher::fetchSounds(const std::string &name, /** GUIEngine */ /******************************************************************************/ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev, + JoystickController *joystick, gui::IGUIElement* parent, IMenuManager *menumgr, scene::ISceneManager* smgr, @@ -189,6 +190,7 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev, /* Create menu */ m_menu = new GUIFormSpecMenu(m_device, + joystick, m_parent, -1, m_menumanager, diff --git a/src/guiEngine.h b/src/guiEngine.h index fa98a21e4..a59436953 100644 --- a/src/guiEngine.h +++ b/src/guiEngine.h @@ -149,7 +149,8 @@ public: * @param smgr scene manager to add scene elements to * @param data struct to transfer data to main game handling */ - GUIEngine( irr::IrrlichtDevice* dev, + GUIEngine(irr::IrrlichtDevice* dev, + JoystickController *joystick, gui::IGUIElement* parent, IMenuManager *menumgr, scene::ISceneManager* smgr, diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index cf01dc38c..a9cbb6254 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -79,6 +79,7 @@ static unsigned int font_line_height(gui::IGUIFont *font) } GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev, + JoystickController *joystick, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, InventoryManager *invmgr, IGameDef *gamedef, ISimpleTextureSource *tsrc, IFormSource* fsrc, TextDest* tdst, @@ -102,6 +103,7 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev, m_text_dst(tdst), m_formspec_version(0), m_focused_element(""), + m_joystick(joystick), m_font(NULL), m_remap_dbl_click(remap_dbl_click) #ifdef __ANDROID__ @@ -2459,7 +2461,7 @@ void GUIFormSpecMenu::drawMenu() Draw static text elements */ for (u32 i = 0; i < m_static_texts.size(); i++) { - const StaticTextSpec &spec = m_static_texts[i]; + const StaticTextSpec &spec = m_static_texts[i]; core::rect rect = spec.rect; if (spec.parent_button && spec.parent_button->isPressed()) { #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) @@ -3024,6 +3026,25 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) } #endif + if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) { + /* TODO add a check like: + if (event.JoystickEvent != joystick_we_listen_for) + return false; + */ + bool handled = m_joystick->handleEvent(event.JoystickEvent); + if (handled) { + if (m_joystick->wasKeyDown(KeyType::ESC)) { + tryClose(); + } else if (m_joystick->wasKeyDown(KeyType::JUMP)) { + if (m_allowclose) { + acceptInput(quit_mode_accept); + quitMenu(); + } + } + } + return handled; + } + return false; } @@ -3085,19 +3106,24 @@ bool GUIFormSpecMenu::DoubleClickDetection(const SEvent event) return false; } +void GUIFormSpecMenu::tryClose() +{ + if (m_allowclose) { + doPause = false; + acceptInput(quit_mode_cancel); + quitMenu(); + } else { + m_text_dst->gotText(L"MenuQuit"); + } +} + bool GUIFormSpecMenu::OnEvent(const SEvent& event) { if (event.EventType==EET_KEY_INPUT_EVENT) { KeyPress kp(event.KeyInput); if (event.KeyInput.PressedDown && ( (kp == EscapeKey) || (kp == getKeySetting("keymap_inventory")) || (kp == CancelKey))) { - if (m_allowclose) { - doPause = false; - acceptInput(quit_mode_cancel); - quitMenu(); - } else { - m_text_dst->gotText(L"MenuQuit"); - } + tryClose(); return true; } else if (m_client != NULL && event.KeyInput.PressedDown && (kp == getKeySetting("keymap_screenshot"))) { diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index 4122b1f56..2fb55070d 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "modalMenu.h" #include "guiTable.h" #include "network/networkprotocol.h" +#include "client/joystick_controller.h" #include "util/string.h" #include "util/enriched_string.h" @@ -278,6 +279,7 @@ class GUIFormSpecMenu : public GUIModalMenu public: GUIFormSpecMenu(irr::IrrlichtDevice* dev, + JoystickController *joystick, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, InventoryManager *invmgr, @@ -433,10 +435,11 @@ protected: video::SColor m_default_tooltip_color; private: - IFormSource *m_form_src; - TextDest *m_text_dst; - unsigned int m_formspec_version; - std::string m_focused_element; + IFormSource *m_form_src; + TextDest *m_text_dst; + unsigned int m_formspec_version; + std::string m_focused_element; + JoystickController *m_joystick; typedef struct { bool explicit_size; @@ -494,6 +497,8 @@ private: bool parseSizeDirect(parserData* data, std::string element); void parseScrollBar(parserData* data, std::string element); + void tryClose(); + /** * check if event is part of a double click * @param event event to evaluate diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 507f31980..732ca8acf 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -528,18 +528,23 @@ void LocalPlayer::applyControl(float dtime) speedH += move_direction; } } - if(control.down) - { + if (control.down) { speedH -= move_direction; } - if(control.left) - { + if (!control.up && !control.down) { + speedH -= move_direction * + (control.forw_move_joystick_axis / 32767.f); + } + if (control.left) { speedH += move_direction.crossProduct(v3f(0,1,0)); } - if(control.right) - { + if (control.right) { speedH += move_direction.crossProduct(v3f(0,-1,0)); } + if (!control.left && !control.right) { + speedH -= move_direction.crossProduct(v3f(0,1,0)) * + (control.sidew_move_joystick_axis / 32767.f); + } if(control.jump) { if (free_move) { diff --git a/src/player.h b/src/player.h index b317cda4f..6687ca86e 100644 --- a/src/player.h +++ b/src/player.h @@ -46,6 +46,8 @@ struct PlayerControl RMB = false; pitch = 0; yaw = 0; + sidew_move_joystick_axis = .0f; + forw_move_joystick_axis = .0f; } PlayerControl( bool a_up, @@ -58,7 +60,9 @@ struct PlayerControl bool a_LMB, bool a_RMB, float a_pitch, - float a_yaw + float a_yaw, + float a_sidew_move_joystick_axis, + float a_forw_move_joystick_axis ) { up = a_up; @@ -72,6 +76,8 @@ struct PlayerControl RMB = a_RMB; pitch = a_pitch; yaw = a_yaw; + sidew_move_joystick_axis = a_sidew_move_joystick_axis; + forw_move_joystick_axis = a_forw_move_joystick_axis; } bool up; bool down; @@ -84,6 +90,8 @@ struct PlayerControl bool RMB; float pitch; float yaw; + float sidew_move_joystick_axis; + float forw_move_joystick_axis; }; class Map; -- cgit v1.2.3