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 "zlib/zlib.h"
4 #include "Protocol_1_8.h"
5 #include "Protocol_1_9.h"
6 #include "../ByteBuffer.h"
7 
8 
9 
10 
11 
13 template <class Func>
14 void ForEachSection(const cChunkData & a_Data, Func a_Func)
15 {
16  for (size_t SectionIdx = 0; SectionIdx < cChunkData::NumSections; ++SectionIdx)
17  {
18  auto Section = a_Data.GetSection(SectionIdx);
19  if (Section != nullptr)
20  {
21  a_Func(*Section);
22  }
23  }
24 }
25 
26 
27 
28 
29 
31 // cChunkDataSerializer:
32 
34  const cChunkData & a_Data,
35  const unsigned char * a_BiomeData,
36  const eDimension a_Dimension
37 ):
38  m_Data(a_Data),
39  m_BiomeData(a_BiomeData),
40  m_Dimension(a_Dimension)
41 {
42 }
43 
44 
45 
46 
47 
48 const AString & cChunkDataSerializer::Serialize(int a_Version, int a_ChunkX, int a_ChunkZ, const std::map<UInt32, UInt32> & a_BlockTypeMap)
49 {
50  Serializations::const_iterator itr = m_Serializations.find(a_Version);
51  if (itr != m_Serializations.end())
52  {
53  return itr->second;
54  }
55 
56  AString data;
57  switch (a_Version)
58  {
59  case RELEASE_1_8_0: Serialize47 (data, a_ChunkX, a_ChunkZ); break;
60  case RELEASE_1_9_0: Serialize107(data, a_ChunkX, a_ChunkZ); break;
61  case RELEASE_1_9_4: Serialize110(data, a_ChunkX, a_ChunkZ); break;
62  case RELEASE_1_13: Serialize393(data, a_ChunkX, a_ChunkZ, a_BlockTypeMap); break;
63 
64  default:
65  {
66  LOGERROR("cChunkDataSerializer::Serialize(): Unknown version: %d", a_Version);
67  ASSERT(!"Unknown chunk data serialization version");
68  break;
69  }
70  }
71  if (!data.empty())
72  {
73  m_Serializations[a_Version] = data;
74  }
75  return m_Serializations[a_Version];
76 }
77 
78 
79 
80 
81 
82 void cChunkDataSerializer::Serialize47(AString & a_Data, int a_ChunkX, int a_ChunkZ)
83 {
84  // This function returns the fully compressed packet (including packet size), not the raw packet!
85 
86  // Create the packet:
87  cByteBuffer Packet(512 KiB);
88  Packet.WriteVarInt32(0x21); // Packet id (Chunk Data packet)
89  Packet.WriteBEInt32(a_ChunkX);
90  Packet.WriteBEInt32(a_ChunkZ);
91  Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
93 
94  // Write the chunk size:
95  const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
96  UInt32 ChunkSize = (
97  m_Data.NumPresentSections() * cChunkData::SectionBlockCount * 3 + // Blocks and lighting
98  BiomeDataSize // Biome data
99  );
100  Packet.WriteVarInt32(ChunkSize);
101 
102  // Chunk written as seperate arrays of (blocktype + meta), blocklight and skylight
103  // each array stores all present sections of the same kind packed together
104 
105  // Write the block types to the packet:
106  ForEachSection(m_Data, [&](const cChunkData::sChunkSection & a_Section)
107  {
108  for (size_t BlockIdx = 0; BlockIdx != cChunkData::SectionBlockCount; ++BlockIdx)
109  {
110  BLOCKTYPE BlockType = a_Section.m_BlockTypes[BlockIdx] & 0xFF;
111  NIBBLETYPE BlockMeta = a_Section.m_BlockMetas[BlockIdx / 2] >> ((BlockIdx & 1) * 4) & 0x0f;
112  Packet.WriteBEUInt8(static_cast<unsigned char>(BlockType << 4) | BlockMeta);
113  Packet.WriteBEUInt8(static_cast<unsigned char>(BlockType >> 4));
114  }
115  }
116  );
117 
118  // Write the block lights:
119  ForEachSection(m_Data, [&](const cChunkData::sChunkSection & a_Section)
120  {
121  Packet.WriteBuf(a_Section.m_BlockLight, sizeof(a_Section.m_BlockLight));
122  }
123  );
124 
125  // Write the sky lights:
126  ForEachSection(m_Data, [&](const cChunkData::sChunkSection & a_Section)
127  {
128  Packet.WriteBuf(a_Section.m_BlockSkyLight, sizeof(a_Section.m_BlockSkyLight));
129  }
130  );
131 
132  // Write the biome data:
133  Packet.WriteBuf(m_BiomeData, BiomeDataSize);
134 
135  AString PacketData;
136  Packet.ReadAll(PacketData);
137  Packet.CommitRead();
138 
139  cByteBuffer Buffer(20);
140  if (PacketData.size() >= 256)
141  {
142  if (!cProtocol_1_8_0::CompressPacket(PacketData, a_Data))
143  {
144  ASSERT(!"Packet compression failed.");
145  a_Data.clear();
146  return;
147  }
148  }
149  else
150  {
151  AString PostData;
152  Buffer.WriteVarInt32(static_cast<UInt32>(Packet.GetUsedSpace() + 1));
153  Buffer.WriteVarInt32(0);
154  Buffer.ReadAll(PostData);
155  Buffer.CommitRead();
156 
157  a_Data.clear();
158  a_Data.reserve(PostData.size() + PacketData.size());
159  a_Data.append(PostData.data(), PostData.size());
160  a_Data.append(PacketData.data(), PacketData.size());
161  }
162 }
163 
164 
165 
166 
167 
168 void cChunkDataSerializer::Serialize107(AString & a_Data, int a_ChunkX, int a_ChunkZ)
169 {
170  // This function returns the fully compressed packet (including packet size), not the raw packet!
171 
172  // Create the packet:
173  cByteBuffer Packet(512 KiB);
174  Packet.WriteVarInt32(0x20); // Packet id (Chunk Data packet)
175  Packet.WriteBEInt32(a_ChunkX);
176  Packet.WriteBEInt32(a_ChunkZ);
177  Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
179  // Write the chunk size:
180  const size_t BitsPerEntry = 13;
181  const size_t Mask = (1 << BitsPerEntry) - 1; // Creates a mask that is 13 bits long, ie 0b1111111111111
182  const size_t ChunkSectionDataArraySize = (cChunkData::SectionBlockCount * BitsPerEntry) / 8 / 8; // Convert from bit count to long count
183  size_t ChunkSectionSize = (
184  1 + // Bits per block - set to 13, so the global palette is used and the palette has a length of 0
185  1 + // Palette length
186  2 + // Data array length VarInt - 2 bytes for the current value
187  ChunkSectionDataArraySize * 8 + // Actual block data - multiplied by 8 because first number is longs
188  cChunkData::SectionBlockCount / 2 // Block light
189  );
190 
191  if (m_Dimension == dimOverworld)
192  {
193  // Sky light is only sent in the overworld.
194  ChunkSectionSize += cChunkData::SectionBlockCount / 2;
195  }
196 
197  const size_t BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
198  size_t ChunkSize = (
199  ChunkSectionSize * m_Data.NumPresentSections() +
200  BiomeDataSize
201  );
202  Packet.WriteVarInt32(static_cast<UInt32>(ChunkSize));
203 
204  // Write each chunk section...
205  ForEachSection(m_Data, [&](const cChunkData::sChunkSection & a_Section)
206  {
207  Packet.WriteBEUInt8(static_cast<UInt8>(BitsPerEntry));
208  Packet.WriteVarInt32(0); // Palette length is 0
209  Packet.WriteVarInt32(static_cast<UInt32>(ChunkSectionDataArraySize));
210 
211  UInt64 TempLong = 0; // Temporary value that will be stored into
212  UInt64 CurrentlyWrittenIndex = 0; // "Index" of the long that would be written to
213 
214  for (size_t Index = 0; Index < cChunkData::SectionBlockCount; Index++)
215  {
216  UInt64 Value = static_cast<UInt64>(a_Section.m_BlockTypes[Index] << 4);
217  if (Index % 2 == 0)
218  {
219  Value |= a_Section.m_BlockMetas[Index / 2] & 0x0f;
220  }
221  else
222  {
223  Value |= a_Section.m_BlockMetas[Index / 2] >> 4;
224  }
225  Value &= Mask; // It shouldn't go out of bounds, but it's still worth being careful
226 
227  // Painful part where we write data into the long array. Based off of the normal code.
228  size_t BitPosition = Index * BitsPerEntry;
229  size_t FirstIndex = BitPosition / 64;
230  size_t SecondIndex = ((Index + 1) * BitsPerEntry - 1) / 64;
231  size_t BitOffset = BitPosition % 64;
232 
233  if (FirstIndex != CurrentlyWrittenIndex)
234  {
235  // Write the current data before modifiying it.
236  Packet.WriteBEUInt64(TempLong);
237  TempLong = 0;
238  CurrentlyWrittenIndex = FirstIndex;
239  }
240 
241  TempLong |= (Value << BitOffset);
242 
243  if (FirstIndex != SecondIndex)
244  {
245  // Part of the data is now in the second long; write the first one first
246  Packet.WriteBEUInt64(TempLong);
247  CurrentlyWrittenIndex = SecondIndex;
248 
249  TempLong = (Value >> (64 - BitOffset));
250  }
251  }
252  // The last long will generally not be written
253  Packet.WriteBEUInt64(TempLong);
254 
255  // Write lighting:
256  Packet.WriteBuf(a_Section.m_BlockLight, sizeof(a_Section.m_BlockLight));
257  if (m_Dimension == dimOverworld)
258  {
259  // Skylight is only sent in the overworld; the nether and end do not use it
260  Packet.WriteBuf(a_Section.m_BlockSkyLight, sizeof(a_Section.m_BlockSkyLight));
261  }
262  }
263  );
264 
265  // Write the biome data
266  Packet.WriteBuf(m_BiomeData, BiomeDataSize);
267 
268  AString PacketData;
269  Packet.ReadAll(PacketData);
270  Packet.CommitRead();
271 
272  cByteBuffer Buffer(20);
273  if (PacketData.size() >= 256)
274  {
275  if (!cProtocol_1_9_0::CompressPacket(PacketData, a_Data))
276  {
277  ASSERT(!"Packet compression failed.");
278  a_Data.clear();
279  return;
280  }
281  }
282  else
283  {
284  AString PostData;
285  Buffer.WriteVarInt32(static_cast<UInt32>(Packet.GetUsedSpace() + 1));
286  Buffer.WriteVarInt32(0);
287  Buffer.ReadAll(PostData);
288  Buffer.CommitRead();
289 
290  a_Data.clear();
291  a_Data.reserve(PostData.size() + PacketData.size());
292  a_Data.append(PostData.data(), PostData.size());
293  a_Data.append(PacketData.data(), PacketData.size());
294  }
295 }
296 
297 
298 
299 
300 
301 void cChunkDataSerializer::Serialize110(AString & a_Data, int a_ChunkX, int a_ChunkZ)
302 {
303  // This function returns the fully compressed packet (including packet size), not the raw packet!
304 
305  // Create the packet:
306  cByteBuffer Packet(512 KiB);
307  Packet.WriteVarInt32(0x20); // Packet id (Chunk Data packet)
308  Packet.WriteBEInt32(a_ChunkX);
309  Packet.WriteBEInt32(a_ChunkZ);
310  Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
312  // Write the chunk size:
313  const size_t BitsPerEntry = 13;
314  const size_t Mask = (1 << BitsPerEntry) - 1; // Creates a mask that is 13 bits long, ie 0b1111111111111
315  const size_t ChunkSectionDataArraySize = (cChunkData::SectionBlockCount * BitsPerEntry) / 8 / 8; // Convert from bit count to long count
316  size_t ChunkSectionSize = (
317  1 + // Bits per block - set to 13, so the global palette is used and the palette has a length of 0
318  1 + // Palette length
319  2 + // Data array length VarInt - 2 bytes for the current value
320  ChunkSectionDataArraySize * 8 + // Actual block data - multiplied by 8 because first number is longs
321  cChunkData::SectionBlockCount / 2 // Block light
322  );
323 
324  if (m_Dimension == dimOverworld)
325  {
326  // Sky light is only sent in the overworld.
327  ChunkSectionSize += cChunkData::SectionBlockCount / 2;
328  }
329 
330  const size_t BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
331  size_t ChunkSize = (
332  ChunkSectionSize * m_Data.NumPresentSections() +
333  BiomeDataSize
334  );
335  Packet.WriteVarInt32(static_cast<UInt32>(ChunkSize));
336 
337  // Write each chunk section...
338  ForEachSection(m_Data, [&](const cChunkData::sChunkSection & a_Section)
339  {
340  Packet.WriteBEUInt8(static_cast<UInt8>(BitsPerEntry));
341  Packet.WriteVarInt32(0); // Palette length is 0
342  Packet.WriteVarInt32(static_cast<UInt32>(ChunkSectionDataArraySize));
343 
344  UInt64 TempLong = 0; // Temporary value that will be stored into
345  UInt64 CurrentlyWrittenIndex = 0; // "Index" of the long that would be written to
346 
347  for (size_t Index = 0; Index < cChunkData::SectionBlockCount; Index++)
348  {
349  UInt64 Value = static_cast<UInt64>(a_Section.m_BlockTypes[Index] << 4);
350  if (Index % 2 == 0)
351  {
352  Value |= a_Section.m_BlockMetas[Index / 2] & 0x0f;
353  }
354  else
355  {
356  Value |= a_Section.m_BlockMetas[Index / 2] >> 4;
357  }
358  Value &= Mask; // It shouldn't go out of bounds, but it's still worth being careful
359 
360  // Painful part where we write data into the long array. Based off of the normal code.
361  size_t BitPosition = Index * BitsPerEntry;
362  size_t FirstIndex = BitPosition / 64;
363  size_t SecondIndex = ((Index + 1) * BitsPerEntry - 1) / 64;
364  size_t BitOffset = BitPosition % 64;
365 
366  if (FirstIndex != CurrentlyWrittenIndex)
367  {
368  // Write the current data before modifiying it.
369  Packet.WriteBEUInt64(TempLong);
370  TempLong = 0;
371  CurrentlyWrittenIndex = FirstIndex;
372  }
373 
374  TempLong |= (Value << BitOffset);
375 
376  if (FirstIndex != SecondIndex)
377  {
378  // Part of the data is now in the second long; write the first one first
379  Packet.WriteBEUInt64(TempLong);
380  CurrentlyWrittenIndex = SecondIndex;
381 
382  TempLong = (Value >> (64 - BitOffset));
383  }
384  }
385  // The last long will generally not be written
386  Packet.WriteBEUInt64(TempLong);
387 
388  // Write lighting:
389  Packet.WriteBuf(a_Section.m_BlockLight, sizeof(a_Section.m_BlockLight));
390  if (m_Dimension == dimOverworld)
391  {
392  // Skylight is only sent in the overworld; the nether and end do not use it
393  Packet.WriteBuf(a_Section.m_BlockSkyLight, sizeof(a_Section.m_BlockSkyLight));
394  }
395  }
396  );
397 
398  // Write the biome data
399  Packet.WriteBuf(m_BiomeData, BiomeDataSize);
400 
401  // Identify 1.9.4's tile entity list as empty
402  Packet.WriteBEUInt8(0);
403 
404  AString PacketData;
405  Packet.ReadAll(PacketData);
406  Packet.CommitRead();
407 
408  cByteBuffer Buffer(20);
409  if (PacketData.size() >= 256)
410  {
411  if (!cProtocol_1_9_0::CompressPacket(PacketData, a_Data))
412  {
413  ASSERT(!"Packet compression failed.");
414  a_Data.clear();
415  return;
416  }
417  }
418  else
419  {
420  AString PostData;
421  Buffer.WriteVarInt32(static_cast<UInt32>(Packet.GetUsedSpace() + 1));
422  Buffer.WriteVarInt32(0);
423  Buffer.ReadAll(PostData);
424  Buffer.CommitRead();
425 
426  a_Data.clear();
427  a_Data.reserve(PostData.size() + PacketData.size());
428  a_Data.append(PostData.data(), PostData.size());
429  a_Data.append(PacketData.data(), PacketData.size());
430  }
431 }
432 
433 
434 
435 
436 
437 void cChunkDataSerializer::Serialize393(AString & a_Data, int a_ChunkX, int a_ChunkZ, const std::map<UInt32, UInt32> & a_BlockTypeMap)
438 {
439  // This function returns the fully compressed packet (including packet size), not the raw packet!
440 
441  ASSERT(!a_BlockTypeMap.empty()); // We need a protocol-specific translation map
442 
443  // Create the packet:
444  cByteBuffer Packet(512 KiB);
445  Packet.WriteVarInt32(0x22); // Packet id (Chunk Data packet)
446  Packet.WriteBEInt32(a_ChunkX);
447  Packet.WriteBEInt32(a_ChunkZ);
448  Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
449  Packet.WriteVarInt32(m_Data.GetSectionBitmask());
450 
451  // Write the chunk size in bytes:
452  const size_t BitsPerEntry = 14;
453  const size_t Mask = (1 << BitsPerEntry) - 1;
454  const size_t ChunkSectionDataArraySize = (cChunkData::SectionBlockCount * BitsPerEntry) / 8 / 8;
455  size_t ChunkSectionSize = (
456  1 + // Bits per entry, BEUInt8, 1 byte
457  Packet.GetVarIntSize(static_cast<UInt32>(ChunkSectionDataArraySize)) + // Field containing "size of whole section", VarInt32, variable size
458  ChunkSectionDataArraySize * 8 + // Actual section data, lots of bytes (multiplier 1 long = 8 bytes)
459  cChunkData::SectionBlockCount / 2 // Size of blocklight which is always sent
460  );
461 
462  if (m_Dimension == dimOverworld)
463  {
464  // Sky light is only sent in the overworld.
465  ChunkSectionSize += cChunkData::SectionBlockCount / 2;
466  }
467 
468  const size_t BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
469  size_t ChunkSize = (
470  ChunkSectionSize * m_Data.NumPresentSections() +
471  BiomeDataSize * 4 // Biome data now BE ints
472  );
473  Packet.WriteVarInt32(static_cast<UInt32>(ChunkSize));
474 
475  // Write each chunk section...
476  ForEachSection(m_Data, [&](const cChunkData::sChunkSection & a_Section)
477  {
478  Packet.WriteBEUInt8(static_cast<UInt8>(BitsPerEntry));
479  Packet.WriteVarInt32(static_cast<UInt32>(ChunkSectionDataArraySize));
480 
481  UInt64 TempLong = 0; // Temporary value that will be stored into
482  UInt64 CurrentlyWrittenIndex = 0; // "Index" of the long that would be written to
483 
484  for (size_t Index = 0; Index < cChunkData::SectionBlockCount; Index++)
485  {
486  UInt32 blockType = a_Section.m_BlockTypes[Index];
487  UInt32 blockMeta = (a_Section.m_BlockMetas[Index / 2] >> ((Index % 2) * 4)) & 0x0f;
488  auto itr = a_BlockTypeMap.find(blockType * 16 | blockMeta);
489  UInt64 Value = (itr == a_BlockTypeMap.end()) ? 0 :itr->second;
490  Value &= Mask; // It shouldn't go out of bounds, but it's still worth being careful
491 
492  // Painful part where we write data into the long array. Based off of the normal code.
493  size_t BitPosition = Index * BitsPerEntry;
494  size_t FirstIndex = BitPosition / 64;
495  size_t SecondIndex = ((Index + 1) * BitsPerEntry - 1) / 64;
496  size_t BitOffset = BitPosition % 64;
497 
498  if (FirstIndex != CurrentlyWrittenIndex)
499  {
500  // Write the current data before modifiying it.
501  Packet.WriteBEUInt64(TempLong);
502  TempLong = 0;
503  CurrentlyWrittenIndex = FirstIndex;
504  }
505 
506  TempLong |= (Value << BitOffset);
507 
508  if (FirstIndex != SecondIndex)
509  {
510  // Part of the data is now in the second long; write the first one first
511  Packet.WriteBEUInt64(TempLong);
512  CurrentlyWrittenIndex = SecondIndex;
513 
514  TempLong = (Value >> (64 - BitOffset));
515  }
516  }
517  // The last long will generally not be written
518  Packet.WriteBEUInt64(TempLong);
519 
520  // Write lighting:
521  Packet.WriteBuf(a_Section.m_BlockLight, sizeof(a_Section.m_BlockLight));
522  if (m_Dimension == dimOverworld)
523  {
524  // Skylight is only sent in the overworld; the nether and end do not use it
525  Packet.WriteBuf(a_Section.m_BlockSkyLight, sizeof(a_Section.m_BlockSkyLight));
526  }
527  }
528  );
529 
530  // Write the biome data
531  for (size_t i = 0; i != BiomeDataSize; i++)
532  {
533  Packet.WriteBEUInt32(static_cast<UInt32>(m_BiomeData[i]) & 0xff);
534  }
535 
536  // Identify 1.9.4's tile entity list as empty
537  Packet.WriteVarInt32(0);
538 
539  AString PacketData;
540  Packet.ReadAll(PacketData);
541  Packet.CommitRead();
542 
543  if (PacketData.size() >= 256)
544  {
545  if (!cProtocol_1_9_0::CompressPacket(PacketData, a_Data))
546  {
547  ASSERT(!"Packet compression failed.");
548  a_Data.clear();
549  return;
550  }
551  }
552  else
553  {
554  cByteBuffer Buffer(20);
555  AString PostData;
556 
557  Buffer.WriteVarInt32(static_cast<UInt32>(Packet.GetUsedSpace() + 1));
558  Buffer.WriteVarInt32(0);
559  Buffer.ReadAll(PostData);
560  Buffer.CommitRead();
561 
562  a_Data.clear();
563  a_Data.reserve(PostData.size() + PacketData.size());
564  a_Data.append(PostData.data(), PostData.size());
565  a_Data.append(PacketData.data(), PacketData.size());
566  }
567 }
bool WriteVarInt32(UInt32 a_Value)
Definition: ByteBuffer.cpp:660
void ReadAll(AString &a_Data)
Reads all available data into a_Data.
Definition: ByteBuffer.cpp:849
eDimension
Dimension of a world.
Definition: BlockID.h:1127
void ForEachSection(const cChunkData &a_Data, Func a_Func)
Calls the given function with every present chunk section.
BLOCKTYPE m_BlockTypes[SectionBlockCount]
Definition: ChunkData.h:29
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:42
const sChunkSection * GetSection(size_t a_SectionNum) const
Return a pointer to the chunk section or nullptr if all air.
Definition: ChunkData.cpp:288
static const int Width
Definition: ChunkDef.h:134
void Serialize393(AString &a_Data, int a_ChunkX, int a_ChunkZ, const std::map< UInt32, UInt32 > &a_BlockTypeMap)
void Serialize107(AString &a_Data, int a_ChunkX, int a_ChunkZ)
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:45
void LOGERROR(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:183
void Serialize47(AString &a_Data, int a_ChunkX, int a_ChunkZ)
void CommitRead(void)
Removes the bytes that have been read from the ringbuffer.
Definition: ByteBuffer.cpp:885
bool WriteBEUInt64(UInt64 a_Value)
Definition: ByteBuffer.cpp:609
static const size_t SectionBlockCount
Definition: ChunkData.h:25
unsigned long long UInt64
Definition: Globals.h:112
#define ASSERT(x)
Definition: Globals.h:335
NIBBLETYPE m_BlockSkyLight[SectionBlockCount/2]
Definition: ChunkData.h:32
cChunkDataSerializer(const cChunkData &a_Data, const unsigned char *a_BiomeData, const eDimension a_Dimension)
An object that can store incoming bytes and lets its clients read the bytes sequentially The bytes ar...
Definition: ByteBuffer.h:29
#define KiB
Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it...
Definition: Globals.h:293
bool WriteBEUInt8(UInt8 a_Value)
Definition: ByteBuffer.cpp:530
const AString & Serialize(int a_Version, int a_ChunkX, int a_ChunkZ, const std::map< UInt32, UInt32 > &a_BlockTypeMap)
Serializes the contained chunk data into the specified protocol version.
NIBBLETYPE m_BlockMetas[SectionBlockCount/2]
Definition: ChunkData.h:30
std::string AString
Definition: StringUtils.h:13
size_t GetUsedSpace(void) const
Returns the number of bytes that are currently in the ringbuffer.
Definition: ByteBuffer.cpp:181
UInt16 GetSectionBitmask() const
Returns a bitmask of chunk sections which are currently stored.
Definition: ChunkData.cpp:302
bool WriteBEInt32(Int32 a_Value)
Definition: ByteBuffer.cpp:570
bool WriteBuf(const void *a_Buffer, size_t a_Count)
Writes a_Count bytes into a_Buffer; returns true if successful.
Definition: ByteBuffer.cpp:769
unsigned int UInt32
Definition: Globals.h:113
static bool CompressPacket(const AString &a_Packet, AString &a_Compressed)
Compress the packet.
static const size_t NumSections
Definition: ChunkData.h:24
const unsigned char * m_BiomeData
The biomes in the chunk, to be serialized.
const cChunkData & m_Data
The data read from the chunk, to be serialized.
bool WriteBool(bool a_Value)
Definition: ByteBuffer.cpp:648
void Serialize110(AString &a_Data, int a_ChunkX, int a_ChunkZ)
UInt32 NumPresentSections() const
Returns the number of sections present (i.e.
Definition: ChunkData.cpp:684
NIBBLETYPE m_BlockLight[SectionBlockCount/2]
Definition: ChunkData.h:31
Serializations m_Serializations
The per-protocol serialized data, cached for reuse for other clients.
static bool CompressPacket(const AString &a_Packet, AString &a_Compressed)
Compress the packet.
bool WriteBEUInt16(UInt16 a_Value)
Definition: ByteBuffer.cpp:557
const eDimension m_Dimension
The dimension where the chunk resides.