A third try on terrain generation. No trees yet.
authorPerttu Ahola <celeron55@gmail.com>
Mon, 28 Feb 2011 00:01:40 +0000 (02:01 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Mon, 28 Feb 2011 00:01:40 +0000 (02:01 +0200)
13 files changed:
data/mud.png
src/client.cpp
src/client.h
src/clientserver.h
src/main.cpp
src/map.cpp
src/map.h
src/mapblock.cpp
src/noise.cpp
src/noise.h
src/server.cpp
src/tile.cpp
src/utility.h

index 7cb9c89a637584b4e53c82a7c6eb1ec7109befae..8a72bea90aeb27e7741092499c72cae48dd4d264 100644 (file)
Binary files a/data/mud.png and b/data/mud.png differ
index 3ea6665491fa6549f3763221b73ea98a3118aa72..fe1669dddae81debf8cbf23df5d1a50bbe7794f3 100644 (file)
@@ -510,6 +510,10 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                        assert(player != NULL);
                        player->setPosition(playerpos_f);
                }
+
+               // Get map seed
+               m_map_seed = readU64(&data[2+1+6]);
+               dstream<<"Client: received map seed: "<<m_map_seed<<std::endl;
                
                // Reply to server
                u32 replysize = 2;
index fb1e70722e1a936cf8c96d88c8cda2099f01b8e3..d6496d9dfd471982aaff5e260709ee39108700ae 100644 (file)
@@ -252,6 +252,8 @@ public:
                                (std::wstring)L"<"+name+L"> "+message);
        }
 
+       u64 getMapSeed(){ return m_map_seed; }
+
 private:
        
        // Virtual methods from con::PeerHandler
@@ -311,6 +313,9 @@ private:
        //u32 m_daynight_ratio;
 
        Queue<std::wstring> m_chat_queue;
+       
+       // The seed returned by the server in TOCLIENT_INIT is stored here
+       u64 m_map_seed;
 };
 
 #endif // !SERVER
index 893bbc1e0fb88c86b1ba48f81651b2f35bbde7d7..52b4e520eabe010aa97472c2172895ee1b7f0c54 100644 (file)
@@ -34,6 +34,7 @@ enum ToClientCommand
                [0] u16 TOSERVER_INIT
                [2] u8 deployed version
                [3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
+               [4] u64 map seed (new as of 2011-02-27)
        */
 
        TOCLIENT_BLOCKDATA = 0x20, //TODO: Multiple blocks
index 2c059840ed2de0f5ef5ab5182e1b06687e2df7c2..be3776623afb8a11bef54794548457ceff0e61bc 100644 (file)
@@ -253,11 +253,9 @@ Doing now (most important at the top):
 * not done\r
 \r
 === Next\r
-* Continue making the scripting system:\r
-  * Make updateNodeMesh for a less verbose mesh update on add/removenode\r
-  * Switch to using a safe way for the self and env pointers\r
-  * Make some global environment hooks, like node placed and general\r
-    on_step()\r
+* Make a system for pregenerating quick information for mapblocks, so\r
+  that the client can show them as cubes before they are actually sent\r
+  or even generated.\r
 \r
 === Fixmes\r
 * Check the fixmes in the list above\r
@@ -274,6 +272,11 @@ Doing now (most important at the top):
   with the ones in utility.h\r
 \r
 === Features\r
+* Continue making the scripting system:\r
+  * Make updateNodeMesh for a less verbose mesh update on add/removenode\r
+  * Switch to using a safe way for the self and env pointers\r
+  * Make some global environment hooks, like node placed and general\r
+    on_step()\r
 * Map should make the appropriate MapEditEvents\r
 * Add a global Lua spawn handler and such\r
 * Get rid of MapBlockObjects\r
@@ -490,6 +493,9 @@ Inventory local_inventory;
 \r
 u16 g_selected_item = 0;\r
 \r
+bool g_show_map_plot = false;\r
+bool g_refresh_map_plot = true;\r
+\r
 /*\r
        Debug streams\r
 */\r
@@ -606,6 +612,15 @@ public:
                        if(event.KeyInput.PressedDown)\r
                        {\r
                                //dstream<<"Pressed key: "<<(char)event.KeyInput.Key<<std::endl;\r
+                               if(g_show_map_plot)\r
+                               {\r
+                                       if(event.KeyInput.Key == irr::KEY_ESCAPE\r
+                                               || event.KeyInput.Key == irr::KEY_KEY_M)\r
+                                       {\r
+                                               g_show_map_plot = false;\r
+                                       }\r
+                                       return true;\r
+                               }\r
                                \r
                                /*\r
                                        Launch menus\r
@@ -679,6 +694,16 @@ public:
                                                        <<std::endl;\r
                                        debug_stacks_print();\r
                                }\r
+\r
+                               // Map plot\r
+                               if(event.KeyInput.Key == irr::KEY_KEY_M)\r
+                               {\r
+                                       dstream<<"Map plot requested"<<std::endl;\r
+                                       g_show_map_plot = !g_show_map_plot;\r
+                                       if(g_show_map_plot)\r
+                                               g_refresh_map_plot = true;\r
+                               }\r
+                               \r
                        }\r
                }\r
 \r
@@ -1110,8 +1135,8 @@ void updateViewingRange(f32 frametime_in, Client *client)
        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
+       // If needed frametime change is small, just return\r
+       if(fabs(wanted_frametime_change) < wanted_frametime*0.4)\r
        {\r
                //dstream<<"ignoring small wanted_frametime_change"<<std::endl;\r
                return;\r
@@ -1239,6 +1264,93 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
        }\r
 }\r
 \r
+video::ITexture *g_map_plot_texture = NULL;\r
+float g_map_plot_texture_scale = 2;\r
+\r
+void updateMapPlotTexture(v2f centerpos, video::IVideoDriver* driver,\r
+               Client *client)\r
+{\r
+       assert(driver);\r
+       assert(client);\r
+\r
+       core::dimension2d<u32> dim(640,480);\r
+       video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim);\r
+       assert(img);\r
+       for(u32 y=0; y<dim.Height; y++)\r
+       for(u32 x=0; x<dim.Width; x++)\r
+       {\r
+               v2f pf = v2f(x, dim.Height-y) - v2f(dim.Width, dim.Height)/2;\r
+               pf *= g_map_plot_texture_scale;\r
+               pf += centerpos;\r
+               double h = base_rock_level_2d(client->getMapSeed(), pf);\r
+               video::SColor c;\r
+               //double d1 = 50;\r
+               /*s32 ux = x - centerpos.X / g_map_plot_texture_scale;\r
+               s32 uy = y - centerpos.Y / g_map_plot_texture_scale;*/\r
+                       \r
+               // Screen coordinates that are based on multiples of\r
+               // 1000/g_map_plot_texture_scale and never negative\r
+               u32 ux = x + (u32)(1000/g_map_plot_texture_scale) * 10;\r
+               u32 uy = y + (u32)(1000/g_map_plot_texture_scale) * 10;\r
+               // Offset to center of image\r
+               ux -= dim.Width/2;\r
+               uy -= dim.Height/2;\r
+\r
+               if(uy % (u32)(1000/g_map_plot_texture_scale) == 0\r
+                               || ux % (u32)(1000/g_map_plot_texture_scale) == 0)\r
+                       c.set(255, 255, 255, 255);\r
+               else if(uy % (u32)(100/g_map_plot_texture_scale) == 0\r
+                               || ux % (u32)(100/g_map_plot_texture_scale) == 0)\r
+                       c.set(255, 160, 160, 160);\r
+               else if(h < WATER_LEVEL - 0.5) // Water\r
+                       c.set(255, 50, 50, 255);\r
+               else if(h < WATER_LEVEL + 2) // Sand\r
+                       c.set(255, 237, 201, 175);\r
+#if 1\r
+               else if(h < WATER_LEVEL + 10) // Green\r
+                       c.set(255, 50, 150, 50);\r
+               else if(h < WATER_LEVEL + 20) // Greenish yellow\r
+                       c.set(255, 110, 185, 50);\r
+               else if(h < WATER_LEVEL + 50) // Yellow\r
+                       c.set(255, 220, 220, 50);\r
+               else if(h < WATER_LEVEL + 100) // White\r
+                       c.set(255, 180, 180, 180);\r
+               else\r
+                       c.set(255, 255, 255, 255);\r
+#endif\r
+               /*else if(h < WATER_LEVEL + d1)\r
+               {\r
+                       h -= WATER_LEVEL;\r
+                       u32 a = (u32)(h / d1 * 255);\r
+                       if(a > 255)\r
+                               a = 255;\r
+                       c.set(255, 0, a, 0);\r
+               }*/\r
+#if 0\r
+               else\r
+               {\r
+                       h -= WATER_LEVEL;\r
+                       h /= 20.0;\r
+                       h = 1.0 - exp(-h);\r
+\r
+                       video::SColor c1(255,200,200,50);\r
+                       video::SColor c2(255,0,150,0);\r
+                       c = c1.getInterpolated(c2, h);\r
+\r
+                       /*u32 a = (u32)(h*255);\r
+                       if(a > 255)\r
+                               a = 255;\r
+                       a = 255-a;\r
+                       c.set(255, a, a, a);*/\r
+               }\r
+#endif\r
+               img->setPixel(x, y, c);\r
+       }\r
+       g_map_plot_texture = driver->addTexture("map_plot", img);\r
+       img->drop();\r
+       assert(g_map_plot_texture);\r
+}\r
+\r
 // Chat data\r
 struct ChatLine\r
 {\r
@@ -2252,6 +2364,10 @@ int main(int argc, char *argv[])
                */\r
                g_input->step(dtime);\r
 \r
+               /*\r
+                       Misc. stuff\r
+               */\r
+\r
                /*\r
                        Player speed control\r
                */\r
@@ -3020,16 +3136,6 @@ int main(int argc, char *argv[])
                        driver->draw3DBox(*i, video::SColor(255,0,0,0));\r
                }\r
 \r
