diff options
-rw-r--r-- | data/mud.png | bin | 1586 -> 763 bytes | |||
-rw-r--r-- | src/client.cpp | 4 | ||||
-rw-r--r-- | src/client.h | 5 | ||||
-rw-r--r-- | src/clientserver.h | 1 | ||||
-rw-r--r-- | src/main.cpp | 182 | ||||
-rw-r--r-- | src/map.cpp | 881 | ||||
-rw-r--r-- | src/map.h | 11 | ||||
-rw-r--r-- | src/mapblock.cpp | 1 | ||||
-rw-r--r-- | src/noise.cpp | 35 | ||||
-rw-r--r-- | src/noise.h | 6 | ||||
-rw-r--r-- | src/server.cpp | 52 | ||||
-rw-r--r-- | src/tile.cpp | 2 | ||||
-rw-r--r-- | src/utility.h | 20 |
13 files changed, 974 insertions, 226 deletions
diff --git a/data/mud.png b/data/mud.png Binary files differindex 7cb9c89a6..8a72bea90 100644 --- a/data/mud.png +++ b/data/mud.png diff --git a/src/client.cpp b/src/client.cpp index 3ea666549..fe1669ddd 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -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; diff --git a/src/client.h b/src/client.h index fb1e70722..d6496d9df 100644 --- a/src/client.h +++ b/src/client.h @@ -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 diff --git a/src/clientserver.h b/src/clientserver.h index 893bbc1e0..52b4e520e 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -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 diff --git a/src/main.cpp b/src/main.cpp index 2c059840e..be3776623 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -253,11 +253,9 @@ Doing now (most important at the top): * not done
=== Next
-* Continue making the scripting system:
- * Make updateNodeMesh for a less verbose mesh update on add/removenode
- * Switch to using a safe way for the self and env pointers
- * Make some global environment hooks, like node placed and general
- on_step()
+* Make a system for pregenerating quick information for mapblocks, so
+ that the client can show them as cubes before they are actually sent
+ or even generated.
=== Fixmes
* Check the fixmes in the list above
@@ -274,6 +272,11 @@ Doing now (most important at the top): with the ones in utility.h
=== Features
+* Continue making the scripting system:
+ * Make updateNodeMesh for a less verbose mesh update on add/removenode
+ * Switch to using a safe way for the self and env pointers
+ * Make some global environment hooks, like node placed and general
+ on_step()
* Map should make the appropriate MapEditEvents
* Add a global Lua spawn handler and such
* Get rid of MapBlockObjects
@@ -490,6 +493,9 @@ Inventory local_inventory; u16 g_selected_item = 0;
+bool g_show_map_plot = false;
+bool g_refresh_map_plot = true;
+
/*
Debug streams
*/
@@ -606,6 +612,15 @@ public: if(event.KeyInput.PressedDown)
{
//dstream<<"Pressed key: "<<(char)event.KeyInput.Key<<std::endl;
+ if(g_show_map_plot)
+ {
+ if(event.KeyInput.Key == irr::KEY_ESCAPE
+ || event.KeyInput.Key == irr::KEY_KEY_M)
+ {
+ g_show_map_plot = false;
+ }
+ return true;
+ }
/*
Launch menus
@@ -679,6 +694,16 @@ public: <<std::endl;
debug_stacks_print();
}
+
+ // Map plot
+ if(event.KeyInput.Key == irr::KEY_KEY_M)
+ {
+ dstream<<"Map plot requested"<<std::endl;
+ g_show_map_plot = !g_show_map_plot;
+ if(g_show_map_plot)
+ g_refresh_map_plot = true;
+ }
+
}
}
@@ -1110,8 +1135,8 @@ void updateViewingRange(f32 frametime_in, Client *client) f32 wanted_frametime_change = wanted_frametime - frametime;
//dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
- // If needed frametime change is very small, just return
- if(fabs(wanted_frametime_change) < wanted_frametime*0.2)
+ // If needed frametime change is small, just return
+ if(fabs(wanted_frametime_change) < wanted_frametime*0.4)
{
//dstream<<"ignoring small wanted_frametime_change"<<std::endl;
return;
@@ -1239,6 +1264,93 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font, }
}
+video::ITexture *g_map_plot_texture = NULL;
+float g_map_plot_texture_scale = 2;
+
+void updateMapPlotTexture(v2f centerpos, video::IVideoDriver* driver,
+ Client *client)
+{
+ assert(driver);
+ assert(client);
+
+ core::dimension2d<u32> dim(640,480);
+ video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim);
+ assert(img);
+ for(u32 y=0; y<dim.Height; y++)
+ for(u32 x=0; x<dim.Width; x++)
+ {
+ v2f pf = v2f(x, dim.Height-y) - v2f(dim.Width, dim.Height)/2;
+ pf *= g_map_plot_texture_scale;
+ pf += centerpos;
+ double h = base_rock_level_2d(client->getMapSeed(), pf);
+ video::SColor c;
+ //double d1 = 50;
+ /*s32 ux = x - centerpos.X / g_map_plot_texture_scale;
+ s32 uy = y - centerpos.Y / g_map_plot_texture_scale;*/
+
+ // Screen coordinates that are based on multiples of
+ // 1000/g_map_plot_texture_scale and never negative
+ u32 ux = x + (u32)(1000/g_map_plot_texture_scale) * 10;
+ u32 uy = y + (u32)(1000/g_map_plot_texture_scale) * 10;
+ // Offset to center of image
+ ux -= dim.Width/2;
+ uy -= dim.Height/2;
+
+ if(uy % (u32)(1000/g_map_plot_texture_scale) == 0
+ || ux % (u32)(1000/g_map_plot_texture_scale) == 0)
+ c.set(255, 255, 255, 255);
+ else if(uy % (u32)(100/g_map_plot_texture_scale) == 0
+ || ux % (u32)(100/g_map_plot_texture_scale) == 0)
+ c.set(255, 160, 160, 160);
+ else if(h < WATER_LEVEL - 0.5) // Water
+ c.set(255, 50, 50, 255);
+ else if(h < WATER_LEVEL + 2) // Sand
+ c.set(255, 237, 201, 175);
+#if 1
+ else if(h < WATER_LEVEL + 10) // Green
+ c.set(255, 50, 150, 50);
+ else if(h < WATER_LEVEL + 20) // Greenish yellow
+ c.set(255, 110, 185, 50);
+ else if(h < WATER_LEVEL + 50) // Yellow
+ c.set(255, 220, 220, 50);
+ else if(h < WATER_LEVEL + 100) // White
+ c.set(255, 180, 180, 180);
+ else
+ c.set(255, 255, 255, 255);
+#endif
+ /*else if(h < WATER_LEVEL + d1)
+ {
+ h -= WATER_LEVEL;
+ u32 a = (u32)(h / d1 * 255);
+ if(a > 255)
+ a = 255;
+ c.set(255, 0, a, 0);
+ }*/
+#if 0
+ else
+ {
+ h -= WATER_LEVEL;
+ h /= 20.0;
+ h = 1.0 - exp(-h);
+
+ video::SColor c1(255,200,200,50);
+ video::SColor c2(255,0,150,0);
+ c = c1.getInterpolated(c2, h);
+
+ /*u32 a = (u32)(h*255);
+ if(a > 255)
+ a = 255;
+ a = 255-a;
+ c.set(255, a, a, a);*/
+ }
+#endif
+ img->setPixel(x, y, c);
+ }
+ g_map_plot_texture = driver->addTexture("map_plot", img);
+ img->drop();
+ assert(g_map_plot_texture);
+}
+
// Chat data
struct ChatLine
{
@@ -2253,6 +2365,10 @@ int main(int argc, char *argv[]) g_input->step(dtime);
/*
+ Misc. stuff
+ */
+
+ /*
Player speed control
*/
@@ -3021,16 +3137,6 @@ int main(int argc, char *argv[]) }
/*
- Draw crosshair
- */
- driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
- displaycenter + core::vector2d<s32>(10,0),
- video::SColor(255,255,255,255));
- driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
- displaycenter + core::vector2d<s32>(0,10),
- video::SColor(255,255,255,255));
-
- /*
Frametime log
*/
if(g_settings.getBool("frametime_graph") == true)
@@ -3048,6 +3154,31 @@ int main(int argc, char *argv[]) }
}
+ /*
+ Draw map plot
+ */
+ if(g_show_map_plot && g_map_plot_texture)
+ {
+ core::dimension2d<u32> drawdim(640,480);
+ core::rect<s32> dest(v2s32(0,0), drawdim);
+ dest += v2s32(
+ (screensize.X-drawdim.Width)/2,
+ (screensize.Y-drawdim.Height)/2
+ );
+ core::rect<s32> source(v2s32(0,0), g_map_plot_texture->getSize());
+ driver->draw2DImage(g_map_plot_texture, dest, source);
+ }
+
+ /*
+ Draw crosshair
+ */
+ driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
+ displaycenter + core::vector2d<s32>(10,0),
+ video::SColor(255,255,255,255));
+ driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
+ displaycenter + core::vector2d<s32>(0,10),
+ video::SColor(255,255,255,255));
+
} // timer
//timer10.stop();
@@ -3077,8 +3208,23 @@ int main(int argc, char *argv[]) drawtime = drawtimer.stop(true);
/*
- Drawing ends
+ End of drawing
+ */
+
+ /*
+ Refresh map plot if player has moved considerably
*/
+ if(g_refresh_map_plot)
+ {
+ static v3f old_player_pos = v3f(1,1,1) * 10000000;
+ v3f p = client.getPlayerPosition() / BS;
+ if(old_player_pos.getDistanceFrom(p) > 4 * g_map_plot_texture_scale)
+ {
+ updateMapPlotTexture(v2f(p.X,p.Z), driver, &client);
+ old_player_pos = p;
+ }
+ g_refresh_map_plot = false;
+ }
static s16 lastFPS = 0;
//u16 fps = driver->getFPS();
diff --git a/src/map.cpp b/src/map.cpp index 8e71212b0..7b16834e2 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -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; @@ -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; diff --git a/src/mapblock.cpp b/src/mapblock.cpp index d489ec8ac..9594b2961 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -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) { diff --git a/src/noise.cpp b/src/noise.cpp index 63682e1e4..bc5148545 100644 --- a/src/noise.cpp +++ b/src/noise.cpp @@ -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; +} + diff --git a/src/noise.h b/src/noise.h index 63974e86a..88b995b1e 100644 --- a/src/noise.h +++ b/src/noise.h @@ -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 diff --git a/src/server.cpp b/src/server.cpp index 24f22c6b3..e4c92e356 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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); diff --git a/src/tile.cpp b/src/tile.cpp index cfbb68249..1f4456653 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -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 diff --git a/src/utility.h b/src/utility.h index 2b878b82b..ce43f26a3 100644 --- a/src/utility.h +++ b/src/utility.h @@ -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); |