]> git.lizzy.rs Git - minetest.git/blobdiff - src/main.cpp
added dedicated server build without irrlicht
[minetest.git] / src / main.cpp
index a2185450f0922a1b548359f11b8c7848050ec12c..b747da66aa9cdee6174211337cf4b79651bb0a6f 100644 (file)
@@ -27,30 +27,87 @@ NOTE: VBO cannot be turned on for fast-changing stuff because there
 NOTE: iostream.imbue(std::locale("C")) is very slow\r
 NOTE: Global locale is now set at initialization\r
 \r
-SUGGESTION: add a second lighting value to the MS nibble of param of\r
-       air to tell how bright the air node is when there is no sunlight.\r
-       When day changes to night, these two values can be interpolated.\r
+SUGG: Fix address to be ipv6 compatible\r
 \r
-TODO: Fix address to be ipv6 compatible\r
+FIXME: When a new sector is generated, it may change the ground level\r
+       of it's and it's neighbors border that two blocks that are\r
+          above and below each other and that are generated before and\r
+          after the sector heightmap generation (order doesn't matter),\r
+          can have a small gap between each other at the border.\r
+SUGGESTION: Use same technique for sector heightmaps as what we're\r
+            using for UnlimitedHeightmap? (getting all neighbors\r
+                       when generating)\r
+\r
+SUGG: Transfer more blocks in a single packet\r
+SUGG: A blockdata combiner class, to which blocks are added and at\r
+      destruction it sends all the stuff in as few packets as possible.\r
+\r
+SUGG: If player is on ground, mainly fetch ground-level blocks\r
+SUGG: Fetch stuff mainly from the viewing direction\r
+\r
+SUGG: Expose Connection's seqnums and ACKs to server and client.\r
+      - This enables saving many packets and making a faster connection\r
+         - This also enables server to check if client has received the\r
+           most recent block sent, for example.\r
+SUGG: Add a sane bandwidth throttling system to Connection\r
+\r
+SUGG: More fine-grained control of client's dumping of blocks from\r
+      memory\r
+         - ...What does this mean in the first place?\r
+\r
+SUGG: A map editing mode (similar to dedicated server mode)\r
+\r
+SUGG: Add a time value to the param of footstepped grass and check it\r
+      against a global timer when a block is accessed, to make old\r
+         steps fade away.\r
+\r
+SUGG: Make a copy of close-range environment on client for showing\r
+      on screen, with minimal mutexes to slow down the main loop\r
+\r
+SUGG: Make a PACKET_COMBINED which contains many subpackets. Utilize\r
+      it by sending more stuff in a single packet.\r
+         - Add a packet queue to RemoteClient, from which packets will be\r
+           combined with object data packets\r
+               - This is not exactly trivial: the object data packets are\r
+                 sometimes very big by themselves\r
+\r
+SUGG: Split MapBlockObject serialization to to-client and to-disk\r
+      - This will allow saving ages of rats on disk but not sending\r
+           them to clients\r
+\r
+SUGG: Implement lighting using VoxelManipulator\r
+      - Would it be significantly faster?\r
+\r
+FIXME: Rats somehow go underground sometimes (you can see it in water)\r
+       - Does their position get saved to a border value or something?\r
+          - Does this happen anymore?\r
+\r
+SUGG: MovingObject::move and Player::move are basically the same.\r
+      combine them.\r
+\r
+SUGG: Implement a "Fast check queue" (a queue with a map for checking\r
+      if something is already in it)\r
+      - Use it in active block queue in water flowing\r
+\r
+SUGG: Signs could be done in the same way as torches. For this, blocks\r
+      need an additional metadata field for the texts\r
+\r
+SUGG: Precalculate lighting translation table at runtime (at startup)\r
+\r
+SUGG: A version number to blocks, which increments when the block is\r
+      modified (node add/remove, water update, lighting update)\r
+         - This can then be used to make sure the most recent version of\r
+           a block has been sent to client\r
 \r
-TODO: ESC Pause mode in which the cursor is not kept at the center of window.\r
 TODO: Stop player if focus of window is taken away (go to pause mode)\r
-TODO: Optimize and fix makeFastFace or whatever it's called\r
-      - Face calculation is the source of CPU usage on the client\r
-SUGGESTION: The client will calculate and send lighting changes and\r
-  the server will randomly check some of them and kick the client out\r
-  if it fails to calculate them right.\r
-  - Actually, it could just start ignoring them and calculate them\r
-    itself.\r
-SUGGESTION: Combine MapBlock's face caches to so big pieces that VBO\r
-            gets used\r
-            - That is >500 vertices\r
+\r
+TODO: Combine MapBlock's face caches to so big pieces that VBO\r
+      gets used\r
+      - That is >500 vertices\r
 \r
 TODO: Better dungeons\r
-TODO: There should be very slight natural caves also, starting from\r
-      only a straightened-up cliff\r
+TODO: Cliffs, arcs\r
 \r
-TODO: Changing of block with mouse wheel or something\r
 TODO: Menus\r
 \r
 TODO: Mobs\r
@@ -63,8 +120,6 @@ TODO: - Keep track of the place of the mob in the last few hundreth's
                avg_rtt/2 before the moment the packet is received.\r
 TODO: - Scripting\r
 \r
-SUGGESTION: Modify client to calculate single changes asynchronously\r
-\r
 TODO: Moving players more smoothly. Calculate moving animation\r
       in a way that doesn't make the player jump to the right place\r
          immediately when the server sends a new position\r
@@ -72,36 +127,9 @@ TODO: Moving players more smoothly. Calculate moving animation
 TODO: There are some lighting-related todos and fixmes in\r
       ServerMap::emergeBlock\r
 \r
-FIXME: When a new sector is generated, it may change the ground level\r
-       of it's and it's neighbors border that two blocks that are\r
-          above and below each other and that are generated before and\r
-          after the sector heightmap generation (order doesn't matter),\r
-          can have a small gap between each other at the border.\r
-SUGGESTION: Use same technique for sector heightmaps as what we're\r
-            using for UnlimitedHeightmap? (getting all neighbors\r
-                       when generating)\r
-\r
-SUGG: Set server to automatically find a good spawning place in some\r
-      place where there is water and land.\r
-         - Map to have a getWalkableNear(p)\r
-         - Is this a good idea? It's part of the game to find a good place.\r
-\r
-TODO: Transfer more blocks in a single packet\r
-SUGG: A blockdata combiner class, to which blocks are added and at\r
-      destruction it sends all the stuff in as few packets as possible.\r
-\r
-SUGG: If player is on ground, mainly fetch ground-level blocks\r
-SUGG: Fetch stuff mainly from the viewing direction\r
-\r
-SUGG: Expose Connection's seqnums and ACKs to server and client.\r
-      - This enables saving many packets and making a faster connection\r
-         - This also enables server to check if client has received the\r
-           most recent block sent, for example.\r
-TODO: Add a sane bandwidth throttling system to Connection\r
-\r
-SUGG: More fine-grained control of client's dumping of blocks from\r
-      memory\r
-         - ...What does this mean in the first place?\r
+TODO: Proper handling of spawning place (try to find something that\r
+      is not in the middle of an ocean (some land to stand on at\r
+         least) and save it in map config.\r
 \r
 TODO: Make the amount of blocks sending to client and the total\r
          amount of blocks dynamically limited. Transferring blocks is the\r
@@ -110,12 +138,10 @@ TODO: Make the amount of blocks sending to client and the total
 \r
 TODO: Server to load starting inventory from disk\r
 \r
-TODO: PLayers to only be hidden when the client quits.\r
+TODO: Players to only be hidden when the client quits.\r
 TODO: - Players to be saved on disk, with inventory\r
 TODO: Players to be saved as text in map/players/<name>\r
 \r
-SUGG: A map editing mode (similar to dedicated server mode)\r
-\r
 TODO: Make fetching sector's blocks more efficient when rendering\r
       sectors that have very large amounts of blocks (on client)\r
 \r
@@ -126,15 +152,11 @@ Block object server side:
          - For all blocks in the buffer, objects are stepped(). This\r
            means they are active.\r
          - TODO: A global active buffer is needed for the server\r
+         - TODO: A timestamp to blocks\r
       - TODO: All blocks going in and out of the buffer are recorded.\r
-           - TODO: For outgoing blocks, timestamp is written.\r
-           - TODO: For incoming blocks, the time difference is calculated and\r
+           - TODO: For outgoing blocks, timestamp is written.\r
+           - TODO: For incoming blocks, time difference is calculated and\r
              objects are stepped according to it.\r
-TODO: A timestamp to blocks\r
-\r
-SUGG: Add a time value to the param of footstepped grass and check it\r
-      against a global timer when a block is accessed, to make old\r
-         steps fade away.\r
 \r
 TODO: Add config parameters for server's sending and generating distance\r
 \r
@@ -144,33 +166,23 @@ TODO: Copy the text of the last picked sign to inventory in creative
 TODO: Untie client network operations from framerate\r
       - Needs some input queues or something\r
 \r
-SUGG: Make a copy of close-range environment on client for showing\r
-      on screen, with minimal mutexes to slow down the main loop\r
-\r
-SUGG: Make a PACKET_COMBINED which contains many subpackets. Utilize\r
-      it by sending more stuff in a single packet.\r
-         - Add a packet queue to RemoteClient, from which packets will be\r
-           combined with object data packets\r
-               - This is not exactly trivial: the object data packets are\r
-                 sometimes very big by themselves\r
-\r
-SUGG: Split MapBlockObject serialization to to-client and to-disk\r
-      - This will allow saving ages of rats on disk but not sending\r
-           them to clients\r
-\r
 TODO: Get rid of GotSplitPacketException\r
 \r
-SUGG: Implement lighting using VoxelManipulator\r
-      - Would it be significantly faster?\r
-\r
 TODO: Check what goes wrong with caching map to disk (Kray)\r
 \r
 TODO: Remove LazyMeshUpdater. It is not used as supposed.\r
 \r
+TODO: Node cracking animation when digging\r
+      - TODO: A way to generate new textures by combining textures\r
+         - TODO: Mesh update to fetch cracked faces from the former\r
+\r
+TODO: Add server unused sector deletion settings to settings\r
+\r
+TODO: TOSERVER_LEAVE\r
+\r
 Doing now:\r
 ======================================================================\r
 \r
-\r
 ======================================================================\r
 \r
 */\r
@@ -201,6 +213,7 @@ Doing now:
 #ifdef _MSC_VER\r
 #pragma comment(lib, "Irrlicht.lib")\r
 #pragma comment(lib, "jthread.lib")\r
+#pragma comment(lib, "zlibwapi.lib")\r
 // This would get rid of the console window\r
 //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")\r
 #endif\r
@@ -218,6 +231,7 @@ Doing now:
 #include <fstream>\r
 #include <time.h>\r
 #include <jmutexautolock.h>\r
+#include <locale.h>\r
 #include "common_irrlicht.h"\r
 #include "debug.h"\r
 #include "map.h"\r
@@ -231,31 +245,37 @@ Doing now:
 #include "constants.h"\r
 #include "strfnd.h"\r
 #include "porting.h"\r
-#include <locale.h>\r
+#include "guiPauseMenu.h"\r
 \r
 IrrlichtDevice *g_device = NULL;\r
 \r
-const char *g_material_filenames[MATERIALS_COUNT] =\r
+/*const char *g_content_filenames[MATERIALS_COUNT] =\r
 {\r
        "../data/stone.png",\r
        "../data/grass.png",\r
        "../data/water.png",\r
-       "../data/light.png",\r
+       "../data/torch_on_floor.png",\r
        "../data/tree.png",\r
        "../data/leaves.png",\r
        "../data/grass_footsteps.png",\r
        "../data/mese.png",\r
-       "../data/mud.png"\r
+       "../data/mud.png",\r
+       "../data/water.png", // CONTENT_OCEAN\r
 };\r
 \r
-video::SMaterial g_materials[MATERIALS_COUNT];\r
-//video::SMaterial g_mesh_materials[3];\r
+// Material cache\r
+video::SMaterial g_materials[MATERIALS_COUNT];*/\r
+\r
+// Texture cache\r
+TextureCache g_texturecache;\r
+\r
 \r
 // All range-related stuff below is locked behind this\r
 JMutex g_range_mutex;\r
 \r
 // Blocks are viewed in this range from the player\r
 s16 g_viewing_range_nodes = 60;\r
+//s16 g_viewing_range_nodes = 0;\r
 \r
 // This is updated by the client's fetchBlocks routine\r
 //s16 g_actual_viewing_range_nodes = VIEWING_RANGE_NODES_DEFAULT;\r
@@ -281,34 +301,37 @@ Settings g_settings;
 // Sets default settings\r
 void set_default_settings()\r
 {\r
-       g_settings.set("dedicated_server", "");\r
-\r
        // Client stuff\r
-       g_settings.set("wanted_fps", "30");\r
-       g_settings.set("fps_max", "60");\r
-       g_settings.set("viewing_range_nodes_max", "300");\r
-       g_settings.set("viewing_range_nodes_min", "20");\r
-       g_settings.set("screenW", "");\r
-       g_settings.set("screenH", "");\r
-       g_settings.set("host_game", "");\r
-       g_settings.set("port", "");\r
-       g_settings.set("address", "");\r
-       g_settings.set("name", "");\r
-       g_settings.set("random_input", "false");\r
-       g_settings.set("client_delete_unused_sectors_timeout", "1200");\r
+       g_settings.setDefault("wanted_fps", "30");\r
+       g_settings.setDefault("fps_max", "60");\r
+       g_settings.setDefault("viewing_range_nodes_max", "300");\r
+       g_settings.setDefault("viewing_range_nodes_min", "35");\r
+       g_settings.setDefault("screenW", "");\r
+       g_settings.setDefault("screenH", "");\r
+       g_settings.setDefault("host_game", "");\r
+       g_settings.setDefault("port", "");\r
+       g_settings.setDefault("address", "");\r
+       g_settings.setDefault("name", "");\r
+       g_settings.setDefault("random_input", "false");\r
+       g_settings.setDefault("client_delete_unused_sectors_timeout", "1200");\r
+       g_settings.setDefault("enable_fog", "true");\r
 \r
        // Server stuff\r
-       g_settings.set("creative_mode", "false");\r
-       g_settings.set("heightmap_blocksize", "128");\r
-       g_settings.set("height_randmax", "constant 70.0");\r
-       g_settings.set("height_randfactor", "constant 0.6");\r
-       g_settings.set("height_base", "linear 0 35 0");\r
-       g_settings.set("plants_amount", "1.0");\r
-       g_settings.set("ravines_amount", "1.0");\r
-       g_settings.set("objectdata_interval", "0.2");\r
-       g_settings.set("active_object_range", "2");\r
-       g_settings.set("max_simultaneous_block_sends_per_client", "1");\r
-       g_settings.set("max_simultaneous_block_sends_server_total", "4");\r
+       g_settings.setDefault("creative_mode", "false");\r
+       g_settings.setDefault("heightmap_blocksize", "32");\r
+       g_settings.setDefault("height_randmax", "constant 50.0");\r
+       g_settings.setDefault("height_randfactor", "constant 0.6");\r
+       g_settings.setDefault("height_base", "linear 0 0 0");\r
+       g_settings.setDefault("plants_amount", "1.0");\r
+       g_settings.setDefault("ravines_amount", "1.0");\r
+       g_settings.setDefault("objectdata_interval", "0.2");\r
+       g_settings.setDefault("active_object_range", "2");\r
+       g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");\r
+       g_settings.setDefault("max_simultaneous_block_sends_server_total", "4");\r
+       g_settings.setDefault("disable_water_climb", "true");\r
+       g_settings.setDefault("endless_water", "true");\r
+       g_settings.setDefault("max_block_send_distance", "5");\r
+       g_settings.setDefault("max_block_generate_distance", "4");\r
 }\r
 \r
 /*\r
@@ -404,6 +427,7 @@ class MyEventReceiver : public IEventReceiver
                                \r
                                if(event.KeyInput.Key == irr::KEY_ESCAPE)\r
                                {\r
+                                       //TODO: Not used anymore?\r
                                        if(g_game_focused == true)\r
                                        {\r
                                                dstream<<DTIME<<"ESC pressed"<<std::endl;\r
@@ -458,6 +482,10 @@ class MyEventReceiver : public IEventReceiver
 \r
                if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)\r
                {\r
+                       left_active = event.MouseInput.isLeftPressed();\r
+                       middle_active = event.MouseInput.isMiddlePressed();\r
+                       right_active = event.MouseInput.isRightPressed();\r
+\r
                        if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
                        {\r
                                leftclicked = true;\r
@@ -466,6 +494,14 @@ class MyEventReceiver : public IEventReceiver
                        {\r
                                rightclicked = true;\r
                        }\r
+                       if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
+                       {\r
+                               leftreleased = true;\r
+                       }\r
+                       if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)\r
+                       {\r
+                               rightreleased = true;\r
+                       }\r
                        if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)\r
                        {\r
                                /*dstream<<"event.MouseInput.Wheel="\r
@@ -502,10 +538,23 @@ class MyEventReceiver : public IEventReceiver
                                keyIsDown[i] = false;\r
                leftclicked = false;\r
                rightclicked = false;\r
+               leftreleased = false;\r
+               rightreleased = false;\r
+\r
+               left_active = false;\r
+               middle_active = false;\r
+               right_active = false;\r
        }\r
 \r
        bool leftclicked;\r
        bool rightclicked;\r
+       bool leftreleased;\r
+       bool rightreleased;\r
+\r
+       bool left_active;\r
+       bool middle_active;\r
+       bool right_active;\r
+\r
 private:\r
        // We use this array to store the current state of each key\r
        bool keyIsDown[KEY_KEY_CODES_COUNT];\r
@@ -522,13 +571,24 @@ class InputHandler
        virtual ~InputHandler()\r
        {\r
        }\r
+\r
        virtual bool isKeyDown(EKEY_CODE keyCode) = 0;\r
+\r
        virtual v2s32 getMousePos() = 0;\r
        virtual void setMousePos(s32 x, s32 y) = 0;\r
+\r
+       virtual bool getLeftState() = 0;\r
+       virtual bool getRightState() = 0;\r
+\r
        virtual bool getLeftClicked() = 0;\r
        virtual bool getRightClicked() = 0;\r
        virtual void resetLeftClicked() = 0;\r
        virtual void resetRightClicked() = 0;\r
+\r
+       virtual bool getLeftReleased() = 0;\r
+       virtual bool getRightReleased() = 0;\r
+       virtual void resetLeftReleased() = 0;\r
+       virtual void resetRightReleased() = 0;\r
        \r
        virtual void step(float dtime) {};\r
 \r
@@ -569,6 +629,15 @@ class RealInputHandler : public InputHandler
                m_device->getCursorControl()->setPosition(x, y);\r
        }\r
 \r
+       virtual bool getLeftState()\r
+       {\r
+               return m_receiver->left_active;\r
+       }\r
+       virtual bool getRightState()\r
+       {\r
+               return m_receiver->right_active;\r
+       }\r
+       \r
        virtual bool getLeftClicked()\r
        {\r
                if(g_game_focused == false)\r
@@ -590,6 +659,27 @@ class RealInputHandler : public InputHandler
                m_receiver->rightclicked = false;\r
        }\r
 \r
+       virtual bool getLeftReleased()\r
+       {\r
+               if(g_game_focused == false)\r
+                       return false;\r
+               return m_receiver->leftreleased;\r
+       }\r
+       virtual bool getRightReleased()\r
+       {\r
+               if(g_game_focused == false)\r
+                       return false;\r
+               return m_receiver->rightreleased;\r
+       }\r
+       virtual void resetLeftReleased()\r
+       {\r
+               m_receiver->leftreleased = false;\r
+       }\r
+       virtual void resetRightReleased()\r
+       {\r
+               m_receiver->rightreleased = false;\r
+       }\r
+\r
        void clear()\r
        {\r
                resetRightClicked();\r
@@ -623,6 +713,15 @@ class RandomInputHandler : public InputHandler
                mousepos = v2s32(x,y);\r
        }\r
 \r
+       virtual bool getLeftState()\r
+       {\r
+               return false;\r
+       }\r
+       virtual bool getRightState()\r
+       {\r
+               return false;\r
+       }\r
+\r
        virtual bool getLeftClicked()\r
        {\r
                return leftclicked;\r
@@ -640,6 +739,21 @@ class RandomInputHandler : public InputHandler
                rightclicked = false;\r
        }\r
 \r
+       virtual bool getLeftReleased()\r
+       {\r
+               return false;\r
+       }\r
+       virtual bool getRightReleased()\r
+       {\r
+               return false;\r
+       }\r
+       virtual void resetLeftReleased()\r
+       {\r
+       }\r
+       virtual void resetRightReleased()\r
+       {\r
+       }\r
+\r
        virtual void step(float dtime)\r
        {\r
                {\r
@@ -648,7 +762,7 @@ class RandomInputHandler : public InputHandler
                        if(counter1 < 0.0)\r
                        {\r
                                counter1 = 0.1*Rand(1,10);\r
-                               /*if(g_selected_material < USEFUL_MATERIAL_COUNT-1)\r
+                               /*if(g_selected_material < USEFUL_CONTENT_COUNT-1)\r
                                        g_selected_material++;\r
                                else\r
                                        g_selected_material = 0;*/\r
@@ -746,7 +860,8 @@ void updateViewingRange(f32 frametime, Client *client)
        \r
        // Initialize to the target value\r
        static float frametime_avg = 1.0/wanted_fps;\r
-       frametime_avg = frametime_avg * 0.9 + frametime * 0.1;\r
+       //frametime_avg = frametime_avg * 0.9 + frametime * 0.1;\r
+       frametime_avg = frametime_avg * 0.7 + frametime * 0.3;\r
 \r
        static f32 counter = 0;\r
        if(counter > 0){\r
@@ -764,10 +879,16 @@ void updateViewingRange(f32 frametime, Client *client)
 \r
        float fraction = sqrt(frametime_avg / frametime_wanted);\r
 \r
+       /*float fraction = sqrt(frametime_avg / frametime_wanted) / 2.0\r
+                       + frametime_avg / frametime_wanted / 2.0;*/\r
+       \r
+       //float fraction = frametime_avg / frametime_wanted;\r
+\r
        static bool fraction_is_good = false;\r
        \r
        float fraction_good_threshold = 0.1;\r
-       float fraction_bad_threshold = 0.25;\r
+       //float fraction_bad_threshold = 0.25;\r
+       float fraction_bad_threshold = 0.1;\r
        float fraction_limit;\r
        // Use high limit if fraction is good AND the fraction would\r
        // lower the range. We want to keep the range fairly high.\r
@@ -931,6 +1052,55 @@ int main(int argc, char *argv[])
        try\r
        {\r
        \r
+       /*\r
+               Parse command line\r
+       */\r
+       \r
+       // List all allowed options\r
+       core::map<std::string, ValueSpec> allowed_options;\r
+       allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));\r
+       allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,\r
+                       "Run server directly"));\r
+       allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,\r
+                       "Load configuration from specified file"));\r
+       allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));\r
+       allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));\r
+       allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));\r
+       allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
+       allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
+\r
+       Settings cmd_args;\r
+       \r
+       bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);\r
+\r
+       if(ret == false || cmd_args.getFlag("help"))\r
+       {\r
+               dstream<<"Allowed options:"<<std::endl;\r
+               for(core::map<std::string, ValueSpec>::Iterator\r
+                               i = allowed_options.getIterator();\r
+                               i.atEnd() == false; i++)\r
+               {\r
+                       dstream<<"  --"<<i.getNode()->getKey();\r
+                       if(i.getNode()->getValue().type == VALUETYPE_FLAG)\r
+                       {\r
+                       }\r
+                       else\r
+                       {\r
+                               dstream<<" <value>";\r
+                       }\r
+                       dstream<<std::endl;\r
+\r
+                       if(i.getNode()->getValue().help != NULL)\r
+                       {\r
+                               dstream<<"      "<<i.getNode()->getValue().help\r
+                                               <<std::endl;\r
+                       }\r
+               }\r
+\r
+               return cmd_args.getFlag("help") ? 0 : 1;\r
+       }\r
+\r
+\r
        /*\r
                Basic initialization\r
        */\r
@@ -956,23 +1126,27 @@ int main(int argc, char *argv[])
        // Initialize timestamp mutex\r
        g_timestamp_mutex.Init();\r
 \r
-       /*\r
-               Run unit tests\r
-       */\r
-       if(ENABLE_TESTS)\r
-       {\r
-               run_tests();\r
-       }\r
-       \r
        /*\r
                Initialization\r
        */\r
 \r
-       // Read config file\r
+       /*\r
+               Read config file\r
+       */\r
+       \r
+       // Path of configuration file in use\r
+       std::string configpath = "";\r
        \r
-       if(argc >= 2)\r
+       if(cmd_args.exists("config"))\r
        {\r
-               g_settings.readConfigFile(argv[1]);\r
+               bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());\r
+               if(r == false)\r
+               {\r
+                       dstream<<"Could not read configuration from \""\r
+                                       <<cmd_args.get("config")<<"\""<<std::endl;\r
+                       return 1;\r
+               }\r
+               configpath = cmd_args.get("config");\r
        }\r
        else\r
        {\r
@@ -986,13 +1160,28 @@ int main(int argc, char *argv[])
                {\r
                        bool r = g_settings.readConfigFile(filenames[i]);\r
                        if(r)\r
+                       {\r
+                               configpath = filenames[i];\r
                                break;\r
+                       }\r
                }\r
        }\r
 \r
        // Initialize random seed\r
        srand(time(0));\r
 \r
+       /*\r
+               Run unit tests\r
+       */\r
+       if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)\r
+                       || cmd_args.getFlag("enable-unittests") == true)\r
+       {\r
+               run_tests();\r
+       }\r
+       \r
+       /*\r
+               Global range mutex\r
+       */\r
        g_range_mutex.Init();\r
        assert(g_range_mutex.IsInitialized());\r
 \r
@@ -1013,18 +1202,34 @@ int main(int argc, char *argv[])
        */\r
 \r
        std::cout<<std::endl<<std::endl;\r
-       char templine[100];\r
        \r
-       // Dedicated?\r
-       bool dedicated = g_settings.getBoolAsk\r
-                       ("dedicated_server", "Dedicated server?", false);\r
-       std::cout<<"dedicated = "<<dedicated<<std::endl;\r
+       std::cout\r
+       <<"        .__               __                   __   "<<std::endl\r
+       <<"  _____ |__| ____   _____/  |_  ____   _______/  |_ "<<std::endl\r
+       <<" /     \\|  |/    \\_/ __ \\   __\\/ __ \\ /  ___/\\   __\\"<<std::endl\r
+       <<"|  Y Y  \\  |   |  \\  ___/|  | \\  ___/ \\___ \\  |  |  "<<std::endl\r
+       <<"|__|_|  /__|___|  /\\___  >__|  \\___  >____  > |__|  "<<std::endl\r
+       <<"      \\/        \\/     \\/          \\/     \\/        "<<std::endl\r
+       <<std::endl\r
+       <<"Now with more waterish water!"\r
+       <<std::endl;\r
+\r
+       std::cout<<std::endl;\r
+       char templine[100];\r
        \r
        // Port?\r
-       u16 port = g_settings.getU16Ask("port", "Port", 30000);\r
-       std::cout<<"-> "<<port<<std::endl;\r
+       u16 port = 30000;\r
+       if(cmd_args.exists("port"))\r
+       {\r
+               port = cmd_args.getU16("port");\r
+       }\r
+       else\r
+       {\r
+               port = g_settings.getU16Ask("port", "Port", 30000);\r
+               std::cout<<"-> "<<port<<std::endl;\r
+       }\r
        \r
-       if(dedicated)\r
+       if(cmd_args.getFlag("server"))\r
        {\r
                DSTACK("Dedicated server branch");\r
                \r
@@ -1072,14 +1277,18 @@ int main(int argc, char *argv[])
        bool hosting = false;\r
        char connect_name[100] = "";\r
 \r
-       std::cout<<"Address to connect to [empty = host a game]: ";\r
-       if(g_settings.get("address") != "" && is_yes(g_settings.get("host_game")) == false)\r
+       if(cmd_args.exists("address"))\r
+       {\r
+               snprintf(connect_name, 100, "%s", cmd_args.get("address").c_str());\r
+       }\r
+       else if(g_settings.get("address") != "" && is_yes(g_settings.get("host_game")) == false)\r
        {\r
                std::cout<<g_settings.get("address")<<std::endl;\r
                snprintf(connect_name, 100, "%s", g_settings.get("address").c_str());\r
        }\r
        else\r
        {\r
+               std::cout<<"Address to connect to [empty = host a game]: ";\r
                std::cin.getline(connect_name, 100);\r
        }\r
        \r
@@ -1089,9 +1298,9 @@ int main(int argc, char *argv[])
        }\r
        \r
        if(hosting)\r
-               std::cout<<"-> hosting"<<std::endl;\r
+               std::cout<<"> Hosting game"<<std::endl;\r
        else\r
-               std::cout<<"-> "<<connect_name<<std::endl;\r
+               std::cout<<"> Connecting to "<<connect_name<<std::endl;\r
        \r
        char playername[PLAYERNAME_SIZE] = "";\r
        if(g_settings.get("name") != "")\r
@@ -1202,7 +1411,9 @@ int main(int argc, char *argv[])
        \r
        device->setResizable(true);\r
 \r
-       if(g_settings.getBool("random_input"))\r
+       bool random_input = g_settings.getBool("random_input")\r
+                       || cmd_args.getFlag("random-input");\r
+       if(random_input)\r
                g_input = new RandomInputHandler();\r
        else\r
                g_input = new RealInputHandler(device, &receiver);\r
@@ -1219,6 +1430,9 @@ int main(int argc, char *argv[])
        //driver->setMinHardwareBufferVertexCount(1);\r
 \r
        scene::ISceneManager* smgr = device->getSceneManager();\r
+       \r
+       // Pause menu\r
+       guiPauseMenu pauseMenu(device, &receiver);\r
 \r
        gui::IGUIEnvironment* guienv = device->getGUIEnvironment();\r
        gui::IGUISkin* skin = guienv->getSkin();\r
@@ -1250,49 +1464,34 @@ int main(int argc, char *argv[])
        driver->endScene();\r
 \r
        /*\r
-               Initialize material array\r
+               Preload some random textures that are used in threads\r
        */\r
-\r
-       //video::SMaterial g_materials[MATERIALS_COUNT];\r
-       for(u16 i=0; i<MATERIALS_COUNT; i++)\r
+       \r
+       g_texturecache.set("torch", driver->getTexture("../data/torch.png"));\r
+       g_texturecache.set("torch_on_floor", driver->getTexture("../data/torch_on_floor.png"));\r
+       g_texturecache.set("torch_on_ceiling", driver->getTexture("../data/torch_on_ceiling.png"));\r
+       \r
+       /*\r
+               Load tile textures\r
+       */\r
+       for(s32 i=0; i<TILES_COUNT; i++)\r
        {\r
-               g_materials[i].Lighting = false;\r
-               g_materials[i].BackfaceCulling = false;\r
-\r
-               const char *filename = g_material_filenames[i];\r
-               if(filename != NULL){\r
-                       video::ITexture *t = driver->getTexture(filename);\r
-                       if(t == NULL){\r
-                               std::cout<<DTIME<<"Texture could not be loaded: \""\r
-                                               <<filename<<"\""<<std::endl;\r
-                               return 1;\r
-                       }\r
-                       g_materials[i].setTexture(0, driver->getTexture(filename));\r
-               }\r
-               //g_materials[i].setFlag(video::EMF_TEXTURE_WRAP, video::ETC_REPEAT);\r
-               g_materials[i].setFlag(video::EMF_BILINEAR_FILTER, false);\r
-               //g_materials[i].setFlag(video::EMF_ANISOTROPIC_FILTER, false);\r
-               //g_materials[i].setFlag(video::EMF_FOG_ENABLE, true);\r
-               if(i == MATERIAL_WATER)\r
-               {\r
-                       g_materials[i].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;\r
-                       //g_materials[i].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;\r
-               }\r
+               if(g_tile_texture_names[i] == NULL)\r
+                       continue;\r
+               std::string name = g_tile_texture_names[i];\r
+               std::string filename;\r
+               filename += "../data/";\r
+               filename += name;\r
+               filename += ".png";\r
+               g_texturecache.set(name, driver->getTexture(filename.c_str()));\r
        }\r
 \r
-       /*g_mesh_materials[0].setTexture(0, driver->getTexture("../data/water.png"));\r
-       g_mesh_materials[1].setTexture(0, driver->getTexture("../data/grass.png"));\r
-       g_mesh_materials[2].setTexture(0, driver->getTexture("../data/stone.png"));\r
-       for(u32 i=0; i<3; i++)\r
-       {\r
-               g_mesh_materials[i].Lighting = false;\r
-               g_mesh_materials[i].BackfaceCulling = false;\r
-               g_mesh_materials[i].setFlag(video::EMF_BILINEAR_FILTER, false);\r
-               g_mesh_materials[i].setFlag(video::EMF_FOG_ENABLE, true);\r
-       }*/\r
+       tile_materials_preload(g_texturecache);\r
 \r
