Cuberite
A lightweight, fast and extensible game server for Minecraft
LightingThread.cpp
Go to the documentation of this file.
1 
2 // LightingThread.cpp
3 
4 // Implements the cLightingThread class representing the thread that processes requests for lighting
5 
6 #include "Globals.h"
7 #include "LightingThread.h"
8 #include "ChunkMap.h"
9 #include "World.h"
10 #include "BlockInfo.h"
11 
12 
13 
14 
15 
17 class cReader :
18  public cChunkDataCallback
19 {
20  virtual void ChunkData(const ChunkBlockData & a_BlockData, const ChunkLightData &) override
21  {
22  BLOCKTYPE * OutputRows = m_BlockTypes;
23  int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
24  for (size_t i = 0; i != cChunkDef::NumSections; ++i)
25  {
26  const auto Section = a_BlockData.GetSection(i);
27  if (Section == nullptr)
28  {
29  // Skip to the next section
30  OutputIdx += 9 * cChunkDef::SectionHeight * cChunkDef::Width;
31  continue;
32  }
33 
34  for (size_t OffsetY = 0; OffsetY != cChunkDef::SectionHeight; ++OffsetY)
35  {
36  for (size_t Z = 0; Z != cChunkDef::Width; ++Z)
37  {
38  auto InPtr = Section->data() + Z * cChunkDef::Width + OffsetY * cChunkDef::Width * cChunkDef::Width;
39  std::copy_n(InPtr, cChunkDef::Width, OutputRows + OutputIdx * cChunkDef::Width);
40 
41  OutputIdx += 3;
42  }
43  // Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows
44  // We've already walked cChunkDef::Width * 3 in the "for z" cycle, that makes cChunkDef::Width * 6 rows left to skip
45  OutputIdx += cChunkDef::Width * 6;
46  }
47  }
48  } // BlockTypes()
49 
50 
51  virtual void HeightMap(const cChunkDef::HeightMap & a_Heightmap) override
52  {
53  // Copy the entire heightmap, distribute it into the 3x3 chunk blob:
54  typedef struct {HEIGHTTYPE m_Row[16]; } ROW;
55  const ROW * InputRows = reinterpret_cast<const ROW *>(a_Heightmap);
56  ROW * OutputRows = reinterpret_cast<ROW *>(m_HeightMap);
57  int InputIdx = 0;
58  int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
59  for (int z = 0; z < cChunkDef::Width; z++)
60  {
61  OutputRows[OutputIdx] = InputRows[InputIdx++];
62  OutputIdx += 3;
63  } // for z
64 
65  // Find the highest block in the entire chunk, use it as a base for m_MaxHeight:
66  HEIGHTTYPE MaxHeight = m_MaxHeight;
67  for (size_t i = 0; i < ARRAYCOUNT(a_Heightmap); i++)
68  {
69  if (a_Heightmap[i] > MaxHeight)
70  {
71  MaxHeight = a_Heightmap[i];
72  }
73  }
74  m_MaxHeight = MaxHeight;
75  }
76 
77 public:
78  int m_ReadingChunkX; // 0, 1 or 2; x-offset of the chunk we're reading from the BlockTypes start
79  int m_ReadingChunkZ; // 0, 1 or 2; z-offset of the chunk we're reading from the BlockTypes start
80  HEIGHTTYPE m_MaxHeight; // Maximum value in this chunk's heightmap
81  BLOCKTYPE * m_BlockTypes; // 3x3 chunks of block types, organized as a single XZY blob of data (instead of 3x3 XZY blobs)
82  HEIGHTTYPE * m_HeightMap; // 3x3 chunks of height map, organized as a single XZY blob of data (instead of 3x3 XZY blobs)
83 
84  cReader(BLOCKTYPE * a_BlockTypes, HEIGHTTYPE * a_HeightMap) :
85  m_ReadingChunkX(0),
86  m_ReadingChunkZ(0),
87  m_MaxHeight(0),
88  m_BlockTypes(a_BlockTypes),
89  m_HeightMap(a_HeightMap)
90  {
92  }
93 } ;
94 
95 
96 
97 
98 
100 // cLightingThread:
101 
103  Super("Lighting Executor"),
104  m_World(a_World),
105  m_MaxHeight(0),
106  m_NumSeeds(0)
107 {
108 }
109 
110 
111 
112 
113 
115 {
116  Stop();
117 }
118 
119 
120 
121 
122 
124 {
125  {
126  cCSLock Lock(m_CS);
127  for (cChunkStays::iterator itr = m_PendingQueue.begin(), end = m_PendingQueue.end(); itr != end; ++itr)
128  {
129  (*itr)->Disable();
130  delete *itr;
131  }
132  m_PendingQueue.clear();
133  for (cChunkStays::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr)
134  {
135  (*itr)->Disable();
136  delete *itr;
137  }
138  m_Queue.clear();
139  }
140  m_ShouldTerminate = true;
142 
143  Super::Stop();
144 }
145 
146 
147 
148 
149 
150 void cLightingThread::QueueChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_CallbackAfter)
151 {
152  cChunkStay * ChunkStay = new cLightingChunkStay(*this, a_ChunkX, a_ChunkZ, std::move(a_CallbackAfter));
153  {
154  // The ChunkStay will enqueue itself using the QueueChunkStay() once it is fully loaded
155  // In the meantime, put it into the PendingQueue so that it can be removed when stopping the thread
156  cCSLock Lock(m_CS);
157  m_PendingQueue.push_back(ChunkStay);
158  }
159  ChunkStay->Enable(*m_World.GetChunkMap());
160 }
161 
162 
163 
164 
165 
167 {
168  cCSLock Lock(m_CS);
169  while (!m_ShouldTerminate && (!m_Queue.empty() || !m_PendingQueue.empty()))
170  {
171  cCSUnlock Unlock(Lock);
173  }
174 }
175 
176 
177 
178 
179 
181 {
182  cCSLock Lock(m_CS);
183  return m_Queue.size() + m_PendingQueue.size();
184 }
185 
186 
187 
188 
189 
191 {
192  for (;;)
193  {
194  {
195  cCSLock Lock(m_CS);
196  if (m_Queue.empty())
197  {
198  cCSUnlock Unlock(Lock);
200  }
201  }
202 
203  if (m_ShouldTerminate)
204  {
205  return;
206  }
207 
208  // Process one items from the queue:
210  {
211  cCSLock Lock(m_CS);
212  if (m_Queue.empty())
213  {
214  continue;
215  }
216  Item = static_cast<cLightingChunkStay *>(m_Queue.front());
217  m_Queue.pop_front();
218  if (m_Queue.empty())
219  {
221  }
222  } // CSLock(m_CS)
223 
224  LightChunk(*Item);
225  Item->Disable();
226  delete Item;
227  }
228 }
229 
230 
231 
232 
233 
235 {
236  // If the chunk is already lit, skip it (report as success):
237  if (m_World.IsChunkLighted(a_Item.m_ChunkX, a_Item.m_ChunkZ))
238  {
239  if (a_Item.m_CallbackAfter != nullptr)
240  {
241  a_Item.m_CallbackAfter->Call({a_Item.m_ChunkX, a_Item.m_ChunkZ}, true);
242  }
243  return;
244  }
245 
246  cChunkDef::BlockNibbles BlockLight, SkyLight;
247 
248  ReadChunks(a_Item.m_ChunkX, a_Item.m_ChunkZ);
249 
252 
253  PrepareSkyLight();
254 
255  /*
256  // DEBUG: Save chunk data with highlighted seeds for visual inspection:
257  cFile f4;
258  if (
259  f4.Open(fmt::format(FMT_STRING("Chunk_{}_{}_seeds.grab"), a_Item.m_ChunkX, a_Item.m_ChunkZ), cFile::fmWrite)
260  )
261  {
262  for (int z = 0; z < cChunkDef::Width * 3; z++)
263  {
264  for (int y = cChunkDef::Height / 2; y >= 0; y--)
265  {
266  unsigned char Seeds [cChunkDef::Width * 3];
267  memcpy(Seeds, m_BlockTypes + y * BlocksPerYLayer + z * cChunkDef::Width * 3, cChunkDef::Width * 3);
268  for (int x = 0; x < cChunkDef::Width * 3; x++)
269  {
270  if (m_IsSeed1[y * BlocksPerYLayer + z * cChunkDef::Width * 3 + x])
271  {
272  Seeds[x] = E_BLOCK_DIAMOND_BLOCK;
273  }
274  }
275  f4.Write(Seeds, cChunkDef::Width * 3);
276  }
277  }
278  f4.Close();
279  }
280  //*/
281 
283 
284  /*
285  // DEBUG: Save XY slices of the chunk data and lighting for visual inspection:
286  cFile f1, f2, f3;
287  if (
288  f1.Open(fmt::format(FMT_STRING("Chunk_{}_{}_data.grab"), a_Item.m_ChunkX, a_Item.m_ChunkZ), cFile::fmWrite) &&
289  f2.Open(fmt::format(FMT_STRING("Chunk_{}_{}_sky.grab"), a_Item.m_ChunkX, a_Item.m_ChunkZ), cFile::fmWrite) &&
290  f3.Open(fmt::format(FMT_STRING("Chunk_{}_{}_glow.grab"), a_Item.m_ChunkX, a_Item.m_ChunkZ), cFile::fmWrite)
291  )
292  {
293  for (int z = 0; z < cChunkDef::Width * 3; z++)
294  {
295  for (int y = cChunkDef::Height / 2; y >= 0; y--)
296  {
297  f1.Write(m_BlockTypes + y * BlocksPerYLayer + z * cChunkDef::Width * 3, cChunkDef::Width * 3);
298  unsigned char SkyLight [cChunkDef::Width * 3];
299  unsigned char BlockLight[cChunkDef::Width * 3];
300  for (int x = 0; x < cChunkDef::Width * 3; x++)
301  {
302  SkyLight[x] = m_SkyLight [y * BlocksPerYLayer + z * cChunkDef::Width * 3 + x] << 4;
303  BlockLight[x] = m_BlockLight[y * BlocksPerYLayer + z * cChunkDef::Width * 3 + x] << 4;
304  }
305  f2.Write(SkyLight, cChunkDef::Width * 3);
306  f3.Write(BlockLight, cChunkDef::Width * 3);
307  }
308  }
309  f1.Close();
310  f2.Close();
311  f3.Close();
312  }
313  //*/
314 
315  CompressLight(m_BlockLight, BlockLight);
316  CompressLight(m_SkyLight, SkyLight);
317 
318  m_World.ChunkLighted(a_Item.m_ChunkX, a_Item.m_ChunkZ, BlockLight, SkyLight);
319 
320  if (a_Item.m_CallbackAfter != nullptr)
321  {
322  a_Item.m_CallbackAfter->Call({a_Item.m_ChunkX, a_Item.m_ChunkZ}, true);
323  }
324 }
325 
326 
327 
328 
329 
330 void cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ)
331 {
333 
334  for (int z = 0; z < 3; z++)
335  {
336  Reader.m_ReadingChunkZ = z;
337  for (int x = 0; x < 3; x++)
338  {
339  Reader.m_ReadingChunkX = x;
340  VERIFY(m_World.GetChunkData({a_ChunkX + x - 1, a_ChunkZ + z - 1}, Reader));
341  } // for z
342  } // for x
343 
344  memset(m_BlockLight, 0, sizeof(m_BlockLight));
345  memset(m_SkyLight, 0, sizeof(m_SkyLight));
346  m_MaxHeight = Reader.m_MaxHeight;
347 }
348 
349 
350 
351 
352 
354 {
355  // Clear seeds:
356  memset(m_IsSeed1, 0, sizeof(m_IsSeed1));
357  m_NumSeeds = 0;
358 
359  // Fill the top of the chunk with all-light:
360  if (m_MaxHeight < cChunkDef::Height - 1)
361  {
362  std::fill(m_SkyLight + (m_MaxHeight + 1) * BlocksPerYLayer, m_SkyLight + ARRAYCOUNT(m_SkyLight), static_cast<NIBBLETYPE>(15));
363  }
364 
365  // Walk every column that has all XZ neighbors
366  for (int z = 1; z < cChunkDef::Width * 3 - 1; z++)
367  {
368  int BaseZ = z * cChunkDef::Width * 3;
369  for (int x = 1; x < cChunkDef::Width * 3 - 1; x++)
370  {
371  int idx = BaseZ + x;
372  // Find the lowest block in this column that receives full sunlight (go through transparent blocks):
373  int Current = m_HeightMap[idx];
374  ASSERT(Current < cChunkDef::Height);
375  while (
376  (Current >= 0) &&
379  )
380  {
381  Current -= 1; // Sunlight goes down unchanged through this block
382  }
383  Current += 1; // Point to the last sunlit block, rather than the first non-transparent one
384  // The other neighbors don't need transparent-block-checking. At worst we'll have a few dud seeds above the ground.
385  int Neighbor1 = m_HeightMap[idx + 1] + 1; // X + 1
386  int Neighbor2 = m_HeightMap[idx - 1] + 1; // X - 1
387  int Neighbor3 = m_HeightMap[idx + cChunkDef::Width * 3] + 1; // Z + 1
388  int Neighbor4 = m_HeightMap[idx - cChunkDef::Width * 3] + 1; // Z - 1
389  int MaxNeighbor = std::max(std::max(Neighbor1, Neighbor2), std::max(Neighbor3, Neighbor4)); // Maximum of the four neighbors
390 
391  // Fill the column from m_MaxHeight to Current with all-light:
392  for (int y = m_MaxHeight, Index = idx + y * BlocksPerYLayer; y >= Current; y--, Index -= BlocksPerYLayer)
393  {
394  m_SkyLight[Index] = 15;
395  }
396 
397  // Add Current as a seed:
398  if (Current < cChunkDef::Height)
399  {
400  int CurrentIdx = idx + Current * BlocksPerYLayer;
401  m_IsSeed1[CurrentIdx] = true;
402  m_SeedIdx1[m_NumSeeds++] = static_cast<UInt32>(CurrentIdx);
403  }
404 
405  // Add seed from Current up to the highest neighbor:
406  for (int y = Current + 1, Index = idx + y * BlocksPerYLayer; y < MaxNeighbor; y++, Index += BlocksPerYLayer)
407  {
408  m_IsSeed1[Index] = true;
409  m_SeedIdx1[m_NumSeeds++] = static_cast<UInt32>(Index);
410  }
411  }
412  }
413 }
414 
415 
416 
417 
418 
420 {
421  // Clear seeds:
422  memset(m_IsSeed1, 0, sizeof(m_IsSeed1));
423  memset(m_IsSeed2, 0, sizeof(m_IsSeed2));
424  m_NumSeeds = 0;
425 
426  // Add each emissive block into the seeds:
427  for (int Idx = 0; Idx < (m_MaxHeight * BlocksPerYLayer); ++Idx)
428  {
430  {
431  // Not a light-emissive block
432  continue;
433  }
434 
435  // Add current block as a seed:
436  m_IsSeed1[Idx] = true;
437  m_SeedIdx1[m_NumSeeds++] = static_cast<UInt32>(Idx);
438 
439  // Light it up:
441  }
442 }
443 
444 
445 
446 
447 
449 {
450  size_t NumSeeds2 = 0;
451  while (m_NumSeeds > 0)
452  {
453  // Buffer 1 -> buffer 2
454  memset(m_IsSeed2, 0, sizeof(m_IsSeed2));
455  NumSeeds2 = 0;
457  if (NumSeeds2 == 0)
458  {
459  return;
460  }
461 
462  // Buffer 2 -> buffer 1
463  memset(m_IsSeed1, 0, sizeof(m_IsSeed1));
464  m_NumSeeds = 0;
466  }
467 }
468 
469 
470 
471 
472 
474  NIBBLETYPE * a_Light,
475  size_t a_NumSeedsIn, unsigned char * a_IsSeedIn, unsigned int * a_SeedIdxIn,
476  size_t & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
477 )
478 {
479  UNUSED(a_IsSeedIn);
480  size_t NumSeedsOut = 0;
481  for (size_t i = 0; i < a_NumSeedsIn; i++)
482  {
483  UInt32 SeedIdx = static_cast<UInt32>(a_SeedIdxIn[i]);
484  int SeedX = SeedIdx % (cChunkDef::Width * 3);
485  int SeedZ = (SeedIdx / (cChunkDef::Width * 3)) % (cChunkDef::Width * 3);
486 
487  // Propagate seed:
488  if (SeedX < cChunkDef::Width * 3 - 1)
489  {
490  PropagateLight(a_Light, SeedIdx, SeedIdx + 1, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
491  }
492  if (SeedX > 0)
493  {
494  PropagateLight(a_Light, SeedIdx, SeedIdx - 1, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
495  }
496  if (SeedZ < cChunkDef::Width * 3 - 1)
497  {
498  PropagateLight(a_Light, SeedIdx, SeedIdx + cChunkDef::Width * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
499  }
500  if (SeedZ > 0)
501  {
502  PropagateLight(a_Light, SeedIdx, SeedIdx - cChunkDef::Width * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
503  }
504  if (SeedIdx < (cChunkDef::Height - 1) * BlocksPerYLayer)
505  {
506  PropagateLight(a_Light, SeedIdx, SeedIdx + BlocksPerYLayer, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
507  }
508  if (SeedIdx >= BlocksPerYLayer)
509  {
510  PropagateLight(a_Light, SeedIdx, SeedIdx - BlocksPerYLayer, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
511  }
512  } // for i - a_SeedIdxIn[]
513  a_NumSeedsOut = NumSeedsOut;
514 }
515 
516 
517 
518 
519 
520 void cLightingThread::CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_ChunkLight)
521 {
522  int InIdx = cChunkDef::Width * 49; // Index to the first nibble of the middle chunk in the a_LightArray
523  int OutIdx = 0;
524  for (int y = 0; y < cChunkDef::Height; y++)
525  {
526  for (int z = 0; z < cChunkDef::Width; z++)
527  {
528  for (int x = 0; x < cChunkDef::Width; x += 2)
529  {
530  a_ChunkLight[OutIdx++] = static_cast<NIBBLETYPE>(a_LightArray[InIdx + 1] << 4) | a_LightArray[InIdx];
531  InIdx += 2;
532  }
533  InIdx += cChunkDef::Width * 2;
534  }
535  // Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows
536  // We've already walked cChunkDef::Width * 3 in the "for z" cycle, that makes cChunkDef::Width * 6 rows left to skip
537  InIdx += cChunkDef::Width * cChunkDef::Width * 6;
538  }
539 }
540 
541 
542 
543 
544 
546  NIBBLETYPE * a_Light,
547  unsigned int a_SrcIdx, unsigned int a_DstIdx,
548  size_t & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
549 )
550 {
551  ASSERT(a_SrcIdx < ARRAYCOUNT(m_SkyLight));
552  ASSERT(a_DstIdx < ARRAYCOUNT(m_BlockTypes));
553 
554  if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + cBlockInfo::GetSpreadLightFalloff(m_BlockTypes[a_DstIdx]))
555  {
556  // We're not offering more light than the dest block already has
557  return;
558  }
559 
560  a_Light[a_DstIdx] = a_Light[a_SrcIdx] - cBlockInfo::GetSpreadLightFalloff(m_BlockTypes[a_DstIdx]);
561  if (!a_IsSeedOut[a_DstIdx])
562  {
563  a_IsSeedOut[a_DstIdx] = true;
564  a_SeedIdxOut[a_NumSeedsOut++] = a_DstIdx;
565  }
566 }
567 
568 
569 
570 
571 
573 {
574  // Move the ChunkStay from the Pending queue to the lighting queue.
575  {
576  cCSLock Lock(m_CS);
577  m_PendingQueue.remove(&a_ChunkStay);
578  m_Queue.push_back(&a_ChunkStay);
579  }
581 }
582 
583 
584 
585 
586 
588 // cLightingThread::cLightingChunkStay:
589 
590 cLightingThread::cLightingChunkStay::cLightingChunkStay(cLightingThread & a_LightingThread, int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_CallbackAfter) :
591  m_LightingThread(a_LightingThread),
592  m_ChunkX(a_ChunkX),
593  m_ChunkZ(a_ChunkZ),
594  m_CallbackAfter(std::move(a_CallbackAfter))
595 {
596  Add(a_ChunkX + 1, a_ChunkZ + 1);
597  Add(a_ChunkX + 1, a_ChunkZ);
598  Add(a_ChunkX + 1, a_ChunkZ - 1);
599  Add(a_ChunkX, a_ChunkZ + 1);
600  Add(a_ChunkX, a_ChunkZ);
601  Add(a_ChunkX, a_ChunkZ - 1);
602  Add(a_ChunkX - 1, a_ChunkZ + 1);
603  Add(a_ChunkX - 1, a_ChunkZ);
604  Add(a_ChunkX - 1, a_ChunkZ - 1);
605 }
606 
607 
608 
609 
610 
612 {
613  m_LightingThread.QueueChunkStay(*this);
614 
615  // Keep the ChunkStay alive:
616  return false;
617 }
618 
619 
620 
621 
622 
624 {
625  // Nothing needed in this callback
626 }
627 
628 
629 
630 
@ E_BLOCK_AIR
Definition: BlockType.h:10
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char HEIGHTTYPE
The type used by the heightmap.
Definition: ChunkDef.h:47
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
#define VERIFY(x)
Definition: Globals.h:280
unsigned int UInt32
Definition: Globals.h:157
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
Item
Definition: Items.h:4
Definition: FastNBT.h:132
static NIBBLETYPE GetSpreadLightFalloff(BLOCKTYPE Block)
How much light do the blocks consume?
Definition: BlockInfo.cpp:447
static NIBBLETYPE GetLightValue(BLOCKTYPE Block)
How much light do the blocks emit on their own?
Definition: BlockInfo.cpp:411
static bool IsTransparent(BLOCKTYPE Block)
Is a block transparent? (https://minecraft.wiki/w/Opacity)
Definition: BlockInfo.cpp:961
static bool IsSkylightDispersant(BLOCKTYPE Block)
Does this block disperse sky light? (only relevant for transparent blocks)
Definition: BlockInfo.cpp:864
BlockArray * GetSection(size_t a_Y) const
Definition: ChunkData.h:83
HEIGHTTYPE HeightMap[Width *Width]
The type used for any heightmap operations and storage; idx = x + Width * z; Height points to the hig...
Definition: ChunkDef.h:132
static const int Width
Definition: ChunkDef.h:124
NIBBLETYPE BlockNibbles[NumBlocks/2]
The type used for block data in nibble format, AXIS_ORDER ordering.
Definition: ChunkDef.h:143
static const size_t NumSections
Definition: ChunkDef.h:129
static const int SectionHeight
Definition: ChunkDef.h:128
static const int Height
Definition: ChunkDef.h:125
static const int NumBlocks
Definition: ChunkDef.h:126
Makes chunks stay loaded until this object is cleared or destroyed Works by setting internal flags in...
Definition: ChunkStay.h:36
void Add(int a_ChunkX, int a_ChunkZ)
Adds a chunk to be locked from unloading.
Definition: ChunkStay.cpp:42
void Enable(cChunkMap &a_ChunkMap)
Enables the ChunkStay on the specified chunkmap, causing it to load and generate chunks.
Definition: ChunkStay.cpp:80
Chunk data callback that takes the chunk data and puts them into cLightingThread's m_BlockTypes[] / m...
virtual void ChunkData(const ChunkBlockData &a_BlockData, const ChunkLightData &) override
cReader(BLOCKTYPE *a_BlockTypes, HEIGHTTYPE *a_HeightMap)
HEIGHTTYPE m_MaxHeight
virtual void HeightMap(const cChunkDef::HeightMap &a_Heightmap) override
int m_ReadingChunkX
int m_ReadingChunkZ
HEIGHTTYPE * m_HeightMap
BLOCKTYPE * m_BlockTypes
HEIGHTTYPE m_MaxHeight
The highest block in the current 3x3 chunk data.
void CalcLight(NIBBLETYPE *a_Light)
Calculates light in the light array specified, using stored seeds.
void ReadChunks(int a_ChunkX, int a_ChunkZ)
Prepares m_BlockTypes and m_HeightMap data; zeroes out the light arrays.
virtual ~cLightingThread() override
virtual void Execute(void) override
This function, overloaded by the descendants, is called in the new thread.
cChunkStays m_Queue
The ChunkStays that are loaded and are waiting to be lit.
unsigned int m_SeedIdx2[BlocksPerYLayer *cChunkDef::Height]
void PropagateLight(NIBBLETYPE *a_Light, unsigned int a_SrcIdx, unsigned int a_DstIdx, size_t &a_NumSeedsOut, unsigned char *a_IsSeedOut, unsigned int *a_SeedIdxOut)
unsigned char m_IsSeed1[BlocksPerYLayer *cChunkDef::Height]
void CalcLightStep(NIBBLETYPE *a_Light, size_t a_NumSeedsIn, unsigned char *a_IsSeedIn, unsigned int *a_SeedIdxIn, size_t &a_NumSeedsOut, unsigned char *a_IsSeedOut, unsigned int *a_SeedIdxOut)
Does one step in the light calculation - one seed propagation and seed recalculation.
unsigned int m_SeedIdx1[BlocksPerYLayer *cChunkDef::Height]
cChunkStays m_PendingQueue
The ChunkStays that are waiting for load.
void LightChunk(cLightingChunkStay &a_Item)
Lights the entire chunk.
void PrepareSkyLight(void)
Uses m_HeightMap to initialize the m_SkyLight[] data; fills in seeds for the skylight.
NIBBLETYPE m_SkyLight[BlocksPerYLayer *cChunkDef::Height]
void CompressLight(NIBBLETYPE *a_LightArray, NIBBLETYPE *a_ChunkLight)
Compresses from 1-block-per-byte (faster calc) into 2-blocks-per-byte (MC storage):
void WaitForQueueEmpty(void)
Blocks until the queue is empty or the thread is terminated.
size_t GetQueueLength(void)
void QueueChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr< cChunkCoordCallback > a_CallbackAfter)
Queues the entire chunk for lighting.
cCriticalSection m_CS
The mutex to protect m_Queue and m_PendingQueue.
NIBBLETYPE m_BlockLight[BlocksPerYLayer *cChunkDef::Height]
HEIGHTTYPE m_HeightMap[BlocksPerYLayer]
unsigned char m_IsSeed2[BlocksPerYLayer *cChunkDef::Height]
BLOCKTYPE m_BlockTypes[BlocksPerYLayer *cChunkDef::Height]
void QueueChunkStay(cLightingChunkStay &a_ChunkStay)
Queues a chunkstay that has all of its chunks loaded.
cLightingThread(cWorld &a_World)
static const int BlocksPerYLayer
void PrepareBlockLight(void)
Uses m_BlockTypes to initialize the m_BlockLight[] data; fills in seeds for the blocklight.
virtual void OnDisabled(void) override
Called by the ChunkMap when the ChunkStay is disabled.
cLightingChunkStay(cLightingThread &a_LightingThread, int a_ChunkX, int a_ChunkZ, std::unique_ptr< cChunkCoordCallback > a_CallbackAfter)
virtual bool OnAllChunksAvailable(void) override
Called once all of the contained chunks are available.
std::unique_ptr< cChunkCoordCallback > m_CallbackAfter
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
Temporary RAII unlock for a cCSLock.
void Wait(void)
Waits until the event has been set.
Definition: Event.cpp:23
void Set(void)
Sets the event - releases one thread that has been waiting in Wait().
Definition: Event.cpp:52
std::atomic< bool > m_ShouldTerminate
The overriden Execute() method should check this value periodically and terminate if this is true.
Definition: IsThread.h:45
void Stop(void)
Signals the thread to terminate and waits until it's finished.
Definition: IsThread.cpp:48
Definition: World.h:53
bool GetChunkData(cChunkCoords a_Coords, cChunkDataCallback &a_Callback) const
Calls the callback with the chunk's data, if available (with ChunkCS locked).
Definition: World.cpp:2202
void ChunkLighted(int a_ChunkX, int a_ChunkZ, const cChunkDef::BlockNibbles &a_BlockLight, const cChunkDef::BlockNibbles &a_SkyLight)
Definition: World.cpp:2189
cChunkMap * GetChunkMap(void)
Definition: World.h:852
bool IsChunkLighted(int a_ChunkX, int a_ChunkZ)
Definition: World.cpp:2685