From cfaa15895ad73ce3cef174f770d877059e9708e0 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 15 Jan 2011 01:26:29 +0200 Subject: [PATCH] tweaking around, including mapgen, player speed in water, settings --- src/defaultsettings.cpp | 11 +- src/environment.cpp | 2 +- src/main.cpp | 127 ++++++++++++---------- src/map.cpp | 234 ++++++++++++++++++++++++---------------- src/mapblock.cpp | 18 ++++ src/materials.cpp | 6 +- src/player.h | 22 +++- src/server.cpp | 20 ++-- 8 files changed, 275 insertions(+), 165 deletions(-) diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 66564bc1..e15a5b3a 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -40,12 +40,19 @@ void set_default_settings() // Server stuff g_settings.setDefault("creative_mode", "false"); - g_settings.setDefault("heightmap_blocksize", "32"); + /*g_settings.setDefault("heightmap_blocksize", "32"); g_settings.setDefault("height_randmax", "constant 45.0"); g_settings.setDefault("height_randfactor", "constant 0.6"); g_settings.setDefault("height_base", "linear 0 0 0"); g_settings.setDefault("plants_amount", "1.0"); 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_base", "linear 5 0 0"); + g_settings.setDefault("plants_amount", "0.2"); + g_settings.setDefault("ravines_amount", "0"); g_settings.setDefault("coal_amount", "1.0"); g_settings.setDefault("objectdata_interval", "0.2"); @@ -55,7 +62,7 @@ void set_default_settings() g_settings.setDefault("disable_water_climb", "true"); g_settings.setDefault("endless_water", "true"); g_settings.setDefault("max_block_send_distance", "5"); - g_settings.setDefault("max_block_generate_distance", "4"); + g_settings.setDefault("max_block_generate_distance", "5"); g_settings.setDefault("time_send_interval", "20"); g_settings.setDefault("time_speed", "96"); g_settings.setDefault("server_unload_unused_sectors_timeout", "60"); diff --git a/src/environment.cpp b/src/environment.cpp index 7c236c35..c43525c3 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -121,7 +121,7 @@ void Environment::step(float dtime) f32 max_down = 1.0*BS; if(speed.Y < -max_down) speed.Y = -max_down; - f32 max = 2.0*BS; + f32 max = 2.5*BS; if(speed.getLength() > max) { speed = speed / speed.getLength() * max; diff --git a/src/main.cpp b/src/main.cpp index eacf08c7..f36f17a1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,20 +23,21 @@ NOTE: Things starting with TODO are sometimes only suggestions. NOTE: VBO cannot be turned on for fast-changing stuff because there is an apparanet memory leak in irrlicht when using it (not sure) + - It is not a memory leak but some kind of a buffer. NOTE: iostream.imbue(std::locale("C")) is very slow NOTE: Global locale is now set at initialization SUGG: Fix address to be ipv6 compatible -FIXME: When a new sector is generated, it may change the ground level - of it's and it's neighbors border that two blocks that are - above and below each other and that are generated before and - after the sector heightmap generation (order doesn't matter), - can have a small gap between each other at the border. -SUGGESTION: Use same technique for sector heightmaps as what we're - using for UnlimitedHeightmap? (getting all neighbors - when generating) +NOTE: When a new sector is generated, it may change the ground level + of it's and it's neighbors border that two blocks that are + above and below each other and that are generated before and + after the sector heightmap generation (order doesn't matter), + can have a small gap between each other at the border. +SUGG: Use same technique for sector heightmaps as what we're + using for UnlimitedHeightmap? (getting all neighbors + when generating) SUGG: Transfer more blocks in a single packet SUGG: A blockdata combiner class, to which blocks are added and at @@ -78,10 +79,6 @@ SUGG: Split MapBlockObject serialization to to-client and to-disk SUGG: Implement lighting using VoxelManipulator - Would it be significantly faster? -FIXME: Rats somehow go underground sometimes (you can see it in water) - - Does their position get saved to a border value or something? - - Does this happen anymore? - SUGG: MovingObject::move and Player::move are basically the same. combine them. @@ -90,6 +87,8 @@ SUGG: Implement a "Fast check queue" (a queue with a map for checking - Use it in active block queue in water flowing SUGG: Precalculate lighting translation table at runtime (at startup) + - This is not doable because it is currently hand-made and not + based on some mathematical function. SUGG: A version number to blocks, which increments when the block is modified (node add/remove, water update, lighting update) @@ -105,51 +104,71 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into different directions and then only those drawn that need to be - Also an 1-dimensional tile map would be nice probably -TODO: Untie client network operations from framerate - - Needs some input queues or something - - Not really necessary? +Networking: + +TODO: Get rid of GotSplitPacketException + +GUI: + +TODO: Add gui option to remove map + +TODO: Startup and configuration menu + +Graphics: + +TODO: Optimize day/night mesh updating somehow + - create copies of all textures for all lighting values and only + change texture for material? + - Umm... the collecting of the faces is the slow part + -> what about just changing the color values of the existing + meshbuffers? It should go quite fast. + +TODO: Draw big amounts of torches better (that is, throw them in the + same meshbuffer (can the meshcollector class be used?)) TODO: Combine MapBlock's face caches to so big pieces that VBO gets used - That is >500 vertices -TODO: Startup and configuration menu +TODO: Make fetching sector's blocks more efficient when rendering + sectors that have very large amounts of blocks (on client) -TODO: There are some lighting-related todos and fixmes in - ServerMap::emergeBlock +Configuration: -TODO: Proper handling of spawning place (try to find something that - is not in the middle of an ocean (some land to stand on at - least) and save it in map config. +TODO: Make the video backend selectable + +Client: + +TODO: Untie client network operations from framerate + - Needs some input queues or something + - Not really necessary? + +Server: + +TODO: When player dies, throw items on map + +TODO: Make an option to the server to disable building and digging near + the starting position TODO: Players to only be hidden when the client quits. TODO: - Players to be saved on disk, with inventory TODO: Players to be saved as text in map/players/ TODO: Player inventory to be saved on disk -TODO: Make fetching sector's blocks more efficient when rendering - sectors that have very large amounts of blocks (on client) - -TODO: Make the video backend selectable +TODO: Proper handling of spawning place (try to find something that + is not in the middle of an ocean (some land to stand on at + least) and save it in map config. TODO: Copy the text of the last picked sign to inventory in creative mode -TODO: Get rid of GotSplitPacketException - TODO: Check what goes wrong with caching map to disk (Kray) - Nothing? -Block object server side: - - A "near blocks" buffer, in which some nearby blocks are stored. - - For all blocks in the buffer, objects are stepped(). This - means they are active. - - TODO: A global active buffer is needed for the server - - TODO: A timestamp to blocks - - TODO: All blocks going in and out of the buffer are recorded. - - TODO: For outgoing blocks, timestamp is written. - - TODO: For incoming blocks, time difference is calculated and - objects are stepped according to it. +TODO: When server sees that client is removing an inexistent block or + adding a block to an existent position, resend the MapBlock. + +Objects: TODO: Better handling of objects and mobs - Scripting? @@ -160,31 +179,31 @@ TODO: Better handling of objects and mobs - This is also needed for objects that don't get sent to client but are used for triggers etc -TODO: Draw big amounts of torches better (that is, throw them in the - same meshbuffer (can the meshcollector class be used?)) - -TODO: Make an option to the server to disable building and digging near - the starting position - SUGG: Signs could be done in the same way as torches. For this, blocks need an additional metadata field for the texts - This is also needed for item container chests TODO: There has to be some better way to handle static objects than to send them all the time. This affects signs and item objects. -TODO: When server sees that client is removing an inexistent block or - adding a block to an existent position, resend the MapBlock. +Block object server side: + - A "near blocks" buffer, in which some nearby blocks are stored. + - For all blocks in the buffer, objects are stepped(). This + means they are active. + - TODO: A global active buffer is needed for the server + - TODO: A timestamp to blocks + - TODO: All blocks going in and out of the buffer are recorded. + - TODO: For outgoing blocks, timestamp is written. + - TODO: For incoming blocks, time difference is calculated and + objects are stepped according to it. -TODO: When player dies, throw items on map +Map generator: -TODO: Use porting::path_userdata for configuration file +TODO: There are some lighting-related todos and fixmes in + ServerMap::emergeBlock -TODO: Optimize day/night mesh updating somehow - - create copies of all textures for all lighting values and only - change texture for material? - - Umm... the collecting of the faces is the slow part - -> what about just changing the color values of the existing - meshbuffers? It should go quite fast. +TODO: When generating a block, check that there is no sunlight + below the block if the bottom of the block doesn't have + sunlight. If it has, add it to the invalid lighting list. TODO: Map generator version 2 - Create surface areas based on central points; a given point's @@ -193,8 +212,6 @@ TODO: Map generator version 2 - Flat land, mountains, forest, jungle - Cliffs, arcs -TODO: Add gui option to remove map - Doing now: ====================================================================== diff --git a/src/map.cpp b/src/map.cpp index f5e490ad..119b487d 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1482,8 +1482,10 @@ MapSector * ServerMap::emergeSector(v2s16 p2d) sector->setHeightmap(p_in_sector, hm); //TODO: Make these values configurable + //hm->generateContinued(0.0, 0.0, corners); - hm->generateContinued(0.5, 0.2, corners); + hm->generateContinued(0.25, 0.2, corners); + //hm->generateContinued(0.5, 0.2, corners); //hm->generateContinued(1.0, 0.2, corners); //hm->generateContinued(2.0, 0.2, corners); @@ -1712,6 +1714,7 @@ MapBlock * ServerMap::emergeBlock( { underground_emptiness[i] = 0; } + // Generate dungeons { /* @@ -1863,6 +1866,10 @@ 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; z0 max_slope) @@ -1935,101 +1943,85 @@ continue_generating: // 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_AIR; + n.d = CONTENT_STONE; } else { - // If it's surface_depth under ground, it's stone - if(real_y <= surface_y - surface_depth) + // 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_STONE; + n.d = CONTENT_MUD; } 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;*/ + 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;*/ } - } -#if 0 - else if(real_y <= surface_y - surface_depth) - { + // Create dungeons if(underground_emptiness[ ued*ued*(z0*ued/MAP_BLOCKSIZE) +ued*(y0*ued/MAP_BLOCKSIZE) +(x0*ued/MAP_BLOCKSIZE)]) { + // Has now caves if previous content is air + if(n.d != CONTENT_AIR) + { + has_caves = true; + } + n.d = CONTENT_AIR; } - else - { - n.d = CONTENT_STONE; - } } - // If node is at or under heightmap y - else if(real_y <= surface_y) - { - // 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 it's the main material - else - n.d = material; - } -#endif + block->setNode(v3s16(x0,y0,z0), n); } } /* - Calculate is_underground + Calculate completely_underground */ - // Probably underground if the highest part of block is under lowest - // ground height - bool is_underground = (block_y+1) * MAP_BLOCKSIZE <= lowest_ground_y; - block->setIsUnderground(is_underground); + // 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 underground - This is needed because of caves. + Force lighting update if some part of block is partly + underground and has caves. */ - bool some_part_underground = (block_y+0) * MAP_BLOCKSIZE < highest_ground_y; - if(some_part_underground) - //if(is_underground) + 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 */ @@ -2041,9 +2033,9 @@ continue_generating: /* Add meseblocks */ - for(s16 i=0; igetValue(); - //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0); + // Ground level point (user for stuff that is on ground) + v3s16 gp = p; + bool ground_found = true; + // Search real ground level + try{ + for(;;) + { + MapNode n = sector->getNode(gp); + + // If not air, go one up and continue to placing the tree + if(n.d != CONTENT_AIR) + { + gp += v3s16(0,1,0); + break; + } + + // If air, go one down + gp += v3s16(0,-1,0); + } + }catch(InvalidPositionException &e) + { + // Ground not found. + ground_found = false; + // This is most close to ground + gp += v3s16(0,1,0); + } + try { @@ -2175,40 +2193,64 @@ continue_generating: } else if(d == SECTOR_OBJECT_TREE_1) { - v3s16 p_min = p + v3s16(-1,0,-1); - v3s16 p_max = p + v3s16(1,4,1); + if(ground_found == false) + continue; + + v3s16 p_min = gp + v3s16(-1,0,-1); + v3s16 p_max = gp + v3s16(1,5,1); if(sector->isValidArea(p_min, p_max, &changed_blocks_sector)) { MapNode n; n.d = CONTENT_TREE; - sector->setNode(p+v3s16(0,0,0), n); - sector->setNode(p+v3s16(0,1,0), n); - sector->setNode(p+v3s16(0,2,0), n); - sector->setNode(p+v3s16(0,3,0), n); + sector->setNode(gp+v3s16(0,0,0), n); + sector->setNode(gp+v3s16(0,1,0), n); + sector->setNode(gp+v3s16(0,2,0), n); + sector->setNode(gp+v3s16(0,3,0), n); n.d = CONTENT_LEAVES; - sector->setNode(p+v3s16(0,4,0), n); + if(rand()%4!=0) sector->setNode(gp+v3s16(0,5,0), n); + + if(rand()%3!=0) sector->setNode(gp+v3s16(-1,5,0), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(1,5,0), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(0,5,-1), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(0,5,1), n); + /*if(rand()%3!=0) sector->setNode(gp+v3s16(1,5,1), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(-1,5,1), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(-1,5,-1), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(1,5,-1), n);*/ + + sector->setNode(gp+v3s16(0,4,0), n); - sector->setNode(p+v3s16(-1,4,0), n); - sector->setNode(p+v3s16(1,4,0), n); - sector->setNode(p+v3s16(0,4,-1), n); - sector->setNode(p+v3s16(0,4,1), n); - sector->setNode(p+v3s16(1,4,1), n); - sector->setNode(p+v3s16(-1,4,1), n); - sector->setNode(p+v3s16(-1,4,-1), n); - sector->setNode(p+v3s16(1,4,-1), n); - - sector->setNode(p+v3s16(-1,3,0), n); - sector->setNode(p+v3s16(1,3,0), n); - sector->setNode(p+v3s16(0,3,-1), n); - sector->setNode(p+v3s16(0,3,1), n); - sector->setNode(p+v3s16(1,3,1), n); - sector->setNode(p+v3s16(-1,3,1), n); - sector->setNode(p+v3s16(-1,3,-1), n); - sector->setNode(p+v3s16(1,3,-1), n); + sector->setNode(gp+v3s16(-1,4,0), n); + sector->setNode(gp+v3s16(1,4,0), n); + sector->setNode(gp+v3s16(0,4,-1), n); + sector->setNode(gp+v3s16(0,4,1), n); + sector->setNode(gp+v3s16(1,4,1), n); + sector->setNode(gp+v3s16(-1,4,1), n); + sector->setNode(gp+v3s16(-1,4,-1), n); + sector->setNode(gp+v3s16(1,4,-1), n); + + sector->setNode(gp+v3s16(-1,3,0), n); + sector->setNode(gp+v3s16(1,3,0), n); + sector->setNode(gp+v3s16(0,3,-1), n); + sector->setNode(gp+v3s16(0,3,1), n); + sector->setNode(gp+v3s16(1,3,1), n); + sector->setNode(gp+v3s16(-1,3,1), n); + sector->setNode(gp+v3s16(-1,3,-1), n); + sector->setNode(gp+v3s16(1,3,-1), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(-1,2,0), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(1,2,0), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(0,2,-1), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(0,2,1), n); + /*if(rand()%3!=0) sector->setNode(gp+v3s16(1,2,1), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(-1,2,1), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(-1,2,-1), n); + if(rand()%3!=0) sector->setNode(gp+v3s16(1,2,-1), n);*/ + + // Objects are identified by wanted position objects_to_remove.push_back(p); // Lighting has to be recalculated for this one. @@ -2218,13 +2260,17 @@ continue_generating: } else if(d == SECTOR_OBJECT_BUSH_1) { - if(sector->isValidArea(p + v3s16(0,0,0), - p + v3s16(0,0,0), &changed_blocks_sector)) + if(ground_found == false) + continue; + + if(sector->isValidArea(gp + v3s16(0,0,0), + gp + v3s16(0,0,0), &changed_blocks_sector)) { MapNode n; n.d = CONTENT_LEAVES; - sector->setNode(p+v3s16(0,0,0), n); + sector->setNode(gp+v3s16(0,0,0), n); + // Objects are identified by wanted position objects_to_remove.push_back(p); } } diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 90ff05bd..2d077121 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -876,6 +876,7 @@ bool MapBlock::propagateSunlight(core::map & light_sources) { for(s16 z=0; z & light_sources) // No sunlight here //no_sunlight = true; } +#endif +#if 0 // Doesn't work; nothing gets light. + bool no_sunlight = true; + bool no_top_block = false; + // Check if node above block has sunlight + try{ + MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z)); + if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN) + { + no_sunlight = false; + } + } + catch(InvalidPositionException &e) + { + no_top_block = true; + } +#endif /*std::cout<<"("<m_env_mutex); - //TimeTaker timer("block emerge envlock", g_device); + //envlockwaittimer.stop(); + + //TimeTaker timer("block emerge (while env locked)"); try{ bool only_from_disk = false; @@ -209,8 +214,9 @@ void * EmergeThread::Thread() } /*dstream<<"lighting "< d_max_gen / 2) + // Limit the generating area vertically to 2/3 + if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3) generate = false; /* @@ -2967,7 +2973,7 @@ void Server::handlePeerChange(PeerChange &c) // The player shouldn't already exist assert(player == NULL); - player = new ServerRemotePlayer(); + player = new ServerRemotePlayer(true); player->peer_id = c.peer_id; /* -- 2.30.2