-       // Make a scope here for the client so that it gets removed\r
-       // before the irrlicht device\r
+       /*\r
+               Make a scope here for the client so that it gets removed\r
+               before the irrlicht device\r
+       */\r
        {\r
 \r
        std::cout<<DTIME<<"Creating server and client"<<std::endl;\r
@@ -1310,10 +1509,10 @@ int main(int argc, char *argv[])
                Create client\r
        */\r
 \r
-       // TODO: Get rid of the g_materials parameter or it's globalness\r
-       Client client(device, g_materials,\r
-                       g_settings.getFloat("client_delete_unused_sectors_timeout"),\r
-                       playername);\r
+       Client client(device, playername,\r
+                       g_range_mutex,\r
+                       g_viewing_range_nodes,\r
+                       g_viewing_range_all);\r
        \r
        Address connect_address(0,0,0,0, port);\r
        try{\r
@@ -1343,6 +1542,18 @@ int main(int argc, char *argv[])
                std::cout<<DTIME<<"Timed out."<<std::endl;\r
                return 0;\r
        }\r
+\r
+       /*\r
+               Create skybox\r
+       */\r
+       /*scene::ISceneNode* skybox;\r
+       skybox = smgr->addSkyBoxSceneNode(\r
+               driver->getTexture("../data/skybox2.png"),\r
+               driver->getTexture("../data/skybox3.png"),\r
+               driver->getTexture("../data/skybox1.png"),\r
+               driver->getTexture("../data/skybox1.png"),\r
+               driver->getTexture("../data/skybox1.png"),\r
+               driver->getTexture("../data/skybox1.png"));*/\r
        \r
        /*\r
                Create the camera node\r
@@ -1365,26 +1576,17 @@ int main(int argc, char *argv[])
        // Just so big a value that everything rendered is visible\r
        camera->setFarValue(100000*BS);\r
 \r
-       /*//f32 range = BS*HEIGHTMAP_RANGE_NODES*0.9;\r
-       f32 range = BS*HEIGHTMAP_RANGE_NODES*0.9;\r
-       \r
-       camera->setFarValue(range);\r
-       \r
-       driver->setFog(\r
-               skycolor,\r
-               video::EFT_FOG_LINEAR,\r
-               range*0.8,\r
-               range,\r
-               0.01,\r
-               false,\r
-               false\r
-               );*/\r
-       \r
        f32 camera_yaw = 0; // "right/left"\r
        f32 camera_pitch = 0; // "up/down"\r
+\r
+       /*\r
+               Move into game\r
+       */\r
        \r
        gui_loadingtext->remove();\r
 \r
+       pauseMenu.setVisible(true);\r
+\r
        /*\r
                Add some gui stuff\r
        */\r
@@ -1392,12 +1594,12 @@ int main(int argc, char *argv[])
        // First line of debug text\r
        gui::IGUIStaticText *guitext = guienv->addStaticText(\r
                        L"Minetest-c55",\r
-                       core::rect<s32>(5, 5, 5+600, 5+textsize.Y),\r
+                       core::rect<s32>(5, 5, 795, 5+textsize.Y),\r
                        false, false);\r
        // Second line of debug text\r
        gui::IGUIStaticText *guitext2 = guienv->addStaticText(\r
                        L"",\r
-                       core::rect<s32>(5, 5+(textsize.Y+5)*1, 5+600, (5+textsize.Y)*2),\r
+                       core::rect<s32>(5, 5+(textsize.Y+5)*1, 795, (5+textsize.Y)*2),\r
                        false, false);\r
        \r
        // At the middle of the screen\r
@@ -1417,6 +1619,7 @@ int main(int argc, char *argv[])
                Some statistics are collected in these\r
        */\r
        u32 drawtime = 0;\r
+       u32 beginscenetime = 0;\r
        u32 scenetime = 0;\r
        u32 endscenetime = 0;\r
 \r
@@ -1454,6 +1657,11 @@ int main(int argc, char *argv[])
        //gui::IGUIWindow* input_window = NULL;\r
        gui::IGUIStaticText* input_guitext = NULL;\r
 \r
+       /*\r
+               Digging animation\r
+       */\r
+       //f32 \r
+\r
        /*\r
                Main loop\r
        */\r
@@ -1467,6 +1675,12 @@ int main(int argc, char *argv[])
 \r
        while(device->run())\r
        {\r
+               /*\r
+                       Random calculations\r
+               */\r
+               v2u32 screensize = driver->getScreenSize();\r
+               core::vector2d<s32> displaycenter(screensize.X/2,screensize.Y/2);\r
+\r
                // Hilight boxes collected during the loop and displayed\r
                core::list< core::aabbox3d<f32> > hilightboxes;\r
                \r
@@ -1619,10 +1833,10 @@ int main(int argc, char *argv[])
                /*\r
                        Special keys\r
                */\r
-               if(g_esc_pressed)\r
+               /*if(g_esc_pressed)\r
                {\r
                        break;\r
-               }\r
+               }*/\r
 \r
                /*\r
                        Player speed control\r
@@ -1682,24 +1896,26 @@ int main(int argc, char *argv[])
                        Mouse and camera control\r
                */\r
                \r
-               if(device->isWindowActive() && g_game_focused)\r
+               if((device->isWindowActive() && g_game_focused && !pauseMenu.isVisible())\r
+                               || random_input)\r
                {\r
-                       device->getCursorControl()->setVisible(false);\r
+                       if(!random_input)\r
+                               device->getCursorControl()->setVisible(false);\r
 \r
                        if(first_loop_after_window_activation){\r
                                //std::cout<<"window active, first loop"<<std::endl;\r
                                first_loop_after_window_activation = false;\r
                        }\r
                        else{\r
-                               s32 dx = g_input->getMousePos().X - 320;\r
-                               s32 dy = g_input->getMousePos().Y - 240;\r
+                               s32 dx = g_input->getMousePos().X - displaycenter.X;\r
+                               s32 dy = g_input->getMousePos().Y - displaycenter.Y;\r
                                //std::cout<<"window active, pos difference "<<dx<<","<<dy<<std::endl;\r
                                camera_yaw -= dx*0.2;\r
                                camera_pitch += dy*0.2;\r
                                if(camera_pitch < -89.5) camera_pitch = -89.5;\r
                                if(camera_pitch > 89.5) camera_pitch = 89.5;\r
                        }\r
-                       g_input->setMousePos(320, 240);\r
+                       g_input->setMousePos(displaycenter.X, displaycenter.Y);\r
                }\r
                else{\r
                        device->getCursorControl()->setVisible(true);\r
@@ -1775,7 +1991,7 @@ int main(int argc, char *argv[])
                                if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)\r
                                {\r
                                        dstream<<"Sign object right-clicked"<<std::endl;\r
-\r
+                                       \r
                                        unFocusGame();\r
 \r
                                        input_guitext = guienv->addStaticText(L"",\r
@@ -1786,8 +2002,17 @@ int main(int argc, char *argv[])
 \r
                                        input_guitext->setDrawBackground(true);\r
 \r
-                                       g_text_buffer = L"";\r
-                                       g_text_buffer_accepted = false;\r
+                                       if(random_input)\r
+                                       {\r
+                                               g_text_buffer = L"ASD LOL 8)";\r
+                                               g_text_buffer_accepted = true;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               g_text_buffer = L"";\r
+                                               g_text_buffer_accepted = false;\r
+                                       }\r
+\r
                                        textbuf_dest = new TextDestSign(\r
                                                        selected_object->getBlock()->getPos(),\r
                                                        selected_object->getId(),\r
@@ -1805,6 +2030,10 @@ int main(int argc, char *argv[])
                }\r
                else // selected_object == NULL\r
                {\r
+\r
+               /*\r
+                       Find out which node we are pointing at\r
+               */\r
                \r
                bool nodefound = false;\r
                v3s16 nodepos;\r
@@ -1825,15 +2054,19 @@ int main(int argc, char *argv[])
                s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);\r
                s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);\r
                \r
-               for(s16 y = ystart; y <= yend; y++){\r
-               for(s16 z = zstart; z <= zend; z++){\r
+               for(s16 y = ystart; y <= yend; y++)\r
+               for(s16 z = zstart; z <= zend; z++)\r
                for(s16 x = xstart; x <= xend; x++)\r
                {\r
-                       try{\r
-                               if(client.getNode(v3s16(x,y,z)).d == MATERIAL_AIR){\r
+                       MapNode n;\r
+                       try\r
+                       {\r
+                               n = client.getNode(v3s16(x,y,z));\r
+                               if(content_pointable(n.d) == false)\r
                                        continue;\r
-                               }\r
-                       }catch(InvalidPositionException &e){\r
+                       }\r
+                       catch(InvalidPositionException &e)\r
+                       {\r
                                continue;\r
                        }\r
 \r
@@ -1842,55 +2075,113 @@ int main(int argc, char *argv[])
                        \r
                        f32 d = 0.01;\r
                        \r
-                       v3s16 directions[6] = {\r
+                       v3s16 dirs[6] = {\r
                                v3s16(0,0,1), // back\r
                                v3s16(0,1,0), // top\r
                                v3s16(1,0,0), // right\r
-                               v3s16(0,0,-1),\r
-                               v3s16(0,-1,0),\r
-                               v3s16(-1,0,0),\r
+                               v3s16(0,0,-1), // front\r
+                               v3s16(0,-1,0), // bottom\r
+                               v3s16(-1,0,0), // left\r
                        };\r
+                       \r
+                       /*\r
+                               Meta-objects\r
+                       */\r
+                       if(n.d == CONTENT_TORCH)\r
+                       {\r
+                               v3s16 dir = unpackDir(n.dir);\r
+                               v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
+                               dir_f *= BS/2 - BS/6 - BS/20;\r
+                               v3f cpf = npf + dir_f;\r
+                               f32 distance = (cpf - camera_position).getLength();\r
 \r
-                       for(u16 i=0; i<6; i++){\r
-                       //{u16 i=3;\r
-                               v3f dir_f = v3f(directions[i].X,\r
-                                               directions[i].Y, directions[i].Z);\r
-                               v3f centerpoint = npf + dir_f * BS/2;\r
-                               f32 distance =\r
-                                               (centerpoint - camera_position).getLength();\r
+                               core::aabbox3d<f32> box;\r
                                \r
-                               if(distance < mindistance){\r
-                                       //std::cout<<DTIME<<"for centerpoint=("<<centerpoint.X<<","<<centerpoint.Y<<","<<centerpoint.Z<<"): distance < mindistance"<<std::endl;\r
-                                       //std::cout<<DTIME<<"npf=("<<npf.X<<","<<npf.Y<<","<<npf.Z<<")"<<std::endl;\r
-                                       core::CMatrix4<f32> m;\r
-                                       m.buildRotateFromTo(v3f(0,0,1), dir_f);\r
-\r
-                                       // This is the back face\r
-                                       v3f corners[2] = {\r
-                                               v3f(BS/2, BS/2, BS/2),\r
-                                               v3f(-BS/2, -BS/2, BS/2+d)\r
-                                       };\r
-                                       \r
-                                       for(u16 j=0; j<2; j++){\r
-                                               m.rotateVect(corners[j]);\r
-                                               corners[j] += npf;\r
-                                               //std::cout<<DTIME<<"box corners["<<j<<"]: ("<<corners[j].X<<","<<corners[j].Y<<","<<corners[j].Z<<")"<<std::endl;\r
-                                       }\r
-\r
-                                       //core::aabbox3d<f32> facebox(corners[0],corners[1]);\r
-                                       core::aabbox3d<f32> facebox(corners[0]);\r
-                                       facebox.addInternalPoint(corners[1]);\r
+                               // bottom\r
+                               if(dir == v3s16(0,-1,0))\r
+                               {\r
+                                       box = core::aabbox3d<f32>(\r
+                                               npf - v3f(BS/6, BS/2, BS/6),\r
+                                               npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)\r
+                                       );\r
+                               }\r
+                               // top\r
+                               else if(dir == v3s16(0,1,0))\r
+                               {\r
+                                       box = core::aabbox3d<f32>(\r
+                                               npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),\r
+                                               npf + v3f(BS/6, BS/2, BS/6)\r
+                                       );\r
+                               }\r
+                               // side\r
+                               else\r
+                               {\r
+                                       box = core::aabbox3d<f32>(\r
+                                               cpf - v3f(BS/6, BS/3, BS/6),\r
+                                               cpf + v3f(BS/6, BS/3, BS/6)\r
+                                       );\r
+                               }\r
 \r
-                                       if(facebox.intersectsWithLine(shootline)){\r
+                               if(distance < mindistance)\r
+                               {\r
+                                       if(box.intersectsWithLine(shootline))\r
+                                       {\r
                                                nodefound = true;\r
                                                nodepos = np;\r
-                                               neighbourpos = np + directions[i];\r
+                                               neighbourpos = np;\r
                                                mindistance = distance;\r
-                                               nodefacebox = facebox;\r
+                                               nodefacebox = box;\r
                                        }\r
                                }\r
                        }\r
-               }}}\r
+                       /*\r
+                               Regular blocks\r
+                       */\r
+                       else\r
+                       {\r
+                               for(u16 i=0; i<6; i++)\r
+                               {\r
+                                       v3f dir_f = v3f(dirs[i].X,\r
+                                                       dirs[i].Y, dirs[i].Z);\r
+                                       v3f centerpoint = npf + dir_f * BS/2;\r
+                                       f32 distance =\r
+                                                       (centerpoint - camera_position).getLength();\r
+                                       \r
+                                       if(distance < mindistance)\r
+                                       {\r
+                                               core::CMatrix4<f32> m;\r
+                                               m.buildRotateFromTo(v3f(0,0,1), dir_f);\r
+\r
+                                               // This is the back face\r
+                                               v3f corners[2] = {\r
+                                                       v3f(BS/2, BS/2, BS/2),\r
+                                                       v3f(-BS/2, -BS/2, BS/2+d)\r
+                                               };\r
+                                               \r
+                                               for(u16 j=0; j<2; j++)\r
+                                               {\r
+                                                       m.rotateVect(corners[j]);\r
+                                                       corners[j] += npf;\r
+                                               }\r
+\r
+                                               core::aabbox3d<f32> facebox(corners[0]);\r
+                                               facebox.addInternalPoint(corners[1]);\r
+\r
+                                               if(facebox.intersectsWithLine(shootline))\r
+                                               {\r
+                                                       nodefound = true;\r
+                                                       nodepos = np;\r
+                                                       neighbourpos = np + dirs[i];\r
+                                                       mindistance = distance;\r
+                                                       nodefacebox = facebox;\r
+                                               }\r
+                                       } // if distance < mindistance\r
+                               } // for dirs\r
+                       } // regular block\r
+               } // for coords\r
+\r
+               /*static v3s16 oldnodepos;\r
+               static bool oldnodefound = false;*/\r
 \r
                if(nodefound)\r
                {\r
@@ -1902,49 +2193,108 @@ int main(int argc, char *argv[])
                        if(nodepos != nodepos_old){\r
                                std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","\r
                                                <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;\r
-                               nodepos_old = nodepos;\r
-\r
-                               /*wchar_t positiontext[20];\r
-                               swprintf(positiontext, 20, L"(%i,%i,%i)",\r
-                                               nodepos.X, nodepos.Y, nodepos.Z);\r
-                               positiontextgui->setText(positiontext);*/\r
                        }\r
 \r
                        hilightboxes.push_back(nodefacebox);\r
                        \r
-                       if(g_input->getLeftClicked())\r
+                       //if(g_input->getLeftClicked())\r
+                       if(g_input->getLeftClicked() ||\r
+                                       (g_input->getLeftState() && nodepos != nodepos_old))\r
                        {\r
-                               //std::cout<<DTIME<<"Removing node"<<std::endl;\r
-                               //client.removeNode(nodepos);\r
                                std::cout<<DTIME<<"Ground left-clicked"<<std::endl;\r
-                               client.clickGround(0, nodepos, neighbourpos, g_selected_item);\r
+                               client.pressGround(0, nodepos, neighbourpos, g_selected_item);\r
                        }\r
                        if(g_input->getRightClicked())\r
+                       /*if(g_input->getRightClicked() ||\r
+                                       (g_input->getRightState() && nodepos != nodepos_old))*/\r
                        {\r
-                               //std::cout<<DTIME<<"Placing node"<<std::endl;\r
-                               //client.addNodeFromInventory(neighbourpos, g_selected_item);\r
                                std::cout<<DTIME<<"Ground right-clicked"<<std::endl;\r
-                               client.clickGround(1, nodepos, neighbourpos, g_selected_item);\r
+                               client.pressGround(1, nodepos, neighbourpos, g_selected_item);\r
                        }\r
+                       \r
+                       nodepos_old = nodepos;\r
                }\r
                else{\r
                        //std::cout<<DTIME<<"nodefound == false"<<std::endl;\r
                        //positiontextgui->setText(L"");\r
                }\r
 \r
+               /*oldnodefound = nodefound;\r
+               oldnodepos = nodepos;*/\r
+\r
                } // selected_object == NULL\r
                \r
                g_input->resetLeftClicked();\r
                g_input->resetRightClicked();\r
                \r
+               if(g_input->getLeftReleased())\r
+               {\r
+                       std::cout<<DTIME<<"Left released"<<std::endl;\r
+                       client.stopDigging();\r
+               }\r
+               if(g_input->getRightReleased())\r
+               {\r
+                       //std::cout<<DTIME<<"Right released"<<std::endl;\r
+                       // Nothing here\r
+               }\r
+               \r
+               g_input->resetLeftReleased();\r
+               g_input->resetRightReleased();\r
+               \r
                /*\r
                        Calculate stuff for drawing\r
                */\r
 \r
-               v2u32 screensize = driver->getScreenSize();\r
-               core::vector2d<s32> displaycenter(screensize.X/2,screensize.Y/2);\r
-\r
                camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y);\r
+               \r
+               // Background color is choosen based on whether the player is\r
+               // much beyond the initial ground level\r
+               /*video::SColor bgcolor;\r
+               v3s16 p0 = Map::floatToInt(player_position);\r
+               // Does this make short random delays?\r
+               // NOTE: no need for this, sky doesn't show underground with\r
+               // enough range\r
+               bool is_underground = client.isNodeUnderground(p0);\r
+               //bool is_underground = false;\r
+               if(is_underground == false)\r
+                       bgcolor = video::SColor(255,90,140,200);\r
+               else\r
+                       bgcolor = video::SColor(255,0,0,0);*/\r
+                       \r
+               //video::SColor bgcolor = video::SColor(255,90,140,200);\r
+               //video::SColor bgcolor = skycolor;\r
+               \r
+               //s32 daynight_i = client.getDayNightIndex();\r
+               //video::SColor bgcolor = skycolor[daynight_i];\r
+\r
+               u32 daynight_ratio = client.getDayNightRatio();\r
+               video::SColor bgcolor = video::SColor(\r
+                               255,\r
+                               skycolor.getRed() * daynight_ratio / 1000,\r
+                               skycolor.getGreen() * daynight_ratio / 1000,\r
+                               skycolor.getBlue() * daynight_ratio / 1000);\r
+\r
+               /*\r
+                       Fog\r
+               */\r
+               \r
+               if(g_settings.getBool("enable_fog") == true)\r
+               {\r
+                       f32 range = g_viewing_range_nodes * BS;\r
+                       if(g_viewing_range_all)\r
+                               range = 100000*BS;\r
+\r
+                       driver->setFog(\r
+                               bgcolor,\r
+                               video::EFT_FOG_LINEAR,\r
+                               range*0.6,\r
+                               range,\r
+                               0.01,\r
+                               false, // pixel fog\r
+                               false // range fog\r
+                               );\r
+               }\r
+\r
 \r
                /*\r
                        Update gui stuff (0ms)\r
@@ -1953,23 +2303,26 @@ int main(int argc, char *argv[])
                //TimeTaker guiupdatetimer("Gui updating", device);\r
                \r
                {\r
-                       wchar_t temptext[100];\r
+                       wchar_t temptext[150];\r
 \r
                        static float drawtime_avg = 0;\r
                        drawtime_avg = drawtime_avg * 0.98 + (float)drawtime*0.02;\r
+                       static float beginscenetime_avg = 0;\r
+                       beginscenetime_avg = beginscenetime_avg * 0.98 + (float)beginscenetime*0.02;\r
                        static float scenetime_avg = 0;\r
                        scenetime_avg = scenetime_avg * 0.98 + (float)scenetime*0.02;\r
                        static float endscenetime_avg = 0;\r
                        endscenetime_avg = endscenetime_avg * 0.98 + (float)endscenetime*0.02;\r
                        \r
-                       swprintf(temptext, 100, L"Minetest-c55 ("\r
+                       swprintf(temptext, 150, L"Minetest-c55 ("\r
                                        L"F: item=%i"\r
                                        L", R: range_all=%i"\r
                                        L")"\r
-                                       L" drawtime=%.0f, scenetime=%.0f, endscenetime=%.0f",\r
+                                       L" drawtime=%.0f, beginscenetime=%.0f, scenetime=%.0f, endscenetime=%.0f",\r
                                        g_selected_item,\r
                                        g_viewing_range_all,\r
                                        drawtime_avg,\r
+                                       beginscenetime_avg,\r
                                        scenetime_avg,\r
                                        endscenetime_avg\r
                                        );\r
@@ -1978,19 +2331,8 @@ int main(int argc, char *argv[])
                }\r
                \r
                {\r
-                       wchar_t temptext[100];\r
-                       /*swprintf(temptext, 100,\r
-                                       L"("\r
-                                       L"% .3f < btime_jitter < % .3f"\r
-                                       L", dtime_jitter = % .1f %%"\r
-                                       //L", ftime_ratio = % .3f"\r
-                                       L")",\r
-                                       busytime_jitter1_min_sample,\r
-                                       busytime_jitter1_max_sample,\r
-                                       dtime_jitter1_max_fraction * 100.0\r
-                                       //g_freetime_ratio\r
-                                       );*/\r
-                       swprintf(temptext, 100,\r
+                       wchar_t temptext[150];\r
+                       swprintf(temptext, 150,\r
                                        L"(% .1f, % .1f, % .1f)"\r
                                        L" (% .3f < btime_jitter < % .3f"\r
                                        L", dtime_jitter = % .1f %%)",\r
@@ -2070,27 +2412,13 @@ int main(int argc, char *argv[])
 \r
                TimeTaker drawtimer("Drawing", device);\r
 \r
-               /*\r
-                       Background color is choosen based on whether the player is\r
-                       much beyond the initial ground level\r
-               */\r
-               /*video::SColor bgcolor;\r
-               v3s16 p0 = Map::floatToInt(player_position);\r
-               // Does this make short random delays?\r
-               // NOTE: no need for this, sky doesn't show underground with\r
-               // enough range\r
-               bool is_underground = client.isNodeUnderground(p0);\r
-               //bool is_underground = false;\r
-               if(is_underground == false)\r
-                       bgcolor = video::SColor(255,90,140,200);\r
-               else\r
-                       bgcolor = video::SColor(255,0,0,0);*/\r
-                       \r
-               //video::SColor bgcolor = video::SColor(255,90,140,200);\r
-               video::SColor bgcolor = skycolor;\r
                \r
-               // 0ms\r
+               {\r
+               TimeTaker timer("beginScene", device);\r
                driver->beginScene(true, true, bgcolor);\r
+               //driver->beginScene(false, true, bgcolor);\r
+               beginscenetime = timer.stop(true);\r
+               }\r
 \r
                //timer3.stop();\r
                \r
@@ -2178,6 +2506,8 @@ int main(int argc, char *argv[])
                        device->yield();*/\r
        }\r
 \r
+       delete quick_inventory;\r
+\r
        } // client is deleted at this point\r
        \r
        delete g_input;\r
@@ -2186,6 +2516,14 @@ int main(int argc, char *argv[])
                In the end, delete the Irrlicht device.\r
        */\r
        device->drop();\r
+       \r
+       /*\r
+               Update configuration file\r
+       */\r
+       if(configpath != "")\r
+       {\r
+               g_settings.updateConfigFile(configpath.c_str());\r
+       }\r
 \r
        } //try\r
        catch(con::PeerNotFoundException &e)\r