diff --git a/source/WSSCompact.cpp b/source/WSSCompact.cpp index 04fb45351..3b0f6c2cf 100644 --- a/source/WSSCompact.cpp +++ b/source/WSSCompact.cpp @@ -313,7 +313,7 @@ bool cWSSCompact::cPAKFile::LoadChunk(const cChunkCoords & a_Chunk, int a_Offset } } - a_World->ChunkDataLoaded(a_Chunk.m_ChunkX, 0, a_Chunk.m_ChunkZ, UncompressedData.data(), Entities, BlockEntities); + a_World->ChunkDataLoaded(a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ, UncompressedData.data(), Entities, BlockEntities); return true; } @@ -348,11 +348,11 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld { // Serialize the chunk: cJsonChunkSerializer Serializer; - a_World->GetChunkData(a_Chunk.m_ChunkX, 0, a_Chunk.m_ChunkZ, &Serializer); + a_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ, &Serializer); if (Serializer.GetBlockData().empty()) { // Chunk not valid - LOG("cWSSCompact: Trying to save chunk [%d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); + LOG("cWSSCompact: Trying to save chunk [%d, %d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); return false; } @@ -371,7 +371,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld int errorcode = CompressString(Data.data(), Data.size(), CompressedData); if ( errorcode != Z_OK ) { - LOGERROR("Error %i compressing data for chunk [%d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); + LOGERROR("Error %i compressing data for chunk [%d, %d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); return false; } @@ -382,7 +382,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld sChunkHeader * Header = new sChunkHeader; if (Header == NULL) { - LOGWARNING("Cannot create a new chunk header to save chunk [%d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); + LOGWARNING("Cannot create a new chunk header to save chunk [%d, %d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); return false; } Header->m_CompressedSize = (int)CompressedData.size(); diff --git a/source/WorldStorage.cpp b/source/WorldStorage.cpp index 73ad18f15..f6be97753 100644 --- a/source/WorldStorage.cpp +++ b/source/WorldStorage.cpp @@ -161,12 +161,12 @@ void cWorldStorage::WaitForFinish(void) -void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkZ) +void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { // Queues the chunk for loading; if not loaded, the chunk will be generated cCSLock Lock(m_CSLoadQueue); - m_LoadQueue.remove (cChunkCoords(a_ChunkX, a_ChunkZ)); // Don't add twice - m_LoadQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); + m_LoadQueue.remove (cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); // Don't add twice + m_LoadQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); m_Event.Set(); } @@ -174,11 +174,11 @@ void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkZ) -void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkZ) +void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cCSLock Lock(m_CSSaveQueue); - m_SaveQueue.remove (cChunkCoords(a_ChunkX, a_ChunkZ)); // Don't add twice - m_SaveQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); + m_SaveQueue.remove (cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); // Don't add twice + m_SaveQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); m_Event.Set(); } @@ -268,7 +268,7 @@ void cWorldStorage::Execute(void) bool cWorldStorage::LoadOneChunk(void) { - cChunkCoords ToLoad(0, 0); + cChunkCoords ToLoad(0, 0, 0); bool HasMore; bool ShouldLoad = false; { @@ -284,7 +284,7 @@ bool cWorldStorage::LoadOneChunk(void) if (ShouldLoad && !LoadChunk(ToLoad)) { // The chunk couldn't be loaded, generate it: - m_World->GetGenerator().GenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkZ); + m_World->GetGenerator().GenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ); } return HasMore; } @@ -295,7 +295,7 @@ bool cWorldStorage::LoadOneChunk(void) bool cWorldStorage::SaveOneChunk(void) { - cChunkCoords Save(0, 0); + cChunkCoords Save(0, 0, 0); bool HasMore; bool ShouldSave = false; { @@ -308,16 +308,16 @@ bool cWorldStorage::SaveOneChunk(void) } HasMore = (m_SaveQueue.size() > 0); } - if (ShouldSave) + if (ShouldSave && m_World->IsChunkValid(Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ)) { - m_World->MarkChunkSaving(Save.m_ChunkX, 0, Save.m_ChunkZ); + m_World->MarkChunkSaving(Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ); if (m_SaveSchema->SaveChunk(Save)) { - m_World->MarkChunkSaved(Save.m_ChunkX, 0, Save.m_ChunkZ); + m_World->MarkChunkSaved(Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ); } else { - LOGWARNING("Cannot save chunk [%d, %d]", Save.m_ChunkX, Save.m_ChunkZ); + LOGWARNING("Cannot save chunk [%d, %d, %d]", Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ); } } return HasMore; @@ -329,7 +329,7 @@ bool cWorldStorage::SaveOneChunk(void) bool cWorldStorage::LoadChunk(const cChunkCoords & a_Chunk) { - if (m_World->IsChunkValid(a_Chunk.m_ChunkX, 0, a_Chunk.m_ChunkZ)) + if (m_World->IsChunkValid(a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ)) { // Already loaded (can happen, since the queue is async) return true; diff --git a/source/WorldStorage.h b/source/WorldStorage.h index 5de7f49fa..220585c57 100644 --- a/source/WorldStorage.h +++ b/source/WorldStorage.h @@ -97,8 +97,8 @@ public: cWorldStorage(void); ~cWorldStorage(); - void QueueLoadChunk(int a_ChunkX, int a_ChunkZ); // Queues the chunk for loading; if not loaded, the chunk will be generated - void QueueSaveChunk(int a_ChunkX, int a_ChunkZ); + void QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Queues the chunk for loading; if not loaded, the chunk will be generated + void QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); void UnqueueLoad(const cChunkCoords & a_Chunk); void UnqueueSave(const cChunkCoords & a_Chunk); diff --git a/source/cChunk.h b/source/cChunk.h index 66efa0d1e..b750e10db 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -20,6 +20,15 @@ +/** This is really only a placeholder to be used in places where we need to "make up" a chunk's Y coord. +It will help us when the new chunk format comes out and we need to patch everything up for compatibility. +*/ +#define ZERO_CHUNK_Y 0 + + + + + namespace Json { class Value; @@ -238,13 +247,14 @@ class cChunkCoords { public: int m_ChunkX; + int m_ChunkY; int m_ChunkZ; - cChunkCoords(int a_ChunkX, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ) {} + cChunkCoords(int a_ChunkX, int a_ChunkY, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ) {} bool operator == (const cChunkCoords & a_Other) { - return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ)); + return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkY == a_Other.m_ChunkY) && (m_ChunkZ == a_Other.m_ChunkZ)); } } ; diff --git a/source/cChunkGenerator.cpp b/source/cChunkGenerator.cpp index 4d9aef421..5c8144f05 100644 --- a/source/cChunkGenerator.cpp +++ b/source/cChunkGenerator.cpp @@ -81,14 +81,14 @@ void cChunkGenerator::Stop(void) -void cChunkGenerator::GenerateChunk(int a_ChunkX, int a_ChunkZ) +void cChunkGenerator::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cCSLock Lock(m_CS); // Check if it is already in the queue: for (cChunkCoordsList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr) { - if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ)) + if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ)) { // Already in the queue, bail out return; @@ -100,7 +100,7 @@ void cChunkGenerator::GenerateChunk(int a_ChunkX, int a_ChunkZ) { LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (%i)", a_ChunkX, a_ChunkZ, m_Queue.size()); } - m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); + m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); m_Event.Set(); } @@ -130,24 +130,32 @@ void cChunkGenerator::Execute(void) Lock.Unlock(); // Unlock ASAP if ( - m_World->IsChunkValid(coords.m_ChunkX, 0, coords.m_ChunkZ) || - (SkipEnabled && m_World->HasChunkAnyClients(coords.m_ChunkX, 0, coords.m_ChunkZ)) + m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ) || + (SkipEnabled && m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ)) ) { // Already generated / overload-skip, ignore request continue; } - LOG("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); - m_pWorldGenerator->GenerateChunk(coords.m_ChunkX, 0, coords.m_ChunkZ); + LOG("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); + DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - // Chunk->SetValid(); - // Save the chunk right after generating, so that we don't have to generate it again on next run - m_World->GetStorage().QueueSaveChunk(coords.m_ChunkX, coords.m_ChunkZ); + m_World->GetStorage().QueueSaveChunk(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); } // while (!bStop) } +void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +{ + // TODO: Convert this not to require the actual cChunkPtr (generate into raw char array) + // char BlockData[cChunk::c_BlockDataSize]; + m_pWorldGenerator->GenerateChunk(a_ChunkX, a_ChunkY, a_ChunkZ); +} + + + + diff --git a/source/cChunkGenerator.h b/source/cChunkGenerator.h index 5de056572..8b0efc9e8 100644 --- a/source/cChunkGenerator.h +++ b/source/cChunkGenerator.h @@ -42,19 +42,21 @@ public: bool Start(cWorld * a_World, const AString & a_WorldGeneratorName); void Stop(void); - void GenerateChunk(int a_ChunkX, int a_ChunkZ); // Queues the chunk for generation; removes duplicate requests + void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Queues the chunk for generation; removes duplicate requests private: - // cIsThread override: - virtual void Execute(void) override; - cWorld * m_World; cWorldGenerator * m_pWorldGenerator; cCriticalSection m_CS; cChunkCoordsList m_Queue; cEvent m_Event; // Set when an item is added to the queue or the thread should terminate + + // cIsThread override: + virtual void Execute(void) override; + + void DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ); }; diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index dbe6607fc..7adaebf90 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -103,10 +103,10 @@ cChunkPtr cChunkMap::GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) return cChunkPtr(); } - cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); + cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); if (!(Chunk->IsValid())) { - m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ); + m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ); } return Chunk; } @@ -125,7 +125,7 @@ cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) return cChunkPtr(); } - cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); + cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); // TODO: Load, but do not generate, if not valid @@ -341,7 +341,7 @@ cChunkMap::cChunkLayer::cChunkLayer(int a_LayerX, int a_LayerZ, cChunkMap * a_Pa -cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkZ ) +cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) { // Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check @@ -371,7 +371,8 @@ void cChunkMap::cChunkLayer::Tick(float a_Dt, MTRand & a_TickRand) { for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) { - if ((m_Chunks[i] != NULL) && (m_Chunks[i]->IsValid())) + // Only tick chunks that are valid and have clients: + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) { m_Chunks[i]->Tick(a_Dt, a_TickRand); } @@ -382,6 +383,23 @@ void cChunkMap::cChunkLayer::Tick(float a_Dt, MTRand & a_TickRand) +int cChunkMap::cChunkLayer::GetNumChunksLoaded(void) const +{ + int NumChunks = 0; + for ( int i = 0; i < ARRAYCOUNT(m_Chunks); ++i ) + { + if (m_Chunks[i] != NULL) + { + NumChunks++; + } + } // for i - m_Chunks[] + return NumChunks; +} + + + + + void cChunkMap::cChunkLayer::Save(void) { cWorld * World = m_Parent->GetWorld(); @@ -389,7 +407,7 @@ void cChunkMap::cChunkLayer::Save(void) { if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->IsDirty()) { - World->GetStorage().QueueSaveChunk(m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosZ()); + World->GetStorage().QueueSaveChunk(m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosY(), m_Chunks[i]->GetPosZ()); } } // for i - m_Chunks[] } diff --git a/source/cChunkMap.h b/source/cChunkMap.h index 0b3e79931..4ec7ef01d 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -89,18 +89,12 @@ private: cChunkLayer(int a_LayerX, int a_LayerZ, cChunkMap * a_Parent); /// Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check - cChunkPtr GetChunk( int a_ChunkX, int a_ChunkZ ); + cChunkPtr GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); int GetX(void) const {return m_LayerX; } int GetZ(void) const {return m_LayerZ; } - int GetNumChunksLoaded(void) const - { - int NumChunks = 0; - for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i ) - if( m_Chunks[i].get() ) - NumChunks++; - return NumChunks; - } + + int GetNumChunksLoaded(void) const ; void Save(void); void UnloadUnusedChunks(void); diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index c8f8e82ed..6edddac6b 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -342,7 +342,7 @@ void cClientHandle::StreamChunks(void) int RelZ = (*itr).m_ChunkZ - ChunkPosZ; if ((RelX > VIEWDISTANCE) || (RelX < -VIEWDISTANCE) || (RelZ > VIEWDISTANCE) || (RelZ < -VIEWDISTANCE)) { - World->GetChunk((*itr).m_ChunkX, 0, (*itr).m_ChunkZ)->RemoveClient(this); + World->GetChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ)->RemoveClient(this); itr = m_LoadedChunks.erase(itr); } else @@ -372,13 +372,13 @@ void cClientHandle::StreamChunks(void) // For each distance add chunks in a hollow square centered around current position: for (int i = -d; i <= d; ++i) { - StreamChunk(ChunkPosX + d, ChunkPosZ + i); - StreamChunk(ChunkPosX - d, ChunkPosZ + i); + StreamChunk(ChunkPosX + d, ZERO_CHUNK_Y, ChunkPosZ + i); + StreamChunk(ChunkPosX - d, ZERO_CHUNK_Y, ChunkPosZ + i); } // for i for (int i = -d + 1; i < d; ++i) { - StreamChunk(ChunkPosX + i, ChunkPosZ + d); - StreamChunk(ChunkPosX + i, ChunkPosZ - d); + StreamChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ + d); + StreamChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ - d); } // for i } // for d @@ -388,13 +388,13 @@ void cClientHandle::StreamChunks(void) // For each distance touch chunks in a hollow square centered around current position: for (int i = -d; i <= d; ++i) { - World->GetChunk(ChunkPosX + d, 0, ChunkPosZ + i); - World->GetChunk(ChunkPosX - d, 0, ChunkPosZ + i); + World->GetChunk(ChunkPosX + d, ZERO_CHUNK_Y, ChunkPosZ + i); + World->GetChunk(ChunkPosX - d, ZERO_CHUNK_Y, ChunkPosZ + i); } // for i for (int i = -d + 1; i < d; ++i) { - World->GetChunk(ChunkPosX + i, 0, ChunkPosZ + d); - World->GetChunk(ChunkPosX + i, 0, ChunkPosZ - d); + World->GetChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ + d); + World->GetChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ - d); } // for i } // for d } @@ -402,7 +402,7 @@ void cClientHandle::StreamChunks(void) -void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ) +void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cWorld * World = m_Player->GetWorld(); assert(World != NULL); @@ -412,8 +412,8 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ) { Chunk->AddClient(this); cCSLock Lock(m_CSChunkLists); - m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); - m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); + m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); } } @@ -430,7 +430,7 @@ void cClientHandle::RemoveFromAllChunks() { for (cChunkCoordsList::iterator itr = m_LoadedChunks.begin(); itr != m_LoadedChunks.end(); ++itr) { - World->GetChunk(itr->m_ChunkX, 0, itr->m_ChunkZ)->RemoveClient(this); + World->GetChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ)->RemoveClient(this); } } m_LoadedChunks.clear(); @@ -1656,7 +1656,7 @@ void cClientHandle::Tick(float a_Dt) int NumSent = 0; for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end();) { - cChunkPtr Chunk = World->GetChunk(itr->m_ChunkX, 0, itr->m_ChunkZ); + cChunkPtr Chunk = World->GetChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); if (!Chunk->IsValid()) { ++itr; diff --git a/source/cClientHandle.h b/source/cClientHandle.h index f45cf5b7d..ffe25db2b 100644 --- a/source/cClientHandle.h +++ b/source/cClientHandle.h @@ -201,7 +201,7 @@ private: void SendConfirmPosition(void); /// Adds a single chunk to be streamed to the client; used by StreamChunks() - void StreamChunk(int a_ChunkX, int a_ChunkZ); + void StreamChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // cSocketThreads::cCallback overrides: virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client diff --git a/source/cWorld.cpp b/source/cWorld.cpp index ca435fe64..744780242 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -273,6 +273,8 @@ cWorld::cWorld( const AString & a_WorldName ) g_BlockTransparent[ E_BLOCK_TORCH ] = true; g_BlockTransparent[ E_BLOCK_SIGN_POST ] = true; g_BlockTransparent[ E_BLOCK_WALLSIGN ] = true; + + // TODO: Also set flowers, mushrooms etc as transparent // One hit break blocks g_BlockOneHitDig[ E_BLOCK_SAPLING ] = true;