]> git.lizzy.rs Git - dragonfireclient.git/commitdiff
Merged Minetest
authorElias Fleckenstein <eliasfleckenstein@web.de>
Sat, 28 Nov 2020 12:48:33 +0000 (13:48 +0100)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Sat, 28 Nov 2020 12:48:33 +0000 (13:48 +0100)
46 files changed:
1  2 
CMakeLists.txt
builtin/client/chatcommands.lua
builtin/client/register.lua
builtin/game/item.lua
builtin/mainmenu/init.lua
builtin/settingtypes.txt
doc/client_lua_api.txt
doc/lua_api.txt
src/client/camera.cpp
src/client/client.cpp
src/client/client.h
src/client/clientenvironment.cpp
src/client/clientmap.cpp
src/client/content_cao.cpp
src/client/content_cao.h
src/client/game.cpp
src/client/game.h
src/client/gameui.cpp
src/client/inputhandler.cpp
src/client/inputhandler.h
src/client/keys.h
src/client/localplayer.cpp
src/client/mapblock_mesh.cpp
src/client/mapblock_mesh.h
src/client/mesh_generator_thread.h
src/client/minimap.cpp
src/client/render/core.cpp
src/defaultsettings.cpp
src/environment.cpp
src/gui/CMakeLists.txt
src/map.cpp
src/map.h
src/network/clientpackethandler.cpp
src/network/networkprotocol.h
src/nodedef.cpp
src/player.h
src/script/common/c_content.cpp
src/script/common/c_content.h
src/script/cpp_api/s_security.cpp
src/script/lua_api/l_base.cpp
src/script/lua_api/l_base.h
src/script/lua_api/l_env.cpp
src/script/lua_api/l_env.h
src/script/lua_api/l_http.cpp
src/script/lua_api/l_item.cpp
src/script/lua_api/l_localplayer.cpp

diff --cc CMakeLists.txt
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 498e3f0351aced1b1b7c3cce99ac372e0333b05a,dd49142018d89e8d5c5a8f42444f3fedf59a89e3..49a15f4ffd65fa9fdf12179d7dd016ec70e94de7
@@@ -2213,163 -2187,5 +2199,166 @@@ contentdb_url (ContentDB URL) string ht
  #    so see a full list at https://content.minetest.net/help/content_flags/
  contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_default
  
+ #    Maximum number of concurrent downloads. Downloads exceeding this limit will be queued.
+ contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3
++
 +[Cheat Menu]
 +
 +#   Font to use for cheat menu
 +cheat_menu_font (MenuFont) enum FM_Mono FM_Standard,FM_Mono,FM_Fallback,FM_Simple,FM_SimpleMono,FM_MaxMode,FM_Unspecified
 +
 +#   (RGB value)
 +cheat_menu_bg_color (Cell background color) v3f 255, 145, 88
 +
 +cheat_menu_bg_color_alpha (Cell background color alpha) int 192
 +
 +#   (RGB value)
 +cheat_menu_active_bg_color (Active cell background color) v3f 255, 87, 53
 +
 +cheat_menu_active_bg_color_alpha (Active cell background color alpha) int 192
 +
 +#   (RGB value)
 +cheat_menu_font_color (Font color) v3f 0, 0, 0
 +
 +cheat_menu_font_color_alpha (Font color alpha) int 255 
 +
 +#   (RGB value)
 +cheat_menu_selected_font_color (Selected font color) v3f 255, 252, 88
 +
 +cheat_menu_selected_font_color_alpha (Selected font color alpha) int 255
 +
 +[Cheats]
 +
 +fullbright (Fullbright) bool false
 +
 +xray (XRay) bool false
 +
 +xray_nodes (XRay Nodes) string default:stone,mcl_core:stone
 +
 +priv_bypass (PrivBypass) bool true
 +
 +fastdig (FastDig) bool false
 +
 +fastplace (FastPlace) bool false
 +
 +autodig (AutoDig) bool false
 +
 +autoplace (AutoPlace) bool false
 +
 +prevent_natural_damage (NoFallDamage) bool true
 +
 +freecam (Freecam) bool false
 +
 +killaura (Killaura) bool false
 +
 +no_hurt_cam (NoHurtCam) bool false
 +
 +increase_tool_range (IncreasedRange) bool true
 +
 +increase_tool_range_plus (IncreasedRangePlus) bool true
 +
 +hud_flags_bypass (HUDBypass) bool true
 +
 +antiknockback (AntiKnockback) bool false
 +
 +entity_speed (GodMode) bool false
 +
 +jesus (Jesus) bool false
 +
 +instant_break (InstantBreak) bool false
 +
 +no_night (BrightNight) bool false
 +
 +coords (Coords) bool false
 +
 +point_liquids (PointLiquids) bool false
 +
 +log_particles (ParticleExploit) bool false
 +
 +spamclick (FastHit) bool false
 +
 +no_force_rotate (NoForceRotate) bool false
 +
 +enable_tracers (Tracers) bool false
 +
 +enable_esp (ESP) bool false
 +
 +no_slow (NoSlow) bool false
 +
 +ignore_status_messages (IgnoreStatus) bool true
 +
 +mark_deathmessages (Deathmessages) bool true
 +
 +autosneak (AutoSneak) bool false
 +
 +autoeject (AutoEject) bool false
 +
 +eject_items (AutoEject Items) string
 +
 +autotool (AutoTool) bool false
 +
 +autorespawn (AutoRespawn) bool false
 +
 +next_item (NextItem) bool false
 +
 +scaffold (Scaffold) bool false
 +
 +scaffold_plus (ScaffoldPlus) bool false
 +
 +block_water (BlockWater) bool false
 +
 +autotnt (PlaceOnTop) bool false
 +
 +replace (Replace) bool false
 +
 +crystal_pvp (CrystalPvP) bool false
 +
 +autototem (AutoTotem) bool false
 +
 +dont_point_nodes (ThroughWalls) bool false
 +
 +strip (Strip) bool false
 +
 +autorefill (AutoRefill) bool false
 +
 +nuke (Nuke) bool false
 +
 +chat_color (Chat Color) string rainbow
 +
 +use_chat_color (ColoredChat) bool false
 +
 +chat_reverse (ReversedChat) bool false
 +
 +forcefield (Forcefield) bool false
 +
 +friendlist (Killaura / Forcefield Friendlist) string
 +
 +cheat_hud (CheatHUD) bool true
 +
 +enable_node_esp (NodeESP) bool false
 +
 +enable_node_tracers (NodeTracers) bool false
 +
 +node_esp_nodes (NodeESP Nodes) string
 +
 +only_trace_players (OnlyTracePlayers) bool false
 +
 +autosprint (AutoSprint) bool false
 +
 +override_speed (SpeedOverride) bool false
 +
 +override_jump (JumpOverride) bool false
 +
 +override_gravity (GravityOverride) bool false
 +
 +override_speed_factor (SpeedOverride Factor) float 1.2
 +
 +override_jump_factor (JumpOverride Factor) float 2.0
 +
 +override_gravity_factor (GravityOverride) float 0.8
 +
 +jetpack (JetPack) bool false
 +
 +autohit (AutoHit) bool false
 +
 +antislip (AntiSlip) bool false
