From 3a8d2aa421fcfa11a84a911aaaa6b5aa4e16cab3 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sat, 18 Feb 2012 20:10:57 +0000 Subject: [PATCH] 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 --- source/cChunk.cpp | 36 ++++++++++++++++++++++++------- source/cChunk.h | 17 ++++++++++++++- source/cChunkMap.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++++ source/cChunkMap.h | 1 + source/cWorld.cpp | 29 ++++++++----------------- source/cWorld.h | 17 +-------------- 6 files changed, 106 insertions(+), 45 deletions(-) diff --git a/source/cChunk.cpp b/source/cChunk.cpp index afa69fb68..d070e82aa 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -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) : m_bCalculateLighting( 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) - { - return; // Clip - } + assert(!((a_X < 0 || a_X >= 16 || a_Y < 0 || a_Y >= 128 || a_Z < 0 || a_Z >= 16))); 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 ); } + // It's called SetLight(), but it sets the Meta when passed the BlockMeta workspace SetLight( m_BlockMeta, index, a_BlockMeta ); // ONLY recalculate lighting if it's necessary! - if( g_BlockLightValue[ OldBlock ] != g_BlockLightValue[ a_BlockType ] - || g_BlockSpreadLightFalloff[ OldBlock ] != g_BlockSpreadLightFalloff[ a_BlockType ] - || g_BlockTransparent[ OldBlock ] != g_BlockTransparent[ a_BlockType ] ) + if( + (g_BlockLightValue[ OldBlock ] != g_BlockLightValue[ a_BlockType ]) || + (g_BlockSpreadLightFalloff[ OldBlock ] != g_BlockSpreadLightFalloff[ a_BlockType ]) || + (g_BlockTransparent[ OldBlock ] != g_BlockTransparent[ a_BlockType ] ) + ) { RecalculateLighting(); } diff --git a/source/cChunk.h b/source/cChunk.h index 2576e2412..4453ed16a 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -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 { public: @@ -118,7 +133,7 @@ public: void AsyncUnload( cClientHandle* a_Client ); 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_BlockIdx ); diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index c5512dd68..0657f51d3 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -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 ) { cCSLock Lock(m_CSLayers); diff --git a/source/cChunkMap.h b/source/cChunkMap.h index 7c26a14c0..a9cb4d661 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -47,6 +47,7 @@ public: bool HasChunkAnyClients (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); + void FastSetBlocks (sSetBlockList & a_BlockList); void Tick( float a_Dt, MTRand & a_TickRand ); diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 41b9c5068..f5e40ec0b 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -503,17 +503,18 @@ void cWorld::Tick(float a_Dt) TickWeather(a_Dt); - // Asynchronously set blocks - FastSetBlockList FastSetBlockQueueCopy; + // Asynchronously set blocks: + sSetBlockList FastSetBlockQueueCopy; { cCSLock Lock(m_CSFastSetBlock); - FastSetBlockQueueCopy = m_FastSetBlockQueue; - m_FastSetBlockQueue.clear(); + std::swap(FastSetBlockQueueCopy, m_FastSetBlockQueue); } - for ( FastSetBlockList::iterator itr = FastSetBlockQueueCopy.begin(); itr != FastSetBlockQueueCopy.end(); ++itr ) + m_ChunkMap->FastSetBlocks(FastSetBlockQueueCopy); + if (FastSetBlockQueueCopy.size() > 0) { - sSetBlockData & SetBlockData = *itr; - FastSetBlock( SetBlockData.x, SetBlockData.y, SetBlockData.z, SetBlockData.BlockID, SetBlockData.BlockMeta ); // If unable to set block, it's added to FastSetBlockQueue again + // Some blocks failed, store them for next tick: + cCSLock Lock(m_CSFastSetBlock); + m_FastSetBlockQueue.splice(m_FastSetBlockQueue.end(), FastSetBlockQueueCopy); } 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 ) { - 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); - 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)); } diff --git a/source/cWorld.h b/source/cWorld.h index 569fe8d32..a9c068336 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -183,21 +183,6 @@ private: 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) MTRand m_TickRand; @@ -252,7 +237,7 @@ private: cChunkCoordsList m_SpreadQueue; cCriticalSection m_CSFastSetBlock; - FastSetBlockList m_FastSetBlockQueue; + sSetBlockList m_FastSetBlockQueue; cChunkGenerator m_Generator;