Cuberite
A lightweight, fast and extensible game server for Minecraft
ChunkDataSerializer.cpp
Go to the documentation of this file.
1 #include "Globals.h"
2 #include "ChunkDataSerializer.h"
3 #include "Protocol_1_8.h"
4 #include "Protocol_1_9.h"
5 #include "../ClientHandle.h"
6 #include "../WorldStorage/FastNBT.h"
7 
8 #include "Palettes/Upgrade.h"
11 #include "Palettes/Palette_1_14.h"
12 
13 
14 
15 
16 
17 namespace
18 {
19  std::pair<UInt16, size_t> GetSectionBitmask(const ChunkBlockData & a_BlockData, const ChunkLightData & a_LightData)
20  {
21  size_t Present = 0;
22  UInt16 Mask = 0;
23 
24  ChunkDef_ForEachSection(a_BlockData, a_LightData,
25  {
26  Present++;
27  Mask |= (1 << Y);
28  });
29 
30  return { Mask, Present };
31  }
32 
33  auto PaletteLegacy(const BLOCKTYPE a_BlockType, const NIBBLETYPE a_Meta)
34  {
35  return (a_BlockType << 4) | a_Meta;
36  }
37 
38  auto Palette393(const BLOCKTYPE a_BlockType, const NIBBLETYPE a_Meta)
39  {
40  return Palette_1_13::From(PaletteUpgrade::FromBlock(a_BlockType, a_Meta));
41  }
42 
43  auto Palette401(const BLOCKTYPE a_BlockType, const NIBBLETYPE a_Meta)
44  {
45  return Palette_1_13_1::From(PaletteUpgrade::FromBlock(a_BlockType, a_Meta));
46  }
47 
48  auto Palette477(const BLOCKTYPE a_BlockType, const NIBBLETYPE a_Meta)
49  {
50  return Palette_1_14::From(PaletteUpgrade::FromBlock(a_BlockType, a_Meta));
51  }
52 }
53 
54 
55 
56 
57 
59 // cChunkDataSerializer:
60 
62  m_Packet(512 KiB),
63  m_Dimension(a_Dimension)
64 {
65 }
66 
67 
68 
69 
70 
71 void cChunkDataSerializer::SendToClients(const int a_ChunkX, const int a_ChunkZ, const ChunkBlockData & a_BlockData, const ChunkLightData & a_LightData, const unsigned char * a_BiomeMap, const ClientHandles & a_SendTo)
72 {
73  for (const auto & Client : a_SendTo)
74  {
75  switch (static_cast<cProtocol::Version>(Client->GetProtocolVersion()))
76  {
78  {
79  Serialize(Client, a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap, CacheVersion::v47);
80  continue;
81  }
85  {
86  Serialize(Client, a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap, CacheVersion::v107);
87  continue;
88  }
96  {
97  Serialize(Client, a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap, CacheVersion::v110);
98  continue;
99  }
101  {
102  Serialize(Client, a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap, CacheVersion::v393); // This version didn't last very long xD
103  continue;
104  }
107  {
108  Serialize(Client, a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap, CacheVersion::v401);
109  continue;
110  }
116  {
117  Serialize(Client, a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap, CacheVersion::v477);
118  continue;
119  }
120  }
121  UNREACHABLE("Unknown chunk data serialization version");
122  }
123 
124  // Our cache is only persistent during the function call:
125  for (auto & Cache : m_Cache)
126  {
127  Cache.Engaged = false;
128  }
129 }
130 
131 
132 
133 
134 
135 inline void cChunkDataSerializer::Serialize(const ClientHandles::value_type & a_Client, const int a_ChunkX, const int a_ChunkZ, const ChunkBlockData & a_BlockData, const ChunkLightData & a_LightData, const unsigned char * a_BiomeMap, const CacheVersion a_CacheVersion)
136 {
137  auto & Cache = m_Cache[static_cast<size_t>(a_CacheVersion)];
138  if (Cache.Engaged)
139  {
140  // Success! We've done it already, just re-use:
141  a_Client->SendChunkData(a_ChunkX, a_ChunkZ, Cache.ToSend);
142  return;
143  }
144 
145  switch (a_CacheVersion)
146  {
147  case CacheVersion::v47:
148  {
149  Serialize47(a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap);
150  break;
151  }
152  case CacheVersion::v107:
153  {
154  Serialize107(a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap);
155  break;
156  }
157  case CacheVersion::v110:
158  {
159  Serialize110(a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap);
160  break;
161  }
162  case CacheVersion::v393:
163  {
164  Serialize393<&Palette393>(a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap);
165  break;
166  }
167  case CacheVersion::v401:
168  {
169  Serialize393<&Palette401>(a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap);
170  break;
171  }
172  case CacheVersion::v477:
173  {
174  Serialize477(a_ChunkX, a_ChunkZ, a_BlockData, a_LightData, a_BiomeMap);
175  break;
176  }
177  }
178 
179  CompressPacketInto(Cache);
180  ASSERT(Cache.Engaged); // Cache must be populated now
181  a_Client->SendChunkData(a_ChunkX, a_ChunkZ, Cache.ToSend);
182 }
183 
184 
185 
186 
187 
188 inline void cChunkDataSerializer::Serialize47(const int a_ChunkX, const int a_ChunkZ, const ChunkBlockData & a_BlockData, const ChunkLightData & a_LightData, const unsigned char * a_BiomeMap)
189 {
190  // This function returns the fully compressed packet (including packet size), not the raw packet!
191 
192  const auto Bitmask = GetSectionBitmask(a_BlockData, a_LightData);
193 
194  // Create the packet:
195  m_Packet.WriteVarInt32(0x21); // Packet id (Chunk Data packet)
196  m_Packet.WriteBEInt32(a_ChunkX);
197  m_Packet.WriteBEInt32(a_ChunkZ);
198  m_Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
199 
200  // Minecraft 1.8 does not like completely empty packets
201  // Send one completely empty chunk section if this is the case
202  m_Packet.WriteBEUInt16(Bitmask.first ? Bitmask.first : 1);
203 
204  // Write the chunk size:
205  // Account for the single empty section if sending an empty chunk
206  const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
207  const size_t ChunkSize = (
208  (Bitmask.second ? Bitmask.second : 1) * (ChunkBlockData::SectionBlockCount * 2 + ChunkLightData::SectionLightCount * 2) + // Blocks and lighting
209  BiomeDataSize // Biome data
210  );
211  m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSize));
212 
213  // Chunk written as seperate arrays of (blocktype + meta), blocklight and skylight
214  // each array stores all present sections of the same kind packed together
215 
216  // Write the block types to the packet:
217  ChunkDef_ForEachSection(a_BlockData, a_LightData,
218  {
219  const bool BlocksExist = Blocks != nullptr;
220  const bool MetasExist = Metas != nullptr;
221 
222  for (size_t BlockIdx = 0; BlockIdx != ChunkBlockData::SectionBlockCount; ++BlockIdx)
223  {
224  BLOCKTYPE BlockType = BlocksExist ? (*Blocks)[BlockIdx] : 0;
225  NIBBLETYPE BlockMeta = MetasExist ? cChunkDef::ExpandNibble(Metas->data(), BlockIdx) : 0;
226  m_Packet.WriteBEUInt8(static_cast<unsigned char>(BlockType << 4) | BlockMeta);
227  m_Packet.WriteBEUInt8(static_cast<unsigned char>(BlockType >> 4));
228  }
229  });
230 
231  // Write the block lights:
232  ChunkDef_ForEachSection(a_BlockData, a_LightData,
233  {
234  if (BlockLights == nullptr)
235  {
237  }
238  else
239  {
240  m_Packet.WriteBuf(BlockLights->data(), BlockLights->size());
241  }
242  });
243 
244  // Write the sky lights:
245  ChunkDef_ForEachSection(a_BlockData, a_LightData,
246  {
247  if (SkyLights == nullptr)
248  {
250  }
251  else
252  {
253  m_Packet.WriteBuf(SkyLights->data(), SkyLights->size());
254  }
255  });
256 
257  // Serialize a single empty section if sending an empty chunk
258  if (!Bitmask.first)
259  {
260  // Block data (all air)
261  for (size_t i = 0; i < ChunkBlockData::SectionBlockCount * 2; i++)
262  {
264  }
265  // Light data (XXX: sky light is not sent if in the nether)
268  }
269 
270  // Write the biome data:
271  m_Packet.WriteBuf(a_BiomeMap, BiomeDataSize);
272 }
273 
274 
275 
276 
277 
278 inline void cChunkDataSerializer::Serialize107(const int a_ChunkX, const int a_ChunkZ, const ChunkBlockData & a_BlockData, const ChunkLightData & a_LightData, const unsigned char * a_BiomeMap)
279 {
280  // This function returns the fully compressed packet (including packet size), not the raw packet!
281  // Below variables tagged static because of https://developercommunity.visualstudio.com/content/problem/367326
282 
283  static constexpr UInt8 BitsPerEntry = 13;
284  static constexpr size_t ChunkSectionDataArraySize = (ChunkBlockData::SectionBlockCount * BitsPerEntry) / 8 / 8; // Convert from bit count to long count
285 
286  const auto Bitmask = GetSectionBitmask(a_BlockData, a_LightData);
287 
288  // Create the packet:
289  m_Packet.WriteVarInt32(0x20); // Packet id (Chunk Data packet)
290  m_Packet.WriteBEInt32(a_ChunkX);
291  m_Packet.WriteBEInt32(a_ChunkZ);
292  m_Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
293  m_Packet.WriteVarInt32(Bitmask.first);
294 
295  size_t ChunkSectionSize = (
296  1 + // Bits per block - set to 13, so the global palette is used and the palette has a length of 0
297  1 + // Palette length
298  2 + // Data array length VarInt - 2 bytes for the current value
299  ChunkSectionDataArraySize * 8 + // Actual block data - multiplied by 8 because first number is longs
300  ChunkLightData::SectionLightCount // Block light
301  );
302 
303  if (m_Dimension == dimOverworld)
304  {
305  // Sky light is only sent in the overworld.
306  ChunkSectionSize += ChunkLightData::SectionLightCount;
307  }
308 
309  const size_t BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
310  const size_t ChunkSize = (
311  ChunkSectionSize * Bitmask.second +
312  BiomeDataSize
313  );
314 
315  // Write the chunk size:
316  m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSize));
317 
318  // Write each chunk section...
319  ChunkDef_ForEachSection(a_BlockData, a_LightData,
320  {
321  m_Packet.WriteBEUInt8(BitsPerEntry);
322  m_Packet.WriteVarInt32(0); // Palette length is 0
323  m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSectionDataArraySize));
324  WriteBlockSectionSeamless<&PaletteLegacy>(Blocks, Metas, BitsPerEntry);
325  WriteLightSectionGrouped(BlockLights, SkyLights);
326  });
327 
328  // Write the biome data
329  m_Packet.WriteBuf(a_BiomeMap, BiomeDataSize);
330 }
331 
332 
333 
334 
335 
336 inline void cChunkDataSerializer::Serialize110(const int a_ChunkX, const int a_ChunkZ, const ChunkBlockData & a_BlockData, const ChunkLightData & a_LightData, const unsigned char * a_BiomeMap)
337 {
338  // This function returns the fully compressed packet (including packet size), not the raw packet!
339  // Below variables tagged static because of https://developercommunity.visualstudio.com/content/problem/367326
340 
341  static constexpr UInt8 BitsPerEntry = 13;
342  static constexpr size_t ChunkSectionDataArraySize = (ChunkBlockData::SectionBlockCount * BitsPerEntry) / 8 / 8; // Convert from bit count to long count
343 
344  const auto Bitmask = GetSectionBitmask(a_BlockData, a_LightData);
345 
346  // Create the packet:
347  m_Packet.WriteVarInt32(0x20); // Packet id (Chunk Data packet)
348  m_Packet.WriteBEInt32(a_ChunkX);
349  m_Packet.WriteBEInt32(a_ChunkZ);
350  m_Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
351  m_Packet.WriteVarInt32(Bitmask.first);
352 
353  size_t ChunkSectionSize = (
354  1 + // Bits per block - set to 13, so the global palette is used and the palette has a length of 0
355  1 + // Palette length
356  2 + // Data array length VarInt - 2 bytes for the current value
357  ChunkSectionDataArraySize * 8 + // Actual block data - multiplied by 8 because first number is longs
358  ChunkLightData::SectionLightCount // Block light
359  );
360 
361  if (m_Dimension == dimOverworld)
362  {
363  // Sky light is only sent in the overworld.
364  ChunkSectionSize += ChunkLightData::SectionLightCount;
365  }
366 
367  const size_t BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
368  const size_t ChunkSize = (
369  ChunkSectionSize * Bitmask.second +
370  BiomeDataSize
371  );
372 
373  // Write the chunk size:
374  m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSize));
375 
376  // Write each chunk section...
377  ChunkDef_ForEachSection(a_BlockData, a_LightData,
378  {
379  m_Packet.WriteBEUInt8(BitsPerEntry);
380  m_Packet.WriteVarInt32(0); // Palette length is 0
381  m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSectionDataArraySize));
382  WriteBlockSectionSeamless<&PaletteLegacy>(Blocks, Metas, BitsPerEntry);
383  WriteLightSectionGrouped(BlockLights, SkyLights);
384  });
385 
386  // Write the biome data
387  m_Packet.WriteBuf(a_BiomeMap, BiomeDataSize);
388 
389  // Identify 1.9.4's tile entity list as empty
391 }
392 
393 
394 
395 
396 
397 template <auto Palette>
398 inline void cChunkDataSerializer::Serialize393(const int a_ChunkX, const int a_ChunkZ, const ChunkBlockData & a_BlockData, const ChunkLightData & a_LightData, const unsigned char * a_BiomeMap)
399 {
400  // This function returns the fully compressed packet (including packet size), not the raw packet!
401  // Below variables tagged static because of https://developercommunity.visualstudio.com/content/problem/367326
402 
403  static constexpr UInt8 BitsPerEntry = 14;
404  static constexpr size_t ChunkSectionDataArraySize = (ChunkBlockData::SectionBlockCount * BitsPerEntry) / 8 / 8;
405 
406  const auto Bitmask = GetSectionBitmask(a_BlockData, a_LightData);
407 
408  // Create the packet:
409  m_Packet.WriteVarInt32(0x22); // Packet id (Chunk Data packet)
410  m_Packet.WriteBEInt32(a_ChunkX);
411  m_Packet.WriteBEInt32(a_ChunkZ);
412  m_Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
413  m_Packet.WriteVarInt32(Bitmask.first);
414 
415  size_t ChunkSectionSize = (
416  1 + // Bits per entry, BEUInt8, 1 byte
417  m_Packet.GetVarIntSize(static_cast<UInt32>(ChunkSectionDataArraySize)) + // Field containing "size of whole section", VarInt32, variable size
418  ChunkSectionDataArraySize * 8 + // Actual section data, lots of bytes (multiplier 1 long = 8 bytes)
419  ChunkLightData::SectionLightCount // Size of blocklight which is always sent
420  );
421 
422  if (m_Dimension == dimOverworld)
423  {
424  // Sky light is only sent in the overworld.
425  ChunkSectionSize += ChunkLightData::SectionLightCount;
426  }
427 
428  const size_t BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
429  const size_t ChunkSize = (
430  ChunkSectionSize * Bitmask.second +
431  BiomeDataSize * 4 // Biome data now BE ints
432  );
433 
434  // Write the chunk size in bytes:
435  m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSize));
436 
437  // Write each chunk section...
438  ChunkDef_ForEachSection(a_BlockData, a_LightData,
439  {
440  m_Packet.WriteBEUInt8(BitsPerEntry);
441  m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSectionDataArraySize));
442  WriteBlockSectionSeamless<Palette>(Blocks, Metas, BitsPerEntry);
443  WriteLightSectionGrouped(BlockLights, SkyLights);
444  });
445 
446  // Write the biome data
447  for (size_t i = 0; i != BiomeDataSize; i++)
448  {
449  m_Packet.WriteBEUInt32(static_cast<UInt32>(a_BiomeMap[i]));
450  }
451 
452  // Identify 1.9.4's tile entity list as empty
454 }
455 
456 
457 
458 
459 
460 inline void cChunkDataSerializer::Serialize477(const int a_ChunkX, const int a_ChunkZ, const ChunkBlockData & a_BlockData, const ChunkLightData & a_LightData, const unsigned char * a_BiomeMap)
461 {
462  // This function returns the fully compressed packet (including packet size), not the raw packet!
463  // Below variables tagged static because of https://developercommunity.visualstudio.com/content/problem/367326
464 
465  static constexpr UInt8 BitsPerEntry = 14;
466  static constexpr size_t ChunkSectionDataArraySize = (ChunkBlockData::SectionBlockCount * BitsPerEntry) / 8 / 8;
467 
468  const auto Bitmask = GetSectionBitmask(a_BlockData, a_LightData);
469 
470  // Create the packet:
471  m_Packet.WriteVarInt32(0x21); // Packet id (Chunk Data packet)
472  m_Packet.WriteBEInt32(a_ChunkX);
473  m_Packet.WriteBEInt32(a_ChunkZ);
474  m_Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
475  m_Packet.WriteVarInt32(Bitmask.first);
476 
477  {
478  cFastNBTWriter Writer;
479  // TODO: client works fine without?
480  // std::array<Int64, 36> Longz = {};
481  // Writer.AddLongArray("MOTION_BLOCKING", Longz.data(), Longz.size());
482  Writer.Finish();
483  m_Packet.Write(Writer.GetResult().data(), Writer.GetResult().size());
484  }
485 
486  const size_t ChunkSectionSize = (
487  2 + // Block count, BEInt16, 2 bytes
488  1 + // Bits per entry, BEUInt8, 1 byte
489  m_Packet.GetVarIntSize(static_cast<UInt32>(ChunkSectionDataArraySize)) + // Field containing "size of whole section", VarInt32, variable size
490  ChunkSectionDataArraySize * 8 // Actual section data, lots of bytes (multiplier 1 long = 8 bytes)
491  );
492 
493  const size_t BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
494  const size_t ChunkSize = (
495  ChunkSectionSize * Bitmask.second +
496  BiomeDataSize * 4 // Biome data now BE ints
497  );
498 
499  // Write the chunk size in bytes:
500  m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSize));
501 
502  // Write each chunk section...
503  ChunkDef_ForEachSection(a_BlockData, a_LightData,
504  {
506  m_Packet.WriteBEUInt8(BitsPerEntry);
507  m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSectionDataArraySize));
508  WriteBlockSectionSeamless<&Palette477>(Blocks, Metas, BitsPerEntry);
509  });
510 
511  // Write the biome data
512  for (size_t i = 0; i != BiomeDataSize; i++)
513  {
514  m_Packet.WriteBEUInt32(a_BiomeMap[i]);
515  }
516 
517  // Identify 1.9.4's tile entity list as empty
519 }
520 
521 
522 
523 
524 
525 template <auto Palette>
526 inline void cChunkDataSerializer::WriteBlockSectionSeamless(const ChunkBlockData::BlockArray * a_Blocks, const ChunkBlockData::MetaArray * a_Metas, const UInt8 a_BitsPerEntry)
527 {
528  // https://wiki.vg/Chunk_Format#Data_structure
529 
530  // We shift a UInt64 by a_BitsPerEntry, the latter cannot be too big:
531  ASSERT(a_BitsPerEntry < 64);
532 
533  UInt64 Buffer = 0; // A buffer to compose multiple smaller bitsizes into one 64-bit number
534  unsigned char BitIndex = 0; // The bit-position in Buffer that represents where to write next
535 
536  const bool BlocksExist = a_Blocks != nullptr;
537  const bool MetasExist = a_Metas != nullptr;
538 
539  for (size_t Index = 0; Index != ChunkBlockData::SectionBlockCount; Index++)
540  {
541  const BLOCKTYPE BlockType = BlocksExist ? (*a_Blocks)[Index] : 0;
542  const NIBBLETYPE BlockMeta = MetasExist ? cChunkDef::ExpandNibble(a_Metas->data(), Index) : 0;
543  const auto Value = Palette(BlockType, BlockMeta);
544 
545  // Write as much as possible of Value, starting from BitIndex, into Buffer:
546  Buffer |= static_cast<UInt64>(Value) << BitIndex;
547 
548  // The _signed_ count of bits in Value left to write
549  const auto Remaining = static_cast<char>(a_BitsPerEntry - (64 - BitIndex));
550  if (Remaining >= 0)
551  {
552  // There were some bits remaining: we've filled the buffer. Flush it:
553  m_Packet.WriteBEUInt64(Buffer);
554 
555  // And write the remaining bits, setting the new BitIndex:
556  Buffer = static_cast<UInt64>(Value >> (a_BitsPerEntry - Remaining));
557  BitIndex = static_cast<unsigned char>(Remaining);
558  }
559  else
560  {
561  // It fit, excellent.
562  BitIndex += a_BitsPerEntry;
563  }
564  }
565 
566  static_assert((ChunkBlockData::SectionBlockCount % 64) == 0, "Section must fit wholly into a 64-bit long array");
567  ASSERT(BitIndex == 0);
568  ASSERT(Buffer == 0);
569 }
570 
571 
572 
573 
574 
575 inline void cChunkDataSerializer::WriteLightSectionGrouped(const ChunkLightData::LightArray * const a_BlockLights, const ChunkLightData::LightArray * const a_SkyLights)
576 {
577  // Write lighting:
578  if (a_BlockLights == nullptr)
579  {
581  }
582  else
583  {
584  m_Packet.WriteBuf(a_BlockLights->data(), a_BlockLights->size());
585  }
586 
587  // Skylight is only sent in the overworld; the nether and end do not use it:
588  if (m_Dimension == dimOverworld)
589  {
590  if (a_SkyLights == nullptr)
591  {
593  }
594  else
595  {
596  m_Packet.WriteBuf(a_SkyLights->data(), a_SkyLights->size());
597  }
598  }
599 }
600 
601 
602 
603 
604 
606 {
609 
611 
612  a_Cache.Engaged = true;
613 }
#define ChunkDef_ForEachSection(BlockData, LightData, Callback)
Invokes the callback functor for every chunk section containing at least one present block or light s...
Definition: ChunkData.h:136
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
eDimension
Dimension of a world.
Definition: Defines.h:231
@ dimOverworld
Definition: Defines.h:233
#define UNREACHABLE(x)
Definition: Globals.h:288
unsigned int UInt32
Definition: Globals.h:157
unsigned char UInt8
Definition: Globals.h:159
unsigned long long UInt64
Definition: Globals.h:156
#define KiB
Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it,...
Definition: Globals.h:234
#define ASSERT(x)
Definition: Globals.h:276
unsigned short UInt16
Definition: Globals.h:158
BlockType
Definition: BlockTypes.h:4
UInt32 From(const BlockState Block)
Definition: Palette_1_13.cpp:7
UInt32 From(const BlockState Block)
UInt32 From(const BlockState Block)
Definition: Palette_1_14.cpp:8
BlockState FromBlock(const BLOCKTYPE Block, const NIBBLETYPE Meta)
Definition: Upgrade.cpp:8
void CommitRead(void)
Removes the bytes that have been read from the ringbuffer.
bool WriteBEUInt32(UInt32 a_Value)
Definition: ByteBuffer.cpp:668
bool WriteBEInt32(Int32 a_Value)
Definition: ByteBuffer.cpp:655
bool WriteBEInt16(Int16 a_Value)
Definition: ByteBuffer.cpp:627
bool WriteBEUInt64(UInt64 a_Value)
Definition: ByteBuffer.cpp:694
bool WriteBuf(const void *a_Buffer, size_t a_Count)
Writes a_Count bytes into a_Buffer; returns true if successful.
Definition: ByteBuffer.cpp:869
bool WriteBool(bool a_Value)
Definition: ByteBuffer.cpp:733
bool WriteVarInt32(UInt32 a_Value)
Definition: ByteBuffer.cpp:745
static size_t GetVarIntSize(UInt32 a_Value)
Gets the number of bytes that are needed to represent the given VarInt.
bool Write(const void *a_Bytes, size_t a_Count)
Writes the bytes specified to the ringbuffer.
Definition: ByteBuffer.cpp:111
bool WriteBEUInt16(UInt16 a_Value)
Definition: ByteBuffer.cpp:642
bool WriteBEUInt8(UInt8 a_Value)
Definition: ByteBuffer.cpp:615
decltype(m_Blocks)::Type BlockArray
Definition: ChunkData.h:75
static constexpr size_t SectionBlockCount
Definition: ChunkData.h:59
decltype(m_Metas)::Type MetaArray
Definition: ChunkData.h:76
static constexpr NIBBLETYPE DefaultSkyLightValue
Definition: ChunkData.h:104
decltype(m_BlockLights)::Type LightArray
Definition: ChunkData.h:115
static constexpr NIBBLETYPE DefaultBlockLightValue
Definition: ChunkData.h:103
static constexpr size_t SectionLightCount
Definition: ChunkData.h:101
static NIBBLETYPE ExpandNibble(const NIBBLETYPE *const a_Buffer, const size_t a_Index)
Definition: ChunkDef.h:357
static const int Width
Definition: ChunkDef.h:124
void ReadFrom(cByteBuffer &Buffer)
void WriteLightSectionGrouped(const ChunkLightData::LightArray *a_BlockLights, const ChunkLightData::LightArray *a_SkyLights)
Copies all lights in a chunk section into the packet, block light followed immediately by sky light.
void WriteBlockSectionSeamless(const ChunkBlockData::BlockArray *a_Blocks, const ChunkBlockData::MetaArray *a_Metas, UInt8 a_BitsPerEntry)
Writes all blocks in a chunk section into a series of Int64.
CircularBufferCompressor m_Compressor
A compressor used to compress the chunk data.
void Serialize47(int a_ChunkX, int a_ChunkZ, const ChunkBlockData &a_BlockData, const ChunkLightData &a_LightData, const unsigned char *a_BiomeMap)
void Serialize393(int a_ChunkX, int a_ChunkZ, const ChunkBlockData &a_BlockData, const ChunkLightData &a_LightData, const unsigned char *a_BiomeMap)
void Serialize(const ClientHandles::value_type &a_Client, int a_ChunkX, int a_ChunkZ, const ChunkBlockData &a_BlockData, const ChunkLightData &a_LightData, const unsigned char *a_BiomeMap, CacheVersion a_CacheVersion)
Serialises the given chunk, storing the result into the given cache entry, and sends the data.
cChunkDataSerializer(eDimension a_Dimension)
void Serialize110(int a_ChunkX, int a_ChunkZ, const ChunkBlockData &a_BlockData, const ChunkLightData &a_LightData, const unsigned char *a_BiomeMap)
CacheVersion
Enum to collapse protocol versions into a contiguous index.
const eDimension m_Dimension
The dimension for the World this Serializer is tied to.
std::vector< std::shared_ptr< cClientHandle > > ClientHandles
void CompressPacketInto(ChunkDataCache &a_Cache)
Finalises the data, compresses it if required, and stores it into cache.
void SendToClients(int a_ChunkX, int a_ChunkZ, const ChunkBlockData &a_BlockData, const ChunkLightData &a_LightData, const unsigned char *a_BiomeMap, const ClientHandles &a_SendTo)
For each client, serializes the chunk into their protocol version and sends it.
cByteBuffer m_Packet
A staging area used to construct the chunk packet, persistent to avoid reallocating.
void Serialize477(int a_ChunkX, int a_ChunkZ, const ChunkBlockData &a_BlockData, const ChunkLightData &a_LightData, const unsigned char *a_BiomeMap)
void Serialize107(int a_ChunkX, int a_ChunkZ, const ChunkBlockData &a_BlockData, const ChunkLightData &a_LightData, const unsigned char *a_BiomeMap)
std::array< ChunkDataCache, static_cast< size_t >CacheVersion::Last)+1 > m_Cache
A cache, mapping protocol version to a fully serialised chunk.
A single cache entry containing the raw data, compressed data, and a validity flag.
Version
The protocol version number, received from the client in the Handshake packet.
Definition: Protocol.h:335
static void CompressPacket(CircularBufferCompressor &a_Packet, ContiguousByteBuffer &a_Compressed)
Compress the packet.
void Finish(void)
Definition: FastNBT.cpp:674
ContiguousByteBufferView GetResult(void) const
Definition: FastNBT.h:351