index ea6f4e13fa32358f40e23c7814aebc35099ca0c1,32be2fabfd35edaff60335c65fd302d2d37f0f47..f14b8ecebd6de8fd1c3625da8a3652511cff1f36
@@@ -696,13 -686,11 +696,18 @@@ Call these functions only at load time
      * Adds definition to minetest.registered_chatcommands
  * `minetest.unregister_chatcommand(name)`
      * Unregisters a chatcommands registered with register_chatcommand.
 +* `minetest.register_list_command(command, desc, setting)`
 +    * Registers a chatcommand `command` to manage a list that takes the args `del | add | list <param>`
 +    * The list is stored comma-seperated in `setting`
 +    * `desc` is the description
 +    * `add` adds something to the list 
 +    * `del` del removes something from the list
 +    * `list` lists all items on the list
+ * `minetest.register_on_chatcommand(function(command, params))`
+     * Called always when a chatcommand is triggered, before `minetest.registered_chatcommands`
+       is checked to see if that the command exists, but after the input is parsed.
+     * Return `true` to mark the command as handled, which means that the default
+       handlers will be prevented.
  * `minetest.register_on_death(function())`
      * Called when the local player dies
  * `minetest.register_on_hp_modification(function(hp))`
diff --cc doc/lua_api.txt
Simple merge
Simple merge
index aa3e257acc261d004d809b9fc63e7c859ec6718f,af69d0ec9055cd63b175372ce6cda9b9fc75fc3b..9bbb57668062eaf371c9e7164fdd5c22c8b7c030
@@@ -1662,27 -1657,6 +1660,25 @@@ void Client::addUpdateMeshTaskForNode(v
        }
  }
  
