From 499745c1c7a865941b3c102532777c19dfb92ca4 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sat, 18 Feb 2012 17:53:22 +0000 Subject: Thread-safe chunk generation, storage and generator are queried for progress while initializing server Note that this commit breaks foliage generation - there are no trees in the chunks generated! git-svn-id: http://mc-server.googlecode.com/svn/trunk@292 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/WorldStorage.cpp | 52 ++++++++++-- source/WorldStorage.h | 16 ++-- source/cAuthenticator.cpp | 4 +- source/cChunk.cpp | 16 ++-- source/cChunk.h | 2 +- source/cChunkGenerator.cpp | 36 ++++++++- source/cChunkGenerator.h | 5 ++ source/cChunkMap.cpp | 59 +++++++++++++- source/cChunkMap.h | 21 ++--- source/cPluginManager.cpp | 1 - source/cWorld.cpp | 148 ++++++++++++++++++++++++--------- source/cWorld.h | 12 +-- source/cWorldGenerator.cpp | 175 ++++++++++++++++++++++------------------ source/cWorldGenerator.h | 9 ++- source/cWorldGenerator_Test.cpp | 23 +++--- source/cWorldGenerator_Test.h | 5 +- 16 files changed, 408 insertions(+), 176 deletions(-) (limited to 'source') diff --git a/source/WorldStorage.cpp b/source/WorldStorage.cpp index f6be97753..bc830c272 100644 --- a/source/WorldStorage.cpp +++ b/source/WorldStorage.cpp @@ -147,13 +147,14 @@ void cWorldStorage::WaitForFinish(void) { // Cancel all loading requests: - cCSLock Lock(m_CSLoadQueue); + cCSLock Lock(m_CSQueues); m_LoadQueue.clear(); } // Wait for the thread to finish: mShouldTerminate = true; m_Event.Set(); + m_evtRemoved.Set(); // Wake up anybody waiting in the WaitForQueuesEmpty() method super::Wait(); } @@ -161,10 +162,44 @@ void cWorldStorage::WaitForFinish(void) +void cWorldStorage::WaitForQueuesEmpty(void) +{ + cCSLock Lock(m_CSQueues); + while (!mShouldTerminate && (!m_LoadQueue.empty() || !m_SaveQueue.empty())) + { + cCSUnlock Unlock(Lock); + m_evtRemoved.Wait(); + } +} + + + + + +int cWorldStorage::GetLoadQueueLength(void) +{ + cCSLock Lock(m_CSQueues); + return (int)m_LoadQueue.size(); +} + + + + + +int cWorldStorage::GetSaveQueueLength(void) +{ + cCSLock Lock(m_CSQueues); + return (int)m_SaveQueue.size(); +} + + + + + 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); + cCSLock Lock(m_CSQueues); 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(); @@ -176,7 +211,7 @@ void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { - cCSLock Lock(m_CSSaveQueue); + cCSLock Lock(m_CSQueues); 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(); @@ -188,8 +223,9 @@ void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) void cWorldStorage::UnqueueLoad(const cChunkCoords & a_Chunk) { - cCSLock Lock(m_CSLoadQueue); + cCSLock Lock(m_CSQueues); m_LoadQueue.remove(a_Chunk); + m_evtRemoved.Set(); } @@ -198,8 +234,9 @@ void cWorldStorage::UnqueueLoad(const cChunkCoords & a_Chunk) void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk) { - cCSLock Lock(m_CSSaveQueue); + cCSLock Lock(m_CSQueues); m_SaveQueue.remove(a_Chunk); + m_evtRemoved.Set(); } @@ -258,6 +295,7 @@ void cWorldStorage::Execute(void) HasMore = LoadOneChunk(); HasMore = HasMore | SaveOneChunk(); + m_evtRemoved.Set(); } while (HasMore); } } @@ -272,7 +310,7 @@ bool cWorldStorage::LoadOneChunk(void) bool HasMore; bool ShouldLoad = false; { - cCSLock Lock(m_CSLoadQueue); + cCSLock Lock(m_CSQueues); if (m_LoadQueue.size() > 0) { ToLoad = m_LoadQueue.front(); @@ -299,7 +337,7 @@ bool cWorldStorage::SaveOneChunk(void) bool HasMore; bool ShouldSave = false; { - cCSLock Lock(m_CSSaveQueue); + cCSLock Lock(m_CSQueues); if (m_SaveQueue.size() > 0) { Save = m_SaveQueue.front(); diff --git a/source/WorldStorage.h b/source/WorldStorage.h index 220585c57..1ea39cf66 100644 --- a/source/WorldStorage.h +++ b/source/WorldStorage.h @@ -105,19 +105,23 @@ public: bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args void WaitForFinish(void); + void WaitForQueuesEmpty(void); + + int GetLoadQueueLength(void); + int GetSaveQueueLength(void); protected: cWorld * m_World; AString m_StorageSchemaName; - cCriticalSection m_CSLoadQueue; - cChunkCoordsList m_LoadQueue; - - cCriticalSection m_CSSaveQueue; - cChunkCoordsList m_SaveQueue; + // Both queues are locked by the same CS + cCriticalSection m_CSQueues; + cChunkCoordsList m_LoadQueue; + cChunkCoordsList m_SaveQueue; - cEvent m_Event; // Set when there's any addition to the queues + cEvent m_Event; // Set when there's any addition to the queues + cEvent m_evtRemoved; // Set when an item has been removed from the queue, either by the worker thread or the Unqueue methods /// All the storage schemas (all used for loading) cWSSchemaList m_Schemas; diff --git a/source/cAuthenticator.cpp b/source/cAuthenticator.cpp index c82b8cec0..0c482a9a1 100644 --- a/source/cAuthenticator.cpp +++ b/source/cAuthenticator.cpp @@ -113,7 +113,7 @@ void cAuthenticator::Stop(void) void cAuthenticator::Execute(void) { - while (true) + for (;;) { cCSLock Lock(mCS); while (!mShouldTerminate && (mQueue.size() == 0)) @@ -142,7 +142,7 @@ void cAuthenticator::Execute(void) { cRoot::Get()->AuthenticateUser(UserName); } - } + } // for (-ever) } diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 5bd6ca1e9..b5e56f3c6 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -109,6 +109,8 @@ void cChunk::SetValid(bool a_SendToClients) { m_IsValid = true; + m_World->GetChunkMap()->ChunkValidated(); + if (!a_SendToClients) { return; @@ -177,7 +179,7 @@ void cChunk::MarkSaved(void) void cChunk::MarkLoaded(void) { m_IsDirty = false; - m_IsValid = true; + SetValid(); } @@ -240,8 +242,6 @@ void cChunk::SetAllData(const char * a_BlockData, cEntityList & a_Entities, cBlo CreateBlockEntities(); CalculateHeightmap(); - - MarkDirty(); } @@ -511,7 +511,7 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) -char cChunk::GetHeight( int a_X, int a_Z ) +int cChunk::GetHeight( int a_X, int a_Z ) { if( a_X >= 0 && a_X < 16 && a_Z >= 0 && a_Z < 16 ) { @@ -756,10 +756,10 @@ void cChunk::SpreadLight(char* a_LightBuffer) } } - if( bCalcLeft ) m_World->ReSpreadLighting( LeftChunk ); - if( bCalcRight ) m_World->ReSpreadLighting( RightChunk ); - if( bCalcFront ) m_World->ReSpreadLighting( FrontChunk ); - if( bCalcBack ) m_World->ReSpreadLighting( BackChunk ); + if( bCalcLeft ) m_World->ReSpreadLighting( m_PosX - 1, m_PosY, m_PosZ ); + if( bCalcRight ) m_World->ReSpreadLighting( m_PosX + 1, m_PosY, m_PosZ ); + if( bCalcFront ) m_World->ReSpreadLighting( m_PosX, m_PosY, m_PosZ - 1 ); + if( bCalcBack ) m_World->ReSpreadLighting( m_PosX, m_PosY, m_PosZ + 1 ); } diff --git a/source/cChunk.h b/source/cChunk.h index b750e10db..60e11b133 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -119,7 +119,7 @@ public: void CollectPickupsByPlayer(cPlayer * a_Player); void UpdateSign(int a_PosX, int a_PosY, int a_PosZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); // Also sends update packets to all clients in the chunk - char GetHeight( int a_X, int a_Z ); + int GetHeight( int a_X, int a_Z ); void SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client ); diff --git a/source/cChunkGenerator.cpp b/source/cChunkGenerator.cpp index 5c8144f05..c0fea1fae 100644 --- a/source/cChunkGenerator.cpp +++ b/source/cChunkGenerator.cpp @@ -71,6 +71,7 @@ void cChunkGenerator::Stop(void) { mShouldTerminate = true; m_Event.Set(); + m_evtRemoved.Set(); // Wake up anybody waiting for empty queue Wait(); delete m_pWorldGenerator; @@ -109,6 +110,30 @@ void cChunkGenerator::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkGenerator::WaitForQueueEmpty(void) +{ + cCSLock Lock(m_CS); + while (!mShouldTerminate && !m_Queue.empty()) + { + cCSUnlock Unlock(Lock); + m_evtRemoved.Wait(); + } +} + + + + + +int cChunkGenerator::GetQueueLength(void) +{ + cCSLock Lock(m_CS); + return (int)m_Queue.size(); +} + + + + + void cChunkGenerator::Execute(void) { while (!mShouldTerminate) @@ -128,6 +153,7 @@ void cChunkGenerator::Execute(void) m_Queue.erase( m_Queue.begin() ); // Remove coordinate from queue bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT); Lock.Unlock(); // Unlock ASAP + m_evtRemoved.Set(); if ( m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ) || @@ -138,7 +164,7 @@ void cChunkGenerator::Execute(void) continue; } - LOG("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); + LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); // Save the chunk right after generating, so that we don't have to generate it again on next run @@ -151,9 +177,11 @@ void cChunkGenerator::Execute(void) 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); + char BlockData[cChunk::c_BlockDataSize]; + cEntityList Entities; + cBlockEntityList BlockEntities; + m_pWorldGenerator->GenerateChunk(a_ChunkX, a_ChunkY, a_ChunkZ, BlockData, Entities, BlockEntities); + m_World->ChunkDataGenerated(a_ChunkX, a_ChunkY, a_ChunkZ, BlockData, Entities, BlockEntities); } diff --git a/source/cChunkGenerator.h b/source/cChunkGenerator.h index 8b0efc9e8..cb30636c3 100644 --- a/source/cChunkGenerator.h +++ b/source/cChunkGenerator.h @@ -43,6 +43,10 @@ public: void Stop(void); void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Queues the chunk for generation; removes duplicate requests + + void WaitForQueueEmpty(void); + + int GetQueueLength(void); private: @@ -52,6 +56,7 @@ private: cCriticalSection m_CS; cChunkCoordsList m_Queue; cEvent m_Event; // Set when an item is added to the queue or the thread should terminate + cEvent m_evtRemoved; // Set when an item is removed from the queue // cIsThread override: virtual void Execute(void) override; diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 7adaebf90..96d3b14e0 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -235,7 +235,7 @@ void cChunkMap::ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const -void cChunkMap::SetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) +void cChunkMap::ChunkDataGenerated(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); @@ -244,6 +244,12 @@ void cChunkMap::SetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const cha return; } Chunk->SetAllData(a_BlockData, a_Entities, a_BlockEntities); + + // TODO: This has to go - lighting takes way too long to execute in a locked ChunkMap! + Chunk->CalculateLighting(); + + Chunk->SetValid(); + Chunk->MarkDirty(); } @@ -287,6 +293,48 @@ bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkMap::SpreadChunkLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + if ((Chunk != NULL) && Chunk->IsValid()) + { + // TODO: Rewrite this to call Chunk's lighting without any parameters + Chunk->SpreadLight( Chunk->pGetSkyLight() ); + Chunk->SpreadLight( Chunk->pGetLight() ); + } +} + + + + + +int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ) +{ + cCSLock Lock(m_CSLayers); + int ChunkX, ChunkZ, BlockY = 0; + AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if (Chunk == NULL) + { + return 0; + } + + // Wait for the chunk to become valid: + while (!Chunk->IsValid()) + { + GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); // Re-queue (in case it managed to get unloaded before we caught it + cCSUnlock Unlock(Lock); + m_evtChunkValid.Wait(); + } + + return Chunk->GetHeight(a_BlockX, a_BlockZ); +} + + + + + void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom ) { cCSLock Lock(m_CSLayers); @@ -445,3 +493,12 @@ int cChunkMap::GetNumChunks(void) + +void cChunkMap::ChunkValidated(void) +{ + m_evtChunkValid.Set(); +} + + + + diff --git a/source/cChunkMap.h b/source/cChunkMap.h index 4ec7ef01d..ffea1d504 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -36,14 +36,16 @@ public: void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL); void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // a_Player rclked block entity at the coords specified, handle it - void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaving (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void ChunkDataLoaded (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); - void SetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); - void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); - bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - bool HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkSaving (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void ChunkDataLoaded (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); + void ChunkDataGenerated (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); + void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); + bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + bool HasChunkAnyClients (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void SpreadChunkLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + int GetHeight (int a_BlockX, int a_BlockZ); void Tick( float a_Dt, MTRand & a_TickRand ); @@ -79,7 +81,7 @@ public: } } - + void ChunkValidated(void); // Called by chunks that have become valid private: @@ -120,6 +122,7 @@ private: cCriticalSection m_CSLayers; cChunkLayerList m_Layers; + cEvent m_evtChunkValid; // Set whenever any chunk becomes valid, via ChunkValidated() cWorld * m_World; }; diff --git a/source/cPluginManager.cpp b/source/cPluginManager.cpp index fd1a093d7..1aeb0eb2f 100644 --- a/source/cPluginManager.cpp +++ b/source/cPluginManager.cpp @@ -10,7 +10,6 @@ #include "cRoot.h" #include "cLuaCommandBinder.h" #include "../iniFile/iniFile.h" -#include #include "SquirrelBindings.h" #if USE_SQUIRREL diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 744780242..f57c8b5cf 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -91,6 +91,55 @@ inline float fRadRand( float a_Radius ) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cWorldLoadProgress: + +/// A simple thread that displays the progress of world loading / saving in cWorld::InitializeSpawn() +class cWorldLoadProgress : + public cIsThread +{ +public: + cWorldLoadProgress(cWorld * a_World) : + cIsThread("cWorldLoadProgress"), + m_World(a_World) + { + Start(); + } + +protected: + + cWorld * m_World; + + virtual void Execute(void) override + { + for (;;) + { + LOG("%d chunks to load, %d chunks to generate", + m_World->GetStorage().GetLoadQueueLength(), + m_World->GetGenerator().GetQueueLength() + ); + + // Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish + for (int i = 0; i < 20; i++) + { + cSleep::MilliSleep(100); + if (mShouldTerminate) + { + return; + } + } + } // for (-ever) + } + +} ; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cWorld: + cWorld* cWorld::GetWorld() { LOGWARN("WARNING: Using deprecated function cWorld::GetWorld() use cRoot::Get()->GetWorld() instead!"); @@ -154,7 +203,7 @@ cWorld::cWorld( const AString & a_WorldName ) m_GameMode = 0; AString GeneratorName; - AString StorageSchema; + AString StorageSchema("Default"); cIniFile IniFile( m_WorldName + "/world.ini"); if( IniFile.ReadFile() ) @@ -164,8 +213,8 @@ cWorld::cWorld( const AString & a_WorldName ) m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ ); m_WorldSeed = IniFile.GetValueI("Seed", "Seed", m_WorldSeed ); m_GameMode = IniFile.GetValueI("GameMode", "GameMode", m_GameMode ); - GeneratorName = IniFile.GetValue("Generator", "GeneratorName", "Default"); - StorageSchema = IniFile.GetValue("Storage", "Schema", "Default"); + GeneratorName = IniFile.GetValue("Generator", "GeneratorName", GeneratorName); + StorageSchema = IniFile.GetValue("Storage", "Schema", StorageSchema); } else { @@ -174,7 +223,8 @@ cWorld::cWorld( const AString & a_WorldName ) IniFile.SetValueF("SpawnPosition", "Z", m_SpawnZ ); IniFile.SetValueI("Seed", "Seed", m_WorldSeed ); IniFile.SetValueI("GameMode", "GameMode", m_GameMode ); - IniFile.SetValue("Generator", "GeneratorName", "Default" ); + IniFile.SetValue("Generator", "GeneratorName", GeneratorName); + IniFile.SetValue("Storage", "Schema", StorageSchema); if( !IniFile.WriteFile() ) { LOG("WARNING: Could not write to %s/world.ini", a_WorldName.c_str()); @@ -380,7 +430,9 @@ void cWorld::InitializeSpawn() { int ChunkX = 0, ChunkY = 0, ChunkZ = 0; BlockToChunk( (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ ); + int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is + LOG("Preparing spawn area in world \"%s\"", m_WorldName.c_str()); for (int x = 0; x < ViewDist; x++) { @@ -390,7 +442,16 @@ void cWorld::InitializeSpawn() } } - // TODO: Wait for the generator to finish generating these chunks + // Display progress during this process: + cWorldLoadProgress Progress(this); + + // Wait for the loader to finish loading + m_Storage.WaitForQueuesEmpty(); + + // Wait for the generator to finish generating + m_Generator.WaitForQueueEmpty(); + + m_SpawnY = (double)GetHeight( (int)m_SpawnX, (int)m_SpawnZ ) + 1.6f; // +1.6f eye height } @@ -434,23 +495,7 @@ void cWorld::Tick(float a_Dt) } } - { - cCSLock Lock(m_CSLighting); - if (m_SpreadQueue.size() >= 50 ) - { - LOGWARN("cWorld: Lots of lighting to do! Still %i chunks left!", m_SpreadQueue.size() ); - } - int TimesSpreaded = 0; - while ( !m_SpreadQueue.empty() && TimesSpreaded < MAX_LIGHTING_SPREAD_PER_TICK ) // Do not choke the tick thread - { - cChunkPtr & Chunk = *m_SpreadQueue.begin(); - //LOG("Spreading: %p", Chunk ); - Chunk->SpreadLight( Chunk->pGetSkyLight() ); - Chunk->SpreadLight( Chunk->pGetLight() ); - m_SpreadQueue.pop_front(); - TimesSpreaded++; - } - } + TickLighting(); m_ChunkMap->Tick(a_Dt, m_TickRand); @@ -602,7 +647,7 @@ void cWorld::TickSpawnMobs(float a_Dt) int nightRand = m_TickRand.randInt() % 10; SpawnPos += Vector3d( (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32 ); - char Height = GetHeight( (int)SpawnPos.x, (int)SpawnPos.z ); + int Height = GetHeight( (int)SpawnPos.x, (int)SpawnPos.z ); if (m_WorldTime >= 12000 + 1000) { @@ -657,6 +702,37 @@ void cWorld::TickSpawnMobs(float a_Dt) +void cWorld::TickLighting(void) +{ + // To avoid a deadlock, we lock the spread queue only long enough to pick the chunk coords to spread + // The spreading itself will run unlocked + cChunkCoordsList SpreadQueue; + { + cCSLock Lock(m_CSLighting); + if (m_SpreadQueue.size() == 0) + { + return; + } + if (m_SpreadQueue.size() >= MAX_LIGHTING_SPREAD_PER_TICK ) + { + LOGWARN("cWorld: Lots of lighting to do! Still %i chunks left!", m_SpreadQueue.size() ); + } + // Move up to MAX_LIGHTING_SPREAD_PER_TICK elements from m_SpreadQueue out into SpreadQueue: + cChunkCoordsList::iterator itr = m_SpreadQueue.begin(); + std::advance(itr, MIN(m_SpreadQueue.size(), MAX_LIGHTING_SPREAD_PER_TICK)); + SpreadQueue.splice(SpreadQueue.begin(), m_SpreadQueue, m_SpreadQueue.begin(), itr); + } + + for (cChunkCoordsList::iterator itr = SpreadQueue.begin(); itr != SpreadQueue.end(); ++itr) + { + m_ChunkMap->SpreadChunkLighting(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); + } +} + + + + + void cWorld::GrowTree( int a_X, int a_Y, int a_Z ) { // new tree code, looks much better @@ -896,16 +972,9 @@ cBlockEntity * cWorld::GetBlockEntity( int a_X, int a_Y, int a_Z ) -char cWorld::GetHeight( int a_X, int a_Z ) +int cWorld::GetHeight( int a_X, int a_Z ) { - int PosX = a_X, PosY = 0, PosZ = a_Z, ChunkX, ChunkY, ChunkZ; - AbsoluteToRelative( PosX, PosY, PosZ, ChunkX, ChunkY, ChunkZ ); - cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - if ( Chunk->IsValid()) - { - return Chunk->GetHeight( PosX, PosZ ); - } - return 0; + return m_ChunkMap->GetHeight(a_X, a_Z); } @@ -914,7 +983,6 @@ char cWorld::GetHeight( int a_X, int a_Z ) const double & cWorld::GetSpawnY(void) { - m_SpawnY = (double)GetHeight( (int)m_SpawnX, (int)m_SpawnZ ) + 1.6f; // +1.6f eye height return m_SpawnY; } @@ -983,9 +1051,9 @@ void cWorld::ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const cha -void cWorld::SetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) +void cWorld::ChunkDataGenerated(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) { - m_ChunkMap->SetChunkData(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockData, a_Entities, a_BlockEntities); + m_ChunkMap->ChunkDataGenerated(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockData, a_Entities, a_BlockEntities); } @@ -1217,21 +1285,21 @@ void cWorld::SaveAllChunks() -void cWorld::ReSpreadLighting( const cChunkPtr & a_Chunk ) +void cWorld::ReSpreadLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cCSLock Lock(m_CSLighting); - m_SpreadQueue.remove( a_Chunk ); - m_SpreadQueue.push_back( a_Chunk ); + m_SpreadQueue.remove(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + m_SpreadQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); } -void cWorld::RemoveSpread( const cChunkPtr & a_Chunk ) +void cWorld::RemoveSpread(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cCSLock Lock(m_CSLighting); - m_SpreadQueue.remove( a_Chunk ); + m_SpreadQueue.remove(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); } diff --git a/source/cWorld.h b/source/cWorld.h index 19051bbe1..131361d21 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -60,7 +60,7 @@ public: cChunkPtr GetChunk ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) {return m_ChunkMap->GetChunk (a_ChunkX, a_ChunkY, a_ChunkZ); } cChunkPtr GetChunkNoGen ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) {return m_ChunkMap->GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); } cChunkPtr GetChunkOfBlock( int a_X, int a_Y, int a_Z ); - char GetHeight( int a_X, int a_Z ); //tolua_export + int GetHeight( int a_X, int a_Z ); //tolua_export //void AddClient( cClientHandle* a_Client ); //void RemoveClient( cClientHandle* a_Client ); @@ -74,7 +74,7 @@ public: void MarkChunkSaving (int a_ChunkX, int a_ChunkY, int a_ChunkZ); void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ); void ChunkDataLoaded (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); - void SetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); + void ChunkDataGenerated(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; bool HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; @@ -165,8 +165,8 @@ public: void Tick(float a_Dt); - void ReSpreadLighting(const cChunkPtr & a_Chunk ); - void RemoveSpread(const cChunkPtr & a_Chunk ); + void ReSpreadLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void RemoveSpread(int a_ChunkX, int a_ChunkY, int a_ChunkZ); void InitializeSpawn(); @@ -176,6 +176,7 @@ public: cChunkGenerator & GetGenerator(void) { return m_Generator; } cWorldStorage & GetStorage (void) { return m_Storage; } + cChunkMap * GetChunkMap (void) { return m_ChunkMap; } private: @@ -247,7 +248,7 @@ private: cPlayerList m_Players; cCriticalSection m_CSLighting; - cChunkPtrList m_SpreadQueue; + cChunkCoordsList m_SpreadQueue; cCriticalSection m_CSFastSetBlock; FastSetBlockList m_FastSetBlockQueue; @@ -261,6 +262,7 @@ private: void TickWeather(float a_Dt); // Handles weather each tick void TickSpawnMobs(float a_Dt); // Handles mob spawning each tick + void TickLighting(void); // Handles lighting re-spreading void RemoveEntity( cEntity * a_Entity ); }; //tolua_export diff --git a/source/cWorldGenerator.cpp b/source/cWorldGenerator.cpp index fcbbcdad3..284b4c478 100644 --- a/source/cWorldGenerator.cpp +++ b/source/cWorldGenerator.cpp @@ -31,19 +31,9 @@ cWorldGenerator::~cWorldGenerator() -void cWorldGenerator::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorldGenerator::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) { - // TODO: use a raw char array instead of the entire chunk, then set it as chunk's blockdata - - cChunkPtr Chunk = m_World->GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); - assert(!Chunk->IsValid()); - - memset(Chunk->pGetBlockData(), 0, cChunk::c_BlockDataSize); - GenerateTerrain(Chunk); - GenerateFoliage(Chunk); - Chunk->CalculateHeightmap(); - Chunk->CalculateLighting(); - Chunk->SetValid(); + GenerateTerrain(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockData); } @@ -101,40 +91,44 @@ static float GetOreNoise( float x, float y, float z, cNoise & a_Noise ) -void cWorldGenerator::GenerateTerrain( cChunkPtr a_Chunk ) +unsigned int cWorldGenerator::MakeIndex(int x, int y, int z ) { - Vector3i ChunkPos( a_Chunk->GetPosX(), a_Chunk->GetPosY(), a_Chunk->GetPosZ() ); - char* BlockType = a_Chunk->pGetType(); + assert((x < 16) && (x > -1) && (y < 128) && (y > -1) && (z < 16) && (z > -1)); - //const ENUM_BLOCK_ID GrassID = E_BLOCK_GRASS; - const ENUM_BLOCK_ID DirtID = E_BLOCK_DIRT; - const ENUM_BLOCK_ID StoneID = E_BLOCK_STONE; - const ENUM_BLOCK_ID SandID = E_BLOCK_SAND; - const ENUM_BLOCK_ID SandStoneID = E_BLOCK_SANDSTONE; - const ENUM_BLOCK_ID CaveID = E_BLOCK_AIR; - const ENUM_BLOCK_ID LavaID = E_BLOCK_STATIONARY_LAVA; - const ENUM_BLOCK_ID CoalID = E_BLOCK_COAL_ORE; - const ENUM_BLOCK_ID IronID = E_BLOCK_IRON_ORE; - const ENUM_BLOCK_ID GoldID = E_BLOCK_GOLD_ORE; - const ENUM_BLOCK_ID DiamondID = E_BLOCK_DIAMOND_ORE; - const ENUM_BLOCK_ID RedID = E_BLOCK_REDSTONE_ORE; - - cNoise Noise( a_Chunk->GetWorld()->GetWorldSeed() ); - for(int z = 0; z < 16; z++) + return y + (z * 128) + (x * 128 * 16); +} + + + + + +void cWorldGenerator::GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData) +{ + const int WATER_LEVEL = 60; + const int SAND_LEVEL = 3; + + memset(a_BlockData, E_BLOCK_AIR, cChunk::c_BlockDataSize); + + cNoise Noise(m_World->GetWorldSeed()); + + for (int z = 0; z < 16; z++) { - const float zz = (float)(ChunkPos.z*16 + z); - for(int x = 0; x < 16; x++) + const float zz = (float)(a_ChunkZ * 16 + z); + for (int x = 0; x < 16; x++) { // Place bedrock on bottom layer - BlockType[ cChunk::MakeIndex(x, 0, z) ] = E_BLOCK_BEDROCK; + a_BlockData[MakeIndex(x, 0, z)] = E_BLOCK_BEDROCK; - const float xx = (float)(ChunkPos.x*16 + x); + const float xx = (float)(a_ChunkX * 16 + x); - int Height = (int)(GetNoise( xx*0.05f, zz*0.05f, Noise )*16); + int Height = (int)(GetNoise( xx * 0.05f, zz * 0.05f, Noise ) * 16); const int Lower = 64; - if( Height+Lower > 127 ) Height = 127-Lower; - const int Top = Lower+Height; - const float WaveNoise = 1;//m_Noise.CubicNoise2D( xx*0.01f, zz*0.01f ) + 0.5f; + if ( Height + Lower > 127 ) + { + Height = 127 - Lower; + } + const int Top = Lower + Height; + const float WaveNoise = 1; // m_Noise.CubicNoise2D( xx*0.01f, zz*0.01f ) + 0.5f; for( int y = 1; y < Top; ++y ) { const float yy = (float)y; @@ -143,42 +137,69 @@ void cWorldGenerator::GenerateTerrain( cChunkPtr a_Chunk ) { if( y > 4 ) { - BlockType[ cChunk::MakeIndex(x, y, z) ] = CaveID; - if( z > 0 ) BlockType[ cChunk::MakeIndex(x, y, z-1) ] = CaveID; - if( z < 15 ) BlockType[ cChunk::MakeIndex(x, y, z+1) ] = CaveID; - if( x > 0 ) BlockType[ cChunk::MakeIndex(x-1, y, z) ] = CaveID; - if( x < 15 ) BlockType[ cChunk::MakeIndex(x+1, y, z) ] = CaveID; + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_AIR; + if( z > 0 ) a_BlockData[ MakeIndex(x, y, z-1) ] = E_BLOCK_AIR; + if( z < 15 ) a_BlockData[ MakeIndex(x, y, z+1) ] = E_BLOCK_AIR; + if( x > 0 ) a_BlockData[ MakeIndex(x-1, y, z) ] = E_BLOCK_AIR; + if( x < 15 ) a_BlockData[ MakeIndex(x+1, y, z) ] = E_BLOCK_AIR; } else { - BlockType[ cChunk::MakeIndex(x, y, z) ] = LavaID; + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_STATIONARY_LAVA; } } - else if( y < 61 && Top - y < 3 ) - BlockType[ cChunk::MakeIndex(x, y, z) ] = SandID; - else if( y < 61 && Top - y < 4 ) - BlockType[ cChunk::MakeIndex(x, y, z) ] = SandStoneID; - else if( Top - y > ((WaveNoise+1.5f)*1.5f) ) // rock and ores between 1.5 .. 4.5 deep + else if ((y < 61) && (Top - y < SAND_LEVEL )) + { + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_SAND; + } + else if ((y < 61) && (Top - y < 4 )) { - if( GetOreNoise( xx, yy, zz, Noise ) > 0.5f ) - BlockType[ cChunk::MakeIndex(x, y, z) ] = CoalID; - else if( GetOreNoise( xx, yy+100.f, zz, Noise ) > 0.6f ) - BlockType[ cChunk::MakeIndex(x, y, z) ] = IronID; - else if( yy < 20 && GetOreNoise( xx*1.5f, yy+300.f, zz*1.5f, Noise ) > 0.6f ) - BlockType[ cChunk::MakeIndex(x, y, z) ] = RedID; - else if( yy < 30 && GetOreNoise( xx*2, yy+200.f, zz*2, Noise ) > 0.75f ) - BlockType[ cChunk::MakeIndex(x, y, z) ] = DiamondID; - else if( yy < 40 && GetOreNoise( xx*2, yy+100.f, zz*2, Noise ) > 0.75f ) - BlockType[ cChunk::MakeIndex(x, y, z) ] = GoldID; + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_SANDSTONE; + } + else if (Top - y > ((WaveNoise + 1.5f) * 1.5f)) // rock and ores between 1.5 .. 4.5 deep + { + if ( GetOreNoise( xx, yy, zz, Noise ) > 0.5f ) + { + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_COAL_ORE; + } + else if ( GetOreNoise( xx, yy+100.f, zz, Noise ) > 0.6f ) + { + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_IRON_ORE; + } + else if (( yy < 20) && (GetOreNoise( xx * 1.5f, yy + 300.f, zz * 1.5f, Noise ) > 0.6f )) + { + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_REDSTONE_ORE; + } + else if (( yy < 30) && (GetOreNoise( xx * 2, yy + 200.f, zz * 2, Noise ) > 0.75f )) + { + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_DIAMOND_ORE; + } + else if (( yy < 40) && (GetOreNoise( xx * 2, yy + 100.f, zz * 2, Noise ) > 0.75f )) + { + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_GOLD_ORE; + } else - BlockType[ cChunk::MakeIndex(x, y, z) ] = StoneID; + { + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_STONE; + } } else - BlockType[ cChunk::MakeIndex(x, y, z) ] = DirtID; + { + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_DIRT; + } + } + if (Top + 1 >= WATER_LEVEL + SAND_LEVEL) + { + // Replace top dirt with grass: + a_BlockData[MakeIndex(x, Top - 1, z)] = E_BLOCK_GRASS; } - for( int y = Lower+Height; y < 60; ++y ) + else { - BlockType[ cChunk::MakeIndex(x, y, z) ] = E_BLOCK_STATIONARY_WATER; + // Add water up to the WATER_LEVEL: + for (int y = Top; y < WATER_LEVEL; ++y ) + { + a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_STATIONARY_WATER; + } } } } @@ -188,7 +209,7 @@ void cWorldGenerator::GenerateTerrain( cChunkPtr a_Chunk ) -void cWorldGenerator::GenerateFoliage( cChunkPtr a_Chunk ) +void cWorldGenerator::GenerateFoliage( cChunkPtr & a_Chunk ) { const ENUM_BLOCK_ID GrassID = E_BLOCK_GRASS; const ENUM_BLOCK_ID DirtID = E_BLOCK_DIRT; @@ -209,7 +230,7 @@ void cWorldGenerator::GenerateFoliage( cChunkPtr a_Chunk ) int TopY = -1; for(int y = 127; y > 0; y--) { - int index = cChunk::MakeIndex( x, y, z ); + int index = MakeIndex( x, y, z ); if( BlockType[index] != E_BLOCK_AIR ) { TopY = y; @@ -219,12 +240,12 @@ void cWorldGenerator::GenerateFoliage( cChunkPtr a_Chunk ) if( TopY > 0 ) { // Change top dirt into grass and prevent sand from floating over caves - int index = cChunk::MakeIndex( x, TopY, z ); - int index1 = cChunk::MakeIndex( x, TopY-1, z ); - int index2 = cChunk::MakeIndex( x, TopY-2, z ); - int index3 = cChunk::MakeIndex( x, TopY-3, z ); - int index4 = cChunk::MakeIndex( x, TopY-4, z ); - int index5 = cChunk::MakeIndex( x, TopY-5, z ); + int index = MakeIndex( x, TopY, z ); + int index1 = MakeIndex( x, TopY-1, z ); + int index2 = MakeIndex( x, TopY-2, z ); + int index3 = MakeIndex( x, TopY-3, z ); + int index4 = MakeIndex( x, TopY-4, z ); + int index5 = MakeIndex( x, TopY-5, z ); if( BlockType[index] == SandID ) { @@ -258,10 +279,10 @@ void cWorldGenerator::GenerateFoliage( cChunkPtr a_Chunk ) { if( (val1 + val2 > 0.f) && (r1.randInt()%128) > 124 && BlockType[index] == E_BLOCK_SAND ) { - BlockType[ cChunk::MakeIndex(x, TopY+1, z) ] = E_BLOCK_CACTUS; + BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_CACTUS; if( (r1.randInt() & 3) == 3 ) { - BlockType[ cChunk::MakeIndex(x, TopY+2, z) ] = E_BLOCK_CACTUS; + BlockType[ MakeIndex(x, TopY+2, z) ] = E_BLOCK_CACTUS; } continue; } @@ -273,13 +294,13 @@ void cWorldGenerator::GenerateFoliage( cChunkPtr a_Chunk ) if( val1 + val2 > 0.2f && (r1.randInt()%128) > 124 ) World->GrowTree( xx, TopY, zz ); else if( val3 > 0.2f && (r1.randInt()%128) > 124 ) - BlockType[ cChunk::MakeIndex(x, TopY+1, z) ] = E_BLOCK_YELLOW_FLOWER; + BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_YELLOW_FLOWER; else if( val4 > 0.2f && (r1.randInt()%128) > 124 ) - BlockType[ cChunk::MakeIndex(x, TopY+1, z) ] = E_BLOCK_RED_ROSE; + BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_RED_ROSE; else if( val1+val2+val3+val4 > 0.2f && (r1.randInt()%128) > 124 ) - BlockType[ cChunk::MakeIndex(x, TopY+1, z) ] = E_BLOCK_RED_MUSHROOM; + BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_RED_MUSHROOM; else if( val1+val2+val3+val4 > 0.2f && (r1.randInt()%128) > 124 ) - BlockType[ cChunk::MakeIndex(x, TopY+1, z) ] = E_BLOCK_BROWN_MUSHROOM; + BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_BROWN_MUSHROOM; } } diff --git a/source/cWorldGenerator.h b/source/cWorldGenerator.h index 208178d4a..92c2a1d0c 100644 --- a/source/cWorldGenerator.h +++ b/source/cWorldGenerator.h @@ -18,7 +18,7 @@ public: cWorldGenerator(cWorld * a_World); ~cWorldGenerator(); - virtual void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + virtual void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); protected: @@ -27,8 +27,11 @@ protected: // Thread-unsafe: MTRand r1; - virtual void GenerateTerrain( cChunkPtr a_Chunk ); - virtual void GenerateFoliage( cChunkPtr a_Chunk ); + static unsigned int MakeIndex(int x, int y, int z ); + + virtual void GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData); + + virtual void GenerateFoliage(cChunkPtr & a_Chunk ); }; diff --git a/source/cWorldGenerator_Test.cpp b/source/cWorldGenerator_Test.cpp index 08e649fb9..1ffcdbfbe 100644 --- a/source/cWorldGenerator_Test.cpp +++ b/source/cWorldGenerator_Test.cpp @@ -9,24 +9,27 @@ -void cWorldGenerator_Test::GenerateTerrain( cChunkPtr a_Chunk ) +void cWorldGenerator_Test::GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData) { - char* BlockType = a_Chunk->pGetType(); - + memset(a_BlockData, E_BLOCK_DIRT, cChunk::c_NumBlocks); for(int x = 0; x < 16; x++) { for(int z = 0; z < 16; z++) { - for( int y = 1; y < 128; ++y ) - { - unsigned int idx = cChunk::MakeIndex(x, y, z); - BlockType[idx] = E_BLOCK_DIRT; - } + a_BlockData[MakeIndex(x, 0, z)] = E_BLOCK_BEDROCK; } } } -void cWorldGenerator_Test::GenerateFoliage( cChunkPtr a_Chunk ) + + + + +void cWorldGenerator_Test::GenerateFoliage( cChunkPtr & a_Chunk ) { (void)a_Chunk; -} \ No newline at end of file +} + + + + diff --git a/source/cWorldGenerator_Test.h b/source/cWorldGenerator_Test.h index 5a5483fa9..8c4dc0e99 100644 --- a/source/cWorldGenerator_Test.h +++ b/source/cWorldGenerator_Test.h @@ -15,8 +15,9 @@ public: cWorldGenerator_Test(cWorld * a_World) : cWorldGenerator(a_World) {} protected: - virtual void GenerateTerrain( cChunkPtr a_Chunk ) override; - virtual void GenerateFoliage( cChunkPtr a_Chunk ) override; + + virtual void GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData) override; + virtual void GenerateFoliage(cChunkPtr & a_Chunk ) override; }; -- cgit v1.2.3