Cuberite
A lightweight, fast and extensible game server for Minecraft
BlockArea.cpp
Go to the documentation of this file.
1 
2 // BlockArea.cpp
3 
4 // NOTE: compile.sh checks for this file in order to determine if this is the Cuberite folder.
5 // Please modify compile.sh if you want to rename or remove this file.
6 // This file was chosen arbitrarily and it's a good enough indicator we're in the Cuberite folder.
7 
8 // Implements the cBlockArea object representing an area of block data that can be queried from cWorld and then accessed again without further queries
9 // The object also supports writing the blockdata back into cWorld, even into other coords
10 
11 #include "Globals.h"
12 #include "BlockArea.h"
13 #include "OSSupport/GZipFile.h"
14 #include "Blocks/BlockHandler.h"
15 #include "ChunkData.h"
17 #include "Item.h"
18 #include "BlockInfo.h"
19 
20 
21 
22 
23 
24 // Disable MSVC warnings: "conditional expression is constant"
25 #ifdef _MSC_VER
26  #pragma warning(push)
27  #pragma warning(disable:4127)
28 #endif
29 
30 
31 
32 
33 
34 typedef void (CombinatorFunc)(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta);
35 
38 template <bool MetasValid, CombinatorFunc Combinator>
40  BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes,
41  NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas,
42  int a_SizeX, int a_SizeY, int a_SizeZ,
43  int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ,
44  int a_DstOffX, int a_DstOffY, int a_DstOffZ,
45  int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ,
46  int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ
47 )
48 {
49  UNUSED(a_SrcSizeY);
50  UNUSED(a_DstSizeY);
51  for (int y = 0; y < a_SizeY; y++)
52  {
53  int SrcBaseY = (y + a_SrcOffY) * a_SrcSizeX * a_SrcSizeZ;
54  int DstBaseY = (y + a_DstOffY) * a_DstSizeX * a_DstSizeZ;
55  for (int z = 0; z < a_SizeZ; z++)
56  {
57  int SrcBaseZ = SrcBaseY + (z + a_SrcOffZ) * a_SrcSizeX;
58  int DstBaseZ = DstBaseY + (z + a_DstOffZ) * a_DstSizeX;
59  int SrcIdx = SrcBaseZ + a_SrcOffX;
60  int DstIdx = DstBaseZ + a_DstOffX;
61  for (int x = 0; x < a_SizeX; x++)
62  {
63  if (MetasValid)
64  {
65  Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]);
66  }
67  else
68  {
69  NIBBLETYPE FakeDestMeta = 0;
70  Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], FakeDestMeta, static_cast<NIBBLETYPE>(0));
71  }
72  ++DstIdx;
73  ++SrcIdx;
74  } // for x
75  } // for z
76  } // for y
77 }
78 
79 
80 
81 
82 
84 template <bool MetaValid>
85 void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
86 {
87  a_DstType = a_SrcType;
88  if (MetaValid)
89  {
90  a_DstMeta = a_SrcMeta;
91  }
92 }
93 
94 
95 
96 
97 
99 template <bool MetaValid>
100 void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
101 {
102  if (a_DstType == E_BLOCK_AIR)
103  {
104  a_DstType = a_SrcType;
105  if (MetaValid)
106  {
107  a_DstMeta = a_SrcMeta;
108  }
109  }
110  // "else" is the default, already in place
111 }
112 
113 
114 
115 
116 
118 template <bool MetaValid>
119 void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
120 {
121  if (a_SrcType != E_BLOCK_AIR)
122  {
123  a_DstType = a_SrcType;
124  if (MetaValid)
125  {
126  a_DstMeta = a_SrcMeta;
127  }
128  }
129  // "else" is the default, already in place
130 }
131 
132 
133 
134 
135 
137 template <bool MetaValid>
138 void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
139 {
140  // Sponge is the NOP block
141  if (a_SrcType == E_BLOCK_SPONGE)
142  {
143  return;
144  }
145 
146  // Air is always hollowed out
147  if (a_SrcType == E_BLOCK_AIR)
148  {
149  a_DstType = E_BLOCK_AIR;
150  if (MetaValid)
151  {
152  a_DstMeta = 0;
153  }
154  return;
155  }
156 
157  // Water and lava are never overwritten
158  switch (a_DstType)
159  {
160  case E_BLOCK_WATER:
162  case E_BLOCK_LAVA:
164  {
165  return;
166  }
167  }
168 
169  // Water and lava always overwrite
170  switch (a_SrcType)
171  {
172  case E_BLOCK_WATER:
174  case E_BLOCK_LAVA:
176  {
177  a_DstType = a_SrcType;
178  if (MetaValid)
179  {
180  a_DstMeta = a_SrcMeta;
181  }
182  return;
183  }
184  }
185 
186  if (a_SrcType == E_BLOCK_STONE)
187  {
188  switch (a_DstType)
189  {
190  case E_BLOCK_DIRT:
191  case E_BLOCK_GRASS:
192  case E_BLOCK_MYCELIUM:
193  {
194  a_DstType = E_BLOCK_STONE;
195  if (MetaValid)
196  {
197  a_DstMeta = 0;
198  }
199  return;
200  }
201  }
202  }
203  // Everything else is left as it is
204 }
205 
206 
207 
208 
209 
211 template <bool MetaValid>
212 void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
213 {
214  // Sponge overwrites nothing, everything else overwrites anything
215  if (a_SrcType != E_BLOCK_SPONGE)
216  {
217  a_DstType = a_SrcType;
218  if (MetaValid)
219  {
220  a_DstMeta = a_SrcMeta;
221  }
222  }
223 }
224 
225 
226 
227 
228 
230 template <bool MetaValid>
231 void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
232 {
233  if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta)))
234  {
235  a_DstType = E_BLOCK_AIR;
236  if (MetaValid)
237  {
238  a_DstMeta = 0;
239  }
240  }
241  else
242  {
243  a_DstType = a_SrcType;
244  if (MetaValid)
245  {
246  a_DstMeta = a_SrcMeta;
247  }
248  }
249 }
250 
251 
252 
253 
254 
256 template <bool MetaValid>
257 void MergeCombinatorSimpleCompare(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
258 {
259  if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta)))
260  {
261  // The blocktypes are the same, and the blockmetas are not present or are the same
262  a_DstType = E_BLOCK_AIR;
263  }
264  else
265  {
266  // The blocktypes or blockmetas differ
267  a_DstType = E_BLOCK_STONE;
268  }
269 }
270 
271 
272 
273 
274 
276 template <bool MetaValid>
277 void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
278 {
279  // If the blocks are the same, keep the dest; otherwise replace with air
280  if ((a_SrcType != a_DstType) || !MetaValid || (a_SrcMeta != a_DstMeta))
281  {
282  a_DstType = E_BLOCK_AIR;
283  if (MetaValid)
284  {
285  a_DstMeta = 0;
286  }
287  }
288 }
289 
290 // Re-enable previously disabled MSVC warnings
291 #ifdef _MSC_VER
292  #pragma warning(pop)
293 #endif
294 
295 
296 
297 
298 
300 // cBlockArea:
301 
302 cBlockArea::cBlockArea(void) = default;
303 
305 {
306  // BlockEntities require that BlockTypes be present, too
307  if ((a_DataTypes & baBlockEntities) != 0)
308  {
309  if ((a_DataTypes & baTypes) == 0)
310  {
311  return false;
312  }
313  }
314 
315  // All other combinations are considered valid
316  return true;
317 }
318 
319 
320 
321 
322 
324 {
325  m_BlockTypes.reset();
326  m_BlockMetas.reset();
327  m_BlockLight.reset();
328  m_BlockSkyLight.reset();
329  m_BlockEntities.reset();
330  m_Origin.Set(0, 0, 0);
331  m_Size.Set(0, 0, 0);
332 }
333 
334 
335 
336 
337 
338 void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
339 {
340  ASSERT(a_SizeX > 0);
341  ASSERT(a_SizeY > 0);
342  ASSERT(a_SizeZ > 0);
343  ASSERT(IsValidDataTypeCombination(a_DataTypes));
344 
345  // Warn if the height is too much, but proceed with the creation:
346  if (a_SizeY > cChunkDef::Height)
347  {
348  LOGWARNING("Creating a cBlockArea with height larger than world height (%d). Continuing, but the area may misbehave.", a_SizeY);
349  }
350 
351  Clear();
352  SetSize(a_SizeX, a_SizeY, a_SizeZ, a_DataTypes);
353  Fill(a_DataTypes, E_BLOCK_AIR);
354 }
355 
356 
357 
358 
359 
360 void cBlockArea::Create(const Vector3i & a_Size, int a_DataTypes)
361 {
362  Create(a_Size.x, a_Size.y, a_Size.z, a_DataTypes);
363 }
364 
365 
366 
367 
368 
369 void cBlockArea::SetWEOffset(int a_OffsetX, int a_OffsetY, int a_OffsetZ)
370 {
371  m_WEOffset.Set(a_OffsetX, a_OffsetY, a_OffsetZ);
372 }
373 
374 
375 
376 
377 
378 void cBlockArea::SetWEOffset(const Vector3i & a_Offset)
379 {
380  m_WEOffset.Set(a_Offset.x, a_Offset.y, a_Offset.z);
381 }
382 
383 
384 
385 
386 
387 void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
388 {
389  m_Origin.Set(a_OriginX, a_OriginY, a_OriginZ);
390 }
391 
392 
393 
394 
395 
396 void cBlockArea::SetOrigin(const Vector3i & a_Origin)
397 {
398  m_Origin.Set(a_Origin.x, a_Origin.y, a_Origin.z);
399 }
400 
401 
402 
403 
404 
405 bool cBlockArea::IsValidRelCoords(int a_RelX, int a_RelY, int a_RelZ) const
406 {
407  return (
408  (a_RelX >= 0) && (a_RelX < m_Size.x) &&
409  (a_RelY >= 0) && (a_RelY < m_Size.y) &&
410  (a_RelZ >= 0) && (a_RelZ < m_Size.z)
411  );
412 }
413 
414 
415 
416 
417 
418 bool cBlockArea::IsValidRelCoords(const Vector3i & a_RelCoords) const
419 {
420  return IsValidRelCoords(a_RelCoords.x, a_RelCoords.y, a_RelCoords.z);
421 }
422 
423 
424 
425 
426 
427 bool cBlockArea::IsValidCoords(int a_BlockX, int a_BlockY, int a_BlockZ) const
428 {
429  return IsValidRelCoords(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z);
430 }
431 
432 
433 
434 
435 
436 bool cBlockArea::IsValidCoords(const Vector3i & a_Coords) const
437 {
438  return IsValidRelCoords(a_Coords - m_Origin);
439 }
440 
441 
442 
443 
444 
445 bool cBlockArea::Read(cForEachChunkProvider & a_ForEachChunkProvider, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes)
446 {
447  ASSERT(IsValidDataTypeCombination(a_DataTypes));
448  ASSERT(cChunkDef::IsValidHeight({a_MinBlockX, a_MinBlockY, a_MinBlockZ}));
449  ASSERT(cChunkDef::IsValidHeight({a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ}));
450  ASSERT(a_MinBlockX <= a_MaxBlockX);
451  ASSERT(a_MinBlockY <= a_MaxBlockY);
452  ASSERT(a_MinBlockZ <= a_MaxBlockZ);
453 
454  // Include the Max coords:
455  a_MaxBlockX += 1;
456  a_MaxBlockY += 1;
457  a_MaxBlockZ += 1;
458 
459  // Allocate the needed memory:
460  Clear();
461  if (!SetSize(a_MaxBlockX - a_MinBlockX, a_MaxBlockY - a_MinBlockY, a_MaxBlockZ - a_MinBlockZ, a_DataTypes))
462  {
463  return false;
464  }
465  m_Origin.Set(a_MinBlockX, a_MinBlockY, a_MinBlockZ);
466  cChunkReader Reader(*this);
467 
468  // Convert block coords to chunks coords:
469  int MinChunkX, MaxChunkX;
470  int MinChunkZ, MaxChunkZ;
471  cChunkDef::AbsoluteToRelative(a_MinBlockX, a_MinBlockY, a_MinBlockZ, MinChunkX, MinChunkZ);
472  cChunkDef::AbsoluteToRelative(a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ, MaxChunkX, MaxChunkZ);
473 
474  // Query block data:
475  if (!a_ForEachChunkProvider.ForEachChunkInRect(MinChunkX, MaxChunkX, MinChunkZ, MaxChunkZ, Reader))
476  {
477  Clear();
478  return false;
479  }
480 
481  return true;
482 }
483 
484 
485 
486 
487 
488 bool cBlockArea::Read(cForEachChunkProvider & a_ForEachChunkProvider, const cCuboid & a_Bounds, int a_DataTypes)
489 {
490  return Read(
491  a_ForEachChunkProvider,
492  a_Bounds.p1.x, a_Bounds.p2.x,
493  a_Bounds.p1.y, a_Bounds.p2.y,
494  a_Bounds.p1.z, a_Bounds.p2.z,
495  a_DataTypes
496  );
497 }
498 
499 
500 
501 
502 
503 bool cBlockArea::Read(cForEachChunkProvider & a_ForEachChunkProvider, const Vector3i & a_Point1, const Vector3i & a_Point2, int a_DataTypes)
504 {
505  return Read(
506  a_ForEachChunkProvider,
507  a_Point1.x, a_Point2.x,
508  a_Point1.y, a_Point2.y,
509  a_Point1.z, a_Point2.z,
510  a_DataTypes
511  );
512 }
513 
514 
515 
516 
517 
518 bool cBlockArea::Write(cForEachChunkProvider & a_ForEachChunkProvider, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes)
519 {
520  ASSERT((a_DataTypes & GetDataTypes()) == a_DataTypes); // Are you requesting only the data that I have?
521  ASSERT(cChunkDef::IsValidHeight({a_MinBlockX, a_MinBlockY, a_MinBlockZ}));
522  ASSERT(cChunkDef::IsValidHeight({a_MinBlockX, a_MinBlockY + m_Size.y - 1, a_MinBlockZ}));
523 
524  return a_ForEachChunkProvider.WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
525 }
526 
527 
528 
529 
530 
531 bool cBlockArea::Write(cForEachChunkProvider & a_ForEachChunkProvider, const Vector3i & a_MinCoords, int a_DataTypes)
532 {
533  return Write(
534  a_ForEachChunkProvider,
535  a_MinCoords.x, a_MinCoords.y, a_MinCoords.z,
536  a_DataTypes
537  );
538 }
539 
540 
541 
542 
543 
544 void cBlockArea::CopyTo(cBlockArea & a_Into) const
545 {
546  if (&a_Into == this)
547  {
548  LOGWARNING("Trying to copy a cBlockArea into self, ignoring.");
549  return;
550  }
551 
552  a_Into.Clear();
553  a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
554  a_Into.m_Origin = m_Origin;
555  size_t BlockCount = GetBlockCount();
556  if (HasBlockTypes())
557  {
558  memcpy(a_Into.GetBlockTypes(), GetBlockTypes(), BlockCount * sizeof(BLOCKTYPE));
559  }
560  if (HasBlockMetas())
561  {
562  memcpy(a_Into.GetBlockMetas(), GetBlockMetas(), BlockCount * sizeof(NIBBLETYPE));
563  }
564  if (HasBlockLights())
565  {
566  memcpy(a_Into.GetBlockLight(), GetBlockLight(), BlockCount * sizeof(NIBBLETYPE));
567  }
568  if (HasBlockSkyLights())
569  {
570  memcpy(a_Into.GetBlockSkyLight(), GetBlockSkyLight(), BlockCount * sizeof(NIBBLETYPE));
571  }
572  if (HasBlockEntities())
573  {
574  a_Into.m_BlockEntities->clear();
575  for (const auto & keyPair: *m_BlockEntities)
576  {
577  const auto & pos = keyPair.second->GetPos();
578  a_Into.m_BlockEntities->emplace(keyPair.first, keyPair.second->Clone(pos));
579  }
580  }
581 }
582 
583 
584 
585 
586 
587 void cBlockArea::CopyFrom(const cBlockArea & a_From)
588 {
589  a_From.CopyTo(*this);
590 }
591 
592 
593 
594 
595 
596 void cBlockArea::DumpToRawFile(const AString & a_FileName)
597 {
598  cFile f;
599  if (!f.Open(a_FileName, cFile::fmWrite))
600  {
601  LOGWARNING("cBlockArea: Cannot open file \"%s\" for raw dump", a_FileName.c_str());
602  return;
603  }
604  UInt32 SizeX = ntohl(static_cast<UInt32>(m_Size.x));
605  UInt32 SizeY = ntohl(static_cast<UInt32>(m_Size.y));
606  UInt32 SizeZ = ntohl(static_cast<UInt32>(m_Size.z));
607  f.Write(&SizeX, 4);
608  f.Write(&SizeY, 4);
609  f.Write(&SizeZ, 4);
610  unsigned char DataTypes = static_cast<unsigned char>(GetDataTypes());
611  f.Write(&DataTypes, 1);
612  size_t NumBlocks = GetBlockCount();
613  if (HasBlockTypes())
614  {
615  f.Write(GetBlockTypes(), NumBlocks * sizeof(BLOCKTYPE));
616  }
617  if (HasBlockMetas())
618  {
619  f.Write(GetBlockMetas(), NumBlocks);
620  }
621  if (HasBlockLights())
622  {
623  f.Write(GetBlockLight(), NumBlocks);
624  }
625  if (HasBlockSkyLights())
626  {
627  f.Write(GetBlockSkyLight(), NumBlocks);
628  }
629 }
630 
631 
632 
633 
634 
635 void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ)
636 {
637  if (
638  (a_AddMinX + a_SubMaxX >= m_Size.x) ||
639  (a_AddMinY + a_SubMaxY >= m_Size.y) ||
640  (a_AddMinZ + a_SubMaxZ >= m_Size.z)
641  )
642  {
643  LOGWARNING("cBlockArea:Crop called with more croping than the dimensions: %d x %d x %d with cropping %d, %d and %d",
644  m_Size.x, m_Size.y, m_Size.z,
645  a_AddMinX + a_SubMaxX, a_AddMinY + a_SubMaxY, a_AddMinZ + a_SubMaxZ
646  );
647  return;
648  }
649 
650  if (HasBlockTypes())
651  {
652  CropBlockTypes(a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ);
653  }
654  if (HasBlockMetas())
655  {
656  CropNibbles(m_BlockMetas, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ);
657  }
658  if (HasBlockLights())
659  {
660  CropNibbles(m_BlockLight, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ);
661  }
662  if (HasBlockSkyLights())
663  {
664  CropNibbles(m_BlockSkyLight, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ);
665  }
666  if (HasBlockEntities())
667  {
668  const Vector3i AddMin{ a_AddMinX, a_AddMinY, a_AddMinZ };
669  const cCuboid CropBox{ AddMin, m_Size - Vector3i{a_SubMaxX, a_SubMaxY, a_SubMaxZ} };
670 
671  // Move and crop block Entities:
672  cBlockEntities oldBE;
673  std::swap(oldBE, *m_BlockEntities);
674  for (auto & keyPair: oldBE)
675  {
676  auto & be = keyPair.second;
677  auto Pos = be->GetPos();
678  if (CropBox.IsInside(Pos))
679  {
680  // The block entity is within the new coords, recalculate its coords to match the new area:
681  Pos -= AddMin;
682  be->SetPos(Pos);
683  m_BlockEntities->emplace(MakeIndex(Pos.x, Pos.y, Pos.z), std::move(be));
684  }
685  }
686  }
687 
688  m_Origin.Move(a_AddMinX, a_AddMinY, a_AddMinZ);
689  m_Size.x -= a_AddMinX + a_SubMaxX;
690  m_Size.y -= a_AddMinY + a_SubMaxY;
691  m_Size.z -= a_AddMinZ + a_SubMaxZ;
692 }
693 
694 
695 
696 
697 
698 void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
699 {
700  if (HasBlockTypes())
701  {
702  ExpandBlockTypes(a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ);
703  }
704  if (HasBlockMetas())
705  {
706  ExpandNibbles(m_BlockMetas, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ);
707  }
708  if (HasBlockLights())
709  {
710  ExpandNibbles(m_BlockLight, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ);
711  }
712  if (HasBlockSkyLights())
713  {
714  ExpandNibbles(m_BlockSkyLight, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ);
715  }
716  if (HasBlockEntities())
717  {
718  // Move block entities:
719  cBlockEntities oldBE;
720  std::swap(oldBE, *m_BlockEntities);
721  for (auto & keyPair: oldBE)
722  {
723  auto & be = keyPair.second;
724  auto posX = be->GetPosX() + a_SubMinX;
725  auto posY = be->GetPosY() + a_SubMinY;
726  auto posZ = be->GetPosZ() + a_SubMinZ;
727  be->SetPos({posX, posY, posZ});
728  m_BlockEntities->emplace(MakeIndex(posX, posY, posZ), std::move(be));
729  }
730  }
731 
732  m_Origin.Move(-a_SubMinX, -a_SubMinY, -a_SubMinZ);
733  m_Size.x += a_SubMinX + a_AddMaxX;
734  m_Size.y += a_SubMinY + a_AddMaxY;
735  m_Size.z += a_SubMinZ + a_AddMaxZ;
736 }
737 
738 
739 
740 
741 
742 void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy)
743 {
744 
745  const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas();
746  NIBBLETYPE * DstMetas = GetBlockMetas();
747 
748  bool IsDummyMetas = ((SrcMetas == nullptr) || (DstMetas == nullptr));
749 
750  if (IsDummyMetas)
751  {
752  MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
753  }
754  else
755  {
756  MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
757  }
758 }
759 
760 
761 
762 
763 
764 void cBlockArea::Merge(const cBlockArea & a_Src, const Vector3i & a_RelMinCoords, eMergeStrategy a_Strategy)
765 {
766  Merge(a_Src, a_RelMinCoords.x, a_RelMinCoords.y, a_RelMinCoords.z, a_Strategy);
767 }
768 
769 
770 
771 
772 
773 void cBlockArea::Fill(int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight)
774 {
775  if ((a_DataTypes & GetDataTypes()) != a_DataTypes)
776  {
777  LOGWARNING("%s: requested datatypes that are not present in the BlockArea object, trimming those away (req 0x%x, stor 0x%x)",
778  __FUNCTION__, a_DataTypes, GetDataTypes()
779  );
780  a_DataTypes = a_DataTypes & GetDataTypes();
781  }
782 
783  size_t BlockCount = GetBlockCount();
784  if ((a_DataTypes & baTypes) != 0)
785  {
786  for (size_t i = 0; i < BlockCount; i++)
787  {
788  m_BlockTypes[i] = a_BlockType;
789  }
790  }
791  if ((a_DataTypes & baMetas) != 0)
792  {
793  for (size_t i = 0; i < BlockCount; i++)
794  {
795  m_BlockMetas[i] = a_BlockMeta;
796  }
797  }
798  if ((a_DataTypes & baLight) != 0)
799  {
800  for (size_t i = 0; i < BlockCount; i++)
801  {
802  m_BlockLight[i] = a_BlockLight;
803  }
804  }
805  if ((a_DataTypes & baSkyLight) != 0)
806  {
807  for (size_t i = 0; i < BlockCount; i++)
808  {
809  m_BlockSkyLight[i] = a_BlockSkyLight;
810  }
811  }
812 
813  // If the area contains block entities, remove those not matching and replace with whatever block entity block was filled
814  if (HasBlockEntities() && ((a_DataTypes & baTypes) != 0))
815  {
816  if (cBlockEntity::IsBlockEntityBlockType(a_BlockType))
817  {
819  }
820  else
821  {
822  m_BlockEntities->clear();
823  }
824  }
825 }
826 
827 
828 
829 
830 
831 void cBlockArea::FillRelCuboid(int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ,
832  int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
833  NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
834 )
835 {
836  if ((a_DataTypes & GetDataTypes()) != a_DataTypes)
837  {
838  LOGWARNING("%s: requested datatypes that are not present in the BlockArea object, trimming those away (req 0x%x, stor 0x%x)",
839  __FUNCTION__, a_DataTypes, GetDataTypes()
840  );
841  a_DataTypes = a_DataTypes & GetDataTypes();
842  }
843 
844  if ((a_DataTypes & baTypes) != 0)
845  {
846  for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++)
847  {
848  m_BlockTypes[MakeIndex(x, y, z)] = a_BlockType;
849  } // for x, z, y
850  }
851  if ((a_DataTypes & baMetas) != 0)
852  {
853  for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++)
854  {
855  m_BlockMetas[MakeIndex(x, y, z)] = a_BlockMeta;
856  } // for x, z, y
857  }
858  if ((a_DataTypes & baLight) != 0)
859  {
860  for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++)
861  {
862  m_BlockLight[MakeIndex(x, y, z)] = a_BlockLight;
863  } // for x, z, y
864  }
865  if ((a_DataTypes & baSkyLight) != 0)
866  {
867  for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++)
868  {
869  m_BlockSkyLight[MakeIndex(x, y, z)] = a_BlockSkyLight;
870  } // for x, z, y
871  }
872 
873  // If the area contains block entities, remove those in the affected cuboid and replace with whatever block entity block was filled:
874  if (HasBlockEntities() && ((a_DataTypes & baTypes) != 0))
875  {
876  if (cBlockEntity::IsBlockEntityBlockType(a_BlockType))
877  {
879  }
880  else
881  {
882  m_BlockEntities->clear();
883  }
884  }
885 }
886 
887 
888 
889 
890 
891 void cBlockArea::FillRelCuboid(const cCuboid & a_RelCuboid,
892  int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
893  NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
894 )
895 {
897  a_RelCuboid.p1.x, a_RelCuboid.p2.x,
898  a_RelCuboid.p1.y, a_RelCuboid.p2.y,
899  a_RelCuboid.p1.z, a_RelCuboid.p2.z,
900  a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight
901  );
902 }
903 
904 
905 
906 
907 
908 void cBlockArea::RelLine(int a_RelX1, int a_RelY1, int a_RelZ1, int a_RelX2, int a_RelY2, int a_RelZ2,
909  int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
910  NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
911 )
912 {
913  // Bresenham-3D algorithm for drawing lines:
914  int dx = abs(a_RelX2 - a_RelX1);
915  int dy = abs(a_RelY2 - a_RelY1);
916  int dz = abs(a_RelZ2 - a_RelZ1);
917  int sx = (a_RelX1 < a_RelX2) ? 1 : -1;
918  int sy = (a_RelY1 < a_RelY2) ? 1 : -1;
919  int sz = (a_RelZ1 < a_RelZ2) ? 1 : -1;
920 
921  if (dx >= std::max(dy, dz)) // x dominant
922  {
923  int yd = dy - dx / 2;
924  int zd = dz - dx / 2;
925 
926  for (;;)
927  {
928  RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight);
929 
930  if (a_RelX1 == a_RelX2)
931  {
932  break;
933  }
934 
935  if (yd >= 0) // move along y
936  {
937  a_RelY1 += sy;
938  yd -= dx;
939  }
940 
941  if (zd >= 0) // move along z
942  {
943  a_RelZ1 += sz;
944  zd -= dx;
945  }
946 
947  // move along x
948  a_RelX1 += sx;
949  yd += dy;
950  zd += dz;
951  }
952  }
953  else if (dy >= std::max(dx, dz)) // y dominant
954  {
955  int xd = dx - dy / 2;
956  int zd = dz - dy / 2;
957 
958  for (;;)
959  {
960  RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight);
961 
962  if (a_RelY1 == a_RelY2)
963  {
964  break;
965  }
966 
967  if (xd >= 0) // move along x
968  {
969  a_RelX1 += sx;
970  xd -= dy;
971  }
972 
973  if (zd >= 0) // move along z
974  {
975  a_RelZ1 += sz;
976  zd -= dy;
977  }
978 
979  // move along y
980  a_RelY1 += sy;
981  xd += dx;
982  zd += dz;
983  }
984  }
985  else
986  {
987  // z dominant
988  ASSERT(dz >= std::max(dx, dy));
989  int xd = dx - dz / 2;
990  int yd = dy - dz / 2;
991 
992  for (;;)
993  {
994  RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight);
995 
996  if (a_RelZ1 == a_RelZ2)
997  {
998  break;
999  }
1000 
1001  if (xd >= 0) // move along x
1002  {
1003  a_RelX1 += sx;
1004  xd -= dz;
1005  }
1006 
1007  if (yd >= 0) // move along y
1008  {
1009  a_RelY1 += sy;
1010  yd -= dz;
1011  }
1012 
1013  // move along z
1014  a_RelZ1 += sz;
1015  xd += dx;
1016  yd += dy;
1017  }
1018  } // if (which dimension is dominant)
1019 }
1020 
1021 
1022 
1023 
1024 
1025 void cBlockArea::RelLine(const Vector3i & a_Point1, const Vector3i & a_Point2,
1026  int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
1027  NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
1028 )
1029 {
1030  RelLine(
1031  a_Point1.x, a_Point1.y, a_Point1.z,
1032  a_Point2.x, a_Point2.y, a_Point2.z,
1033  a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight
1034  );
1035 }
1036 
1037 
1038 
1039 
1040 
1042 {
1043  if (!HasBlockTypes())
1044  {
1045  LOGWARNING("cBlockArea: Cannot rotate blockmeta without blocktypes!");
1046  return;
1047  }
1048 
1049  if (!HasBlockMetas())
1050  {
1051  // There are no blockmetas to rotate, just use the NoMeta function
1052  RotateCCWNoMeta();
1053  return;
1054  }
1055 
1056  // We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time:
1057  BLOCKARRAY NewTypes{ new BLOCKTYPE[GetBlockCount()] };
1058  NIBBLEARRAY NewMetas{ new NIBBLETYPE[GetBlockCount()] };
1059  for (int x = 0; x < m_Size.x; x++)
1060  {
1061  int NewZ = m_Size.x - x - 1;
1062  for (int z = 0; z < m_Size.z; z++)
1063  {
1064  int NewX = z;
1065  for (int y = 0; y < m_Size.y; y++)
1066  {
1067  auto NewIdx = MakeIndexForSize({ NewX, y, NewZ }, { m_Size.z, m_Size.y, m_Size.x });
1068  auto OldIdx = MakeIndex(x, y, z);
1069  NewTypes[NewIdx] = m_BlockTypes[OldIdx];
1070  NewMetas[NewIdx] = cBlockHandler::For(m_BlockTypes[OldIdx]).MetaRotateCCW(m_BlockMetas[OldIdx]);
1071  } // for y
1072  } // for z
1073  } // for x
1074  m_BlockTypes = std::move(NewTypes);
1075  m_BlockMetas = std::move(NewMetas);
1076 
1077  // Rotate the BlockEntities:
1078  if (HasBlockEntities())
1079  {
1080  cBlockEntities oldBE;
1081  std::swap(oldBE, *m_BlockEntities);
1082  for (auto & keyPair: oldBE)
1083  {
1084  auto & be = keyPair.second;
1085  auto newX = be->GetPosZ();
1086  auto newY = be->GetPosY();
1087  auto newZ = m_Size.x - be->GetPosX() - 1;
1088  auto newIdx = newX + newZ * m_Size.z + newY * m_Size.x * m_Size.z;
1089  be->SetPos({newX, newY, newZ});
1090  m_BlockEntities->emplace(newIdx, std::move(be));
1091  }
1092  }
1093 
1094  std::swap(m_Size.x, m_Size.z);
1095 }
1096 
1097 
1098 
1099 
1100 
1102 {
1103  if (!HasBlockTypes())
1104  {
1105  LOGWARNING("cBlockArea: Cannot rotate blockmeta without blocktypes!");
1106  return;
1107  }
1108 
1109  if (!HasBlockMetas())
1110  {
1111  // There are no blockmetas to rotate, just use the NoMeta function
1112  RotateCWNoMeta();
1113  return;
1114  }
1115 
1116  // We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time:
1117  BLOCKARRAY NewTypes{ new BLOCKTYPE[GetBlockCount()] };
1118  NIBBLEARRAY NewMetas{ new NIBBLETYPE[GetBlockCount()] };
1119  for (int x = 0; x < m_Size.x; x++)
1120  {
1121  int NewZ = x;
1122  for (int z = 0; z < m_Size.z; z++)
1123  {
1124  int NewX = m_Size.z - z - 1;
1125  for (int y = 0; y < m_Size.y; y++)
1126  {
1127  auto NewIdx = MakeIndexForSize({ NewX, y, NewZ }, { m_Size.z, m_Size.y, m_Size.x });
1128  auto OldIdx = MakeIndex(x, y, z);
1129  NewTypes[NewIdx] = m_BlockTypes[OldIdx];
1130  NewMetas[NewIdx] = cBlockHandler::For(m_BlockTypes[OldIdx]).MetaRotateCW(m_BlockMetas[OldIdx]);
1131  } // for y
1132  } // for z
1133  } // for x
1134  m_BlockTypes = std::move(NewTypes);
1135  m_BlockMetas = std::move(NewMetas);
1136 
1137  // Rotate the BlockEntities:
1138  if (HasBlockEntities())
1139  {
1140  cBlockEntities oldBE;
1141  std::swap(oldBE, *m_BlockEntities);
1142  for (auto & keyPair: oldBE)
1143  {
1144  auto & be = keyPair.second;
1145  auto newX = m_Size.z - be->GetPosZ() - 1;
1146  auto newY = be->GetPosY();
1147  auto newZ = be->GetPosX();
1148  auto newIdx = newX + newZ * m_Size.z + newY * m_Size.x * m_Size.z;
1149  be->SetPos({newX, newY, newZ});
1150  m_BlockEntities->emplace(newIdx, std::move(be));
1151  }
1152  }
1153 
1154  std::swap(m_Size.x, m_Size.z);
1155 }
1156 
1157 
1158 
1159 
1160 
1162 {
1163  if (!HasBlockTypes())
1164  {
1165  LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!");
1166  return;
1167  }
1168 
1169  if (!HasBlockMetas())
1170  {
1171  // There are no blockmetas to mirror, just use the NoMeta function
1172  MirrorXYNoMeta();
1173  return;
1174  }
1175 
1176  // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
1177  int HalfZ = m_Size.z / 2;
1178  int MaxZ = m_Size.z - 1;
1179  for (int y = 0; y < m_Size.y; y++)
1180  {
1181  for (int z = 0; z < HalfZ; z++)
1182  {
1183  for (int x = 0; x < m_Size.x; x++)
1184  {
1185  auto Idx1 = MakeIndex(x, y, z);
1186  auto Idx2 = MakeIndex(x, y, MaxZ - z);
1187  std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]);
1190  m_BlockMetas[Idx1] = Meta2;
1191  m_BlockMetas[Idx2] = Meta1;
1192  } // for x
1193  } // for z
1194  } // for y
1195 
1196  // Mirror the BlockEntities:
1197  if (HasBlockEntities())
1198  {
1199  cBlockEntities oldBE;
1200  std::swap(oldBE, *m_BlockEntities);
1201  for (auto & keyPair: oldBE)
1202  {
1203  auto & be = keyPair.second;
1204  auto newX = be->GetPosX();
1205  auto newY = be->GetPosY();
1206  auto newZ = MaxZ - be->GetPosZ();
1207  auto newIdx = MakeIndex(newX, newY, newZ);
1208  be->SetPos({newX, newY, newZ});
1209  m_BlockEntities->emplace(newIdx, std::move(be));
1210  }
1211  }
1212 }
1213 
1214 
1215 
1216 
1217 
1219 {
1220  if (!HasBlockTypes())
1221  {
1222  LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!");
1223  return;
1224  }
1225 
1226  if (!HasBlockMetas())
1227  {
1228  // There are no blockmetas to mirror, just use the NoMeta function
1229  MirrorXZNoMeta();
1230  return;
1231  }
1232 
1233  // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
1234  int HalfY = m_Size.y / 2;
1235  int MaxY = m_Size.y - 1;
1236  for (int y = 0; y < HalfY; y++)
1237  {
1238  for (int z = 0; z < m_Size.z; z++)
1239  {
1240  for (int x = 0; x < m_Size.x; x++)
1241  {
1242  auto Idx1 = MakeIndex(x, y, z);
1243  auto Idx2 = MakeIndex(x, MaxY - y, z);
1244  std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]);
1247  m_BlockMetas[Idx1] = Meta2;
1248  m_BlockMetas[Idx2] = Meta1;
1249  } // for x
1250  } // for z
1251  } // for y
1252 
1253  // Mirror the BlockEntities:
1254  if (HasBlockEntities())
1255  {
1256  cBlockEntities oldBE;
1257  std::swap(oldBE, *m_BlockEntities);
1258  for (auto & keyPair: oldBE)
1259  {
1260  auto & be = keyPair.second;
1261  auto newX = be->GetPosX();
1262  auto newY = MaxY - be->GetPosY();
1263  auto newZ = be->GetPosZ();
1264  auto newIdx = MakeIndex(newX, newY, newZ);
1265  be->SetPos({newX, newY, newZ});
1266  m_BlockEntities->emplace(newIdx, std::move(be));
1267  }
1268  }
1269 }
1270 
1271 
1272 
1273 
1274 
1276 {
1277  if (!HasBlockTypes())
1278  {
1279  LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!");
1280  return;
1281  }
1282 
1283  if (!HasBlockMetas())
1284  {
1285  // There are no blockmetas to mirror, just use the NoMeta function
1286  MirrorYZNoMeta();
1287  return;
1288  }
1289 
1290  // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
1291  int HalfX = m_Size.x / 2;
1292  int MaxX = m_Size.x - 1;
1293  for (int y = 0; y < m_Size.y; y++)
1294  {
1295  for (int z = 0; z < m_Size.z; z++)
1296  {
1297  for (int x = 0; x < HalfX; x++)
1298  {
1299  auto Idx1 = MakeIndex(x, y, z);
1300  auto Idx2 = MakeIndex(MaxX - x, y, z);
1301  std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]);
1304  m_BlockMetas[Idx1] = Meta2;
1305  m_BlockMetas[Idx2] = Meta1;
1306  } // for x
1307  } // for z
1308  } // for y
1309 
1310  // Mirror the BlockEntities:
1311  if (HasBlockEntities())
1312  {
1313  cBlockEntities oldBE;
1314  std::swap(oldBE, *m_BlockEntities);
1315  for (auto & keyPair: oldBE)
1316  {
1317  auto & be = keyPair.second;
1318  auto newX = MaxX - be->GetPosX();
1319  auto newY = be->GetPosY();
1320  auto newZ = be->GetPosZ();
1321  auto newIdx = MakeIndex(newX, newY, newZ);
1322  be->SetPos({newX, newY, newZ});
1323  m_BlockEntities->emplace(newIdx, std::move(be));
1324  }
1325  }
1326 }
1327 
1328 
1329 
1330 
1331 
1333 {
1334  if (HasBlockTypes())
1335  {
1336  BLOCKARRAY NewTypes{ new BLOCKTYPE[GetBlockCount()] };
1337  for (int x = 0; x < m_Size.x; x++)
1338  {
1339  int NewZ = m_Size.x - x - 1;
1340  for (int z = 0; z < m_Size.z; z++)
1341  {
1342  int NewX = z;
1343  for (int y = 0; y < m_Size.y; y++)
1344  {
1345  NewTypes[MakeIndexForSize({ NewX, y, NewZ }, { m_Size.z, m_Size.y, m_Size.x })] = m_BlockTypes[MakeIndex(x, y, z)];
1346  } // for y
1347  } // for z
1348  } // for x
1349  m_BlockTypes = std::move(NewTypes);
1350  }
1351  if (HasBlockMetas())
1352  {
1353  NIBBLEARRAY NewMetas{ new NIBBLETYPE[GetBlockCount()] };
1354  for (int x = 0; x < m_Size.x; x++)
1355  {
1356  int NewZ = m_Size.x - x - 1;
1357  for (int z = 0; z < m_Size.z; z++)
1358  {
1359  int NewX = z;
1360  for (int y = 0; y < m_Size.y; y++)
1361  {
1362  NewMetas[MakeIndexForSize({ NewX, y, NewZ }, { m_Size.z, m_Size.y, m_Size.x })] = m_BlockMetas[MakeIndex(x, y, z)];
1363  } // for y
1364  } // for z
1365  } // for x
1366  m_BlockMetas = std::move(NewMetas);
1367  }
1368 
1369  // Rotate the BlockEntities:
1370  if (HasBlockEntities())
1371  {
1372  cBlockEntities oldBE;
1373  std::swap(oldBE, *m_BlockEntities);
1374  for (auto & keyPair: oldBE)
1375  {
1376  auto & be = keyPair.second;
1377  auto newX = be->GetPosZ();
1378  auto newY = be->GetPosY();
1379  auto newZ = m_Size.x - be->GetPosX() - 1;
1380  auto newIdx = newX + newZ * m_Size.z + newY * m_Size.x * m_Size.z;
1381  be->SetPos({newX, newY, newZ});
1382  m_BlockEntities->emplace(newIdx, std::move(be));
1383  }
1384  }
1385 
1386  std::swap(m_Size.x, m_Size.z);
1387 }
1388 
1389 
1390 
1391 
1392 
1394 {
1395  if (HasBlockTypes())
1396  {
1397  BLOCKARRAY NewTypes{ new BLOCKTYPE[GetBlockCount()] };
1398  for (int z = 0; z < m_Size.z; z++)
1399  {
1400  int NewX = m_Size.z - z - 1;
1401  for (int x = 0; x < m_Size.x; x++)
1402  {
1403  int NewZ = x;
1404  for (int y = 0; y < m_Size.y; y++)
1405  {
1406  NewTypes[MakeIndexForSize({ NewX, y, NewZ }, { m_Size.z, m_Size.y, m_Size.x })] = m_BlockTypes[MakeIndex(x, y, z)];
1407  } // for y
1408  } // for x
1409  } // for z
1410  m_BlockTypes = std::move(NewTypes);
1411  }
1412  if (HasBlockMetas())
1413  {
1414  NIBBLEARRAY NewMetas{ new NIBBLETYPE[GetBlockCount()] };
1415  for (int z = 0; z < m_Size.z; z++)
1416  {
1417  int NewX = m_Size.z - z - 1;
1418  for (int x = 0; x < m_Size.x; x++)
1419  {
1420  int NewZ = x;
1421  for (int y = 0; y < m_Size.y; y++)
1422  {
1423  NewMetas[MakeIndexForSize({ NewX, y, NewZ }, { m_Size.z, m_Size.y, m_Size.x })] = m_BlockMetas[MakeIndex(x, y, z)];
1424  } // for y
1425  } // for x
1426  } // for z
1427  m_BlockMetas = std::move(NewMetas);
1428  }
1429 
1430  // Rotate the BlockEntities:
1431  if (HasBlockEntities())
1432  {
1433  cBlockEntities oldBE;
1434  std::swap(oldBE, *m_BlockEntities);
1435  for (auto & keyPair: oldBE)
1436  {
1437  auto & be = keyPair.second;
1438  auto newX = m_Size.z - be->GetPosZ() - 1;
1439  auto newY = be->GetPosY();
1440  auto newZ = be->GetPosX();
1441  auto newIdx = newX + newZ * m_Size.z + newY * m_Size.x * m_Size.z;
1442  be->SetPos({newX, newY, newZ});
1443  m_BlockEntities->emplace(newIdx, std::move(be));
1444  }
1445  }
1446 
1447  std::swap(m_Size.x, m_Size.z);
1448 }
1449 
1450 
1451 
1452 
1453 
1455 {
1456  int HalfZ = m_Size.z / 2;
1457  int MaxZ = m_Size.z - 1;
1458  if (HasBlockTypes())
1459  {
1460  for (int y = 0; y < m_Size.y; y++)
1461  {
1462  for (int z = 0; z < HalfZ; z++)
1463  {
1464  for (int x = 0; x < m_Size.x; x++)
1465  {
1466  std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, y, MaxZ - z)]);
1467  } // for x
1468  } // for z
1469  } // for y
1470  } // if (HasBlockTypes)
1471 
1472  if (HasBlockMetas())
1473  {
1474  for (int y = 0; y < m_Size.y; y++)
1475  {
1476  for (int z = 0; z < HalfZ; z++)
1477  {
1478  for (int x = 0; x < m_Size.x; x++)
1479  {
1480  std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, y, MaxZ - z)]);
1481  } // for x
1482  } // for z
1483  } // for y
1484  } // if (HasBlockMetas)
1485 
1486  // Mirror the BlockEntities:
1487  if (HasBlockEntities())
1488  {
1489  cBlockEntities oldBE;
1490  std::swap(oldBE, *m_BlockEntities);
1491  for (auto & keyPair: oldBE)
1492  {
1493  auto & be = keyPair.second;
1494  auto newX = be->GetPosX();
1495  auto newY = be->GetPosY();
1496  auto newZ = MaxZ - be->GetPosZ();
1497  auto newIdx = MakeIndex(newX, newY, newZ);
1498  be->SetPos({newX, newY, newZ});
1499  m_BlockEntities->emplace(newIdx, std::move(be));
1500  }
1501  }
1502 }
1503 
1504 
1505 
1506 
1507 
1509 {
1510  int HalfY = m_Size.y / 2;
1511  int MaxY = m_Size.y - 1;
1512  if (HasBlockTypes())
1513  {
1514  for (int y = 0; y < HalfY; y++)
1515  {
1516  for (int z = 0; z < m_Size.z; z++)
1517  {
1518  for (int x = 0; x < m_Size.x; x++)
1519  {
1520  std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, MaxY - y, z)]);
1521  } // for x
1522  } // for z
1523  } // for y
1524  } // if (HasBlockTypes)
1525 
1526  if (HasBlockMetas())
1527  {
1528  for (int y = 0; y < HalfY; y++)
1529  {
1530  for (int z = 0; z < m_Size.z; z++)
1531  {
1532  for (int x = 0; x < m_Size.x; x++)
1533  {
1534  std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, MaxY - y, z)]);
1535  } // for x
1536  } // for z
1537  } // for y
1538  } // if (HasBlockMetas)
1539 
1540  // Mirror the BlockEntities:
1541  if (HasBlockEntities())
1542  {
1543  cBlockEntities oldBE;
1544  std::swap(oldBE, *m_BlockEntities);
1545  for (auto & keyPair: oldBE)
1546  {
1547  auto & be = keyPair.second;
1548  auto newX = be->GetPosX();
1549  auto newY = MaxY - be->GetPosY();
1550  auto newZ = be->GetPosZ();
1551  auto newIdx = MakeIndex(newX, newY, newZ);
1552  be->SetPos({newX, newY, newZ});
1553  m_BlockEntities->emplace(newIdx, std::move(be));
1554  }
1555  }
1556 }
1557 
1558 
1559 
1560 
1561 
1563 {
1564  int HalfX = m_Size.x / 2;
1565  int MaxX = m_Size.x - 1;
1566  if (HasBlockTypes())
1567  {
1568  for (int y = 0; y < m_Size.y; y++)
1569  {
1570  for (int z = 0; z < m_Size.z; z++)
1571  {
1572  for (int x = 0; x < HalfX; x++)
1573  {
1574  std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(MaxX - x, y, z)]);
1575  } // for x
1576  } // for z
1577  } // for y
1578  } // if (HasBlockTypes)
1579 
1580  if (HasBlockMetas())
1581  {
1582  for (int y = 0; y < m_Size.y; y++)
1583  {
1584  for (int z = 0; z < m_Size.z; z++)
1585  {
1586  for (int x = 0; x < HalfX; x++)
1587  {
1588  std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(MaxX - x, y, z)]);
1589  } // for x
1590  } // for z
1591  } // for y
1592  } // if (HasBlockMetas)
1593 
1594  // Mirror the BlockEntities:
1595  if (HasBlockEntities())
1596  {
1597  cBlockEntities oldBE;
1598  std::swap(oldBE, *m_BlockEntities);
1599  for (auto & keyPair: oldBE)
1600  {
1601  auto & be = keyPair.second;
1602  auto newX = MaxX - be->GetPosX();
1603  auto newY = be->GetPosY();
1604  auto newZ = be->GetPosZ();
1605  auto newIdx = MakeIndex(newX, newY, newZ);
1606  be->SetPos({newX, newY, newZ});
1607  m_BlockEntities->emplace(newIdx, std::move(be));
1608  }
1609  }
1610 }
1611 
1612 
1613 
1614 
1615 
1616 void cBlockArea::SetRelBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType)
1617 {
1618  ASSERT(m_BlockTypes != nullptr);
1619  auto idx = MakeIndex(a_RelX, a_RelY, a_RelZ);
1620  m_BlockTypes[idx] = a_BlockType;
1621 
1622  // Update the block entities, if appropriate:
1623  if (HasBlockEntities())
1624  {
1625  auto itr = m_BlockEntities->find(idx);
1626  if (itr != m_BlockEntities->end())
1627  {
1628  if (itr->second->GetBlockType() == a_BlockType)
1629  {
1630  // The block entity is for the same block type, keep the current one
1631  return;
1632  }
1633  m_BlockEntities->erase(itr);
1634  }
1635  if (cBlockEntity::IsBlockEntityBlockType(a_BlockType))
1636  {
1637  NIBBLETYPE meta = HasBlockMetas() ? m_BlockMetas[idx] : 0;
1638  m_BlockEntities->emplace(idx, cBlockEntity::CreateByBlockType(a_BlockType, meta, {a_RelX, a_RelY, a_RelZ}));
1639  }
1640  }
1641 }
1642 
1643 
1644 
1645 
1646 
1647 void cBlockArea::SetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
1648 {
1649  SetRelBlockType(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType);
1650 }
1651 
1652 
1653 
1654 
1655 
1656 void cBlockArea::SetRelBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockMeta)
1657 {
1658  SetRelNibble(a_RelX, a_RelY, a_RelZ, a_BlockMeta, GetBlockMetas());
1659 }
1660 
1661 
1662 
1663 
1664 
1665 void cBlockArea::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta)
1666 {
1667  SetNibble(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta, GetBlockMetas());
1668 }
1669 
1670 
1671 
1672 
1673 
1674 void cBlockArea::SetRelBlockLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockLight)
1675 {
1676  SetRelNibble(a_RelX, a_RelY, a_RelZ, a_BlockLight, GetBlockLight());
1677 }
1678 
1679 
1680 
1681 
1682 
1683 void cBlockArea::SetBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockLight)
1684 {
1685  SetNibble(a_BlockX, a_BlockY, a_BlockZ, a_BlockLight, GetBlockLight());
1686 }
1687 
1688 
1689 
1690 
1691 
1692 void cBlockArea::SetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockSkyLight)
1693 {
1694  SetRelNibble(a_RelX, a_RelY, a_RelZ, a_BlockSkyLight, GetBlockSkyLight());
1695 }
1696 
1697 
1698 
1699 
1700 
1701 void cBlockArea::SetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockSkyLight)
1702 {
1703  SetNibble(a_BlockX, a_BlockY, a_BlockZ, a_BlockSkyLight, GetBlockSkyLight());
1704 }
1705 
1706 
1707 
1708 
1709 
1710 BLOCKTYPE cBlockArea::GetRelBlockType(int a_RelX, int a_RelY, int a_RelZ) const
1711 {
1712  if (m_BlockTypes == nullptr)
1713  {
1714  LOGWARNING("cBlockArea: BlockTypes have not been read!");
1715  return E_BLOCK_AIR;
1716  }
1717  return m_BlockTypes[MakeIndex(a_RelX, a_RelY, a_RelZ)];
1718 }
1719 
1720 
1721 
1722 
1723 
1724 BLOCKTYPE cBlockArea::GetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ) const
1725 {
1726  return GetRelBlockType(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z);
1727 }
1728 
1729 
1730 
1731 
1732 
1733 NIBBLETYPE cBlockArea::GetRelBlockMeta(int a_RelX, int a_RelY, int a_RelZ) const
1734 {
1735  return GetRelNibble(a_RelX, a_RelY, a_RelZ, GetBlockMetas());
1736 }
1737 
1738 
1739 
1740 
1741 
1742 NIBBLETYPE cBlockArea::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) const
1743 {
1744  return GetNibble(a_BlockX, a_BlockY, a_BlockZ, GetBlockMetas());
1745 }
1746 
1747 
1748 
1749 
1750 
1751 NIBBLETYPE cBlockArea::GetRelBlockLight(int a_RelX, int a_RelY, int a_RelZ) const
1752 {
1753  return GetRelNibble(a_RelX, a_RelY, a_RelZ, GetBlockLight());
1754 }
1755 
1756 
1757 
1758 
1759 
1760 NIBBLETYPE cBlockArea::GetBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ) const
1761 {
1762  return GetNibble(a_BlockX, a_BlockY, a_BlockZ, GetBlockLight());
1763 }
1764 
1765 
1766 
1767 
1768 
1769 NIBBLETYPE cBlockArea::GetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ) const
1770 {
1771  return GetRelNibble(a_RelX, a_RelY, a_RelZ, GetBlockSkyLight());
1772 }
1773 
1774 
1775 
1776 
1777 
1778 NIBBLETYPE cBlockArea::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ) const
1779 {
1780  return GetNibble(a_BlockX, a_BlockY, a_BlockZ, GetBlockSkyLight());
1781 }
1782 
1783 
1784 
1785 
1786 
1787 void cBlockArea::SetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
1788 {
1789  SetRelBlockTypeMeta(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType, a_BlockMeta);
1790 }
1791 
1792 
1793 
1794 
1795 
1796 void cBlockArea::SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
1797 {
1798  auto idx = MakeIndex(a_RelX, a_RelY, a_RelZ);
1799  if (m_BlockTypes == nullptr)
1800  {
1801  LOGWARNING("%s: BlockTypes not available but requested to be written to.", __FUNCTION__);
1802  }
1803  else
1804  {
1805  m_BlockTypes[idx] = a_BlockType;
1806  }
1807  if (m_BlockMetas == nullptr)
1808  {
1809  LOGWARNING("%s: BlockMetas not available but requested to be written to.", __FUNCTION__);
1810  }
1811  else
1812  {
1813  m_BlockMetas[idx] = a_BlockMeta;
1814  }
1815 
1816  // Update the block entities, if appropriate:
1817  if (HasBlockEntities())
1818  {
1819  auto itr = m_BlockEntities->find(idx);
1820  if (itr != m_BlockEntities->end())
1821  {
1822  if (itr->second->GetBlockType() == a_BlockType)
1823  {
1824  // The block entity is for the same block type, keep the current one
1825  return;
1826  }
1827  m_BlockEntities->erase(itr);
1828  }
1829  if (cBlockEntity::IsBlockEntityBlockType(a_BlockType))
1830  {
1831  m_BlockEntities->emplace(idx, cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, {a_RelX, a_RelY, a_RelZ}));
1832  }
1833  }
1834 }
1835 
1836 
1837 
1838 
1839 
1840 void cBlockArea::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const
1841 {
1842  return GetRelBlockTypeMeta(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType, a_BlockMeta);
1843 }
1844 
1845 
1846 
1847 
1848 
1849 void cBlockArea::GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const
1850 {
1851  auto idx = MakeIndex(a_RelX, a_RelY, a_RelZ);
1852  if (m_BlockTypes == nullptr)
1853  {
1854  LOGWARNING("cBlockArea: BlockTypes have not been read!");
1855  a_BlockType = E_BLOCK_AIR;
1856  }
1857  else
1858  {
1859  a_BlockType = m_BlockTypes[idx];
1860  }
1861 
1862  if (m_BlockMetas == nullptr)
1863  {
1864  LOGWARNING("cBlockArea: BlockMetas have not been read!");
1865  a_BlockMeta = 0;
1866  }
1867  else
1868  {
1869  a_BlockMeta = m_BlockMetas[idx];
1870  }
1871 }
1872 
1873 
1874 
1875 
1876 
1878 {
1879  return cCuboid(
1880  m_Origin,
1881  m_Origin + m_Size - Vector3i(1, 1, 1)
1882  );
1883 }
1884 
1885 
1886 
1887 
1888 
1890 {
1891  // Check if blocktypes are valid:
1892  if (m_BlockTypes == nullptr)
1893  {
1894  LOGWARNING("%s: BlockTypes have not been read!", __FUNCTION__);
1895  return 0;
1896  }
1897 
1898  // Count the blocks:
1899  size_t res = 0;
1900  for (int y = 0; y < m_Size.y; y++)
1901  {
1902  for (int z = 0; z < m_Size.z; z++)
1903  {
1904  for (int x = 0; x < m_Size.x; x++)
1905  {
1906  if (m_BlockTypes[MakeIndex(x, y, z)] != E_BLOCK_AIR)
1907  {
1908  ++res;
1909  }
1910  } // for x
1911  } // for z
1912  } // for y
1913  return res;
1914 }
1915 
1916 
1917 
1918 
1919 
1921 {
1922  // If blocktypes are not valid, log a warning and return zero occurences:
1923  if (m_BlockTypes == nullptr)
1924  {
1925  LOGWARNING("%s: BlockTypes not available!", __FUNCTION__);
1926  return 0;
1927  }
1928 
1929  // Count the blocks:
1930  size_t num = GetBlockCount();
1931  size_t res = 0;
1932  for (size_t i = 0; i < num; i++)
1933  {
1934  if (m_BlockTypes[i] == a_BlockType)
1935  {
1936  res++;
1937  }
1938  }
1939  return res;
1940 }
1941 
1942 
1943 
1944 
1945 
1946 size_t cBlockArea::CountSpecificBlocks(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const
1947 {
1948  // If blocktypes are not valid, log a warning and return zero occurences:
1949  if (m_BlockTypes == nullptr)
1950  {
1951  LOGWARNING("%s: BlockTypes not available!", __FUNCTION__);
1952  return 0;
1953  }
1954 
1955  // If blockmetas are not valid, log a warning and count only blocktypes:
1956  if (m_BlockMetas == nullptr)
1957  {
1958  LOGWARNING("%s: BlockMetas not available, comparing blocktypes only!", __FUNCTION__);
1959  return CountSpecificBlocks(a_BlockType);
1960  }
1961 
1962  // Count the blocks:
1963  size_t num = GetBlockCount();
1964  size_t res = 0;
1965  for (size_t i = 0; i < num; i++)
1966  {
1967  if ((m_BlockTypes[i] == a_BlockType) && (m_BlockMetas[i] == a_BlockMeta))
1968  {
1969  res++;
1970  }
1971  }
1972  return res;
1973 }
1974 
1975 
1976 
1977 
1978 
1979 void cBlockArea::GetNonAirCropRelCoords(int & a_MinRelX, int & a_MinRelY, int & a_MinRelZ, int & a_MaxRelX, int & a_MaxRelY, int & a_MaxRelZ, BLOCKTYPE a_IgnoreBlockType)
1980 {
1981  // Check if blocktypes are valid:
1982  if (m_BlockTypes == nullptr)
1983  {
1984  LOGWARNING("%s: BlockTypes have not been read!", __FUNCTION__);
1985  a_MinRelX = 1;
1986  a_MaxRelX = 0;
1987  return;
1988  }
1989 
1990  // Walk all the blocks and find the min and max coords for the non-ignored ones:
1991  int MaxX = 0, MinX = m_Size.x - 1;
1992  int MaxY = 0, MinY = m_Size.y - 1;
1993  int MaxZ = 0, MinZ = m_Size.z - 1;
1994  for (int y = 0; y < m_Size.y; y++)
1995  {
1996  for (int z = 0; z < m_Size.z; z++)
1997  {
1998  for (int x = 0; x < m_Size.x; x++)
1999  {
2000  if (m_BlockTypes[MakeIndex(x, y, z)] == a_IgnoreBlockType)
2001  {
2002  continue;
2003  }
2004  // The block is not ignored, update any coords that need updating:
2005  if (x < MinX)
2006  {
2007  MinX = x;
2008  }
2009  if (x > MaxX)
2010  {
2011  MaxX = x;
2012  }
2013  if (y < MinY)
2014  {
2015  MinY = y;
2016  }
2017  if (y > MaxY)
2018  {
2019  MaxY = y;
2020  }
2021  if (z < MinZ)
2022  {
2023  MinZ = z;
2024  }
2025  if (z > MaxZ)
2026  {
2027  MaxZ = z;
2028  }
2029  } // for x
2030  } // for z
2031  } // for y
2032 
2033  // Assign to the output:
2034  a_MinRelX = MinX;
2035  a_MinRelY = MinY;
2036  a_MinRelZ = MinZ;
2037  a_MaxRelX = MaxX;
2038  a_MaxRelY = MaxY;
2039  a_MaxRelZ = MaxZ;
2040 }
2041 
2042 
2043 
2044 
2045 
2047 {
2048  int res = 0;
2049  if (m_BlockTypes != nullptr)
2050  {
2051  res |= baTypes;
2052  }
2053  if (m_BlockMetas != nullptr)
2054  {
2055  res |= baMetas;
2056  }
2057  if (m_BlockLight != nullptr)
2058  {
2059  res |= baLight;
2060  }
2061  if (m_BlockSkyLight != nullptr)
2062  {
2063  res |= baSkyLight;
2064  }
2065  if (m_BlockEntities != nullptr)
2066  {
2067  res |= baBlockEntities;
2068  }
2069  return res;
2070 }
2071 
2072 
2073 
2074 
2075 
2076 bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
2077 {
2078  ASSERT(IsValidDataTypeCombination(a_DataTypes));
2079 
2080  BLOCKARRAY NewBlocks;
2081  NIBBLEARRAY NewMetas;
2082  NIBBLEARRAY NewLight;
2083  NIBBLEARRAY NewSkyLight;
2084  cBlockEntitiesPtr NewBlockEntities;
2085 
2086  // Try to allocate the new storage
2087  if ((a_DataTypes & baTypes) != 0)
2088  {
2089  NewBlocks.reset(new BLOCKTYPE[ToUnsigned(a_SizeX * a_SizeY * a_SizeZ)]);
2090  if (NewBlocks == nullptr)
2091  {
2092  return false;
2093  }
2094  }
2095  if ((a_DataTypes & baMetas) != 0)
2096  {
2097  NewMetas.reset(new NIBBLETYPE[ToUnsigned(a_SizeX * a_SizeY * a_SizeZ)]);
2098  if (NewMetas == nullptr)
2099  {
2100  return false;
2101  }
2102  }
2103  if ((a_DataTypes & baLight) != 0)
2104  {
2105  NewLight.reset(new NIBBLETYPE[ToUnsigned(a_SizeX * a_SizeY * a_SizeZ)]);
2106  if (NewLight == nullptr)
2107  {
2108  return false;
2109  }
2110  }
2111  if ((a_DataTypes & baSkyLight) != 0)
2112  {
2113  NewSkyLight.reset(new NIBBLETYPE[ToUnsigned(a_SizeX * a_SizeY * a_SizeZ)]);
2114  if (NewSkyLight == nullptr)
2115  {
2116  return false;
2117  }
2118  }
2119  if ((a_DataTypes & baBlockEntities) != 0)
2120  {
2121  NewBlockEntities.reset(new cBlockEntities);
2122  if (NewBlockEntities == nullptr)
2123  {
2124  return false;
2125  }
2126  }
2127 
2128  // Commit changes
2129  m_BlockTypes = std::move(NewBlocks);
2130  m_BlockMetas = std::move(NewMetas);
2131  m_BlockLight = std::move(NewLight);
2132  m_BlockSkyLight = std::move(NewSkyLight);
2133  m_BlockEntities = std::move(NewBlockEntities);
2134  m_Size.Set(a_SizeX, a_SizeY, a_SizeZ);
2135  return true;
2136 }
2137 
2138 
2139 
2140 
2141 
2143 {
2144  ASSERT(a_RelPos.x >= 0);
2145  ASSERT(a_RelPos.x < a_Size.x);
2146  ASSERT(a_RelPos.y >= 0);
2147  ASSERT(a_RelPos.y < a_Size.y);
2148  ASSERT(a_RelPos.z >= 0);
2149  ASSERT(a_RelPos.z < a_Size.z);
2150 
2151  return static_cast<size_t>(a_RelPos.x + a_RelPos.z * a_Size.x + a_RelPos.y * a_Size.x * a_Size.z);
2152 }
2153 
2154 
2155 
2156 
2157 
2158 bool cBlockArea::DoWithBlockEntityRelAt(int a_RelX, int a_RelY, int a_RelZ, cBlockEntityCallback a_Callback)
2159 {
2160  ASSERT(IsValidRelCoords(a_RelX, a_RelY, a_RelZ));
2161  if (!HasBlockEntities())
2162  {
2163  return false;
2164  }
2165  auto idx = MakeIndex(a_RelX, a_RelY, a_RelZ);
2166  auto itr = m_BlockEntities->find(idx);
2167  if (itr == m_BlockEntities->end())
2168  {
2169  return false;
2170  }
2171  return a_Callback(*itr->second);
2172 }
2173 
2174 
2175 
2176 
2177 
2178 bool cBlockArea::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback a_Callback)
2179 {
2180  return DoWithBlockEntityRelAt(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Callback);
2181 }
2182 
2183 
2184 
2185 
2186 
2188 {
2189  if (!HasBlockEntities())
2190  {
2191  return true;
2192  }
2193  for (auto & keyPair: *m_BlockEntities)
2194  {
2195  if (a_Callback(*keyPair.second))
2196  {
2197  return false;
2198  }
2199  }
2200  return true;
2201 }
2202 
2203 
2204 
2205 
2206 
2207 void cBlockArea::SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array)
2208 {
2209  if (a_Array == nullptr)
2210  {
2211  LOGWARNING("cBlockArea: datatype has not been read!");
2212  return;
2213  }
2214  a_Array[MakeIndex(a_RelX, a_RelY, a_RelZ)] = a_Value;
2215 }
2216 
2217 
2218 
2219 
2220 
2221 void cBlockArea::SetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array)
2222 {
2223  SetRelNibble(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Value, a_Array);
2224 }
2225 
2226 
2227 
2228 
2229 
2230 NIBBLETYPE cBlockArea::GetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE * a_Array) const
2231 {
2232  if (a_Array == nullptr)
2233  {
2234  LOGWARNING("cBlockArea: datatype has not been read!");
2235  return 16;
2236  }
2237  return a_Array[MakeIndex(a_RelX, a_RelY, a_RelZ)];
2238 }
2239 
2240 
2241 
2242 
2243 
2244 NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE * a_Array) const
2245 {
2246  return GetRelNibble(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Array);
2247 }
2248 
2249 
2250 
2251 
2252 
2253 void cBlockArea::CropBlockTypes(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ)
2254 {
2255  int NewSizeX = GetSizeX() - a_AddMinX - a_SubMaxX;
2256  int NewSizeY = GetSizeY() - a_AddMinY - a_SubMaxY;
2257  int NewSizeZ = GetSizeZ() - a_AddMinZ - a_SubMaxZ;
2258  BLOCKARRAY NewBlockTypes{ new BLOCKTYPE[ToUnsigned(NewSizeX * NewSizeY * NewSizeZ)] };
2259  size_t idx = 0;
2260  for (int y = 0; y < NewSizeY; y++)
2261  {
2262  for (int z = 0; z < NewSizeZ; z++)
2263  {
2264  for (int x = 0; x < NewSizeX; x++)
2265  {
2266  auto OldIndex = MakeIndex(x + a_AddMinX, y + a_AddMinY, z + a_AddMinZ);
2267  NewBlockTypes[idx++] = m_BlockTypes[OldIndex];
2268  } // for x
2269  } // for z
2270  } // for y
2271  m_BlockTypes = std::move(NewBlockTypes);
2272 }
2273 
2274 
2275 
2276 
2277 
2278 void cBlockArea::CropNibbles(NIBBLEARRAY & a_Array, int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ)
2279 {
2280  int NewSizeX = GetSizeX() - a_AddMinX - a_SubMaxX;
2281  int NewSizeY = GetSizeY() - a_AddMinY - a_SubMaxY;
2282  int NewSizeZ = GetSizeZ() - a_AddMinZ - a_SubMaxZ;
2283  NIBBLEARRAY NewNibbles{ new NIBBLETYPE[ToUnsigned(NewSizeX * NewSizeY * NewSizeZ)] };
2284  size_t idx = 0;
2285  for (int y = 0; y < NewSizeY; y++)
2286  {
2287  for (int z = 0; z < NewSizeZ; z++)
2288  {
2289  for (int x = 0; x < NewSizeX; x++)
2290  {
2291  NewNibbles[idx++] = a_Array[MakeIndex(x + a_AddMinX, y + a_AddMinY, z + a_AddMinZ)];
2292  } // for x
2293  } // for z
2294  } // for y
2295  a_Array = std::move(NewNibbles);
2296 }
2297 
2298 
2299 
2300 
2301 
2302 void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
2303 {
2304  int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
2305  int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
2306  int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
2307  size_t BlockCount = static_cast<size_t>(NewSizeX * NewSizeY * NewSizeZ);
2308  BLOCKARRAY NewBlockTypes{ new BLOCKTYPE[BlockCount] };
2309  memset(NewBlockTypes.get(), 0, BlockCount * sizeof(BLOCKTYPE));
2310  size_t OldIndex = 0;
2311  for (int y = 0; y < m_Size.y; y++)
2312  {
2313  int IndexBaseY = (y + a_SubMinY) * m_Size.x * m_Size.z;
2314  for (int z = 0; z < m_Size.z; z++)
2315  {
2316  int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_Size.x;
2317  auto idx = static_cast<size_t>(IndexBaseZ + a_SubMinX);
2318  for (int x = 0; x < m_Size.x; x++)
2319  {
2320  NewBlockTypes[idx++] = m_BlockTypes[OldIndex++];
2321  } // for x
2322  } // for z
2323  } // for y
2324  m_BlockTypes = std::move(NewBlockTypes);
2325 }
2326 
2327 
2328 
2329 
2330 
2331 void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
2332 {
2333  int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
2334  int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
2335  int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
2336  size_t BlockCount = static_cast<size_t>(NewSizeX * NewSizeY * NewSizeZ);
2337  NIBBLEARRAY NewNibbles{ new NIBBLETYPE[BlockCount] };
2338  memset(NewNibbles.get(), 0, BlockCount * sizeof(NIBBLETYPE));
2339  size_t OldIndex = 0;
2340  for (int y = 0; y < m_Size.y; y++)
2341  {
2342  int IndexBaseY = (y + a_SubMinY) * m_Size.x * m_Size.z;
2343  for (int z = 0; z < m_Size.z; z++)
2344  {
2345  int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_Size.x;
2346  auto idx = static_cast<size_t>(IndexBaseZ + a_SubMinX);
2347  for (int x = 0; x < m_Size.x; x++)
2348  {
2349  NewNibbles[idx++] = a_Array[OldIndex++];
2350  } // for x
2351  } // for z
2352  } // for y
2353  a_Array = std::move(NewNibbles);
2354 }
2355 
2356 
2357 
2358 
2359 
2361  int a_RelX, int a_RelY, int a_RelZ,
2362  int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
2363  NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
2364 )
2365 {
2366  if (!IsValidCoords(a_RelX, a_RelY, a_RelZ))
2367  {
2368  return;
2369  }
2370 
2371  auto Index = MakeIndex(a_RelX, a_RelY, a_RelZ);
2372  if ((a_DataTypes & baTypes) != 0)
2373  {
2374  m_BlockTypes[Index] = a_BlockType;
2375  }
2376  if ((a_DataTypes & baMetas) != 0)
2377  {
2378  m_BlockMetas[Index] = a_BlockMeta;
2379  }
2380  if ((a_DataTypes & baLight) != 0)
2381  {
2382  m_BlockLight[Index] = a_BlockLight;
2383  }
2384  if ((a_DataTypes & baSkyLight) != 0)
2385  {
2386  m_BlockSkyLight[Index] = a_BlockSkyLight;
2387  }
2388 
2389  // Update the block entities, if appropriate:
2390  if (HasBlockEntities())
2391  {
2392  auto itr = m_BlockEntities->find(Index);
2393  if (itr != m_BlockEntities->end())
2394  {
2395  if (itr->second->GetBlockType() == a_BlockType)
2396  {
2397  // The block entity is for the same block type, keep the current one
2398  return;
2399  }
2400  // The block entity is for a different block type, remove it:
2401  m_BlockEntities->erase(itr);
2402  }
2403  if (cBlockEntity::IsBlockEntityBlockType(a_BlockType))
2404  {
2405  // The block type should have a block entity attached to it, create an empty one:
2406  m_BlockEntities->emplace(Index, cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, {a_RelX, a_RelY, a_RelZ}));
2407  }
2408  }
2409 }
2410 
2411 
2412 
2413 
2414 
2415 template <bool MetasValid>
2416 void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas)
2417 {
2418  // Block types are compulsory, block metas are optional
2419  if (!HasBlockTypes() || !a_Src.HasBlockTypes())
2420  {
2421  LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
2422  return;
2423  }
2424 
2425  // Dst is *this, Src is a_Src
2426  int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading
2427  int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing
2428  int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy
2429 
2430  int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading
2431  int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing
2432  int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy
2433 
2434  int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading
2435  int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing
2436  int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy
2437 
2438  [&]
2439  {
2440  switch (a_Strategy)
2441  {
2443  {
2444  InternalMergeBlocks<MetasValid, MergeCombinatorOverwrite<MetasValid> >(
2445  GetBlockTypes(), a_Src.GetBlockTypes(),
2446  DstMetas, SrcMetas,
2447  SizeX, SizeY, SizeZ,
2448  SrcOffX, SrcOffY, SrcOffZ,
2449  DstOffX, DstOffY, DstOffZ,
2450  a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
2451  m_Size.x, m_Size.y, m_Size.z
2452  );
2453  return;
2454  } // case msOverwrite
2455 
2456  case cBlockArea::msFillAir:
2457  {
2458  InternalMergeBlocks<MetasValid, MergeCombinatorFillAir<MetasValid> >(
2459  GetBlockTypes(), a_Src.GetBlockTypes(),
2460  DstMetas, SrcMetas,
2461  SizeX, SizeY, SizeZ,
2462  SrcOffX, SrcOffY, SrcOffZ,
2463  DstOffX, DstOffY, DstOffZ,
2464  a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
2465  m_Size.x, m_Size.y, m_Size.z
2466  );
2467  return;
2468  } // case msFillAir
2469 
2470  case cBlockArea::msImprint:
2471  {
2472  InternalMergeBlocks<MetasValid, MergeCombinatorImprint<MetasValid> >(
2473  GetBlockTypes(), a_Src.GetBlockTypes(),
2474  DstMetas, SrcMetas,
2475  SizeX, SizeY, SizeZ,
2476  SrcOffX, SrcOffY, SrcOffZ,
2477  DstOffX, DstOffY, DstOffZ,
2478  a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
2479  m_Size.x, m_Size.y, m_Size.z
2480  );
2481  return;
2482  } // case msImprint
2483 
2484  case cBlockArea::msLake:
2485  {
2486  InternalMergeBlocks<MetasValid, MergeCombinatorLake<MetasValid> >(
2487  GetBlockTypes(), a_Src.GetBlockTypes(),
2488  DstMetas, SrcMetas,
2489  SizeX, SizeY, SizeZ,
2490  SrcOffX, SrcOffY, SrcOffZ,
2491  DstOffX, DstOffY, DstOffZ,
2492  a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
2493  m_Size.x, m_Size.y, m_Size.z
2494  );
2495  return;
2496  } // case msLake
2497 
2499  {
2500  InternalMergeBlocks<MetasValid, MergeCombinatorSpongePrint<MetasValid> >(
2501  GetBlockTypes(), a_Src.GetBlockTypes(),
2502  DstMetas, SrcMetas,
2503  SizeX, SizeY, SizeZ,
2504  SrcOffX, SrcOffY, SrcOffZ,
2505  DstOffX, DstOffY, DstOffZ,
2506  a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
2507  m_Size.x, m_Size.y, m_Size.z
2508  );
2509  return;
2510  } // case msSpongePrint
2511 
2513  {
2514  InternalMergeBlocks<MetasValid, MergeCombinatorDifference<MetasValid> >(
2515  GetBlockTypes(), a_Src.GetBlockTypes(),
2516  DstMetas, SrcMetas,
2517  SizeX, SizeY, SizeZ,
2518  SrcOffX, SrcOffY, SrcOffZ,
2519  DstOffX, DstOffY, DstOffZ,
2520  a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
2521  m_Size.x, m_Size.y, m_Size.z
2522  );
2523  return;
2524  } // case msDifference
2525 
2527  {
2528  InternalMergeBlocks<MetasValid, MergeCombinatorSimpleCompare<MetasValid> >(
2529  GetBlockTypes(), a_Src.GetBlockTypes(),
2530  DstMetas, SrcMetas,
2531  SizeX, SizeY, SizeZ,
2532  SrcOffX, SrcOffY, SrcOffZ,
2533  DstOffX, DstOffY, DstOffZ,
2534  a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
2535  m_Size.x, m_Size.y, m_Size.z
2536  );
2537  return;
2538  } // case msSimpleCompare
2539 
2540  case cBlockArea::msMask:
2541  {
2542  InternalMergeBlocks<MetasValid, MergeCombinatorMask<MetasValid> >(
2543  GetBlockTypes(), a_Src.GetBlockTypes(),
2544  DstMetas, SrcMetas,
2545  SizeX, SizeY, SizeZ,
2546  SrcOffX, SrcOffY, SrcOffZ,
2547  DstOffX, DstOffY, DstOffZ,
2548  a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
2549  m_Size.x, m_Size.y, m_Size.z
2550  );
2551  return;
2552  } // case msMask
2553  } // switch (a_Strategy)
2554  UNREACHABLE("Unsupported block area merge strategy");
2555  }();
2556 
2557  if (HasBlockEntities())
2558  {
2559  if (a_Src.HasBlockEntities())
2560  {
2561  MergeBlockEntities(a_RelX, a_RelY, a_RelZ, a_Src);
2562  }
2563  else
2564  {
2566  }
2567  }
2568 }
2569 
2570 
2571 
2572 
2573 
2574 void cBlockArea::MergeBlockEntities(int a_RelX, int a_RelY, int a_RelZ, const cBlockArea & a_Src)
2575 {
2576  // Only supported with both BlockEntities and BlockTypes (caller should check):
2577  ASSERT(HasBlockTypes());
2579  ASSERT(a_Src.HasBlockTypes());
2580  ASSERT(a_Src.HasBlockEntities());
2581 
2582  // Remove block entities that no longer match the block at their coords:
2584 
2585  // Clone BEs from a_Src wherever a BE is missing:
2586  for (int y = 0; y < m_Size.y; ++y) for (int z = 0; z < m_Size.z; ++z) for (int x = 0; x < m_Size.x; ++x)
2587  {
2588  auto idx = MakeIndex(x, y, z);
2589  auto type = m_BlockTypes[idx];
2591  {
2592  continue;
2593  }
2594 
2595  // This block should have a block entity, check that there is one:
2596  auto itr = m_BlockEntities->find(idx);
2597  if (itr != m_BlockEntities->end())
2598  {
2599  // There is one already
2600  continue;
2601  }
2602 
2603  // Copy a BE from a_Src, if it exists there:
2604  auto srcX = x + a_RelX;
2605  auto srcY = y + a_RelY;
2606  auto srcZ = z + a_RelZ;
2607  if (a_Src.IsValidRelCoords(srcX, srcY, srcZ))
2608  {
2609  auto srcIdx = a_Src.MakeIndex(srcX, srcY, srcZ);
2610  auto itrSrc = a_Src.m_BlockEntities->find(srcIdx);
2611  if (itrSrc != a_Src.m_BlockEntities->end())
2612  {
2613  m_BlockEntities->emplace(idx, itrSrc->second->Clone({x, y, z}));
2614  continue;
2615  }
2616  }
2617  // No BE found in a_Src, insert a new empty one:
2618  NIBBLETYPE meta = HasBlockMetas() ? m_BlockMetas[idx] : 0;
2619  m_BlockEntities->emplace(idx, cBlockEntity::CreateByBlockType(type, meta, {x, y, z}));
2620  } // for x, z, y
2621 }
2622 
2623 
2624 
2625 
2626 
2628 {
2629  // Only supported with both BlockEntities and BlockTypes
2630  if (!HasBlockEntities() || !HasBlockTypes())
2631  {
2632  return;
2633  }
2634 
2635  // Remove block entities that no longer match the block at their coords:
2637 
2638  // Add block entities for all block types that should have a BE assigned to them:
2639  for (int y = 0; y < m_Size.y; ++y) for (int z = 0; z < m_Size.z; ++z) for (int x = 0; x < m_Size.x; ++x)
2640  {
2641  auto idx = MakeIndex(x, y, z);
2642  auto type = m_BlockTypes[idx];
2644  {
2645  continue;
2646  }
2647  // This block should have a block entity, check that there is one:
2648  auto itr = m_BlockEntities->find(idx);
2649  if (itr != m_BlockEntities->end())
2650  {
2651  continue;
2652  }
2653  // Create a new BE for this block:
2654  NIBBLETYPE meta = HasBlockMetas() ? m_BlockMetas[idx] : 0;
2655  m_BlockEntities->emplace(idx, cBlockEntity::CreateByBlockType(type, meta, {x, y, z}));
2656  } // for x, z, y
2657 }
2658 
2659 
2660 
2661 
2662 
2664 {
2665  // Only supported with both BlockEntities and BlockTypes:
2666  ASSERT(HasBlockTypes());
2668 
2669  cBlockEntities oldBE;
2670  std::swap(oldBE, *m_BlockEntities);
2671  for (auto & keyPair: oldBE)
2672  {
2673  auto type = m_BlockTypes[static_cast<size_t>(keyPair.first)];
2674  if (type == keyPair.second->GetBlockType())
2675  {
2676  m_BlockEntities->insert(std::move(keyPair));
2677  }
2678  }
2679 }
2680 
2681 
2682 
2683 
2684 
2686 {
2687  if (!HasBlockEntities())
2688  {
2689  return nullptr;
2690  }
2691  auto itr = m_BlockEntities->find(MakeIndex(a_RelPos));
2692  return (itr == m_BlockEntities->end()) ? nullptr : itr->second.get();
2693 }
2694 
2695 
2696 
2697 
2698 
2700 // cBlockArea::cChunkReader:
2701 
2703  m_Area(a_Area),
2704  m_AreaBounds(cCuboid(a_Area.GetOrigin(), a_Area.GetOrigin() + a_Area.GetSize() - Vector3i(1, 1, 1))),
2705  m_Origin(a_Area.m_Origin.x, a_Area.m_Origin.y, a_Area.m_Origin.z),
2706  m_CurrentChunkX(0),
2707  m_CurrentChunkZ(0)
2708 {
2709 }
2710 
2711 
2712 
2713 
2714 
2715 void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLETYPE * a_ChunkSrc)
2716 {
2717  int SizeY = m_Area.m_Size.y;
2718  int MinY = m_Origin.y;
2719 
2720  // SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
2721  // OffX, OffZ are the offsets of the current chunk data from the area origin
2722  // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders
2723  int SizeX = cChunkDef::Width;
2724  int SizeZ = cChunkDef::Width;
2725  int OffX, OffZ;
2726  int BaseX, BaseZ;
2727  OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
2728  if (OffX < 0)
2729  {
2730  BaseX = -OffX;
2731  SizeX += OffX; // SizeX is decreased, OffX is negative
2732  OffX = 0;
2733  }
2734  else
2735  {
2736  BaseX = 0;
2737  }
2738  OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
2739  if (OffZ < 0)
2740  {
2741  BaseZ = -OffZ;
2742  SizeZ += OffZ; // SizeZ is decreased, OffZ is negative
2743  OffZ = 0;
2744  }
2745  else
2746  {
2747  BaseZ = 0;
2748  }
2749  // If the chunk extends beyond the area in the X or Z axis, cut off the Size:
2750  if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
2751  {
2752  SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
2753  }
2754  if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
2755  {
2756  SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
2757  }
2758 
2759  for (int y = 0; y < SizeY; y++)
2760  {
2761  int ChunkY = MinY + y;
2762  int AreaY = y;
2763  for (int z = 0; z < SizeZ; z++)
2764  {
2765  int ChunkZ = BaseZ + z;
2766  int AreaZ = OffZ + z;
2767  for (int x = 0; x < SizeX; x++)
2768  {
2769  int ChunkX = BaseX + x;
2770  int AreaX = OffX + x;
2771  a_AreaDst[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetNibble(a_ChunkSrc, ChunkX, ChunkY, ChunkZ);
2772  } // for x
2773  } // for z
2774  } // for y
2775 }
2776 
2777 
2778 
2779 
2780 
2781 bool cBlockArea::cChunkReader::Coords(int a_ChunkX, int a_ChunkZ)
2782 {
2783  m_CurrentChunkX = a_ChunkX;
2784  m_CurrentChunkZ = a_ChunkZ;
2785  return true;
2786 }
2787 
2788 
2789 
2790 
2791 
2792 void cBlockArea::cChunkReader::ChunkData(const ChunkBlockData & a_BlockData, const ChunkLightData & a_LightData)
2793 {
2794  int SizeY = m_Area.m_Size.y;
2795  int MinY = m_Origin.y;
2796 
2797  // SizeX, SizeZ are the dimensions of the block data to copy from the current chunk (size of the geometric union)
2798  // OffX, OffZ are the offsets of the current chunk data from the area origin
2799  // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders
2800  int SizeX = cChunkDef::Width;
2801  int SizeZ = cChunkDef::Width;
2802  int OffX, OffZ;
2803  int BaseX, BaseZ;
2804  OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
2805  if (OffX < 0)
2806  {
2807  BaseX = -OffX;
2808  SizeX += OffX; // SizeX is decreased, OffX is negative
2809  OffX = 0;
2810  }
2811  else
2812  {
2813  BaseX = 0;
2814  }
2815  OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
2816  if (OffZ < 0)
2817  {
2818  BaseZ = -OffZ;
2819  SizeZ += OffZ; // SizeZ is decreased, OffZ is negative
2820  OffZ = 0;
2821  }
2822  else
2823  {
2824  BaseZ = 0;
2825  }
2826  // If the chunk extends beyond the area in the X or Z axis, cut off the Size:
2827  if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
2828  {
2829  SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
2830  }
2831  if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
2832  {
2833  SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
2834  }
2835 
2836  // Copy the blocktypes:
2837  if (m_Area.m_BlockTypes != nullptr)
2838  {
2839  for (int y = 0; y < SizeY; y++)
2840  {
2841  int InChunkY = MinY + y;
2842  int AreaY = y;
2843  for (int z = 0; z < SizeZ; z++)
2844  {
2845  int InChunkZ = BaseZ + z;
2846  int AreaZ = OffZ + z;
2847  for (int x = 0; x < SizeX; x++)
2848  {
2849  int InChunkX = BaseX + x;
2850  int AreaX = OffX + x;
2851  m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = a_BlockData.GetBlock({ InChunkX, InChunkY, InChunkZ });
2852  } // for x
2853  } // for z
2854  } // for y
2855  }
2856 
2857  // Copy the block metas:
2858  if (m_Area.m_BlockMetas != nullptr)
2859  {
2860  for (int y = 0; y < SizeY; y++)
2861  {
2862  int InChunkY = MinY + y;
2863  int AreaY = y;
2864  for (int z = 0; z < SizeZ; z++)
2865  {
2866  int InChunkZ = BaseZ + z;
2867  int AreaZ = OffZ + z;
2868  for (int x = 0; x < SizeX; x++)
2869  {
2870  int InChunkX = BaseX + x;
2871  int AreaX = OffX + x;
2872  m_Area.m_BlockMetas[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = a_BlockData.GetMeta({ InChunkX, InChunkY, InChunkZ });
2873  } // for x
2874  } // for z
2875  } // for y
2876  }
2877 
2878  // Copy the blocklight:
2879  if (m_Area.m_BlockLight != nullptr)
2880  {
2881  for (int y = 0; y < SizeY; y++)
2882  {
2883  int InChunkY = MinY + y;
2884  int AreaY = y;
2885  for (int z = 0; z < SizeZ; z++)
2886  {
2887  int InChunkZ = BaseZ + z;
2888  int AreaZ = OffZ + z;
2889  for (int x = 0; x < SizeX; x++)
2890  {
2891  int InChunkX = BaseX + x;
2892  int AreaX = OffX + x;
2893  m_Area.m_BlockLight[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = a_LightData.GetBlockLight({ InChunkX, InChunkY, InChunkZ });
2894  } // for x
2895  } // for z
2896  } // for y
2897  }
2898 
2899  // Copy the skylight:
2900  if (m_Area.m_BlockSkyLight != nullptr)
2901  {
2902  for (int y = 0; y < SizeY; y++)
2903  {
2904  int InChunkY = MinY + y;
2905  int AreaY = y;
2906  for (int z = 0; z < SizeZ; z++)
2907  {
2908  int InChunkZ = BaseZ + z;
2909  int AreaZ = OffZ + z;
2910  for (int x = 0; x < SizeX; x++)
2911  {
2912  int InChunkX = BaseX + x;
2913  int AreaX = OffX + x;
2914  m_Area.m_BlockSkyLight[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = a_LightData.GetSkyLight({ InChunkX, InChunkY, InChunkZ });
2915  } // for x
2916  } // for z
2917  } // for y
2918  }
2919 }
2920 
2921 
2922 
2923 
2924 
2926 {
2927  if (!m_Area.HasBlockEntities())
2928  {
2929  return;
2930  }
2931  if (!m_AreaBounds.IsInside(a_BlockEntity->GetPos()))
2932  {
2933  return;
2934  }
2935  auto areaPos = a_BlockEntity->GetPos() - m_Area.m_Origin;
2936  auto Idx = m_Area.MakeIndex(areaPos);
2937  m_Area.m_BlockEntities->emplace(Idx, a_BlockEntity->Clone(areaPos));
2938 }
2939 
2940 
2941 
2942 
2943 
void MergeCombinatorSimpleCompare(BLOCKTYPE &a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE &a_DstMeta, NIBBLETYPE a_SrcMeta)
Combinator used for cBlockArea::msSimpleCompare merging.
Definition: BlockArea.cpp:257
void() CombinatorFunc(BLOCKTYPE &a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE &a_DstMeta, NIBBLETYPE a_SrcMeta)
Definition: BlockArea.cpp:34
void MergeCombinatorDifference(BLOCKTYPE &a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE &a_DstMeta, NIBBLETYPE a_SrcMeta)
Combinator used for cBlockArea::msDifference merging.
Definition: BlockArea.cpp:231
void MergeCombinatorSpongePrint(BLOCKTYPE &a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE &a_DstMeta, NIBBLETYPE a_SrcMeta)
Combinator used for cBlockArea::msSpongePrint merging.
Definition: BlockArea.cpp:212
void InternalMergeBlocks(BLOCKTYPE *a_DstTypes, const BLOCKTYPE *a_SrcTypes, NIBBLETYPE *a_DstMetas, const NIBBLETYPE *a_SrcMetas, int a_SizeX, int a_SizeY, int a_SizeZ, int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ, int a_DstOffX, int a_DstOffY, int a_DstOffZ, int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ, int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ)
Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinato...
Definition: BlockArea.cpp:39
void MergeCombinatorMask(BLOCKTYPE &a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE &a_DstMeta, NIBBLETYPE a_SrcMeta)
Combinator used for cBlockArea::msMask merging.
Definition: BlockArea.cpp:277
void MergeCombinatorLake(BLOCKTYPE &a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE &a_DstMeta, NIBBLETYPE a_SrcMeta)
Combinator used for cBlockArea::msLake merging.
Definition: BlockArea.cpp:138
void MergeCombinatorOverwrite(BLOCKTYPE &a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE &a_DstMeta, NIBBLETYPE a_SrcMeta)
Combinator used for cBlockArea::msOverwrite merging.
Definition: BlockArea.cpp:85
void MergeCombinatorFillAir(BLOCKTYPE &a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE &a_DstMeta, NIBBLETYPE a_SrcMeta)
Combinator used for cBlockArea::msFillAir merging.
Definition: BlockArea.cpp:100
void MergeCombinatorImprint(BLOCKTYPE &a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE &a_DstMeta, NIBBLETYPE a_SrcMeta)
Combinator used for cBlockArea::msImprint merging.
Definition: BlockArea.cpp:119
@ E_BLOCK_SPONGE
Definition: BlockType.h:29
@ E_BLOCK_WATER
Definition: BlockType.h:18
@ E_BLOCK_STATIONARY_LAVA
Definition: BlockType.h:21
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_GRASS
Definition: BlockType.h:12
@ E_BLOCK_MYCELIUM
Definition: BlockType.h:125
@ E_BLOCK_STONE
Definition: BlockType.h:11
@ E_BLOCK_DIRT
Definition: BlockType.h:13
@ E_BLOCK_STATIONARY_WATER
Definition: BlockType.h:19
@ E_BLOCK_LAVA
Definition: BlockType.h:20
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
#define UNREACHABLE(x)
Definition: Globals.h:288
auto ToUnsigned(T a_Val)
Definition: Globals.h:387
unsigned int UInt32
Definition: Globals.h:157
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
std::string AString
Definition: StringUtils.h:11
Vector3< int > Vector3i
Definition: Vector3.h:487
void Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes=baTypes|baMetas|baBlockEntities)
Creates a new area of the specified size and contents.
Definition: BlockArea.cpp:338
void GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: BlockArea.cpp:1849
NIBBLETYPE GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ) const
Definition: BlockArea.cpp:1778
void SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Definition: BlockArea.cpp:1796
void SetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Definition: BlockArea.cpp:1787
void MergeByStrategy(const cBlockArea &a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE *SrcMetas, NIBBLETYPE *DstMetas)
Definition: BlockArea.cpp:2416
size_t MakeIndex(Vector3i a_RelPos) const
Returns the index into the internal arrays for the specified coords.
Definition: BlockArea.h:397
cBlockEntitiesPtr m_BlockEntities
The block entities contained within the area.
Definition: BlockArea.h:475
void Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
Expands the internal contents by the specified amount of blocks from each border.
Definition: BlockArea.cpp:698
void SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
Resets the origin.
Definition: BlockArea.cpp:387
static bool IsValidDataTypeCombination(int a_DataTypes)
Returns true if the datatype combination is valid.
Definition: BlockArea.cpp:304
void MirrorYZ(void)
Mirrors the entire area around the YZ plane.
Definition: BlockArea.cpp:1275
NIBBLETYPE GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE *a_Array) const
Definition: BlockArea.cpp:2244
NIBBLETYPE GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) const
Definition: BlockArea.cpp:1742
bool DoWithBlockEntityRelAt(int a_RelX, int a_RelY, int a_RelZ, cBlockEntityCallback a_Callback)
Calls the callback for the block entity at the specified coords.
Definition: BlockArea.cpp:2158
bool Write(cForEachChunkProvider &a_ForEachChunkProvider, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes)
Writes the area back into cWorld at the coords specified.
Definition: BlockArea.cpp:518
NIBBLETYPE * GetBlockMetas(void) const
Definition: BlockArea.h:390
Vector3i m_Size
Definition: BlockArea.h:461
BLOCKARRAY m_BlockTypes
Definition: BlockArea.h:467
void FillRelCuboid(int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ, int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta=0, NIBBLETYPE a_BlockLight=0, NIBBLETYPE a_BlockSkyLight=0x0f)
Fills a cuboid inside the block area with the specified data.
Definition: BlockArea.cpp:831
bool ForEachBlockEntity(cBlockEntityCallback a_Callback)
Calls the callback for all the block entities.
Definition: BlockArea.cpp:2187
void SetBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockLight)
Definition: BlockArea.cpp:1683
Vector3i m_WEOffset
An extra data value sometimes stored in the .schematic file.
Definition: BlockArea.h:465
void SetWEOffset(int a_OffsetX, int a_OffsetY, int a_OffsetZ)
Definition: BlockArea.cpp:369
std::unique_ptr< BLOCKTYPE[]> BLOCKARRAY
Definition: BlockArea.h:457
bool HasBlockSkyLights(void) const
Definition: BlockArea.h:364
void MirrorXY(void)
Mirrors the entire area around the XY plane.
Definition: BlockArea.cpp:1161
void RescanBlockEntities(void)
Updates m_BlockEntities to remove BEs that no longer match the blocktype at their coords,...
Definition: BlockArea.cpp:2627
size_t CountSpecificBlocks(BLOCKTYPE a_BlockType) const
Returns how many times the specified block is contained in the area.
Definition: BlockArea.cpp:1920
void MirrorYZNoMeta(void)
Mirrors the entire area around the YZ plane, doesn't use blockhandlers for block meta.
Definition: BlockArea.cpp:1562
void Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ)
Crops the internal contents by the specified amount of blocks from each border.
Definition: BlockArea.cpp:635
void RotateCCWNoMeta(void)
Rotates the entire area counter-clockwise around the Y axis, doesn't use blockhandlers for block meta...
Definition: BlockArea.cpp:1332
void SetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockSkyLight)
Definition: BlockArea.cpp:1692
void CropBlockTypes(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ)
Definition: BlockArea.cpp:2253
void ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
Definition: BlockArea.cpp:2302
@ baSkyLight
Definition: BlockArea.h:51
@ baBlockEntities
Definition: BlockArea.h:53
cBlockEntity * GetBlockEntityRel(Vector3i a_RelPos)
Returns the cBlockEntity at the specified coords, or nullptr if none.
Definition: BlockArea.cpp:2685
void GetNonAirCropRelCoords(int &a_MinRelX, int &a_MinRelY, int &a_MinRelZ, int &a_MaxRelX, int &a_MaxRelY, int &a_MaxRelZ, BLOCKTYPE a_IgnoreBlockType=E_BLOCK_AIR)
Returns the minimum and maximum coords in each direction for the first non-ignored block in each dire...
Definition: BlockArea.cpp:1979
void MirrorXYNoMeta(void)
Mirrors the entire area around the XY plane, doesn't use blockhandlers for block meta.
Definition: BlockArea.cpp:1454
void GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: BlockArea.cpp:1840
NIBBLETYPE GetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE *a_Array) const
Definition: BlockArea.cpp:2230
size_t CountNonAirBlocks(void) const
Returns the count of blocks that are not air.
Definition: BlockArea.cpp:1889
NIBBLEARRAY m_BlockMetas
Definition: BlockArea.h:468
Vector3i m_Origin
Definition: BlockArea.h:460
void SetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
Definition: BlockArea.cpp:1647
NIBBLEARRAY m_BlockLight
Definition: BlockArea.h:469
void SetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockSkyLight)
Definition: BlockArea.cpp:1701
bool SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
Clears the data stored and prepares a fresh new block area with the specified dimensions.
Definition: BlockArea.cpp:2076
NIBBLETYPE GetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ) const
Definition: BlockArea.cpp:1769
void SetRelBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType)
Definition: BlockArea.cpp:1616
bool HasBlockLights(void) const
Definition: BlockArea.h:363
bool HasBlockEntities(void) const
Definition: BlockArea.h:365
size_t GetBlockCount(void) const
Definition: BlockArea.h:393
bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback a_Callback)
Calls the callback for the block entity at the specified coords.
Definition: BlockArea.cpp:2178
void CopyFrom(const cBlockArea &a_From)
Copies the contents from the specified BlockArea into this object.
Definition: BlockArea.cpp:587
int GetSizeY(void) const
Definition: BlockArea.h:348
NIBBLETYPE GetRelBlockLight(int a_RelX, int a_RelY, int a_RelZ) const
Definition: BlockArea.cpp:1751
bool HasBlockTypes(void) const
Definition: BlockArea.h:361
cBlockArea(void)
void RotateCW(void)
Rotates the entire area clockwise around the Y axis.
Definition: BlockArea.cpp:1101
int GetDataTypes(void) const
Returns the datatypes that are stored in the object (bitmask of baXXX values)
Definition: BlockArea.cpp:2046
void SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta)
Definition: BlockArea.cpp:1665
void CropNibbles(NIBBLEARRAY &a_Array, int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ)
Definition: BlockArea.cpp:2278
void MirrorXZ(void)
Mirrors the entire area around the XZ plane.
Definition: BlockArea.cpp:1218
BLOCKTYPE * GetBlockTypes(void) const
Returns the internal pointer to the block types.
Definition: BlockArea.h:389
void Fill(int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta=0, NIBBLETYPE a_BlockLight=0, NIBBLETYPE a_BlockSkyLight=0x0f)
Fills the entire block area with the specified data.
Definition: BlockArea.cpp:773
void RotateCCW(void)
Rotates the entire area counter-clockwise around the Y axis.
Definition: BlockArea.cpp:1041
NIBBLETYPE GetBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ) const
Definition: BlockArea.cpp:1760
BLOCKTYPE GetRelBlockType(int a_RelX, int a_RelY, int a_RelZ) const
Definition: BlockArea.cpp:1710
void RelSetData(int a_RelX, int a_RelY, int a_RelZ, int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight)
Sets the specified datatypes at the specified location.
Definition: BlockArea.cpp:2360
void SetRelBlockLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockLight)
Definition: BlockArea.cpp:1674
int GetSizeZ(void) const
Definition: BlockArea.h:349
void RelLine(int a_RelX1, int a_RelY1, int a_RelZ1, int a_RelX2, int a_RelY2, int a_RelZ2, int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta=0, NIBBLETYPE a_BlockLight=0, NIBBLETYPE a_BlockSkyLight=0x0f)
Draws a line between two points with the specified data.
Definition: BlockArea.cpp:908
void MirrorXZNoMeta(void)
Mirrors the entire area around the XZ plane, doesn't use blockhandlers for block meta.
Definition: BlockArea.cpp:1508
cCuboid GetBounds(void) const
Definition: BlockArea.cpp:1877
NIBBLETYPE * GetBlockSkyLight(void) const
Definition: BlockArea.h:392
NIBBLETYPE GetRelBlockMeta(int a_RelX, int a_RelY, int a_RelZ) const
Definition: BlockArea.cpp:1733
NIBBLETYPE * GetBlockLight(void) const
Definition: BlockArea.h:391
eMergeStrategy
The per-block strategy to use when merging another block area into this object.
Definition: BlockArea.h:59
@ msOverwrite
Definition: BlockArea.h:60
@ msSimpleCompare
Definition: BlockArea.h:66
@ msDifference
Definition: BlockArea.h:65
@ msSpongePrint
Definition: BlockArea.h:64
bool Read(cForEachChunkProvider &a_ForEachChunkProvider, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes=baTypes|baMetas|baBlockEntities)
Reads an area of blocks specified.
Definition: BlockArea.cpp:445
void DumpToRawFile(const AString &a_FileName)
For testing purposes only, dumps the area into a file.
Definition: BlockArea.cpp:596
int GetSizeX(void) const
Definition: BlockArea.h:347
void SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Value, NIBBLETYPE *a_Array)
Definition: BlockArea.cpp:2207
bool IsValidRelCoords(int a_RelX, int a_RelY, int a_RelZ) const
Returns true if the specified relative coords are within this area's coord range (0 - m_Size).
Definition: BlockArea.cpp:405
void CopyTo(cBlockArea &a_Into) const
Copies this object's contents into the specified BlockArea.
Definition: BlockArea.cpp:544
std::unique_ptr< NIBBLETYPE[]> NIBBLEARRAY
Definition: BlockArea.h:456
static size_t MakeIndexForSize(Vector3i a_RelPos, Vector3i a_Size)
Definition: BlockArea.cpp:2142
std::unique_ptr< cBlockEntities > cBlockEntitiesPtr
Definition: BlockArea.h:458
bool HasBlockMetas(void) const
Definition: BlockArea.h:362
void Merge(const cBlockArea &a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy)
Merges another block area into this one, using the specified block combinating strategy This function...
Definition: BlockArea.cpp:742
void MergeBlockEntities(int a_RelX, int a_RelY, int a_RelZ, const cBlockArea &a_Src)
Updates m_BlockEntities to remove BEs that no longer match the blocktype at their coords,...
Definition: BlockArea.cpp:2574
void RotateCWNoMeta(void)
Rotates the entire area clockwise around the Y axis, doesn't use blockhandlers for block meta.
Definition: BlockArea.cpp:1393
void SetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Value, NIBBLETYPE *a_Array)
Definition: BlockArea.cpp:2221
bool IsValidCoords(int a_BlockX, int a_BlockY, int a_BlockZ) const
Returns true if the specified coords are within this area's coord range (as indicated by m_Origin).
Definition: BlockArea.cpp:427
void ExpandNibbles(NIBBLEARRAY &a_Array, int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
Definition: BlockArea.cpp:2331
void SetRelBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockMeta)
Definition: BlockArea.cpp:1656
void Clear(void)
Clears the data stored to reclaim memory.
Definition: BlockArea.cpp:323
NIBBLEARRAY m_BlockSkyLight
Definition: BlockArea.h:470
void RemoveNonMatchingBlockEntities(void)
Removes from m_BlockEntities those BEs that no longer match the blocktype at their coords.
Definition: BlockArea.cpp:2663
BLOCKTYPE GetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ) const
Definition: BlockArea.cpp:1724
virtual bool Coords(int a_ChunkX, int a_ChunkZ) override
Definition: BlockArea.cpp:2781
virtual void BlockEntity(cBlockEntity *a_BlockEntity) override
Definition: BlockArea.cpp:2925
cChunkReader(cBlockArea &a_Area)
Definition: BlockArea.cpp:2702
void CopyNibbles(NIBBLETYPE *a_AreaDst, const NIBBLETYPE *a_ChunkSrc)
Definition: BlockArea.cpp:2715
virtual void ChunkData(const ChunkBlockData &a_BlockData, const ChunkLightData &a_LightData) override
Definition: BlockArea.cpp:2792
static OwnedBlockEntity CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld *a_World=nullptr)
Creates a new block entity for the specified block type at the specified absolute pos.
Definition: BlockEntity.cpp:77
Vector3i GetPos() const
Definition: BlockEntity.h:90
static bool IsBlockEntityBlockType(BLOCKTYPE a_BlockType)
Returns true if the specified blocktype is supposed to have an associated block entity.
OwnedBlockEntity Clone(Vector3i a_Pos)
Makes an exact copy of this block entity, except for its m_World (set to nullptr),...
Definition: BlockEntity.cpp:46
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) const
Rotates a given block meta clockwise.
Definition: BlockHandler.h:163
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) const
Rotates a given block meta counter-clockwise.
Definition: BlockHandler.h:159
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) const
Mirros a given block meta around the XZ plane.
Definition: BlockHandler.h:171
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) const
Mirros a given block meta around the YZ plane.
Definition: BlockHandler.h:175
static const cBlockHandler & For(BLOCKTYPE a_BlockType)
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) const
Mirrors a given block meta around the XY plane.
Definition: BlockHandler.h:167
NIBBLETYPE GetMeta(Vector3i a_Position) const
Definition: ChunkData.h:81
BLOCKTYPE GetBlock(Vector3i a_Position) const
Definition: ChunkData.h:80
NIBBLETYPE GetSkyLight(Vector3i a_Position) const
Definition: ChunkData.h:120
NIBBLETYPE GetBlockLight(Vector3i a_Position) const
Definition: ChunkData.h:119
static bool IsValidHeight(Vector3i a_BlockPosition)
Validates a height-coordinate.
Definition: ChunkDef.h:185
static void AbsoluteToRelative(int &a_X, int &a_Y, int &a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords into relative (chunk + block) coords:
Definition: ChunkDef.h:147
static NIBBLETYPE GetNibble(const NIBBLETYPE *a_Buffer, int x, int y, int z)
Definition: ChunkDef.h:335
static const int Width
Definition: ChunkDef.h:124
static const int Height
Definition: ChunkDef.h:125
Definition: Cuboid.h:10
Vector3i p2
Definition: Cuboid.h:13
Vector3i p1
Definition: Cuboid.h:13
virtual bool WriteBlockArea(cBlockArea &a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes)=0
Writes the block area into the specified coords.
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback &a_Callback)=0
Calls the callback for each chunk in the specified range.
Definition: File.h:38
@ fmWrite
Definition: File.h:55
bool Open(const AString &iFileName, eMode iMode)
Definition: File.cpp:52
int Write(const void *a_Buffer, size_t a_NumBytes)
Writes up to a_NumBytes bytes from a_Buffer, returns the number of bytes actually written,...
Definition: File.cpp:180
T x
Definition: Vector3.h:17
void Move(T a_X, T a_Y, T a_Z)
Definition: Vector3.h:162
T y
Definition: Vector3.h:17
void Set(T a_x, T a_y, T a_z)
Definition: Vector3.h:42
T z
Definition: Vector3.h:17
std::unordered_map< size_t, OwnedBlockEntity > cBlockEntities
Definition: BlockEntity.h:17