summaryrefslogblamecommitdiffstats
path: root/source/cChunkGenerator.cpp
blob: 78853a26bceb5923be9551e2757065f0196ccabd (plain) (tree)
1
2
3
4
5
6
7
8
9
10


                     




                             

                       


                                                









                                                                               


                                             













                                                                                            



                                                
           

   
 
 
 




                                                           



                                                                                                    



 



                                    
                                                                                  

                                  
                         

  



 

                                                        
                                                    
 
                                            
          
                                                                                                                               
                  



                                                                            
                                                                
                                                                   
          
                                                                                                                                                  

                                                                   
 


                                        

  



 


                                                                                







                                                                           
          

                                               
                  

                                                
                  

                                            



                                                                                                     
                                                               











                                                                                                                                                                                                                   
                             
                                                        
                               
 
                                                           




                                                     
                             

                                                        

                               

  
 
 
 

#include "Globals.h"

#include "cChunkGenerator.h"
#include "cChunkMap.h"
#include "cChunk.h"
#include "cWorld.h"

#include "cMCLogger.h"

typedef std::pair<int, int> ChunkCoord;
typedef std::list< ChunkCoord > ChunkCoordList;





/// If the generation queue size exceeds this number, a warning will be output
#define QUEUE_WARNING_LIMIT 1000





struct cChunkGenerator::sChunkGeneratorState
{
	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( cChunkMap* a_pChunkMap )
	: m_pState( new sChunkGeneratorState )
	, m_pChunkMap( a_pChunkMap )
{
	m_pState->pThread = new cThread( GenerateThread, this, "cChunkGenerator::GenerateThread" );
	m_pState->pThread->Start( true );
}





cChunkGenerator::~cChunkGenerator()
{
	m_pState->bStop = true;

	m_pState->m_Semaphore.Signal(); // Signal so thread can continue and exit
	delete m_pState->pThread;

	delete m_pState;
}





void cChunkGenerator::GenerateChunk( int a_X, int a_Z )
{
	cCSLock Lock(&m_pState->m_CriticalSection);

	if (m_pState->bCurrentlyGenerating)
	{
		if ((m_pState->CurrentlyGeneratingCoords.first == a_X) && (m_pState->CurrentlyGeneratingCoords.second == a_Z))
		{
			return;	// Already generating this chunk, so ignore
		}
	}

	m_pState->GenerateQueue.remove( ChunkCoord(a_X, a_Z) );
	if (m_pState->GenerateQueue.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() );
	}
	m_pState->GenerateQueue.push_back( ChunkCoord(a_X, a_Z) );

	Lock.Unlock();
	
	m_pState->m_Semaphore.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->m_CriticalSection;
	cSemaphore & Semaphore = m_pState->m_Semaphore;

	while (!m_pState->bStop)
	{
		cCSLock Lock(CriticalSection);
		if (GenerateQueue.size() == 0)
		{
			cCSUnlock Unlock(Lock);
			Semaphore.Wait();
		}
		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;
		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();
			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();
	}  // while (!bStop)
}