diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Chunk.cpp | 16 | ||||
-rw-r--r-- | src/Chunk.h | 1 | ||||
-rw-r--r-- | src/ChunkMap.cpp | 16 | ||||
-rw-r--r-- | src/ChunkMap.h | 3 | ||||
-rw-r--r-- | src/ChunkSender.cpp | 145 | ||||
-rw-r--r-- | src/ChunkSender.h | 14 | ||||
-rw-r--r-- | src/World.cpp | 57 | ||||
-rw-r--r-- | src/World.h | 2 |
8 files changed, 138 insertions, 116 deletions
diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 7af669163..02bc2ba8c 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -2852,22 +2852,6 @@ void cChunk::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cons -void cChunk::BroadcastChunkData(cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude) -{ - for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) - { - if (*itr == a_Exclude) - { - continue; - } - (*itr)->SendChunkData(m_PosX, m_PosZ, a_Serializer); - } // for itr - LoadedByClient[] -} - - - - - void cChunk::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) { for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) diff --git a/src/Chunk.h b/src/Chunk.h index f57769107..fd9ea0b0c 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -319,7 +319,6 @@ public: void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = nullptr); void BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr); void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr); - void BroadcastChunkData (cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = nullptr); void BroadcastCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = nullptr); diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 2f38e4cd6..4db73971c 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -409,22 +409,6 @@ void cChunkMap::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c -void cChunkMap::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude) -{ - cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if (Chunk == nullptr) - { - return; - } - // It's perfectly legal to broadcast packets even to invalid chunks! - Chunk->BroadcastChunkData(a_Serializer, a_Exclude); -} - - - - - void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 964188bbe..64e83f3f6 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -73,7 +73,6 @@ public: void BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = nullptr); void BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr); void BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude); - void BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = nullptr); void BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); void BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); void BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); @@ -303,7 +302,7 @@ public: Returns false if there's no command block at those coords or callback returns true, returns true if found. */ bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible - /** Calls the callback for the mob head block at the specified coords. + /** Calls the callback for the mob head block at the specified coords.chu Returns false if there's no mob head block at those coords or callback returns true, returns true if found. */ bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); // Lua-accessible diff --git a/src/ChunkSender.cpp b/src/ChunkSender.cpp index 2f18ea75c..1a3d234cc 100644 --- a/src/ChunkSender.cpp +++ b/src/ChunkSender.cpp @@ -13,7 +13,7 @@ #include "BlockEntities/BlockEntity.h" #include "Protocol/ChunkDataSerializer.h" #include "ClientHandle.h" - +#include "Chunk.h" @@ -28,25 +28,29 @@ class cNotifyChunkSender : { virtual void Call(int a_ChunkX, int a_ChunkZ) override { - m_ChunkSender->ChunkReady(a_ChunkX, a_ChunkZ); + cChunkSender & ChunkSender = m_ChunkSender; + m_World.DoWithChunk( + a_ChunkX, a_ChunkZ, + [&ChunkSender] (cChunk & a_Chunk) -> bool + { + ChunkSender.QueueSendChunkTo(a_Chunk.GetPosX(), a_Chunk.GetPosZ(), cChunkSender::PRIORITY_BROADCAST, a_Chunk.GetAllClients()); + return true; + } + ); } - cChunkSender * m_ChunkSender; -public: - cNotifyChunkSender(cChunkSender * a_ChunkSender) : m_ChunkSender(a_ChunkSender) {} -}; - - - + cChunkSender & m_ChunkSender; + cWorld & m_World; +public: + cNotifyChunkSender(cChunkSender & a_ChunkSender, cWorld & a_World) : m_ChunkSender(a_ChunkSender), m_World(a_World) {} -//////////////////////////////////////////////////////////////////////////////// -// cChunkSender: +}; -cChunkSender::cChunkSender(void) : +cChunkSender::cChunkSender(cWorld & a_World) : super("ChunkSender"), - m_World(nullptr), + m_World(a_World), m_RemoveCount(0) { } @@ -64,10 +68,9 @@ cChunkSender::~cChunkSender() -bool cChunkSender::Start(cWorld * a_World) +bool cChunkSender::Start() { m_ShouldTerminate = false; - m_World = a_World; return super::Start(); } @@ -86,20 +89,6 @@ void cChunkSender::Stop(void) -void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkZ) -{ - // This is probably never gonna be called twice for the same chunk, and if it is, we don't mind, so we don't check - { - cCSLock Lock(m_CS); - m_ChunksReady.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); - } - m_evtQueue.Set(); -} - - - - - void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, eChunkPriority a_Priority, cClientHandle * a_Client) { ASSERT(a_Client != nullptr); @@ -134,6 +123,61 @@ void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, eChunkPriority a m_SendChunksHighPriority.push_back(Chunk); break; } + case PRIORITY_BROADCAST: + { + m_SendChunksBroadcastPriority.push_back(Chunk); + break; + } + } + } + m_evtQueue.Set(); +} + + + + + + +void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, eChunkPriority a_Priority, std::list<cClientHandle *> a_Clients) +{ + { + cCSLock Lock(m_CS); + for (auto client : a_Clients) + { + sSendChunk Chunk(a_ChunkX, a_ChunkZ, client); + if ( + std::find(m_SendChunksLowPriority.begin(), m_SendChunksLowPriority.end(), Chunk) != m_SendChunksLowPriority.end() || + std::find(m_SendChunksMediumPriority.begin(), m_SendChunksMediumPriority.end(), Chunk) != m_SendChunksMediumPriority.end() || + std::find(m_SendChunksHighPriority.begin(), m_SendChunksHighPriority.end(), Chunk) != m_SendChunksHighPriority.end() + ) + { + // Already queued, bail out + continue; + } + + switch (a_Priority) + { + case E_CHUNK_PRIORITY_LOW: + { + m_SendChunksLowPriority.push_back(Chunk); + break; + } + case E_CHUNK_PRIORITY_MEDIUM: + { + m_SendChunksMediumPriority.push_back(Chunk); + break; + } + case E_CHUNK_PRIORITY_HIGH: + { + m_SendChunksHighPriority.push_back(Chunk); + break; + } + case PRIORITY_BROADCAST: + { + m_SendChunksBroadcastPriority.push_back(Chunk); + break; + } + } } } m_evtQueue.Set(); @@ -189,7 +233,7 @@ void cChunkSender::Execute(void) while (!m_ShouldTerminate) { cCSLock Lock(m_CS); - while (m_ChunksReady.empty() && m_SendChunksLowPriority.empty() && m_SendChunksMediumPriority.empty() && m_SendChunksHighPriority.empty()) + while (m_SendChunksBroadcastPriority.empty() && m_SendChunksLowPriority.empty() && m_SendChunksMediumPriority.empty() && m_SendChunksHighPriority.empty()) { int RemoveCount = m_RemoveCount; m_RemoveCount = 0; @@ -214,14 +258,14 @@ void cChunkSender::Execute(void) SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkZ, Chunk.m_Client); } - else if (!m_ChunksReady.empty()) + else if (!m_SendChunksBroadcastPriority.empty()) { // Take one from the queue: - cChunkCoords Coords(m_ChunksReady.front()); - m_ChunksReady.pop_front(); + sSendChunk Chunk(m_SendChunksBroadcastPriority.front()); + m_SendChunksBroadcastPriority.pop_front(); Lock.Unlock(); - - SendChunk(Coords.m_ChunkX, Coords.m_ChunkZ, nullptr); + + SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkZ, Chunk.m_Client); } else if (!m_SendChunksMediumPriority.empty()) { @@ -258,61 +302,46 @@ void cChunkSender::Execute(void) void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { - ASSERT(m_World != nullptr); // Ask the client if it still wants the chunk: - if ((a_Client != nullptr) && !a_Client->WantsSendChunk(a_ChunkX, a_ChunkZ)) + if (!a_Client->WantsSendChunk(a_ChunkX, a_ChunkZ)) { return; } // If the chunk has no clients, no need to packetize it: - if (!m_World->HasChunkAnyClients(a_ChunkX, a_ChunkZ)) + if (!m_World.HasChunkAnyClients(a_ChunkX, a_ChunkZ)) { return; } // If the chunk is not valid, do nothing - whoever needs it has queued it for loading / generating - if (!m_World->IsChunkValid(a_ChunkX, a_ChunkZ)) + if (!m_World.IsChunkValid(a_ChunkX, a_ChunkZ)) { return; } // If the chunk is not lighted, queue it for relighting and get notified when it's ready: - if (!m_World->IsChunkLighted(a_ChunkX, a_ChunkZ)) + if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ)) { - m_World->QueueLightChunk(a_ChunkX, a_ChunkZ, cpp14::make_unique<cNotifyChunkSender>(this)); + m_World.QueueLightChunk(a_ChunkX, a_ChunkZ, cpp14::make_unique<cNotifyChunkSender>(*this, m_World)); return; } // Query and prepare chunk data: - if (!m_World->GetChunkData(a_ChunkX, a_ChunkZ, *this)) + if (!m_World.GetChunkData(a_ChunkX, a_ChunkZ, *this)) { return; } cChunkDataSerializer Data(m_BlockTypes, m_BlockMetas, m_BlockLight, m_BlockSkyLight, m_BiomeMap); // Send: - if (a_Client == nullptr) - { - m_World->BroadcastChunkData(a_ChunkX, a_ChunkZ, Data); - } - else - { - a_Client->SendChunkData(a_ChunkX, a_ChunkZ, Data); - } + a_Client->SendChunkData(a_ChunkX, a_ChunkZ, Data); // Send block-entity packets: for (sBlockCoords::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) { - if (a_Client == nullptr) - { - m_World->BroadcastBlockEntity(itr->m_BlockX, itr->m_BlockY, itr->m_BlockZ); - } - else - { - m_World->SendBlockEntity(itr->m_BlockX, itr->m_BlockY, itr->m_BlockZ, *a_Client); - } + m_World.SendBlockEntity(itr->m_BlockX, itr->m_BlockY, itr->m_BlockZ, *a_Client); } // for itr - m_Packets[] m_BlockEntities.clear(); diff --git a/src/ChunkSender.h b/src/ChunkSender.h index 1376baeb3..1f87e9e08 100644 --- a/src/ChunkSender.h +++ b/src/ChunkSender.h @@ -53,7 +53,7 @@ class cChunkSender: { typedef cIsThread super; public: - cChunkSender(void); + cChunkSender(cWorld & a_World); ~cChunkSender(); enum eChunkPriority @@ -61,17 +61,16 @@ public: E_CHUNK_PRIORITY_HIGH = 0, E_CHUNK_PRIORITY_MEDIUM = 1, E_CHUNK_PRIORITY_LOW = 2, + PRIORITY_BROADCAST }; - bool Start(cWorld * a_World); + bool Start(); void Stop(void); - /// Notifies that a chunk has become ready and it should be sent to all its clients - void ChunkReady(int a_ChunkX, int a_ChunkZ); - /// Queues a chunk to be sent to a specific client void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, eChunkPriority a_Priority, cClientHandle * a_Client); + void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, eChunkPriority a_Priority, std::list<cClientHandle *> a_Client); /// Removes the a_Client from all waiting chunk send operations void RemoveClient(cClientHandle * a_Client); @@ -119,17 +118,16 @@ protected: typedef std::vector<sBlockCoord> sBlockCoords; - cWorld * m_World; + cWorld & m_World; cCriticalSection m_CS; - cChunkCoordsList m_ChunksReady; sSendChunkList m_SendChunksLowPriority; sSendChunkList m_SendChunksMediumPriority; + sSendChunkList m_SendChunksBroadcastPriority; sSendChunkList m_SendChunksHighPriority; cEvent m_evtQueue; // Set when anything is added to m_ChunksReady cEvent m_evtRemoved; // Set when removed clients are safe to be deleted int m_RemoveCount; // Number of threads waiting for a client removal (m_evtRemoved needs to be set this many times) - // Data about the chunk that is being sent: // NOTE that m_BlockData[] is inherited from the cChunkDataCollector unsigned char m_BiomeMap[cChunkDef::Width * cChunkDef::Width]; diff --git a/src/World.cpp b/src/World.cpp index f7d2165c7..ccb6abd0b 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -186,6 +186,7 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_Scoreboard(this), m_MapManager(this), m_GeneratorCallbacks(*this), + m_ChunkSender(*this), m_TickThread(*this) { LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); @@ -509,7 +510,7 @@ void cWorld::Start(void) m_Lighting.Start(this); m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor); m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile); - m_ChunkSender.Start(this); + m_ChunkSender.Start(); m_TickThread.Start(); // Init of the spawn monster time (as they are supposed to have different spawn rate) @@ -1326,6 +1327,30 @@ bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback +bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback) +{ + struct cCallBackWrapper : cChunkCallback + { + cCallBackWrapper(std::function<bool(cChunk &)> a_InnerCallback) : + m_Callback(a_InnerCallback) + { + } + + virtual bool Item(cChunk * a_Chunk) + { + return m_Callback(*a_Chunk); + } + + private: + std::function<bool(cChunk &)> m_Callback; + } callback(a_Callback); + return m_ChunkMap->DoWithChunk(a_ChunkX, a_ChunkZ, callback); +} + + + + + bool cWorld::DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback) { return m_ChunkMap->DoWithChunkAt(a_BlockPos, a_Callback); @@ -2001,15 +2026,6 @@ void cWorld::BroadcastChat(const cCompositeChat & a_Message, const cClientHandle -void cWorld::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude) -{ - m_ChunkMap->BroadcastChunkData(a_ChunkX, a_ChunkZ, a_Serializer, a_Exclude); -} - - - - - void cWorld::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) { m_ChunkMap->BroadcastCollectEntity(a_Entity, a_Player, a_Exclude); @@ -2461,10 +2477,23 @@ void cWorld::SetChunkData(cSetChunkData & a_SetChunkData) // If a client is requesting this chunk, send it to them: int ChunkX = a_SetChunkData.GetChunkX(); int ChunkZ = a_SetChunkData.GetChunkZ(); - if (m_ChunkMap->HasChunkAnyClients(ChunkX, ChunkZ)) - { - m_ChunkSender.ChunkReady(ChunkX, ChunkZ); - } + cChunkSender & ChunkSender = m_ChunkSender; + DoWithChunk( + ChunkX, ChunkZ, + [&ChunkSender] (cChunk & a_Chunk) -> bool + { + if (a_Chunk.HasAnyClients()) + { + ChunkSender.QueueSendChunkTo( + a_Chunk.GetPosX(), + a_Chunk.GetPosZ(), + cChunkSender::PRIORITY_BROADCAST, + a_Chunk.GetAllClients() + ); + } + return true; + } + ); // Save the chunk right after generating, so that we don't have to generate it again on next run if (a_SetChunkData.ShouldMarkDirty()) diff --git a/src/World.h b/src/World.h index 064b50165..078a25562 100644 --- a/src/World.h +++ b/src/World.h @@ -231,7 +231,6 @@ public: void BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = nullptr); // tolua_end - void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = nullptr); void BroadcastCollectEntity (const cEntity & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = nullptr); @@ -609,6 +608,7 @@ public: /** Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */ bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback); + bool DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback); /** Calls the callback for the chunk at the block position specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback **/ bool DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback); |