From f0145ee9fa09ce2c27b8149fee37c6f5fce7e1da Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Tue, 21 Feb 2012 15:18:02 +0000 Subject: Fixed heightmap optimization from rev 302; removed a few more cChunkPtrs git-svn-id: http://mc-server.googlecode.com/svn/trunk@303 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChunk.cpp | 58 +++++++++++++++++++++++++++++++++++------------- source/cChunk.h | 7 +++--- source/cChunkMap.cpp | 45 +++++++++++++++++++++++++++++++++++++ source/cChunkMap.h | 9 ++++++++ source/cClientHandle.cpp | 14 +++--------- source/cPiston.cpp | 15 ++++++------- source/cWorld.cpp | 27 ++++++++++++++++++++++ source/cWorld.h | 9 ++++++++ 8 files changed, 146 insertions(+), 38 deletions(-) (limited to 'source') diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 5ac0a991c..a783e30b4 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -798,17 +798,7 @@ void cChunk::SpreadLight(char* a_LightBuffer) -void cChunk::AsyncUnload( cClientHandle* a_Client ) -{ - m_UnloadQuery.remove( a_Client ); // Make sure this client is only in the list once - m_UnloadQuery.push_back( a_Client ); -} - - - - - -void cChunk::Send( cClientHandle* a_Client ) +void cChunk::SendTo(cClientHandle* a_Client) { cPacket_PreChunk PreChunk; PreChunk.m_PosX = m_PosX; @@ -870,7 +860,21 @@ void cChunk::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_Block // Update heightmap, if needed: if (a_Y >= m_HeightMap[a_X + a_Z * 16]) { - m_HeightMap[a_X + a_Z * 16] = (a_BlockType == E_BLOCK_AIR) ? (a_Y - 1) : a_Y; + if (a_BlockType != E_BLOCK_AIR) + { + m_HeightMap[a_X + a_Z * 16] = a_Y; + } + else + { + for (int y = a_Y - 1; y > 0; --y) + { + if (m_BlockData[MakeIndex(a_X, y, a_Z)] != E_BLOCK_AIR) + { + m_HeightMap[a_X + a_Z * 16] = y; + break; + } + } // for y - column in m_BlockData + } } m_ToTickBlocks[ MakeIndex( a_X, a_Y, a_Z ) ]++; @@ -951,7 +955,21 @@ void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_B // Update heightmap, if needed: if (a_Y >= m_HeightMap[a_X + a_Z * 16]) { - m_HeightMap[a_X + a_Z * 16] = (a_BlockType == E_BLOCK_AIR) ? (a_Y - 1) : a_Y; + if (a_BlockType != E_BLOCK_AIR) + { + m_HeightMap[a_X + a_Z * 16] = a_Y; + } + else + { + for (int y = a_Y - 1; y > 0; --y) + { + if (m_BlockData[MakeIndex(a_X, y, a_Z)] != E_BLOCK_AIR) + { + m_HeightMap[a_X + a_Z * 16] = y; + break; + } + } // for y - column in m_BlockData + } } } @@ -1102,20 +1120,28 @@ void cChunk::RemoveBlockEntity( cBlockEntity* a_BlockEntity ) -void cChunk::AddClient( cClientHandle* a_Client ) +bool cChunk::AddClient(cClientHandle* a_Client) { { cCSLock Lock(m_CSClients); - m_LoadedByClient.remove( a_Client ); + for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) + { + if (a_Client == *itr) + { + // Already there, nothing needed + return false; + } + } m_LoadedByClient.push_back( a_Client ); } cCSLock Lock(m_CSEntities); for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr ) { - LOG("Entity #%d (%s) at [%i %i %i] spawning for player \"%s\"", (*itr)->GetUniqueID(), (*itr)->GetClass(), m_PosX, m_PosY, m_PosZ, a_Client->GetUsername().c_str() ); + LOGD("cChunk: Entity #%d (%s) at [%i, %i, %i] spawning for player \"%s\"", (*itr)->GetUniqueID(), (*itr)->GetClass(), m_PosX, m_PosY, m_PosZ, a_Client->GetUsername().c_str() ); (*itr)->SpawnOn( a_Client ); } + return true; } diff --git a/source/cChunk.h b/source/cChunk.h index 289461f0d..bbeb2f1b4 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -146,8 +146,7 @@ public: int GetPosZ() { return m_PosZ; } cWorld * GetWorld() { return m_World; } - void Send( cClientHandle* a_Client ); - void AsyncUnload( cClientHandle* a_Client ); + void SendTo( cClientHandle * a_Client ); void SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); 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. @@ -161,7 +160,9 @@ public: void SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client ); - void AddClient (cClientHandle* a_Client ); + /// Adds a client to the chunk; returns true if added, false if already there + bool AddClient (cClientHandle* a_Client ); + void RemoveClient (cClientHandle* a_Client ); bool HasClient (cClientHandle* a_Client ); bool HasAnyClients(void); // Returns true if theres any client in the chunk; false otherwise diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 3e59c08ef..2621e0793 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -537,6 +537,51 @@ void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, +bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + if (Chunk == NULL) + { + return false; + } + return Chunk->AddClient(a_Client); +} + + + + + +void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks) +{ + cCSLock Lock(m_CSLayers); + + for (cChunkCoordsList::const_iterator itr = a_Chunks.begin(); itr != a_Chunks.end(); ++itr) + { + GetChunkNoGen(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ)->RemoveClient(a_Client); + } +} + + + + + +bool cChunkMap::SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + if ((Chunk == NULL) || !Chunk->IsValid()) + { + return false; + } + Chunk->SendTo(a_Client); + return true; +} + + + + + void cChunkMap::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cCSLock Lock(m_CSLayers); diff --git a/source/cChunkMap.h b/source/cChunkMap.h index 2ab8ea0d0..026594f11 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -59,6 +59,15 @@ public: /// Compares clients of two chunks, calls the callback accordingly void CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback); + + /// Adds client to a chunk, if not already present; returns true if added, false if present + bool AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + + /// Removes the client from all chunks specified + void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); + + /// Sends a chunk to client, returns true if successful, false if not sent + bool SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); /// Moves the entity from its current chunk to the new chunk specified void MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 51cd31433..6db6a2501 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -408,10 +408,8 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) cWorld * World = m_Player->GetWorld(); ASSERT(World != NULL); - cChunkPtr Chunk = World->GetChunk(a_ChunkX, 0, a_ChunkZ); - if (!Chunk->HasClient(this)) + if (World->AddChunkClient(a_ChunkX, a_ChunkY, a_ChunkZ, this)) { - Chunk->AddClient(this); cCSLock Lock(m_CSChunkLists); m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); @@ -429,10 +427,7 @@ void cClientHandle::RemoveFromAllChunks() cWorld * World = m_Player->GetWorld(); if (World != NULL) { - for (cChunkCoordsList::iterator itr = m_LoadedChunks.begin(); itr != m_LoadedChunks.end(); ++itr) - { - World->GetChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ)->RemoveClient(this); - } + World->RemoveClientFromChunks(this, m_LoadedChunks); } m_LoadedChunks.clear(); m_ChunksToSend.clear(); @@ -1657,14 +1652,11 @@ void cClientHandle::Tick(float a_Dt) int NumSent = 0; for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end();) { - cChunkPtr Chunk = World->GetChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); - if (!Chunk->IsValid()) + if (!World->SendChunkTo(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ, this)) { ++itr; continue; } - // The chunk has become valid, send it and remove it from the list: - Chunk->Send(this); itr = m_ChunksToSend.erase(itr); NumSent++; if (NumSent > 10) diff --git a/source/cPiston.cpp b/source/cPiston.cpp index cc6d48ca9..9c4363eeb 100644 --- a/source/cPiston.cpp +++ b/source/cPiston.cpp @@ -88,9 +88,7 @@ void cPiston::ExtendPiston( int pistx, int pisty, int pistz ) { Action.m_Byte1 = 0; Action.m_Byte2 = pistonMeta; - - cChunkPtr Chunk = m_World->GetChunkOfBlock(pistx, pisty, pistz); - Chunk->Broadcast( Action ); + m_World->BroadcastToChunkOfBlock(pistx, pisty, pistz, &Action); m_World->FastSetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta | 8 ); int extx = pistx; @@ -106,9 +104,7 @@ void cPiston::ExtendPiston( int pistx, int pisty, int pistz ) { Redstone.ChangeRedstone( extx, exty, extz, false ); //recalculate redstone around current device. Redstone.ChangeRedstone( pistx, pisty, pistz, false ); //recalculate redstone around current device. } - } - } @@ -131,8 +127,7 @@ void cPiston::RetractPiston( int pistx, int pisty, int pistz ) Action.m_PosZ = (int)pistz; Action.m_Byte1 = 1; Action.m_Byte2 = pistonMeta & ~(8); - cChunkPtr Chunk = m_World->GetChunkOfBlock(pistx, pisty, pistz); - Chunk->Broadcast( Action ); + m_World->BroadcastToChunkOfBlock(pistx, pisty, pistz, &Action ); m_World->FastSetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta & ~(8) ); AddDir( pistx, pisty, pistz, pistonMeta & 7, 1 ) @@ -160,4 +155,8 @@ void cPiston::RetractPiston( int pistx, int pisty, int pistz ) m_World->SetBlock( pistx, pisty, pistz, E_BLOCK_AIR, 0 ); } } -} \ No newline at end of file +} + + + + diff --git a/source/cWorld.cpp b/source/cWorld.cpp index a8e02a277..84f350495 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -1331,6 +1331,33 @@ void cWorld::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, in +bool cWorld::AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +{ + return m_ChunkMap->AddChunkClient(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client); +} + + + + + +void cWorld::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks) +{ + m_ChunkMap->RemoveClientFromChunks(a_Client, a_Chunks); +} + + + + + +bool cWorld::SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +{ + return m_ChunkMap->SendChunkTo(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client); +} + + + + + void cWorld::SaveAllChunks() { LOG("Saving all chunks..."); diff --git a/source/cWorld.h b/source/cWorld.h index 8a1cf729d..b181df365 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -120,6 +120,15 @@ public: /// Compares clients of two chunks, calls the callback accordingly void CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback); + + /// Adds client to a chunk, if not already present; returns true if added, false if present + bool AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + + /// Removes the client from all chunks specified + void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); + + /// Sends a chunk to client, returns true if successful, false if not sent + bool SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); // TODO: Export to Lua bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback ); -- cgit v1.2.3