-       std::map<v2s16, MapSector*> *sectors = m_env.getMap().getSectorsPtr();
 +void Client::updateAllMapBlocks()
 +{
 +      v3s16 currentBlock = getNodeBlockPos(floatToInt(m_env.getLocalPlayer()->getPosition(), BS));
 +      
 +      for (s16 X = currentBlock.X - 2; X <= currentBlock.X + 2; X++)
 +      for (s16 Y = currentBlock.Y - 2; Y <= currentBlock.Y + 2; Y++)
 +      for (s16 Z = currentBlock.Z - 2; Z <= currentBlock.Z + 2; Z++)
 +              addUpdateMeshTask(v3s16(X, Y, Z), false, true);
 +      
-       for (auto &sector_it : *sectors) {
-               MapSector *sector = sector_it.second;
-               MapBlockVect blocks;
-               sector->getBlocks(blocks);
-               for (MapBlock *block : blocks) {
-                       addUpdateMeshTask(block->getPos(), false, false);
-               }
++      Map &map = m_env.getMap();
 +      
++      std::vector<v3s16> positions;
++      map.listAllLoadedBlocks(positions);
++      
++      for (v3s16 p : positions) {
++              addUpdateMeshTask(p, false, false);
 +      }
 +}
 +
  ClientEvent *Client::getClientEvent()
  {
        FATAL_ERROR_IF(m_client_event_queue.empty(),
Simple merge
index 3f82bd3165bf5d25907a54237cda6c9309692e2a,ea7be4200c3bc9726134bfe1b9d55b3d162b08a3..2b50fbf64beb065dcec8ad1620ba19692cde54d2
@@@ -189,78 -187,57 +187,57 @@@ void ClientEnvironment::step(float dtim
                Stuff that has a maximum time increment
        */
  
-       u32 loopcount = 0;
-       do
-       {
-               loopcount++;
-               f32 dtime_part;
-               if(dtime_downcount > dtime_max_increment)
-               {
-                       dtime_part = dtime_max_increment;
-                       dtime_downcount -= dtime_part;
-               }
-               else
-               {
-                       dtime_part = dtime_downcount;
-                       /*
-                               Setting this to 0 (no -=dtime_part) disables an infinite loop
-                               when dtime_part is so small that dtime_downcount -= dtime_part
-                               does nothing
-                       */
-                       dtime_downcount = 0;
-               }
+       u32 steps = ceil(dtime / dtime_max_increment);
+       f32 dtime_part = dtime / steps;
+       for (; steps > 0; --steps) {
                /*
-                       Handle local player
+                       Local player handling
                */
  
-               {
-                       // Control local player
-                       lplayer->applyControl(dtime_part, this);
-                       // Apply physics
-                       if (!free_move && !is_climbing && ! g_settings->getBool("freecam")) {
-                               // Gravity
-                               v3f speed = lplayer->getSpeed();
-                               if (!lplayer->in_liquid)
-                                       speed.Y -= lplayer->movement_gravity *
-                                               lplayer->physics_override_gravity * dtime_part * 2.0f;
-                               // Liquid floating / sinking
-                               if (lplayer->in_liquid && !lplayer->swimming_vertical &&
-                                               !lplayer->swimming_pitch)
-                                       speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2.0f;
-                               // Liquid resistance
-                               if (lplayer->in_liquid_stable || lplayer->in_liquid) {
-                                       // How much the node's viscosity blocks movement, ranges
-                                       // between 0 and 1. Should match the scale at which viscosity
-                                       // increase affects other liquid attributes.
-                                       static const f32 viscosity_factor = 0.3f;
-                                       v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
-                                       f32 dl = d_wanted.getLength();
-                                       if (dl > lplayer->movement_liquid_fluidity_smooth)
-                                               dl = lplayer->movement_liquid_fluidity_smooth;
-                                       dl *= (lplayer->liquid_viscosity * viscosity_factor) +
-                                               (1 - viscosity_factor);
-                                       v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f);
-                                       speed += d;
-                               }
-                               lplayer->setSpeed(speed);
+               // Control local player
+               lplayer->applyControl(dtime_part, this);
+               // Apply physics
 -              if (!free_move && !is_climbing) {
++              if (!free_move && !is_climbing && !g_settings->getBool("freecam")) {
+                       // Gravity
+                       v3f speed = lplayer->getSpeed();
+                       if (!lplayer->in_liquid)
+                               speed.Y -= lplayer->movement_gravity *
+                                       lplayer->physics_override_gravity * dtime_part * 2.0f;
+                       // Liquid floating / sinking
+                       if (lplayer->in_liquid && !lplayer->swimming_vertical &&
+                                       !lplayer->swimming_pitch)
+                               speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2.0f;
+                       // Liquid resistance
+                       if (lplayer->in_liquid_stable || lplayer->in_liquid) {
+                               // How much the node's viscosity blocks movement, ranges
+                               // between 0 and 1. Should match the scale at which viscosity
+                               // increase affects other liquid attributes.
+                               static const f32 viscosity_factor = 0.3f;
+                               v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
+                               f32 dl = d_wanted.getLength();
+                               if (dl > lplayer->movement_liquid_fluidity_smooth)
+                                       dl = lplayer->movement_liquid_fluidity_smooth;
+                               dl *= (lplayer->liquid_viscosity * viscosity_factor) +
+                                       (1 - viscosity_factor);
+                               v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f);
+                               speed += d;
                        }
  
-                       /*
-                               Move the lplayer.
-                               This also does collision detection.
-                       */
-                       lplayer->move(dtime_part, this, position_max_increment,
-                               &player_collisions);
+                       lplayer->setSpeed(speed);
                }
-       } while (dtime_downcount > 0.001);
+               /*
+                       Move the lplayer.
+                       This also does collision detection.
+               */
+               lplayer->move(dtime_part, this, position_max_increment,
+                       &player_collisions);
+       }
  
        bool player_immortal = lplayer->getCAO() && lplayer->getCAO()->isImmortal();
  
Simple merge
index e1cebf461acaec2831ea3425a88aabee0a6ef77b,c645900aa258c3c903359bd65f8dfd18fcbb8c4e..7208212d41d0a086236a21972bb0315bab31ac4a
@@@ -47,7 -47,7 +47,8 @@@ with this program; if not, write to th
  #include <algorithm>
  #include <cmath>
  #include "client/shader.h"
 +#include "script/scripting_client.h"
+ #include "client/minimap.h"
  
  class Settings;
  struct ToolCapabilities;
@@@ -480,8 -483,21 +486,22 @@@ void GenericCAO::setAttachment(int pare
                if (parent)
                        parent->addAttachmentChild(m_id);
        }
-       
++
        updateAttachments();
+       // Forcibly show attachments if required by set_attach
+       if (m_force_visible) {
+               m_is_visible = true;
+       } else if (!m_is_local_player) {
+               // Objects attached to the local player should be hidden in first person
+               m_is_visible = !m_attached_to_local ||
+                       m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST;
+               m_force_visible = false;
+       } else {
+               // Local players need to have this set,
+               // otherwise first person attachments fail.
+               m_is_visible = true;
+       }
  }
  
  void GenericCAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
@@@ -889,9 -909,29 +915,29 @@@ u16 GenericCAO::getLightPosition(v3s16 
        return 3;
  }
  
+ void GenericCAO::updateMarker()
+ {
+       if (!m_client->getMinimap())
+               return;
+       if (!m_prop.show_on_minimap) {
+               if (m_marker)
+                       m_client->getMinimap()->removeMarker(&m_marker);
+               return;
+       }
+       if (m_marker)
+               return;
+       scene::ISceneNode *node = getSceneNode();
+       if (!node)
+               return;
+       m_marker = m_client->getMinimap()->addMarker(node);
+ }
  void GenericCAO::updateNametag()
  {
 -      if (m_is_local_player) // No nametag for local player
 +      if (m_is_local_player && ! g_settings->getBool("freecam")) // No nametag for local player
                return;
  
        if (m_prop.nametag.empty()) {
@@@ -978,16 -1016,16 +1024,16 @@@ void GenericCAO::step(float dtime, Clie
                                        m_client->checkLocalPrivilege("fly"))))
                                        new_speed *= 1.5;
                        // slowdown speed if sneeking
 -                      if (controls.sneak && walking)
 +                      if (controls.sneak && walking && ! g_settings->getBool("no_slow"))
                                new_speed /= 2;
  
-                       if (walking && (controls.LMB || controls.RMB)) {
+                       if (walking && (controls.dig || controls.place)) {
                                new_anim = player->local_animations[3];
                                player->last_animation = WD_ANIM;
-                       } else if(walking) {
+                       } else if (walking) {
                                new_anim = player->local_animations[1];
                                player->last_animation = WALK_ANIM;
-                       } else if(controls.LMB || controls.RMB) {
+                       } else if (controls.dig || controls.place) {
                                new_anim = player->local_animations[2];
                                player->last_animation = DIG_ANIM;
                        }
index 75882a07496ff030089ef6104c2fc97aff896387,7c134fb48ec7f5fe4d9951fbd02f60e7aa52d34c..09c26bd9c12d69db4c539173dce24e2380094ce3
@@@ -301,11 -281,6 +307,13 @@@ public
        {
                return m_prop.infotext;
        }
 +      
 +      float m_waiting_for_reattach;
 +      
 +      ObjectProperties *getProperties()
 +      {
 +              return &m_prop;
 +      }
+       void updateMeshCulling();
  };
index 88607d1d86ed8feb38d840c909190b827ab697ae,2001f0487b3448ef70c97e0213883f392068ce3f..cc2a1bc43dd65ed8ebbec04c15b7470831be2a55
@@@ -2244,15 -2964,6 +2227,16 @@@ void Game::updateCamera(u32 busy_time, 
        }
  }
  
-       playercao->setVisible(camera->getCameraMode() > CAMERA_MODE_FIRST || g_settings->getBool("freecam"));
-       playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST || g_settings->getBool("freecam"));
 +void Game::updatePlayerCAOVisibility()
 +{
++      // Make the player visible depending on camera mode.
 +      LocalPlayer *player = client->getEnv().getLocalPlayer();
 +      GenericCAO *playercao = player->getCAO();
 +      if (!playercao)
 +              return;
++      playercao->updateMeshCulling();
++      playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST || g_settings->getBool("freecam"));   
 +}
  
  void Game::updateSound(f32 dtime)
  {
@@@ -2406,14 -3108,14 +2386,14 @@@ void Game::processPlayerInteraction(f3
        soundmaker->m_player_leftpunch_sound.name = "";
  
        // Prepare for repeating, unless we're not supposed to
-       if ((input->getRightState() || g_settings->getBool("autoplace")) && !g_settings->getBool("safe_dig_and_place"))
-               runData.repeat_rightclick_timer += dtime;
 -      if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place"))
++      if ((isKeyDown(KeyType::PLACE) || g_settings->getBool("autoplace")) && !g_settings->getBool("safe_dig_and_place"))
+               runData.repeat_place_timer += dtime;
        else
-               runData.repeat_rightclick_timer = 0;
+               runData.repeat_place_timer = 0;
  
-       if (selected_def.usable && input->getLeftState()) {
-               if (input->getLeftClicked() && (!client->modsLoaded()
-                               || !client->getScript()->on_item_use(selected_item, pointed)))
+       if (selected_def.usable && isKeyDown(KeyType::DIG)) {
+               if (wasKeyPressed(KeyType::DIG) && (!client->modsLoaded() ||
+                               !client->getScript()->on_item_use(selected_item, pointed)))
                        client->interact(INTERACT_USE, pointed);
        } else if (pointed.type == POINTEDTHING_NODE) {
                handlePointingAtNode(pointed, selected_item, hand_item, dtime);
@@@ -2535,9 -3241,10 +2518,9 @@@ PointedThing Game::updatePointedThing
        return result;
  }
  
 -
  void Game::handlePointingAtNothing(const ItemStack &playerItem)
  {
-       infostream << "Right Clicked in Air" << std::endl;
+       infostream << "Attempted to place item while pointing at nothing" << std::endl;
        PointedThing fauxPointed;
        fauxPointed.type = POINTEDTHING_NOTHING;
        client->interact(INTERACT_ACTIVATE, fauxPointed);
@@@ -2556,10 -3263,9 +2539,10 @@@ void Game::handlePointingAtNode(const P
  
        ClientMap &map = client->getEnv().getClientMap();
  
-       if (((runData.nodig_delay_timer <= 0.0 || g_settings->getBool("fastdig")) && (input->getLeftState() || g_settings->getBool("autodig"))
 -      if (runData.nodig_delay_timer <= 0.0 && isKeyDown(KeyType::DIG)
++      if (((runData.nodig_delay_timer <= 0.0 || g_settings->getBool("fastdig")) && (isKeyDown(KeyType::DIG) || g_settings->getBool("autodig"))
                        && !runData.digging_blocked
 -                      && client->checkPrivilege("interact")) {
 +                      && client->checkPrivilege("interact"))
 +              ) {
                handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
        }
  
                }
        }
  
-       if ((input->getRightState() || g_settings->getBool("autoplace")) && 
-                       (input->getRightClicked() ||
-                       (runData.repeat_rightclick_timer >= (g_settings->getBool("fastplace") ? 0 : m_repeat_right_click_time))) &&
 -      if ((wasKeyPressed(KeyType::PLACE) ||
 -                      runData.repeat_place_timer >= m_repeat_place_time) &&
++      if (((wasKeyPressed(KeyType::PLACE) || g_settings->getBool("autoplace")) ||
++                      (runData.repeat_place_timer >= (g_settings->getBool("fastplace") ? 0 : m_repeat_place_time))) &&
                        client->checkPrivilege("interact")) {
-               runData.repeat_rightclick_timer = 0;
-               infostream << "Ground right-clicked" << std::endl;
+               runData.repeat_place_timer = 0;
+               infostream << "Place button pressed while looking at ground" << std::endl;
  
-               camera->setDigging(1);  // right click animation (always shown for feedback)
+               // Placing animation (always shown for feedback)
+               camera->setDigging(1);
  
                soundmaker->m_player_rightpunch_sound = SimpleSoundSpec();
  
@@@ -2811,7 -3518,7 +2795,7 @@@ void Game::handlePointingAtObject(cons
  
        m_game_ui->setInfoText(infotext);
  
-       if (input->getLeftState() || g_settings->getBool("autohit")) {
 -      if (isKeyDown(KeyType::DIG)) {
++      if (isKeyDown(KeyType::DIG) || g_settings->getBool("autohit")) {
                bool do_punch = false;
                bool do_punch_damage = false;
  
                                        dir, &tool_item, runData.time_from_last_punch);
                        runData.time_from_last_punch = 0;
  
 -                      if (!disable_send)
 +                      if (!disable_send) {
                                client->interact(INTERACT_START_DIGGING, pointed);
 +                      }
                }
-       } else if (input->getRightClicked()) {
-               infostream << "Right-clicked object" << std::endl;
+       } else if (wasKeyDown(KeyType::PLACE)) {
+               infostream << "Pressed place button while pointing at object" << std::endl;
                client->interact(INTERACT_PLACE, pointed);  // place
        }
  }
@@@ -3446,40 -4141,32 +3450,42 @@@ void Game::showPauseMenu(
                "- %s: move backwards\n"
                "- %s: move left\n"
                "- %s: move right\n"
-               "- %s: jump/climb\n"
-               "- %s: sneak/go down\n"
+               "- %s: jump/climb up\n"
+               "- %s: dig/punch\n"
+               "- %s: place/use\n"
+               "- %s: sneak/climb down\n"
                "- %s: drop item\n"
                "- %s: inventory\n"
 +              "- %s: enderchest\n"
                "- Mouse: turn/look\n"
-               "- Mouse left: dig/punch\n"
-               "- Mouse right: place/use\n"
                "- Mouse wheel: select item\n"
                "- %s: chat\n"
 +              "- %s: Killaura\n"
 +              "- %s: Freecam\n"
 +              "- %s: Scaffold\n"
 +              "- %s: NextItem\n"
        );
  
 -      char control_text_buf[600];
 -
 -      porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
 -              GET_KEY_NAME(keymap_forward),
 -              GET_KEY_NAME(keymap_backward),
 -              GET_KEY_NAME(keymap_left),
 -              GET_KEY_NAME(keymap_right),
 -              GET_KEY_NAME(keymap_jump),
 -              GET_KEY_NAME(keymap_dig),
 -              GET_KEY_NAME(keymap_place),
 -              GET_KEY_NAME(keymap_sneak),
 -              GET_KEY_NAME(keymap_drop),
 -              GET_KEY_NAME(keymap_inventory),
 -              GET_KEY_NAME(keymap_chat)
 -      );
 +       char control_text_buf[600];
 +
 +       porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
 +                      GET_KEY_NAME(keymap_forward),
 +                      GET_KEY_NAME(keymap_backward),
 +                      GET_KEY_NAME(keymap_left),
 +                      GET_KEY_NAME(keymap_right),
 +                      GET_KEY_NAME(keymap_jump),
++                      GET_KEY_NAME(keymap_dig),
++                      GET_KEY_NAME(keymap_place),
 +                      GET_KEY_NAME(keymap_sneak),
 +                      GET_KEY_NAME(keymap_drop),
 +                      GET_KEY_NAME(keymap_inventory),
 +                      GET_KEY_NAME(keymap_enderchest),
 +                      GET_KEY_NAME(keymap_chat),
 +                      GET_KEY_NAME(keymap_toggle_killaura),
 +                      GET_KEY_NAME(keymap_toggle_freecam),
 +                      GET_KEY_NAME(keymap_toggle_scaffold),
 +                      GET_KEY_NAME(keymap_toggle_next_item)
 +                      );
  
        std::string control_text = std::string(control_text_buf);
        str_formspec_escape(control_text);
index 51accc67903e06efb28f4440ac75182dab8d1976,d041532717640a8c1f4109377ca5ee0f297b9d82..26117ab868eb7a29e9bcdf9228b8caf08b32d4f2
@@@ -94,847 -42,6 +94,853 @@@ struct CameraOrientation 
        f32 camera_pitch;  // "up/down"
  };
  
-               m_player_step_timer(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;
 +                      }
 +
 +                      if (fields.find("quit") != fields.end()) {
 +                              return;
 +                      }
 +
 +                      if (fields.find("btn_continue") != fields.end()) {
 +                              return;
 +                      }
 +              }
 +
 +              if (m_formname == "MT_DEATH_SCREEN") {
 +                      assert(m_client != 0);
 +                      m_client->sendRespawn();
 +                      return;
 +              }
 +
 +              if (m_client && 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),
-       CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
-       CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags;
++              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;
-               m_normal_texture("normalTexture"),
-               m_texture_flags("textureFlags"),
 +      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"),
-               SamplerLayer_t base_tex = 0,
-                               normal_tex = 1,
-                               flags_tex = 2;
 +              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);
 +      }
 +
 +      virtual void onSetConstants(video::IMaterialRendererServices *services,
 +                      bool is_highlevel)
 +      {
 +              if (!is_highlevel)
 +                      return;
 +
 +              // 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);
 +
-               m_normal_texture.set(&normal_tex, services);
-               m_texture_flags.set(&flags_tex, services);
++              SamplerLayer_t base_tex = 0;
 +              m_base_texture.set(&base_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()
 +      {
 +              GameGlobalShaderConstantSetter *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
 +
 +/****************************************************************************
-       bool ldown_for_dig;
 + ****************************************************************************/
 +
 +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;
-       float repeat_rightclick_timer;
++      bool punching;
++      bool btn_down_for_dig;
 +      bool dig_instantly;
 +      bool digging_blocked;
 +      bool left_punch;
 +      bool reset_jump_timer;
 +      float nodig_delay_timer;
 +      float dig_time;
 +      float dig_time_complete;
-       bool random_input;
++      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 *);
 +};
 +
 +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();
 +
 +      inline bool isKeyDown(GameKeyType k)
 +      {
 +              return input->isKeyDown(k);
 +      }
 +      inline bool wasKeyDown(GameKeyType k)
 +      {
 +              return input->wasKeyDown(k);
 +      }
++      inline bool wasKeyPressed(GameKeyType k)
++      {
++              return input->wasKeyPressed(k);
++      }
++      inline bool wasKeyReleased(GameKeyType k)
++      {
++              return input->wasKeyReleased(k);
++      }
 +
 +#ifdef __ANDROID__
 +      void handleAndroidChatInput();
 +#endif
 +
 +      struct Flags {
 +              bool force_fog_off = false;
 +              bool disable_camera_update = false;
 +      };
 +
 +      void showDeathFormspec();
 +      void showPauseMenu();
 +
 +      // 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);
 +      static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
 +
 +      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;
 +
 +      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;
 +
-       f32  m_repeat_right_click_time;
 +      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
index e006affb2f2c38aa4cdec0b9e4516376e869df5d,def147a822728bfae7f8d56ac5d00c51ac59ffe1..b3a7d4ba3b501e3477caa04d5a9aebdec73b8ac9
@@@ -195,10 -197,19 +197,18 @@@ public
        TouchScreenGUI *m_touchscreengui;
  #endif
  
 -private:
        // The current state of keys
        KeyList keyIsDown;
-       // Whether a key has been pressed or not
+       // Whether a key was down
        KeyList keyWasDown;
+       // Whether a key has just been pressed
+       KeyList keyWasPressed;
+       // Whether a key has just been released
+       KeyList keyWasReleased;
        // List of keys we listen for
        // TODO perhaps the type of this is not really
        // performant as KeyList is designed for few but
@@@ -224,11 -235,14 +234,16 @@@ public
        }
  
        virtual bool isKeyDown(GameKeyType k) = 0;
 +      virtual void setKeypress(const KeyPress &keyCode) = 0;
 +      virtual void unsetKeypress(const KeyPress &keyCode) = 0;
        virtual bool wasKeyDown(GameKeyType k) = 0;
+       virtual bool wasKeyPressed(GameKeyType k) = 0;
+       virtual bool wasKeyReleased(GameKeyType k) = 0;
        virtual bool cancelPressed() = 0;
  
+       virtual void clearWasKeyPressed() {}
+       virtual void clearWasKeyReleased() {}
        virtual void listenForKey(const KeyPress &keyCode) {}
        virtual void dontListenForKeys() {}
  
@@@ -393,15 -348,9 +358,17 @@@ public
        }
  
        virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
 +      virtual void setKeypress(const KeyPress &keyCode)
 +      {
 +              keydown.set(keyCode);
 +      }
 +      virtual void unsetKeypress(const KeyPress &keyCode)
 +      {
 +              keydown.unset(keyCode);
 +      }
        virtual bool wasKeyDown(GameKeyType k) { return false; }
+       virtual bool wasKeyPressed(GameKeyType k) { return false; }
+       virtual bool wasKeyReleased(GameKeyType k) { return false; }
        virtual bool cancelPressed() { return false; }
        virtual v2s32 getMousePos() { return mousepos; }
        virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 8ea1a0283d61bb17ed78ef091372c4aa5d40547a,d068ad5f782fe63c261cf64e11322cdc69c0ac84..60b095712e49a4770baae526d61ac9edca830a27
@@@ -473,9 -598,7 +598,10 @@@ void Minimap::drawMinimap(core::rect<s3
        core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
        core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
  
-       driver->setViewPort(core::rect<s32>(
-               screensize.X - size * 2 - 10, 10,
-               screensize.X - size - 10, size + 10));
++//    driver->setViewPort(core::rect<s32>(
++//            screensize.X - size * 2 - 10, 10,
++//            screensize.X - size - 10, size + 10));
+       driver->setViewPort(rect);
        driver->setTransform(video::ETS_PROJECTION, core::matrix4());
        driver->setTransform(video::ETS_VIEW, core::matrix4());
  
        driver->setViewPort(oldViewPort);
  
        // Draw player markers
-       v2s32 s_pos(screensize.X - size * 2 - 10, 10);
++//    v2s32 s_pos(screensize.X - size * 2 - 10, 10);
+       v2s32 s_pos(rect.UpperLeftCorner.X, rect.UpperLeftCorner.Y);
        core::dimension2di imgsize(data->object_marker_red->getOriginalSize());
        core::rect<s32> img_rect(0, 0, imgsize.Width, imgsize.Height);
        static const video::SColor col(255, 255, 255, 255);
index 1fad4af5277d336117d7f8eed3cd069af1d422ee,92a7137eaa7fea99388f0cf2c137d7f11cb60750..44e3ed7447a0cc5908c73562a86b07146cb31ffc
@@@ -78,84 -70,6 +78,80 @@@ void RenderingCore::draw(video::SColor 
        drawAll();
  }
  
-               std::map<v2s16, MapSector*> *sectors = map.getSectorsPtr();
-               
-               for (auto &sector_it : *sectors) {
-                       MapSector *sector = sector_it.second;
-                       MapBlockVect blocks;
-                       sector->getBlocks(blocks);
-                       for (MapBlock *block : blocks) {
-                               if (! block->mesh)
-                                       continue;
-                               for (v3s16 p : block->mesh->esp_nodes) {
-                                       v3f pos = intToFloat(p, BS) - camera_offset;
-                                       MapNode node = map.getNode(p);
-                                       std::vector<aabb3f> boxes;
-                                       node.getSelectionBoxes(client->getNodeDefManager(), &boxes, node.getNeighbors(p, &map));
-                                       video::SColor color = client->getNodeDefManager()->get(node).minimap_color;
-                               
-                                       for (aabb3f box : boxes) {
-                                               box.MinEdge += pos;
-                                               box.MaxEdge += pos;
-                                               if (draw_node_esp)
-                                                       driver->draw3DBox(box, color);
-                                               if (draw_node_tracers)
-                                                       driver->draw3DLine(eye_pos, box.getCenter(), color);
-                                       }
 +void RenderingCore::drawTracersAndESP()
 +{
 +      bool only_trace_players = g_settings->getBool("only_trace_players");
 +      
 +      ClientEnvironment &env = client->getEnv();
 +      Camera *camera = client->getCamera();
 +      
 +      v3f camera_offset = intToFloat(camera->getOffset(), BS);
 +      
 +      v3f eye_pos = (camera->getPosition() + camera->getDirection() - camera_offset);
 +      
 +      video::SMaterial material, oldmaterial;
 +      oldmaterial = driver->getMaterial2D();
 +      material.setFlag(video::EMF_LIGHTING, false);
 +      material.setFlag(video::EMF_BILINEAR_FILTER, false);
 +      material.setFlag(video::EMF_ZBUFFER, false);
 +      material.setFlag(video::EMF_ZWRITE_ENABLE, false);
 +      driver->setMaterial(material);
 +      
 +      if (draw_esp || draw_tracers) {
 +              auto allObjects = env.getAllActiveObjects();
 +
 +              for (auto &it : allObjects) {
 +                      ClientActiveObject *cao = it.second;
 +                      if (cao->isLocalPlayer() || cao->getParent())
 +                              continue;
 +                      GenericCAO *obj = dynamic_cast<GenericCAO *>(cao);
 +                      if (! obj)
 +                              continue;
 +                      if (only_trace_players && ! obj->isPlayer())
 +                              continue;
 +                      aabb3f box;
 +                      if (! obj->getSelectionBox(&box))
 +                              continue;
 +                      v3f pos = obj->getPosition() - camera_offset;
 +                      box.MinEdge += pos;
 +                      box.MaxEdge += pos;
 +                      if (draw_esp)
 +                              driver->draw3DBox(box, video::SColor(255, 255, 255, 255));
 +                      if (draw_tracers)
 +                              driver->draw3DLine(eye_pos, box.getCenter(), video::SColor(255, 255, 255, 255));
 +              }
 +      }
 +      if (draw_node_esp || draw_node_tracers) {
 +              Map &map = env.getMap();
++
++              std::vector<v3s16> positions;
++              map.listAllLoadedBlocks(positions);
++
++              for (v3s16 blockp : positions) {
++                      MapBlock *block = map.getBlockNoCreate(blockp);
++                      if (! block->mesh)
++                              continue;
++                      for (v3s16 p : block->mesh->esp_nodes) {
++                              v3f pos = intToFloat(p, BS) - camera_offset;
++                              MapNode node = map.getNode(p);
++                              std::vector<aabb3f> boxes;
++                              node.getSelectionBoxes(client->getNodeDefManager(), &boxes, node.getNeighbors(p, &map));
++                              video::SColor color = client->getNodeDefManager()->get(node).minimap_color;
++                              for (aabb3f box : boxes) {
++                                      box.MinEdge += pos;
++                                      box.MaxEdge += pos;
++                                      if (draw_node_esp)
++                                              driver->draw3DBox(box, color);
++                                      if (draw_node_tracers)
++                                              driver->draw3DLine(eye_pos, box.getCenter(), color);
 +                              }
 +                      }
 +              }
 +      }
 +      
 +      driver->setMaterial(oldmaterial);
 +}
 +
  void RenderingCore::draw3D()
  {
        smgr->drawAll();
index bfcee01f8721be32e9870a7b27696966d4486ae7,42e7fc16b43a5d108f72ab2c5dcf0464f7dc1e61..8050b533c82aed961c5f16f8aa4548f5990cad46
@@@ -52,8 -52,8 +52,8 @@@ void set_default_settings(Settings *set
        settings->setDefault("screenshot_format", "png");
        settings->setDefault("screenshot_quality", "0");
        settings->setDefault("client_unload_unused_data_timeout", "600");
-       settings->setDefault("client_mapblock_limit", "5000");
+       settings->setDefault("client_mapblock_limit", "7500");
 -      settings->setDefault("enable_build_where_you_stand", "false");
 +      settings->setDefault("enable_build_where_you_stand", "true");
        settings->setDefault("curl_timeout", "5000");
        settings->setDefault("curl_parallel_limit", "8");
        settings->setDefault("curl_file_download_timeout", "300000");
        settings->setDefault("port", "30000");
        settings->setDefault("strict_protocol_version_checking", "false");
        settings->setDefault("player_transfer_distance", "0");
-       settings->setDefault("max_simultaneous_block_sends_per_client", "40");
+       settings->setDefault("max_simultaneous_block_sends_per_client", "128");
        settings->setDefault("time_send_interval", "5");
  
 -      settings->setDefault("default_game", "minetest");
 +      settings->setDefault("default_game", "mineclone2");
        settings->setDefault("motd", "");
        settings->setDefault("max_users", "15");
        settings->setDefault("creative_mode", "false");
Simple merge
Simple merge
diff --cc src/map.cpp
index b9ab7c066cf750f3099f9a1278ba4dceed6befba,37b6e9b6b89aa37f973f93aa8678c2ae95e44c00..6d53351efeed2b1bc15ae8f773823063fff4686a
@@@ -140,6 -139,6 +139,21 @@@ MapBlock * Map::getBlockNoCreate(v3s16 
        return block;
  }
  
++void Map::listAllLoadedBlocks(std::vector<v3s16> &dst)
++{
++      for (auto &sector_it : m_sectors) {
++              MapSector *sector = sector_it.second;
++
++              MapBlockVect blocks;
++              sector->getBlocks(blocks);
++
++              for (MapBlock *block : blocks) {
++                      v3s16 p = block->getPos();
++                      dst.push_back(p);
++              }
++      }
++}
++
  bool Map::isNodeUnderground(v3s16 p)
  {
        v3s16 blockpos = getNodeBlockPos(p);
@@@ -1864,21 -1808,21 +1823,6 @@@ void ServerMap::listAllLoadableBlocks(s
                dbase_ro->listAllLoadableBlocks(dst);
  }
  
--void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
--{
--      for (auto &sector_it : m_sectors) {
--              MapSector *sector = sector_it.second;
--
--              MapBlockVect blocks;
--              sector->getBlocks(blocks);
--
--              for (MapBlock *block : blocks) {
--                      v3s16 p = block->getPos();
--                      dst.push_back(p);
--              }
--      }
--}
--
  MapDatabase *ServerMap::createDatabase(
        const std::string &name,
        const std::string &savedir,
diff --cc src/map.h
index 4d9847063066075eb575c8a6c929bfd80b63289c,3bc30c482a4634601dc863edbcf48353bc550927..0b0213ca012e703d209087c6d76cbd85743b87ed
+++ b/src/map.h
@@@ -162,7 -160,7 +160,9 @@@ public
        MapBlock * getBlockNoCreate(v3s16 p);
        // Returns NULL if not found
        MapBlock * getBlockNoCreateNoEx(v3s16 p);
--
++      
++      void listAllLoadedBlocks(std::vector<v3s16> &dst);
++      
        /* Server overrides */
        virtual MapBlock * emergeBlock(v3s16 p, bool create_blank=true)
        { return getBlockNoCreateNoEx(p); }
@@@ -394,7 -376,7 +378,6 @@@ public
  
        void save(ModifiedState save_level);
        void listAllLoadableBlocks(std::vector<v3s16> &dst);
--      void listAllLoadedBlocks(std::vector<v3s16> &dst);
  
        MapgenParams *getMapgenParams();
  
index a3f1e668d09bb85dda800e2c63c40ee11579b80a,65db02300d82939796ec7c6a23a19ce4bd11dd33..c39586f2c3eae5115c318541b01a3e1c80baf9d2
@@@ -1184,13 -1161,6 +1184,12 @@@ void Client::handleCommand_HudSetFlags(
        player->hud_flags &= ~mask;
        player->hud_flags |= flags;
  
-               player->hud_flags = HUD_FLAG_HOTBAR_VISIBLE    | HUD_FLAG_HEALTHBAR_VISIBLE |
 +      if (g_settings->getBool("hud_flags_bypass"))
-       
++              player->hud_flags = HUD_FLAG_HOTBAR_VISIBLE     | HUD_FLAG_HEALTHBAR_VISIBLE |
 +                      HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE |
 +                      HUD_FLAG_BREATHBAR_VISIBLE | HUD_FLAG_MINIMAP_VISIBLE   |
 +                      HUD_FLAG_MINIMAP_RADAR_VISIBLE;
 +
        m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
        bool m_minimap_radar_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
  
index e57a7a794cba4892e7d1ac46a34c88ab155f4e88,666e75e458e0cf5f73e8ec6561ecae09a666767b..98d143c89a15904ed8115d0d4b44e0da7133c78a
@@@ -204,9 -204,10 +204,10 @@@ with this program; if not, write to th
        PROTOCOL VERSION 39:
                Updated set_sky packet
                Adds new sun, moon and stars packets
+               Minimap modes
  */
  
 -#define LATEST_PROTOCOL_VERSION 39
 +#define LATEST_PROTOCOL_VERSION 40
  #define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION)
  
  // Server's supported network protocol range
diff --cc src/nodedef.cpp
Simple merge
diff --cc src/player.h
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge