]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/main.cpp
CMake stuff works now on linux and windows... and should be possible to make to work...
[dragonfireclient.git] / src / main.cpp
index ac91b9d3dd44630c4418eccf420f845cb53e9151..a0da103c94aa06974495ea867aa1b80f99b188bb 100644 (file)
@@ -89,10 +89,6 @@ SUGG: Implement a "Fast check queue" (a queue with a map for checking
       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
-         - This is also needed for item container chests\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
@@ -117,9 +113,6 @@ TODO: Combine MapBlock's face caches to so big pieces that VBO
       gets used\r
       - That is >500 vertices\r
 \r
-TODO: Better dungeons\r
-TODO: Cliffs, arcs\r
-\r
 TODO: Startup and configuration menu\r
 \r
 TODO: There are some lighting-related todos and fixmes in\r
@@ -139,6 +132,14 @@ TODO: Make fetching sector's blocks more efficient when rendering
 \r
 TODO: Make the video backend selectable\r
 \r
+TODO: Copy the text of the last picked sign to inventory in creative\r
+      mode\r
+\r
+TODO: Get rid of GotSplitPacketException\r
+\r
+TODO: Check what goes wrong with caching map to disk (Kray)\r
+      - Nothing?\r
+\r
 Block object server side:\r
       - A "near blocks" buffer, in which some nearby blocks are stored.\r
          - For all blocks in the buffer, objects are stepped(). This\r
@@ -150,36 +151,53 @@ Block object server side:
            - TODO: For incoming blocks, time difference is calculated and\r
              objects are stepped according to it.\r
 \r
-TODO: Copy the text of the last picked sign to inventory in creative\r
-      mode\r
-\r
-TODO: Get rid of GotSplitPacketException\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: TOSERVER_LEAVE\r
-\r
 TODO: Better handling of objects and mobs\r
       - Scripting?\r
       - There has to be some way to do it with less spaghetti code\r
          - Make separate classes for client and server\r
            - Client should not discriminate between blocks, server should\r
            - Make other players utilize the same framework\r
+               - This is also needed for objects that don't get sent to client\r
+                 but are used for triggers etc\r
 \r
 TODO: Draw big amounts of torches better (that is, throw them in the\r
       same meshbuffer (can the meshcollector class be used?))\r
 \r
-TODO: Check if the usage of Client::isFetchingBlocks() in\r
-      updateViewingRange() actually does something\r
+TODO: Make an option to the server to disable building and digging near\r
+      the starting position\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
+         - This is also needed for item container chests\r
+TODO: There has to be some better way to handle static objects than to\r
+      send them all the time. This affects signs and item objects.\r
+\r
+TODO: When server sees that client is removing an inexistent block or\r
+      adding a block to an existent position, resend the MapBlock.\r
+\r
+TODO: When player dies, throw items on map\r
+\r
+TODO: Use porting::path_userdata for configuration file\r
+\r
+TODO: Optimize day/night mesh updating somehow\r
+      - create copies of all textures for all lighting values and only\r
+           change texture for material?\r
+         - Umm... the collecting of the faces is the slow part\r
+           -> what about just changing the color values of the existing\r
+                  meshbuffers? It should go quite fast.\r
+\r
+TODO: Map generator version 2\r
+       - Create surface areas based on central points; a given point's\r
+         area type is given by the nearest central point\r
+         - Separate points for heightmap, caves, plants and minerals?\r
+         - Flat land, mountains, forest, jungle\r
+    - Cliffs, arcs\r
+\r
+TODO: Add gui option to remove map\r
 \r
 Doing now:\r
 ======================================================================\r
 \r
-TODO: Tool capability table\r
-TODO: Transferring of the table from server to client\r
-\r
 ======================================================================\r
 \r
 */\r
@@ -194,7 +212,7 @@ TODO: Transferring of the table from server to client
 */\r
 #define FIELD_OF_VIEW_TEST 0\r
 \r
-#ifdef UNITTEST_DISABLE\r
+#ifdef NDEBUG\r
        #ifdef _WIN32\r
                #pragma message ("Disabling unit tests")\r
        #else\r
@@ -238,28 +256,14 @@ TODO: Transferring of the table from server to client
 #include "guiPauseMenu.h"\r
 #include "guiInventoryMenu.h"\r
 #include "guiTextInputMenu.h"\r
+#include "materials.h"\r
+#include "guiMessageMenu.h"\r
+#include "filesys.h"\r
+#include "config.h"\r
 \r
 IrrlichtWrapper *g_irrlicht;\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
-\r
-// If true, the preceding value has no meaning and all blocks\r
-// already existing in memory are drawn\r
-bool g_viewing_range_all = false;\r
-\r
-// This is the freetime ratio imposed by the dynamic viewing\r
-// range changing code.\r
-// It is controlled by the main loop to the smallest value that\r
-// inhibits glitches (dtime jitter) in the main loop.\r
-//float g_freetime_ratio = FREETIME_RATIO_MAX;\r
+MapDrawControl draw_control;\r
 \r
 /*\r
        Settings.\r
@@ -443,15 +447,14 @@ class MyEventReceiver : public IEventReceiver
                                // Viewing range selection\r
                                if(event.KeyInput.Key == irr::KEY_KEY_R)\r
                                {\r
-                                       JMutexAutoLock lock(g_range_mutex);\r
-                                       if(g_viewing_range_all)\r
+                                       if(draw_control.range_all)\r
                                        {\r
-                                               g_viewing_range_all = false;\r
+                                               draw_control.range_all = false;\r
                                                dstream<<DTIME<<"Disabled full viewing range"<<std::endl;\r
                                        }\r
                                        else\r
                                        {\r
-                                               g_viewing_range_all = true;\r
+                                               draw_control.range_all = true;\r
                                                dstream<<DTIME<<"Enabled full viewing range"<<std::endl;\r
                                        }\r
                                }\r
@@ -827,7 +830,7 @@ class RandomInputHandler : public InputHandler
 \r
        s32 Rand(s32 min, s32 max)\r
        {\r
-               return (rand()%(max-min+1))+min;\r
+               return (myrand()%(max-min+1))+min;\r
        }\r
 private:\r
        bool keydown[KEY_KEY_CODES_COUNT];\r
@@ -837,90 +840,135 @@ class RandomInputHandler : public InputHandler
        bool rightclicked;\r
 };\r
 \r
-void updateViewingRange(f32 frametime, Client *client)\r
+void updateViewingRange(f32 frametime_in, Client *client)\r
 {\r
-       // Range_all messes up frametime_avg\r
-       if(g_viewing_range_all == true)\r
+       if(draw_control.range_all == true)\r
                return;\r
-\r
-       float wanted_fps = g_settings.getFloat("wanted_fps");\r
        \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.7 + frametime * 0.3;\r
+       static f32 added_frametime = 0;\r
+       static s16 added_frames = 0;\r
 \r
+       added_frametime += frametime_in;\r
+       added_frames += 1;\r
+\r
+       // Actually this counter kind of sucks because frametime is busytime\r
        static f32 counter = 0;\r
-       if(counter > 0){\r
-               counter -= frametime;\r
+       counter -= frametime_in;\r
+       if(counter > 0)\r
                return;\r
-       }\r
-       //counter = 1.0; //seconds\r
-       counter = 0.5; //seconds\r
-\r
-       //float freetime_ratio = 0.2;\r
-       //float freetime_ratio = 0.4;\r
-       float freetime_ratio = FREETIME_RATIO;\r
-\r
-       float frametime_wanted = (1.0/(wanted_fps/(1.0-freetime_ratio)));\r
-\r
-       float fraction = sqrt(frametime_avg / frametime_wanted);\r
+       //counter = 0.1;\r
+       counter = 0.2;\r
 \r
-       /*float fraction = sqrt(frametime_avg / frametime_wanted) / 2.0\r
-                       + frametime_avg / frametime_wanted / 2.0;*/\r
+       /*dstream<<__FUNCTION_NAME\r
+                       <<": Collected "<<added_frames<<" frames, total of "\r
+                       <<added_frametime<<"s."<<std::endl;*/\r
        \r
-       //float fraction = frametime_avg / frametime_wanted;\r
-\r
-       static bool fraction_is_good = false;\r
+       /*dstream<<"draw_control.blocks_drawn="\r
+                       <<draw_control.blocks_drawn\r
+                       <<", draw_control.blocks_would_have_drawn="\r
+                       <<draw_control.blocks_would_have_drawn\r
+                       <<std::endl;*/\r
        \r
-       //float fraction_good_threshold = 0.1;\r
-       //float fraction_bad_threshold = 0.25;\r
-       float fraction_good_threshold = 0.075;\r
-       float fraction_bad_threshold = 0.125;\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
-       if(fraction_is_good && fraction > 1.0)\r
-               fraction_limit = fraction_bad_threshold;\r
-       else\r
-               fraction_limit = fraction_good_threshold;\r
-\r
-       if(fabs(fraction - 1.0) < fraction_limit)\r
+       float range_min = g_settings.getS16("viewing_range_nodes_min");\r
+       float range_max = g_settings.getS16("viewing_range_nodes_max");\r
+       \r
+       draw_control.wanted_min_range = range_min;\r
+       draw_control.wanted_max_blocks = (1.2*draw_control.blocks_drawn)+1;\r
+       \r
+       float block_draw_ratio = 1.0;\r
+       if(draw_control.blocks_would_have_drawn != 0)\r
        {\r
-               fraction_is_good = true;\r
-               return;\r
+               block_draw_ratio = (float)draw_control.blocks_drawn\r
+                       / (float)draw_control.blocks_would_have_drawn;\r
        }\r
-       else\r
+\r
+       // Calculate the average frametime in the case that all wanted\r
+       // blocks had been drawn\r
+       f32 frametime = added_frametime / added_frames / block_draw_ratio;\r
+       \r
+       added_frametime = 0.0;\r
+       added_frames = 0;\r
+       \r
+       float wanted_fps = g_settings.getFloat("wanted_fps");\r
+       float wanted_frametime = 1.0 / wanted_fps;\r
+       \r
+       f32 wanted_frametime_change = wanted_frametime - frametime;\r
+       //dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;\r
+       \r
+       // If needed frametime change is very small, just return\r
+       if(fabs(wanted_frametime_change) < wanted_frametime*0.2)\r
        {\r
-               fraction_is_good = false;\r
+               //dstream<<"ignoring small wanted_frametime_change"<<std::endl;\r
+               return;\r
        }\r
 \r
-       //dstream<<"frametime_avg="<<frametime_avg<<std::endl;\r
-       //dstream<<"frametime_wanted="<<frametime_wanted<<std::endl;\r
-       /*dstream<<"fetching="<<client->isFetchingBlocks()\r
-                       <<" faction = "<<fraction<<std::endl;*/\r
+       float range = draw_control.wanted_range;\r
+       float new_range = range;\r
 \r
-       JMutexAutoLock lock(g_range_mutex);\r
+       static s16 range_old = 0;\r
+       static f32 frametime_old = 0;\r
        \r
-       s16 viewing_range_nodes_min = g_settings.getS16("viewing_range_nodes_min");\r
-       s16 viewing_range_nodes_max = g_settings.getS16("viewing_range_nodes_max");\r
+       float d_range = range - range_old;\r
+       f32 d_frametime = frametime - frametime_old;\r
+       // A sane default of 30ms per 50 nodes of range\r
+       static f32 time_per_range = 30. / 50;\r
+       if(d_range != 0)\r
+       {\r
+               time_per_range = d_frametime / d_range;\r
+       }\r
+       \r
+       // The minimum allowed calculated frametime-range derivative:\r
+       // Practically this sets the maximum speed of changing the range.\r
+       // The lower this value, the higher the maximum changing speed.\r
+       // A low value here results in wobbly range (0.001)\r
+       // A high value here results in slow changing range (0.0025)\r
+       // SUGG: This could be dynamically adjusted so that when\r
+       //       the camera is turning, this is lower\r
+       //float min_time_per_range = 0.0015;\r
+       float min_time_per_range = 0.0010;\r
+       //float min_time_per_range = 0.05 / range;\r
+       if(time_per_range < min_time_per_range)\r
+       {\r
+               time_per_range = min_time_per_range;\r
+               //dstream<<"time_per_range="<<time_per_range<<" (min)"<<std::endl;\r
+       }\r
+       else\r
+       {\r
+               //dstream<<"time_per_range="<<time_per_range<<std::endl;\r
+       }\r
 \r
-       s16 n = (float)g_viewing_range_nodes / fraction;\r
-       if(n < viewing_range_nodes_min)\r
-               n = viewing_range_nodes_min;\r
-       if(n > viewing_range_nodes_max)\r
-               n = viewing_range_nodes_max;\r
+       f32 wanted_range_change = wanted_frametime_change / time_per_range;\r
+       // Dampen the change a bit to kill oscillations\r
+       //wanted_range_change *= 0.9;\r
+       //wanted_range_change *= 0.75;\r
+       wanted_range_change *= 0.5;\r
+       //dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;\r
 \r
-       bool can_change = true;\r
+       // If needed range change is very small, just return\r
+       if(fabs(wanted_range_change) < 0.001)\r
+       {\r
+               //dstream<<"ignoring small wanted_range_change"<<std::endl;\r
+               return;\r
+       }\r
 \r
-       if(client->isFetchingBlocks() == true && n > g_viewing_range_nodes)\r
-               can_change = false;\r
+       new_range += wanted_range_change;\r
+       //dstream<<"new_range="<<new_range/*<<std::endl*/;\r
        \r
-       if(can_change)\r
-               g_viewing_range_nodes = n;\r
+       //float new_range_unclamped = new_range;\r
+       if(new_range < range_min)\r
+               new_range = range_min;\r
+       if(new_range > range_max)\r
+               new_range = range_max;\r
+       \r
+       /*if(new_range != new_range_unclamped)\r
+               dstream<<", clamped to "<<new_range<<std::endl;\r
+       else\r
+               dstream<<std::endl;*/\r
+\r
+       draw_control.wanted_range = new_range;\r
 \r
-       /*dstream<<"g_viewing_range_nodes = "\r
-                       <<g_viewing_range_nodes<<std::endl;*/\r
+       range_old = new_range;\r
+       frametime_old = frametime;\r
 }\r
 \r
 class GUIQuickInventory : public IEventReceiver\r
@@ -1021,6 +1069,22 @@ class GUIQuickInventory : public IEventReceiver
        s32 m_selection;\r
 };\r
 \r
+// Chat data\r
+struct ChatLine\r
+{\r
+       ChatLine():\r
+               age(0.0)\r
+       {\r
+       }\r
+       ChatLine(const std::wstring &a_text):\r
+               age(0.0),\r
+               text(a_text)\r
+       {\r
+       }\r
+       float age;\r
+       std::wstring text;\r
+};\r
+\r
 int main(int argc, char *argv[])\r
 {\r
        /*\r
@@ -1039,6 +1103,20 @@ int main(int argc, char *argv[])
 \r
        DSTACK(__FUNCTION_NAME);\r
 \r
+       porting::initializePaths();\r
+       // Create user data directory\r
+       fs::CreateDir(porting::path_userdata);\r
+\r
+       initializeMaterialProperties();\r
+\r
+       BEGIN_DEBUG_EXCEPTION_HANDLER\r
+\r
+       // Print startup message\r
+       dstream<<DTIME<<"minetest-c55"\r
+                       " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
+                       <<", "<<BUILD_INFO\r
+                       <<std::endl;\r
+       \r
        try\r
        {\r
        \r
@@ -1058,6 +1136,7 @@ int main(int argc, char *argv[])
        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
+       allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));\r
 \r
        Settings cmd_args;\r
        \r
@@ -1098,12 +1177,6 @@ int main(int argc, char *argv[])
        // Initialize default settings\r
        set_default_settings();\r
        \r
-       // Print startup message\r
-       dstream<<DTIME<<"minetest-c55"\r
-                       " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
-                       <<", ENABLE_TESTS="<<ENABLE_TESTS\r
-                       <<std::endl;\r
-       \r
        // Set locale. This is for forcing '.' as the decimal point.\r
        std::locale::global(std::locale("C"));\r
        // This enables printing all characters in bitmap font\r
@@ -1137,15 +1210,15 @@ int main(int argc, char *argv[])
        }\r
        else\r
        {\r
-               const char *filenames[2] =\r
-               {\r
-                       "../minetest.conf",\r
-                       "../../minetest.conf"\r
-               };\r
+               core::array<std::string> filenames;\r
+               filenames.push_back(porting::path_userdata + "/minetest.conf");\r
+#ifdef RUN_IN_PLACE\r
+               filenames.push_back(porting::path_userdata + "/../minetest.conf");\r
+#endif\r
 \r
-               for(u32 i=0; i<2; i++)\r
+               for(u32 i=0; i<filenames.size(); i++)\r
                {\r
-                       bool r = g_settings.readConfigFile(filenames[i]);\r
+                       bool r = g_settings.readConfigFile(filenames[i].c_str());\r
                        if(r)\r
                        {\r
                                configpath = filenames[i];\r
@@ -1156,6 +1229,7 @@ int main(int argc, char *argv[])
 \r
        // Initialize random seed\r
        srand(time(0));\r
+       mysrand(time(0));\r
 \r
        /*\r
                Run unit tests\r
@@ -1166,12 +1240,6 @@ int main(int argc, char *argv[])
                run_tests();\r
        }\r
        \r
-       /*\r
-               Global range mutex\r
-       */\r
-       g_range_mutex.Init();\r
-       assert(g_range_mutex.IsInitialized());\r
-\r
        // Read map parameters from settings\r
 \r
        HMParams hm_params;\r
@@ -1214,6 +1282,13 @@ int main(int argc, char *argv[])
                std::cout<<"-> "<<port<<std::endl;\r
        }\r
        \r
+       //Map directory\r
+       std::string map_dir = porting::path_userdata+"/map";\r
+       if(cmd_args.exists("map-dir"))\r
+               map_dir = cmd_args.get("map-dir");\r
+       else if(g_settings.exists("map-dir"))\r
+               map_dir = g_settings.get("map-dir");\r
+       \r
        if(cmd_args.getFlag("server"))\r
        {\r
                DSTACK("Dedicated server branch");\r
@@ -1224,7 +1299,7 @@ int main(int argc, char *argv[])
                std::cout<<"========================"<<std::endl;\r
                std::cout<<std::endl;\r
 \r
-               Server server("../map", hm_params, map_params);\r
+               Server server(map_dir, hm_params, map_params);\r
                server.start(port);\r
        \r
                for(;;)\r
@@ -1356,13 +1431,13 @@ int main(int argc, char *argv[])
        /*\r
                This changes the minimum allowed number of vertices in a VBO\r
        */\r
-       //driver->setMinHardwareBufferVertexCount(1);\r
+       //driver->setMinHardwareBufferVertexCount(50);\r
 \r
        scene::ISceneManager* smgr = device->getSceneManager();\r
        \r
        guienv = device->getGUIEnvironment();\r
        gui::IGUISkin* skin = guienv->getSkin();\r
-       gui::IGUIFont* font = guienv->getFont("../data/fontlucida.png");\r
+       gui::IGUIFont* font = guienv->getFont(porting::getDataPath("fontlucida.png").c_str());\r
        if(font)\r
                skin->setFont(font);\r
        \r
@@ -1393,6 +1468,8 @@ int main(int argc, char *argv[])
                Preload some textures\r
        */\r
 \r
+       init_content_inventory_texture_paths();\r
+       init_tile_texture_paths();\r
        tile_materials_preload(g_irrlicht);\r
 \r
        /*\r
@@ -1408,7 +1485,7 @@ int main(int argc, char *argv[])
        */\r
        SharedPtr<Server> server;\r
        if(hosting){\r
-               server = new Server("../map", hm_params, map_params);\r
+               server = new Server(map_dir, hm_params, map_params);\r
                server->start(port);\r
        }\r
        \r
@@ -1416,10 +1493,7 @@ int main(int argc, char *argv[])
                Create client\r
        */\r
 \r
-       Client client(device, playername,\r
-                       g_range_mutex,\r
-                       g_viewing_range_nodes,\r
-                       g_viewing_range_all);\r
+       Client client(device, playername, draw_control);\r
                        \r
        g_client = &client;\r
        \r
@@ -1457,12 +1531,12 @@ int main(int argc, char *argv[])
        */\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
+               driver->getTexture(porting::getDataPath("skybox2.png").c_str()),\r
+               driver->getTexture(porting::getDataPath("skybox3.png").c_str()),\r
+               driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
+               driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
+               driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
+               driver->getTexture(porting::getDataPath("skybox1.png").c_str()));*/\r
        \r
        /*\r
                Create the camera node\r
@@ -1512,6 +1586,15 @@ int main(int argc, char *argv[])
        // Test the text input system\r
        /*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count,\r
                        NULL))->drop();*/\r
+       /*GUIMessageMenu *menu =\r
+                       new GUIMessageMenu(guienv, guiroot, -1, \r
+                               &g_active_menu_count,\r
+                               L"Asd");\r
+       menu->drop();*/\r
+       \r
+       // Launch pause menu\r
+       (new GUIPauseMenu(guienv, guiroot, -1, g_device,\r
+                       &g_active_menu_count))->drop();\r
 \r
        // First line of debug text\r
        gui::IGUIStaticText *guitext = guienv->addStaticText(\r
@@ -1536,8 +1619,8 @@ int main(int argc, char *argv[])
                        L"Chat here\nOther line\nOther line\nOther line\nOther line",\r
                        core::rect<s32>(70, 60, 795, 150),\r
                        false, true);\r
-       core::list<std::wstring> chat_lines;\r
-       //chat_lines.push_back(L"Minetest-c55 up and running!");\r
+       chat_guitext->setBackgroundColor(video::SColor(96,0,0,0));\r
+       core::list<ChatLine> chat_lines;\r
        \r
        /*\r
                Some statistics are collected in these\r
@@ -1546,6 +1629,9 @@ int main(int argc, char *argv[])
        u32 beginscenetime = 0;\r
        u32 scenetime = 0;\r
        u32 endscenetime = 0;\r
+       \r
+       // A test\r
+       //throw con::PeerNotFoundException("lol");\r
 \r
        /*\r
                Main loop\r
@@ -1554,8 +1640,8 @@ int main(int argc, char *argv[])
        bool first_loop_after_window_activation = true;\r
 \r
        // Time is in milliseconds\r
-       // NOTE: getRealTime() without run()s causes strange problems in wine\r
-       // NOTE: Have to call run() between calls of this to update the timer\r
+       // NOTE: getRealTime() causes strange problems in wine (imprecision?)\r
+       // NOTE: So we have to use getTime() and call run()s between them\r
        u32 lasttime = device->getTimer()->getTime();\r
 \r
        while(device->run())\r
@@ -1802,9 +1888,13 @@ int main(int argc, char *argv[])
                v3f camera_direction = v3f(0,0,1);\r
                camera_direction.rotateYZBy(camera_pitch);\r
                camera_direction.rotateXZBy(camera_yaw);\r
-\r
+               \r
+               // This is at the height of the eyes of the current figure\r
                v3f camera_position =\r
                                player_position + v3f(0, BS+BS/2, 0);\r
+               // This is more like in minecraft\r
+               /*v3f camera_position =\r
+                               player_position + v3f(0, BS+BS*0.65, 0);*/\r
 \r
                camera->setPosition(camera_position);\r
                // *100.0 helps in large map coordinates\r
@@ -2097,34 +2187,50 @@ int main(int argc, char *argv[])
                                if(g_input->getLeftState())\r
                                {\r
                                        MapNode n = client.getNode(nodepos);\r
-\r
-                                       // TODO: Get this from some table that is sent by server\r
-                                       float dig_time_complete = 0.5;\r
-                                       if(n.d == CONTENT_STONE || n.d == CONTENT_COALSTONE)\r
+                               \r
+                                       // Get tool name. Default is "" = bare hands\r
+                                       std::string toolname = "";\r
+                                       InventoryList *mlist = local_inventory.getList("main");\r
+                                       if(mlist != NULL)\r
                                        {\r
-                                               dig_time_complete = 10.0;\r
-\r
-                                               InventoryList *mlist = local_inventory.getList("main");\r
-                                               if(mlist != NULL)\r
+                                               InventoryItem *item = mlist->getItem(g_selected_item);\r
+                                               if(item && (std::string)item->getName() == "ToolItem")\r
                                                {\r
-                                                       InventoryItem *item = mlist->getItem(g_selected_item);\r
-                                                       if(item && (std::string)item->getName() == "ToolItem")\r
-                                                       {\r
-                                                               ToolItem *titem = (ToolItem*)item;\r
-                                                               if(titem->getToolName() == "WPick")\r
-                                                               {\r
-                                                                       dig_time_complete = 1.2;\r
-                                                               }\r
-                                                               else if(titem->getToolName() == "STPick")\r
-                                                               {\r
-                                                                       dig_time_complete = 0.6;\r
-                                                               }\r
-                                                       }\r
+                                                       ToolItem *titem = (ToolItem*)item;\r
+                                                       toolname = titem->getToolName();\r
                                                }\r
                                        }\r
+\r
+                                       // Get digging properties for material and tool\r
+                                       u8 material = n.d;\r
+                                       DiggingProperties prop =\r
+                                                       getDiggingProperties(material, toolname);\r
                                        \r
-                                       dig_index = (u16)((float)CRACK_ANIMATION_LENGTH\r
-                                                       * dig_time/dig_time_complete);\r
+                                       float dig_time_complete = 0.0;\r
+\r
+                                       if(prop.diggable == false)\r
+                                       {\r
+                                               /*dstream<<"Material "<<(int)material\r
+                                                               <<" not diggable with \""\r
+                                                               <<toolname<<"\""<<std::endl;*/\r
+                                               // I guess nobody will wait for this long\r
+                                               dig_time_complete = 10000000.0;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               dig_time_complete = prop.time;\r
+                                       }\r
+                                       \r
+                                       if(dig_time_complete >= 0.001)\r
+                                       {\r
+                                               dig_index = (u16)((float)CRACK_ANIMATION_LENGTH\r
+                                                               * dig_time/dig_time_complete);\r
+                                       }\r
+                                       // This is for torches\r
+                                       else\r
+                                       {\r
+                                               dig_index = CRACK_ANIMATION_LENGTH;\r
+                                       }\r
 \r
                                        if(dig_index < CRACK_ANIMATION_LENGTH)\r
                                        {\r
@@ -2142,6 +2248,21 @@ int main(int argc, char *argv[])
 \r
                                                nodig_delay_counter = dig_time_complete\r
                                                                / (float)CRACK_ANIMATION_LENGTH;\r
+\r
+                                               // We don't want a corresponding delay to\r
+                                               // very time consuming nodes\r
+                                               if(nodig_delay_counter > 0.5)\r
+                                               {\r
+                                                       nodig_delay_counter = 0.5;\r
+                                               }\r
+                                               // We want a slight delay to very little\r
+                                               // time consuming nodes\r
+                                               //float mindelay = 0.15;\r
+                                               float mindelay = 0.20;\r
+                                               if(nodig_delay_counter < mindelay)\r
+                                               {\r
+                                                       nodig_delay_counter = mindelay;\r
+                                               }\r
                                        }\r
 \r
                                        dig_time += dtime;\r
@@ -2186,11 +2307,18 @@ int main(int argc, char *argv[])
                camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y);\r
                \r
                u32 daynight_ratio = client.getDayNightRatio();\r
