From: Perttu Ahola Date: Sun, 3 Apr 2011 09:14:23 +0000 (+0300) Subject: Revert mapgen to best working version (2) X-Git-Url: http://81.2.79.47:8989/gitweb/?a=commitdiff_plain;h=ee89e29ae10d58a2a3d00641f4e459600a49e09e;p=zefram%2Fminetest%2Fminetest_engine.git Revert mapgen to best working version (2) --- diff --git a/src/main.cpp b/src/main.cpp index fb1b2d8f..b069ee87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -259,11 +259,11 @@ FEATURE: Erosion simulation at map generation time - Simulate rock falling from cliffs when water has removed enough solid rock from the bottom -Mapgen v2 (not doing): +Mapgen v2: * only_from_disk might not work anymore - check and fix it. * Make the generator to run in background and not blocking block placement and transfer -* Add some kind of erosion and other stuff that now is possible +* Possibly add some kind of erosion and other stuff * Make client to fetch stuff asynchronously - Needs method SyncProcessData * Better water generation (spread it to underwater caverns but don't @@ -273,28 +273,6 @@ Mapgen v2 (not doing): the other chunk making nasty straight walls when the other chunk is generated. Fix it. -Mapgen v4 (not doing): -* only_from_disk might not work anymore - check and fix it. -* Make the generator to run in background and not blocking block - placement and transfer -* Make chunks to be tiled vertically too -* MAKE IT FASTER - -Mapgen v3 (not doing): -* Generate trees better - - Add a "trees_added" flag to sector, or something -* How 'bout making turbulence controlled so that for a given 2d position - it can be completely turned off, and is usually so. This way generation - can be sped up a lot. -* Add a way to generate a block partly, so that trees are not added, like - the chunks in v2 -* Add mud "discretely", not by guessing from the noise - -Mapgen v4: -* This will be the final way. -* Generate blocks in the same way as chunks, by copying a VoxelManipulator - from the map that is one block larger in all directions. - Misc. stuff: ------------ * Make an "environment metafile" to store at least time of day @@ -1275,6 +1253,7 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font, } } +#if 0 video::ITexture *g_map_plot_texture = NULL; float g_map_plot_texture_scale = 4; @@ -1416,6 +1395,7 @@ void updateMapPlotTexture(v2f centerpos, video::IVideoDriver* driver, img->drop(); assert(g_map_plot_texture); } +#endif // Chat data struct ChatLine @@ -3219,7 +3199,7 @@ int main(int argc, char *argv[]) x++; } } - +#if 0 /* Draw map plot */ @@ -3234,7 +3214,7 @@ int main(int argc, char *argv[]) core::rect source(v2s32(0,0), g_map_plot_texture->getSize()); driver->draw2DImage(g_map_plot_texture, dest, source); } - +#endif /* Draw crosshair */ @@ -3277,6 +3257,7 @@ int main(int argc, char *argv[]) End of drawing */ +#if 0 /* Refresh map plot if player has moved considerably */ @@ -3291,6 +3272,7 @@ int main(int argc, char *argv[]) } g_refresh_map_plot = false; } +#endif static s16 lastFPS = 0; //u16 fps = driver->getFPS(); diff --git a/src/map.cpp b/src/map.cpp index 651bece4..0ed2d7da 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -183,9 +183,6 @@ bool Map::isNodeUnderground(v3s16 p) light_sources to re-light the area without the removed light. values of from_nodes are lighting values. - - There is a duplicate implementation of this in VoxelManipulator, - which is faster for large volumes */ void Map::unspreadLight(enum LightBank bank, core::map & from_nodes, @@ -369,9 +366,6 @@ void Map::unLightNeighbors(enum LightBank bank, /* Lights neighbors of from_nodes, collects all them and then goes on recursively. - - There is a duplicate implementation of this in VoxelManipulator, - which is faster for large volumes */ void Map::spreadLight(enum LightBank bank, core::map & from_nodes, @@ -846,8 +840,6 @@ void Map::updateLighting(core::map & a_blocks, This is called after changing a node from transparent to opaque. The lighting value of the node should be left as-is after changing other values. This sets the lighting value to 0. - - NOTE: This takes almost no time, the slow one is updateMeshes. */ void Map::addNodeAndUpdate(v3s16 p, MapNode n, core::map &modified_blocks) @@ -1044,7 +1036,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, } /* - NOTE: This takes almost no time, the slow one is updateMeshes. */ void Map::removeNodeAndUpdate(v3s16 p, core::map &modified_blocks) @@ -1431,9 +1422,6 @@ void Map::transformLiquids(core::map & modified_blocks) while(m_transforming_liquid.size() != 0) { - try - { - /* Get a queued transforming liquid node */ @@ -1692,12 +1680,9 @@ void Map::transformLiquids(core::map & modified_blocks) } loopcount++; - if(loopcount >= initial_size * 1 || loopcount >= 1000) + //if(loopcount >= 100000) + if(loopcount >= initial_size * 1) break; - - }catch(InvalidPositionException &e) - { - } } //dstream<<"Map::transformLiquids(): loopcount="<::Iterator i = m_chunks.getIterator(); + for(; i.atEnd() == false; i++) + { + MapChunk *chunk = i.getNode()->getValue(); + delete chunk; + } } /* @@ -1863,11 +1868,8 @@ void make_tree(VoxelManipulator &vmanip, v3s16 p0) { MapNode treenode(CONTENT_TREE); MapNode leavesnode(CONTENT_LEAVES); - leavesnode.setLight(LIGHTBANK_DAY, LIGHT_MAX-1); - vmanip.emerge(VoxelArea(p0-v3s16(2,0,2),p0+v3s16(2,7+2,2))); - - s16 trunk_h = myrand_range(4, 7); + s16 trunk_h = myrand_range(3, 6); v3s16 p1 = p0; for(s16 ii=0; ii -0.25); -} - -bool get_have_sand_ground(u64 seed, v2f p) -{ - double sandnoise = noise2d_perlin( - 0.5+(float)p.X/500, 0.5+(float)p.Y/500, - seed+54290232, 6, 0.65); - return (sandnoise > 1.0); + return 0.04 * (noise-zeroval) / (1.0-zeroval); } -// -1->0, 0->1, 1->0 -double contour(double v) -{ - 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)); -} +#define AVERAGE_MUD_AMOUNT 4 -double base_rock_level_2d(u64 seed, v2f p) +double base_rock_level_2d(u64 seed, v2s16 p) { - // The ground level (return value) - double h = WATER_LEVEL-1.5; - - // 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; - }*/ - - /*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 0 - { - // Large mountains - double m3 = 100.0 - 600.0 * noise2d_perlin_abs( - 0.324+(float)p.X/2000., 0.423+(float)p.Y/2000., - (seed>>32)+985251, 9, 0.55); - if(m3 > h) - h = m3; - } -#endif - -#if 0 - { - // More mountain ranges - double d = 100; - double a1 = d*2.0 - d*7 * noise2d_perlin_abs( - 0.5+(float)p.X/1000., 0.5+(float)p.Y/1000., - seed+850342, 7, 0.55); - /*if(a1 > d) - a1 = d + sqrt(a1-d);*/ - a1 = (1.0 - exp(-a1/d))*d; - /*if(a1 > h) - h = a1;*/ - if(a1 > 0) - h += a1; - } -#endif - -#if 0 - { - // More mountain ranges - double d = 60; - double a1 = d*2.0 - d*7 * noise2d_perlin_abs( - 0.5+(float)p.X/1000., 0.5+(float)p.Y/1000., - seed+850342, 7, 0.55); - /*if(a1 > d) - a1 = d + sqrt(a1-d);*/ - a1 = (1.0 - exp(-a1/d))*d; - /*if(a1 > h) - h = a1;*/ - if(a1 > 0) - h += a1; - } -#endif - -#if 0 - { - // Very steep mountain ranges - double d = 120; - double a1 = d*2 - d*6.5 * noise2d_perlin_abs( - 0.5+(float)p.X/500., 0.5+(float)p.Y/500., - seed+850342, 6, 0.6); - /*if(a1 > d) - a1 = d + sqrt(a1-d);*/ - a1 = (1.0 - exp(-a1/d))*d; - /*if(a1 > h) - h = a1;*/ - if(a1 > 0) - h += a1; - /*double a = noise2d_perlin_abs( - 0.94+(float)p.X/2000., 0.26+(float)p.Y/2000., - (seed>>32)+65012102, 8, 0.50); - double m4 = 100.0 - 400.0 * a; - if(m4 > h) - h = m4;*/ - } -#endif - - /* - The stuff before this comment is usually not used. - The stuff after this comment is usually used. - */ - -#if 1 - { - // Mountains - double m4 = 1.0 - 3.0 * noise2d_perlin_abs( - 0.324+(float)p.X/1000., 0.423+(float)p.Y/1000., - (seed>>32)+65012102, 8, 0.57); - m4 *= 120; - if(m4 > h) - h = m4; - } -#endif - -#if 1 - // Some kind of hill chains or something - { - double a1 = 1.0 - 2.5 * noise2d_perlin_abs( - 0.5+(float)p.X/250., 0.5+(float)p.Y/250., - seed+850342, 5, 0.6); - a1 *= 30; - double d = 15; - if(a1 > d) - a1 = d + sqrt(a1-d); - /*if(a1 > h) - h = a1;*/ - if(a1 > 0) - h += a1; - } -#endif - -#if 1 - double base = -2. + 25. * noise2d_perlin( + // The base ground level + double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT + + 25. * noise2d_perlin( 0.5+(float)p.X/500., 0.5+(float)p.Y/500., - (seed>>32)+653876, 7, 0.65); -#else - double base = 0; -#endif + (seed>>32)+654879876, 6, 0.6); -#if 1 - /* - Combined with turbulence, this thing here is able to make very - awesome terrain, albeit rarely. - - This is also responsible for small islands. - */ - - double higher = 40. * noise2d_perlin( - 0.5+(float)p.X/250., 0.5+(float)p.Y/250., - seed+39292, 6, 0.50); - /*double higher = 50. * noise2d_perlin_abs( + /*// 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+85039, 5, 0.63);*/ - //higher = 25; - - 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, 6, 0.7); - b = rangelim(b, 0.0, 1000.0); + (seed>>27)+90340, 6, 0.69); + if(base2 > base) + base = base2;*/ #if 1 - b = pow(b, 5); - b *= 16; - b = rangelim(b, 3.0, 1000.0); - //dstream<<"b="< 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 + Skip of already generated */ { v3s16 p(p2d.X, y_nodes_min, p2d.Y); @@ -2757,7 +2214,6 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, vmanip.m_area.add_y(em, i, 1); } } -#endif } }//timer1 @@ -2779,8 +2235,8 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, /* Loop this part, it will make stuff look older and newer nicely */ - u32 age_count = 2; - for(u32 i_age=0; i_age -0.15); if(have_sand == false) continue; @@ -3665,6 +3127,9 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, // Don't make a tree under water level if(y < WATER_LEVEL) continue; + // Don't make a tree so high that it doesn't fit + if(y > y_nodes_max - 6) + continue; v3s16 p(x,y,z); /* Trees grow only on mud and grass @@ -3985,22 +3450,73 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, } #endif - }//timer1 - - // Spread light around +#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++) { - TimeTaker timer("generateChunkRaw() spreadLight"); - vmanip.spreadLight(LIGHTBANK_DAY, light_sources); - } - - /* - Generation ended - */ - - timer_generate.stop(); - - /* - Blit generated stuff to map + // 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 + { + TimeTaker timer("generateChunkRaw() spreadLight"); + vmanip.spreadLight(LIGHTBANK_DAY, light_sources); + } + + /* + Generation ended + */ + + timer_generate.stop(); + + /* + Blit generated stuff to map */ { // 70ms @cs=8 @@ -4020,7 +3536,6 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, } } -#endif /* Create chunk metadata @@ -4061,1838 +3576,176 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, */ return chunk; } -#endif -#if 0 -MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, - core::map &changed_blocks, - bool force) +MapChunk* ServerMap::generateChunk(v2s16 chunkpos1, + core::map &changed_blocks) { - DSTACK(__FUNCTION_NAME); - - /* - Don't generate if already fully generated - */ - if(force == false) + dstream<<"generateChunk(): Generating chunk " + <<"("<getGenLevel() == GENERATED_FULLY) - { - dstream<<"generateChunkRaw(): Chunk " - <<"("<setLightingExpired(true); - // Lighting will be calculated - block->setLightingExpired(false); + /* + Do not create over-limit + */ + if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) + throw InvalidPositionException("createSector(): pos. over limit"); - /* - Block gets sunlight if this is true. + /* + Generate blank sector + */ + + sector = new ServerMapSector(this, p2d); + + // Sector position on map in nodes + v2s16 nodepos2d = p2d * MAP_BLOCKSIZE; - This should be set to true when the top side of a block - is completely exposed to the sky. + /* + Insert to container + */ + m_sectors.insert(p2d, sector); + + return sector; +} - Actually this doesn't matter now because the - initial lighting is done here. - */ - block->setIsUnderground(y != y_blocks_max); - } - } - } +MapSector * ServerMap::emergeSector(v2s16 p2d, + core::map &changed_blocks) +{ + DSTACK("%s: p2d=(%d,%d)", + __FUNCTION_NAME, + p2d.X, p2d.Y); /* - Now we have a big empty area. - - Make a ManualMapVoxelManipulator that contains this and the - neighboring chunks + Check chunk status */ + v2s16 chunkpos = sector_to_chunk(p2d); + /*bool chunk_nonvolatile = false; + MapChunk *chunk = getChunk(chunkpos); + if(chunk && chunk->getIsVolatile() == false) + chunk_nonvolatile = true;*/ + bool chunk_nonvolatile = chunkNonVolatile(chunkpos); - ManualMapVoxelManipulator vmanip(this); - // Add the area we just generated + /* + If chunk is not fully generated, generate chunk + */ + if(chunk_nonvolatile == false) { - TimeTaker timer("generateChunkRaw() initialEmerge"); - vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max); + // Generate chunk and neighbors + generateChunk(chunkpos, changed_blocks); } - - // Clear all flags - vmanip.clearFlag(0xff); - - TimeTaker timer_generate("generateChunkRaw() generate"); - + /* - Generate general ground level to full area + Return sector if it exists now */ + MapSector *sector = getSectorNoGenerateNoEx(p2d); + if(sector != NULL) + return sector; - { - // 22ms @cs=8 - TimeTaker timer1("ground level"); - dstream<<"Generating base ground..."< 0.001); - - s16 surface_y = 0; - - float noturb_surface_y_f = base_rock_level_2d(m_seed, p2df); - s16 noturb_surface_y = noturb_surface_y_f; - - { - s16 depth_counter = 0; - s16 min = y_nodes_min; - s16 max = y_nodes_max; - // Use fast index incrementing - v3s16 em = vmanip.m_area.getExtent(); - u32 i = vmanip.m_area.index(v3s16(p2d.X, max, p2d.Y)); - for(s16 y=max; y>=min; y--) - { - v3f p3df(p2df.X, y, p2df.Y); - - bool is_ground = false; - - bool turb_for_node = (turbulence_is_used - && y >= TURBULENCE_BOTTOM_CUTOFF_Y); - - if(is_carved(m_seed, p3df)) - { - is_ground = false; - } - else - { - if(turb_for_node) - { - double depth_guess; - is_ground = is_base_ground(m_seed, - p3df, &depth_guess); - - // Estimate the surface height - surface_y = y + depth_guess; - } - else - { - surface_y = noturb_surface_y; - } - - is_ground = (y <= surface_y); - } - - if(is_ground) - { - //vmanip.m_data[i].d = CONTENT_STONE; - /*if(y > surface_y - mud_amount) - vmanip.m_data[i].d = CONTENT_MUD; - else - vmanip.m_data[i].d = CONTENT_STONE;*/ - if(depth_counter < mud_amount) - vmanip.m_data[i].d = CONTENT_MUD; - else - vmanip.m_data[i].d = CONTENT_STONE; - } - else - vmanip.m_data[i].d = CONTENT_AIR; - - if(is_ground || depth_counter != 0) - depth_counter++; - -#if 0 -#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 -#endif - - vmanip.m_area.add_y(em, i, -1); - } - } - } - - }//timer1 - - { - // 50ms @cs=8 - //TimeTaker timer1("add water"); - - /* - Add water to the central chunk (and a bit more) - */ - - for(s16 x=0-max_spread_amount; - x WATER_LEVEL) - continue;*/ - - /* - Add water on ground - */ - { - v3s16 em = vmanip.m_area.getExtent(); - u8 light = LIGHT_MAX; - // Start at global water surface level - s16 y_start = WATER_LEVEL; - u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y)); - MapNode *n = &vmanip.m_data[i]; - - /*// Add first one to transforming liquid queue, if water - if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE) - { - v3s16 p = v3s16(p2d.X, y_start, p2d.Y); - m_transforming_liquid.push_back(p); - }*/ - - for(s16 y=y_start; y>=y_nodes_min; y--) - { - n = &vmanip.m_data[i]; - - // Stop when there is no water and no air - if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE - && n->d != CONTENT_WATER) - { - /*// Add bottom one to transforming liquid queue - vmanip.m_area.add_y(em, i, 1); - n = &vmanip.m_data[i]; - if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE) - { - v3s16 p = v3s16(p2d.X, y, p2d.Y); - m_transforming_liquid.push_back(p); - }*/ - - break; - } - - // Make water only not in dungeons - if(!(vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON)) - { - n->d = CONTENT_WATERSOURCE; - //n->setLight(LIGHTBANK_DAY, light); - - // Add to transforming liquid queue (in case it'd - // start flowing) - v3s16 p = v3s16(p2d.X, y, p2d.Y); - m_transforming_liquid.push_back(p); - } - - // Next one - vmanip.m_area.add_y(em, i, -1); - if(light > 0) - light--; - } - } - - } - - }//timer1 - - { - //TimeTaker timer1("convert mud to sand"); - - /* - Convert mud to sand - */ - - //s16 mud_add_amount = myrand_range(2, 4); - //s16 mud_add_amount = 0; - - /*for(s16 x=0; x WATER_LEVEL + 2) - continue; - - { - v3s16 em = vmanip.m_area.getExtent(); - s16 y_start = surface_y; - u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y)); - u32 not_sand_counter = 0; - for(s16 y=y_start; y>=y_nodes_min; y--) - { - MapNode *n = &vmanip.m_data[i]; - if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS) - { - n->d = CONTENT_SAND; - } - else - { - not_sand_counter++; - if(not_sand_counter > 3) - break; - } - - vmanip.m_area.add_y(em, i, -1); - } - } - - } - - }//timer1 - - { - // 19ms @cs=8 - //TimeTaker timer1("grow grass"); - - /* - Grow grass - */ - - /*for(s16 x=0-4; x=y_nodes_min; y--) - { - MapNode &n = vmanip.m_data[i]; - if(n.d != CONTENT_AIR - && n.d != CONTENT_LEAVES) - break; - vmanip.m_area.add_y(em, i, -1); - } - if(y >= y_nodes_min) - surface_y = y; - else - surface_y = y_nodes_min; - } - - u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y); - MapNode *n = &vmanip.m_data[i]; - if(n->d == CONTENT_MUD) - n->d = CONTENT_GRASS; - } - - }//timer1 - - { - // 1ms @cs=8 - //TimeTaker timer1("generate trees"); - - /* - Generate some trees - */ - { - // Divide area into parts - s16 div = 8; - s16 sidelen = sectorpos_base_size*MAP_BLOCKSIZE / div; - double area = sidelen * sidelen; - for(s16 x0=0; x0d != CONTENT_MUD && n->d != CONTENT_GRASS) - continue; - } - p.Y++; - // Make a tree - make_tree(vmanip, p); - } - } - /*u32 tree_max = relative_area / 60; - //u32 count = myrand_range(0, tree_max); - for(u32 i=0; i light_sources; - - { - // 750ms @cs=8, can't optimize more - TimeTaker timer1("initial lighting"); - -#if 1 - /* - This has to be 1 smaller than the actual area, because - neighboring nodes are checked. - */ - 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; - bool add_to_sources = false; - 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--; - } - - // This doesn't take much time - if(add_to_sources == false) - { - /* - Check sides. If side is not air or water, start - adding to light_sources. - */ - v3s16 dirs4[4] = { - v3s16(0,0,1), // back - v3s16(1,0,0), // right - v3s16(0,0,-1), // front - v3s16(-1,0,0), // left - }; - for(u32 di=0; di<4; di++) - { - v3s16 dirp = dirs4[di]; - u32 i2 = i; - vmanip.m_area.add_p(em, i2, dirp); - MapNode *n2 = &vmanip.m_data[i2]; - if( - n2->d != CONTENT_AIR - && n2->d != CONTENT_WATERSOURCE - && n2->d != CONTENT_WATER - ){ - add_to_sources = true; - break; - } - } - } - - n->setLight(LIGHTBANK_DAY, light); - n->setLight(LIGHTBANK_NIGHT, 0); - - // This doesn't take much time - if(light != 0 && add_to_sources) - { - // 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 - { - TimeTaker timer("generateChunkRaw() spreadLight"); - vmanip.spreadLight(LIGHTBANK_DAY, light_sources); - } - - /* - Generation ended - */ - - timer_generate.stop(); - - /* - Blit generated stuff to map - */ - { - // 70ms @cs=8 - //TimeTaker timer("generateChunkRaw() blitBackAll"); - vmanip.blitBackAll(&changed_blocks); - } - - /* - Update day/night difference cache of the MapBlocks - */ - { - for(core::map::Iterator i = changed_blocks.getIterator(); - i.atEnd() == false; i++) - { - MapBlock *block = i.getNode()->getValue(); - block->updateDayNightDiff(); - } - } -#endif - - /* - Create chunk metadata - */ - - for(s16 x=-1; x<=1; x++) - for(s16 y=-1; y<=1; y++) - { - v2s16 chunkpos0 = chunkpos + v2s16(x,y); - // Add chunk meta information - MapChunk *chunk = getChunk(chunkpos0); - if(chunk == NULL) - { - chunk = new MapChunk(); - m_chunks.insert(chunkpos0, chunk); - } - //chunk->setIsVolatile(true); - if(chunk->getGenLevel() > GENERATED_PARTLY) - chunk->setGenLevel(GENERATED_PARTLY); - } - - /* - Set central chunk non-volatile - */ - MapChunk *chunk = getChunk(chunkpos); - assert(chunk); - // Set non-volatile - //chunk->setIsVolatile(false); - chunk->setGenLevel(GENERATED_FULLY); - - /* - Save changed parts of map - */ - save(true); - - /* - Return central chunk (which was requested) - */ - return chunk; -} - - -MapChunk* ServerMap::generateChunk(v2s16 chunkpos1, - core::map &changed_blocks) -{ - dstream<<"generateChunk(): Generating chunk " - <<"("<getGenLevel() == GENERATED_FULLY) - continue; - generateChunkRaw(chunkpos0, changed_blocks); - } - - assert(chunkNonVolatile(chunkpos1)); - - MapChunk *chunk = getChunk(chunkpos1); - return chunk; -} -#endif - -ServerMapSector * ServerMap::createSector(v2s16 p2d) -{ - DSTACK("%s: p2d=(%d,%d)", - __FUNCTION_NAME, - p2d.X, p2d.Y); - - /* - Check if it exists already in memory - */ - ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d); - if(sector != NULL) - return sector; - - /* - Try to load it from disk (with blocks) - */ - if(loadSectorFull(p2d) == true) - { - ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d); - if(sector == NULL) - { - dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"< MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) - throw InvalidPositionException("createSector(): pos. over limit"); - - /* - Generate blank sector - */ - - sector = new ServerMapSector(this, p2d); - - // Sector position on map in nodes - v2s16 nodepos2d = p2d * MAP_BLOCKSIZE; - - /* - Insert to container - */ - m_sectors.insert(p2d, sector); - - return sector; -} - -MapSector * ServerMap::emergeSector(v2s16 p2d, - core::map &changed_blocks) -{ - DSTACK("%s: p2d=(%d,%d)", - __FUNCTION_NAME, - p2d.X, p2d.Y); - -#if 0 - /* - Check chunk status - */ - v2s16 chunkpos = sector_to_chunk(p2d); - /*bool chunk_nonvolatile = false; - MapChunk *chunk = getChunk(chunkpos); - if(chunk && chunk->getIsVolatile() == false) - chunk_nonvolatile = true;*/ - bool chunk_nonvolatile = chunkNonVolatile(chunkpos); - - /* - If chunk is not fully generated, generate chunk - */ - if(chunk_nonvolatile == false) - { - // Generate chunk and neighbors - generateChunk(chunkpos, changed_blocks); - } -#endif - - /* - Return sector if it exists now - */ - MapSector *sector = getSectorNoGenerateNoEx(p2d); - if(sector != NULL) - return sector; - - /* - Try to load it from disk - */ - if(loadSectorFull(p2d) == true) - { - MapSector *sector = getSectorNoGenerateNoEx(p2d); - if(sector == NULL) - { - dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"< &changed_blocks, - bool force) -{ - DSTACK(__FUNCTION_NAME); - - /* - Don't generate if already fully generated - */ - if(force == false) - { - MapBlock *block = getBlockNoCreateNoEx(blockpos0); - if(block != NULL && block->isFullyGenerated()) - { - dstream<<"generateBlockRaw(): Block " - <<"("< blocks_created; - - { - //TimeTaker timer("generateBlockRaw() create area"); - - for(s16 x=-1; x<=1; x++) - for(s16 z=-1; z<=1; z++) - { - v2s16 sectorpos = sectorpos0 + v2s16(x,z); - ServerMapSector *sector = createSector(sectorpos); - assert(sector); - - for(s16 y=blockpos0.Y-1; y<=blockpos0.Y+1; y++) - { - v3s16 blockpos(sectorpos.X, y, sectorpos.Y); - - MapBlock *block = getBlockNoCreateNoEx(blockpos); - if(block && block->isDummy() == false) - continue; - - block = createBlock(blockpos); - block->setFullyGenerated(false); - - blocks_created.push_back(blockpos); - - // Lighting won't be calculated - block->setLightingExpired(true); - // Lighting will be calculated - //block->setLightingExpired(false); - - /* - Block gets sunlight if this is true. - - This should be set to true when the top side of a block - is completely exposed to the sky. - - This doesn't matter if the initial lighting is done - here. - */ - //block->setIsUnderground(y != y_blocks_max); - block->setIsUnderground(false); - } - } - } - - /* - Now we have a big empty area of (16x16x16)x27. - - Make a ManualMapVoxelManipulator that contains the whole area. - */ - - ManualMapVoxelManipulator vmanip(this); - // Add the area we just generated - { - //TimeTaker timer("generateBlockRaw() initialEmerge"); - vmanip.initialEmerge(blockpos0-v3s16(1,1,1), blockpos0+v3s16(1,1,1)); - } - - // Clear all flags - vmanip.clearFlag(0xff); - - // Block type of blockpos0 - BlockType center_block_type = BT_SURFACE; - - /* - Generate general ground level to newly created blocks. - Only stone is used and it is converted to other stuff later on. - */ - { - // 22ms @cs=8 - //dstream<<"Generating base ground..."<::Iterator i = blocks_created.begin(); - i != blocks_created.end(); i++) - { - v3s16 blockpos = *i; - v2s16 sectorpos(blockpos.X, blockpos.Z); - - /* - 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. - */ - - BlockType block_type = BT_SURFACE; - v3s16 p_nodes = blockpos * MAP_BLOCKSIZE; - s32 lowest_ground_y = 32767; - s32 highest_ground_y = -32768; - u8 water_material = CONTENT_WATERSOURCE; - - { - /* - 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 surface_y_max) - surface_y_max = surface_y_f; - if(surface_y_f < surface_y_min) - surface_y_min = surface_y_f; - } - - float block_low_y_f = p_nodes_f.Y; - float block_high_y_f = p_nodes_f.Y + MAP_BLOCKSIZE; - - /*dstream<<"surface_y_max="<= surface_y_max + d_up - && block_low_y_f > WATER_LEVEL + d_up) - { - //dstream<<"BT_SKY"<setIsUnderground(true); - } - - /* - If the block has ground, generate ground precisely. - */ - - if(block_type == BT_SURFACE || block_type == BT_GROUND) - { - for(s16 z0=0; z0 0.001); - - float surface_y_f = 0; - s16 surface_y = 0; - - float noturb_surface_y_f = base_rock_level_2d(m_seed, real_p2d_f); - s16 noturb_surface_y = noturb_surface_y_f; - - // Get some statistics of surface height - if(noturb_surface_y < lowest_ground_y) - lowest_ground_y = noturb_surface_y; - if(noturb_surface_y > highest_ground_y) - highest_ground_y = noturb_surface_y; - - // Use fast index incrementing - v3s16 em = vmanip.m_area.getExtent(); - u32 i = vmanip.m_area.index(v3s16( - real_p2d.X, - blockpos.Y*MAP_BLOCKSIZE, - real_p2d.Y)); - for(s16 y0=0; y0= TURBULENCE_BOTTOM_CUTOFF_Y); - - bool is_cavern = false; - - if(is_carved(m_seed, real_pos_f)) - { - is_ground = false; - if(real_y < noturb_surface_y) - is_cavern = true; - } - else - { - if(turb_for_node) - { - double depth_guess; - is_ground = is_base_ground(m_seed, - real_pos_f, &depth_guess); - - // Estimate the surface height - surface_y_f = (float)real_y + depth_guess; - surface_y = real_y + depth_guess; - - // Save 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; - } - else - { - surface_y = noturb_surface_y; - } - - is_ground = (real_y <= surface_y); - } - - // If node is not ground, it's air or water - if(is_ground == false) - { - // If under water level, it's water - if(real_y < WATER_LEVEL && !is_cavern) - { - n.d = water_material; - u8 dist = 16; - if(real_y >= surface_y) - dist = WATER_LEVEL-real_y+1; - n.setLight(LIGHTBANK_DAY, - diminish_light(LIGHT_SUN, dist)); - /* - 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; - - /* - Guess lighting - */ - if(real_y > surface_y + 4) - n.setLight(LIGHTBANK_DAY, LIGHT_SUN); - } - } - // Else it's ground - else - { - if(is_underground_mud(m_seed, real_pos_f)) - n.d = CONTENT_MUD; - else - n.d = CONTENT_STONE; - } - - vmanip.m_data[i] = n; - vmanip.m_area.add_y(em, i, 1); - } - } - }// BT_SURFACE - else // 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; - } - - for(s16 x=0; x=min; y--) - { - if(vmanip.m_data[i].d == CONTENT_STONE) - { - found = true; - break; - } - vmanip.m_area.add_y(em, i, -1); - } - if(found == false) - continue; - // Set mud - s16 mud_amount = get_mud_amount(m_seed, real_p2d_f); - for(s16 j=0; j= WATER_LEVEL) - vmanip.m_data[i].d = CONTENT_GRASS; - else - vmanip.m_data[i].d = CONTENT_MUD; - vmanip.m_area.add_y(em, i, -1); - } - } - } -#endif - } - - /* - Convert mud to sand - */ - if(center_block_type == BT_SURFACE) - { - for(s16 x=0; x= WATER_LEVEL + 2) - continue; - - { - v3s16 em = vmanip.m_area.getExtent(); - s16 y_start = surface_y; - u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y)); - u32 not_sand_counter = 0; - for(s16 y=y_start; y>=y_nodes_min; y--) - { - MapNode *n = &vmanip.m_data[i]; - if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS) - { - n->d = CONTENT_SAND; - } - else - { - not_sand_counter++; - if(not_sand_counter > 3) - break; - } - - vmanip.m_area.add_y(em, i, -1); - } - } - } - } - - /* - Add some minerals - */ - - if(center_block_type == BT_SURFACE || center_block_type == BT_GROUND) - { - s16 underground_level = 1 - blockpos0.Y; - - /* - Add meseblocks - */ - for(s16 i=0; i= (blockpos0.Y+1)*MAP_BLOCKSIZE) - continue; - v3s16 p(x,y,z); - /* - Trees grow only on mud and grass - */ - { - u32 i = vmanip.m_area.index(v3s16(p)); - MapNode *n = &vmanip.m_data[i]; - if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS) - continue; - } - p.Y++; - // Make a tree - make_tree(vmanip, p); - } - } - } - -#if 0 - /* - Initial lighting (sunlight) - TODO: Do the lighting this way, with the VoxelManipulator - */ - - core::map light_sources; - - { - // 750ms @cs=8, can't optimize more - TimeTaker timer1("initial lighting"); - - /* - Go through the edges and apply sunlight to them, not caring - about neighbors - */ - - // Four edges - for(s16 i=0; i<4; i++) - // Edge length - for(s16 j=lighting_min_d; - j<=lighting_max_d; - j++) - { - s16 x; - s16 z; - // +-X - if(i == 0 || i == 1) - { - x = (i==0) ? lighting_min_d : lighting_max_d; - if(i == 0) - z = lighting_min_d; - else - z = lighting_max_d; - } - // +-Z - else - { - z = (i==0) ? lighting_min_d : lighting_max_d; - if(i == 0) - x = lighting_min_d; - else - x = lighting_max_d; - } - - // Node position in 2d - v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z); - - // Loop from top to down - { - 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); - - 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); - } - } - } - /* - This has to be 1 smaller than the actual area, because - neighboring nodes are checked. + Try to load it from disk */ - 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++) + if(loadSectorFull(p2d) == true) { - // Node position in 2d - v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z); - - /* - Apply initial sunlight - */ + MapSector *sector = getSectorNoGenerateNoEx(p2d); + if(sector == NULL) { - u8 light = LIGHT_SUN; - bool add_to_sources = false; - 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--; - } - - // This doesn't take much time - if(add_to_sources == false) - { - /* - Check sides. If side is not air or water, start - adding to light_sources. - */ - v3s16 dirs4[4] = { - v3s16(0,0,1), // back - v3s16(1,0,0), // right - v3s16(0,0,-1), // front - v3s16(-1,0,0), // left - }; - for(u32 di=0; di<4; di++) - { - v3s16 dirp = dirs4[di]; - u32 i2 = i; - vmanip.m_area.add_p(em, i2, dirp); - MapNode *n2 = &vmanip.m_data[i2]; - if( - n2->d != CONTENT_AIR - && n2->d != CONTENT_WATERSOURCE - && n2->d != CONTENT_WATER - ){ - add_to_sources = true; - break; - } - } - } - - n->setLight(LIGHTBANK_DAY, light); - n->setLight(LIGHTBANK_NIGHT, 0); - - // This doesn't take much time - if(light != 0 && add_to_sources) - { - // 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); - } + dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"<::Iterator i = changed_blocks.getIterator(); - i.atEnd() == false; i++) - { - MapBlock *block = i.getNode()->getValue(); - block->updateDayNightDiff(); - } - } -#endif - - /*for(core::map::Iterator - i = changed_blocks*/ - - // Done! - MapBlock *block = getBlockNoCreate(blockpos0); - block->setFullyGenerated(true); + //assert(0); - /* - TODO: Calculate lighting with the VoxelManipulator, not this way - */ - // emergeBlock reads this - block->setLightingExpired(true); - // Also set the above one, trees often will be there - { - MapBlock *block = getBlockNoCreate(blockpos0+v3s16(0,1,0)); - if(block) - block->setLightingExpired(true); - } - - return block; -} - - -/*MapBlock* ServerMap::generateBlock(v3s16 blockpos1, - core::map &changed_blocks)*/ -MapBlock * ServerMap::generateBlock( - v3s16 blockpos1, - MapBlock *original_dummy, - ServerMapSector *sector, - core::map &changed_blocks, - core::map &lighting_invalidated_blocks -) -{ - dstream<<"generateBlock(): Generating block " - <<"("<isFullyGenerated()) - continue; - generateBlockRaw(blockpos0, changed_blocks); - } + sector = getSectorNoGenerateNoEx(p2d); + if(sector != NULL) + return sector; - assert(blockNonVolatile(blockpos1)); - - MapBlock *block = getBlockNoCreate(blockpos1); + dstream<<"ERROR: Could not get sector from anywhere."< surface_y_max) - surface_y_max = surface_y_f; - if(surface_y_f < surface_y_min) - surface_y_min = surface_y_f; - } + //dstream<<"generateBlock: x0="<= surface_y_max + d_up - && block_low_y_f > WATER_LEVEL + d_up) - { - //dstream<<"BT_SKY"< highest_ground_y) + highest_ground_y = surface_y; - 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 || block_type == BT_GROUND) - { - /* - Generate ground precisely - */ + s32 surface_depth = AVERAGE_MUD_AMOUNT; - for(s16 z0=0; z0setNode(v3s16(x0,y0,z0), n); } } -#endif /* This is used for guessing whether or not the block should @@ -6668,8 +4242,8 @@ continue_generating: /* Add coal */ - u16 coal_amount = 60; - u16 coal_rareness = 120 / coal_amount; + u16 coal_amount = 30; + u16 coal_rareness = 60 / coal_amount; if(coal_rareness == 0) coal_rareness = 1; if(myrand()%coal_rareness == 0) @@ -6700,8 +4274,9 @@ continue_generating: /* Add iron */ - u16 iron_amount = 40; - u16 iron_rareness = 80 / iron_amount; + //TODO: change to iron_amount or whatever + u16 iron_amount = 15; + u16 iron_rareness = 60 / iron_amount; if(iron_rareness == 0) iron_rareness = 1; if(myrand()%iron_rareness == 0) @@ -6754,55 +4329,12 @@ continue_generating: } /* - Add block to sector + Add block to sector. */ sector->insertBlock(block); - // Lighting is invalid after generation for surface blocks - if(block_type == BT_SURFACE) - { -#if 1 - block->setLightingExpired(true); - lighting_invalidated_blocks.insert(p, block); -#else - block->setLightingExpired(false); -#endif - } - // Lighting is not invalid for other blocks - else - { - block->setLightingExpired(false); - } - - /* - Add trees - */ -#if 1 - if(some_part_underground && !completely_underground) - { - MapVoxelManipulator vm(this); - - double a = tree_amount_2d(m_seed, v2s16(p_nodes.X+8, p_nodes.Z+8)); - u16 tree_count = (u16)(a*MAP_BLOCKSIZE*MAP_BLOCKSIZE); - for(u16 i=0; isetLightingExpired(true); #if 0 /* @@ -6822,7 +4354,6 @@ continue_generating: return block; } -#endif MapBlock * ServerMap::createBlock(v3s16 p) { @@ -6955,7 +4486,6 @@ MapBlock * ServerMap::emergeBlock( bool does_not_exist = false; bool lighting_expired = false; - bool half_generated = false; MapBlock *block = sector->getBlockNoCreateNoEx(block_y); if(block == NULL) @@ -6970,10 +4500,6 @@ MapBlock * ServerMap::emergeBlock( { lighting_expired = true; } - else if(block->isFullyGenerated() == false) - { - half_generated = true; - } else { // Valid block @@ -6981,27 +4507,24 @@ MapBlock * ServerMap::emergeBlock( return block; } - if(half_generated == false) + /* + If block was not found on disk and not going to generate a + new one, make sure there is a dummy block in place. + */ + if(only_from_disk && (does_not_exist || lighting_expired)) { - /* - If block was not found on disk and not going to generate a - new one, make sure there is a dummy block in place. - */ - if(only_from_disk && (does_not_exist || lighting_expired)) - { - //dstream<<"emergeBlock(): Was not on disk but not generating"<insertBlock(block); - } - // Done. - return block; + // Add block to sector + sector->insertBlock(block); } + // Done. + return block; } //dstream<<"Not found on disk, generating."<getLightingExpired(); + lighting_invalidated_blocks); } if(lighting_expired) @@ -7030,7 +4551,6 @@ MapBlock * ServerMap::emergeBlock( Initially update sunlight */ - if(lighting_expired) { core::map light_sources; bool black_air_left = false; @@ -7156,7 +4676,7 @@ void ServerMap::save(bool only_changed) < list = fs::GetDirListing(m_savedir+"/sectors/"); @@ -7307,8 +4827,7 @@ void ServerMap::saveMapMeta() DSTACK(__FUNCTION_NAME); dstream<<"INFO: ServerMap::saveMapMeta(): " - <<"seed="<::Node *n; + n = m_chunks.find(chunkpos); + if(n == NULL) + return NULL; + return n->getValue(); + } + /* - True if the block and its neighbors are fully generated. - It means the block will not be touched in the future by the - generator. If false, generateBlock will make it true. + True if the chunk and its neighbors are fully generated. + It means the chunk will not be touched in the future by the + generator. If false, generateChunk will make it true. */ - bool blockNonVolatile(v3s16 blockpos) + bool chunkNonVolatile(v2s16 chunkpos) { - for(s16 x=-1; x<=1; x++) - for(s16 y=-1; y<=1; y++) - for(s16 z=-1; z<=1; z++) + /*for(s16 x=-1; x<=1; x++) + for(s16 y=-1; y<=1; y++)*/ + s16 x=0; + s16 y=0; { - v3s16 blockpos0 = blockpos + v3s16(x,y,z); - MapBlock *block = getBlockNoCreateNoEx(blockpos); - if(block == NULL) + v2s16 chunkpos0 = chunkpos + v2s16(x,y); + MapChunk *chunk = getChunk(chunkpos); + if(chunk == NULL) return false; - if(block->isFullyGenerated() == false) + if(chunk->getGenLevel() != GENERATED_FULLY) return false; } return true; } + /* + Generate a chunk. + + All chunks touching this one can be altered also. + */ + MapChunk* generateChunkRaw(v2s16 chunkpos, + core::map &changed_blocks, + bool force=false); + + /* + Generate a chunk and its neighbors so that it won't be touched + anymore. + */ + MapChunk* generateChunk(v2s16 chunkpos, + core::map &changed_blocks); + /* Generate a sector. + + This is mainly called by generateChunkRaw. */ //ServerMapSector * generateSector(v2s16 p); @@ -384,27 +425,6 @@ public: return emergeSector(p, changed_blocks); } - /*MapBlock * generateBlock( - v3s16 p, - MapBlock *original_dummy, - ServerMapSector *sector, - core::map &changed_blocks, - core::map &lighting_invalidated_blocks - );*/ - - /* - Generate a block. - - All blocks touching this one can be altered also. - */ - MapBlock* generateBlockRaw(v3s16 blockpos, - core::map &changed_blocks, - bool force=false); - - /* - Generate a block and its neighbors so that it won't be touched - anymore. - */ MapBlock * generateBlock( v3s16 p, MapBlock *original_dummy, @@ -412,8 +432,6 @@ public: core::map &changed_blocks, core::map &lighting_invalidated_blocks ); - /*MapBlock* generateBlock(v3s16 blockpos, - core::map &changed_blocks);*/ /* Get a block from somewhere. @@ -486,6 +504,9 @@ public: void saveMapMeta(); void loadMapMeta(); + void saveChunkMeta(); + void loadChunkMeta(); + // The sector mutex should be locked when calling most of these // This only saves sector-specific data such as the heightmap @@ -510,14 +531,17 @@ public: bool isSavingEnabled(){ return m_map_saving_enabled; } - u64 getSeed(){ return m_seed; } - private: // Seed used for all kinds of randomness u64 m_seed; std::string m_savedir; bool m_map_saving_enabled; + + // Chunk size in MapSectors + s16 m_chunksize; + // Chunks + core::map m_chunks; }; /* @@ -641,7 +665,7 @@ public: void updateMeshes(v3s16 blockpos, u32 daynight_ratio); // Update meshes that touch the node - void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio); + //void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio); // For debug printing virtual void PrintInfo(std::ostream &out); diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 94c6ad90..66833add 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -36,7 +36,7 @@ MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy): is_underground(false), m_lighting_expired(true), m_day_night_differs(false), - m_not_fully_generated(false), + //m_not_fully_generated(false), m_objects(this) { data = NULL; @@ -1763,8 +1763,8 @@ void MapBlock::serialize(std::ostream &os, u8 version) flags |= 0x02; if(m_lighting_expired) flags |= 0x04; - if(m_not_fully_generated) - flags |= 0x08; + /*if(m_not_fully_generated) + flags |= 0x08;*/ os.write((char*)&flags, 1); u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; @@ -1887,7 +1887,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version) is_underground = (flags & 0x01) ? true : false; m_day_night_differs = (flags & 0x02) ? true : false; m_lighting_expired = (flags & 0x04) ? true : false; - m_not_fully_generated = (flags & 0x08) ? true : false; + //m_not_fully_generated = (flags & 0x08) ? true : false; // Uncompress data std::ostringstream os(std::ios_base::binary); diff --git a/src/mapblock.h b/src/mapblock.h index 97129bd3..3614d136 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -244,16 +244,15 @@ public: return m_lighting_expired; } - bool isFullyGenerated() + /*bool isFullyGenerated() { return !m_not_fully_generated; } - void setFullyGenerated(bool b) { setChangedFlag(); m_not_fully_generated = !b; - } + }*/ bool isValid() { @@ -680,7 +679,7 @@ private: TODO: Save in file */ - bool m_not_fully_generated; + //bool m_not_fully_generated; MapBlockObjectList m_objects; diff --git a/src/server.cpp b/src/server.cpp index 79600a44..2227cbd0 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -544,10 +544,16 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, block_is_invalid = true; } - if(block->isFullyGenerated() == false) + /*if(block->isFullyGenerated() == false) { block_is_invalid = true; - } + }*/ + + v2s16 p2d(p.X, p.Z); + ServerMap *map = (ServerMap*)(&server->m_env.getMap()); + v2s16 chunkpos = map->sector_to_chunk(p2d); + if(map->chunkNonVolatile(chunkpos) == false) + block_is_invalid = true; } /* @@ -1711,7 +1717,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) writeU16(&reply[0], TOCLIENT_INIT); writeU8(&reply[2], deployed); writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS)); - writeU64(&reply[2+1+6], m_env.getServerMap().getSeed()); + //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed()); + // Send as reliable m_con.Send(peer_id, 0, reply, true);