diff options
author | Perttu Ahola <celeron55@gmail.com> | 2011-04-10 20:18:34 +0300 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2011-04-10 20:18:34 +0300 |
commit | 10eedbc1d233da36c244de67fcec555bcea87d5f (patch) | |
tree | 2a404f4b68371dcb1e89a8b02d791f8d529df60b /src | |
parent | 6fa85c8502ced2293cd7f56d47dce9ce8add57dc (diff) | |
download | minetest-10eedbc1d233da36c244de67fcec555bcea87d5f.tar.gz minetest-10eedbc1d233da36c244de67fcec555bcea87d5f.tar.bz2 minetest-10eedbc1d233da36c244de67fcec555bcea87d5f.zip |
Map generation is now properly threaded and doesn't block block placement and other stuff.
Diffstat (limited to 'src')
-rw-r--r-- | src/environment.cpp | 2 | ||||
-rw-r--r-- | src/map.cpp | 118 | ||||
-rw-r--r-- | src/map.h | 26 | ||||
-rw-r--r-- | src/server.cpp | 121 |
4 files changed, 152 insertions, 115 deletions
diff --git a/src/environment.cpp b/src/environment.cpp index d2fb8a39d..77746c5be 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -429,7 +429,7 @@ void ServerEnvironment::step(float dtime) bool send_recommended = false; m_send_recommended_timer += dtime; - if(m_send_recommended_timer > 0.1) + if(m_send_recommended_timer > 0.15) { m_send_recommended_timer = 0; send_recommended = true; diff --git a/src/map.cpp b/src/map.cpp index 334de40de..8d79ae366 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2170,23 +2170,6 @@ void addRandomObjects(MapBlock *block) This is the main map generation method */ -struct ChunkMakeData -{ - ManualMapVoxelManipulator vmanip; - u64 seed; - s16 y_blocks_min; - s16 y_blocks_max; - v2s16 sectorpos_base; - s16 sectorpos_base_size; - v2s16 sectorpos_bigbase; - s16 sectorpos_bigbase_size; - s16 max_spread_amount; - - ChunkMakeData(): - vmanip(NULL) - {} -}; - void makeChunk(ChunkMakeData *data) { s16 y_nodes_min = data->y_blocks_min * MAP_BLOCKSIZE; @@ -2235,11 +2218,11 @@ void makeChunk(ChunkMakeData *data) /* Skip of already generated */ - { + /*{ v3s16 p(p2d.X, y_nodes_min, p2d.Y); if(data->vmanip.m_data[data->vmanip.m_area.index(p)].d != CONTENT_AIR) continue; - } + }*/ // Ground height at this point float surface_y_f = 0.0; @@ -2270,6 +2253,13 @@ void makeChunk(ChunkMakeData *data) u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y)); for(s16 y=y_nodes_min; y<surface_y && y<=y_nodes_max; y++) { + // Skip if already generated. + // This is done here because there might be a cave at + // any point in ground, which could look like it + // wasn't generated. + if(data->vmanip.m_data[i].d != CONTENT_AIR) + break; + data->vmanip.m_data[i].d = CONTENT_STONE; data->vmanip.m_area.add_y(em, i, 1); @@ -3426,33 +3416,8 @@ void makeChunk(ChunkMakeData *data) //################################################################### //################################################################### -MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, - core::map<v3s16, MapBlock*> &changed_blocks, - bool force) +void ServerMap::initChunkMake(ChunkMakeData &data, v2s16 chunkpos) { - DSTACK(__FUNCTION_NAME); - - /* - Don't generate if already fully generated - */ - if(force == false) - { - MapChunk *chunk = getChunk(chunkpos); - if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY) - { - dstream<<"generateChunkRaw(): Chunk " - <<"("<<chunkpos.X<<","<<chunkpos.Y<<")" - <<" already generated"<<std::endl; - return chunk; - } - } - - dstream<<"generateChunkRaw(): Generating chunk " - <<"("<<chunkpos.X<<","<<chunkpos.Y<<")" - <<std::endl; - - TimeTaker timer("generateChunkRaw()"); - // The distance how far into the neighbors the generator is allowed to go. s16 max_spread_amount_sectors = 2; assert(max_spread_amount_sectors <= m_chunksize); @@ -3469,8 +3434,8 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, s16 sectorpos_bigbase_size = sectorpos_base_size + 2 * max_spread_amount_sectors; - ChunkMakeData data; data.seed = m_seed; + data.chunkpos = chunkpos; data.y_blocks_min = y_blocks_min; data.y_blocks_max = y_blocks_max; data.sectorpos_base = sectorpos_base; @@ -3541,9 +3506,11 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, data.vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max); } - // Generate stuff - makeChunk(&data); +} +MapChunk* ServerMap::finishChunkMake(ChunkMakeData &data, + core::map<v3s16, MapBlock*> &changed_blocks) +{ /* Blit generated stuff to map */ @@ -3569,14 +3536,14 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, Add random objects to blocks */ { - for(s16 x=0; x<sectorpos_base_size; x++) - for(s16 z=0; z<sectorpos_base_size; z++) + for(s16 x=0; x<data.sectorpos_base_size; x++) + for(s16 z=0; z<data.sectorpos_base_size; z++) { - v2s16 sectorpos = sectorpos_base + v2s16(x,z); + v2s16 sectorpos = data.sectorpos_base + v2s16(x,z); ServerMapSector *sector = createSector(sectorpos); assert(sector); - for(s16 y=y_blocks_min; y<=y_blocks_max; y++) + for(s16 y=data.y_blocks_min; y<=data.y_blocks_max; y++) { v3s16 blockpos(sectorpos.X, y, sectorpos.Y); MapBlock *block = createBlock(blockpos); @@ -3592,7 +3559,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, for(s16 x=-1; x<=1; x++) for(s16 y=-1; y<=1; y++) { - v2s16 chunkpos0 = chunkpos + v2s16(x,y); + v2s16 chunkpos0 = data.chunkpos + v2s16(x,y); // Add chunk meta information MapChunk *chunk = getChunk(chunkpos0); if(chunk == NULL) @@ -3608,7 +3575,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, /* Set central chunk non-volatile */ - MapChunk *chunk = getChunk(chunkpos); + MapChunk *chunk = getChunk(data.chunkpos); assert(chunk); // Set non-volatile //chunk->setIsVolatile(false); @@ -3618,6 +3585,48 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, Save changed parts of map */ save(true); + + return chunk; +} + +// NOTE: Deprecated +MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, + core::map<v3s16, MapBlock*> &changed_blocks, + bool force) +{ + DSTACK(__FUNCTION_NAME); + + /* + Don't generate if already fully generated + */ + if(force == false) + { + MapChunk *chunk = getChunk(chunkpos); + if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY) + { + dstream<<"generateChunkRaw(): Chunk " + <<"("<<chunkpos.X<<","<<chunkpos.Y<<")" + <<" already generated"<<std::endl; + return chunk; + } + } + + dstream<<"generateChunkRaw(): Generating chunk " + <<"("<<chunkpos.X<<","<<chunkpos.Y<<")" + <<std::endl; + + TimeTaker timer("generateChunkRaw()"); + + ChunkMakeData data; + + // Initialize generation + initChunkMake(data, chunkpos); + + // Generate stuff + makeChunk(&data); + + // Finalize generation + MapChunk *chunk = finishChunkMake(data, changed_blocks); /* Return central chunk (which was requested) @@ -3625,6 +3634,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, return chunk; } +// NOTE: Deprecated MapChunk* ServerMap::generateChunk(v2s16 chunkpos1, core::map<v3s16, MapBlock*> &changed_blocks) { @@ -318,6 +318,8 @@ protected: This is the only map class that is able to generate map. */ +struct ChunkMakeData; + class ServerMap : public Map { public: @@ -391,6 +393,10 @@ public: return true; } + void initChunkMake(ChunkMakeData &data, v2s16 chunkpos); + MapChunk* finishChunkMake(ChunkMakeData &data, + core::map<v3s16, MapBlock*> &changed_blocks); + /* Generate a chunk. @@ -746,5 +752,25 @@ protected: bool m_create_area; }; +struct ChunkMakeData +{ + ManualMapVoxelManipulator vmanip; + u64 seed; + v2s16 chunkpos; + s16 y_blocks_min; + s16 y_blocks_max; + v2s16 sectorpos_base; + s16 sectorpos_base_size; + v2s16 sectorpos_bigbase; + s16 sectorpos_bigbase_size; + s16 max_spread_amount; + + ChunkMakeData(): + vmanip(NULL) + {} +}; + +void makeChunk(ChunkMakeData *data); + #endif diff --git a/src/server.cpp b/src/server.cpp index c5703bf33..63d8e31db 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -72,7 +72,7 @@ void * EmergeThread::Thread() DSTACK(__FUNCTION_NAME); - bool debug=false; + //bool debug=false; BEGIN_DEBUG_EXCEPTION_HANDLER @@ -91,7 +91,19 @@ void * EmergeThread::Thread() SharedPtr<QueuedBlockEmerge> q(qptr); v3s16 &p = q->pos; - + v2s16 p2d(p.X,p.Z); + + /* + Do not generate over-limit + */ + if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) + continue; + //derr_server<<"EmergeThread::Thread(): running"<<std::endl; //TimeTaker timer("block emerge"); @@ -144,78 +156,67 @@ void * EmergeThread::Thread() if(optional) only_from_disk = true; - /* - TODO: Map loading logic here, so that the chunk can be - generated asynchronously: - - - Check limits - With the environment locked: - - Check if block already is loaded and not dummy - - If so, we're ready - - - */ - - {//envlock - - //TimeTaker envlockwaittimer("block emerge envlock wait time"); - - // 0-50ms - JMutexAutoLock envlock(m_server->m_env_mutex); - - //envlockwaittimer.stop(); + v2s16 chunkpos = map.sector_to_chunk(p2d); - //TimeTaker timer("block emerge (while env locked)"); - - try{ + bool generate_chunk = false; + if(only_from_disk == false) + { + JMutexAutoLock envlock(m_server->m_env_mutex); + if(map.chunkNonVolatile(chunkpos) == false) + generate_chunk = true; + } + if(generate_chunk) + { + ChunkMakeData data; - // First check if the block already exists - //block = map.getBlockNoCreate(p); - - if(block == NULL) { - //dstream<<"Calling emergeBlock"<<std::endl; - block = map.emergeBlock( - p, - only_from_disk, - changed_blocks, - lighting_invalidated_blocks); + JMutexAutoLock envlock(m_server->m_env_mutex); + map.initChunkMake(data, chunkpos); } - // If it is a dummy, block was not found on disk - if(block->isDummy()) - { - //dstream<<"EmergeThread: Got a dummy block"<<std::endl; - got_block = false; + makeChunk(&data); - if(only_from_disk == false) - { - dstream<<"EmergeThread: wanted to generate a block but got a dummy"<<std::endl; - assert(0); - } + { + JMutexAutoLock envlock(m_server->m_env_mutex); + map.finishChunkMake(data, changed_blocks); } } - catch(InvalidPositionException &e) - { - // Block not found. - // This happens when position is over limit. - got_block = false; - } - - if(got_block) + + /* + Fetch block from map or generate a single block + */ { - if(debug && changed_blocks.size() > 0) + JMutexAutoLock envlock(m_server->m_env_mutex); + + // Load sector if it isn't loaded + if(map.getSectorNoGenerateNoEx(p2d) == NULL) + map.loadSectorFull(p2d); + + block = map.getBlockNoCreateNoEx(p); + if(!block || block->isDummy()) { - dout_server<<DTIME<<"Got changed_blocks: "; - for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator(); - i.atEnd() == false; i++) + if(only_from_disk) + { + got_block = false; + } + else { - MapBlock *block = i.getNode()->getValue(); - v3s16 p = block->getPos(); - dout_server<<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "; + ServerMapSector *sector = + (ServerMapSector*)map.getSectorNoGenerateNoEx(p2d); + block = map.generateBlock(p, block, sector, changed_blocks, + lighting_invalidated_blocks); } - dout_server<<std::endl; } + // TODO: Some additional checking and lighting updating, + // see emergeBlock + } + + {//envlock + JMutexAutoLock envlock(m_server->m_env_mutex); + + if(got_block) + { /* Collect a list of blocks that have been modified in addition to the fetched one. |