Substantial cWorld::FastSetBlock() speed up by queueing all such calls and processing them later chunk-wise (makes growing trees in the generator fast again)
git-svn-id: http://mc-server.googlecode.com/svn/trunk@295 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
993bdab1e8
commit
3a8d2aa421
@ -47,6 +47,26 @@ extern bool g_bWaterPhysics;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// sSetBlock:
|
||||||
|
|
||||||
|
sSetBlock::sSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ) // absolute block position
|
||||||
|
: x( a_X )
|
||||||
|
, y( a_Y )
|
||||||
|
, z( a_Z )
|
||||||
|
, BlockType( a_BlockType )
|
||||||
|
, BlockMeta( a_BlockMeta )
|
||||||
|
{
|
||||||
|
cChunkMap::AbsoluteToRelative(x, y, z, ChunkX, ChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cChunk:
|
||||||
|
|
||||||
cChunk::cChunk(int a_X, int a_Y, int a_Z, cWorld * a_World)
|
cChunk::cChunk(int a_X, int a_Y, int a_Z, cWorld * a_World)
|
||||||
: m_bCalculateLighting( false )
|
: m_bCalculateLighting( false )
|
||||||
, m_bCalculateHeightmap( false )
|
, m_bCalculateHeightmap( false )
|
||||||
@ -872,12 +892,9 @@ void cChunk::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_Block
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta )
|
void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta)
|
||||||
{
|
{
|
||||||
if(a_X < 0 || a_X >= 16 || a_Y < 0 || a_Y >= 128 || a_Z < 0 || a_Z >= 16)
|
assert(!((a_X < 0 || a_X >= 16 || a_Y < 0 || a_Y >= 128 || a_Z < 0 || a_Z >= 16)));
|
||||||
{
|
|
||||||
return; // Clip
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(IsValid());
|
assert(IsValid());
|
||||||
|
|
||||||
@ -897,12 +914,15 @@ void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_B
|
|||||||
m_PendingSendBlocks.push_back( index );
|
m_PendingSendBlocks.push_back( index );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It's called SetLight(), but it sets the Meta when passed the BlockMeta workspace
|
||||||
SetLight( m_BlockMeta, index, a_BlockMeta );
|
SetLight( m_BlockMeta, index, a_BlockMeta );
|
||||||
|
|
||||||
// ONLY recalculate lighting if it's necessary!
|
// ONLY recalculate lighting if it's necessary!
|
||||||
if( g_BlockLightValue[ OldBlock ] != g_BlockLightValue[ a_BlockType ]
|
if(
|
||||||
|| g_BlockSpreadLightFalloff[ OldBlock ] != g_BlockSpreadLightFalloff[ a_BlockType ]
|
(g_BlockLightValue[ OldBlock ] != g_BlockLightValue[ a_BlockType ]) ||
|
||||||
|| g_BlockTransparent[ OldBlock ] != g_BlockTransparent[ a_BlockType ] )
|
(g_BlockSpreadLightFalloff[ OldBlock ] != g_BlockSpreadLightFalloff[ a_BlockType ]) ||
|
||||||
|
(g_BlockTransparent[ OldBlock ] != g_BlockTransparent[ a_BlockType ] )
|
||||||
|
)
|
||||||
{
|
{
|
||||||
RecalculateLighting();
|
RecalculateLighting();
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,21 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct sSetBlock
|
||||||
|
{
|
||||||
|
int x, y, z;
|
||||||
|
int ChunkX, ChunkZ;
|
||||||
|
char BlockType, BlockMeta;
|
||||||
|
|
||||||
|
sSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); // absolute block position
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list< sSetBlock > sSetBlockList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cChunk
|
class cChunk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -118,7 +133,7 @@ public:
|
|||||||
void AsyncUnload( cClientHandle* a_Client );
|
void AsyncUnload( cClientHandle* a_Client );
|
||||||
|
|
||||||
void SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta );
|
void SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta );
|
||||||
void FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
|
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, char a_BlockType, char a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
|
||||||
char GetBlock( int a_X, int a_Y, int a_Z );
|
char GetBlock( int a_X, int a_Y, int a_Z );
|
||||||
char GetBlock( int a_BlockIdx );
|
char GetBlock( int a_BlockIdx );
|
||||||
|
|
||||||
|
@ -351,6 +351,57 @@ int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
|
||||||
|
{
|
||||||
|
sSetBlockList Failed;
|
||||||
|
|
||||||
|
// Process all items from a_BlockList, either successfully or by placing into Failed
|
||||||
|
while (!a_BlockList.empty())
|
||||||
|
{
|
||||||
|
int ChunkX = a_BlockList.front().ChunkX;
|
||||||
|
int ChunkZ = a_BlockList.front().ChunkZ;
|
||||||
|
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||||
|
if ((Chunk != NULL) && Chunk->IsValid())
|
||||||
|
{
|
||||||
|
for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();)
|
||||||
|
{
|
||||||
|
if ((itr->ChunkX == ChunkX) && (itr->ChunkZ == ChunkZ))
|
||||||
|
{
|
||||||
|
Chunk->FastSetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta);
|
||||||
|
itr = a_BlockList.erase(itr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
} // for itr - a_BlockList[]
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The chunk is not valid, move all blocks within this chunk to Failed
|
||||||
|
for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();)
|
||||||
|
{
|
||||||
|
if ((itr->ChunkX == ChunkX) && (itr->ChunkZ == ChunkZ))
|
||||||
|
{
|
||||||
|
Failed.push_back(*itr);
|
||||||
|
itr = a_BlockList.erase(itr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
} // for itr - a_BlockList[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the failed:
|
||||||
|
std::swap(Failed, a_BlockList);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
|
void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLayers);
|
cCSLock Lock(m_CSLayers);
|
||||||
|
@ -47,6 +47,7 @@ public:
|
|||||||
bool HasChunkAnyClients (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
bool HasChunkAnyClients (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
void SpreadChunkLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void SpreadChunkLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
int GetHeight (int a_BlockX, int a_BlockZ);
|
int GetHeight (int a_BlockX, int a_BlockZ);
|
||||||
|
void FastSetBlocks (sSetBlockList & a_BlockList);
|
||||||
|
|
||||||
void Tick( float a_Dt, MTRand & a_TickRand );
|
void Tick( float a_Dt, MTRand & a_TickRand );
|
||||||
|
|
||||||
|
@ -503,17 +503,18 @@ void cWorld::Tick(float a_Dt)
|
|||||||
|
|
||||||
TickWeather(a_Dt);
|
TickWeather(a_Dt);
|
||||||
|
|
||||||
// Asynchronously set blocks
|
// Asynchronously set blocks:
|
||||||
FastSetBlockList FastSetBlockQueueCopy;
|
sSetBlockList FastSetBlockQueueCopy;
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSFastSetBlock);
|
cCSLock Lock(m_CSFastSetBlock);
|
||||||
FastSetBlockQueueCopy = m_FastSetBlockQueue;
|
std::swap(FastSetBlockQueueCopy, m_FastSetBlockQueue);
|
||||||
m_FastSetBlockQueue.clear();
|
|
||||||
}
|
}
|
||||||
for ( FastSetBlockList::iterator itr = FastSetBlockQueueCopy.begin(); itr != FastSetBlockQueueCopy.end(); ++itr )
|
m_ChunkMap->FastSetBlocks(FastSetBlockQueueCopy);
|
||||||
|
if (FastSetBlockQueueCopy.size() > 0)
|
||||||
{
|
{
|
||||||
sSetBlockData & SetBlockData = *itr;
|
// Some blocks failed, store them for next tick:
|
||||||
FastSetBlock( SetBlockData.x, SetBlockData.y, SetBlockData.z, SetBlockData.BlockID, SetBlockData.BlockMeta ); // If unable to set block, it's added to FastSetBlockQueue again
|
cCSLock Lock(m_CSFastSetBlock);
|
||||||
|
m_FastSetBlockQueue.splice(m_FastSetBlockQueue.end(), FastSetBlockQueueCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_Time - m_LastSave > 60 * 5 ) // Save each 5 minutes
|
if( m_Time - m_LastSave > 60 * 5 ) // Save each 5 minutes
|
||||||
@ -847,20 +848,8 @@ void cWorld::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_Block
|
|||||||
|
|
||||||
void cWorld::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta )
|
void cWorld::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta )
|
||||||
{
|
{
|
||||||
int ChunkX, ChunkY, ChunkZ, X = a_X, Y = a_Y, Z = a_Z;
|
|
||||||
|
|
||||||
AbsoluteToRelative( X, Y, Z, ChunkX, ChunkY, ChunkZ );
|
|
||||||
|
|
||||||
cChunkPtr Chunk = GetChunkNoGen( ChunkX, ChunkY, ChunkZ );
|
|
||||||
if (Chunk->IsValid())
|
|
||||||
{
|
|
||||||
Chunk->FastSetBlock(X, Y, Z, a_BlockType, a_BlockMeta );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unable to set block right now, try again later
|
|
||||||
cCSLock Lock(m_CSFastSetBlock);
|
cCSLock Lock(m_CSFastSetBlock);
|
||||||
m_FastSetBlockQueue.push_back( sSetBlockData( a_X, a_Y, a_Z, a_BlockType, a_BlockMeta ) );
|
m_FastSetBlockQueue.push_back(sSetBlock(a_X, a_Y, a_Z, a_BlockType, a_BlockMeta));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -183,21 +183,6 @@ private:
|
|||||||
|
|
||||||
friend class cRoot;
|
friend class cRoot;
|
||||||
|
|
||||||
struct sSetBlockData
|
|
||||||
{
|
|
||||||
sSetBlockData( int a_X, int a_Y, int a_Z, char a_BlockID, char a_BlockMeta )
|
|
||||||
: x( a_X )
|
|
||||||
, y( a_Y )
|
|
||||||
, z( a_Z )
|
|
||||||
, BlockID( a_BlockID )
|
|
||||||
, BlockMeta( a_BlockMeta )
|
|
||||||
{}
|
|
||||||
int x, y, z;
|
|
||||||
char BlockID, BlockMeta;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::list< sSetBlockData > FastSetBlockList;
|
|
||||||
|
|
||||||
// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
|
// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
|
||||||
MTRand m_TickRand;
|
MTRand m_TickRand;
|
||||||
|
|
||||||
@ -252,7 +237,7 @@ private:
|
|||||||
cChunkCoordsList m_SpreadQueue;
|
cChunkCoordsList m_SpreadQueue;
|
||||||
|
|
||||||
cCriticalSection m_CSFastSetBlock;
|
cCriticalSection m_CSFastSetBlock;
|
||||||
FastSetBlockList m_FastSetBlockQueue;
|
sSetBlockList m_FastSetBlockQueue;
|
||||||
|
|
||||||
cChunkGenerator m_Generator;
|
cChunkGenerator m_Generator;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user