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