]> git.lizzy.rs Git - dragonfireclient.git/commitdiff
Merge branch 'master' of https://github.com/minetest/minetest
authorElias Fleckenstein <eliasfleckenstein@web.de>
Fri, 26 Mar 2021 13:00:57 +0000 (14:00 +0100)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Fri, 26 Mar 2021 13:00:57 +0000 (14:00 +0100)
38 files changed:
1  2 
.gitignore
CMakeLists.txt
LICENSE.txt
builtin/client/chatcommands.lua
builtin/client/death_formspec.lua
builtin/common/chatcommands.lua
builtin/game/item.lua
builtin/init.lua
builtin/mainmenu/dlg_contentstore.lua
builtin/mainmenu/pkgmgr.lua
builtin/mainmenu/tab_content.lua
builtin/mainmenu/tab_credits.lua
builtin/settingtypes.txt
doc/client_lua_api.txt
doc/lua_api.txt
misc/Info.plist
src/activeobjectmgr.h
src/client/camera.cpp
src/client/client.cpp
src/client/client.h
src/client/clientmap.cpp
src/client/content_cao.cpp
src/client/game.cpp
src/client/game.h
src/client/inputhandler.cpp
src/client/inputhandler.h
src/client/keys.h
src/client/mapblock_mesh.cpp
src/client/minimap.cpp
src/client/renderingengine.cpp
src/defaultsettings.cpp
src/gui/CMakeLists.txt
src/gui/guiKeyChangeMenu.cpp
src/network/clientpackethandler.cpp
src/nodedef.cpp
src/script/common/c_content.cpp
util/buildbot/buildwin32.sh
util/buildbot/buildwin64.sh

diff --cc .gitignore
Simple merge
diff --cc CMakeLists.txt
index 1a5bd957403bc31cb3a2ba6a499349cfaf33061b,e4bda3afbec8a990314a33c3ff6455aff3308141..0c0fcc5864b96bce78fd7e1d00f595c212a82184
@@@ -1,10 -1,8 +1,8 @@@
  cmake_minimum_required(VERSION 3.5)
  
- cmake_policy(SET CMP0025 OLD)
  # This can be read from ${PROJECT_NAME} after project() is called
  project(minetest)
 -set(PROJECT_NAME_CAPITALIZED "Minetest")
 +set(PROJECT_NAME_CAPITALIZED "Dragonfire")
  
  set(CMAKE_CXX_STANDARD 11)
  set(GCC_MINIMUM_VERSION "4.8")