-               /*\r
-                       Draw crosshair\r
-               */\r
-               driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),\r
-                               displaycenter + core::vector2d<s32>(10,0),\r
-                               video::SColor(255,255,255,255));\r
-               driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),\r
-                               displaycenter + core::vector2d<s32>(0,10),\r
-                               video::SColor(255,255,255,255));\r
-\r
                /*\r
                        Frametime log\r
                */\r
@@ -3048,6 +3154,31 @@ int main(int argc, char *argv[])
                        }\r
                }\r
 \r
+               /*\r
+                       Draw map plot\r
+               */\r
+               if(g_show_map_plot && g_map_plot_texture)\r
+               {\r
+                       core::dimension2d<u32> drawdim(640,480);\r
+                       core::rect<s32> dest(v2s32(0,0), drawdim);\r
+                       dest += v2s32(\r
+                               (screensize.X-drawdim.Width)/2,\r
+                               (screensize.Y-drawdim.Height)/2\r
+                       );\r
+                       core::rect<s32> source(v2s32(0,0), g_map_plot_texture->getSize());\r
+                       driver->draw2DImage(g_map_plot_texture, dest, source);\r
+               }\r
+\r
+               /*\r
+                       Draw crosshair\r
+               */\r
+               driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),\r
+                               displaycenter + core::vector2d<s32>(10,0),\r
+                               video::SColor(255,255,255,255));\r
+               driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),\r
+                               displaycenter + core::vector2d<s32>(0,10),\r
+                               video::SColor(255,255,255,255));\r
+\r
                } // timer\r
 \r
                //timer10.stop();\r
@@ -3077,8 +3208,23 @@ int main(int argc, char *argv[])
                drawtime = drawtimer.stop(true);\r
 \r
                /*\r
-                       Drawing ends\r
+                       End of drawing\r
+               */\r
+\r
+               /*\r
+                       Refresh map plot if player has moved considerably\r
                */\r
+               if(g_refresh_map_plot)\r
+               {\r
+                       static v3f old_player_pos = v3f(1,1,1) * 10000000;\r
+                       v3f p = client.getPlayerPosition() / BS;\r
+                       if(old_player_pos.getDistanceFrom(p) > 4 * g_map_plot_texture_scale)\r
+                       {\r
+                               updateMapPlotTexture(v2f(p.X,p.Z), driver, &client);\r
+                               old_player_pos = p;\r
+                       }\r
+                       g_refresh_map_plot = false;\r
+               }\r
                \r
                static s16 lastFPS = 0;\r
                //u16 fps = driver->getFPS();\r
index 8e71212b0fe6bc1ed29d1e984cb15443bf97fddc..7b16834e20d3e836a3a9ded54aaf7bb24111aba6 100644 (file)
@@ -1422,6 +1422,9 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
 
        while(m_transforming_liquid.size() != 0)
        {
+               try
+               {
+
                /*
                        Get a queued transforming liquid node
                */
@@ -1680,9 +1683,12 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                }
 
                loopcount++;
-               //if(loopcount >= 100000)
-               if(loopcount >= initial_size * 1)
+               if(loopcount >= initial_size * 1 || loopcount >= 1000)
                        break;
+                       
+               }catch(InvalidPositionException &e)
+               {
+               }
        }
        //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
 }
@@ -1698,8 +1704,8 @@ ServerMap::ServerMap(std::string savedir):
        
        //m_chunksize = 64;
        //m_chunksize = 16; // Too slow
-       m_chunksize = 8; // Takes a few seconds
-       //m_chunksize = 4;
+       //m_chunksize = 8; // Takes a few seconds
+       m_chunksize = 4; // Too small?
        //m_chunksize = 2;
        
        // TODO: Save to and load from a file
@@ -1954,61 +1960,288 @@ double tree_amount_2d(u64 seed, v2s16 p)
 
 #define AVERAGE_MUD_AMOUNT 4
 
-double base_rock_level_2d(u64 seed, v2s16 p)
+double get_mud_amount(u64 seed, v2f p)
+{
+       return ((float)AVERAGE_MUD_AMOUNT + 2.5 * noise2d_perlin(
+                       0.5+p.X/200, 0.5+p.Y/200,
+                       seed+1, 5, 0.65));
+}
+
+// -1->0, 0->1, 1->0
+double contour(double v)
 {
-       // The base ground level
-       double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
-                       + 25. * noise2d_perlin(
+       v = fabs(v);
+       if(v >= 1.0)
+               return 0.0;
+       return (1.0-v);
+}
+
+// -1->0, -r->1, 0->1, r->1, 1->0
+double contour_flat_top(double v, double r)
+{
+       v = fabs(v);
+       if(v >= 1.0)
+               return 0.0;
+       double rmax = 0.999;
+       if(r >= rmax)
+               r = rmax;
+       if(v <= r)
+               return 1.0;
+       v -= r;
+       return ((1.0-r)-v) / (1.0-r);
+       //return easeCurve(((1.0-r)-v) / (1.0-r));
+}
+
+double base_rock_level_2d(u64 seed, v2f p)
+{
+       // The ground level (return value)
+       double h = WATER_LEVEL;
+       
+       // Raises from 0 when parameter is -1...1
+       /*double m2 = contour_flat_top(-0.8 + 2.0 * noise2d_perlin(
+                       0.0+(float)p.X/1500., 0.0+(float)p.Y/1500.,
+                       (seed>>32)+34758, 5, 0.55), 0.10);*/
+       /*double m2 = 1.0;
+       if(m2 > 0.0001)
+       {
+               // HUGE mountains
+               double m1 = 200.0 + 300.0 * noise2d_perlin(
+                               0.0+(float)p.X/1000., 0.0+(float)p.Y/1000.,
+                               (seed>>32)+98525, 8, 0.5);
+               h += m1 * m2;
+               //h += 30 * m2;
+       }*/
+
+       // Huge mountains
+       double m3 = 150.0 - 800.0 * noise2d_perlin_abs(
+                       0.5+(float)p.X/2000., 0.5+(float)p.Y/2000.,
+                       (seed>>32)+985251, 9, 0.5);
+       if(m3 > h)
+               h = m3;
+
+       /*double tm2 = contour_flat_top(-1.0 + 3.0 * noise2d_perlin(
+                       0.0+(float)p.X/300., 0.0+(float)p.Y/300.,
+                       (seed>>32)+78593, 5, 0.55), 0.15);
+       h += 30 * tm2;*/
+
+#if 1
+       {
+               double a1 = 30 - 100. * noise2d_perlin_abs(
+                               0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
+                               seed+850342, 5, 0.63);
+               double d = 15;
+               if(a1 > d)
+                       a1 = d + sqrt(a1-d);
+               if(a1 > h)
+                       h = a1;
+       }
+#endif
+
+#if 1
+       double base = 35. * noise2d_perlin(
                        0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
-                       (seed>>32)+654879876, 6, 0.6);
+                       (seed>>32)+653876, 7, 0.55);
+#else
+       double base = 0;
+#endif
        
-       /*// A bit hillier one
-       double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
-                       0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
-                       (seed>>27)+90340, 6, 0.69);
-       if(base2 > base)
-               base = base2;*/
 #if 1
-       // Higher ground level
-       double higher = (double)WATER_LEVEL + 25. + 45. * noise2d_perlin(
+       double higher = 50. * noise2d_perlin(
                        0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
-                       seed+85039, 5, 0.69);
-       //higher = 30; // For debugging
-
-       // Limit higher to at least base
-       if(higher < base)
-               higher = base;
-               
-       // Steepness factor of cliffs
-       double b = 1.0 + 1.0 * noise2d_perlin(
+                       seed+39292, 6, 0.63);
+       /*double higher = 50. * noise2d_perlin_abs(
                        0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
-                       seed-932, 7, 0.7);
-       b = rangelim(b, 0.0, 1000.0);
-       b = pow(b, 5);
-       b *= 7;
-       b = rangelim(b, 3.0, 1000.0);
-       //dstream<<"b="<<b<<std::endl;
-       //double b = 20;
-
-       // Offset to more low
-       double a_off = -0.2;
-       // High/low selector
-       /*double a = 0.5 + b * (a_off + noise2d_perlin(
-                       0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
-                       seed-359, 6, 0.7));*/
-       double a = (double)0.5 + b * (a_off + noise2d_perlin(
-                       0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
-                       seed-359, 5, 0.60));
-       // Limit
-       a = rangelim(a, 0.0, 1.0);
+                       seed+85039, 5, 0.63);*/
+
+       if(higher > base)
+       {
+               // Steepness factor of cliffs
+               double b = 1.0 + 1.0 * noise2d_perlin(
+                               0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
+                               seed-932, 7, 0.7);
+               b = rangelim(b, 0.0, 1000.0);
+               b = pow(b, 5);
+               b *= 7;
+               b = rangelim(b, 3.0, 1000.0);
+               //dstream<<"b="<<b<<std::endl;
+               //double b = 20;
+
+               // Offset to more low
+               //double a_off = -0.30;
+               double a_off = -0.00;
+               // High/low selector
+               double a = (double)0.5 + b * (a_off + noise2d_perlin(
+                               0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
+                               seed-359, 5, 0.6));
+               // Limit
+               a = rangelim(a, 0.0, 1.0);
+               //a = easeCurve(a);
+
+               //dstream<<"a="<<a<<std::endl;
+               
+               h += base*(1.0-a) + higher*a;
+       }
+       else
+       {
+               h += base;
+       }
+#else
+       h += base;
+#endif
 
-       //dstream<<"a="<<a<<std::endl;
+       return h;
+}
+
+double base_rock_level_2d(u64 seed, v2s16 p)
+{
+       return base_rock_level_2d(seed, v2f((float)p.X, (float)p.Y));
+}
+
+v2f base_ground_turbulence(u64 seed, v3f p)
+{
+       double f = 12;
+
+       double v1 = f * noise3d_perlin(
+                       0.5+p.X/200,
+                       0.5+p.Y/200,
+                       0.5+p.Z/200,
+                       seed+4045, 5, 0.7);
+
+       double v2 = f * noise3d_perlin(
+                       0.5+p.X/200,
+                       0.5+p.Y/200,
+                       0.5+p.Z/200,
+                       seed+9495, 5, 0.7);
        
-       double h = base*(1.0-a) + higher*a;
+       return v2f(v1, v2);
+}
+
+bool is_carved(u64 seed, v3f p)
+{
+#if 1
+       double v1 = noise3d_perlin_abs(
+                       0.5+p.X/200,
+                       0.5+p.Y/200,
+                       0.5+p.Z/200,
+                       seed+657890854, 5, 0.7);
+       
+       if(v1 > 1.5)
+               return true;
+#endif
+
+#if 0
+       double v2 = noise3d_perlin_abs(
+                       0.5+p.X/200,
+                       0.5+p.Y/200,
+                       0.5+p.Z/200,
+                       seed+657890854, 5, 0.7);
+#if 0
+       double v3 = noise3d_perlin_abs(
+                       0.5+p.X/200,
+                       0.5+p.Y/200,
+                       0.5+p.Z/200,
+                       seed+657890854, 5, 0.7);
 #else
-       double h = base;
+       double v3 = 1.0;
 #endif
-       return h;
+       double v23 = v2*v3;
+       if(v23 > 0.7)
+               return true;
+#endif
+       
+       double f = 10.0;
+       double y_div = 1.5;
+
+       double v4 = contour(f*noise3d_perlin(
+                       0.5+p.X/200,
+                       0.5+p.Y/200*y_div,
+                       0.5+p.Z/200,
+                       seed+87592, 5, 0.7));
+       // Tilted 90 degrees
+       double v5 = contour(f*noise3d_perlin(
+                       0.5+p.X/200,
+                       0.5+p.Z/200,
+                       0.5+p.Y/200*y_div,
+                       seed+98594, 5, 0.7));
+       
+       double v45 = v4*v5;
+       if(v45 > 2.5/f)
+               return true;
+       
+       return false;
+}
+
+/*
+       if depth_guess!=NULL, it is set to a guessed value of how deep
+       underground the position is.
+*/
+bool is_base_ground(u64 seed, v3f p, double *depth_guess=NULL)
+{
+#if 0
+       // This is used for testing the output of the cave function
+       {
+               if(depth_guess)
+                       *depth_guess = 10;
+               if(p.Y > 50)
+                       return false;
+               return is_carved(seed, p);
+       }
+#endif
+
+       v2f t = base_ground_turbulence(seed, p);
+
+       double surface_y_f = base_rock_level_2d(seed, v2f(p.X+t.X, p.Z+t.Y));
+
+       /*if(depth_guess)
+               *depth_guess = surface_y_f - p.Y;*/
+       
+       if(depth_guess)
+       {
+               // Find highest surface near current
+               v3f dirs[4] = {
+                       v3f(1,-1,0),
+                       v3f(-1,-1,0),
+                       v3f(0,-1,1),
+                       v3f(0,-1,-1)
+               };
+               double s2 = surface_y_f;
+               for(u32 i=0; i<4; i++)
+               {
+                       v3f dir = dirs[i];
+                       v2f l = v2f(p.X+t.X+dir.X, p.Z+t.Y+dir.Z);
+                       double s = base_rock_level_2d(seed, l);
+                       if(s > s2)
+                               s2 = s;
+               }
+               *depth_guess = s2 - p.Y;
+       }
+       
+       /*if(depth_guess)
+       {
+               // Check a bit lower also, take highest surface
+               v2f t2 = base_ground_turbulence(seed, p + v3f(0,-2,0));
+               double s2 = base_rock_level_2d(seed, v2f(p.X+t2.X, p.Z+t2.Y));
+               if(s2 > surface_y_f)
+                       *depth_guess = s2 - p.Y;
+               else
+                       *depth_guess = surface_y_f - p.Y;
+       }*/
+       
+       /*if(depth_guess)
+       {
+               // Guess surface point
+               v3f p2(p.X, surface_y_f, p.Z);
+               v2f t2 = base_ground_turbulence
+               double u1 = 
+               double s1 = base_rock_level_2d(seed, v2f(p.X+v1,p.Z+v2));
+       }*/
+
+       bool is_ground = (p.Y <= surface_y_f);
+       
+       if(is_carved(seed, p))
+               is_ground = false;
+
+       return is_ground;
 }
 
 #define VMANIP_FLAG_DUNGEON VOXELFLAG_CHECKED1
@@ -2023,6 +2256,11 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 {
        DSTACK(__FUNCTION_NAME);
 
+       // Shall be not used now
+       //assert(0);
+
+#if 0
+
        /*
                Don't generate if already fully generated
        */
@@ -2163,7 +2401,8 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
        
        {
        // 22ms @cs=8
-       //TimeTaker timer1("ground level");
+       TimeTaker timer1("ground level");
+       dstream<<"Generating base ground..."<<std::endl;
 
        for(s16 x=0; x<sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
        for(s16 z=0; z<sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
@@ -2172,7 +2411,79 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
                v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
                
                /*
-                       Skip of already generated
+                       Skip if already generated
+               */
+               {
+                       v3s16 p(p2d.X, y_nodes_min, p2d.Y);
+                       if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
+                               continue;
+               }
+
+               v2f p2df(p2d.X, p2d.Y);
+
+               {
+                       // Use fast index incrementing
+                       v3s16 em = vmanip.m_area.getExtent();
+                       s16 min = y_nodes_min;
+                       s16 max = y_nodes_max;
+                       /*s16 min = -10;
+                       s16 max = 20;*/
+                       //float surface_y_f = base_rock_level_2d(m_seed, p2df);
+                       u32 i = vmanip.m_area.index(v3s16(p2d.X, min, p2d.Y));
+                       for(s16 y=min; y<=max; y++)
+                       {
+#if 1
+                               bool is = is_base_ground(m_seed, v3f(p2df.X,y,p2df.Y));
+                               if(is)
+                                       vmanip.m_data[i].d = CONTENT_STONE;
+                               else
+                                       vmanip.m_data[i].d = CONTENT_AIR;
+#endif
+#if 0
+                               double v = noise3d_perlin(
+                                               0.5+(float)p2d.X/200,
+                                               0.5+(float)y/200,
+                                               0.5+(float)p2d.Y/200,
+                                               m_seed+293, 6, 0.55);
+                               if(v > 0.0)
+                                       vmanip.m_data[i].d = CONTENT_STONE;
+                               else
+                                       vmanip.m_data[i].d = CONTENT_AIR;
+#endif
+#if 0
+                               /*double v1 = 5 * noise3d_perlin(
+                                               0.5+(float)p2df.X/200,
+                                               0.5+(float)y/200,
+                                               0.5+(float)p2df.Y/200,
+                                               m_seed+293, 6, 0.55);
+
+                               double v2 = 5 * noise3d_perlin(
+                                               0.5+(float)p2df.X/200,
+                                               0.5+(float)y/200,
+                                               0.5+(float)p2df.Y/200,
+                                               m_seed+293, 6, 0.55);*/
+
+                               double v1 = 0;
+                               double v2 = 0;
+
+                               float surface_y_f = base_rock_level_2d(m_seed, p2df+v2f(v1,v2));
+
+                               if(y <= surface_y_f)
+                                       vmanip.m_data[i].d = CONTENT_STONE;
+                               else
+                                       vmanip.m_data[i].d = CONTENT_AIR;
+#endif
+
+                               vmanip.m_area.add_y(em, i, 1);
+                       }
+               }
+
+#if 0
+               // Node position
+               v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
+
+               /*
+                       Skip if already generated
                */
                {
                        v3s16 p(p2d.X, y_nodes_min, p2d.Y);
@@ -2214,6 +2525,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
                                vmanip.m_area.add_y(em, i, 1);
                        }
                }
+#endif
        }
        
        }//timer1
@@ -2235,8 +2547,8 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
        /*
                Loop this part, it will make stuff look older and newer nicely
        */
-       //for(u32 i_age=0; i_age<1; i_age++)
-       for(u32 i_age=0; i_age<2; i_age++)
+       u32 age_count = 2;
+       for(u32 i_age=0; i_age<age_count; i_age++)
        { // Aging loop
 
        {
@@ -2732,9 +3044,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
                v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
                
                // Randomize mud amount
-               s16 mud_add_amount = (s16)(2.5 + 2.0 * noise2d_perlin(
-                               0.5+(float)p2d.X/200, 0.5+(float)p2d.Y/200,
-                               m_seed+1, 3, 0.55));
+               s16 mud_add_amount = get_mud_amount(m_seed, v2f(p2d.X,p2d.Y))/age_count;
 
                // Find ground level
                s16 surface_y = find_ground_level_clever(vmanip, p2d);
@@ -2777,7 +3087,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
        }//timer1
        {
        // 340ms @cs=8
-       TimeTaker timer1("flow mud");
+       //TimeTaker timer1("flow mud");
 
        /*
                Flow mud away from steep edges
@@ -3447,57 +3757,6 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
        }
 #endif
 
-#if 0
-       for(s16 x=lighting_min_d+1;
-                       x<=lighting_max_d-1;
-                       x++)
-       for(s16 z=lighting_min_d+1;
-                       z<=lighting_max_d-1;
-                       z++)
-       {
-               // Node position in 2d
-               v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
-               
-               /*
-                       Apply initial sunlight
-               */
-               {
-                       u8 light = LIGHT_SUN;
-                       v3s16 em = vmanip.m_area.getExtent();
-                       s16 y_start = y_nodes_max;
-                       u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
-                       for(s16 y=y_start; y>=y_nodes_min; y--)
-                       {
-                               MapNode *n = &vmanip.m_data[i];
-
-                               if(light_propagates_content(n->d) == false)
-                               {
-                                       light = 0;
-                               }
-                               else if(light != LIGHT_SUN
-                                       || sunlight_propagates_content(n->d) == false)
-                               {
-                                       if(light > 0)
-                                               light--;
-                               }
-                               
-                               n->setLight(LIGHTBANK_DAY, light);
-                               n->setLight(LIGHTBANK_NIGHT, 0);
-                               
-                               // This doesn't take much time
-                               if(light != 0)
-                               {
-                                       // Insert light source
-                                       light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
-                               }
-                               
-                               // Increment index by y
-                               vmanip.m_area.add_y(em, i, -1);
-                       }
-               }
-       }
-#endif
-
        }//timer1
 
        // Spread light around
@@ -3533,6 +3792,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
                }
        }
 
