summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormadmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6>2012-03-06 15:52:44 +0100
committermadmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6>2012-03-06 15:52:44 +0100
commit8cdd63f06c692f117088909ea5c9b950bba34376 (patch)
treef07924d43ede604c6a5fe30df5914c68a8f7f1dc
parentFixed bug FS#157 http://mc-server.org/support/index.php?do=details&task_id=157 (diff)
downloadcuberite-8cdd63f06c692f117088909ea5c9b950bba34376.tar
cuberite-8cdd63f06c692f117088909ea5c9b950bba34376.tar.gz
cuberite-8cdd63f06c692f117088909ea5c9b950bba34376.tar.bz2
cuberite-8cdd63f06c692f117088909ea5c9b950bba34376.tar.lz
cuberite-8cdd63f06c692f117088909ea5c9b950bba34376.tar.xz
cuberite-8cdd63f06c692f117088909ea5c9b950bba34376.tar.zst
cuberite-8cdd63f06c692f117088909ea5c9b950bba34376.zip
-rw-r--r--source/ChunkSender.cpp113
-rw-r--r--source/ChunkSender.h29
-rw-r--r--source/cClientHandle.cpp15
-rw-r--r--source/cWorld.cpp18
-rw-r--r--source/cWorld.h6
5 files changed, 155 insertions, 26 deletions
diff --git a/source/ChunkSender.cpp b/source/ChunkSender.cpp
index 527db4543..47d84d166 100644
--- a/source/ChunkSender.cpp
+++ b/source/ChunkSender.cpp
@@ -62,12 +62,44 @@ void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
+void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client)
+{
+ ASSERT(a_Client != NULL);
+ {
+ cCSLock Lock(m_CS);
+ m_SendChunks.push_back(sSendChunk(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client));
+ }
+ m_Event.Set();
+}
+
+
+
+
+
+void cChunkSender::RemoveClient(cClientHandle * a_Client)
+{
+ cCSLock Lock(m_CS);
+ for (sSendChunkList::iterator itr = m_SendChunks.begin(); itr != m_SendChunks.end();)
+ {
+ if (itr->m_Client == a_Client)
+ {
+ itr = m_SendChunks.erase(itr);
+ continue;
+ }
+ ++itr;
+ } // for itr - m_SendChunks[]
+}
+
+
+
+
+
void cChunkSender::Execute(void)
{
while (!mShouldTerminate)
{
cCSLock Lock(m_CS);
- while (m_ChunksReady.empty())
+ while (m_ChunksReady.empty() && m_SendChunks.empty())
{
cCSUnlock Unlock(Lock);
m_Event.Wait();
@@ -77,28 +109,24 @@ void cChunkSender::Execute(void)
}
} // while (empty)
- // Take one from the queue:
- cChunkCoords Coords(m_ChunksReady.front());
- m_ChunksReady.pop_front();
- Lock.Unlock();
-
- ASSERT(m_World != NULL);
-
- // Send it to anyone waiting:
- m_World->GetChunkData(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, this);
- cPacket_PreChunk PreChunk(Coords.m_ChunkX, Coords.m_ChunkZ, true);
- cPacket_MapChunk MapChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, m_BlockData);
- m_World->BroadcastToChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, PreChunk);
- m_World->BroadcastToChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, MapChunk);
-
- // Send entity creation packets:
- for (PacketList::iterator itr = m_Packets.begin(); itr != m_Packets.end(); ++itr)
+ if (!m_ChunksReady.empty())
{
- m_World->BroadcastToChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, **itr);
- delete *itr;
- } // for itr - m_Packets
- m_Packets.clear();
-
+ // Take one from the queue:
+ cChunkCoords Coords(m_ChunksReady.front());
+ m_ChunksReady.pop_front();
+ Lock.Unlock();
+
+ SendChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, NULL);
+ }
+ else
+ {
+ // Take one from the queue:
+ sSendChunk Chunk(m_SendChunks.front());
+ m_SendChunks.pop_front();
+ Lock.Unlock();
+
+ SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkY, Chunk.m_ChunkZ, Chunk.m_Client);
+ }
} // while (!mShouldTerminate)
}
@@ -106,6 +134,47 @@ void cChunkSender::Execute(void)
+void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client)
+{
+ ASSERT(m_World != NULL);
+
+ // Prepare MapChunk packets:
+ m_World->GetChunkData(a_ChunkX, a_ChunkY, a_ChunkZ, this);
+ cPacket_PreChunk PreChunk(a_ChunkX, a_ChunkZ, true);
+ cPacket_MapChunk MapChunk(a_ChunkX, a_ChunkY, a_ChunkZ, m_BlockData);
+
+ // Send:
+ if (a_Client == NULL)
+ {
+ m_World->BroadcastToChunk(a_ChunkX, a_ChunkY, a_ChunkZ, PreChunk);
+ m_World->BroadcastToChunk(a_ChunkX, a_ChunkY, a_ChunkZ, MapChunk);
+ }
+ else
+ {
+ a_Client->Send(PreChunk);
+ a_Client->Send(MapChunk);
+ }
+
+ // Send entity creation packets:
+ for (PacketList::iterator itr = m_Packets.begin(); itr != m_Packets.end(); ++itr)
+ {
+ if (a_Client == NULL)
+ {
+ m_World->BroadcastToChunk(a_ChunkX, a_ChunkY, a_ChunkZ, **itr);
+ }
+ else
+ {
+ a_Client->Send(**itr);
+ }
+ delete *itr;
+ } // for itr - m_Packets[]
+ m_Packets.clear();
+}
+
+
+
+
+
void cChunkSender::BlockData(const char * a_Data)
{
memcpy(m_BlockData, a_Data, cChunk::c_BlockDataSize);
diff --git a/source/ChunkSender.h b/source/ChunkSender.h
index a56e797da..e61c45d1e 100644
--- a/source/ChunkSender.h
+++ b/source/ChunkSender.h
@@ -18,6 +18,7 @@
class cWorld;
+class cClientHandle;
@@ -34,14 +35,40 @@ public:
bool Start(cWorld * a_World);
+ /// Notifies that a chunk has become ready and it should be sent to all its clients
void ChunkReady(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+ /// Queues a chunk to be sent to a specific client
+ void QueueSendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes the a_Client from all waiting chunk send operations
+ void RemoveClient(cClientHandle * a_Client);
+
protected:
+ /// Used for sending chunks to specific clients
+ struct sSendChunk
+ {
+ int m_ChunkX;
+ int m_ChunkY;
+ int m_ChunkZ;
+ cClientHandle * m_Client;
+
+ sSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) :
+ m_ChunkX(a_ChunkX),
+ m_ChunkY(a_ChunkY),
+ m_ChunkZ(a_ChunkZ),
+ m_Client(a_Client)
+ {
+ }
+ };
+ typedef std::list<sSendChunk> sSendChunkList;
+
cWorld * m_World;
cCriticalSection m_CS;
cChunkCoordsList m_ChunksReady;
+ sSendChunkList m_SendChunks;
cEvent m_Event; // Set when anything is added to m_ChunksReady
// Data about the chunk that is being sent:
@@ -56,6 +83,8 @@ protected:
virtual void Entity(cEntity * a_Entity) override;
virtual void BlockEntity(cBlockEntity * a_Entity) override;
+ /// Sends the specified chunk to a_Client, or to all chunk clients if a_Client == NULL
+ void SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client);
} ;
diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp
index 9ea063f11..ee9f0ab3a 100644
--- a/source/cClientHandle.cpp
+++ b/source/cClientHandle.cpp
@@ -240,6 +240,7 @@ void cClientHandle::Destroy()
if ((m_Player != NULL) && (m_Player->GetWorld() != NULL))
{
RemoveFromAllChunks();
+ m_Player->GetWorld()->RemoveClientFromChunkSender(this);
}
m_bDestroyed = true;
@@ -355,7 +356,8 @@ void cClientHandle::StreamChunks(void)
cWorld * World = m_Player->GetWorld();
ASSERT(World != NULL);
- // Remove all loaded chunks that are no longer in range:
+ // Remove all loaded chunks that are no longer in range; deferred to out-of-CS:
+ cChunkCoordsList RemoveChunks;
{
cCSLock Lock(m_CSChunkLists);
for (cChunkCoordsList::iterator itr = m_LoadedChunks.begin(); itr != m_LoadedChunks.end();)
@@ -364,8 +366,7 @@ void cClientHandle::StreamChunks(void)
int RelZ = (*itr).m_ChunkZ - ChunkPosZ;
if ((RelX > m_ViewDistance) || (RelX < -m_ViewDistance) || (RelZ > m_ViewDistance) || (RelZ < -m_ViewDistance))
{
- World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ, this);
- Send( cPacket_PreChunk( itr->m_ChunkX, itr->m_ChunkZ, false ) );
+ RemoveChunks.push_back(*itr);
itr = m_LoadedChunks.erase(itr);
}
else
@@ -385,8 +386,13 @@ void cClientHandle::StreamChunks(void)
{
++itr;
}
- }
+ } // for itr - m_ChunksToSend[]
}
+ for (cChunkCoordsList::iterator itr = RemoveChunks.begin(); itr != RemoveChunks.end(); ++itr)
+ {
+ World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ, this);
+ Send(cPacket_PreChunk(itr->m_ChunkX, itr->m_ChunkZ, false));
+ } // for itr - RemoveChunks[]
// Add all chunks that are in range and not yet in m_LoadedChunks:
// Queue these smartly - from the center out to the edge
@@ -435,6 +441,7 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
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));
+ World->SendChunkTo(a_ChunkX, a_ChunkY, a_ChunkZ, this);
}
}
diff --git a/source/cWorld.cpp b/source/cWorld.cpp
index d74f6ea93..c5cdca03a 100644
--- a/source/cWorld.cpp
+++ b/source/cWorld.cpp
@@ -1292,6 +1292,24 @@ void cWorld::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoords
+void cWorld::SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client)
+{
+ m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client);
+}
+
+
+
+
+
+void cWorld::RemoveClientFromChunkSender(cClientHandle * a_Client)
+{
+ m_ChunkSender.RemoveClient(a_Client);
+}
+
+
+
+
+
void cWorld::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
{
m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
diff --git a/source/cWorld.h b/source/cWorld.h
index e4fac9d90..bd562ce6f 100644
--- a/source/cWorld.h
+++ b/source/cWorld.h
@@ -130,6 +130,12 @@ public:
/// Removes the client from all chunks specified
void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks);
+ /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is ignored (ChunkSender will send that chunk when it becomes valid)
+ void SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes client from ChunkSender's queue of chunks to be sent
+ void RemoveClientFromChunkSender(cClientHandle * a_Client);
+
/// Touches the chunk, causing it to be loaded or generated
void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);