Map generation is now properly threaded and doesn't block block placement and other stuff.
parent
6fa85c8502
commit
10eedbc1d2
|
@ -429,7 +429,7 @@ void ServerEnvironment::step(float dtime)
|
||||||
|
|
||||||
bool send_recommended = false;
|
bool send_recommended = false;
|
||||||
m_send_recommended_timer += dtime;
|
m_send_recommended_timer += dtime;
|
||||||
if(m_send_recommended_timer > 0.1)
|
if(m_send_recommended_timer > 0.15)
|
||||||
{
|
{
|
||||||
m_send_recommended_timer = 0;
|
m_send_recommended_timer = 0;
|
||||||
send_recommended = true;
|
send_recommended = true;
|
||||||
|
|
118
src/map.cpp
118
src/map.cpp
|
@ -2170,23 +2170,6 @@ void addRandomObjects(MapBlock *block)
|
||||||
This is the main map generation method
|
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)
|
void makeChunk(ChunkMakeData *data)
|
||||||
{
|
{
|
||||||
s16 y_nodes_min = data->y_blocks_min * MAP_BLOCKSIZE;
|
s16 y_nodes_min = data->y_blocks_min * MAP_BLOCKSIZE;
|
||||||
|
@ -2235,11 +2218,11 @@ void makeChunk(ChunkMakeData *data)
|
||||||
/*
|
/*
|
||||||
Skip of already generated
|
Skip of already generated
|
||||||
*/
|
*/
|
||||||
{
|
/*{
|
||||||
v3s16 p(p2d.X, y_nodes_min, p2d.Y);
|
v3s16 p(p2d.X, y_nodes_min, p2d.Y);
|
||||||
if(data->vmanip.m_data[data->vmanip.m_area.index(p)].d != CONTENT_AIR)
|
if(data->vmanip.m_data[data->vmanip.m_area.index(p)].d != CONTENT_AIR)
|
||||||
continue;
|
continue;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// Ground height at this point
|
// Ground height at this point
|
||||||
float surface_y_f = 0.0;
|
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));
|
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++)
|
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_data[i].d = CONTENT_STONE;
|
||||||
|
|
||||||
data->vmanip.m_area.add_y(em, i, 1);
|
data->vmanip.m_area.add_y(em, i, 1);
|
||||||
|
@ -3426,33 +3416,8 @@ void makeChunk(ChunkMakeData *data)
|
||||||
//###################################################################
|
//###################################################################
|
||||||
//###################################################################
|
//###################################################################
|
||||||
|
|
||||||
MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
|
void ServerMap::initChunkMake(ChunkMakeData &data, 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()");
|
|
||||||
|
|
||||||
// The distance how far into the neighbors the generator is allowed to go.
|
// The distance how far into the neighbors the generator is allowed to go.
|
||||||
s16 max_spread_amount_sectors = 2;
|
s16 max_spread_amount_sectors = 2;
|
||||||
assert(max_spread_amount_sectors <= m_chunksize);
|
assert(max_spread_amount_sectors <= m_chunksize);
|
||||||
|
@ -3469,8 +3434,8 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
|
||||||
s16 sectorpos_bigbase_size =
|
s16 sectorpos_bigbase_size =
|
||||||
sectorpos_base_size + 2 * max_spread_amount_sectors;
|
sectorpos_base_size + 2 * max_spread_amount_sectors;
|
||||||
|
|
||||||
ChunkMakeData data;
|
|
||||||
data.seed = m_seed;
|
data.seed = m_seed;
|
||||||
|
data.chunkpos = chunkpos;
|
||||||
data.y_blocks_min = y_blocks_min;
|
data.y_blocks_min = y_blocks_min;
|
||||||
data.y_blocks_max = y_blocks_max;
|
data.y_blocks_max = y_blocks_max;
|
||||||
data.sectorpos_base = sectorpos_base;
|
data.sectorpos_base = sectorpos_base;
|
||||||
|
@ -3541,9 +3506,11 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
|
||||||
data.vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
|
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
|
Blit generated stuff to map
|
||||||
*/
|
*/
|
||||||
|
@ -3569,14 +3536,14 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
|
||||||
Add random objects to blocks
|
Add random objects to blocks
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
for(s16 x=0; x<sectorpos_base_size; x++)
|
for(s16 x=0; x<data.sectorpos_base_size; x++)
|
||||||
for(s16 z=0; z<sectorpos_base_size; z++)
|
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);
|
ServerMapSector *sector = createSector(sectorpos);
|
||||||
assert(sector);
|
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);
|
v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
|
||||||
MapBlock *block = createBlock(blockpos);
|
MapBlock *block = createBlock(blockpos);
|
||||||
|
@ -3592,7 +3559,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
|
||||||
for(s16 x=-1; x<=1; x++)
|
for(s16 x=-1; x<=1; x++)
|
||||||
for(s16 y=-1; y<=1; y++)
|
for(s16 y=-1; y<=1; y++)
|
||||||
{
|
{
|
||||||
v2s16 chunkpos0 = chunkpos + v2s16(x,y);
|
v2s16 chunkpos0 = data.chunkpos + v2s16(x,y);
|
||||||
// Add chunk meta information
|
// Add chunk meta information
|
||||||
MapChunk *chunk = getChunk(chunkpos0);
|
MapChunk *chunk = getChunk(chunkpos0);
|
||||||
if(chunk == NULL)
|
if(chunk == NULL)
|
||||||
|
@ -3608,7 +3575,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
|
||||||
/*
|
/*
|
||||||
Set central chunk non-volatile
|
Set central chunk non-volatile
|
||||||
*/
|
*/
|
||||||
MapChunk *chunk = getChunk(chunkpos);
|
MapChunk *chunk = getChunk(data.chunkpos);
|
||||||
assert(chunk);
|
assert(chunk);
|
||||||
// Set non-volatile
|
// Set non-volatile
|
||||||
//chunk->setIsVolatile(false);
|
//chunk->setIsVolatile(false);
|
||||||
|
@ -3618,6 +3585,48 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
|
||||||
Save changed parts of map
|
Save changed parts of map
|
||||||
*/
|
*/
|
||||||
save(true);
|
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 central chunk (which was requested)
|
||||||
|
@ -3625,6 +3634,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Deprecated
|
||||||
MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
|
MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
|
||||||
core::map<v3s16, MapBlock*> &changed_blocks)
|
core::map<v3s16, MapBlock*> &changed_blocks)
|
||||||
{
|
{
|
||||||
|
|
26
src/map.h
26
src/map.h
|
@ -318,6 +318,8 @@ protected:
|
||||||
This is the only map class that is able to generate map.
|
This is the only map class that is able to generate map.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct ChunkMakeData;
|
||||||
|
|
||||||
class ServerMap : public Map
|
class ServerMap : public Map
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -391,6 +393,10 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initChunkMake(ChunkMakeData &data, v2s16 chunkpos);
|
||||||
|
MapChunk* finishChunkMake(ChunkMakeData &data,
|
||||||
|
core::map<v3s16, MapBlock*> &changed_blocks);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Generate a chunk.
|
Generate a chunk.
|
||||||
|
|
||||||
|
@ -746,5 +752,25 @@ protected:
|
||||||
bool m_create_area;
|
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
|
#endif
|
||||||
|
|
||||||
|
|
123
src/server.cpp
123
src/server.cpp
|
@ -72,7 +72,7 @@ void * EmergeThread::Thread()
|
||||||
|
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
|
||||||
bool debug=false;
|
//bool debug=false;
|
||||||
|
|
||||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||||
|
|
||||||
|
@ -91,7 +91,19 @@ void * EmergeThread::Thread()
|
||||||
SharedPtr<QueuedBlockEmerge> q(qptr);
|
SharedPtr<QueuedBlockEmerge> q(qptr);
|
||||||
|
|
||||||
v3s16 &p = q->pos;
|
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;
|
//derr_server<<"EmergeThread::Thread(): running"<<std::endl;
|
||||||
|
|
||||||
//TimeTaker timer("block emerge");
|
//TimeTaker timer("block emerge");
|
||||||
|
@ -144,78 +156,67 @@ void * EmergeThread::Thread()
|
||||||
if(optional)
|
if(optional)
|
||||||
only_from_disk = true;
|
only_from_disk = true;
|
||||||
|
|
||||||
/*
|
v2s16 chunkpos = map.sector_to_chunk(p2d);
|
||||||
TODO: Map loading logic here, so that the chunk can be
|
|
||||||
generated asynchronously:
|
|
||||||
|
|
||||||
- Check limits
|
bool generate_chunk = false;
|
||||||
With the environment locked:
|
if(only_from_disk == false)
|
||||||
- Check if block already is loaded and not dummy
|
{
|
||||||
- If so, we're ready
|
JMutexAutoLock envlock(m_server->m_env_mutex);
|
||||||
-
|
if(map.chunkNonVolatile(chunkpos) == false)
|
||||||
*/
|
generate_chunk = true;
|
||||||
|
}
|
||||||
{//envlock
|
if(generate_chunk)
|
||||||
|
{
|
||||||
//TimeTaker envlockwaittimer("block emerge envlock wait time");
|
ChunkMakeData data;
|
||||||
|
|
||||||
// 0-50ms
|
|
||||||
JMutexAutoLock envlock(m_server->m_env_mutex);
|
|
||||||
|
|
||||||
//envlockwaittimer.stop();
|
|
||||||
|
|
||||||
//TimeTaker timer("block emerge (while env locked)");
|
|
||||||
|
|
||||||
try{
|
|
||||||
|
|
||||||
// First check if the block already exists
|
|
||||||
//block = map.getBlockNoCreate(p);
|
|
||||||
|
|
||||||
if(block == NULL)
|
|
||||||
{
|
{
|
||||||
//dstream<<"Calling emergeBlock"<<std::endl;
|
JMutexAutoLock envlock(m_server->m_env_mutex);
|
||||||
block = map.emergeBlock(
|
map.initChunkMake(data, chunkpos);
|
||||||
p,
|
|
||||||
only_from_disk,
|
|
||||||
changed_blocks,
|
|
||||||
lighting_invalidated_blocks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it is a dummy, block was not found on disk
|
makeChunk(&data);
|
||||||
if(block->isDummy())
|
|
||||||
{
|
|
||||||
//dstream<<"EmergeThread: Got a dummy block"<<std::endl;
|
|
||||||
got_block = false;
|
|
||||||
|
|
||||||
if(only_from_disk == false)
|
{
|
||||||
|
JMutexAutoLock envlock(m_server->m_env_mutex);
|
||||||
|
map.finishChunkMake(data, changed_blocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fetch block from map or generate a single block
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
if(only_from_disk)
|
||||||
{
|
{
|
||||||
dstream<<"EmergeThread: wanted to generate a block but got a dummy"<<std::endl;
|
got_block = false;
|
||||||
assert(0);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ServerMapSector *sector =
|
||||||
|
(ServerMapSector*)map.getSectorNoGenerateNoEx(p2d);
|
||||||
|
block = map.generateBlock(p, block, sector, changed_blocks,
|
||||||
|
lighting_invalidated_blocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Some additional checking and lighting updating,
|
||||||
|
// see emergeBlock
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e)
|
|
||||||
{
|
{//envlock
|
||||||
// Block not found.
|
JMutexAutoLock envlock(m_server->m_env_mutex);
|
||||||
// This happens when position is over limit.
|
|
||||||
got_block = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(got_block)
|
if(got_block)
|
||||||
{
|
{
|
||||||
if(debug && changed_blocks.size() > 0)
|
|
||||||
{
|
|
||||||
dout_server<<DTIME<<"Got changed_blocks: ";
|
|
||||||
for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
|
|
||||||
i.atEnd() == false; i++)
|
|
||||||
{
|
|
||||||
MapBlock *block = i.getNode()->getValue();
|
|
||||||
v3s16 p = block->getPos();
|
|
||||||
dout_server<<"("<<p.X<<","<<p.Y<<","<<p.Z<<") ";
|
|
||||||
}
|
|
||||||
dout_server<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collect a list of blocks that have been modified in
|
Collect a list of blocks that have been modified in
|
||||||
addition to the fetched one.
|
addition to the fetched one.
|
||||||
|
|
Loading…
Reference in New Issue