<commit_before>
// LightingThread.cpp

// Implements the cLightingThread class representing the thread that processes requests for lighting

#include "Globals.h"
#include "LightingThread.h"
#include "ChunkMap.h"
#include "World.h"





/// If more than this many chunks are in the queue, a warning is printed to the log
#define WARN_ON_QUEUE_SIZE 800





/// Chunk data callback that takes the chunk data and puts them into cLightingThread's m_BlockTypes[] / m_HeightMap[]:
class cReader :
	public cChunkDataCallback
{
	virtual void BlockTypes(const BLOCKTYPE * a_Type) override
	{
		// ROW is a block of 16 Blocks, one whole row is copied at a time (hopefully the compiler will optimize that)
		// C++ doesn't permit copying arrays, but arrays as a part of a struct is ok :)
		typedef struct {BLOCKTYPE m_Row[16]; } ROW;
		ROW * InputRows = (ROW *)a_Type;
		ROW * OutputRows = (ROW *)m_BlockTypes;
		int InputIdx = 0;
		int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
		for (int y = 0; y < cChunkDef::Height; y++)
		{
			for (int z = 0; z < cChunkDef::Width; z++)
			{
				OutputRows[OutputIdx] = InputRows[InputIdx++];
				OutputIdx += 3;
			}  // for z
			// Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows
			// We've already walked cChunkDef::Width * 3 in the "for z" cycle, that makes cChunkDef::Width * 6 rows left to skip
			OutputIdx += cChunkDef::Width * 6;
		}  // for y
	}  // BlockTypes()
	
	
	virtual void HeightMap(const cChunkDef::HeightMap * a_Heightmap) override
	{
		typedef struct {HEIGHTTYPE m_Row[16]; } ROW;
		ROW * InputRows  = (ROW *)a_Heightmap;
		ROW * OutputRows = (ROW *)m_HeightMap;
		int InputIdx = 0;
		int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
		for (int z = 0; z < cChunkDef::Width; z++)
		{
			OutputRows[OutputIdx] = InputRows[InputIdx++];
			OutputIdx += 3;
		}  // for z
	}
	
public:
	int m_ReadingChunkX;  // 0, 1 or 2; x-offset of the chunk we're reading from the BlockTypes start
	int m_ReadingChunkZ;  // 0, 1 or 2; z-offset of the chunk we're reading from the BlockTypes start
	BLOCKTYPE * m_BlockTypes;  // 3x3 chunks of block types, organized as a single XZY blob of data (instead of 3x3 XZY blobs)
	HEIGHTTYPE * m_HeightMap;  // 3x3 chunks of height map,  organized as a single XZY blob of data (instead of 3x3 XZY blobs)
} ;





///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cLightingThread:

cLightingThread::cLightingThread(void) :
	super("cLightingThread"),
	m_World(NULL)
{
}





cLightingThread::~cLightingThread()
{
	Stop();
}





bool cLightingThread::Start(cWorld * a_World)
{
	ASSERT(m_World == NULL);  // Not started yet
	m_World = a_World;
	
	return super::Start();
}





void cLightingThread::Stop(void)
{
	{
		cCSLock Lock(m_CS);
		for (sItems::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr)
		{
			delete itr->m_ChunkStay;
		}
		m_Queue.clear();
	}
	m_ShouldTerminate = true;
	m_evtItemAdded.Set();
	
	Wait();
}





void cLightingThread::QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter)
{
	ASSERT(m_World != NULL);  // Did you call Start() properly?
	
	cChunkStay * ChunkStay = new cChunkStay(m_World);
	ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ + 1);
	ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ);
	ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ - 1);
	ChunkStay->Add(a_ChunkX,     ZERO_CHUNK_Y, a_ChunkZ + 1);
	ChunkStay->Add(a_ChunkX,     ZERO_CHUNK_Y, a_ChunkZ);
	ChunkStay->Add(a_ChunkX,     ZERO_CHUNK_Y, a_ChunkZ - 1);
	ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ + 1);
	ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ);
	ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ - 1);
	ChunkStay->Enable();
	ChunkStay->Load();
	cCSLock Lock(m_CS);
	m_Queue.push_back(sItem(a_ChunkX, a_ChunkZ, ChunkStay, a_CallbackAfter));
	if (m_Queue.size() > WARN_ON_QUEUE_SIZE)
	{
		LOGINFO("Lighting thread overloaded, %d items in queue", m_Queue.size());
	}
	m_evtItemAdded.Set();
}





