From 987e565eeb80f0fe2825267de728f8a1989a051d Mon Sep 17 00:00:00 2001
From: Craig Robbins <kde.psych@gmail.com>
Date: Mon, 10 Nov 2014 12:26:19 +1000
Subject: [PATCH] Create faster key cache for main game loop (client)

---
 src/game.cpp                | 231 +++++++++++++++++++++++++++---------
 src/guiKeyChangeMenu.cpp    |   8 ++
 src/mainmenumanager.h       |  11 ++
 src/quicktune_shortcutter.h |   5 +
 4 files changed, 202 insertions(+), 53 deletions(-)

diff --git a/src/game.cpp b/src/game.cpp
index fee45e31d..1396e9439 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1181,9 +1181,119 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
 }
 
 
+/****************************************************************************
+ Fast key cache for main game loop
+ ****************************************************************************/
+
+/* This is faster than using getKeySetting with the tradeoff that functions
+ * using it must make sure that it's initialised before using it and there is
+ * no error handling (for example bounds checking). This is really intended for
+ * use only in the main running loop of the client (the_game()) where the faster
+ * (up to 10x faster) key lookup is an asset. Other parts of the codebase
+ * (e.g. formspecs) should continue using getKeySetting().
+ */
+struct KeyCache {
+
+	KeyCache() { populate(); }
+
+	enum {
+		// Player movement
+		KEYMAP_ID_FORWARD,
+		KEYMAP_ID_BACKWARD,
+		KEYMAP_ID_LEFT,
+		KEYMAP_ID_RIGHT,
+		KEYMAP_ID_JUMP,
+		KEYMAP_ID_SPECIAL1,
+		KEYMAP_ID_SNEAK,
+
+		// Other
+		KEYMAP_ID_DROP,
+		KEYMAP_ID_INVENTORY,
+		KEYMAP_ID_CHAT,
+		KEYMAP_ID_CMD,
+		KEYMAP_ID_CONSOLE,
+		KEYMAP_ID_FREEMOVE,
+		KEYMAP_ID_FASTMOVE,
+		KEYMAP_ID_NOCLIP,
+		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];
+};
+
+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_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_FREEMOVE]     = getKeySetting("keymap_freemove");
+	key[KEYMAP_ID_FASTMOVE]     = getKeySetting("keymap_fastmove");
+	key[KEYMAP_ID_NOCLIP]       = getKeySetting("keymap_noclip");
+	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]
+			= getKeySetting("keymap_toggle_force_fog_off");
+	key[KEYMAP_ID_TOGGLE_UPDATE_CAMERA]
+			= getKeySetting("keymap_toggle_update_camera");
+	key[KEYMAP_ID_TOGGLE_DEBUG]
+			= getKeySetting("keymap_toggle_debug");
+	key[KEYMAP_ID_TOGGLE_PROFILER]
+			= getKeySetting("keymap_toggle_profiler");
+	key[KEYMAP_ID_CAMERA_MODE]
+			= getKeySetting("keymap_camera_mode");
+	key[KEYMAP_ID_INCREASE_VIEWING_RANGE]
+			= getKeySetting("keymap_increase_viewing_range_min");
+	key[KEYMAP_ID_DECREASE_VIEWING_RANGE]
+			= getKeySetting("keymap_decrease_viewing_range_min");
+	key[KEYMAP_ID_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[KEYMAP_ID_DEBUG_STACKS]   = getKeySetting("keymap_print_debug_stacks");
+}
+
 
 /****************************************************************************
- THE GAME
+
  ****************************************************************************/
 
 const float object_hit_delay = 0.2;
@@ -1264,6 +1374,10 @@ struct VolatileRunFlags {
 };
 
 