@@@ -12,12 -10,12 +10,12 @@@ set(CLANG_MINIMUM_VERSION "3.4"
  
  # Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing
  set(VERSION_MAJOR 5)
- set(VERSION_MINOR 4)
+ set(VERSION_MINOR 5)
  set(VERSION_PATCH 0)
- set(VERSION_EXTRA "-dragonfire" CACHE STRING "Stuff to append to version string")
 -set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
++set(VERSION_EXTRA "dragonfire" CACHE STRING "Stuff to append to version string")
  
  # Change to false for releases
 -set(DEVELOPMENT_BUILD TRUE)
 +set(DEVELOPMENT_BUILD FALSE)
  
  set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
  if(VERSION_EXTRA)
diff --cc LICENSE.txt
index 27b30323aad7b49abff59a9c73f8db71d71e0959,2d1c0c79546cc81362737793d53167eef3a953a0..75db1916b1740759196b74d9b7ef4b8fab788d88
@@@ -33,16 -36,16 +36,16 @@@ rubenwardy, paramat
    textures/base/pack/start_icon.png
    textures/base/pack/end_icon.png
  
 -erlehmann:
 -  misc/minetest-icon-24x24.png
 -  misc/minetest-icon.ico
 -  misc/minetest.svg
 +EliasFleckenstein03:
 +  misc/dragonfire-icon-24x24.png
 +  misc/dragonfire-icon.ico
 +  misc/dragonfire.svg
    textures/base/pack/logo.png
  
- JRottm
+ JRottm:
    textures/base/pack/player_marker.png
  
- srifqi
+ srifqi:
    textures/base/pack/chat_hide_btn.png
    textures/base/pack/chat_show_btn.png
    textures/base/pack/joystick_bg.png
Simple merge
index 7b8530440e80995e8ad78aa63db5faa52aacddbe,7df0cbd750c0485aca33acfe4da223cdb09123ef..6d6fd6fd914456b2dd1b9b5e452efaaa9471e310
@@@ -1,38 -1,16 +1,38 @@@
 --- CSM death formspec. Only used when clientside modding is enabled, otherwise
 --- handled by the engine.
 +local death_formspec = ""
 +      .. "size[11,5.5]"
 +      .. "bgcolor[#320000b4;true]"
 +      .. "label[4.85,1.35;" .. "You died" .. "]"
 +      .. "button_exit[2,3;3,0.5;btn_respawn;" .. "Respawn" .. "]"
 +      .. "button_exit[6,3;3,0.5;btn_ghost_mode;" .. "Ghost Mode" .. "]"
 +      .. "set_focus[btn_respawn;true]"
  
  core.register_on_death(function()
 -      core.display_chat_message(core.gettext("You died."))
 -      local formspec = "size[11,5.5]bgcolor[#320000b4;true]" ..
 -              "label[4.85,1.35;" .. fgettext("You died") ..
 -              "]button_exit[4,3;3,0.5;btn_respawn;".. fgettext("Respawn") .."]"
 -      core.show_formspec("bultin:death", formspec)
 +      core.display_chat_message("You died at " .. core.pos_to_string(vector.round(core.localplayer:get_pos())) .. ".")
 +      if core.settings:get_bool("autorespawn") then
 +              core.send_respawn()
 +      else
-               core.show_formspec("__builtin__:death", death_formspec)
++              core.show_formspec("bultin:death", death_formspec)
 +      end
  end)
  
  core.register_on_formspec_input(function(formname, fields)
-       if formname == "__builtin__:death" then
+       if formname == "bultin:death" then
 -              core.send_respawn()
 +              if fields.btn_ghost_mode then
 +                      core.display_chat_message("You are in ghost mode. Use .respawn to Respawn.")
 +              else
 +                      core.send_respawn()
 +              end
        end
  end)
 +
 +core.register_chatcommand("respawn", {
 +      description = "Respawn when in ghost mode",
 +      func = function()
 +              if core.localplayer:get_hp() == 0 then
 +                      core.send_respawn()
 +                      core.display_chat_message("Respawned.")
 +              else
 +                      core.display_chat_message("You are not in ghost mode.")
 +              end
 +      end
 +})
index fb593e8399619859296b6d5a57a87516f3bf7c9c,c945e7bdb2926733dfecb72dbb8f8a979e3118e9..62f9eacd06c93525fbdeeb377a1357ec1219d54c
@@@ -29,70 -33,12 +33,57 @@@ function core.override_chatcommand(name
        core.registered_chatcommands[name] = chatcommand
  end
  
- local cmd_marker = "/"
- local function gettext(...)
-       return ...
- end
- local function gettext_replace(text, replace)
-       return text:gsub("$1", replace)
- end
- if INIT == "client" then
-       cmd_marker = "."
-       gettext = core.gettext
-       gettext_replace = fgettext_ne
- end
 +if INIT == "client" then
 +      function core.register_list_command(command, desc, setting)
 +              local def = {}
 +              def.description = desc
 +              def.params = "del <item> | add <item> | list"
 +              function def.func(param)
 +                      local list = (minetest.settings:get(setting) or ""):split(",")
 +                      if param == "list" then
 +                              return true, table.concat(list, ", ")
 +                      else
 +                              local sparam = param:split(" ")
 +                              local cmd = sparam[1]
 +                              local item = sparam[2]
 +                              if cmd == "del" then
 +                                      if not item then
 +                                              return false, "Missing item."
 +                                      end
 +                                      local i = table.indexof(list, item)
 +                                      if i == -1 then
 +                                              return false, item .. " is not on the list."
 +                                      else
 +                                              table.remove(list, i)
 +                                              core.settings:set(setting, table.concat(list, ","))
 +                                              return true, "Removed " .. item .. " from the list."
 +                                      end
 +                              elseif cmd == "add" then
 +                                      if not item then
 +                                              return false, "Missing item."
 +                                      end
 +                                      local i = table.indexof(list, item)
 +                                      if i ~= -1 then
 +                                              return false, item .. " is already on the list."
 +                                      else
 +                                              table.insert(list, item)
 +                                              core.settings:set(setting, table.concat(list, ","))
 +                                              return true, "Added " .. item .. " to the list."
 +                                      end
 +                              end
 +                      end
 +                      return false, "Invalid usage. (See .help " .. command .. ")"
 +              end
 +              core.register_chatcommand(command, def)
 +      end
 +end
 +
  local function do_help_cmd(name, param)
        local function format_help_line(cmd, def)
+               local cmd_marker = "/"
+               if INIT == "client" then
+                       cmd_marker = "."
+               end
                local msg = core.colorize("#00ffff", cmd_marker .. cmd)
                if def.params and def.params ~= "" then
                        msg = msg .. " " .. def.params
Simple merge
index f76174be7d5c727fe85b5b20a9a83a584e39646d,89b1fdc645f5b75e10696f1fea72219a4e1caae4..171742ae17567dfbaf25720757497a55e9adcce7
@@@ -36,11 -36,23 +36,22 @@@ dofile(commonpath .. "misc_helpers.lua"
  
  if INIT == "game" then
        dofile(gamepath .. "init.lua")
 -      assert(not core.get_http_api)
  elseif INIT == "mainmenu" then
        local mm_script = core.settings:get("main_menu_script")
+       local custom_loaded = false
        if mm_script and mm_script ~= "" then
-               dofile(mm_script)
-       else
+               local testfile = io.open(mm_script, "r")
+               if testfile then
+                       testfile:close()
+                       dofile(mm_script)
+                       custom_loaded = true
+                       core.log("info", "Loaded custom main menu script: "..mm_script)
+               else
+                       core.log("error", "Failed to load custom main menu script: "..mm_script)
+                       core.log("info", "Falling back to default main menu script")
+               end
+       end
+       if not custom_loaded then
                dofile(core.get_mainmenu_path() .. DIR_DELIM .. "init.lua")
        end
  elseif INIT == "async" then
Simple merge
Simple merge
index a76fee864b93ac3277c76916209941f7b076f5b8,fb7f121f81f8e1373adb96c01bda091918daafa3..1bffeeb223234353a51fd65f301255254e1625a4
@@@ -205,16 -145,25 +205,28 @@@ local function get_formspec(tabview, na
        return retval
  end
  
 -local function handle_doubleclick(pkg)
+ --------------------------------------------------------------------------------
++local function handle_doubleclick(pkg, pkg_name)
+       if pkg.type == "txp" then
+               if core.settings:get("texture_path") == pkg.path then
+                       core.settings:set("texture_path", "")
+               else
+                       core.settings:set("texture_path", pkg.path)
+               end
+               packages = nil
++      elseif pkg.is_clientside then
++              pkgmgr.enable_mod({data = {list = packages, selected_mod = pkg_name}})
++              packages = nil
+       end
+ end
  --------------------------------------------------------------------------------
  local function handle_buttons(tabview, fields, tabname, tabdata)
        if fields["pkglist"] ~= nil then
                local event = core.explode_table_event(fields["pkglist"])
                tabdata.selected_pkg = event.row
-               local mod = packages:get_list()[tabdata.selected_pkg]
-               if event.type == "DCL" and mod.is_clientside then
-                       pkgmgr.enable_mod({data = {list = packages, selected_mod = tabdata.selected_pkg}})
-                       packages = nil
+               if event.type == "DCL" then
 -                      handle_doubleclick(packages:get_list()[tabdata.selected_pkg])
++                      handle_doubleclick(packages:get_list()[tabdata.selected_pkg], tabdata.selected_pkg)
                end
                return true
        end
Simple merge
index 15c48dfc1314f14696f3f92132dca1a372d7541d,75efe64daa681a13d30c7c9bae19b40d75a26a94..50a51b9731768b6e0753c9a9b77cf5669a80928e
@@@ -197,13 -197,9 +197,13 @@@ keymap_place (Place key) key KEY_RBUTTO
  #    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
  keymap_inventory (Inventory key) key KEY_KEY_I
  
 +#    Key for opening the special inventory.
 +#    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
 +keymap_special_inventory (Special inventory key) key KEY_KEY_O
 +
  #    Key for moving fast in fast mode.
  #    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
- keymap_special1 (Special key) key KEY_KEY_E
+ keymap_aux1 (Aux1 key) key KEY_KEY_E
  
  #    Key for opening the chat window.
  #    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
Simple merge
diff --cc doc/lua_api.txt
Simple merge
diff --cc misc/Info.plist
index b80ae9d7cad951613e7957779892c8fdf28c2cc4,0491d2fc11b582620355ed89c2c3626a35126840..9460b273d6f1fec01bd0431c3427e4aea131f7ce
@@@ -7,8 -7,14 +7,14 @@@
        <key>CFBundleExecutable</key>
        <string>minetest</string>
        <key>CFBundleIconFile</key>
 -      <string>minetest-icon.icns</string>
 +      <string>dragonfire-icon.icns</string>
+       <key>CFBundleName</key>
+       <string>Minetest</string>
+       <key>CFBundleDisplayName</key>
+       <string>Minetest</string>
        <key>CFBundleIdentifier</key>
        <string>net.minetest.minetest</string>
+       <key>NSHighResolutionCapable</key>
+       <false/>
  </dict>
  </plist>
Simple merge
Simple merge
Simple merge
index f7a9030bc02ff00c0a1bdeed0af22d1c57e5de98,2dba1506ed1f45faec522b902f3367ce2ea42e25..3e346369bb7952203f67e9289c1d93a2195e8a77
@@@ -414,15 -412,9 +414,10 @@@ public
  
        inline bool checkCSMRestrictionFlag(CSMRestrictionFlags flag) const
        {
 -              return m_csm_restriction_flags & flag;
 +              //return m_csm_restriction_flags & flag;
 +              return false;
        }
  
-       inline std::unordered_map<u32, u32> &getHUDTranslationMap()
-       {
-               return m_hud_server_to_client;
-       }
        bool joinModChannel(const std::string &channel) override;
        bool leaveModChannel(const std::string &channel) override;
        bool sendModChannelMessage(const std::string &channel,
Simple merge
index c44c167b526e3cd1b702dedb58f1f2a9c3c5300a,97ae9afc4019de44b3f773964c9e74345cdb5e8d..36eb55597e38e105a4e3cb8c02c48ae6a359d5c8
@@@ -937,10 -931,10 +937,10 @@@ void GenericCAO::updateMarker(
  
  void GenericCAO::updateNametag()
  {
 -      if (m_is_local_player) // No nametag for local player
 -              return;
 +      //if (m_is_local_player && ! g_settings->getBool("freecam")) // No nametag for local player
 +              //return;
  
-       if (m_prop.nametag.empty()) {
+       if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0) {
                // Delete nametag
                if (m_nametag) {
                        m_client->getCamera()->removeNametag(m_nametag);
index 4862d3ed987c71bc2f6b28259b48757b64eb0878,31c782c51cc14702c6d0ea9987f0029fe14b78ce..104a6e374e6c9f097868426167c2ba6288856a18
@@@ -2563,9 -3303,10 +2575,10 @@@ void Game::handlePointingAtNode(const P
  
  bool Game::nodePlacement(const ItemDefinition &selected_def,
        const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos,
 -      const PointedThing &pointed, const NodeMetadata *meta)
 +      const PointedThing &pointed, const NodeMetadata *meta, bool force)
  {
-       std::string prediction = selected_def.node_placement_prediction;
+       const auto &prediction = selected_def.node_placement_prediction;
        const NodeDefManager *nodedef = client->ndef();
        ClientMap &map = client->getEnv().getClientMap();
        MapNode node;
index 50a734be6b8136575c9d7c93a5369496f50ee102,d041532717640a8c1f4109377ca5ee0f297b9d82..4a5b829d5e012528fd16e65f20135bfa5d365b2b
@@@ -19,58 -19,6 +19,59 @@@ with this program; if not, write to th
  
  #pragma once
  
 +#include <iomanip>
 +#include <cmath>
 +#include "client/renderingengine.h"
 +#include "camera.h"
 +#include "client.h"
 +#include "client/clientevent.h"
 +//#include "client/gameui.h"
 +#include "client/inputhandler.h"
 +#include "client/sound.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"
 +#include "content_cao.h"
 +#include "client/event_manager.h"
 +#include "fontengine.h"
 +#include "itemdef.h"
 +#include "log.h"
 +#include "filesys.h"
 +#include "gettext.h"
 +#include "gui/cheatMenu.h"
 +#include "gui/guiChatConsole.h"
 +#include "gui/guiConfirmRegistration.h"
 +#include "gui/guiFormSpecMenu.h"
 +#include "gui/guiKeyChangeMenu.h"
 +#include "gui/guiPasswordChange.h"
 +#include "gui/guiVolumeChange.h"
 +#include "gui/mainmenumanager.h"
 +#include "gui/profilergraph.h"
 +#include "mapblock.h"
 +#include "minimap.h"
 +#include "nodedef.h"         // Needed for determining pointing to nodes
 +#include "nodemetadata.h"
 +#include "particles.h"
 +#include "porting.h"
 +#include "profiler.h"
 +#include "raycast.h"
 +#include "server.h"
 +#include "settings.h"
 +#include "shader.h"
 +#include "sky.h"
 +#include "translation.h"
 +#include "util/basic_macros.h"
 +#include "util/directiontables.h"
 +#include "util/pointedthing.h"
 +#include "util/quicktune_shortcutter.h"
 +#include "irrlicht_changes/static_text.h"
++#include "irr_ptr.h"
 +#include "version.h"
 +#include "script/scripting_client.h"
 +#include "hud.h"
  #include "irrlichttypes.h"
  #include <string>
  
@@@ -94,830 -42,6 +95,844 @@@ struct CameraOrientation 
        f32 camera_pitch;  // "up/down"
  };
  
-               SamplerLayer_t base_tex = 0;
 +/*
 +      Text input system
 +*/
 +
 +struct TextDestNodeMetadata : public TextDest
 +{
 +      TextDestNodeMetadata(v3s16 p, Client *client)
 +      {
 +              m_p = p;
 +              m_client = client;
 +      }
 +      // This is deprecated I guess? -celeron55
 +      void gotText(const std::wstring &text)
 +      {
 +              std::string ntext = wide_to_utf8(text);
 +              infostream << "Submitting 'text' field of node at (" << m_p.X << ","
 +                         << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
 +              StringMap fields;
 +              fields["text"] = ntext;
 +              m_client->sendNodemetaFields(m_p, "", fields);
 +      }
 +      void gotText(const StringMap &fields)
 +      {
 +              m_client->sendNodemetaFields(m_p, "", fields);
 +      }
 +
 +      v3s16 m_p;
 +      Client *m_client;
 +};
 +
 +struct TextDestPlayerInventory : public TextDest
 +{
 +      TextDestPlayerInventory(Client *client)
 +      {
 +              m_client = client;
 +              m_formname = "";
 +      }
 +      TextDestPlayerInventory(Client *client, const std::string &formname)
 +      {
 +              m_client = client;
 +              m_formname = formname;
 +      }
 +      void gotText(const StringMap &fields)
 +      {
 +              m_client->sendInventoryFields(m_formname, fields);
 +      }
 +
 +      Client *m_client;
 +};
 +
 +struct LocalFormspecHandler : public TextDest
 +{
 +      LocalFormspecHandler(const std::string &formname)
 +      {
 +              m_formname = formname;
 +      }
 +
 +      LocalFormspecHandler(const std::string &formname, Client *client):
 +              m_client(client)
 +      {
 +              m_formname = formname;
 +      }
 +
 +      void gotText(const StringMap &fields)
 +      {
 +              if (m_formname == "MT_PAUSE_MENU") {
 +                      if (fields.find("btn_sound") != fields.end()) {
 +                              g_gamecallback->changeVolume();
 +                              return;
 +                      }
 +
 +                      if (fields.find("btn_key_config") != fields.end()) {
 +                              g_gamecallback->keyConfig();
 +                              return;
 +                      }
 +
 +                      if (fields.find("btn_exit_menu") != fields.end()) {
 +                              g_gamecallback->disconnect();
 +                              return;
 +                      }
 +
 +                      if (fields.find("btn_exit_os") != fields.end()) {
 +                              g_gamecallback->exitToOS();
 +#ifndef __ANDROID__
 +                              RenderingEngine::get_raw_device()->closeDevice();
 +#endif
 +                              return;
 +                      }
 +
 +                      if (fields.find("btn_change_password") != fields.end()) {
 +                              g_gamecallback->changePassword();
 +                              return;
 +                      }
 +
 +                      return;
 +              }
 +
 +              if (m_formname == "MT_DEATH_SCREEN") {
 +                      assert(m_client != 0);
 +                      m_client->sendRespawn();
 +                      return;
 +              }
 +
 +              if (m_client->modsLoaded())
 +                      m_client->getScript()->on_formspec_input(m_formname, fields);
 +      }
 +
 +      Client *m_client = nullptr;
 +};
 +
 +/* Form update callback */
 +
 +class NodeMetadataFormSource: public IFormSource
 +{
 +public:
 +      NodeMetadataFormSource(ClientMap *map, v3s16 p):
 +              m_map(map),
 +              m_p(p)
 +      {
 +      }
 +      const std::string &getForm() const
 +      {
 +              static const std::string empty_string = "";
 +              NodeMetadata *meta = m_map->getNodeMetadata(m_p);
 +
 +              if (!meta)
 +                      return empty_string;
 +
 +              return meta->getString("formspec");
 +      }
 +
 +      virtual std::string resolveText(const std::string &str)
 +      {
 +              NodeMetadata *meta = m_map->getNodeMetadata(m_p);
 +
 +              if (!meta)
 +                      return str;
 +
 +              return meta->resolveString(str);
 +      }
 +
 +      ClientMap *m_map;
 +      v3s16 m_p;
 +};
 +
 +class PlayerInventoryFormSource: public IFormSource
 +{
 +public:
 +      PlayerInventoryFormSource(Client *client):
 +              m_client(client)
 +      {
 +      }
 +
 +      const std::string &getForm() const
 +      {
 +              LocalPlayer *player = m_client->getEnv().getLocalPlayer();
 +              return player->inventory_formspec;
 +      }
 +
 +      Client *m_client;
 +};
 +
 +class NodeDugEvent: public MtEvent
 +{
 +public:
 +      v3s16 p;
 +      MapNode n;
 +
 +      NodeDugEvent(v3s16 p, MapNode n):
 +              p(p),
 +              n(n)
 +      {}
 +      MtEvent::Type getType() const
 +      {
 +              return MtEvent::NODE_DUG;
 +      }
 +};
 +
 +class SoundMaker
 +{
 +      ISoundManager *m_sound;
 +      const NodeDefManager *m_ndef;
 +public:
 +      bool makes_footstep_sound;
 +      float m_player_step_timer;
 +      float m_player_jump_timer;
 +
 +      SimpleSoundSpec m_player_step_sound;
 +      SimpleSoundSpec m_player_leftpunch_sound;
 +      SimpleSoundSpec m_player_rightpunch_sound;
 +
 +      SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
 +              m_sound(sound),
 +              m_ndef(ndef),
 +              makes_footstep_sound(true),
 +              m_player_step_timer(0.0f),
 +              m_player_jump_timer(0.0f)
 +      {
 +      }
 +
 +      void playPlayerStep()
 +      {
 +              if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
 +                      m_player_step_timer = 0.03;
 +                      if (makes_footstep_sound)
 +                              m_sound->playSound(m_player_step_sound, false);
 +              }
 +      }
 +
 +      void playPlayerJump()
 +      {
 +              if (m_player_jump_timer <= 0.0f) {
 +                      m_player_jump_timer = 0.2f;
 +                      m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
 +              }
 +      }
 +
 +      static void viewBobbingStep(MtEvent *e, void *data)
 +      {
 +              SoundMaker *sm = (SoundMaker *)data;
 +              sm->playPlayerStep();
 +      }
 +
 +      static void playerRegainGround(MtEvent *e, void *data)
 +      {
 +              SoundMaker *sm = (SoundMaker *)data;
 +              sm->playPlayerStep();
 +      }
 +
 +      static void playerJump(MtEvent *e, void *data)
 +      {
 +              SoundMaker *sm = (SoundMaker *)data;
 +              sm->playPlayerJump();
 +      }
 +
 +      static void cameraPunchLeft(MtEvent *e, void *data)
 +      {
 +              SoundMaker *sm = (SoundMaker *)data;
 +              sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
 +      }
 +
 +      static void cameraPunchRight(MtEvent *e, void *data)
 +      {
 +              SoundMaker *sm = (SoundMaker *)data;
 +              sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
 +      }
 +
 +      static void nodeDug(MtEvent *e, void *data)
 +      {
 +              SoundMaker *sm = (SoundMaker *)data;
 +              NodeDugEvent *nde = (NodeDugEvent *)e;
 +              sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
 +      }
 +
 +      static void playerDamage(MtEvent *e, void *data)
 +      {
 +              SoundMaker *sm = (SoundMaker *)data;
 +              sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
 +      }
 +
 +      static void playerFallingDamage(MtEvent *e, void *data)
 +      {
 +              SoundMaker *sm = (SoundMaker *)data;
 +              sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
 +      }
 +
 +      void registerReceiver(MtEventManager *mgr)
 +      {
 +              mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
 +              mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
 +              mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
 +              mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
 +              mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
 +              mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
 +              mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
 +              mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
 +      }
 +
 +      void step(float dtime)
 +      {
 +              m_player_step_timer -= dtime;
 +              m_player_jump_timer -= dtime;
 +      }
 +};
 +
 +// Locally stored sounds don't need to be preloaded because of this
 +class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
 +{
 +      std::set<std::string> m_fetched;
 +private:
 +      void paths_insert(std::set<std::string> &dst_paths,
 +              const std::string &base,
 +              const std::string &name)
 +      {
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
 +              dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
 +      }
 +public:
 +      void fetchSounds(const std::string &name,
 +              std::set<std::string> &dst_paths,
 +              std::set<std::string> &dst_datas)
 +      {
 +              if (m_fetched.count(name))
 +                      return;
 +
 +              m_fetched.insert(name);
 +
 +              paths_insert(dst_paths, porting::path_share, name);
 +              paths_insert(dst_paths, porting::path_user,  name);
 +      }
 +};
 +
 +
 +// before 1.8 there isn't a "integer interface", only float
 +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
 +typedef f32 SamplerLayer_t;
 +#else
 +typedef s32 SamplerLayer_t;
 +#endif
 +
 +
 +class GameGlobalShaderConstantSetter : public IShaderConstantSetter
 +{
 +      Sky *m_sky;
 +      bool *m_force_fog_off;
 +      f32 *m_fog_range;
 +      bool m_fog_enabled;
 +      CachedPixelShaderSetting<float, 4> m_sky_bg_color;
 +      CachedPixelShaderSetting<float> m_fog_distance;
 +      CachedVertexShaderSetting<float> m_animation_timer_vertex;
 +      CachedPixelShaderSetting<float> m_animation_timer_pixel;
 +      CachedPixelShaderSetting<float, 3> m_day_light;
 +      CachedPixelShaderSetting<float, 4> m_star_color;
 +      CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
 +      CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
 +      CachedPixelShaderSetting<float, 3> m_minimap_yaw;
 +      CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
 +      CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
 +      CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
++      CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
 +      Client *m_client;
 +
 +public:
 +      void onSettingsChange(const std::string &name)
 +      {
 +              if (name == "enable_fog")
 +                      m_fog_enabled = g_settings->getBool("enable_fog");
 +      }
 +
 +      static void settingsCallback(const std::string &name, void *userdata)
 +      {
 +              reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
 +      }
 +
 +      void setSky(Sky *sky) { m_sky = sky; }
 +
 +      GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
 +                      f32 *fog_range, Client *client) :
 +              m_sky(sky),
 +              m_force_fog_off(force_fog_off),
 +              m_fog_range(fog_range),
 +              m_sky_bg_color("skyBgColor"),
 +              m_fog_distance("fogDistance"),
 +              m_animation_timer_vertex("animationTimer"),
 +              m_animation_timer_pixel("animationTimer"),
 +              m_day_light("dayLight"),
 +              m_star_color("starColor"),
 +              m_eye_position_pixel("eyePosition"),
 +              m_eye_position_vertex("eyePosition"),
 +              m_minimap_yaw("yawVec"),
 +              m_camera_offset_pixel("cameraOffset"),
 +              m_camera_offset_vertex("cameraOffset"),
 +              m_base_texture("baseTexture"),
++              m_normal_texture("normalTexture"),
 +              m_client(client)
 +      {
 +              g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
 +              m_fog_enabled = g_settings->getBool("enable_fog");
 +      }
 +
 +      ~GameGlobalShaderConstantSetter()
 +      {
 +              g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
 +      }
 +
 +      void onSetConstants(video::IMaterialRendererServices *services) override
 +      {
 +              // Background color
 +              video::SColor bgcolor = m_sky->getBgColor();
 +              video::SColorf bgcolorf(bgcolor);
 +              float bgcolorfa[4] = {
 +                      bgcolorf.r,
 +                      bgcolorf.g,
 +                      bgcolorf.b,
 +                      bgcolorf.a,
 +              };
 +              m_sky_bg_color.set(bgcolorfa, services);
 +
 +              // Fog distance
 +              float fog_distance = 10000 * BS;
 +
 +              if (m_fog_enabled && !*m_force_fog_off)
 +                      fog_distance = *m_fog_range;
 +
 +              m_fog_distance.set(&fog_distance, services);
 +
 +              u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
 +              video::SColorf sunlight;
 +              get_sunlight_color(&sunlight, daynight_ratio);
 +              float dnc[3] = {
 +                      sunlight.r,
 +                      sunlight.g,
 +                      sunlight.b };
 +              m_day_light.set(dnc, services);
 +
 +              video::SColorf star_color = m_sky->getCurrentStarColor();
 +              float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
 +              m_star_color.set(clr, services);
 +
 +              u32 animation_timer = porting::getTimeMs() % 1000000;
 +              float animation_timer_f = (float)animation_timer / 100000.f;
 +              m_animation_timer_vertex.set(&animation_timer_f, services);
 +              m_animation_timer_pixel.set(&animation_timer_f, services);
 +
 +              float eye_position_array[3];
 +              v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
 +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
 +              eye_position_array[0] = epos.X;
 +              eye_position_array[1] = epos.Y;
 +              eye_position_array[2] = epos.Z;
 +#else
 +              epos.getAs3Values(eye_position_array);
 +#endif
 +              m_eye_position_pixel.set(eye_position_array, services);
 +              m_eye_position_vertex.set(eye_position_array, services);
 +
 +              if (m_client->getMinimap()) {
 +                      float minimap_yaw_array[3];
 +                      v3f minimap_yaw = m_client->getMinimap()->getYawVec();
 +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
 +                      minimap_yaw_array[0] = minimap_yaw.X;
 +                      minimap_yaw_array[1] = minimap_yaw.Y;
 +                      minimap_yaw_array[2] = minimap_yaw.Z;
 +#else
 +                      minimap_yaw.getAs3Values(minimap_yaw_array);
 +#endif
 +                      m_minimap_yaw.set(minimap_yaw_array, services);
 +              }
 +
 +              float camera_offset_array[3];
 +              v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
 +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
 +              camera_offset_array[0] = offset.X;
 +              camera_offset_array[1] = offset.Y;
 +              camera_offset_array[2] = offset.Z;
 +#else
 +              offset.getAs3Values(camera_offset_array);
 +#endif
 +              m_camera_offset_pixel.set(camera_offset_array, services);
 +              m_camera_offset_vertex.set(camera_offset_array, services);
 +
++              SamplerLayer_t base_tex = 0, normal_tex = 1;
 +              m_base_texture.set(&base_tex, services);
++              m_normal_texture.set(&normal_tex, services);
 +      }
 +};
 +
 +
 +class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
 +{
 +      Sky *m_sky;
 +      bool *m_force_fog_off;
 +      f32 *m_fog_range;
 +      Client *m_client;
 +      std::vector<GameGlobalShaderConstantSetter *> created_nosky;
 +public:
 +      GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
 +                      f32 *fog_range, Client *client) :
 +              m_sky(NULL),
 +              m_force_fog_off(force_fog_off),
 +              m_fog_range(fog_range),
 +              m_client(client)
 +      {}
 +
 +      void setSky(Sky *sky) {
 +              m_sky = sky;
 +              for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
 +                      ggscs->setSky(m_sky);
 +              }
 +              created_nosky.clear();
 +      }
 +
 +      virtual IShaderConstantSetter* create()
 +      {
 +              auto *scs = new GameGlobalShaderConstantSetter(
 +                              m_sky, m_force_fog_off, m_fog_range, m_client);
 +              if (!m_sky)
 +                      created_nosky.push_back(scs);
 +              return scs;
 +      }
 +};
 +
 +#ifdef __ANDROID__
 +#define SIZE_TAG "size[11,5.5]"
 +#else
 +#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
 +#endif
 +
 +/****************************************************************************
 + ****************************************************************************/
 +
 +const float object_hit_delay = 0.2;
 +
 +struct FpsControl {
 +      u32 last_time, busy_time, sleep_time;
 +};
 +
 +
 +/* The reason the following structs are not anonymous structs within the
 + * class is that they are not used by the majority of member functions and
 + * many functions that do require objects of thse types do not modify them
 + * (so they can be passed as a const qualified parameter)
 + */
 +
 +struct GameRunData {
 +      u16 dig_index;
 +      u16 new_playeritem;
 +      PointedThing pointed_old;
 +      bool digging;
 +      bool punching;
 +      bool btn_down_for_dig;
 +      bool dig_instantly;
 +      bool digging_blocked;
 +      bool reset_jump_timer;
 +      float nodig_delay_timer;
 +      float dig_time;
 +      float dig_time_complete;
 +      float repeat_place_timer;
 +      float object_hit_delay_timer;
 +      float time_from_last_punch;
 +      ClientActiveObject *selected_object;
 +
 +      float jump_timer;
 +      float damage_flash;
 +      float update_draw_list_timer;
 +
 +      f32 fog_range;
 +
 +      v3f update_draw_list_last_cam_dir;
 +
 +      float time_of_day_smooth;
 +};
 +
 +class Game;
 +
 +struct ClientEventHandler
 +{
 +      void (Game::*handler)(ClientEvent *, CameraOrientation *);
 +};
 +
++using PausedNodesList = std::vector<std::pair<irr_ptr<scene::IAnimatedMeshSceneNode>, float>>;
++
 +class Game {
 +public:
 +      Game();
 +      ~Game();
 +
 +      bool startup(bool *kill,
 +                      InputHandler *input,
 +                      const GameStartData &game_params,
 +                      std::string &error_message,
 +                      bool *reconnect,
 +                      ChatBackend *chat_backend);
 +
 +
 +      void run();
 +      void shutdown();
 +
 +      void extendedResourceCleanup();
 +
 +      // Basic initialisation
 +      bool init(const std::string &map_dir, const std::string &address,
 +                      u16 port, const SubgameSpec &gamespec);
 +      bool initSound();
 +      bool createSingleplayerServer(const std::string &map_dir,
 +                      const SubgameSpec &gamespec, u16 port);
 +
 +      // Client creation
 +      bool createClient(const GameStartData &start_data);
 +      bool initGui();
 +
 +      // Client connection
 +      bool connectToServer(const GameStartData &start_data,
 +                      bool *connect_ok, bool *aborted);
 +      bool getServerContent(bool *aborted);
 +
 +      // Main loop
 +
 +      void updateInteractTimers(f32 dtime);
 +      bool checkConnection();
 +      bool handleCallbacks();
 +      void processQueues();
 +      void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
 +      void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
 +      void updateProfilerGraphs(ProfilerGraph *graph);
 +
 +      // Input related
 +      void processUserInput(f32 dtime);
 +      void processKeyInput();
 +      void processItemSelection(u16 *new_playeritem);
 +
 +      void dropSelectedItem(bool single_item = false);
 +      void openInventory();
 +      void openEnderchest();
 +      void openConsole(float scale, const wchar_t *line=NULL);
 +      void toggleFreeMove();
 +      void toggleFreeMoveAlt();
 +      void togglePitchMove();
 +      void toggleFast();
 +      void toggleNoClip();
 +      void toggleKillaura();
 +      void toggleFreecam();
 +      void toggleScaffold();
 +      void toggleNextItem();
 +      void toggleCinematic();
 +      void toggleAutoforward();
 +
 +      void toggleMinimap(bool shift_pressed);
 +      void toggleFog();
 +      void toggleDebug();
 +      void toggleUpdateCamera();
 +      void updatePlayerCAOVisibility();
 +
 +      void increaseViewRange();
 +      void decreaseViewRange();
 +      void toggleFullViewRange();
 +      void checkZoomEnabled();
 +
 +      void updateCameraDirection(CameraOrientation *cam, float dtime);
 +      void updateCameraOrientation(CameraOrientation *cam, float dtime);
 +      void updatePlayerControl(const CameraOrientation &cam);
 +      void step(f32 *dtime);
 +      void processClientEvents(CameraOrientation *cam);
 +      void updateCamera(u32 busy_time, f32 dtime);
 +      void updateSound(f32 dtime);
 +      void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug);
 +      /*!
 +       * Returns the object or node the player is pointing at.
 +       * Also updates the selected thing in the Hud.
 +       *
 +       * @param[in]  shootline         the shootline, starting from
 +       * the camera position. This also gives the maximal distance
 +       * of the search.
 +       * @param[in]  liquids_pointable if false, liquids are ignored
 +       * @param[in]  look_for_object   if false, objects are ignored
 +       * @param[in]  camera_offset     offset of the camera
 +       * @param[out] selected_object   the selected object or
 +       * NULL if not found
 +       */
 +      PointedThing updatePointedThing(
 +                      const core::line3d<f32> &shootline, bool liquids_pointable,
 +                      bool look_for_object, const v3s16 &camera_offset);
 +      void handlePointingAtNothing(const ItemStack &playerItem);
 +      void handlePointingAtNode(const PointedThing &pointed,
 +                      const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
 +      void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
 +                      const v3f &player_position, bool show_debug);
 +      void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
 +                      const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
 +      void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
 +                      const CameraOrientation &cam);
 +
 +      // Misc
 +      void limitFps(FpsControl *fps_timings, f32 *dtime);
 +
 +      void showOverlayMessage(const char *msg, float dtime, int percent,
 +                      bool draw_clouds = true);
 +
 +      static void freecamChangedCallback(const std::string &setting_name, void *data);
 +      static void settingChangedCallback(const std::string &setting_name, void *data);
 +      static void updateAllMapBlocksCallback(const std::string &setting_name, void *data);
 +      void readSettings();
 +
 +      bool isKeyDown(GameKeyType k);
 +      bool wasKeyDown(GameKeyType k);
 +      bool wasKeyPressed(GameKeyType k);
 +      bool wasKeyReleased(GameKeyType k);
 +
 +#ifdef __ANDROID__
 +      void handleAndroidChatInput();
 +#endif
 +
 +      struct Flags {
 +              bool force_fog_off = false;
 +              bool disable_camera_update = false;
 +      };
 +
 +      void showDeathFormspec();
 +      void showPauseMenu();
 +
++      void pauseAnimation();
++      void resumeAnimation();
++
 +      // ClientEvent handlers
 +      void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_HandleParticleEvent(ClientEvent *event,
 +              CameraOrientation *cam);
 +      void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
 +      void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
 +              CameraOrientation *cam);
 +      void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
 +
 +      void updateChat(f32 dtime, const v2u32 &screensize);
 +
 +      bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
 +              const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
 +              const NodeMetadata *meta, bool force = false);
 +      static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
 +
++      f32 getSensitivityScaleFactor() const;
++
 +      InputHandler *input = nullptr;
 +
 +      Client *client = nullptr;
 +      Server *server = nullptr;
 +
 +      IWritableTextureSource *texture_src = nullptr;
 +      IWritableShaderSource *shader_src = nullptr;
 +
 +      // When created, these will be filled with data received from the server
 +      IWritableItemDefManager *itemdef_manager = nullptr;
 +      NodeDefManager *nodedef_manager = nullptr;
 +
 +      GameOnDemandSoundFetcher soundfetcher; // useful when testing
 +      ISoundManager *sound = nullptr;
 +      bool sound_is_dummy = false;
 +      SoundMaker *soundmaker = nullptr;
 +
 +      ChatBackend *chat_backend = nullptr;
 +      LogOutputBuffer m_chat_log_buf;
 +
 +      EventManager *eventmgr = nullptr;
 +      QuicktuneShortcutter *quicktune = nullptr;
 +      bool registration_confirmation_shown = false;
 +
 +      std::unique_ptr<GameUI> m_game_ui;
 +      GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
 +      CheatMenu *m_cheat_menu = nullptr;
 +      MapDrawControl *draw_control = nullptr;
 +      Camera *camera = nullptr;
 +      Clouds *clouds = nullptr;                         // Free using ->Drop()
 +      Sky *sky = nullptr;                         // Free using ->Drop()
 +      Hud *hud = nullptr;
 +      Minimap *mapper = nullptr;
 +
++      // Map server hud ids to client hud ids
++      std::unordered_map<u32, u32> m_hud_server_to_client;
++
 +      GameRunData runData;
 +      Flags m_flags;
 +
 +      /* 'cache'
 +         This class does take ownership/responsibily for cleaning up etc of any of
 +         these items (e.g. device)
 +      */
 +      IrrlichtDevice *device;
 +      video::IVideoDriver *driver;
 +      scene::ISceneManager *smgr;
 +      bool *kill;
 +      std::string *error_message;
 +      bool *reconnect_requested;
 +      scene::ISceneNode *skybox;
++      PausedNodesList paused_animated_nodes;
 +
 +      bool simple_singleplayer_mode;
 +      /* End 'cache' */
 +
 +      /* Pre-calculated values
 +       */
 +      int crack_animation_length;
 +
 +      IntervalLimiter profiler_interval;
 +
 +      /*
 +       * 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_clouds;
 +      bool m_cache_enable_joysticks;
 +      bool m_cache_enable_particles;
 +      bool m_cache_enable_fog;
 +      bool m_cache_enable_noclip;
 +      bool m_cache_enable_free_move;
 +      f32  m_cache_mouse_sensitivity;
 +      f32  m_cache_joystick_frustum_sensitivity;
 +      f32  m_repeat_place_time;
 +      f32  m_cache_cam_smoothing;
 +      f32  m_cache_fog_start;
 +
 +      bool m_invert_mouse = false;
 +      bool m_first_loop_after_window_activation = false;
 +      bool m_camera_offset_changed = false;
 +
 +      bool m_does_lost_focus_pause_game = false;
 +
 +      CameraOrientation cam_view_target  = { 0 };
 +      CameraOrientation cam_view  = { 0 };
 +
 +      int m_reset_HW_buffer_counter = 0;
 +#ifdef __ANDROID__
 +      bool m_cache_hold_aux1;
 +      bool m_android_chat_open;
 +#endif
 +};
 +extern Game *g_game;
  
  void the_game(bool *kill,
                InputHandler *input,
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index a1cd6193297d4bf7cea6508a13b2be55b5075719,9d155f76cf12dad656a1c889f245e9fafddd712c..44b8c91d65f66f1d21eca149808df35fed693325
@@@ -138,8 -80,7 +138,8 @@@ void set_default_settings(
        settings->setDefault("keymap_drop", "KEY_KEY_Q");
        settings->setDefault("keymap_zoom", "KEY_KEY_Z");
        settings->setDefault("keymap_inventory", "KEY_KEY_I");
-       settings->setDefault("keymap_special1", "KEY_KEY_E");
 +      settings->setDefault("keymap_enderchest", "KEY_KEY_O");
+       settings->setDefault("keymap_aux1", "KEY_KEY_E");
        settings->setDefault("keymap_chat", "KEY_KEY_T");
        settings->setDefault("keymap_cmd", "/");
        settings->setDefault("keymap_cmd_local", ".");
  #endif
        settings->setDefault("enable_particles", "true");
        settings->setDefault("arm_inertia", "true");
+       settings->setDefault("show_nametag_backgrounds", "true");
  
        settings->setDefault("enable_minimap", "true");
 -      settings->setDefault("minimap_shape_round", "true");
 +      settings->setDefault("minimap_shape_round", "false");
        settings->setDefault("minimap_double_scan_height", "true");
  
        // Effects
Simple merge
Simple merge
Simple merge
diff --cc src/nodedef.cpp
Simple merge
Simple merge
Simple merge
Simple merge