Cuberite
A lightweight, fast and extensible game server for Minecraft
LightingThread.h
Go to the documentation of this file.
1 
2 // LightingThread.h
3 
4 // Interfaces to the cLightingThread class representing the thread that processes requests for lighting
5 
6 /*
7 Lighting is done on whole chunks. For each chunk to be lighted, the whole 3x3 chunk area around it is read,
8 then it is processed, so that the middle chunk area has valid lighting, and the lighting is copied into the ChunkMap.
9 Lighting is calculated in full char arrays instead of nibbles, so that accessing the arrays is fast.
10 Lighting is calculated in a flood-fill fashion:
11 1. Generate seeds from where the light spreads (full skylight / light-emitting blocks)
12 2. For each seed:
13  - Spread the light 1 block in each of the 6 cardinal directions, if the blocktype allows
14  - If the recipient block has had lower lighting value than that being spread, make it a new seed
15 3. Repeat step 2, until there are no more seeds
16 The seeds need two fast operations:
17  - Check if a block at [x, y, z] is already a seed
18  - Get the next seed in the row
19 For that reason it is stored in two arrays, one stores a bool saying a seed is in that position,
20 the other is an array of seed coords, encoded as a single int.
21 Step 2 needs two separate storages for old seeds and new seeds, so there are two actual storages for that purpose,
22 their content is swapped after each full step-2-cycle.
23 
24 The thread has two queues of chunks that are to be lighted.
25 The first queue, m_Queue, is the only one that is publicly visible, chunks get queued there by external requests.
26 The second one, m_PostponedQueue, is for chunks that have been taken out of m_Queue and didn't have neighbors ready.
27 Chunks from m_PostponedQueue are moved back into m_Queue when their neighbors get valid, using the ChunkReady callback.
28 */
29 
30 
31 
32 #pragma once
33 
34 #include "OSSupport/IsThread.h"
35 #include "ChunkStay.h"
36 
37 
38 
39 
40 
41 // fwd: "cWorld.h"
42 class cWorld;
43 
44 
45 
46 
47 
49  public cIsThread
50 {
51  using Super = cIsThread;
52 
53 public:
54 
55  cLightingThread(cWorld & a_World);
56  virtual ~cLightingThread() override;
57 
58  void Stop(void);
59 
62  void QueueChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_CallbackAfter);
63 
65  void WaitForQueueEmpty(void);
66 
67  size_t GetQueueLength(void);
68 
69 protected:
70 
72  public cChunkStay
73  {
74  public:
76  int m_ChunkX;
77  int m_ChunkZ;
78  std::unique_ptr<cChunkCoordCallback> m_CallbackAfter;
79 
80  cLightingChunkStay(cLightingThread & a_LightingThread, int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_CallbackAfter);
81 
82  protected:
83  virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkZ) override
84  {
85  UNUSED(a_ChunkX);
86  UNUSED(a_ChunkZ);
87  }
88  virtual bool OnAllChunksAvailable(void) override;
89  virtual void OnDisabled(void) override;
90  } ;
91 
92  typedef std::list<cChunkStay *> cChunkStays;
93 
94 
96 
99 
102 
105 
106  cEvent m_evtItemAdded; // Set when queue is appended, or to stop the thread
107  cEvent m_evtQueueEmpty; // Set when the queue gets empty
108 
111 
112 
113  // Buffers for the 3x3 chunk data
114  // These buffers alone are 1.7 MiB in size, therefore they cannot be located on the stack safely - some architectures may have only 1 MiB for stack, or even less
115  // Placing the buffers into the object means that this object can light chunks only in one thread!
116  // The blobs are XZY organized as a whole, instead of 3x3 XZY-organized subarrays ->
117  // -> This means data has to be scatterred when reading and gathered when writing!
118  static const int BlocksPerYLayer = cChunkDef::Width * cChunkDef::Width * 3 * 3;
123 
124  // Seed management (5.7 MiB)
125  // Two buffers, in each calc step one is set as input and the other as output, then in the next step they're swapped
126  // Each seed is represented twice in this structure - both as a "list" and as a "position".
127  // "list" allows fast traversal from seed to seed
128  // "position" allows fast checking if a coord is already a seed
133  size_t m_NumSeeds;
134 
135  virtual void Execute(void) override;
136 
138  void LightChunk(cLightingChunkStay & a_Item);
139 
141  void ReadChunks(int a_ChunkX, int a_ChunkZ);
142 
144  void PrepareSkyLight(void);
145 
147  void PrepareBlockLight(void);
148 
150  void CalcLight(NIBBLETYPE * a_Light);
151 
153  void CalcLightStep(
154  NIBBLETYPE * a_Light,
155  size_t a_NumSeedsIn, unsigned char * a_IsSeedIn, unsigned int * a_SeedIdxIn,
156  size_t & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
157  );
158 
160  void CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_ChunkLight);
161 
162  void PropagateLight(
163  NIBBLETYPE * a_Light,
164  unsigned int a_SrcIdx, unsigned int a_DstIdx,
165  size_t & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
166  );
167 
170  void QueueChunkStay(cLightingChunkStay & a_ChunkStay);
171 
172 } ;
173 
174 
175 
176 
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 UNUSED
Definition: Globals.h:72
static const int Width
Definition: ChunkDef.h:124
static const int Height
Definition: ChunkDef.h:125
Makes chunks stay loaded until this object is cleared or destroyed Works by setting internal flags in...
Definition: ChunkStay.h:36
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]
std::list< cChunkStay * > cChunkStays
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.
virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkZ) override
Called when a specific chunk become available.
std::unique_ptr< cChunkCoordCallback > m_CallbackAfter
Definition: Event.h:18
cIsThread(AString &&a_ThreadName)
Definition: IsThread.cpp:16
Definition: World.h:53