+#endif
        
        /*
                Create chunk metadata
@@ -3581,6 +3841,9 @@ MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
                        <<"("<<chunkpos1.X<<","<<chunkpos1.Y<<")"
                        <<std::endl;
        
+       // Shall be not used now
+       //assert(0);
+       
        /*for(s16 x=-1; x<=1; x++)
        for(s16 y=-1; y<=1; y++)*/
        for(s16 x=-0; x<=0; x++)
@@ -3709,13 +3972,6 @@ MapSector * ServerMap::emergeSector(v2s16 p2d,
                        <<p2d.X<<","<<p2d.Y<<" and chunk is already generated. "
                        <<std::endl;
 
-#if 0
-       dstream<<"WARNING: Creating an empty sector."<<std::endl;
-
-       return createSector(p2d);
-       
-#endif
-       
 #if 1
        dstream<<"WARNING: Forcing regeneration of chunk."<<std::endl;
 
@@ -3731,7 +3987,14 @@ MapSector * ServerMap::emergeSector(v2s16 p2d,
        
        dstream<<"ERROR: Could not get sector from anywhere."<<std::endl;
        
-       assert(0);
+       //assert(0);
+#endif
+       
+#if 1
+       dstream<<"WARNING: Creating an empty sector."<<std::endl;
+
+       return createSector(p2d);
+       
 #endif
        
        /*
@@ -3765,6 +4028,7 @@ MapBlock * ServerMap::generateBlock(
        v2s16 p2d(p.X, p.Z);
        s16 block_y = p.Y;
        v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
+       v3s16 p_nodes = p * MAP_BLOCKSIZE;
        
        /*
                Do not generate over-limit
@@ -3797,99 +4061,324 @@ MapBlock * ServerMap::generateBlock(
        
        s32 lowest_ground_y = 32767;
        s32 highest_ground_y = -32768;
-       
-       for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
-       for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+
+       enum{
+               BT_GROUND,
+               BT_SURFACE,
+               BT_SKY
+       } block_type = BT_SURFACE;
+
+       {// ground_timer (0ms or ~100ms)
+       //TimeTaker ground_timer("Ground generation");
+
+       /*
+               Approximate whether this block is a surface block, an air
+               block or a ground block.
+
+               This shall never mark a surface block as non-surface.
+       */
+
        {
-               //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
+               /*
+                       Estimate surface at different positions of the block, to
+                       try to accomodate the effect of turbulence.
+               */
+               v3f checklist[] = {
+                       v3f(0,0,0),
+                       v3f(0,1,0),
+                       v3f(0,1,1),
+                       v3f(0,0,1),
+                       v3f(1,0,0),
+                       v3f(1,1,0),
+                       v3f(1,1,1),
+                       v3f(1,0,1),
+                       v3f(0.5,0.5,0.5),
+               };
+               v3f p_nodes_f = intToFloat(p_nodes, 1);
+               float surface_y_max = -1000000;
+               float surface_y_min = 1000000;
+               for(u32 i=0; i<sizeof(checklist)/sizeof(checklist[0]); i++)
+               {
+                       v3f p_map_f = p_nodes_f + checklist[i]*MAP_BLOCKSIZE;
 
-               //s16 surface_y = 0;
+                       double depth_guess;
+                       bool is_ground = is_base_ground(m_seed, p_map_f, &depth_guess);
+                       
+                       // Estimate the surface height
+                       float surface_y_f = p_map_f.Y + depth_guess;
 
-               s16 surface_y = base_rock_level_2d(m_seed, p2d_nodes+v2s16(x0,z0))
-                               + AVERAGE_MUD_AMOUNT;
+                       if(surface_y_f > surface_y_max)
+                               surface_y_max = surface_y_f;
+                       if(surface_y_f < surface_y_min)
+                               surface_y_min = surface_y_f;
+               }
 
-               if(surface_y < lowest_ground_y)
-                       lowest_ground_y = surface_y;
-               if(surface_y > highest_ground_y)
-                       highest_ground_y = surface_y;
+               float block_low_y_f = p_nodes_f.Y;
+               float block_high_y_f = p_nodes_f.Y + MAP_BLOCKSIZE;
 
-               s32 surface_depth = AVERAGE_MUD_AMOUNT;
+               /*dstream<<"surface_y_max="<<surface_y_max
+                               <<", surface_y_min="<<surface_y_min
+                               <<", block_low_y_f="<<block_low_y_f
+                               <<", block_high_y_f="<<block_high_y_f
+                               <<std::endl;*/
                
-               for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+               // A fuzzyness value
+               // Must accomodate mud and turbulence holes
+               float d_down = 16;
+               // Must accomodate a bit less
+               float d_up = 5;
+
+               if(block_high_y_f < surface_y_min - d_down)
                {
-                       s16 real_y = block_y * MAP_BLOCKSIZE + y0;
-                       MapNode n;
-                       /*
-                               Calculate lighting
-                               
-                               NOTE: If there are some man-made structures above the
-                               newly created block, they won't be taken into account.
-                       */
-                       if(real_y > surface_y)
-                               n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
+                       //dstream<<"BT_GROUND"<<std::endl;
+                       // A ground block
+                       //block_type = BT_GROUND;
+                       // Handled as surface because of caves
+                       block_type = BT_SURFACE;
+               }
+               else if(block_low_y_f >= surface_y_max + d_up
+                               && block_low_y_f > WATER_LEVEL + d_up)
+               {
+                       //dstream<<"BT_SKY"<<std::endl;
+                       // A sky block
+                       block_type = BT_SKY;
+               }
+               else
+               {
+                       //dstream<<"BT_SURFACE"<<std::endl;
+                       // A surface block
+                       block_type = BT_SURFACE;
+               }
 
-                       /*
-                               Calculate material
-                       */
+               if(block_type == BT_GROUND || block_type == BT_SKY)
+               {
+                       lowest_ground_y = surface_y_min;
+                       highest_ground_y = surface_y_max;
+               }
+       }
+       
+       if(block_type == BT_SURFACE)
+       {
+               /*
+                       Generate ground precisely
+               */
+               
+               for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+               for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+               {
+                       //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
 
-                       // If node is over heightmap y, it's air or water
-                       if(real_y > surface_y)
-                       {
-                               // If under water level, it's water
-                               if(real_y < WATER_LEVEL)
-                               {
-                                       n.d = water_material;
-                                       n.setLight(LIGHTBANK_DAY,
-                                                       diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
-                                       /*
-                                               Add to transforming liquid queue (in case it'd
-                                               start flowing)
-                                       */
-                                       v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
-                                       m_transforming_liquid.push_back(real_pos);
-                               }
-                               // else air
-                               else
-                                       n.d = CONTENT_AIR;
-                       }
-                       // Else it's ground or dungeons (air)
-                       else
+                       //s16 surface_y = 0;
+
+                       /*s16 surface_y = base_rock_level_2d(m_seed, p2d_nodes+v2s16(x0,z0))
+                                       + AVERAGE_MUD_AMOUNT;
+
+                       if(surface_y < lowest_ground_y)
+                               lowest_ground_y = surface_y;
+                       if(surface_y > highest_ground_y)
+                               highest_ground_y = surface_y;*/
+
+                       v2s16 real_p2d = v2s16(x0,z0) + p2d*MAP_BLOCKSIZE;
+
+                       //s32 surface_depth = AVERAGE_MUD_AMOUNT;
+                       s16 surface_depth = get_mud_amount(m_seed, v2f(real_p2d.X,real_p2d.Y));
+                       
+                       for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
                        {
-                               // If it's surface_depth under ground, it's stone
-                               if(real_y <= surface_y - surface_depth)
+       #if 1
+                               s16 real_y = block_y * MAP_BLOCKSIZE + y0;
+                               v3s16 real_pos = v3s16(x0,y0,z0) + p_nodes;
+                               MapNode n;
+                               /*
+                                       Calculate lighting
+                                       
+                                       NOTE: If there are some man-made structures above the
+                                       newly created block, they won't be taken into account.
+                               */
+                               /*if(real_y > surface_y)
+                                       n.setLight(LIGHTBANK_DAY, LIGHT_SUN);*/
+
+                               /*
+                                       Calculate material
+                               */
+                               
+                               double depth_guess;
+                               bool is_ground = is_base_ground(m_seed,
+                                               intToFloat(real_pos, 1), &depth_guess);
+                               
+                               // Estimate the surface height
+                               float surface_y_f = (float)real_y + depth_guess;
+                               s16 surface_y = real_y + depth_guess;
+                               
+                               // Get some statistics of surface height
+                               if(surface_y < lowest_ground_y)
+                                       lowest_ground_y = surface_y;
+                               if(surface_y > highest_ground_y)
+                                       highest_ground_y = surface_y;
+
+                               // If node is not ground, it's air or water
+                               if(is_ground == false)
                                {
-                                       n.d = CONTENT_STONE;
+                                       // If under water level, it's water
+                                       if(real_y < WATER_LEVEL)
+                                       {
+                                               n.d = water_material;
+                                               n.setLight(LIGHTBANK_DAY,
+                                                               diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
+                                               /*
+                                                       Add to transforming liquid queue (in case it'd
+                                                       start flowing)
+                                               */
+                                               m_transforming_liquid.push_back(real_pos);
+                                       }
+                                       // else air
+                                       else
+                                               n.d = CONTENT_AIR;
                                }
+                               // Else it's ground or dungeons (air)
                                else
                                {
-                                       // It is mud if it is under the first ground
-                                       // level or under water
-                                       if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
+                                       // If it's surface_depth under ground, it's stone
+                                       if((float)real_y <= surface_y_f - surface_depth - 0.75)
                                        {
-                                               n.d = CONTENT_MUD;
+                                               n.d = CONTENT_STONE;
+                                       }
+                                       else if(surface_y_f <= WATER_LEVEL + 2.0)
+                                       {
+                                               n.d = CONTENT_SAND;
                                        }
                                        else
                                        {
-                                               n.d = CONTENT_GRASS;
+                                               /*// It is mud if it is under the first ground
+                                               // level or under water
+                                               if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
+                                               {
+                                                       n.d = CONTENT_MUD;
+                                               }
+                                               else
+                                               {
+                                                       n.d = CONTENT_GRASS;
+                                               }*/
+
+                                               n.d = CONTENT_MUD;
+                                               
+                                               /*// If under water level, it's mud
+                                               if(real_y < WATER_LEVEL)
+                                                       n.d = CONTENT_MUD;
+                                               // Only the topmost node is grass
+                                               else if(real_y <= surface_y - 1)
+                                                       n.d = CONTENT_MUD;
+                                               else
+                                                       n.d = CONTENT_GRASS;*/
                                        }
+                               }
 
-                                       //n.d = CONTENT_MUD;
+                               block->setNode(v3s16(x0,y0,z0), n);
+       #endif
+       #if 0
+                               s16 real_y = block_y * MAP_BLOCKSIZE + y0;
+                               MapNode n;
+                               /*
+                                       Calculate lighting
                                        
-                                       /*// If under water level, it's mud
+                                       NOTE: If there are some man-made structures above the
+                                       newly created block, they won't be taken into account.
+                               */
+                               if(real_y > surface_y)
+                                       n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
+
+                               /*
+                                       Calculate material
+                               */
+
+                               // If node is over heightmap y, it's air or water
+                               if(real_y > surface_y)
+                               {
+                                       // If under water level, it's water
                                        if(real_y < WATER_LEVEL)
-                                               n.d = CONTENT_MUD;
-                                       // Only the topmost node is grass
-                                       else if(real_y <= surface_y - 1)
-                                               n.d = CONTENT_MUD;
+                                       {
+                                               n.d = water_material;
+                                               n.setLight(LIGHTBANK_DAY,
+                                                               diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
+                                               /*
+                                                       Add to transforming liquid queue (in case it'd
+                                                       start flowing)
+                                               */
+                                               v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
+                                               m_transforming_liquid.push_back(real_pos);
+                                       }
+                                       // else air
                                        else
-                                               n.d = CONTENT_GRASS;*/
+                                               n.d = CONTENT_AIR;
                                }
+                               // Else it's ground or dungeons (air)
+                               else
+                               {
+                                       // If it's surface_depth under ground, it's stone
+                                       if(real_y <= surface_y - surface_depth)
+                                       {
+                                               n.d = CONTENT_STONE;
+                                       }
+                                       else
+                                       {
+                                               // It is mud if it is under the first ground
+                                               // level or under water
+                                               if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
+                                               {
+                                                       n.d = CONTENT_MUD;
+                                               }
+                                               else
+                                               {
+                                                       n.d = CONTENT_GRASS;
+                                               }
+
+                                               //n.d = CONTENT_MUD;
+                                               
+                                               /*// If under water level, it's mud
+                                               if(real_y < WATER_LEVEL)
+                                                       n.d = CONTENT_MUD;
+                                               // Only the topmost node is grass
+                                               else if(real_y <= surface_y - 1)
+                                                       n.d = CONTENT_MUD;
+                                               else
+                                                       n.d = CONTENT_GRASS;*/
+                                       }
+                               }
+
+                               block->setNode(v3s16(x0,y0,z0), n);
+       #endif
                        }
+               }
+       }// BT_SURFACE
+       else // BT_GROUND, BT_SKY or anything else
+       {
+               MapNode n_fill;
+               if(block_type == BT_GROUND)
+               {
+                       n_fill.d = CONTENT_STONE;
+               }
+               else if(block_type == BT_SKY)
+               {
+                       n_fill.d = CONTENT_AIR;
+                       n_fill.setLight(LIGHTBANK_DAY, LIGHT_SUN);
+               }
+               else // fallback
+               {
+                       n_fill.d = CONTENT_MESE;
+               }
 
-                       block->setNode(v3s16(x0,y0,z0), n);
+
+               for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+               for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+               for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+               {
+                       //MapNode n = block->getNode(v3s16(x0,y0,z0));
+                       block->setNode(v3s16(x0,y0,z0), n_fill);
                }
        }
        
+       }// ground_timer
+       
        /*
                Calculate some helper variables
        */
@@ -3945,7 +4434,7 @@ MapBlock * ServerMap::generateBlock(
        }
        
        // Fill table
-#if 1
+#if 0
        {
                /*
                        Initialize orp and ors. Try to find if some neighboring
@@ -4087,7 +4576,8 @@ continue_generating:
                // Partly underground = cave
                else if(!completely_underground)
                {
-                       do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
+                       //do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
+                       do_generate_dungeons = false;
                }
                // Found existing dungeon underground
                else if(found_existing && completely_underground)
@@ -4239,8 +4729,8 @@ continue_generating:
                /*
                        Add coal
                */
-               u16 coal_amount = 30;
-               u16 coal_rareness = 60 / coal_amount;
+               u16 coal_amount = 60;
+               u16 coal_rareness = 120 / coal_amount;
                if(coal_rareness == 0)
                        coal_rareness = 1;
                if(myrand()%coal_rareness == 0)
@@ -4271,9 +4761,8 @@ continue_generating:
                /*
                        Add iron
                */
-               //TODO: change to iron_amount or whatever
-               u16 iron_amount = 15;
-               u16 iron_rareness = 60 / iron_amount;
+               u16 iron_amount = 40;
+               u16 iron_rareness = 80 / iron_amount;
                if(iron_rareness == 0)
                        iron_rareness = 1;
                if(myrand()%iron_rareness == 0)
@@ -4330,8 +4819,17 @@ continue_generating:
        */
        sector->insertBlock(block);
        
-       // Lighting is invalid after generation.
-       block->setLightingExpired(true);
+       // Lighting is invalid after generation for surface blocks
+       if(block_type == BT_SURFACE)
+       {
+               block->setLightingExpired(true);
+               lighting_invalidated_blocks.insert(p, block);
+       }
+       // Lighting is not invalid for other blocks
+       else
+       {
+               block->setLightingExpired(false);
+       }
        
 #if 0
        /*
@@ -4536,7 +5034,9 @@ MapBlock * ServerMap::emergeBlock(
        if(does_not_exist)
        {
                block = generateBlock(p, block, sector, changed_blocks,
-                               lighting_invalidated_blocks); 
+                               lighting_invalidated_blocks);
+
+               lighting_expired = block->getLightingExpired();
        }
 
        if(lighting_expired)
@@ -4548,6 +5048,7 @@ MapBlock * ServerMap::emergeBlock(
                Initially update sunlight
        */
        
+       if(lighting_expired)
        {
                core::map<v3s16, bool> light_sources;
                bool black_air_left = false;
index 1cebef63442727eac60cfdb9dd02a42a07e8af08..0692f2b23be74d7a36bd3095890a20322dd91708 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -40,6 +40,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "voxel.h"
 #include "mapchunk.h"
 
+/*
+       Some exposed functions
+*/
+
+double base_rock_level_2d(u64 seed, v2f p);
+
+/*
+*/
+
 #define MAPTYPE_BASE 0
 #define MAPTYPE_SERVER 1
 #define MAPTYPE_CLIENT 2
@@ -531,6 +540,8 @@ public:
 
        bool isSavingEnabled(){ return m_map_saving_enabled; }
 
+       u64 getSeed(){ return m_seed; }
+
 private:
        // Seed used for all kinds of randomness
        u64 m_seed;
index d489ec8ac11d47137c7ddc60e93bec895d5e464f..9594b2961dd765d0b6fa73a6a47b90c20a85aa4d 100644 (file)
@@ -34,6 +34,7 @@ MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
                m_pos(pos),
                changed(true),
                is_underground(false),
+               m_lighting_expired(true),
                m_day_night_differs(false),
                m_objects(this)
 {
index 63682e1e4b3eb4fa87f47dd1f656624764970341..bc51485453897df4414d0b4e61d97602f07551dc 100644 (file)
@@ -92,8 +92,7 @@ double noise3d(int x, int y, int z, int seed)
        return 1.0 - (double)n/1073741824;
 }
 
-#if 0
-// This is too slow
+#if 1
 double noise2d_gradient(double x, double y, int seed)
 {
        // Calculate the integer coordinates
@@ -118,7 +117,7 @@ double noise2d_gradient(double x, double y, int seed)
 }
 #endif
 
-#if 1
+#if 0
 double noise2d_gradient(double x, double y, int seed)
 {
        // Calculate the integer coordinates
@@ -175,6 +174,21 @@ double noise2d_perlin(double x, double y, int seed,
        return a;
 }
 
+double noise2d_perlin_abs(double x, double y, int seed,
+               int octaves, double persistence)
+{
+       double a = 0;
+       double f = 1.0;
+       double g = 1.0;
+       for(int i=0; i<octaves; i++)
+       {
+               a += g * fabs(noise2d_gradient(x*f, y*f, seed+i));
+               f *= 2.0;
+               g *= persistence;
+       }
+       return a;
+}
+
 double noise3d_perlin(double x, double y, double z, int seed,
                int octaves, double persistence)
 {
@@ -190,3 +204,18 @@ double noise3d_perlin(double x, double y, double z, int seed,
        return a;
 }
 
+double noise3d_perlin_abs(double x, double y, double z, int seed,
+               int octaves, double persistence)
+{
+       double a = 0;
+       double f = 1.0;
+       double g = 1.0;
+       for(int i=0; i<octaves; i++)
+       {
+               a += g * fabs(noise3d_gradient(x*f, y*f, z*f, seed+i));
+               f *= 2.0;
+               g *= persistence;
+       }
+       return a;
+}
+
index 63974e86ab38d832937ec7f0941205e0b8b76351..88b995b1e6484098e43b7bfb08d395b540513677 100644 (file)
@@ -32,8 +32,14 @@ double noise3d_gradient(double x, double y, double z, int seed);
 double noise2d_perlin(double x, double y, int seed,
                int octaves, double persistence);
 
+double noise2d_perlin_abs(double x, double y, int seed,
+               int octaves, double persistence);
+
 double noise3d_perlin(double x, double y, double z, int seed,
                int octaves, double persistence);
 
+double noise3d_perlin_abs(double x, double y, double z, int seed,
+               int octaves, double persistence);
+
 #endif
 
index 24f22c6b38c74feaa252a7288c20bf8853b0aad7..e4c92e356bcb274547ba63805779a5ec47bc7de1 100644 (file)
@@ -167,6 +167,26 @@ void * EmergeThread::Thread()
                                                only_from_disk,
                                                changed_blocks,
                                                lighting_invalidated_blocks);
+                               
+                               /*
+                                       While we're at it, generate some other blocks too
+                               */
+                               try
+                               {
+                                       map.emergeBlock(
+                                                       p+v3s16(0,1,0),
+                                                       only_from_disk,
+                                                       changed_blocks,
+                                                       lighting_invalidated_blocks);
+                                       map.emergeBlock(
+                                                       p+v3s16(0,-1,0),
+                                                       only_from_disk,
+                                                       changed_blocks,
+                                                       lighting_invalidated_blocks);
+                               }
+                               catch(InvalidPositionException &e)
+                               {
+                               }
                        }
 
                        // If it is a dummy, block was not found on disk
@@ -208,23 +228,25 @@ void * EmergeThread::Thread()
                                Collect a list of blocks that have been modified in
                                addition to the fetched one.
                        */
-
-                       // Add all the "changed blocks" to modified_blocks
-                       for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
-                                       i.atEnd() == false; i++)
-                       {
-                               MapBlock *block = i.getNode()->getValue();
-                               modified_blocks.insert(block->getPos(), block);
-                       }
                        
-                       /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
-                                       <<" blocks"<<std::endl;*/
+                       if(lighting_invalidated_blocks.size() > 0)
+                               dstream<<"lighting "<<lighting_invalidated_blocks.size()
+                                               <<" blocks"<<std::endl;
                        
-                       //TimeTaker timer("** updateLighting");
+                       // 50-100ms for single block generation
+                       //TimeTaker timer("** EmergeThread updateLighting");
                        
                        // Update lighting without locking the environment mutex,
                        // add modified blocks to changed blocks
                        map.updateLighting(lighting_invalidated_blocks, modified_blocks);
+                       
+                       // Add all from changed_blocks to modified_blocks
+                       for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
+                                       i.atEnd() == false; i++)
+                       {
+                               MapBlock *block = i.getNode()->getValue();
+                               modified_blocks.insert(block->getPos(), block);
+                       }
                }
                // If we got no block, there should be no invalidated blocks
                else
@@ -551,7 +573,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                        {
                                //TODO: Get value from somewhere
                                // Allow only one block in emerge queue
-                               if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
+                               //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
+                               if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
                                {
                                        //dstream<<"Adding block to emerge queue"<<std::endl;
                                        
@@ -1681,10 +1704,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                // Now answer with a TOCLIENT_INIT
                
-               SharedBuffer<u8> reply(2+1+6);
+               SharedBuffer<u8> reply(2+1+6+8);
                writeU16(&reply[0], TOCLIENT_INIT);
                writeU8(&reply[2], deployed);
-               writeV3S16(&reply[3], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
+               writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
+               writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
                // Send as reliable
                m_con.Send(peer_id, 0, reply, true);
 
index cfbb6824906427536d1d4ba8bb0d16356133013c..1f4456653f5a1867e60defac5eb03a7dd3dc79cd 100644 (file)
@@ -486,7 +486,7 @@ void TextureSource::buildMainAtlas()
        sourcelist.push_back("sand.png^mineral_iron.png");
        
        // Padding to disallow texture bleeding
-       s32 padding = 8;
+       s32 padding = 16;
 
        /*
                First pass: generate almost everything
index 2b878b82b6a3c6b7af83d9c31a1c004acace8ee1..ce43f26a3e1f019ffcd2e8862a5a1fea3ed5ee1a 100644 (file)
@@ -39,6 +39,18 @@ extern const v3s16 g_26dirs[26];
 // 26th is (0,0,0)
 extern const v3s16 g_27dirs[27];
 
+inline void writeU64(u8 *data, u64 i)
+{
+       data[0] = ((i>>56)&0xff);
+       data[1] = ((i>>48)&0xff);
+       data[2] = ((i>>40)&0xff);
+       data[3] = ((i>>32)&0xff);
+       data[4] = ((i>>24)&0xff);
+       data[5] = ((i>>16)&0xff);
+       data[6] = ((i>> 8)&0xff);
+       data[7] = ((i>> 0)&0xff);
+}
+
 inline void writeU32(u8 *data, u32 i)
 {
        data[0] = ((i>>24)&0xff);
@@ -58,6 +70,14 @@ inline void writeU8(u8 *data, u8 i)
        data[0] = ((i>> 0)&0xff);
 }
 
+inline u64 readU64(u8 *data)
+{
+       return ((u64)data[0]<<56) | ((u64)data[1]<<48)
+               | ((u64)data[2]<<40) | ((u64)data[3]<<32)
+               | ((u64)data[4]<<24) | ((u64)data[5]<<16)
+               | ((u64)data[6]<<8) | ((u64)data[7]<<0);
+}
+
 inline u32 readU32(u8 *data)
 {
        return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);