diff options
Diffstat (limited to 'src/World.cpp')
-rw-r--r-- | src/World.cpp | 205 |
1 files changed, 50 insertions, 155 deletions
diff --git a/src/World.cpp b/src/World.cpp index 3c39de317..3ff8e0723 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -58,6 +58,7 @@ #endif #include "Broadcaster.h" +#include "SpawnPrepare.h" @@ -72,140 +73,6 @@ const int TIME_SPAWN_DIVISOR = 148; //////////////////////////////////////////////////////////////////////////////// -// cSpawnPrepare: - -/** Generates and lights the spawn area of the world. Runs as a separate thread. */ -class cSpawnPrepare: - public cIsThread, - public cChunkCoordCallback -{ - typedef cIsThread super; - -public: - cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance): - super("SpawnPrepare"), - m_World(a_World), - m_SpawnChunkX(a_SpawnChunkX), - m_SpawnChunkZ(a_SpawnChunkZ), - m_PrepareDistance(a_PrepareDistance), - m_MaxIdx(a_PrepareDistance * a_PrepareDistance), - m_NumPrepared(0), - m_LastReportChunkCount(0) - { - // Start the thread: - Start(); - - // Wait for start confirmation, so that the thread can be waited-upon after the constructor returns: - m_EvtStarted.Wait(); - } - - - // cIsThread override: - virtual void Execute(void) override - { - // Confirm thread start: - m_EvtStarted.Set(); - - // Queue the initial chunks: - m_MaxIdx = m_PrepareDistance * m_PrepareDistance; - int maxQueue = std::min(m_MaxIdx - 1, 100); // Number of chunks to queue at once - m_NextIdx = maxQueue; - m_LastReportTime = std::chrono::steady_clock::now(); - for (int i = 0; i < maxQueue; i++) - { - int chunkX, chunkZ; - DecodeChunkCoords(i, chunkX, chunkZ); - m_World.PrepareChunk(chunkX, chunkZ, this); - } // for i - - // Wait for the lighting thread to prepare everything. Event is set in the Call() callback: - m_EvtFinished.Wait(); - } - -protected: - cWorld & m_World; - int m_SpawnChunkX; - int m_SpawnChunkZ; - int m_PrepareDistance; - - /** The index of the next chunk to be queued in the lighting thread. */ - int m_NextIdx; - - /** The maximum index of the prepared chunks. Queueing stops when m_NextIdx reaches this number. */ - int m_MaxIdx; - - /** Total number of chunks already finished preparing. Preparation finishes when this number reaches m_MaxIdx. */ - int m_NumPrepared; - - /** Event used to signal that the thread has started. */ - cEvent m_EvtStarted; - - /** Event used to signal that the preparation is finished. */ - cEvent m_EvtFinished; - - /** The timestamp of the last progress report emitted. */ - std::chrono::steady_clock::time_point m_LastReportTime; - - /** Number of chunks prepared when the last progress report was emitted. */ - int m_LastReportChunkCount; - - // cChunkCoordCallback override: - virtual void Call(int a_ChunkX, int a_ChunkZ) override - { - // Check if this was the last chunk: - m_NumPrepared += 1; - if (m_NumPrepared >= m_MaxIdx) - { - m_EvtFinished.Set(); - // Must return here, because "this" may have gotten deleted by the previous line - return; - } - - // Queue another chunk, if appropriate: - if (m_NextIdx < m_MaxIdx) - { - int chunkX, chunkZ; - DecodeChunkCoords(m_NextIdx, chunkX, chunkZ); - m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, this); - m_NextIdx += 1; - } - - // Report progress every 1 second: - auto Now = std::chrono::steady_clock::now(); - if (Now - m_LastReportTime > std::chrono::seconds(1)) - { - float PercentDone = static_cast<float>(m_NumPrepared * 100) / m_MaxIdx; - float ChunkSpeed = static_cast<float>((m_NumPrepared - m_LastReportChunkCount) * 1000) / std::chrono::duration_cast<std::chrono::milliseconds>(Now - m_LastReportTime).count(); - LOG("Preparing spawn (%s): %.02f%% (%d/%d; %.02f chunks / sec)", - m_World.GetName().c_str(), PercentDone, m_NumPrepared, m_MaxIdx, ChunkSpeed - ); - m_LastReportTime = Now; - m_LastReportChunkCount = m_NumPrepared; - } - } - - - /** Decodes the index into chunk coords. Provides the specific chunk ordering. */ - void DecodeChunkCoords(int a_Idx, int & a_ChunkX, int & a_ChunkZ) - { - // A zigzag pattern from the top to bottom, each row alternating between forward-x and backward-x: - int z = a_Idx / m_PrepareDistance; - int x = a_Idx % m_PrepareDistance; - if ((z & 1) == 0) - { - // Reverse every second row: - x = m_PrepareDistance - 1 - x; - } - a_ChunkZ = m_SpawnChunkZ + z - m_PrepareDistance / 2; - a_ChunkX = m_SpawnChunkX + x - m_PrepareDistance / 2; - } -}; - - - - - -//////////////////////////////////////////////////////////////////////////////// // cWorld::cLock: cWorld::cLock::cLock(cWorld & a_World) : @@ -319,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()); @@ -470,8 +338,7 @@ void cWorld::InitializeSpawn(void) int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist); IniFile.WriteFile(m_IniFileName); - cSpawnPrepare prep(*this, ChunkX, ChunkZ, ViewDist); - prep.Wait(); + cSpawnPrepare::PrepareChunks(*this, ChunkX, ChunkZ, ViewDist); #ifdef TEST_LINEBLOCKTRACER // DEBUG: Test out the cLineBlockTracer class by tracing a few lines: @@ -643,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) @@ -1460,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); @@ -2072,7 +1963,7 @@ void cWorld::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_V -void cWorld::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude) +void cWorld::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, Byte a_Byte1, Byte a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude) { m_ChunkMap->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType, a_Exclude); } @@ -2135,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); @@ -2595,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()) @@ -3006,9 +2901,9 @@ void cWorld::TouchChunk(int a_ChunkX, int a_ChunkZ) -void cWorld::PrepareChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallAfter) +void cWorld::PrepareChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_CallAfter) { - m_ChunkMap->PrepareChunk(a_ChunkX, a_ChunkZ, a_CallAfter); + m_ChunkMap->PrepareChunk(a_ChunkX, a_ChunkZ, std::move(a_CallAfter)); } @@ -3132,9 +3027,9 @@ void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ) -void cWorld::QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback) +void cWorld::QueueLightChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_Callback) { - m_Lighting.QueueChunk(a_ChunkX, a_ChunkZ, a_Callback); + m_Lighting.QueueChunk(a_ChunkX, a_ChunkZ, std::move(a_Callback)); } |