-               video::SColor bgcolor = video::SColor(\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
+                               skycolor.getBlue() * daynight_ratio / 1000);*/\r
+\r
+               u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000);\r
+               video::SColor bgcolor = video::SColor(\r
+                               255,\r
+                               skycolor.getRed() * l / 255,\r
+                               skycolor.getGreen() * l / 255,\r
+                               skycolor.getBlue() * l / 255);\r
 \r
                /*\r
                        Fog\r
@@ -2198,8 +2326,8 @@ int main(int argc, char *argv[])
                \r
                if(g_settings.getBool("enable_fog") == true)\r
                {\r
-                       f32 range = g_viewing_range_nodes * BS;\r
-                       if(g_viewing_range_all)\r
+                       f32 range = draw_control.wanted_range * BS;\r
+                       if(draw_control.range_all)\r
                                range = 100000*BS;\r
 \r
                        driver->setFog(\r
@@ -2224,13 +2352,13 @@ int main(int argc, char *argv[])
                        wchar_t temptext[150];\r
 \r
                        static float drawtime_avg = 0;\r
-                       drawtime_avg = drawtime_avg * 0.98 + (float)drawtime*0.02;\r
+                       drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;\r
                        static float beginscenetime_avg = 0;\r
-                       beginscenetime_avg = beginscenetime_avg * 0.98 + (float)beginscenetime*0.02;\r
+                       beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;\r
                        static float scenetime_avg = 0;\r
-                       scenetime_avg = scenetime_avg * 0.98 + (float)scenetime*0.02;\r
+                       scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;\r
                        static float endscenetime_avg = 0;\r
-                       endscenetime_avg = endscenetime_avg * 0.98 + (float)endscenetime*0.02;\r
+                       endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;\r
                        \r
                        swprintf(temptext, 150, L"Minetest-c55 ("\r
                                        L"F: item=%i"\r
@@ -2238,7 +2366,7 @@ int main(int argc, char *argv[])
                                        L")"\r
                                        L" drawtime=%.0f, beginscenetime=%.0f, scenetime=%.0f, endscenetime=%.0f",\r
                                        g_selected_item,\r
-                                       g_viewing_range_all,\r
+                                       draw_control.range_all,\r
                                        drawtime_avg,\r
                                        beginscenetime_avg,\r
                                        scenetime_avg,\r
@@ -2253,13 +2381,15 @@ int main(int argc, char *argv[])
                        swprintf(temptext, 150,\r
                                        L"(% .1f, % .1f, % .1f)"\r
                                        L" (% .3f < btime_jitter < % .3f"\r
-                                       L", dtime_jitter = % .1f %%)",\r
+                                       L", dtime_jitter = % .1f %%"\r
+                                       L", v_range = %.1f)",\r
                                        player_position.X/BS,\r
                                        player_position.Y/BS,\r
                                        player_position.Z/BS,\r
                                        busytime_jitter1_min_sample,\r
                                        busytime_jitter1_max_sample,\r
-                                       dtime_jitter1_max_fraction * 100.0\r
+                                       dtime_jitter1_max_fraction * 100.0,\r
+                                       draw_control.wanted_range\r
                                        );\r
 \r
                        guitext2->setText(temptext);\r
@@ -2273,26 +2403,52 @@ int main(int argc, char *argv[])
                        Get chat messages from client\r
                */\r
                {\r
-                       // Get messages\r
+                       // Get new messages\r
                        std::wstring message;\r
                        while(client.getChatMessage(message))\r
                        {\r
-                               chat_lines.push_back(message);\r
-                               if(chat_lines.size() > 5)\r
+                               chat_lines.push_back(ChatLine(message));\r
+                               /*if(chat_lines.size() > 6)\r
                                {\r
-                                       core::list<std::wstring>::Iterator\r
+                                       core::list<ChatLine>::Iterator\r
                                                        i = chat_lines.begin();\r
                                        chat_lines.erase(i);\r
-                               }\r
+                               }*/\r
                        }\r
                        // Append them to form the whole static text and throw\r
                        // it to the gui element\r
                        std::wstring whole;\r
-                       for(core::list<std::wstring>::Iterator\r
+                       // This will correspond to the line number counted from\r
+                       // top to bottom, from size-1 to 0\r
+                       s16 line_number = chat_lines.size();\r
+                       // Count of messages to be removed from the top\r
+                       u16 to_be_removed_count = 0;\r
+                       for(core::list<ChatLine>::Iterator\r
                                        i = chat_lines.begin();\r
                                        i != chat_lines.end(); i++)\r
                        {\r
-                               whole += (*i) + L'\n';\r
+                               // After this, line number is valid for this loop\r
+                               line_number--;\r
+                               // Increment age\r
+                               (*i).age += dtime;\r
+                               /*\r
+                                       This results in a maximum age of 60*6 to the\r
+                                       lowermost line and a maximum of 6 lines\r
+                               */\r
+                               float allowed_age = (6-line_number) * 60.0;\r
+\r
+                               if((*i).age > allowed_age)\r
+                               {\r
+                                       to_be_removed_count++;\r
+                                       continue;\r
+                               }\r
+                               whole += (*i).text + L'\n';\r
+                       }\r
+                       for(u16 i=0; i<to_be_removed_count; i++)\r
+                       {\r
+                               core::list<ChatLine>::Iterator\r
+                                               it = chat_lines.begin();\r
+                               chat_lines.erase(it);\r
                        }\r
                        chat_guitext->setText(whole.c_str());\r
                        // Update gui element size and position\r
@@ -2303,6 +2459,11 @@ int main(int argc, char *argv[])
                                        screensize.Y - 10\r
                        );\r
                        chat_guitext->setRelativePosition(rect);\r
+\r
+                       if(chat_lines.size() == 0)\r
+                               chat_guitext->setVisible(false);\r
+                       else\r
+                               chat_guitext->setVisible(true);\r
                }\r
 \r
                /*\r
@@ -2458,19 +2619,33 @@ int main(int argc, char *argv[])
        catch(con::PeerNotFoundException &e)\r
        {\r
                dstream<<DTIME<<"Connection timed out."<<std::endl;\r
+               \r
+               /*if(g_device)\r
+               {\r
+                       GUIMessageMenu *menu =\r
+                                       new GUIMessageMenu(guienv, guiroot, -1, \r
+                                               &g_active_menu_count,\r
+                                               L"Connection timed out");\r
+\r
+                       video::IVideoDriver* driver = g_device->getVideoDriver();\r
+                       \r
+                       dstream<<"Created menu"<<std::endl;\r
+\r
+                       while(g_device->run() && menu->getStatus() == false)\r
+                       {\r
+                               driver->beginScene(true, true, video::SColor(255,0,0,0));\r
+                               guienv->drawAll();\r
+                               driver->endScene();\r
+                       }\r
+                       \r
+                       dstream<<"Dropping menu"<<std::endl;\r
+\r
+                       menu->drop();\r
+               }*/\r
        }\r
-#if CATCH_UNHANDLED_EXCEPTIONS\r
-       /*\r
-               This is what has to be done in every thread to get suitable debug info\r
-       */\r
-       catch(std::exception &e)\r
-       {\r
-               dstream<<std::endl<<DTIME<<"An unhandled exception occurred: "\r
-                               <<e.what()<<std::endl;\r
-               assert(0);\r
-       }\r
-#endif\r
 \r
+       END_DEBUG_EXCEPTION_HANDLER\r
+       \r
        debugstreams_deinit();\r
        \r
        return 0;\r