diff options
Diffstat (limited to 'source/cChunkGenerator.cpp')
-rw-r--r-- | source/cChunkGenerator.cpp | 162 |
1 files changed, 74 insertions, 88 deletions
diff --git a/source/cChunkGenerator.cpp b/source/cChunkGenerator.cpp index 78853a26b..8755ea325 100644 --- a/source/cChunkGenerator.cpp +++ b/source/cChunkGenerator.cpp @@ -2,11 +2,13 @@ #include "Globals.h"
#include "cChunkGenerator.h"
-#include "cChunkMap.h"
-#include "cChunk.h"
#include "cWorld.h"
+#include "cWorldGenerator.h"
+#include "cWorldGenerator_Test.h"
+
+
+
-#include "cMCLogger.h"
typedef std::pair<int, int> ChunkCoord;
typedef std::list< ChunkCoord > ChunkCoordList;
@@ -16,144 +18,128 @@ typedef std::list< ChunkCoord > ChunkCoordList; /// If the generation queue size exceeds this number, a warning will be output
-#define QUEUE_WARNING_LIMIT 1000
+const int QUEUE_WARNING_LIMIT = 1000;
+
+/// If the generation queue size exceeds this number, chunks with no clients will be skipped
+const int QUEUE_SKIP_LIMIT = 50;
-struct cChunkGenerator::sChunkGeneratorState
+cChunkGenerator::cChunkGenerator(void)
+ : super("cChunkGenerator")
+ , m_World(NULL)
+ , m_pWorldGenerator(NULL)
{
- cCriticalSection m_CriticalSection; // For protecting the variables in this struct
+}
+
- ChunkCoordList GenerateQueue;
- ChunkCoord CurrentlyGeneratingCoords;
- cChunk* pCurrentlyGenerating;
- bool bCurrentlyGenerating;
- cSemaphore m_Semaphore;
- cThread * pThread;
- bool bStop;
- sChunkGeneratorState(void)
- : m_Semaphore(1, 0)
- , pThread( 0 )
- , bStop( false )
- , bCurrentlyGenerating( false )
- , pCurrentlyGenerating( false )
- {}
-};
+cChunkGenerator::~cChunkGenerator()
+{
+ Stop();
+}
-cChunkGenerator::cChunkGenerator( cChunkMap* a_pChunkMap )
- : m_pState( new sChunkGeneratorState )
- , m_pChunkMap( a_pChunkMap )
+bool cChunkGenerator::Start(cWorld * a_World, const AString & a_WorldGeneratorName)
{
- m_pState->pThread = new cThread( GenerateThread, this, "cChunkGenerator::GenerateThread" );
- m_pState->pThread->Start( true );
+ m_World = a_World;
+
+ if (a_WorldGeneratorName.compare("Test") == 0 )
+ {
+ m_pWorldGenerator = new cWorldGenerator_Test();
+ }
+ else // Default
+ {
+ m_pWorldGenerator = new cWorldGenerator();
+ }
+
+ return super::Start();
}
-cChunkGenerator::~cChunkGenerator()
+void cChunkGenerator::Stop(void)
{
- m_pState->bStop = true;
-
- m_pState->m_Semaphore.Signal(); // Signal so thread can continue and exit
- delete m_pState->pThread;
-
- delete m_pState;
+ mShouldTerminate = true;
+ m_Event.Set();
+ Wait();
+
+ delete m_pWorldGenerator;
+ m_pWorldGenerator = NULL;
}
-void cChunkGenerator::GenerateChunk( int a_X, int a_Z )
+void cChunkGenerator::GenerateChunk(int a_ChunkX, int a_ChunkZ)
{
- cCSLock Lock(&m_pState->m_CriticalSection);
-
- if (m_pState->bCurrentlyGenerating)
+ 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 ((m_pState->CurrentlyGeneratingCoords.first == a_X) && (m_pState->CurrentlyGeneratingCoords.second == a_Z))
+ if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ))
{
- return; // Already generating this chunk, so ignore
+ // Already in the queue, bail out
+ return;
}
- }
-
- m_pState->GenerateQueue.remove( ChunkCoord(a_X, a_Z) );
- if (m_pState->GenerateQueue.size() >= QUEUE_WARNING_LIMIT)
+ } // for itr - m_Queue[]
+
+ // Add to queue, issue a warning if too many:
+ if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
{
- LOGWARN("WARNING: Adding chunk (%i, %i) to generation queue; Queue is too big! (%i)", a_X, a_Z, m_pState->GenerateQueue.size() );
+ LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (%i)", a_ChunkX, a_ChunkZ, m_Queue.size());
}
- m_pState->GenerateQueue.push_back( ChunkCoord(a_X, a_Z) );
-
- Lock.Unlock();
+ m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
- m_pState->m_Semaphore.Signal();
+ m_Event.Set();
}
-void cChunkGenerator::GenerateThread( void* a_Params )
+void cChunkGenerator::Execute(void)
{
- // Cache some values for easy access (they are all references/pointers)
- cChunkGenerator * self = (cChunkGenerator*)a_Params;
- sChunkGeneratorState * m_pState = self->m_pState;
- ChunkCoordList & GenerateQueue = m_pState->GenerateQueue;
- cChunkMap & ChunkMap = *self->m_pChunkMap;
- cCriticalSection * CriticalSection = &m_pState->m_CriticalSection;
- cSemaphore & Semaphore = m_pState->m_Semaphore;
-
- while (!m_pState->bStop)
+ while (!mShouldTerminate)
{
- cCSLock Lock(CriticalSection);
- if (GenerateQueue.size() == 0)
+ cCSLock Lock(m_CS);
+ while (m_Queue.size() == 0)
{
cCSUnlock Unlock(Lock);
- Semaphore.Wait();
+ m_Event.Wait();
+ if (mShouldTerminate)
+ {
+ return;
+ }
}
- if (m_pState->bStop) break;
- ChunkCoord coord = *GenerateQueue.begin(); // Get next coord from queue
- GenerateQueue.erase( GenerateQueue.begin() ); // Remove coordinate from queue
- m_pState->bCurrentlyGenerating = true;
- m_pState->CurrentlyGeneratingCoords = coord;
+ cChunkCoords coords = m_Queue.front(); // Get next coord from queue
+ m_Queue.erase( m_Queue.begin() ); // Remove coordinate from queue
+ bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
Lock.Unlock(); // Unlock ASAP
- ChunkMap.GetWorld()->LockChunks();
- if( ChunkMap.GetChunk( coord.first, 0, coord.second ) ) // Make sure it has not been loaded in the meantime. Don't want to generate the same chunk twice
- { // This is possible when forcing the server to generate a chunk in the main thread
- ChunkMap.GetWorld()->UnlockChunks();
+ cChunkPtr Chunk = m_World->GetChunk(coords.m_ChunkX, 0, coords.m_ChunkZ);
+ if ((Chunk != NULL) && (Chunk->IsValid() || (SkipEnabled && !Chunk->HasAnyClient())))
+ {
+ // Already generated / overload-skip, ignore request
continue;
}
- ChunkMap.GetWorld()->UnlockChunks();
-
- LOGINFO("cChunkGenerator generating chunk %i %i", coord.first, coord.second );
- cChunk* Chunk = new cChunk( coord.first, 0, coord.second, ChunkMap.GetWorld() );
-
- Lock.Lock();
- m_pState->pCurrentlyGenerating = Chunk;
- Lock.Unlock();
- Chunk->Initialize(); // Generate the chunk
-
- ChunkMap.GetWorld()->LockChunks();
- ChunkMap.AddChunk( Chunk );
- ChunkMap.GetWorld()->UnlockChunks();
-
- Lock.Lock();
- m_pState->bCurrentlyGenerating = false;
- m_pState->pCurrentlyGenerating = 0;
- Lock.Unlock();
+ LOG("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ);
+ m_pWorldGenerator->GenerateChunk(Chunk);
+
+ Chunk->SetValid();
} // while (!bStop)
}
|