Permalink
Please sign in to comment.
Browse files
Clean up Spawn Prepare
Made cSpawnPrepare execute on the same thread since it is a syncronous operation, and most of the code happens on the lighting thread. Also moved cSpawnPrepare into its own file
- Loading branch information...
Showing
with
156 additions
and 136 deletions.
- +2 −0 src/CMakeLists.txt
- +105 −0 src/SpawnPrepare.cpp
- +47 −0 src/SpawnPrepare.h
- +2 −136 src/World.cpp
| @@ -0,0 +1,105 @@ | ||
| #include "Globals.h" | ||
| #include "SpawnPrepare.h" | ||
| #include "World.h" | ||
| 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, &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::Call(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, 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; | ||
| } | ||
| } | ||
| @@ -0,0 +1,47 @@ | ||
| #pragma once | ||
| class cWorld; | ||
| /** Generates and lights the spawn area of the world. Runs as a separate thread. */ | ||
| class cSpawnPrepare: | ||
| public cChunkCoordCallback | ||
| { | ||
| public: | ||
| static void PrepareChunks(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance); | ||
| 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 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; | ||
| cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance, int a_FirstIdx); | ||
| virtual void Call(int a_ChunkX, int a_ChunkZ) override; | ||
| /** Decodes the index into chunk coords. Provides the specific chunk ordering. */ | ||
| void DecodeChunkCoords(int a_Idx, int & a_ChunkX, int & a_ChunkZ); | ||
| }; | ||
0 comments on commit
4feccaa