void cLightingThread::WaitForQueueEmpty(void)
{
	cCSLock Lock(m_CS);
	while (!m_ShouldTerminate && (!m_Queue.empty() || !m_PostponedQueue.empty()))
	{
		cCSUnlock Unlock(Lock);
		m_evtQueueEmpty.Wait();
	}
}





size_t cLightingThread::GetQueueLength(void)
{
	cCSLock Lock(m_CS);
	return m_Queue.size() + m_PostponedQueue.size();
}





void cLightingThread::ChunkReady(int a_ChunkX, int a_ChunkZ)
{
	// Check all the items in the m_PostponedQueue, if the chunk is their neighbor, move the item to m_Queue
	
	bool NewlyAdded = false;
	{
		cCSLock Lock(m_CS);
		for (sItems::iterator itr = m_PostponedQueue.begin(); itr != m_PostponedQueue.end(); )
		{
			if (
				(itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1) &&
				(itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1)
			)
			{
				// It is a neighbor
				m_Queue.push_back(*itr);
				itr = m_PostponedQueue.erase(itr);
				NewlyAdded = true;
			}
			else
			{
				++itr;
			}
		}  // for itr - m_PostponedQueue[]
	}  // Lock(m_CS)
	
	if (NewlyAdded)
	{
		m_evtItemAdded.Set();  // Notify the thread it has some work to do
	}
}





void cLightingThread::Execute(void)
{
	while (true)
	{<commit_msg>take Z axis into account when calculating neighboors in LightingThread::ChunkReady<commit_after>
// LightingThread.cpp

// Implements the cLightingThread class representing the thread that processes requests for lighting

#include "Globals.h"
#include "LightingThread.h"
#include "ChunkMap.h"
#include "World.h"





/// If more than this many chunks are in the queue, a warning is printed to the log
#define WARN_ON_QUEUE_SIZE 800





/// Chunk data callback that takes the chunk data and puts them into cLightingThread's m_BlockTypes[] / m_HeightMap[]:
class cReader :
	public cChunkDataCallback
{
	virtual void BlockTypes(const BLOCKTYPE * a_Type) override
	{
		// ROW is a block of 16 Blocks, one whole row is copied at a time (hopefully the compiler will optimize that)
		// C++ doesn't permit copying arrays, but arrays as a part of a struct is ok :)
		typedef struct {BLOCKTYPE m_Row[16]; } ROW;
		ROW * InputRows = (ROW *)a_Type;
		ROW * OutputRows = (ROW *)m_BlockTypes;
		int InputIdx = 0;
		int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
		for (int y = 0; y < cChunkDef::Height; y++)
		{
			for (int z = 0; z < cChunkDef::Width; z++)
			{
				OutputRows[OutputIdx] = InputRows[InputIdx++];
				OutputIdx += 3;
			}  // for z
			// Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows
			// We've already walked cChunkDef::Width * 3 in the "for z" cycle, that makes cChunkDef::Width * 6 rows left to skip
			OutputIdx += cChunkDef::Width * 6;
		}  // for y
	}  // BlockTypes()
	
	
	virtual void HeightMap(const cChunkDef::HeightMap * a_Heightmap) override
	{
		typedef struct {HEIGHTTYPE m_Row[16]; } ROW;
		ROW * InputRows  = (ROW *)a_Heightmap;
		ROW * OutputRows = (ROW *)m_HeightMap;
		int InputIdx = 0;
		int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
		for (int z = 0; z < cChunkDef::Width; z++)
		{
			OutputRows[OutputIdx] = InputRows[InputIdx++];
			OutputIdx += 3;
		}  // for z
	}
	
public:
	int m_ReadingChunkX;  // 0, 1 or 2; x-offset of the chunk we're reading from the BlockTypes start
	int m_ReadingChunkZ;  // 0, 1 or 2; z-offset of the chunk we're reading from the BlockTypes start
	BLOCKTYPE * m_BlockTypes;  // 3x3 chunks of block types, organized as a single XZY blob of data (instead of 3x3 XZY blobs)
	HEIGHTTYPE * m_HeightMap;  // 3x3 chunks of height map,  organized as a single XZY blob of data (instead of 3x3 XZY blobs)
} ;





///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cLightingThread:

cLightingThread::cLightingThread(void) :
	super("cLightingThread"),
	m_World(NULL)
{
}





cLightingThread::~cLightingThread()
{
	Stop();
}





bool cLightingThread::Start(cWorld * a_World)
{
	ASSERT(m_World == NULL);  // Not started yet
	m_World = a_World;
	
	return super::Start();
}





void cLightingThread::Stop(void)
{
	{
		cCSLock Lock(m_CS);
		for (sItems::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr)
		{
			delete itr->m_ChunkStay;
		}
		m_Queue.clear();
	}
	m_ShouldTerminate = true;
	m_evtItemAdded.Set();
	
	Wait();
}





void cLightingThread::QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter)
{
	ASSERT(m_World != NULL);  // Did you call Start() properly?
	
	cChunkStay * ChunkStay = new cChunkStay(m_World);
	ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ + 1);
	ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ);
	ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ - 1);
	ChunkStay->Add(a_ChunkX,     ZERO_CHUNK_Y, a_ChunkZ + 1);
	ChunkStay->Add(a_ChunkX,     ZERO_CHUNK_Y, a_ChunkZ);
	ChunkStay->Add(a_ChunkX,     ZERO_CHUNK_Y, a_ChunkZ - 1);
	ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ + 1);
	ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ);
	ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ - 1);
	ChunkStay->Enable();
	ChunkStay->Load();
	cCSLock Lock(m_CS);
	m_Queue.push_back(sItem(a_ChunkX, a_ChunkZ, ChunkStay, a_CallbackAfter));
	if (m_Queue.size() > WARN_ON_QUEUE_SIZE)
	{
		LOGINFO("Lighting thread overloaded, %d items in queue", m_Queue.size());
	}
	m_evtItemAdded.Set();
}





