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-c427514a06d6master
parent
57dedd585c
commit
499745c1c7
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
// Both queues are locked by the same CS
|
||||
cCriticalSection m_CSQueues;
|
||||
cChunkCoordsList m_LoadQueue;
|
||||
cChunkCoordsList m_SaveQueue;
|
||||
|
||||
cCriticalSection m_CSSaveQueue;
|
||||
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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "cRoot.h"
|
||||
#include "cLuaCommandBinder.h"
|
||||
#include "../iniFile/iniFile.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "SquirrelBindings.h"
|
||||
#if USE_SQUIRREL
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
return y + (z * 128) + (x * 128 * 16);
|
||||
}
|
||||
|
||||
cNoise Noise( a_Chunk->GetWorld()->GetWorldSeed() );
|
||||
for(int z = 0; z < 16; z++)
|
||||
|
||||
|
||||
|
||||
|
||||
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 ))
|
||||
{
|
||||
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_SAND;
|
||||
}
|
||||
else if ((y < 61) && (Top - y < 4 ))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
for( int y = Lower+Height; y < 60; ++y )
|
||||
if (Top + 1 >= WATER_LEVEL + SAND_LEVEL)
|
||||
{
|
||||
BlockType[ cChunk::MakeIndex(x, y, z) ] = E_BLOCK_STATIONARY_WATER;
|
||||
// Replace top dirt with grass:
|
||||
a_BlockData[MakeIndex(x, Top - 1, z)] = E_BLOCK_GRASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue