diff options
Diffstat (limited to 'src/SpawnPrepare.cpp')
-rw-r--r-- | src/SpawnPrepare.cpp | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/SpawnPrepare.cpp b/src/SpawnPrepare.cpp new file mode 100644 index 000000000..74dcb3ecd --- /dev/null +++ b/src/SpawnPrepare.cpp @@ -0,0 +1,125 @@ + +#include "Globals.h" + +#include "SpawnPrepare.h" +#include "World.h" + + + + + +class cSpawnPrepareCallback : + public cChunkCoordCallback +{ +public: + cSpawnPrepareCallback(cSpawnPrepare & a_SpawnPrepare) : + m_SpawnPrepare(a_SpawnPrepare) + { + } +protected: + + cSpawnPrepare & m_SpawnPrepare; + + virtual void Call(int a_ChunkX, int a_ChunkZ) override + { + m_SpawnPrepare.PreparedChunkCallback(a_ChunkX, a_ChunkZ); + } +}; + + + + + +cSpawnPrepare::cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance, int a_FirstIdx): + m_World(a_World), + m_SpawnChunkX(a_SpawnChunkX), + m_SpawnChunkZ(a_SpawnChunkZ), + m_PrepareDistance(a_PrepareDistance), + m_NextIdx(a_FirstIdx), + m_MaxIdx(a_PrepareDistance * a_PrepareDistance), + m_NumPrepared(0), + m_LastReportTime(std::chrono::steady_clock::now()), + m_LastReportChunkCount(0) +{ +} + + + + + + + +void cSpawnPrepare::PrepareChunks(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance) +{ + + // Queue the initial chunks: + int MaxIdx = a_PrepareDistance * a_PrepareDistance; + int maxQueue = std::min(MaxIdx - 1, 100); // Number of chunks to queue at once + cSpawnPrepare prep(a_World, a_SpawnChunkX, a_SpawnChunkZ, a_PrepareDistance, maxQueue); + for (int i = 0; i < maxQueue; i++) + { + int chunkX, chunkZ; + prep.DecodeChunkCoords(i, chunkX, chunkZ); + a_World.PrepareChunk(chunkX, chunkZ, cpp14::make_unique<cSpawnPrepareCallback>(prep)); + } // for i + + // Wait for the lighting thread to prepare everything. Event is set in the Call() callback: + prep.m_EvtFinished.Wait(); +} + + + + + +void cSpawnPrepare::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; +} + + + + + +void cSpawnPrepare::PreparedChunkCallback(int a_ChunkX, int a_ChunkZ) +{ + // 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, cpp14::make_unique<cSpawnPrepareCallback>(*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; + } +} + |