void cLightingThread::WaitForQueueEmpty(void)
{
	cCSLock Lock(m_CS);
	while (!m_ShouldTerminate && (!m_Queue.empty() || !m_PostponedQueue.empty()))
	{
		cCSUnlock Unlock(Lock);
		m_evtQueueEmpty.Wait();
	}
}





size_t cLightingThread::GetQueueLength(void)
{
	cCSLock Lock(m_CS);
	return m_Queue.size() + m_PostponedQueue.size();
}





void cLightingThread::ChunkReady(int a_ChunkX, int a_ChunkZ)
{
	// Check all the items in the m_PostponedQueue, if the chunk is their neighbor, move the item to m_Queue
	
	bool NewlyAdded = false;
	{
		cCSLock Lock(m_CS);
		for (sItems::iterator itr = m_PostponedQueue.begin(); itr != m_PostponedQueue.end(); )
		{
			if (
				(itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1) &&
				(itr->z - a_ChunkZ >= -1) && (itr->z - a_ChunkZ <= 1)
			)
			{
				// It is a neighbor
				m_Queue.push_back(*itr);
				itr = m_PostponedQueue.erase(itr);
				NewlyAdded = true;
			}
			else
			{
				++itr;
			}
		}  // for itr - m_PostponedQueue[]
	}  // Lock(m_CS)
	
	if (NewlyAdded)
	{
		m_evtItemAdded.Set();  // Notify the thread it has some work to do
	}
}





void cLightingThread::Execute(void)
{
	while (true)
	{
{'fraction_non_alphanumeric': 0.14636903079966093, 'fraction_numerical': 0.010172365074879909, 'mean_word_length': 3.402155887230514, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6502435', 'n_tokens_mistral': 4336, 'n_tokens_neox': 3920, 'n_words': 1029}