diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index e15a5b3..5819480 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -48,8 +48,8 @@ void set_default_settings() g_settings.setDefault("ravines_amount", "1.0"); g_settings.setDefault("coal_amount", "1.0");*/ g_settings.setDefault("heightmap_blocksize", "16"); - g_settings.setDefault("height_randmax", "linear 0 0 40"); - g_settings.setDefault("height_randfactor", "linear 0.60 -0.10 0"); + g_settings.setDefault("height_randmax", "linear 0 0 30"); + g_settings.setDefault("height_randfactor", "linear 0.50 -0.10 0"); g_settings.setDefault("height_base", "linear 5 0 0"); g_settings.setDefault("plants_amount", "0.2"); g_settings.setDefault("ravines_amount", "0"); diff --git a/src/map.cpp b/src/map.cpp index 119b487..c8175c4 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,161 +1703,10 @@ 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(); } - /* - Create dungeon making table - */ - const s32 ued = MAP_BLOCKSIZE; - bool underground_emptiness[ued*ued*ued]; - for(s32 i=0; igetPosRelative(); - if(getNode(ap).d == CONTENT_AIR) - { - orp = v3f(x+1,y+1,0); - found_existing = true; - goto continue_generating; - } - } - } - catch(InvalidPositionException &e){} - - // Check z+ - try - { - s16 z = ued; - for(s16 y=0; ygetPosRelative(); - if(getNode(ap).d == CONTENT_AIR) - { - orp = v3f(x+1,y+1,ued-1); - found_existing = true; - goto continue_generating; - } - } - } - catch(InvalidPositionException &e){} - - // Check x- - try - { - s16 x = -1; - for(s16 y=0; ygetPosRelative(); - if(getNode(ap).d == CONTENT_AIR) - { - orp = v3f(0,y+1,z+1); - found_existing = true; - goto continue_generating; - } - } - } - catch(InvalidPositionException &e){} - - // Check x+ - try - { - s16 x = ued; - for(s16 y=0; ygetPosRelative(); - if(getNode(ap).d == CONTENT_AIR) - { - orp = v3f(ued-1,y+1,z+1); - found_existing = true; - goto continue_generating; - } - } - } - catch(InvalidPositionException &e){} - -continue_generating: - - /* - Don't always generate dungeon - */ - if(found_existing || rand() % 2 == 0) - { - /* - Generate some tunnel starting from orp and ors - */ - for(u16 i=0; i<3; i++) - { - v3f rp( - (float)(myrand()%ued)+0.5, - (float)(myrand()%ued)+0.5, - (float)(myrand()%ued)+0.5 - ); - s16 min_d = 0; - s16 max_d = 4; - s16 rs = (myrand()%(max_d-min_d+1))+min_d; - - v3f vec = rp - orp; - - for(float f=0; f<1.0; f+=0.04) - { - v3f fp = orp + vec * f; - v3s16 cp(fp.X, fp.Y, fp.Z); - s16 d0 = -rs/2; - s16 d1 = d0 + rs - 1; - for(s16 z0=d0; z0<=d1; z0++) - { - s16 si = rs - abs(z0); - for(s16 x0=-si; x0<=si-1; x0++) - { - s16 si2 = rs - abs(x0); - for(s16 y0=-si2+1; y0<=si2-1; y0++) - { - s16 z = cp.Z + z0; - s16 y = cp.Y + y0; - s16 x = cp.X + x0; - v3s16 p(x,y,z); - if(isInArea(p, ued) == false) - continue; - underground_emptiness[ued*ued*z + ued*y + x] = 1; - } - } - } - } - - orp = rp; - } - } - } - u8 water_material = CONTENT_WATER; if(g_settings.getBool("endless_water")) water_material = CONTENT_OCEAN; @@ -1866,10 +1717,6 @@ continue_generating: // 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; - for(s16 z0=0; z0setNode(v3s16(x0,y0,z0), n); } } - + /* - Calculate completely_underground + 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 @@ -2003,25 +1836,224 @@ continue_generating: 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; + /* + Generate dungeons + */ + + // Initialize temporary table + const s32 ued = MAP_BLOCKSIZE; + bool underground_emptiness[ued*ued*ued]; + for(s32 i=0; igetPosRelative(); + if(getNode(ap).d == CONTENT_AIR) + { + orp = v3f(x+1,y+1,0); + found_existing = true; + goto continue_generating; + } + } + } + catch(InvalidPositionException &e){} + + // Check z+ + try + { + s16 z = ued; + for(s16 y=0; ygetPosRelative(); + if(getNode(ap).d == CONTENT_AIR) + { + orp = v3f(x+1,y+1,ued-1); + found_existing = true; + goto continue_generating; + } + } + } + catch(InvalidPositionException &e){} + + // Check x- + try + { + s16 x = -1; + for(s16 y=0; ygetPosRelative(); + if(getNode(ap).d == CONTENT_AIR) + { + orp = v3f(0,y+1,z+1); + found_existing = true; + goto continue_generating; + } + } + } + catch(InvalidPositionException &e){} + + // Check x+ + try + { + s16 x = ued; + for(s16 y=0; ygetPosRelative(); + if(getNode(ap).d == CONTENT_AIR) + { + orp = v3f(ued-1,y+1,z+1); + found_existing = true; + goto continue_generating; + } + } + } + catch(InvalidPositionException &e){} + +continue_generating: + + /* + Don't always generate dungeon + */ + 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 + */ + for(u16 i=0; i<3; i++) + { + v3f rp( + (float)(myrand()%ued)+0.5, + (float)(myrand()%ued)+0.5, + (float)(myrand()%ued)+0.5 + ); + s16 min_d = 0; + s16 max_d = 6; + s16 rs = (myrand()%(max_d-min_d+1))+min_d; + + v3f vec = rp - orp; + + for(float f=0; f<1.0; f+=0.04) + { + v3f fp = orp + vec * f; + v3s16 cp(fp.X, fp.Y, fp.Z); + s16 d0 = -rs/2; + s16 d1 = d0 + rs - 1; + for(s16 z0=d0; z0<=d1; z0++) + { + s16 si = rs - abs(z0); + for(s16 x0=-si; x0<=si-1; x0++) + { + s16 si2 = rs - abs(x0); + for(s16 y0=-si2+1; y0<=si2-1; y0++) + { + s16 z = cp.Z + z0; + s16 y = cp.Y + y0; + s16 x = cp.X + x0; + v3s16 p(x,y,z); + if(isInArea(p, ued) == false) + continue; + underground_emptiness[ued*ued*z + ued*y + x] = 1; + } + } + } + } + + orp = rp; + } + } + } + + // 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; z0getNode(v3s16(x0,y0,z0)); + + // 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 + has_caves = true; + // Set air to node + n.d = CONTENT_AIR; + } + } + + block->setNode(v3s16(x0,y0,z0), n); + } + } + + /* + This is used for guessing whether or not the block should + receive sunlight from the top if the top block doesn't exist + */ + block->setIsUnderground(completely_underground); + /* 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"<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 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::Iterator i = changed_blocks_sector.getIterator(); i.atEnd() == false; i++) diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 68b2961..252f123 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -934,61 +934,68 @@ bool MapBlock::propagateSunlight(core::map & light_sources, s16 y = MAP_BLOCKSIZE-1; - if(no_sunlight == false) - { - // Continue spreading sunlight downwards through transparent - // nodes - for(; y >= 0; y--) - { - v3s16 pos(x, y, z); - - MapNode &n = getNodeRef(pos); - - if(n.sunlight_propagates()) - { - n.setLight(LIGHTBANK_DAY, LIGHT_SUN); - - light_sources.insert(pos_relative + pos, true); - } - else - { - // Turn mud into grass - if(n.d == CONTENT_MUD) - { - n.d = CONTENT_GRASS; - } - - // Sunlight goes no further - break; - } - } - } - - bool sunlight_should_go_down = (y==-1); + // This makes difference to diminishing in water. + bool stopped_to_solid_object = false; - /* - Check rest through to the bottom of the block - */ + u8 current_light = no_sunlight ? 0 : LIGHT_SUN; + for(; y >= 0; y--) { v3s16 pos(x, y, z); MapNode &n = getNodeRef(pos); + + if(current_light == 0) + { + // Do nothing + } + else if(current_light == LIGHT_SUN && n.sunlight_propagates()) + { + // Do nothing: Sunlight is continued + } + else if(n.light_propagates() == false) + { + // Turn mud into grass + if(n.d == CONTENT_MUD && current_light == LIGHT_SUN) + { + n.d = CONTENT_GRASS; + } - if(n.light_propagates()) + // A solid object is on the way. + stopped_to_solid_object = true; + + // Light stops. + current_light = 0; + } + else + { + // Diminish light + current_light = diminish_light(current_light); + } + + u8 old_light = n.getLight(LIGHTBANK_DAY); + + if(current_light > old_light || remove_light) + { + n.setLight(LIGHTBANK_DAY, current_light); + } + + if(diminish_light(current_light) != 0) + { + light_sources.insert(pos_relative + pos, true); + } + + if(current_light == 0 && stopped_to_solid_object) { if(black_air_left) { *black_air_left = true; } - - if(remove_light) - { - // Fill transparent nodes with black - n.setLight(LIGHTBANK_DAY, 0); - } } } + // Whether or not the block below should see LIGHT_SUN + bool sunlight_should_go_down = (current_light == LIGHT_SUN); + /* If the block below hasn't already been marked invalid: diff --git a/src/mapblock.h b/src/mapblock.h index 743dad9..b3fa76b 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -312,7 +312,8 @@ public: #endif // !SERVER // See comments in mapblock.cpp - bool propagateSunlight(core::map & light_sources); + bool propagateSunlight(core::map & light_sources, + bool remove_light=false, bool *black_air_left=NULL); // Copies data to VoxelManipulator to getPosRelative() void copyTo(VoxelManipulator &dst); diff --git a/src/server.cpp b/src/server.cpp index 2f285b6..9d2e969 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3003,7 +3003,7 @@ Player *Server::emergePlayer(const char *name, const char *password) // Try to find a good place a few times for(s32 i=0; i<100; i++) { - s32 range = 1 + i*5; + s32 range = 1 + i*2; // We're going to try to throw the player to this position nodepos = v2s16(-range/2 + (myrand()%range), -range/2 + (myrand()%range)); @@ -3036,6 +3036,10 @@ Player *Server::emergePlayer(const char *name, const char *password) break; } #endif + + // If no suitable place was not found, go above water at least. + if(groundheight < WATER_LEVEL) + groundheight = WATER_LEVEL; player->setPosition(intToFloat(v3s16( nodepos.X, diff --git a/src/test.cpp b/src/test.cpp index 38c6632..f8f9547 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -537,7 +537,7 @@ struct TestMapBlock core::map light_sources; // The block below should be valid because there shouldn't be // sunlight in there either - assert(b.propagateSunlight(light_sources) == true); + assert(b.propagateSunlight(light_sources, true) == true); // Should not touch nodes that are not affected (that is, all of them) //assert(b.getNode(v3s16(1,2,3)).getLight() == LIGHT_SUN); // Should set light of non-sunlighted blocks to 0. diff --git a/src/utility.h b/src/utility.h index 008a95c..e2a6afd 100644 --- a/src/utility.h +++ b/src/utility.h @@ -1323,10 +1323,17 @@ private: MutexedQueue< GetRequest > m_queue; }; -// Pseudo-random (VC++ rand() sucks) +/* + Pseudo-random (VC++ rand() sucks) +*/ int myrand(void); void mysrand(unsigned seed); #define MYRAND_MAX 32767 +/* + TODO: Some kind of a thing that stores arbitary data related to + 2D coordinate points +*/ + #endif