diff options
Diffstat (limited to 'src/map.cpp')
-rw-r--r-- | src/map.cpp | 330 |
1 files changed, 192 insertions, 138 deletions
diff --git a/src/map.cpp b/src/map.cpp index 119b487db..c8175c4cf 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1692,6 +1692,8 @@ MapBlock * ServerMap::emergeBlock( /* If block doesn't exist, create one. If it exists, it is a dummy. In that case unDummify() it. + + NOTE: This already sets the map as the parent of the block */ if(block == NULL) { @@ -1701,13 +1703,146 @@ MapBlock * ServerMap::emergeBlock( { // Remove the block so that nobody can get a half-generated one. sector->removeBlock(block); - // Allocate the block to be a proper one. + // Allocate the block to contain the generated data block->unDummify(); } + u8 water_material = CONTENT_WATER; + if(g_settings.getBool("endless_water")) + water_material = CONTENT_OCEAN; + + s32 lowest_ground_y = 32767; + s32 highest_ground_y = -32768; + + // DEBUG + //sector->printHeightmaps(); + + for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++) + for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++) + { + //dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl; + + float surface_y_f = sector->getGroundHeight(v2s16(x0,z0)); + //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE); + if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE) + { + dstream<<"WARNING: Surface height not found in sector " + "for block that is being emerged"<<std::endl; + surface_y_f = 0.0; + } + + s16 surface_y = surface_y_f; + //avg_ground_y += surface_y; + if(surface_y < lowest_ground_y) + lowest_ground_y = surface_y; + if(surface_y > highest_ground_y) + highest_ground_y = surface_y; + + s32 surface_depth = 0; + + float slope = sector->getSlope(v2s16(x0,z0)).getLength(); + + //float min_slope = 0.45; + //float max_slope = 0.85; + float min_slope = 0.60; + float max_slope = 1.20; + float min_slope_depth = 5.0; + float max_slope_depth = 0; + + if(slope < min_slope) + surface_depth = min_slope_depth; + else if(slope > max_slope) + surface_depth = max_slope_depth; + else + surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth; + + for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++) + { + 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); + + /* + 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 = water_material; + n.setLight(LIGHTBANK_DAY, + diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1)); + } + // else air + else + 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); + } + } + + /* + Calculate some helper variables + */ + + // Completely underground if the highest part of block is under lowest + // ground height. + // This has to be very sure; it's probably one too strict now but + // that's just better. + bool completely_underground = + block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y; + + bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y; + /* - Create dungeon making table + Generate dungeons */ + + // Initialize temporary table const s32 ued = MAP_BLOCKSIZE; bool underground_emptiness[ued*ued*ued]; for(s32 i=0; i<ued*ued*ued; i++) @@ -1715,7 +1850,7 @@ MapBlock * ServerMap::emergeBlock( underground_emptiness[i] = 0; } - // Generate dungeons + // Fill table { /* Initialize orp and ors. Try to find if some neighboring @@ -1807,7 +1942,17 @@ continue_generating: /* Don't always generate dungeon */ - if(found_existing || rand() % 2 == 0) + bool do_generate_dungeons = true; + if(!some_part_underground) + do_generate_dungeons = false; + else if(!completely_underground) + do_generate_dungeons = rand() % 5; + else if(found_existing) + do_generate_dungeons = true; + else + do_generate_dungeons = rand() % 2; + + if(do_generate_dungeons) { /* Generate some tunnel starting from orp and ors @@ -1820,7 +1965,7 @@ continue_generating: (float)(myrand()%ued)+0.5 ); s16 min_d = 0; - s16 max_d = 4; + s16 max_d = 6; s16 rs = (myrand()%(max_d-min_d+1))+min_d; v3f vec = rp - orp; @@ -1855,136 +2000,33 @@ continue_generating: } } } - - u8 water_material = CONTENT_WATER; - if(g_settings.getBool("endless_water")) - water_material = CONTENT_OCEAN; - - s32 lowest_ground_y = 32767; - s32 highest_ground_y = -32768; - - // DEBUG - //sector->printHeightmaps(); // Set to true if has caves. // Set when some non-air is changed to air when making caves. bool has_caves = false; + /* + Apply temporary cave data to block + */ + for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++) for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++) { - //dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl; - - float surface_y_f = sector->getGroundHeight(v2s16(x0,z0)); - //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE); - if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE) - { - dstream<<"WARNING: Surface height not found in sector " - "for block that is being emerged"<<std::endl; - surface_y_f = 0.0; - } - - s16 surface_y = surface_y_f; - //avg_ground_y += surface_y; - if(surface_y < lowest_ground_y) - lowest_ground_y = surface_y; - if(surface_y > highest_ground_y) - highest_ground_y = surface_y; - - s32 surface_depth = 0; - - float slope = sector->getSlope(v2s16(x0,z0)).getLength(); - - //float min_slope = 0.45; - //float max_slope = 0.85; - float min_slope = 0.60; - float max_slope = 1.20; - float min_slope_depth = 5.0; - float max_slope_depth = 0; - - if(slope < min_slope) - surface_depth = min_slope_depth; - else if(slope > max_slope) - surface_depth = max_slope_depth; - else - surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth; - for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++) { - 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); - - /* - Calculate material - */ + MapNode n = block->getNode(v3s16(x0,y0,z0)); - // 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)); - } - // else air - else - n.d = CONTENT_AIR; - } - // Else it's ground or dungeons (air) - else + // Create dungeons + if(underground_emptiness[ + ued*ued*(z0*ued/MAP_BLOCKSIZE) + +ued*(y0*ued/MAP_BLOCKSIZE) + +(x0*ued/MAP_BLOCKSIZE)]) { - // 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;*/ - } - - // Create dungeons - if(underground_emptiness[ - ued*ued*(z0*ued/MAP_BLOCKSIZE) - +ued*(y0*ued/MAP_BLOCKSIZE) - +(x0*ued/MAP_BLOCKSIZE)]) + if(is_ground_content(n.d)) { - // Has now caves if previous content is air - if(n.d != CONTENT_AIR) - { - has_caves = true; - } - + // Has now caves + has_caves = true; + // Set air to node n.d = CONTENT_AIR; } } @@ -1992,36 +2034,26 @@ continue_generating: block->setNode(v3s16(x0,y0,z0), n); } } - + /* - Calculate completely_underground + This is used for guessing whether or not the block should + receive sunlight from the top if the top block doesn't exist */ - // Completely underground if the highest part of block is under lowest - // ground height. - // This has to be very sure; it's probably one too strict now but - // that's just better. - bool completely_underground = - block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y; - - // This isn't used anymore (?) but set it anyway block->setIsUnderground(completely_underground); - bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y; - /* Force lighting update if some part of block is partly underground and has caves. */ - - if(some_part_underground && !completely_underground && has_caves) + /*if(some_part_underground && !completely_underground && has_caves) { //dstream<<"Half-ground caves"<<std::endl; lighting_invalidated_blocks[block->getPos()] = block; - } + }*/ // DEBUG: Always update lighting //lighting_invalidated_blocks[block->getPos()] = block; - + /* Add some minerals */ @@ -2364,6 +2396,28 @@ continue_generating: objects->remove(*i); } + /* + Initially update sunlight + */ + + { + core::map<v3s16, bool> light_sources; + bool black_air_left = false; + bool bottom_invalid = + block->propagateSunlight(light_sources, true, &black_air_left); + + // If sunlight didn't reach everywhere and part of block is + // above ground, lighting has to be properly updated + if(black_air_left && some_part_underground) + { + lighting_invalidated_blocks[block->getPos()] = block; + } + } + + /* + Translate sector's changed blocks to global changed blocks + */ + for(core::map<s16, MapBlock*>::Iterator i = changed_blocks_sector.getIterator(); i.atEnd() == false; i++) |