LuaVoxelManip: Add option to allocate blank data
[oweals/minetest.git] / src / game.cpp
index b4bce33d33f4f35023029aeaab22c22614b90cf1..5d53c67d2556f9d47b8faaca34522ee14ec9e7cb 100644 (file)
@@ -70,6 +70,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/pointedthing.h"
 #include "drawscene.h"
 #include "content_cao.h"
+#include "fontengine.h"
 
 #ifdef HAVE_TOUCHSCREENGUI
 #include "touchscreengui.h"
@@ -360,12 +361,11 @@ PointedThing getPointedThing(Client *client, v3f player_position,
                for (s16 z = zstart; z <= zend; z++)
                        for (s16 x = xstart; x <= xend; x++) {
                                MapNode n;
+                               bool is_valid_position;
 
-                               try {
-                                       n = map.getNode(v3s16(x, y, z));
-                               } catch (InvalidPositionException &e) {
+                               n = map.getNodeNoEx(v3s16(x, y, z), &is_valid_position);
+                               if (!is_valid_position)
                                        continue;
-                               }
 
                                if (!isPointableNode(n, client, liquids_pointable))
                                        continue;
@@ -438,9 +438,8 @@ PointedThing getPointedThing(Client *client, v3f player_position,
 
 /* Profiler display */
 
-void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
-               gui::IGUIFont *font, u32 text_height, u32 show_profiler,
-               u32 show_profiler_max)
+void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, FontEngine *fe,
+               u32 show_profiler, u32 show_profiler_max, s32 screen_height)
 {
        if (show_profiler == 0) {
                guitext_profiler->setVisible(false);
@@ -452,14 +451,25 @@ void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
                guitext_profiler->setText(text.c_str());
                guitext_profiler->setVisible(true);
 
-               s32 w = font->getDimension(text.c_str()).Width;
+               s32 w = fe->getTextWidth(text.c_str());
 
                if (w < 400)
                        w = 400;
 
-               core::rect<s32> rect(6, 4 + (text_height + 5) * 2, 12 + w,
-                                    8 + (text_height + 5) * 2 +
-                                    font->getDimension(text.c_str()).Height);
+               unsigned text_height = fe->getTextHeight();
+
+               core::position2di upper_left, lower_right;
+
+               upper_left.X  = 6;
+               upper_left.Y  = (text_height + 5) * 2;
+               lower_right.X = 12 + w;
+               lower_right.Y = upper_left.Y + (text_height + 1) * MAX_PROFILER_TEXT_ROWS;
+
+               if (lower_right.Y > screen_height * 2 / 3)
+                       lower_right.Y = screen_height * 2 / 3;
+
+               core::rect<s32> rect(upper_left, lower_right);
+
                guitext_profiler->setRelativePosition(rect);
                guitext_profiler->setVisible(true);
        }
@@ -873,22 +883,31 @@ bool nodePlacementPrediction(Client &client,
        std::string prediction = playeritem_def.node_placement_prediction;
        INodeDefManager *nodedef = client.ndef();
        ClientMap &map = client.getEnv().getClientMap();
+       MapNode node;
+       bool is_valid_position;
 
-       if (prediction != "" && !nodedef->get(map.getNode(nodepos)).rightclickable) {
+       node = map.getNodeNoEx(nodepos, &is_valid_position);
+       if (!is_valid_position)
+               return false;
+
+       if (prediction != "" && !nodedef->get(node).rightclickable) {
                verbosestream << "Node placement prediction for "
                              << playeritem_def.name << " is "
                              << prediction << std::endl;
                v3s16 p = neighbourpos;
 
                // Place inside node itself if buildable_to
-               try {
-                       MapNode n_under = map.getNode(nodepos);
-
+               MapNode n_under = map.getNodeNoEx(nodepos, &is_valid_position);
+               if (is_valid_position)
+               {
                        if (nodedef->get(n_under).buildable_to)
                                p = nodepos;
-                       else if (!nodedef->get(map.getNode(p)).buildable_to)
-                               return false;
-               } catch (InvalidPositionException &e) {}
+                       else {
+                               node = map.getNodeNoEx(p, &is_valid_position);
+                               if (is_valid_position &&!nodedef->get(node).buildable_to)
+                                       return false;
+                       }
+               }
 
                // Find id of predicted node
                content_t id;
@@ -946,7 +965,7 @@ bool nodePlacementPrediction(Client &client,
                        else
                                pp = p + v3s16(0, -1, 0);
 
-                       if (!nodedef->get(map.getNode(pp)).walkable)
+                       if (!nodedef->get(map.getNodeNoEx(pp)).walkable)
                                return false;
                }
 
@@ -959,6 +978,7 @@ bool nodePlacementPrediction(Client &client,
                        // Dont place node when player would be inside new node
                        // NOTE: This is to be eventually implemented by a mod as client-side Lua
                        if (!nodedef->get(n).walkable ||
+                                       g_settings->getBool("enable_build_where_you_stand") ||
                                        (client.checkPrivilege("noclip") && g_settings->getBool("noclip")) ||
                                        (nodedef->get(n).walkable &&
                                         neighbourpos != player->getStandingNodePos() + v3s16(0, 1, 0) &&
@@ -1127,8 +1147,7 @@ static void show_pause_menu(GUIFormSpecMenu **cur_formspec,
 /******************************************************************************/
 static void updateChat(Client &client, f32 dtime, bool show_debug,
                const v2u32 &screensize, bool show_chat, u32 show_profiler,
-               ChatBackend &chat_backend, gui::IGUIStaticText *guitext_chat,
-               gui::IGUIFont *font)
+               ChatBackend &chat_backend, gui::IGUIStaticText *guitext_chat)
 {
        // Add chat log output for errors to be shown in chat
        static LogOutputBuffer chat_log_error_buf(LMT_ERROR);
@@ -1151,9 +1170,7 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
        // Display all messages in a static text element
        unsigned int recent_chat_count = chat_backend.getRecentBuffer().getLineCount();
        std::wstring recent_chat       = chat_backend.getRecentChat();
-
-       // TODO replace by fontengine fcts
-       unsigned int line_height       = font->getDimension(L"Ay").Height + font->getKerningHeight();
+       unsigned int line_height       = g_fontengine->getLineHeight();
 
        guitext_chat->setText(recent_chat.c_str());
 
@@ -1164,7 +1181,7 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
                chat_y += line_height;
 
        // first pass to calculate height of text to be set
-       s32 width = std::min(font->getDimension(recent_chat.c_str()).Width + 10,
+       s32 width = std::min(g_fontengine->getTextWidth(recent_chat) + 10,
                             porting::getWindowSize().X - 20);
        core::rect<s32> rect(10, chat_y, width, chat_y + porting::getWindowSize().Y);
        guitext_chat->setRelativePosition(rect);
@@ -1181,9 +1198,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;
@@ -1212,6 +1339,7 @@ struct GameRunData {
        bool ldown_for_dig;
        bool left_punch;
        bool update_wielded_item_trigger;
+       bool reset_jump_timer;
        float nodig_delay_timer;
        float dig_time;
        float dig_time_complete;
@@ -1263,6 +1391,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
@@ -1278,7 +1410,6 @@ public:
                        bool random_input,
                        InputHandler *input,
                        IrrlichtDevice *device,
-                       gui::IGUIFont *font,
                        const std::string &map_dir,
                        const std::string &playername,
                        const std::string &password,
@@ -1323,6 +1454,8 @@ protected:
        bool checkConnection();
        bool handleCallbacks();
        void processQueues();
+       void updateProfilers(const GameRunData &run_data, const RunStats &stats,
+                       const FpsControl &draw_times, f32 dtime);
        void addProfilerGraphs(const RunStats &stats, const FpsControl &draw_times,
                        f32 dtime);
        void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
@@ -1332,6 +1465,7 @@ protected:
        void processKeyboardInput(VolatileRunFlags *flags,
                        float *statustext_time,
                        float *jump_timer,
+                       bool *reset_jump_timer,
                        u32 *profiler_current_page,
                        u32 profiler_max_page);
        void processItemSelection(u16 *new_playeritem);
@@ -1379,8 +1513,9 @@ protected:
        void updateFrame(std::vector<aabb3f> &highlight_boxes, ProfilerGraph *graph,
                        RunStats *stats, GameRunData *runData,
                        f32 dtime, const VolatileRunFlags &flags, const CameraOrientation &cam);
-       void updateGui(float *statustext_time, const RunStats &stats, f32 dtime,
-                       const VolatileRunFlags &flags, const CameraOrientation &cam);
+       void updateGui(float *statustext_time, const RunStats &stats,
+                       const GameRunData& runData, f32 dtime, const VolatileRunFlags &flags,
+                       const CameraOrientation &cam);
        void updateProfilerGraphs(ProfilerGraph *graph);
 
        // Misc
@@ -1395,8 +1530,6 @@ private:
        Client *client;
        Server *server;
 
-       gui::IGUIFont *font;
-
        IWritableTextureSource *texture_src;
        IWritableShaderSource *shader_src;
 
@@ -1431,7 +1564,6 @@ private:
        IrrlichtDevice *device;
        video::IVideoDriver *driver;
        scene::ISceneManager *smgr;
-       u32 text_height;
        bool *kill;
        std::wstring *error_message;
        IGameDef *gamedef;                     // Convenience (same as *client)
@@ -1456,12 +1588,32 @@ private:
 
        std::wstring infotext;
        std::wstring statustext;
+
+       KeyCache keycache;
+
+       IntervalLimiter profiler_interval;
+
+       /* TODO: Add a callback function so these can be updated when a setting
+        *       changes.  At this point in time it doesn't matter (e.g. /set
+        *       is documented to change server settings only)
+        *
+        * TODO: Local caching of settings is not optimal and should at some stage
+        *       be updated to use a global settings object for getting thse values
+        *       (as opposed to the this local caching). This can be addressed in
+        *       a later release.
+        */
+       bool m_cache_doubletap_jump;
+       bool m_cache_enable_node_highlighting;
+       bool m_cache_enable_clouds;
+       bool m_cache_enable_particles;
+       bool m_cache_enable_fog;
+       f32  m_cache_mouse_sensitivity;
+       f32  m_repeat_right_click_time;
 };
 
 Game::Game() :
        client(NULL),
        server(NULL),
-       font(NULL),
        texture_src(NULL),
        shader_src(NULL),
        itemdef_manager(NULL),
@@ -1481,7 +1633,13 @@ Game::Game() :
        local_inventory(NULL),
        hud(NULL)
 {
-
+       m_cache_doubletap_jump            = g_settings->getBool("doubletap_jump");
+       m_cache_enable_node_highlighting  = g_settings->getBool("enable_node_highlighting");
+       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");
 }
 
 
@@ -1517,7 +1675,6 @@ bool Game::startup(bool *kill,
                bool random_input,
                InputHandler *input,
                IrrlichtDevice *device,
-               gui::IGUIFont *font,
                const std::string &map_dir,
                const std::string &playername,
                const std::string &password,
@@ -1530,7 +1687,6 @@ bool Game::startup(bool *kill,
 {
        // "cache"
        this->device        = device;
-       this->font          = font;
        this->kill          = kill;
        this->error_message = error_message;
        this->random_input  = random_input;
@@ -1540,7 +1696,8 @@ bool Game::startup(bool *kill,
 
        driver              = device->getVideoDriver();
        smgr                = device->getSceneManager();
-       text_height         = font->getDimension(L"Random test string").Height;
+
+       smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
 
        if (!init(map_dir, address, port, gamespec))
                return false;
@@ -1568,9 +1725,7 @@ void Game::run()
 
        flags.show_chat = true;
        flags.show_hud = true;
-
-       /* FIXME: This should be updated every iteration, or not stored locally
-                 now that key settings can be changed in-game */
+       flags.show_debug = g_settings->getBool("show_debug");
        flags.invert_mouse = g_settings->getBool("invert_mouse");
 
        /* Clear the profiler */
@@ -1585,6 +1740,8 @@ void Game::run()
                        &runData.fog_range,
                        client));
 
+       std::vector<aabb3f> highlight_boxes;
+
        while (device->run() && !(*kill || g_gamecallback->shutdown_requested)) {
 
                /* Must be called immediately after a device->run() call because it
@@ -1602,11 +1759,10 @@ void Game::run()
 
                processQueues();
 
-               std::vector<aabb3f> highlight_boxes;
-
                infotext = L"";
                hud->resizeHotbar();
-               addProfilerGraphs(stats, draw_times, dtime);
+
+               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, &flags);
@@ -1804,7 +1960,7 @@ bool Game::createClient(const std::string &playername,
        }
 
        // Update cached textures, meshes and materials
-       client->afterContentReceived(device, font);
+       client->afterContentReceived(device, g_fontengine->getFont());
 
        /* Camera
         */
@@ -1814,7 +1970,7 @@ bool Game::createClient(const std::string &playername,
 
        /* Clouds
         */
-       if (g_settings->getBool("enable_clouds")) {
+       if (m_cache_enable_clouds) {
                clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1, time(0));
                if (!clouds) {
                        *error_message = L"Memory allocation error";
@@ -1862,8 +2018,7 @@ bool Game::createClient(const std::string &playername,
        player->hurt_tilt_timer = 0;
        player->hurt_tilt_strength = 0;
 
-       hud = new Hud(driver, smgr, guienv, font, text_height, gamedef,
-                       player, local_inventory);
+       hud = new Hud(driver, smgr, guienv, gamedef, player, local_inventory);
 
        if (!hud) {
                *error_message = L"Memory error: could not create HUD";
@@ -1892,7 +2047,7 @@ bool Game::initGui(std::wstring *error_message)
        // Object infos are shown in this
        guitext_info = guienv->addStaticText(
                        L"",
-                       core::rect<s32>(0, 0, 400, text_height * 5 + 5) + v2s32(100, 200),
+                       core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5) + v2s32(100, 200),
                        false, true, guiroot);
 
        // Status text (displays info when showing and hiding GUI stuff, etc.)
@@ -1932,7 +2087,7 @@ bool Game::initGui(std::wstring *error_message)
 #ifdef HAVE_TOUCHSCREENGUI
 
        if (g_touchscreengui)
-               g_touchscreengui->init(tsrc, porting::getDisplayDensity());
+               g_touchscreengui->init(texture_src, porting::getDisplayDensity());
 
 #endif
 
@@ -1974,9 +2129,11 @@ bool Game::connectToServer(const std::string &playername,
                return false;
        }
 
-       client = new Client(device, playername.c_str(), password, *draw_control,
-                   texture_src, shader_src, itemdef_manager, nodedef_manager, sound,
-                       eventmgr, connect_address.isIPv6());
+       client = new Client(device,
+                       playername.c_str(), password, simple_singleplayer_mode,
+                       *draw_control, texture_src, shader_src,
+                       itemdef_manager, nodedef_manager, sound, eventmgr,
+                       connect_address.isIPv6());
 
        if (!client)
                return false;
@@ -2092,12 +2249,12 @@ bool Game::getServerContent(bool *aborted)
                if (!client->itemdefReceived()) {
                        wchar_t *text = wgettext("Item definitions...");
                        progress = 0;
-                       draw_load_screen(text, device, guienv, font, dtime, progress);
+                       draw_load_screen(text, device, guienv, dtime, progress);
                        delete[] text;
                } else if (!client->nodedefReceived()) {
                        wchar_t *text = wgettext("Node definitions...");
                        progress = 25;
-                       draw_load_screen(text, device, guienv, font, dtime, progress);
+                       draw_load_screen(text, device, guienv, dtime, progress);
                        delete[] text;
                } else {
                        std::stringstream message;
@@ -2119,7 +2276,7 @@ bool Game::getServerContent(bool *aborted)
 
                        progress = 50 + client->mediaReceiveProgress() * 50 + 0.5;
                        draw_load_screen(narrow_to_wide(message.str().c_str()), device,
-                                       guienv, font, dtime, progress);
+                                       guienv, dtime, progress);
                }
        }
 
@@ -2186,6 +2343,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;
 }
 
@@ -2198,6 +2360,35 @@ void Game::processQueues()
 }
 
 
+void Game::updateProfilers(const GameRunData &run_data, const RunStats &stats,
+               const FpsControl &draw_times, f32 dtime)
+{
+       float profiler_print_interval =
+                       g_settings->getFloat("profiler_print_interval");
+       bool print_to_log = true;
+
+       if (profiler_print_interval == 0) {
+               print_to_log = false;
+               profiler_print_interval = 5;
+       }
+
+       if (profiler_interval.step(dtime, profiler_print_interval)) {
+               if (print_to_log) {
+                       infostream << "Profiler:" << std::endl;
+                       g_profiler->print(infostream);
+               }
+
+               update_profiler_gui(guitext_profiler, g_fontengine,
+                               run_data.profiler_current_page, run_data.profiler_max_page,
+                               driver->getScreenSize().Height);
+
+               g_profiler->clear();
+       }
+
+       addProfilerGraphs(stats, draw_times, dtime);
+}
+
+
 void Game::addProfilerGraphs(const RunStats &stats,
                const FpsControl &draw_times, f32 dtime)
 {
@@ -2300,13 +2491,14 @@ void Game::processUserInput(VolatileRunFlags *flags,
 #endif
 
        // Increase timer for double tap of "keymap_jump"
-       if (g_settings->getBool("doubletap_jump") && interact_args->jump_timer <= 0.2)
+       if (m_cache_doubletap_jump && interact_args->jump_timer <= 0.2)
                interact_args->jump_timer += dtime;
 
        processKeyboardInput(
                        flags,
                        &interact_args->statustext_time,
                        &interact_args->jump_timer,
+                       &interact_args->reset_jump_timer,
                        &interact_args->profiler_current_page,
                        interact_args->profiler_max_page);
 
@@ -2317,72 +2509,67 @@ void Game::processUserInput(VolatileRunFlags *flags,
 void Game::processKeyboardInput(VolatileRunFlags *flags,
                float *statustext_time,
                float *jump_timer,
+               bool *reset_jump_timer,
                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);
-       } else if (input->wasKeyDown(getKeySetting("keymap_fastmove"))) {
+               *reset_jump_timer = true;
+       } 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;
@@ -2390,6 +2577,19 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
                        << std::endl;
                debug_stacks_print();
        }
+
+       if (!input->isKeyDown(getKeySetting("keymap_jump")) && *reset_jump_timer) {
+               *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;
+       }
 }
 
 
@@ -2485,10 +2685,8 @@ void Game::toggleFreeMove(float *statustext_time)
 
 void Game::toggleFreeMoveAlt(float *statustext_time, float *jump_timer)
 {
-       if (g_settings->getBool("doubletap_jump") && *jump_timer < 0.2f) {
+       if (m_cache_doubletap_jump && *jump_timer < 0.2f)
                toggleFreeMove(statustext_time);
-               *jump_timer = 0;
-       }
 }
 
 
@@ -2537,7 +2735,8 @@ void Game::toggleHud(float *statustext_time, bool *flag)
        *flag = !*flag;
        *statustext_time = 0;
        statustext = msg[*flag];
-       client->setHighlighted(client->getHighlighted(), *flag);
+       if (g_settings->getBool("enable_node_highlighting"))
+               client->setHighlighted(client->getHighlighted(), *flag);
 }
 
 
@@ -2592,8 +2791,8 @@ void Game::toggleProfiler(float *statustext_time, u32 *profiler_current_page,
        *profiler_current_page = (*profiler_current_page + 1) % (profiler_max_page + 1);
 
        // FIXME: This updates the profiler with incomplete values
-       update_profiler_gui(guitext_profiler, font, text_height,
-                           *profiler_current_page, profiler_max_page);
+       update_profiler_gui(guitext_profiler, g_fontengine, *profiler_current_page,
+                       profiler_max_page, driver->getScreenSize().Height);
 
        if (*profiler_current_page != 0) {
                std::wstringstream sstr;
@@ -2683,8 +2882,8 @@ void Game::updateCameraDirection(CameraOrientation *cam,
 #ifdef HAVE_TOUCHSCREENGUI
 
                if (g_touchscreengui) {
-                       camera_yaw   = g_touchscreengui->getYaw();
-                       camera_pitch = g_touchscreengui->getPitch();
+                       cam->camera_yaw   = g_touchscreengui->getYaw();
+                       cam->camera_pitch = g_touchscreengui->getPitch();
                } else {
 #endif
                        s32 dx = input->getMousePos().X - (driver->getScreenSize().Width / 2);
@@ -2697,7 +2896,7 @@ void Game::updateCameraDirection(CameraOrientation *cam,
 
                        //infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
 
-                       float d = g_settings->getFloat("mouse_sensitivity");
+                       float d = m_cache_mouse_sensitivity;
                        d = rangelim(d, 0.01, 100.0);
                        cam->camera_yaw -= dx * d;
                        cam->camera_pitch += dy * d;
@@ -2724,14 +2923,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,
@@ -2740,17 +2941,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();
 }
 
 
@@ -3036,7 +3238,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();
 
@@ -3168,7 +3370,7 @@ void Game::processPlayerInteraction(std::vector<aabb3f> &highlight_boxes,
        if (pointed != runData->pointed_old) {
                infostream << "Pointing at " << pointed.dump() << std::endl;
 
-               if (g_settings->getBool("enable_node_highlighting")) {
+               if (m_cache_enable_node_highlighting) {
                        if (pointed.type == POINTEDTHING_NODE) {
                                client->setHighlighted(pointed.node_undersurface, show_hud);
                        } else {
@@ -3267,7 +3469,7 @@ void Game::handlePointingAtNode(GameRunData *runData,
        if (meta) {
                infotext = narrow_to_wide(meta->getString("infotext"));
        } else {
-               MapNode n = map.getNode(nodepos);
+               MapNode n = map.getNodeNoEx(nodepos);
 
                if (nodedef_manager->get(n).tiledef[0].name == "unknown_node.png") {
                        infotext = L"Unknown node: ";
@@ -3281,8 +3483,7 @@ void Game::handlePointingAtNode(GameRunData *runData,
        }
 
        if ((input->getRightClicked() ||
-                       runData->repeat_rightclick_timer >=
-                       g_settings->getFloat("repeat_rightclick_time")) &&
+                       runData->repeat_rightclick_timer >= m_repeat_right_click_time) &&
                        client->checkPrivilege("interact")) {
                runData->repeat_rightclick_timer = 0;
                infostream << "Ground right-clicked" << std::endl;
@@ -3325,7 +3526,7 @@ void Game::handlePointingAtNode(GameRunData *runData,
                        }
 
                        if (playeritem_def.node_placement_prediction == "" ||
-                                       nodedef_manager->get(map.getNode(nodepos)).rightclickable)
+                                       nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable)
                                client->interact(3, pointed); // Report to server
                }
        }
@@ -3394,7 +3595,7 @@ void Game::handleDigging(GameRunData *runData,
 
        LocalPlayer *player = client->getEnv().getLocalPlayer();
        ClientMap &map = client->getEnv().getClientMap();
-       MapNode n = client->getEnv().getClientMap().getNode(nodepos);
+       MapNode n = client->getEnv().getClientMap().getNodeNoEx(nodepos);
 
        // NOTE: Similar piece of code exists on the server side for
        // cheat detection.
@@ -3417,7 +3618,7 @@ void Game::handleDigging(GameRunData *runData,
        } else {
                runData->dig_time_complete = params.time;
 
-               if (g_settings->getBool("enable_particles")) {
+               if (m_cache_enable_particles) {
                        const ContentFeatures &features =
                                        client->getNodeDefManager()->get(n);
                        addPunchingParticles(gamedef, smgr, player,
@@ -3459,10 +3660,12 @@ void Game::handleDigging(GameRunData *runData,
                infostream << "Digging completed" << std::endl;
                client->interact(2, pointed);
                client->setCrack(-1, v3s16(0, 0, 0));
-               MapNode wasnode = map.getNode(nodepos);
-               client->removeNode(nodepos);
+               bool is_valid_position;
+               MapNode wasnode = map.getNodeNoEx(nodepos, &is_valid_position);
+               if (is_valid_position)
+                       client->removeNode(nodepos);
 
-               if (g_settings->getBool("enable_particles")) {
+               if (m_cache_enable_particles) {
                        const ContentFeatures &features =
                                client->getNodeDefManager()->get(wasnode);
                        addDiggingParticles
@@ -3598,7 +3801,7 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
                Fog
        */
 
-       if (g_settings->getBool("enable_fog") && !flags.force_fog_off) {
+       if (m_cache_enable_fog && !flags.force_fog_off) {
                driver->setFog(
                                sky->getBgColor(),
                                video::EFT_FOG_LINEAR,
@@ -3628,7 +3831,7 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
 
        updateChat(*client, dtime, flags.show_debug, screensize,
                        flags.show_chat, runData->profiler_current_page,
-                       *chat_backend, guitext_chat, font);
+                       *chat_backend, guitext_chat);
 
        /*
                Inventory
@@ -3650,7 +3853,7 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
 
                if (mlist && (client->getPlayerItem() < mlist->getSize())) {
                        ItemStack item = mlist->getItem(client->getPlayerItem());
-                       camera->wield(item, client->getPlayerItem());
+                       camera->wield(item);
                }
                runData->update_wielded_item_trigger = false;
        }
@@ -3670,7 +3873,7 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
                runData->update_draw_list_last_cam_dir = camera_direction;
        }
 
-       updateGui(&runData->statustext_time, *stats, dtime, flags, cam);
+       updateGui(&runData->statustext_time, *stats, *runData, dtime, flags, cam);
 
        /*
           make sure menu is on top
@@ -3706,7 +3909,7 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
                Profiler graph
        */
        if (flags.show_profiler_graph)
-               graph->draw(10, screensize.Y - 10, driver, font);
+               graph->draw(10, screensize.Y - 10, driver, g_fontengine->getFont());
 
        /*
                Damage flash
@@ -3747,8 +3950,9 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
 }
 
 
-void Game::updateGui(float *statustext_time, const RunStats& stats,
-               f32 dtime, const VolatileRunFlags &flags, const CameraOrientation &cam)
+void Game::updateGui(float *statustext_time, const RunStats &stats,
+               const GameRunData& runData, f32 dtime, const VolatileRunFlags &flags,
+               const CameraOrientation &cam)
 {
        v2u32 screensize = driver->getScreenSize();
        LocalPlayer *player = client->getEnv().getLocalPlayer();
@@ -3759,6 +3963,7 @@ void Game::updateGui(float *statustext_time, const RunStats& stats,
                drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
 
                u16 fps = 1.0 / stats.dtime_jitter.avg;
+               //s32 fps = driver->getFPS();
 
                std::ostringstream os(std::ios_base::binary);
                os << std::fixed
@@ -3788,7 +3993,7 @@ void Game::updateGui(float *statustext_time, const RunStats& stats,
        if (guitext->isVisible()) {
                core::rect<s32> rect(
                                5,              5,
-                               screensize.X,   5 + text_height
+                               screensize.X,   5 + g_fontengine->getTextHeight()
                );
                guitext->setRelativePosition(rect);
        }
@@ -3802,12 +4007,25 @@ void Game::updateGui(float *statustext_time, const RunStats& stats,
                   << ") (yaw=" << (wrapDegrees_0_360(cam.camera_yaw))
                   << ") (seed = " << ((u64)client->getMapSeed())
                   << ")";
+
+               if (runData.pointed_old.type == POINTEDTHING_NODE) {
+                       ClientMap &map = client->getEnv().getClientMap();
+                       const INodeDefManager *nodedef = client->getNodeDefManager();
+                       MapNode n = map.getNodeNoEx(runData.pointed_old.node_undersurface);
+                       if (n.getContent() != CONTENT_IGNORE && nodedef->get(n).name != "unknown") {
+                               const ContentFeatures &features = nodedef->get(n);
+                               os << " (pointing_at = " << nodedef->get(n).name
+                                  << " - " << features.tiledef[0].name.c_str()
+                                  << ")";
+                       }
+               }
+
                guitext2->setText(narrow_to_wide(os.str()).c_str());
                guitext2->setVisible(true);
 
                core::rect<s32> rect(
-                               5,             5 + text_height,
-                               screensize.X,  5 + text_height * 2
+                               5,             5 + g_fontengine->getTextHeight(),
+                               screensize.X,  5 + g_fontengine->getTextHeight() * 2
                );
                guitext2->setRelativePosition(rect);
        } else {
@@ -3871,18 +4089,16 @@ inline void Game::updateProfilerGraphs(ProfilerGraph *graph)
  ****************************************************************************/
 
 /* On some computers framerate doesn't seem to be automatically limited
- *
- * *Must* be called after device->run() so that device->getTimer()->getTime();
- * is correct
  */
 inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
 {
        // not using getRealTime is necessary for wine
+       device->getTimer()->tick(); // Maker sure device time is up-to-date
        u32 time = device->getTimer()->getTime();
 
        u32 last_time = fps_timings->last_time;
 
-       if (time > last_time) // Make sure time hasn't overflowed
+       if (time > last_time)  // Make sure time hasn't overflowed
                fps_timings->busy_time = time - last_time;
        else
                fps_timings->busy_time = 0;
@@ -3894,37 +4110,25 @@ inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
        if (fps_timings->busy_time < frametime_min) {
                fps_timings->sleep_time = frametime_min - fps_timings->busy_time;
                device->sleep(fps_timings->sleep_time);
-               time += fps_timings->sleep_time;
        } else {
                fps_timings->sleep_time = 0;
        }
 
-       if (time > last_time) // Checking for overflow
-               *dtime = (time - last_time) / 1000.0;
-       else
-               *dtime = 0.03; // Choose 30fps as fallback in overflow case
-
-       fps_timings->last_time = time;
-
-#if 0
-
-       /* This is the old method for calculating new_time and dtime, and seems
-        * like overkill considering timings are messed up by expected variation
-        * in execution speed in other places anyway. (This has nothing to do with
-        * WINE... the new method above calculates dtime based on sleep_time)
+       /* Get the new value of the device timer. Note that device->sleep() may
+        * not sleep for the entire requested time as sleep may be interrupted and
+        * therefore it is arguably more accurate to get the new time from the
+        * device rather than calculating it by adding sleep_time to time.
         */
 
-       // Necessary for device->getTimer()->getTime()
-       device->run();
+       device->getTimer()->tick(); // Update device timer
        time = device->getTimer()->getTime();
 
-       if (time > last_time)   // Make sure last_time hasn't overflowed
+       if (time > last_time)  // Make sure last_time hasn't overflowed
                *dtime = (time - last_time) / 1000.0;
        else
-               *dtime = 0.033;
+               *dtime = 0;
 
-       params->last_time = time;
-#endif
+       fps_timings->last_time = time;
 }
 
 
@@ -3932,7 +4136,7 @@ void Game::showOverlayMessage(const char *msg, float dtime,
                int percent, bool draw_clouds)
 {
        wchar_t *text = wgettext(msg);
-       draw_load_screen(text, device, guienv, font, dtime, percent, draw_clouds);
+       draw_load_screen(text, device, guienv, dtime, percent, draw_clouds);
        delete[] text;
 }
 
@@ -3972,7 +4176,6 @@ void the_game(bool *kill,
                bool random_input,
                InputHandler *input,
                IrrlichtDevice *device,
-               gui::IGUIFont *font,
 
                const std::string &map_dir,
                const std::string &playername,
@@ -3995,7 +4198,7 @@ void the_game(bool *kill,
 
        try {
 
-               if (game.startup(kill, random_input, input, device, font, map_dir,
+               if (game.startup(kill, random_input, input, device, map_dir,
                                        playername, password, &server_address, port,
                                        &error_message, &chat_backend, gamespec,
                                        simple_singleplayer_mode)) {