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;
/*
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;
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);
//###################################################################
//###################################################################
-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);
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;
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
*/
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);
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)
/*
Set central chunk non-volatile
*/
- MapChunk *chunk = getChunk(chunkpos);
+ MapChunk *chunk = getChunk(data.chunkpos);
assert(chunk);
// Set non-volatile
//chunk->setIsVolatile(false);
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)
return chunk;
}
+// NOTE: Deprecated
MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
core::map<v3s16, MapBlock*> &changed_blocks)
{
DSTACK(__FUNCTION_NAME);
- bool debug=false;
+ //bool debug=false;
BEGIN_DEBUG_EXCEPTION_HANDLER
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");
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.