+/****************************************************************************
+ THE GAME
+ ****************************************************************************/
+
 /* This is not intended to be a public class. If a public class becomes
  * desirable then it may be better to create another 'wrapper' class that
  * hides most of the stuff in this class (nothing in this class is required
@@ -1458,6 +1572,8 @@ class Game
 
 	std::wstring infotext;
 	std::wstring statustext;
+
+	KeyCache keycache;
 };
 
 Game::Game() :
@@ -2186,6 +2302,11 @@ inline bool Game::handleCallbacks()
 		g_gamecallback->keyconfig_requested = false;
 	}
 
+	if (g_gamecallback->keyconfig_changed) {
+		keycache.populate(); // update the cache with new settings
+		g_gamecallback->keyconfig_changed = false;
+	}
+
 	return true;
 }
 
@@ -2322,70 +2443,63 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
 		u32 *profiler_current_page,
 		u32 profiler_max_page)
 {
-	if (input->wasKeyDown(getKeySetting("keymap_drop"))) {
+
+	//TimeTaker tt("process kybd input", NULL, PRECISION_NANO);
+
+	if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DROP])) {
 		dropSelectedItem();
-	} else if (input->wasKeyDown(getKeySetting("keymap_inventory"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INVENTORY])) {
 		openInventory();
 	} else if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) {
 		show_pause_menu(&current_formspec, client, gamedef, texture_src, device,
 				simple_singleplayer_mode);
-	} else if (input->wasKeyDown(getKeySetting("keymap_chat"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CHAT])) {
 		show_chat_menu(&current_formspec, client, gamedef, texture_src, device,
 				client, "");
-	} else if (input->wasKeyDown(getKeySetting("keymap_cmd"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CMD])) {
 		show_chat_menu(&current_formspec, client, gamedef, texture_src, device,
 				client, "/");
-	} else if (input->wasKeyDown(getKeySetting("keymap_console"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CONSOLE])) {
 		openConsole();
-	} else if (input->wasKeyDown(getKeySetting("keymap_freemove"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FREEMOVE])) {
 		toggleFreeMove(statustext_time);
-	} else if (input->wasKeyDown(getKeySetting("keymap_jump"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP])) {
 		toggleFreeMoveAlt(statustext_time, jump_timer);
 		*reset_jump_timer = true;
-	} else if (input->wasKeyDown(getKeySetting("keymap_fastmove"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FASTMOVE])) {
 		toggleFast(statustext_time);
-	} else if (input->wasKeyDown(getKeySetting("keymap_noclip"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_NOCLIP])) {
 		toggleNoClip(statustext_time);
-	} else if (input->wasKeyDown(getKeySetting("keymap_screenshot"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_SCREENSHOT])) {
 		client->makeScreenshot(device);
-	} else if (input->wasKeyDown(getKeySetting("keymap_toggle_hud"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_HUD])) {
 		toggleHud(statustext_time, &flags->show_hud);
-	} else if (input->wasKeyDown(getKeySetting("keymap_toggle_chat"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_CHAT])) {
 		toggleChat(statustext_time, &flags->show_chat);
-	} else if (input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_FORCE_FOG_OFF])) {
 		toggleFog(statustext_time, &flags->force_fog_off);
-	} else if (input->wasKeyDown(getKeySetting("keymap_toggle_update_camera"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_UPDATE_CAMERA])) {
 		toggleUpdateCamera(statustext_time, &flags->disable_camera_update);
-	} else if (input->wasKeyDown(getKeySetting("keymap_toggle_debug"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_DEBUG])) {
 		toggleDebug(statustext_time, &flags->show_debug, &flags->show_profiler_graph);
-	} else if (input->wasKeyDown(getKeySetting("keymap_toggle_profiler"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_PROFILER])) {
 		toggleProfiler(statustext_time, profiler_current_page, profiler_max_page);
-	} else if (input->wasKeyDown(getKeySetting("keymap_increase_viewing_range_min"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INCREASE_VIEWING_RANGE])) {
 		increaseViewRange(statustext_time);
-	} else if (input->wasKeyDown(getKeySetting("keymap_decrease_viewing_range_min"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DECREASE_VIEWING_RANGE])) {
 		decreaseViewRange(statustext_time);
-	} else if (input->wasKeyDown(getKeySetting("keymap_rangeselect"))) {
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_RANGESELECT])) {
 		toggleFullViewRange(statustext_time);
-	}
-
-	// Handle QuicktuneShortcutter
-	if (input->wasKeyDown(getKeySetting("keymap_quicktune_next")))
+	} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_NEXT]))
 		quicktune->next();
-	else if (input->wasKeyDown(getKeySetting("keymap_quicktune_prev")))
+	else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_PREV]))
 		quicktune->prev();
-	else if (input->wasKeyDown(getKeySetting("keymap_quicktune_inc")))
+	else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_INC]))
 		quicktune->inc();
-	else if (input->wasKeyDown(getKeySetting("keymap_quicktune_dec")))
+	else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_DEC]))
 		quicktune->dec();
-
-	std::string msg = quicktune->getMessage();
-	if (msg != "") {
-		statustext = narrow_to_wide(msg);
-		*statustext_time = 0;
-	}
-
-	// Print debug stacks
-	if (input->wasKeyDown(getKeySetting("keymap_print_debug_stacks"))) {
+	else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DEBUG_STACKS])) {
+		// Print debug stacks
 		dstream << "-----------------------------------------"
 		        << std::endl;
 		dstream << DTIME << "Printing debug stacks:" << std::endl;
@@ -2398,6 +2512,14 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
 		*reset_jump_timer = false;
 		*jump_timer = 0.0;
 	}
+
+	//tt.stop();
+
+	if (quicktune->hasMessage()) {
+		std::string msg = quicktune->getMessage();
+		statustext = narrow_to_wide(msg);
+		*statustext_time = 0;
+	}
 }
 
 
@@ -2730,14 +2852,16 @@ void Game::updateCameraDirection(CameraOrientation *cam,
 
 void Game::updatePlayerControl(const CameraOrientation &cam)
 {
+	//TimeTaker tt("update player control", NULL, PRECISION_NANO);
+
 	PlayerControl control(
-		input->isKeyDown(getKeySetting("keymap_forward")),
-		input->isKeyDown(getKeySetting("keymap_backward")),
-		input->isKeyDown(getKeySetting("keymap_left")),
-		input->isKeyDown(getKeySetting("keymap_right")),
-		input->isKeyDown(getKeySetting("keymap_jump")),
-		input->isKeyDown(getKeySetting("keymap_special1")),
-		input->isKeyDown(getKeySetting("keymap_sneak")),
+		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->getLeftState(),
 		input->getRightState(),
 		cam.camera_pitch,
@@ -2746,17 +2870,18 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
 	client->setPlayerControl(control);
 	LocalPlayer *player = client->getEnv().getLocalPlayer();
 	player->keyPressed =
-			( (u32)(input->isKeyDown(getKeySetting("keymap_forward"))  & 0x1) << 0) |
-			( (u32)(input->isKeyDown(getKeySetting("keymap_backward")) & 0x1) << 1) |
-			( (u32)(input->isKeyDown(getKeySetting("keymap_left"))     & 0x1) << 2) |
-			( (u32)(input->isKeyDown(getKeySetting("keymap_right"))    & 0x1) << 3) |
-			( (u32)(input->isKeyDown(getKeySetting("keymap_jump"))     & 0x1) << 4) |
-			( (u32)(input->isKeyDown(getKeySetting("keymap_special1")) & 0x1) << 5) |
-			( (u32)(input->isKeyDown(getKeySetting("keymap_sneak"))    & 0x1) << 6) |
-			( (u32)(input->getLeftState()                              & 0x1) << 7) |
-			( (u32)(input->getRightState()                             & 0x1) << 8
+		( (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->getLeftState()                                        & 0x1) << 7) |
+		( (u32)(input->getRightState()                                       & 0x1) << 8
 	);
 
+	//tt.stop();
 }
 
 
@@ -3042,7 +3167,7 @@ void Game::updateCamera(VolatileRunFlags *flags, u32 busy_time,
 
 	v3s16 old_camera_offset = camera->getOffset();
 
-	if (input->wasKeyDown(getKeySetting("keymap_camera_mode"))) {
+	if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CAMERA_MODE])) {
 		camera->toggleCameraMode();
 		GenericCAO *playercao = player->getCAO();
 
diff --git a/src/guiKeyChangeMenu.cpp b/src/guiKeyChangeMenu.cpp
index 85222431e..8b0bb8278 100644
--- a/src/guiKeyChangeMenu.cpp
+++ b/src/guiKeyChangeMenu.cpp
@@ -32,8 +32,12 @@
 #include "settings.h"
 #include <algorithm>
 
+#include "mainmenumanager.h"  // for g_gamecallback
+
 #define KMaxButtonPerColumns 12
 
+extern MainGameCallback *g_gamecallback;
+
 enum
 {
 	GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
@@ -234,7 +238,11 @@ bool GUIKeyChangeMenu::acceptInput()
 		if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
 			g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
 	}
+
 	clearKeyCache();
+
+	g_gamecallback->signalKeyConfigChange();
+
 	return true;
 }
 
diff --git a/src/mainmenumanager.h b/src/mainmenumanager.h
index 56ba40129..db8aa9e19 100644
--- a/src/mainmenumanager.h
+++ b/src/mainmenumanager.h
@@ -35,6 +35,8 @@ class IGameCallback
 	virtual void disconnect() = 0;
 	virtual void changePassword() = 0;
 	virtual void changeVolume() = 0;
+
+	virtual void signalKeyConfigChange() = 0;
 };
 
 extern gui::IGUIEnvironment* guienv;
@@ -127,6 +129,7 @@ class MainGameCallback : public IGameCallback
 		changevolume_requested(false),
 		keyconfig_requested(false),
 		shutdown_requested(false),
+		keyconfig_changed(false),
 		device(a_device)
 	{
 	}
@@ -159,12 +162,20 @@ class MainGameCallback : public IGameCallback
 		keyconfig_requested = true;
 	}
 
+	virtual void signalKeyConfigChange()
+	{
+		keyconfig_changed = true;
+	}
+
 	
 	bool disconnect_requested;
 	bool changepassword_requested;
 	bool changevolume_requested;
 	bool keyconfig_requested;
 	bool shutdown_requested;
+
+	bool keyconfig_changed;
+
 	IrrlichtDevice *device;
 };
 
diff --git a/src/quicktune_shortcutter.h b/src/quicktune_shortcutter.h
index 16bcc07e8..fe1463c93 100644
--- a/src/quicktune_shortcutter.h
+++ b/src/quicktune_shortcutter.h
@@ -29,6 +29,11 @@ class QuicktuneShortcutter
 	u32 m_selected_i;
 	std::string m_message;
 public:
+	bool hasMessage()
+	{
+		return m_message != "";
+	}
+
 	std::string getMessage()
 	{
 		std::string s = m_message;
-- 
GitLab