From 81c73341b24688b290c91bddcf83c3f6d3621f1b Mon Sep 17 00:00:00 2001 From: faketruth Date: Sun, 25 Dec 2011 12:55:20 +0000 Subject: The missing file! cChunkGenerator.h/cpp git-svn-id: http://mc-server.googlecode.com/svn/trunk@105 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChunkGenerator.cpp | 172 +++++++++++++++++++++++++++++++++++++++++++++ source/cChunkGenerator.h | 23 ++++++ 2 files changed, 195 insertions(+) create mode 100644 source/cChunkGenerator.cpp create mode 100644 source/cChunkGenerator.h diff --git a/source/cChunkGenerator.cpp b/source/cChunkGenerator.cpp new file mode 100644 index 000000000..f6a16342c --- /dev/null +++ b/source/cChunkGenerator.cpp @@ -0,0 +1,172 @@ +#include "MemoryLeak.h" +#include "cChunkGenerator.h" +#include "cChunkMap.h" +#include "cChunk.h" +#include "cWorld.h" + +#include "cThread.h" +#include "cCriticalSection.h" +#include "cSemaphore.h" + +#include "cMCLogger.h" + +#include + +typedef std::pair ChunkCoord; +typedef std::list< ChunkCoord > ChunkCoordList; + +#define MAX_SEMAPHORES 1000 + +struct cChunkGenerator::sChunkGeneratorState +{ + sChunkGeneratorState() + : pCriticalSection( 0 ) + , pSemaphore( 0 ) + , pThread( 0 ) + , bStop( false ) + , bCurrentlyGenerating( false ) + , pCurrentlyGenerating( false ) + , pChunkCriticalSection( 0 ) + {} + ChunkCoordList GenerateQueue; // Protected by pCriticalSection + ChunkCoord CurrentlyGeneratingCoords; // Protected by pCriticalSection + cChunk* pCurrentlyGenerating; // Protected by pCriticalSection + bool bCurrentlyGenerating; // Protected by pCriticalSection + + cCriticalSection* pCriticalSection; + cSemaphore* pSemaphore; + cThread* pThread; + + cCriticalSection* pChunkCriticalSection;// Specially for protecting the actual chunk that is currently being generated, and not just the variables in this struct + + bool bStop; +}; + +cChunkGenerator::cChunkGenerator( cChunkMap* a_pChunkMap ) + : m_pState( new sChunkGeneratorState ) + , m_pChunkMap( a_pChunkMap ) +{ + m_pState->pCriticalSection = new cCriticalSection(); + m_pState->pSemaphore = new cSemaphore( MAX_SEMAPHORES, 0 ); + + m_pState->pChunkCriticalSection = new cCriticalSection(); + + m_pState->pThread = new cThread( GenerateThread, this, "cChunkGenerator::GenerateThread" ); + m_pState->pThread->Start( true ); +} + +cChunkGenerator::~cChunkGenerator() +{ + m_pState->bStop = true; + + m_pState->pSemaphore->Signal(); // Signal so thread can continue and exit + delete m_pState->pThread; + + delete m_pState->pSemaphore; + delete m_pState->pCriticalSection; + delete m_pState->pChunkCriticalSection; + delete m_pState; m_pState = 0; +} + +void cChunkGenerator::GenerateChunk( int a_X, int a_Z ) +{ + m_pState->pCriticalSection->Lock(); + + if( m_pState->bCurrentlyGenerating ) + { + if( m_pState->CurrentlyGeneratingCoords.first == a_X && m_pState->CurrentlyGeneratingCoords.second == a_Z ) + { + m_pState->pCriticalSection->Unlock(); + return; // Already generating this chunk, so ignore + } + } + + int SizeBefore = m_pState->GenerateQueue.size(); + + m_pState->GenerateQueue.remove( ChunkCoord(a_X, a_Z) ); + if( m_pState->GenerateQueue.size() >= MAX_SEMAPHORES ) + { + LOGWARN("WARNING: Can't add chunk (%i, %i) to generation queue: Queue is too big! (%i)", a_X, a_Z, m_pState->GenerateQueue.size() ); + m_pState->pCriticalSection->Unlock(); + return; + } + m_pState->GenerateQueue.push_back( ChunkCoord(a_X, a_Z) ); + int SizeAfter = m_pState->GenerateQueue.size(); + + m_pState->pCriticalSection->Unlock(); + if( SizeBefore < SizeAfter ) + m_pState->pSemaphore->Signal(); +} + +void cChunkGenerator::GenerateThread( void* a_Params ) +{ + // 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->pCriticalSection; + cSemaphore& Semaphore = *m_pState->pSemaphore; + + while( !m_pState->bStop ) + { + Semaphore.Wait(); + if( m_pState->bStop ) break; + + CriticalSection.Lock(); + if( GenerateQueue.size() == 0 ) + { + if( !m_pState->bStop ) LOGERROR("ERROR: Semaphore was signaled while GenerateQueue.size == 0"); + CriticalSection.Unlock(); + continue; + } + 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; + CriticalSection.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(); + 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() ); + + CriticalSection.Lock(); + m_pState->pCurrentlyGenerating = Chunk; + CriticalSection.Unlock(); + + self->Lock(); // Protect the actual chunk + Chunk->Initialize(); // Generate the chunk + self->Unlock(); + + ChunkMap.GetWorld()->LockChunks(); + ChunkMap.AddChunk( Chunk ); + ChunkMap.GetWorld()->UnlockChunks(); + + CriticalSection.Lock(); + m_pState->bCurrentlyGenerating = false; + m_pState->pCurrentlyGenerating = 0; + CriticalSection.Unlock(); + } +} + +cChunk* cChunkGenerator::GetCurrentlyGenerating() +{ + return m_pState->pCurrentlyGenerating; +} + +void cChunkGenerator::Lock() +{ + m_pState->pChunkCriticalSection->Lock(); +} + +void cChunkGenerator::Unlock() +{ + m_pState->pChunkCriticalSection->Unlock(); +} \ No newline at end of file diff --git a/source/cChunkGenerator.h b/source/cChunkGenerator.h new file mode 100644 index 000000000..df29a3e60 --- /dev/null +++ b/source/cChunkGenerator.h @@ -0,0 +1,23 @@ +#pragma once + +class cChunk; +class cChunkMap; +class cChunkGenerator +{ +public: + cChunkGenerator( cChunkMap* a_pChunkMap ); + ~cChunkGenerator(); + + void GenerateChunk( int a_X, int a_Z ); + + cChunk* GetCurrentlyGenerating(); // WARNING - Be sure to Lock() before calling, and Unlock() after done with the chunk! + void Lock(); + void Unlock(); +private: + static void GenerateThread( void* a_Params ); + + cChunkMap* m_pChunkMap; + + struct sChunkGeneratorState; + sChunkGeneratorState* m_pState; +}; \ No newline at end of file -- cgit v1.2.3