Cuberite
A lightweight, fast and extensible game server for Minecraft
WSSAnvil.cpp
Go to the documentation of this file.
1 #include "Globals.h"
2 #include "WSSAnvil.h"
3 #include "NBTChunkSerializer.h"
5 #include "NamespaceSerializer.h"
6 #include "json/json.h"
7 #include "OSSupport/GZipFile.h"
8 #include "../World.h"
9 #include "../Item.h"
10 #include "../ItemGrid.h"
11 #include "../StringCompression.h"
12 #include "../SetChunkData.h"
13 #include "../Root.h"
14 #include "../BlockType.h"
15 #include "../JsonUtils.h"
16 
17 #include "../BlockEntities/BannerEntity.h"
18 #include "../BlockEntities/BeaconEntity.h"
19 #include "../BlockEntities/BedEntity.h"
20 #include "../BlockEntities/BrewingstandEntity.h"
21 #include "../BlockEntities/ChestEntity.h"
22 #include "../BlockEntities/CommandBlockEntity.h"
23 #include "../BlockEntities/DispenserEntity.h"
24 #include "../BlockEntities/DropperEntity.h"
25 #include "../BlockEntities/EnchantingTableEntity.h"
26 #include "../BlockEntities/EnderChestEntity.h"
27 #include "../BlockEntities/EndPortalEntity.h"
28 #include "../BlockEntities/FurnaceEntity.h"
29 #include "../BlockEntities/HopperEntity.h"
30 #include "../BlockEntities/JukeboxEntity.h"
31 #include "../BlockEntities/NoteEntity.h"
32 #include "../BlockEntities/SignEntity.h"
33 #include "../BlockEntities/MobHeadEntity.h"
34 #include "../BlockEntities/MobSpawnerEntity.h"
35 #include "../BlockEntities/FlowerPotEntity.h"
36 
37 #include "../Mobs/IncludeAllMonsters.h"
38 
39 #include "../Entities/Boat.h"
40 #include "../Entities/EnderCrystal.h"
41 #include "../Entities/FallingBlock.h"
42 #include "../Entities/Minecart.h"
43 #include "../Entities/Pickup.h"
44 #include "../Entities/ArrowEntity.h"
45 #include "../Entities/SplashPotionEntity.h"
46 #include "../Entities/ThrownEggEntity.h"
47 #include "../Entities/ThrownEnderPearlEntity.h"
48 #include "../Entities/ThrownSnowballEntity.h"
49 #include "../Entities/FireChargeEntity.h"
50 #include "../Entities/GhastFireballEntity.h"
51 #include "../Entities/TNTEntity.h"
52 #include "../Entities/ExpOrb.h"
53 #include "../Entities/HangingEntity.h"
54 #include "../Entities/ItemFrame.h"
55 #include "../Entities/LeashKnot.h"
56 #include "../Entities/Painting.h"
57 
58 #include "../Protocol/MojangAPI.h"
59 #include "../Server.h"
60 #include "../BoundingBox.h"
61 
62 
63 
64 
65 
69 // #define DEBUG_SKYLIGHT
70 
74 #define MAX_MCA_FILES 32
75 
76 
77 
78 
79 
81 // cWSSAnvil:
82 
83 cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor):
84  Super(a_World),
85  m_Compressor(a_CompressionFactor)
86 {
87  // Create a level.dat file for mapping tools, if it doesn't already exist:
88  auto fnam = fmt::format(FMT_STRING("{}{}level.dat"), a_World->GetDataPath(), cFile::PathSeparator());
89  if (!cFile::Exists(fnam))
90  {
91  cFastNBTWriter Writer;
92  Writer.BeginCompound("Data");
93  Writer.AddByte("allowCommands", 1);
94  Writer.AddByte("Difficulty", 2);
95  Writer.AddByte("hardcore", cRoot::Get()->GetServer()->IsHardcore() ? 1 : 0);
96  Writer.AddByte("initialized", 1);
97  Writer.AddByte("MapFeatures", 1);
98  Writer.AddByte("raining", a_World->IsWeatherRain() ? 1 : 0);
99  Writer.AddByte("thundering", a_World->IsWeatherStorm() ? 1 : 0);
100  Writer.AddInt("GameType", static_cast<int>(a_World->GetGameMode()));
101  Writer.AddInt("generatorVersion", 1);
102  Writer.AddInt("SpawnX", a_World->GetSpawnX());
103  Writer.AddInt("SpawnY", a_World->GetSpawnY());
104  Writer.AddInt("SpawnZ", a_World->GetSpawnZ());
105  Writer.AddInt("version", 19133);
106  Writer.AddLong("DayTime", a_World->GetWorldDate().count());
107  Writer.AddLong("Time", a_World->GetWorldAge().count());
108  Writer.AddLong("SizeOnDisk", 0);
109  Writer.AddString("generatorName", "default");
110  Writer.AddString("generatorOptions", "");
111  Writer.AddString("LevelName", a_World->GetName());
112  Writer.EndCompound();
113  Writer.Finish();
114 
115  GZipFile::Write(fnam, Writer.GetResult());
116  }
117 }
118 
119 
120 
121 
122 
124 {
125  cCSLock Lock(m_CS);
126  m_Files.clear();
127 }
128 
129 
130 
131 
132 
133 bool cWSSAnvil::LoadChunk(const cChunkCoords & a_Chunk)
134 {
135  ContiguousByteBuffer ChunkData;
136  if (!GetChunkData(a_Chunk, ChunkData))
137  {
138  // The reason for failure is already printed in GetChunkData()
139  return false;
140  }
141 
142  return LoadChunkFromData(a_Chunk, ChunkData);
143 }
144 
145 
146 
147 
148 
149 bool cWSSAnvil::SaveChunk(const cChunkCoords & a_Chunk)
150 {
151  try
152  {
153  if (!SetChunkData(a_Chunk, SaveChunkToData(a_Chunk).GetView()))
154  {
155  LOGWARNING("Cannot store chunk [%d, %d] data", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
156  return false;
157  }
158  }
159  catch (const std::exception & Oops)
160  {
161  LOGWARNING("Cannot serialize chunk [%d, %d] into data: %s", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Oops.what());
162  return false;
163  }
164 
165  // Everything successful
166  return true;
167 }
168 
169 
170 
171 
172 
173 void cWSSAnvil::ChunkLoadFailed(const cChunkCoords a_ChunkCoords, const AString & a_Reason, const ContiguousByteBufferView a_ChunkDataToSave)
174 {
175  // Construct the filename for offloading:
176  auto OffloadFileName = fmt::format(FMT_STRING("{0}{1}region{1}badchunks"), m_World->GetDataPath(), cFile::PathSeparator());
177  cFile::CreateFolder(OffloadFileName);
178  auto t = time(nullptr);
179  struct tm stm;
180  #ifdef _MSC_VER
181  localtime_s(&stm, &t);
182  #else
183  localtime_r(&t, &stm);
184  #endif
185  OffloadFileName.append(fmt::format(
186  FMT_STRING("{}ch.{}.{}.{}-{:02d}-{:02d}-{:02d}-{:02d}-{:02d}.dat"),
187  cFile::PathSeparator(), a_ChunkCoords.m_ChunkX, a_ChunkCoords.m_ChunkZ,
188  stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec
189  ));
190 
191  // Log the warning to console:
192  const int RegionX = FAST_FLOOR_DIV(a_ChunkCoords.m_ChunkX, 32);
193  const int RegionZ = FAST_FLOOR_DIV(a_ChunkCoords.m_ChunkZ, 32);
194  auto Info = fmt::format(
195  FMT_STRING("Loading chunk {} for world {} from file r.{}.{}.mca failed: {} Offloading old chunk data to file {} and regenerating chunk."),
196  a_ChunkCoords, m_World->GetName(), RegionX, RegionZ, a_Reason, OffloadFileName
197  );
198  LOGWARNING("%s", Info);
199 
200  // Write the data:
201  cFile f;
202  if (!f.Open(OffloadFileName, cFile::fmWrite))
203  {
204  LOGWARNING("Cannot open file %s for writing! Old chunk data is lost.", OffloadFileName);
205  return;
206  }
207  f.Write(a_ChunkDataToSave.data(), a_ChunkDataToSave.size());
208  f.Close();
209 
210  // Write a description file:
211  if (!f.Open(OffloadFileName + ".info", cFile::fmWrite))
212  {
213  LOGWARNING("Cannot open file %s.info for writing! The information about the failed chunk will not be written.", OffloadFileName);
214  return;
215  }
216  f.Write(Info.c_str(), Info.size());
217  f.Close();
218 }
219 
220 
221 
222 
223 
225 {
226  cCSLock Lock(m_CS);
227  auto File = LoadMCAFile(a_Chunk);
228  if (File == nullptr)
229  {
230  return false;
231  }
232  return File->GetChunkData(a_Chunk, a_Data);
233 }
234 
235 
236 
237 
238 
240 {
241  cCSLock Lock(m_CS);
242  auto File = LoadMCAFile(a_Chunk);
243  if (File == nullptr)
244  {
245  return false;
246  }
247  return File->SetChunkData(a_Chunk, a_Data);
248 }
249 
250 
251 
252 
253 
254 std::shared_ptr<cWSSAnvil::cMCAFile> cWSSAnvil::LoadMCAFile(const cChunkCoords & a_Chunk)
255 {
256  // ASSUME m_CS is locked
257  ASSERT(m_CS.IsLocked());
258 
259  const int RegionX = FAST_FLOOR_DIV(a_Chunk.m_ChunkX, 32);
260  const int RegionZ = FAST_FLOOR_DIV(a_Chunk.m_ChunkZ, 32);
261  ASSERT(a_Chunk.m_ChunkX - RegionX * 32 >= 0);
262  ASSERT(a_Chunk.m_ChunkZ - RegionZ * 32 >= 0);
263  ASSERT(a_Chunk.m_ChunkX - RegionX * 32 < 32);
264  ASSERT(a_Chunk.m_ChunkZ - RegionZ * 32 < 32);
265 
266  // Is it already cached?
267  for (auto itr = m_Files.begin(); itr != m_Files.end(); ++itr)
268  {
269  if (((*itr) != nullptr) && ((*itr)->GetRegionX() == RegionX) && ((*itr)->GetRegionZ() == RegionZ))
270  {
271  // Move the file to front and return it:
272  auto f = *itr;
273  if (itr != m_Files.begin())
274  {
275  m_Files.erase(itr);
276  m_Files.push_front(f);
277  }
278  return f;
279  }
280  }
281 
282  // Load it anew:
283  auto FileName = fmt::format(FMT_STRING("{}{}region"), m_World->GetDataPath(), cFile::PathSeparator());
284  cFile::CreateFolder(FileName);
285  FileName.append(fmt::format(FMT_STRING("/r.{}.{}.mca"), RegionX, RegionZ));
286  auto f = std::make_shared<cMCAFile>(*this, FileName, RegionX, RegionZ);
287  if (f == nullptr)
288  {
289  return nullptr;
290  }
291  m_Files.push_front(f);
292 
293  // If there are too many MCA files cached, delete the last one used:
294  if (m_Files.size() > MAX_MCA_FILES)
295  {
296  m_Files.pop_back();
297  }
298  return f;
299 }
300 
301 
302 
303 
304 
306 {
307  try
308  {
309  const auto Extracted = m_Extractor.ExtractZLib(a_Data);
310  cParsedNBT NBT(Extracted.GetView());
311 
312  if (!NBT.IsValid())
313  {
314  // NBT Parsing failed:
315  throw std::runtime_error(fmt::format("NBT parsing failed. {} at position {}.", NBT.GetErrorCode().message(), NBT.GetErrorPos()));
316  }
317 
318  // Load the data from NBT:
319  return LoadChunkFromNBT(a_Chunk, NBT, a_Data);
320  }
321  catch (const std::exception & Oops)
322  {
323  ChunkLoadFailed(a_Chunk, Oops.what(), a_Data);
324  return false;
325  }
326 }
327 
328 
329 
330 
331 
333 {
334  cFastNBTWriter Writer;
335  NBTChunkSerializer::Serialize(*m_World, a_Chunk, Writer);
336  Writer.Finish();
337 
338  return m_Compressor.CompressZLib(Writer.GetResult());
339 }
340 
341 
342 
343 
344 
345 bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT, const ContiguousByteBufferView a_RawChunkData)
346 {
347  struct SetChunkData Data(a_Chunk);
348 
349  // Load the blockdata, blocklight and skylight:
350  int Level = a_NBT.FindChildByName(0, "Level");
351  if (Level < 0)
352  {
353  ChunkLoadFailed(a_Chunk, "Missing NBT tag: Level", a_RawChunkData);
354  return false;
355  }
356 
357  int Sections = a_NBT.FindChildByName(Level, "Sections");
358  if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List))
359  {
360  ChunkLoadFailed(a_Chunk, "Missing NBT tag: Sections", a_RawChunkData);
361  return false;
362  }
363 
364  eTagType SectionsType = a_NBT.GetChildrenType(Sections);
365  if ((SectionsType != TAG_Compound) && (SectionsType != TAG_End))
366  {
367  ChunkLoadFailed(a_Chunk, "NBT tag has wrong type: Sections", a_RawChunkData);
368  return false;
369  }
370  for (int Child = a_NBT.GetFirstChild(Sections); Child >= 0; Child = a_NBT.GetNextSibling(Child))
371  {
372  const int SectionYTag = a_NBT.FindChildByName(Child, "Y");
373  if ((SectionYTag < 0) || (a_NBT.GetType(SectionYTag) != TAG_Byte))
374  {
375  ChunkLoadFailed(a_Chunk, "NBT tag missing or has wrong: Y", a_RawChunkData);
376  return false;
377  }
378 
379  const int Y = a_NBT.GetByte(SectionYTag);
380  if ((Y < 0) || (Y > static_cast<int>(cChunkDef::NumSections - 1)))
381  {
382  ChunkLoadFailed(a_Chunk, "NBT tag exceeds chunk bounds: Y", a_RawChunkData);
383  return false;
384  }
385 
386  const auto
388  MetaData = GetSectionData(a_NBT, Child, "Data", ChunkBlockData::SectionMetaCount),
389  BlockLightData = GetSectionData(a_NBT, Child, "BlockLight", ChunkLightData::SectionLightCount),
390  SkyLightData = GetSectionData(a_NBT, Child, "SkyLight", ChunkLightData::SectionLightCount);
391  if ((BlockData != nullptr) && (MetaData != nullptr) && (SkyLightData != nullptr) && (BlockLightData != nullptr))
392  {
393  Data.BlockData.SetSection(*reinterpret_cast<const ChunkBlockData::SectionType *>(BlockData), *reinterpret_cast<const ChunkBlockData::SectionMetaType *>(MetaData), static_cast<size_t>(Y));
394  Data.LightData.SetSection(*reinterpret_cast<const ChunkLightData::SectionType *>(BlockLightData), *reinterpret_cast<const ChunkLightData::SectionType *>(SkyLightData), static_cast<size_t>(Y));
395  }
396  else
397  {
398  ChunkLoadFailed(a_Chunk, "Missing chunk block/light data", a_RawChunkData);
399  return false;
400  }
401  } // for itr - LevelSections[]
402 
403  // Load the biomes from NBT, if present and valid:
404  if (!LoadBiomeMapFromNBT(Data.BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes")))
405  {
406  ChunkLoadFailed(a_Chunk, "Missing chunk biome data", a_RawChunkData);
407  return false;
408  }
409 
410  // Load the Height map, if it fails, recalculate it:
411  if (!LoadHeightMapFromNBT(Data.HeightMap, a_NBT, a_NBT.FindChildByName(Level, "HeightMap")))
412  {
413  Data.UpdateHeightMap();
414  }
415 
416  // Load the entities from NBT:
417  LoadEntitiesFromNBT (Data.Entities, a_NBT, a_NBT.FindChildByName(Level, "Entities"));
418  LoadBlockEntitiesFromNBT(Data.BlockEntities, a_NBT, a_NBT.FindChildByName(Level, "TileEntities"), Data.BlockData);
419 
420  Data.IsLightValid = (a_NBT.FindChildByName(Level, "MCSIsLightValid") > 0);
421 
422  /*
423  // Uncomment this block for really cool stuff :)
424  // DEBUG magic: Invert the underground, so that we can see the MC generator in action :)
425  bool ShouldInvert[cChunkDef::Width * cChunkDef::Width];
426  memset(ShouldInvert, 0, sizeof(ShouldInvert));
427  for (int y = cChunkDef::Height - 1; y >= 0; y--)
428  {
429  for (int x = 0; x < cChunkDef::Width; x++) for (int z = 0; z < cChunkDef::Width; z++)
430  {
431  const auto Index = cChunkDef::MakeIndex(x, y, z);
432  if (ShouldInvert[x + cChunkDef::Width * z])
433  {
434  BlockTypes[Index] = (BlockTypes[Index] == E_BLOCK_AIR) ? E_BLOCK_STONE : E_BLOCK_AIR;
435  }
436  else
437  {
438  switch (BlockTypes[Index])
439  {
440  case E_BLOCK_AIR:
441  case E_BLOCK_LEAVES:
442  case E_BLOCK_NEW_LEAVES:
443  {
444  // nothing needed
445  break;
446  }
447  default:
448  {
449  ShouldInvert[x + cChunkDef::Width * z] = true;
450  }
451  }
452  BlockTypes[Index] = E_BLOCK_AIR;
453  }
454  }
455  } // for y
456  //*/
457 
458  m_World->QueueSetChunkData(std::move(Data));
459  return true;
460 }
461 
462 
463 
464 
465 
466 bool cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap & a_BiomeMap, const cParsedNBT & a_NBT, const int a_TagIdx)
467 {
468  if (
469  (a_TagIdx < 0) ||
470  (a_NBT.GetType(a_TagIdx) != TAG_ByteArray) ||
471  (a_NBT.GetDataLength(a_TagIdx) != std::size(a_BiomeMap))
472  )
473  {
474  return false;
475  }
476 
477  const auto * const BiomeData = a_NBT.GetData(a_TagIdx);
478  for (size_t i = 0; i < ARRAYCOUNT(a_BiomeMap); i++)
479  {
480  if (BiomeData[i] > std::byte(EMCSBiome::biMaxVariantBiome))
481  {
482  // Unassigned biomes:
483  return false;
484  }
485 
486  a_BiomeMap[i] = static_cast<EMCSBiome>(BiomeData[i]);
487  }
488 
489  return true;
490 }
491 
492 
493 
494 
495 
496 bool cWSSAnvil::LoadHeightMapFromNBT(cChunkDef::HeightMap & a_HeightMap, const cParsedNBT & a_NBT, const int a_TagIdx)
497 {
498  if (
499  (a_TagIdx < 0) ||
500  (a_NBT.GetType(a_TagIdx) != TAG_IntArray) ||
501  (a_NBT.GetDataLength(a_TagIdx) != (4 * std::size(a_HeightMap)))
502  )
503  {
504  return false;
505  }
506 
507  const auto * const HeightData = a_NBT.GetData(a_TagIdx);
508  for (int RelZ = 0; RelZ < cChunkDef::Width; RelZ++)
509  {
510  for (int RelX = 0; RelX < cChunkDef::Width; RelX++)
511  {
512  const int Index = 4 * (RelX + RelZ * cChunkDef::Width);
513  const int Height = GetBEInt(HeightData + Index);
514 
515  if (Height > std::numeric_limits<HEIGHTTYPE>::max())
516  {
517  // Invalid data:
518  return false;
519  }
520 
521  cChunkDef::SetHeight(a_HeightMap, RelX, RelZ, static_cast<HEIGHTTYPE>(Height));
522  }
523  }
524 
525  return true;
526 }
527 
528 
529 
530 
531 
532 void cWSSAnvil::LoadEntitiesFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
533 {
534  if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List))
535  {
536  return;
537  }
538 
539  for (int Child = a_NBT.GetFirstChild(a_TagIdx); Child != -1; Child = a_NBT.GetNextSibling(Child))
540  {
541  if (a_NBT.GetType(Child) != TAG_Compound)
542  {
543  continue;
544  }
545  int sID = a_NBT.FindChildByName(Child, "id");
546  if (sID < 0)
547  {
548  continue;
549  }
550 
551  try
552  {
553  LoadEntityFromNBT(a_Entities, a_NBT, Child, a_NBT.GetStringView(sID));
554  }
555  catch (...)
556  {
557  continue;
558  }
559  } // for Child - a_NBT[]
560 }
561 
562 
563 
564 
565 
566 void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntities & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, const ChunkBlockData & a_BlockData)
567 {
568  if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List))
569  {
570  return;
571  }
572 
573  for (int Child = a_NBT.GetFirstChild(a_TagIdx); Child != -1; Child = a_NBT.GetNextSibling(Child))
574  {
575  if (a_NBT.GetType(Child) != TAG_Compound)
576  {
577  continue;
578  }
579 
580  // Get the BlockEntity's position
581  Vector3i absPos;
582  if (!GetBlockEntityNBTPos(a_NBT, Child, absPos) || (absPos.y < 0) || (absPos.y >= cChunkDef::Height))
583  {
584  LOGWARNING("Bad block entity, missing the coords. Will be ignored.");
585  continue;
586  }
587  const auto relPos = cChunkDef::AbsoluteToRelative(absPos);
588 
589  // Load the proper BlockEntity type based on the block type:
590  const auto BlockType = a_BlockData.GetBlock(relPos);
591  const auto BlockMeta = a_BlockData.GetMeta(relPos);
592  OwnedBlockEntity Entity;
593 
594  try
595  {
596  Entity = LoadBlockEntityFromNBT(a_NBT, Child, absPos, BlockType, BlockMeta);
597  }
598  catch (...)
599  {
600  continue;
601  }
602 
603  // TODO: exception-ify the failure case
604  if (Entity == nullptr)
605  {
606  continue;
607  }
608 
609  // Index computed before Entity moved.
610  const auto Index = cChunkDef::MakeIndex(Entity->GetRelPos());
611 
612  // Add the BlockEntity to the loaded data:
613  a_BlockEntities.emplace(Index, std::move(Entity));
614  } // for Child - tag children
615 }
616 
617 
618 
619 
620 
621 OwnedBlockEntity cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a_Tag, Vector3i a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
622 {
623  ASSERT((a_Pos.y >= 0) && (a_Pos.y < cChunkDef::Height));
624 
625  // Load the specific BlockEntity type:
626  switch (a_BlockType)
627  {
628  // Banners:
630  case E_BLOCK_WALL_BANNER: return LoadBannerFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
631 
632  // Others:
633  case E_BLOCK_BEACON: return LoadBeaconFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
634  case E_BLOCK_BED: return LoadBedFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
635  case E_BLOCK_BREWING_STAND: return LoadBrewingstandFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
636  case E_BLOCK_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
637  case E_BLOCK_COMMAND_BLOCK: return LoadCommandBlockFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
638  case E_BLOCK_DISPENSER: return LoadDispenserFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
639  case E_BLOCK_DROPPER: return LoadDropperFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
640  case E_BLOCK_ENCHANTMENT_TABLE: return LoadEnchantingTableFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
641  case E_BLOCK_ENDER_CHEST: return LoadEnderChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
642  case E_BLOCK_END_PORTAL: return LoadEndPortalFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
643  case E_BLOCK_FLOWER_POT: return LoadFlowerPotFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
644  case E_BLOCK_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
645  case E_BLOCK_HEAD: return LoadMobHeadFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
646  case E_BLOCK_HOPPER: return LoadHopperFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
647  case E_BLOCK_JUKEBOX: return LoadJukeboxFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
648  case E_BLOCK_LIT_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
649  case E_BLOCK_MOB_SPAWNER: return LoadMobSpawnerFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
650  case E_BLOCK_NOTE_BLOCK: return LoadNoteBlockFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
651  case E_BLOCK_SIGN_POST: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
652  case E_BLOCK_TRAPPED_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
653  case E_BLOCK_WALLSIGN: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos);
654  default:
655  {
656  // All the other blocktypes should have no entities assigned to them. Report an error:
657  // Get the "id" tag:
658  int TagID = a_NBT.FindChildByName(a_Tag, "id");
659  FLOGINFO("WorldLoader({0}): Block entity mismatch: block type {1} ({2}), type \"{3}\", at {4}; the entity will be lost.",
660  m_World->GetName(),
661  ItemTypeToString(a_BlockType), a_BlockType, (TagID >= 0) ? a_NBT.GetStringView(TagID) : "unknown",
662  a_Pos
663  );
664  return nullptr;
665  }
666  }
667 }
668 
669 
670 
671 
672 
673 bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx)
674 {
675  int Type = a_NBT.FindChildByName(a_TagIdx, "id");
676  if (Type <= 0)
677  {
678  return false;
679  }
680 
681  if (a_NBT.GetType(Type) == TAG_String)
682  {
683  if (!StringToItem(a_NBT.GetString(Type), a_Item))
684  {
685  // Can't resolve item type
686  return false;
687  }
688  }
689  else if (a_NBT.GetType(Type) == TAG_Short)
690  {
691  a_Item.m_ItemType = a_NBT.GetShort(Type);
692  }
693  else
694  {
695  return false;
696  }
697 
698  if (a_Item.m_ItemType < 0)
699  {
700  a_Item.Empty();
701  return true;
702  }
703 
704  int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage");
705  if ((Damage > 0) && (a_NBT.GetType(Damage) == TAG_Short))
706  {
707  a_Item.m_ItemDamage = a_NBT.GetShort(Damage);
708  }
709 
710  int Count = a_NBT.FindChildByName(a_TagIdx, "Count");
711  if ((Count > 0) && (a_NBT.GetType(Count) == TAG_Byte))
712  {
713  a_Item.m_ItemCount = static_cast<char>(a_NBT.GetByte(Count));
714  }
715 
716  // Find the "tag" tag, used for enchantments and other extra data
717  int TagTag = a_NBT.FindChildByName(a_TagIdx, "tag");
718  if (TagTag <= 0)
719  {
720  // No extra data
721  return true;
722  }
723 
724  // Load repair cost:
725  int RepairCost = a_NBT.FindChildByName(TagTag, "RepairCost");
726  if ((RepairCost > 0) && (a_NBT.GetType(RepairCost) == TAG_Int))
727  {
728  a_Item.m_RepairCost = a_NBT.GetInt(RepairCost);
729  }
730 
731  // Load display name:
732  int DisplayTag = a_NBT.FindChildByName(TagTag, "display");
733  if (DisplayTag > 0)
734  {
735  int DisplayName = a_NBT.FindChildByName(DisplayTag, "Name");
736  if ((DisplayName > 0) && (a_NBT.GetType(DisplayName) == TAG_String))
737  {
738  a_Item.m_CustomName = a_NBT.GetString(DisplayName);
739  }
740  int Lore = a_NBT.FindChildByName(DisplayTag, "Lore");
741  if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_String))
742  {
743  // Legacy string lore
744  a_Item.m_LoreTable = StringSplit(a_NBT.GetString(Lore), "`");
745  }
746  else if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_List))
747  {
748  // Lore table
749  a_Item.m_LoreTable.clear();
750  for (int loretag = a_NBT.GetFirstChild(Lore); loretag >= 0; loretag = a_NBT.GetNextSibling(loretag)) // Loop through array of strings
751  {
752  a_Item.m_LoreTable.push_back(a_NBT.GetString(loretag));
753  }
754  }
755  }
756 
757  // Load enchantments:
758  const char * EnchName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
759  int EnchTag = a_NBT.FindChildByName(TagTag, EnchName);
760  if (EnchTag > 0)
761  {
762  EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag);
763  }
764 
765  // Load firework data:
766  int FireworksTag = a_NBT.FindChildByName(TagTag, ((a_Item.m_ItemType == E_ITEM_FIREWORK_STAR) ? "Explosion" : "Fireworks"));
767  if (FireworksTag > 0)
768  {
769  cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, a_NBT, FireworksTag, static_cast<ENUM_ITEM_TYPE>(a_Item.m_ItemType));
770  }
771 
772  return true;
773 }
774 
775 
776 
777 
778 
779 void cWSSAnvil::LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int a_SlotOffset)
780 {
781  int NumSlots = a_ItemGrid.GetNumSlots();
782  for (int Child = a_NBT.GetFirstChild(a_ItemsTagIdx); Child != -1; Child = a_NBT.GetNextSibling(Child))
783  {
784  int SlotTag = a_NBT.FindChildByName(Child, "Slot");
785  if ((SlotTag < 0) || (a_NBT.GetType(SlotTag) != TAG_Byte))
786  {
787  continue;
788  }
789  int SlotNum = static_cast<int>(a_NBT.GetByte(SlotTag)) - a_SlotOffset;
790  if ((SlotNum < 0) || (SlotNum >= NumSlots))
791  {
792  // SlotNum outside of the range
793  continue;
794  }
795  cItem Item;
796  if (LoadItemFromNBT(Item, a_NBT, Child))
797  {
798  a_ItemGrid.SetSlot(SlotNum, Item);
799  }
800  } // for itr - ItemDefs[]
801 }
802 
803 
804 
805 
806 
808 {
809  if (a_Line.empty())
810  {
811  return AString();
812  }
813  if (a_Line[0] != '{')
814  {
815  return a_Line;
816  }
817 
818  // Try to parse the JSON:
819  Json::Value root;
820  if (!JsonUtils::ParseString(a_Line, root) || !root.isObject())
821  {
822  return a_Line;
823  }
824  const auto & txt = root["text"];
825  if (txt.isString())
826  {
827  return txt.asString();
828  }
829  return a_Line;
830 }
831 
832 
833 
834 
835 
836 bool cWSSAnvil::CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const AStringVector & a_ExpectedTypes, Vector3i a_Pos)
837 {
838  // Check if the given tag is a compound:
839  if (a_NBT.GetType(a_TagIdx) != TAG_Compound)
840  {
841  return false;
842  }
843 
844  // Get the "id" tag:
845  int TagID = a_NBT.FindChildByName(a_TagIdx, "id");
846  if (TagID < 0)
847  {
848  return false;
849  }
850 
851  // Check if the "id" tag is a string:
852  if (a_NBT.GetType(TagID) != eTagType::TAG_String)
853  {
854  return false;
855  }
856 
857  // Compare the value:
858  for (const auto & et: a_ExpectedTypes)
859  {
860  if (a_NBT.GetStringView(TagID) == et)
861  {
862  return true;
863  }
864  }
865 
866  // Expectation not met, output an error into the log:
867  AString expectedTypes;
868  for (const auto & et : a_ExpectedTypes)
869  {
870  expectedTypes.append(", \"");
871  expectedTypes.append(et);
872  expectedTypes.push_back('\"');
873  }
874  FLOGWARNING("Block entity type mismatch: exp {0}, got \"{1}\". The block entity at {2} will lose all its properties.",
875  expectedTypes.c_str() + 2, // Skip the first ", " that is extra in the string
876  a_NBT.GetStringView(TagID), a_Pos
877  );
878  return false;
879 }
880 
881 
882 
883 
884 
885 OwnedBlockEntity cWSSAnvil::LoadBannerFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
886 {
887  static const AStringVector expectedTypes({"Banner", "minecraft:standingbanner","minecraft:wallbanner"});
888  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
889  {
890  return nullptr;
891  }
892 
893  unsigned char Color = 15;
894  AString CustomName;
895 
896  // Reads base color from NBT
897  int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Base");
898  if (CurrentLine >= 0)
899  {
900  Color = static_cast<unsigned char>(a_NBT.GetInt(CurrentLine));
901  }
902 
903  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "CustomName");
904  if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_String))
905  {
906  CustomName = a_NBT.GetString(CurrentLine);
907  }
908 
909  return std::make_unique<cBannerEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World, Color, CustomName);
910 }
911 
912 
913 
914 
915 
916 OwnedBlockEntity cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
917 {
918  // Check if the data has a proper type:
919  static const AStringVector expectedTypes({"Beacon", "minecraft:beacon"});
920  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
921  {
922  return nullptr;
923  }
924 
925  auto Beacon = std::make_unique<cBeaconEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
926 
927  int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Levels");
928  if (CurrentLine >= 0)
929  {
930  Beacon->SetBeaconLevel(static_cast<char>(a_NBT.GetInt(CurrentLine)));
931  }
932 
933  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Primary");
934  if (CurrentLine >= 0)
935  {
936  Beacon->SetPrimaryEffect(static_cast<cEntityEffect::eType>(a_NBT.GetInt(CurrentLine)));
937  }
938 
939  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Secondary");
940  if (CurrentLine >= 0)
941  {
942  Beacon->SetSecondaryEffect(static_cast<cEntityEffect::eType>(a_NBT.GetInt(CurrentLine)));
943  }
944 
945  // We are better than mojang, we load / save the beacon inventory!
946  int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
947  if ((Items >= 0) && (a_NBT.GetType(Items) == TAG_List))
948  {
949  LoadItemGridFromNBT(Beacon->GetContents(), a_NBT, Items);
950  }
951 
952  return Beacon;
953 }
954 
955 
956 
957 
958 
959 OwnedBlockEntity cWSSAnvil::LoadBedFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
960 {
961  // Check if the data has a proper type:
962  static const AStringVector expectedTypes({ "Bed", "minecraft:bed" });
963  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
964  {
965  return nullptr;
966  }
967 
968  // Use color red as default
969  short Color = E_META_WOOL_RED;
970 
971  int ColorIDx = a_NBT.FindChildByName(a_TagIdx, "color");
972  if (ColorIDx >= 0)
973  {
974  Color = static_cast<short>(a_NBT.GetInt(ColorIDx));
975  }
976 
977  return std::make_unique<cBedEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World, Color);
978 }
979 
980 
981 
982 
983 
984 OwnedBlockEntity cWSSAnvil::LoadBrewingstandFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
985 {
986  // Check if the data has a proper type:
987  static const AStringVector expectedTypes({ "Brewingstand", "minecraft:brewing_stand" });
988  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
989  {
990  return nullptr;
991  }
992 
993  int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
994  if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
995  {
996  return nullptr; // Make it an empty brewingstand - the chunk loader will provide an empty cBrewingstandEntity for this
997  }
998 
999  auto Brewingstand = std::make_unique<cBrewingstandEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1000 
1001  // Fuel has to be loaded at first, because of slot events:
1002  int Fuel = a_NBT.FindChildByName(a_TagIdx, "Fuel");
1003  if (Fuel >= 0)
1004  {
1005  Int16 tb = a_NBT.GetShort(Fuel);
1006  Brewingstand->SetRemainingFuel(tb);
1007  }
1008 
1009  // Load slots:
1010  for (int Child = a_NBT.GetFirstChild(Items); Child != -1; Child = a_NBT.GetNextSibling(Child))
1011  {
1012  int Slot = a_NBT.FindChildByName(Child, "Slot");
1013  if ((Slot < 0) || (a_NBT.GetType(Slot) != TAG_Byte))
1014  {
1015  continue;
1016  }
1017  cItem Item;
1018  if (LoadItemFromNBT(Item, a_NBT, Child))
1019  {
1020  Brewingstand->SetSlot(a_NBT.GetByte(Slot), Item);
1021  }
1022  } // for itr - ItemDefs[]
1023 
1024  // Load brewing time:
1025  int BrewTime = a_NBT.FindChildByName(a_TagIdx, "BrewTime");
1026  if (BrewTime >= 0)
1027  {
1028  Int16 tb = a_NBT.GetShort(BrewTime);
1029  Brewingstand->SetTimeBrewed(tb);
1030  }
1031 
1032  // Restart brewing:
1033  Brewingstand->LoadRecipes();
1034  Brewingstand->ContinueBrewing();
1035  return Brewingstand;
1036 }
1037 
1038 
1039 
1040 
1041 
1042 OwnedBlockEntity cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1043 {
1044  // Check if the data has a proper type:
1045  // Note that older Cuberite code used "TrappedChest" for trapped chests; new code mimics vanilla and uses "Chest" throughout, but we allow migration here:
1046  static const AStringVector expectedTypes({ "Chest", "TrappedChest", "minecraft:chest" });
1047  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1048  {
1049  return nullptr;
1050  }
1051 
1052  int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
1053  if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
1054  {
1055  return nullptr; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
1056  }
1057  auto Chest = std::make_unique<cChestEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1058  LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items);
1059  return Chest;
1060 }
1061 
1062 
1063 
1064 
1065 
1066 OwnedBlockEntity cWSSAnvil::LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1067 {
1068  // Check if the data has a proper type:
1069  static const AStringVector expectedTypes({ "Control", "minecraft:command_block" });
1070  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1071  {
1072  return nullptr;
1073  }
1074 
1075  auto CmdBlock = std::make_unique<cCommandBlockEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1076 
1077  int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command");
1078  if (currentLine >= 0)
1079  {
1080  CmdBlock->SetCommand(a_NBT.GetString(currentLine));
1081  }
1082 
1083  currentLine = a_NBT.FindChildByName(a_TagIdx, "SuccessCount");
1084  if (currentLine >= 0)
1085  {
1086  CmdBlock->SetResult(static_cast<NIBBLETYPE>(a_NBT.GetInt(currentLine)));
1087  }
1088 
1089  currentLine = a_NBT.FindChildByName(a_TagIdx, "LastOutput");
1090  if (currentLine >= 0)
1091  {
1092  CmdBlock->SetLastOutput(a_NBT.GetString(currentLine));
1093  }
1094 
1095  // TODO 2014-01-18 xdot: Figure out what TrackOutput is and parse it.
1096 
1097  return CmdBlock;
1098 }
1099 
1100 
1101 
1102 
1103 
1104 OwnedBlockEntity cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1105 {
1106  // Check if the data has a proper type:
1107  static const AStringVector expectedTypes({ "Trap", "minecraft:dispenser" });
1108  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1109  {
1110  return nullptr;
1111  }
1112 
1113  int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
1114  if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
1115  {
1116  return nullptr; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this
1117  }
1118  auto Dispenser = std::make_unique<cDispenserEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1119  LoadItemGridFromNBT(Dispenser->GetContents(), a_NBT, Items);
1120  return Dispenser;
1121 }
1122 
1123 
1124 
1125 
1126 
1127 OwnedBlockEntity cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1128 {
1129  // Check if the data has a proper type:
1130  static const AStringVector expectedTypes({ "Dropper", "minecraft:dropper" });
1131  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1132  {
1133  return nullptr;
1134  }
1135 
1136  int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
1137  if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
1138  {
1139  return nullptr; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this
1140  }
1141  auto Dropper = std::make_unique<cDropperEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1142  LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items);
1143  return Dropper;
1144 }
1145 
1146 
1147 
1148 
1149 
1150 OwnedBlockEntity cWSSAnvil::LoadEnchantingTableFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1151 {
1152  // Check if the data has a proper type:
1153  static const AStringVector expectedTypes({ "EnchantingTable", "minecraft:enchanting_table" });
1154  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1155  {
1156  return nullptr;
1157  }
1158 
1159  AString CustomName;
1160  int currentLine = a_NBT.FindChildByName(a_TagIdx, "CustomName");
1161  if (currentLine >= 0)
1162  {
1163  if (a_NBT.GetType(currentLine) == TAG_String)
1164  {
1165  CustomName = a_NBT.GetString(currentLine);
1166  }
1167  }
1168  return std::make_unique<cEnchantingTableEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World, CustomName);
1169 }
1170 
1171 
1172 
1173 
1174 
1175 OwnedBlockEntity cWSSAnvil::LoadEnderChestFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1176 {
1177  // Check if the data has a proper type:
1178  static const AStringVector expectedTypes({ "EnderChest", "minecraft:ender_chest" });
1179  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1180  {
1181  return nullptr;
1182  }
1183  return std::make_unique<cEnderChestEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1184 }
1185 
1186 
1187 
1188 
1189 
1190 OwnedBlockEntity cWSSAnvil::LoadEndPortalFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1191 {
1192  // Check if the data has a proper type:
1193  static const AStringVector expectedTypes({ "EndPortal", "minecraft:end_portal" });
1194  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1195  {
1196  return nullptr;
1197  }
1198  return std::make_unique<cEndPortalEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1199 }
1200 
1201 
1202 
1203 
1204 
1205 OwnedBlockEntity cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1206 {
1207  // Check if the data has a proper type:
1208  static const AStringVector expectedTypes({ "FlowerPot", "minecraft:flower_pot" });
1209  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1210  {
1211  return nullptr;
1212  }
1213 
1214  auto FlowerPot = std::make_unique<cFlowerPotEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1215  cItem Item;
1216 
1217  int currentLine = a_NBT.FindChildByName(a_TagIdx, "Item");
1218  if (currentLine >= 0)
1219  {
1220  if (a_NBT.GetType(currentLine) == TAG_String)
1221  {
1222  StringToItem(a_NBT.GetString(currentLine), Item);
1223  }
1224  else if (a_NBT.GetType(currentLine) == TAG_Int)
1225  {
1226  Item.m_ItemType = static_cast<short>(a_NBT.GetInt(currentLine));
1227  }
1228  }
1229 
1230  currentLine = a_NBT.FindChildByName(a_TagIdx, "Data");
1231  if ((currentLine >= 0) && (a_NBT.GetType(currentLine) == TAG_Int))
1232  {
1233  Item.m_ItemDamage = static_cast<short>(a_NBT.GetInt(currentLine));
1234  }
1235 
1236  FlowerPot->SetItem(Item);
1237  return FlowerPot;
1238 }
1239 
1240 
1241 
1242 
1243 
1244 OwnedBlockEntity cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1245 {
1246  // Check if the data has a proper type:
1247  static const AStringVector expectedTypes({ "Furnace", "minecraft:furnace" });
1248  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1249  {
1250  return nullptr;
1251  }
1252 
1253  int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
1254  if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
1255  {
1256  return nullptr; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this
1257  }
1258 
1259  auto Furnace = std::make_unique<cFurnaceEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1260  Furnace->SetLoading(true);
1261 
1262  // Load slots:
1263  for (int Child = a_NBT.GetFirstChild(Items); Child != -1; Child = a_NBT.GetNextSibling(Child))
1264  {
1265  int Slot = a_NBT.FindChildByName(Child, "Slot");
1266  if ((Slot < 0) || (a_NBT.GetType(Slot) != TAG_Byte))
1267  {
1268  continue;
1269  }
1270  cItem Item;
1271  if (LoadItemFromNBT(Item, a_NBT, Child))
1272  {
1273  Furnace->SetSlot(a_NBT.GetByte(Slot), Item);
1274  }
1275  } // for itr - ItemDefs[]
1276 
1277  // Load burn time:
1278  int BurnTime = a_NBT.FindChildByName(a_TagIdx, "BurnTime");
1279  if (BurnTime >= 0)
1280  {
1281  Int16 bt = a_NBT.GetShort(BurnTime);
1282  // Anvil doesn't store the time that the fuel can burn. We simply "reset" the current value to be the 100%
1283  Furnace->SetBurnTimes(bt, 0);
1284  }
1285 
1286  // Load cook time:
1287  int CookTime = a_NBT.FindChildByName(a_TagIdx, "CookTime");
1288  if (CookTime >= 0)
1289  {
1290  Int16 ct = a_NBT.GetShort(CookTime);
1291  // Anvil doesn't store the time that an item takes to cook. We simply use the default - 10 seconds (200 ticks)
1292  Furnace->SetCookTimes(200, ct);
1293  }
1294  // Restart cooking:
1295  Furnace->ContinueCooking();
1296  Furnace->SetLoading(false);
1297  return Furnace;
1298 }
1299 
1300 
1301 
1302 
1303 
1304 OwnedBlockEntity cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1305 {
1306  // Check if the data has a proper type:
1307  static const AStringVector expectedTypes({ "Hopper", "minecraft:hopper" });
1308  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1309  {
1310  return nullptr;
1311  }
1312 
1313  int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
1314  if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
1315  {
1316  return nullptr; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this
1317  }
1318  auto Hopper = std::make_unique<cHopperEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1319  LoadItemGridFromNBT(Hopper->GetContents(), a_NBT, Items);
1320  return Hopper;
1321 }
1322 
1323 
1324 
1325 
1326 
1327 OwnedBlockEntity cWSSAnvil::LoadJukeboxFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1328 {
1329  // Check if the data has a proper type:
1330  static const AStringVector expectedTypes({ "RecordPlayer", "minecraft:jukebox" });
1331  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1332  {
1333  return nullptr;
1334  }
1335 
1336  auto Jukebox = std::make_unique<cJukeboxEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1337  int Record = a_NBT.FindChildByName(a_TagIdx, "Record");
1338  if (Record >= 0)
1339  {
1340  Jukebox->SetRecord(a_NBT.GetInt(Record));
1341  }
1342  return Jukebox;
1343 }
1344 
1345 
1346 
1347 
1348 
1349 OwnedBlockEntity cWSSAnvil::LoadMobSpawnerFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1350 {
1351  // Check if the data has a proper type:
1352  static const AStringVector expectedTypes({ "MobSpawner", "minecraft:mob_spawner" });
1353  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1354  {
1355  return nullptr;
1356  }
1357 
1358  auto MobSpawner = std::make_unique<cMobSpawnerEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1359 
1360  // Load entity type
1361  int Type = a_NBT.FindChildByName(a_TagIdx, "EntityId");
1362  if ((Type >= 0) && (a_NBT.GetType(Type) == TAG_String))
1363  {
1364  const auto StatInfo = NamespaceSerializer::SplitNamespacedID(a_NBT.GetStringView(Type));
1365  if (StatInfo.first == NamespaceSerializer::Namespace::Unknown)
1366  {
1367  return nullptr;
1368  }
1369 
1370  eMonsterType MonsterType = NamespaceSerializer::ToMonsterType(StatInfo.second);
1371  if (MonsterType != eMonsterType::mtInvalidType)
1372  {
1373  MobSpawner->SetEntity(MonsterType);
1374  }
1375  }
1376 
1377  // Load spawn count:
1378  int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "SpawnCount");
1379  if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
1380  {
1381  MobSpawner->SetSpawnCount(a_NBT.GetShort(CurrentLine));
1382  }
1383 
1384  // Load spawn range:
1385  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "SpawnRange");
1386  if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
1387  {
1388  MobSpawner->SetSpawnRange(a_NBT.GetShort(CurrentLine));
1389  }
1390 
1391  // Load delay:
1392  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Delay");
1393  if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
1394  {
1395  MobSpawner->SetSpawnDelay(a_NBT.GetShort(CurrentLine));
1396  }
1397 
1398  // Load delay range:
1399  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "MinSpawnDelay");
1400  if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
1401  {
1402  MobSpawner->SetMinSpawnDelay(a_NBT.GetShort(CurrentLine));
1403  }
1404 
1405  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "MaxSpawnDelay");
1406  if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
1407  {
1408  MobSpawner->SetMaxSpawnDelay(a_NBT.GetShort(CurrentLine));
1409  }
1410 
1411  // Load MaxNearbyEntities:
1412  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "MaxNearbyEntities");
1413  if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
1414  {
1415  MobSpawner->SetMaxNearbyEntities(a_NBT.GetShort(CurrentLine));
1416  }
1417 
1418  // Load RequiredPlayerRange:
1419  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "RequiredPlayerRange");
1420  if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
1421  {
1422  MobSpawner->SetRequiredPlayerRange(a_NBT.GetShort(CurrentLine));
1423  }
1424 
1425 
1426  return MobSpawner;
1427 }
1428 
1429 
1430 
1431 
1432 
1433 OwnedBlockEntity cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1434 {
1435  // Check if the data has a proper type:
1436  static const AStringVector expectedTypes({ "Skull", "minecraft:skull" });
1437  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1438  {
1439  return nullptr;
1440  }
1441 
1442  auto MobHead = std::make_unique<cMobHeadEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1443 
1444  int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType");
1445  if (currentLine >= 0)
1446  {
1447  MobHead->SetType(static_cast<eMobHeadType>(a_NBT.GetByte(currentLine)));
1448  }
1449 
1450  currentLine = a_NBT.FindChildByName(a_TagIdx, "Rot");
1451  if (currentLine >= 0)
1452  {
1453  MobHead->SetRotation(static_cast<eMobHeadRotation>(a_NBT.GetByte(currentLine)));
1454  }
1455 
1456  int ownerLine = a_NBT.FindChildByName(a_TagIdx, "Owner");
1457  if (ownerLine >= 0)
1458  {
1459  AString OwnerName, OwnerTexture, OwnerTextureSignature;
1460  cUUID OwnerUUID;
1461 
1462  currentLine = a_NBT.FindChildByName(ownerLine, "Id");
1463  if (currentLine >= 0)
1464  {
1465  OwnerUUID.FromString(a_NBT.GetString(currentLine));
1466  }
1467 
1468  currentLine = a_NBT.FindChildByName(ownerLine, "Name");
1469  if (currentLine >= 0)
1470  {
1471  OwnerName = a_NBT.GetString(currentLine);
1472  }
1473 
1474  int textureLine = a_NBT.GetFirstChild( // The first texture of
1475  a_NBT.FindChildByName( // The texture list of
1476  a_NBT.FindChildByName( // The Properties compound of
1477  ownerLine, // The Owner compound
1478  "Properties"
1479  ),
1480  "textures"
1481  )
1482  );
1483  if (textureLine >= 0)
1484  {
1485  currentLine = a_NBT.FindChildByName(textureLine, "Signature");
1486  if (currentLine >= 0)
1487  {
1488  OwnerTextureSignature = a_NBT.GetString(currentLine);
1489  }
1490 
1491  currentLine = a_NBT.FindChildByName(textureLine, "Value");
1492  if (currentLine >= 0)
1493  {
1494  OwnerTexture = a_NBT.GetString(currentLine);
1495  }
1496  }
1497  MobHead->SetOwner(OwnerUUID, OwnerName, OwnerTexture, OwnerTextureSignature);
1498  }
1499 
1500  return MobHead;
1501 }
1502 
1503 
1504 
1505 
1506 
1507 OwnedBlockEntity cWSSAnvil::LoadNoteBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1508 {
1509  // Check if the data has a proper type:
1510  static const AStringVector expectedTypes({ "Music", "minecraft:noteblock" });
1511  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1512  {
1513  return nullptr;
1514  }
1515 
1516  auto NoteBlock = std::make_unique<cNoteEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1517  int note = a_NBT.FindChildByName(a_TagIdx, "note");
1518  if (note >= 0)
1519  {
1520  NoteBlock->SetNote(a_NBT.GetByte(note));
1521  }
1522  return NoteBlock;
1523 }
1524 
1525 
1526 
1527 
1528 
1529 OwnedBlockEntity cWSSAnvil::LoadSignFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
1530 {
1531  // Check if the data has a proper type:
1532  static const AStringVector expectedTypes({ "Sign", "minecraft:sign" });
1533  if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos))
1534  {
1535  return nullptr;
1536  }
1537 
1538  auto Sign = std::make_unique<cSignEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
1539 
1540  int currentLine = a_NBT.FindChildByName(a_TagIdx, "Text1");
1541  if (currentLine >= 0)
1542  {
1543  Sign->SetLine(0, DecodeSignLine(a_NBT.GetString(currentLine)));
1544  }
1545 
1546  currentLine = a_NBT.FindChildByName(a_TagIdx, "Text2");
1547  if (currentLine >= 0)
1548  {
1549  Sign->SetLine(1, DecodeSignLine(a_NBT.GetString(currentLine)));
1550  }
1551 
1552  currentLine = a_NBT.FindChildByName(a_TagIdx, "Text3");
1553  if (currentLine >= 0)
1554  {
1555  Sign->SetLine(2, DecodeSignLine(a_NBT.GetString(currentLine)));
1556  }
1557 
1558  currentLine = a_NBT.FindChildByName(a_TagIdx, "Text4");
1559  if (currentLine >= 0)
1560  {
1561  Sign->SetLine(3, DecodeSignLine(a_NBT.GetString(currentLine)));
1562  }
1563 
1564  return Sign;
1565 }
1566 
1567 
1568 
1569 
1570 
1571 void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const std::string_view a_EntityName)
1572 {
1573  typedef void (cWSSAnvil::*EntityLoaderFunc)(cEntityList &, const cParsedNBT &, int a_EntityTagIdx);
1574  typedef std::map<std::string_view, EntityLoaderFunc> EntityLoaderMap;
1575  static const EntityLoaderMap EntityTypeToFunction
1576  {
1577  { "Boat", &cWSSAnvil::LoadBoatFromNBT },
1578  { "minecraft:boat", &cWSSAnvil::LoadBoatFromNBT },
1579  { "EnderCrystal", &cWSSAnvil::LoadEnderCrystalFromNBT },
1580  { "minecraft:ender_crystal", &cWSSAnvil::LoadEnderCrystalFromNBT },
1581  { "FallingBlock", &cWSSAnvil::LoadFallingBlockFromNBT },
1582  { "minecraft:falling_block", &cWSSAnvil::LoadFallingBlockFromNBT },
1583  { "Minecart", &cWSSAnvil::LoadOldMinecartFromNBT },
1584  { "MinecartChest", &cWSSAnvil::LoadMinecartCFromNBT },
1585  { "minecraft:chest_minecart", &cWSSAnvil::LoadMinecartCFromNBT },
1586  { "MinecartFurnace", &cWSSAnvil::LoadMinecartFFromNBT },
1587  { "minecraft:furnace_minecart", &cWSSAnvil::LoadMinecartFFromNBT },
1588  { "MinecartTNT", &cWSSAnvil::LoadMinecartTFromNBT },
1589  { "minecraft:tnt_minecart", &cWSSAnvil::LoadMinecartTFromNBT },
1590  { "MinecartHopper", &cWSSAnvil::LoadMinecartHFromNBT },
1591  { "minecraft:hopper_minecart", &cWSSAnvil::LoadMinecartHFromNBT },
1592  { "MinecartRideable", &cWSSAnvil::LoadMinecartRFromNBT },
1593  { "minecraft:minecart", &cWSSAnvil::LoadMinecartRFromNBT },
1594  { "Item", &cWSSAnvil::LoadPickupFromNBT },
1595  { "minecraft:item", &cWSSAnvil::LoadPickupFromNBT },
1596  { "Painting", &cWSSAnvil::LoadPaintingFromNBT },
1597  { "minecraft:painting", &cWSSAnvil::LoadPaintingFromNBT },
1598  { "PrimedTnt", &cWSSAnvil::LoadTNTFromNBT },
1599  { "minecraft:tnt", &cWSSAnvil::LoadTNTFromNBT },
1600  { "XPOrb", &cWSSAnvil::LoadExpOrbFromNBT },
1601  { "minecraft:xp_orb", &cWSSAnvil::LoadExpOrbFromNBT },
1602  { "ItemFrame", &cWSSAnvil::LoadItemFrameFromNBT },
1603  { "minecraft:item_frame", &cWSSAnvil::LoadItemFrameFromNBT },
1604  { "LeashKnot", &cWSSAnvil::LoadLeashKnotFromNBT },
1605  { "minecraft:leash_knot", &cWSSAnvil::LoadLeashKnotFromNBT },
1606  { "Arrow", &cWSSAnvil::LoadArrowFromNBT },
1607  { "minecraft:arrow", &cWSSAnvil::LoadArrowFromNBT },
1608  { "SplashPotion", &cWSSAnvil::LoadSplashPotionFromNBT },
1609  { "minecraft:potion", &cWSSAnvil::LoadSplashPotionFromNBT },
1610  { "Snowball", &cWSSAnvil::LoadSnowballFromNBT },
1611  { "minecraft:snowball", &cWSSAnvil::LoadSnowballFromNBT },
1612  { "Egg", &cWSSAnvil::LoadEggFromNBT },
1613  { "minecraft:egg", &cWSSAnvil::LoadEggFromNBT },
1614  { "Fireball", &cWSSAnvil::LoadFireballFromNBT },
1615  { "minecraft:fireball", &cWSSAnvil::LoadFireballFromNBT },
1616  { "SmallFireball", &cWSSAnvil::LoadFireChargeFromNBT },
1617  { "minecraft:small_fireball", &cWSSAnvil::LoadFireChargeFromNBT },
1618  { "ThrownEnderpearl", &cWSSAnvil::LoadThrownEnderpearlFromNBT },
1619  { "minecraft:ender_pearl", &cWSSAnvil::LoadThrownEnderpearlFromNBT }
1620  };
1621 
1622  // TODO: flatten monster\projectile into one entity type enum
1623 
1624  const auto it = EntityTypeToFunction.find(a_EntityName);
1625  if (it != EntityTypeToFunction.end())
1626  {
1627  (this->*it->second)(a_Entities, a_NBT, a_EntityTagIdx);
1628  return;
1629  }
1630 
1631  const auto StatInfo = NamespaceSerializer::SplitNamespacedID(a_EntityName);
1632  if (StatInfo.first == NamespaceSerializer::Namespace::Unknown)
1633  {
1634  return;
1635  }
1636 
1637  switch (NamespaceSerializer::ToMonsterType(StatInfo.second))
1638  {
1639  case mtBat: return LoadBatFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1640  case mtBlaze: return LoadBlazeFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1641  case mtCat: return LoadCatFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1642  case mtCaveSpider: return LoadCaveSpiderFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1643  case mtChicken: return LoadChickenFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1644  case mtCod: return LoadCodFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1645  case mtCow: return LoadCowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1646  case mtCreeper: return LoadCreeperFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1647  case mtDolphin: return LoadDolphinFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1648  case mtDonkey: return LoadDonkeyFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1649  case mtDrowned: return LoadDrownedFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1650  case mtElderGuardian: return LoadElderGuardianFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1651  case mtEnderDragon: return LoadEnderDragonFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1652  case mtEnderman: return LoadEndermanFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1653  case mtEndermite: return LoadEndermiteFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1654  case mtEvoker: return LoadEvokerFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1655  case mtFox: return LoadFoxFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1656  case mtGhast: return LoadGhastFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1657  case mtGiant: return LoadGiantFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1658  case mtGuardian: return LoadGuardianFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1659  case mtHorse: return LoadHorseFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1660  case mtHoglin: return LoadHoglinFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1661  case mtHusk: return LoadHuskFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1662  case mtIllusioner: return LoadIllusionerFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1663  case mtIronGolem: return LoadIronGolemFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1664  case mtLlama: return LoadLlamaFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1665  case mtMagmaCube: return LoadMagmaCubeFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1666  case mtMooshroom: return LoadMooshroomFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1667  case mtMule: return LoadMuleFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1668  case mtOcelot: return LoadOcelotFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1669  case mtPanda: return LoadPandaFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1670  case mtParrot: return LoadParrotFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1671  case mtPhantom: return LoadPhantomFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1672  case mtPig: return LoadPigFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1673  case mtPiglin: return LoadPiglinFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1674  case mtPiglinBrute: return LoadPiglinBruteFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1675  case mtPillager: return LoadPillagerFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1676  case mtPolarBear: return LoadPolarBearFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1677  case mtPufferfish: return LoadPufferfishFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1678  case mtRabbit: return LoadRabbitFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1679  case mtRavager: return LoadRavagerFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1680  case mtSalmon: return LoadSalmonFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1681  case mtSheep: return LoadSheepFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1682  case mtShulker: return LoadShulkerFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1683  case mtSilverfish: return LoadSilverfishFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1684  case mtSkeleton: return LoadSkeletonFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1685  case mtSkeletonHorse: return LoadSkeletonHorseFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1686  case mtSlime: return LoadSlimeFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1687  case mtSnowGolem: return LoadSnowGolemFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1688  case mtSpider: return LoadSpiderFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1689  case mtSquid: return LoadSquidFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1690  case mtStray: return LoadStrayFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1691  case mtStrider: return LoadStriderFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1692  case mtTraderLlama: return LoadTraderLlamaFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1693  case mtTropicalFish: return LoadTropicalFishFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1694  case mtTurtle: return LoadTurtleFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1695  case mtVex: return LoadVexFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1696  case mtVillager: return LoadVillagerFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1697  case mtVindicator: return LoadVindicatorFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1698  case mtWanderingTrader: return LoadWanderingTraderFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1699  case mtWitch: return LoadWitchFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1700  case mtWither: return LoadWitherFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1701  case mtWitherSkeleton: return LoadWitherSkeletonFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1702  case mtWolf: return LoadWolfFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1703  case mtZoglin: return LoadZoglinFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1704  case mtZombie: return LoadZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1705  case mtZombieHorse: return LoadZombieHorseFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1706  case mtZombifiedPiglin: return LoadZombifiedPiglinFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1707  case mtZombieVillager: return LoadZombieVillagerFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
1708  case mtInvalidType: break;
1709  }
1710 }
1711 
1712 
1713 
1714 
1715 
1716 void cWSSAnvil::LoadOldMinecartFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1717 {
1718  // It is a minecart, old style, find out the type:
1719  int TypeTag = a_NBT.FindChildByName(a_TagIdx, "Type");
1720  if ((TypeTag < 0) || (a_NBT.GetType(TypeTag) != TAG_Int))
1721  {
1722  return;
1723  }
1724  int MinecartType = a_NBT.GetInt(TypeTag);
1725  switch (MinecartType)
1726  {
1727  case 0: LoadMinecartRFromNBT(a_Entities, a_NBT, a_TagIdx); break; // Rideable minecart
1728  case 1: LoadMinecartCFromNBT(a_Entities, a_NBT, a_TagIdx); break; // Minecart with chest
1729  case 2: LoadMinecartFFromNBT(a_Entities, a_NBT, a_TagIdx); break; // Minecart with furnace
1730  case 3: LoadMinecartTFromNBT(a_Entities, a_NBT, a_TagIdx); break; // Minecart with TNT
1731  case 4: LoadMinecartHFromNBT(a_Entities, a_NBT, a_TagIdx); break; // Minecart with Hopper
1732  default: LOGWARNING("cWSSAnvil::LoadOldMinecartFromNBT: Unhandled minecart type (%d)", MinecartType); break;
1733  }
1734 }
1735 
1736 
1737 
1738 
1739 
1740 void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1741 {
1742  auto Boat = std::make_unique<cBoat>(Vector3d(), cBoat::bmOak);
1743  if (!LoadEntityBaseFromNBT(*Boat.get(), a_NBT, a_TagIdx))
1744  {
1745  return;
1746  }
1747 
1748  int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Type");
1749  if (TypeIdx > 0)
1750  {
1751  Boat->SetMaterial(cBoat::StringToMaterial(a_NBT.GetString(TypeIdx)));
1752  }
1753  a_Entities.emplace_back(std::move(Boat));
1754 }
1755 
1756 
1757 
1758 
1759 
1760 void cWSSAnvil::LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1761 {
1762  bool DisplayBeam = false, ShowBottom = false;
1763  Vector3i BeamTarget;
1764  int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "BeamTarget");
1765  if (CurrentLine > 0)
1766  {
1767  DisplayBeam = true;
1768  if (a_NBT.GetType(CurrentLine) == TAG_Compound)
1769  {
1770  int CoordinateLine = a_NBT.FindChildByName(CurrentLine, "X");
1771  if (CoordinateLine > 0)
1772  {
1773  BeamTarget.x = a_NBT.GetInt(CoordinateLine);
1774  }
1775  CoordinateLine = a_NBT.FindChildByName(CurrentLine, "Y");
1776  if (CoordinateLine > 0)
1777  {
1778  BeamTarget.y = a_NBT.GetInt(CoordinateLine);
1779  }
1780  CoordinateLine = a_NBT.FindChildByName(CurrentLine, "Z");
1781  if (CoordinateLine > 0)
1782  {
1783  BeamTarget.z = a_NBT.GetInt(CoordinateLine);
1784  }
1785  }
1786  }
1787  CurrentLine = a_NBT.FindChildByName(a_TagIdx, "ShowBottom");
1788  if (CurrentLine > 0)
1789  {
1790  ShowBottom = a_NBT.GetByte(CurrentLine) == 1;
1791  }
1792 
1793  auto EnderCrystal = std::make_unique<cEnderCrystal>(Vector3d(), BeamTarget, DisplayBeam, ShowBottom);
1794  if (!LoadEntityBaseFromNBT(*EnderCrystal.get(), a_NBT, a_TagIdx))
1795  {
1796  return;
1797  }
1798 
1799  a_Entities.emplace_back(std::move(EnderCrystal));
1800 }
1801 
1802 
1803 
1804 
1805 
1806 void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1807 {
1808  int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "TileID");
1809  int MetaIdx = a_NBT.FindChildByName(a_TagIdx, "Data");
1810 
1811  if ((TypeIdx < 0) || (MetaIdx < 0))
1812  {
1813  return;
1814  }
1815 
1816  BLOCKTYPE Type = static_cast<BLOCKTYPE>(a_NBT.GetInt(TypeIdx));
1817  NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_NBT.GetByte(MetaIdx));
1818 
1819  auto FallingBlock = std::make_unique<cFallingBlock>(Vector3i(0, 0, 0), Type, Meta);
1820  if (!LoadEntityBaseFromNBT(*FallingBlock.get(), a_NBT, a_TagIdx))
1821  {
1822  return;
1823  }
1824  a_Entities.emplace_back(std::move(FallingBlock));
1825 }
1826 
1827 
1828 
1829 
1830 
1831 void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1832 {
1833  auto Minecart = std::make_unique<cRideableMinecart>(Vector3d(), cItem(), 1); // TODO: Load the block and the height
1834  if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
1835  {
1836  return;
1837  }
1838  a_Entities.emplace_back(std::move(Minecart));
1839 }
1840 
1841 
1842 
1843 
1844 
1845 void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1846 {
1847  int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
1848  if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
1849  {
1850  return; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
1851  }
1852  auto Minecart = std::make_unique<cMinecartWithChest>(Vector3d());
1853  if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
1854  {
1855  return;
1856  }
1857  for (int Child = a_NBT.GetFirstChild(Items); Child != -1; Child = a_NBT.GetNextSibling(Child))
1858  {
1859  int Slot = a_NBT.FindChildByName(Child, "Slot");
1860  if ((Slot < 0) || (a_NBT.GetType(Slot) != TAG_Byte))
1861  {
1862  continue;
1863  }
1864  cItem Item;
1865  if (LoadItemFromNBT(Item, a_NBT, Child))
1866  {
1867  Minecart->SetSlot(a_NBT.GetByte(Slot), Item);
1868  }
1869  } // for itr - ItemDefs[]
1870  a_Entities.emplace_back(std::move(Minecart));
1871 }
1872 
1873 
1874 
1875 
1876 
1877 void cWSSAnvil::LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1878 {
1879  auto Minecart = std::make_unique<cMinecartWithFurnace>(Vector3d());
1880  if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
1881  {
1882  return;
1883  }
1884 
1885  // TODO: Load the Push and Fuel tags
1886 
1887  a_Entities.emplace_back(std::move(Minecart));
1888 }
1889 
1890 
1891 
1892 
1893 
1894 void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1895 {
1896  auto Minecart = std::make_unique<cMinecartWithTNT>(Vector3d());
1897  if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
1898  {
1899  return;
1900  }
1901 
1902  // TODO: Everything to do with TNT carts
1903 
1904  a_Entities.emplace_back(std::move(Minecart));
1905 }
1906 
1907 
1908 
1909 
1910 
1911 void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1912 {
1913  auto Minecart = std::make_unique<cMinecartWithHopper>(Vector3d());
1914  if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
1915  {
1916  return;
1917  }
1918 
1919  // TODO: Everything to do with hopper carts
1920 
1921  a_Entities.emplace_back(std::move(Minecart));
1922 }
1923 
1924 
1925 
1926 
1927 
1928 void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1929 {
1930  // Load item:
1931  int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
1932  if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
1933  {
1934  return;
1935  }
1936  cItem Item;
1937  if (!LoadItemFromNBT(Item, a_NBT, ItemTag))
1938  {
1939  return;
1940  }
1941 
1942  auto Pickup = std::make_unique<cPickup>(Vector3d(), Item, false); // Pickup delay doesn't matter, just say false
1943  if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx))
1944  {
1945  return;
1946  }
1947 
1948  // Load age:
1949  int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
1950  if (Age > 0)
1951  {
1952  Pickup->SetAge(a_NBT.GetShort(Age));
1953  }
1954 
1955  a_Entities.emplace_back(std::move(Pickup));
1956 }
1957 
1958 
1959 
1960 
1961 
1962 void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1963 {
1964  auto TNT = std::make_unique<cTNTEntity>(Vector3d(), 0);
1965  if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
1966  {
1967  return;
1968  }
1969 
1970  // Load Fuse Ticks:
1971  int FuseTicks = a_NBT.FindChildByName(a_TagIdx, "Fuse");
1972  if (FuseTicks > 0)
1973  {
1974  TNT->SetFuseTicks(a_NBT.GetByte(FuseTicks));
1975  }
1976 
1977  a_Entities.emplace_back(std::move(TNT));
1978 }
1979 
1980 
1981 
1982 
1983 
1984 void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
1985 {
1986  auto ExpOrb = std::make_unique<cExpOrb>(Vector3d(), 0);
1987  if (!LoadEntityBaseFromNBT(*ExpOrb.get(), a_NBT, a_TagIdx))
1988  {
1989  return;
1990  }
1991 
1992  // Load Age:
1993  int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
1994  if (Age > 0)
1995  {
1996  ExpOrb->SetAge(a_NBT.GetShort(Age));
1997  }
1998 
1999  // Load Reward (Value):
2000  int Reward = a_NBT.FindChildByName(a_TagIdx, "Value");
2001  if (Reward > 0)
2002  {
2003  ExpOrb->SetReward(a_NBT.GetShort(Reward));
2004  }
2005 
2006  a_Entities.emplace_back(std::move(ExpOrb));
2007 }
2008 
2009 
2010 
2011 
2012 
2013 void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx)
2014 {
2015  // "Facing" tag is the prime source of the Facing; if not available, translate from older "Direction" or "Dir"
2016  int Facing = a_NBT.FindChildByName(a_TagIdx, "Facing");
2017  if (Facing < 0)
2018  {
2019  return;
2020  }
2021 
2022  a_Hanging.SetProtocolFacing(a_NBT.GetByte(Facing));
2023 
2024  int TileX = a_NBT.FindChildByName(a_TagIdx, "TileX");
2025  int TileY = a_NBT.FindChildByName(a_TagIdx, "TileY");
2026  int TileZ = a_NBT.FindChildByName(a_TagIdx, "TileZ");
2027  if ((TileX > 0) && (TileY > 0) && (TileZ > 0))
2028  {
2029  a_Hanging.SetPosition(
2030  static_cast<double>(a_NBT.GetInt(TileX)),
2031  static_cast<double>(a_NBT.GetInt(TileY)),
2032  static_cast<double>(a_NBT.GetInt(TileZ))
2033  );
2034  }
2035 }
2036 
2037 
2038 
2039 
2040 
2041 void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2042 {
2043  // Load item:
2044  int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
2045  if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
2046  {
2047  return;
2048  }
2049  cItem Item;
2050  if (!LoadItemFromNBT(Item, a_NBT, ItemTag))
2051  {
2052  return;
2053  }
2054 
2055  auto ItemFrame = std::make_unique<cItemFrame>(BLOCK_FACE_NONE, Vector3d());
2056  if (!LoadEntityBaseFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx))
2057  {
2058  return;
2059  }
2060  ItemFrame->SetItem(Item);
2061 
2062  LoadHangingFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx);
2063 
2064  // Load Rotation:
2065  int Rotation = a_NBT.FindChildByName(a_TagIdx, "ItemRotation");
2066  if (Rotation > 0)
2067  {
2068  ItemFrame->SetItemRotation(static_cast<Byte>(a_NBT.GetByte(Rotation)));
2069  }
2070 
2071  a_Entities.emplace_back(std::move(ItemFrame));
2072 }
2073 
2074 
2075 
2076 
2077 
2078 void cWSSAnvil::LoadLeashKnotFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2079 {
2080  auto LeashKnot = std::make_unique<cLeashKnot>(BLOCK_FACE_NONE, Vector3d());
2081 
2082  if (!LoadEntityBaseFromNBT(*LeashKnot.get(), a_NBT, a_TagIdx))
2083  {
2084  return;
2085  }
2086 
2087  LoadHangingFromNBT(*LeashKnot.get(), a_NBT, a_TagIdx);
2088 
2089  a_Entities.emplace_back(std::move(LeashKnot));
2090 }
2091 
2092 
2093 
2094 
2095 
2096 void cWSSAnvil::LoadPaintingFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2097 {
2098  // Load painting name:
2099  int MotiveTag = a_NBT.FindChildByName(a_TagIdx, "Motive");
2100  if ((MotiveTag < 0) || (a_NBT.GetType(MotiveTag) != TAG_String))
2101  {
2102  return;
2103  }
2104 
2105  auto Painting = std::make_unique<cPainting>(a_NBT.GetString(MotiveTag), BLOCK_FACE_NONE, Vector3d());
2106  if (!LoadEntityBaseFromNBT(*Painting.get(), a_NBT, a_TagIdx))
2107  {
2108  return;
2109  }
2110 
2111  LoadHangingFromNBT(*Painting.get(), a_NBT, a_TagIdx);
2112  a_Entities.emplace_back(std::move(Painting));
2113 }
2114 
2115 
2116 
2117 
2118 
2119 void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2120 {
2121  auto Arrow = std::make_unique<cArrowEntity>(nullptr, Vector3d(), Vector3d());
2122  if (!LoadProjectileBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx))
2123  {
2124  return;
2125  }
2126 
2127  // Load pickup state:
2128  int PickupIdx = a_NBT.FindChildByName(a_TagIdx, "pickup");
2129  if ((PickupIdx > 0) && (a_NBT.GetType(PickupIdx) == TAG_Byte))
2130  {
2131  Arrow->SetPickupState(static_cast<cArrowEntity::ePickupState>(a_NBT.GetByte(PickupIdx)));
2132  }
2133  else
2134  {
2135  // Try the older "player" tag:
2136  int PlayerIdx = a_NBT.FindChildByName(a_TagIdx, "player");
2137  if ((PlayerIdx > 0) && (a_NBT.GetType(PlayerIdx) == TAG_Byte))
2138  {
2139  Arrow->SetPickupState((a_NBT.GetByte(PlayerIdx) == 0) ? cArrowEntity::psNoPickup : cArrowEntity::psInSurvivalOrCreative);
2140  }
2141  }
2142 
2143  // Load damage:
2144  int DamageIdx = a_NBT.FindChildByName(a_TagIdx, "damage");
2145  if ((DamageIdx > 0) && (a_NBT.GetType(DamageIdx) == TAG_Double))
2146  {
2147  Arrow->SetDamageCoeff(a_NBT.GetDouble(DamageIdx));
2148  }
2149 
2150  // Load block hit:
2151  int InBlockXIdx = a_NBT.FindChildByName(a_TagIdx, "xTile");
2152  int InBlockYIdx = a_NBT.FindChildByName(a_TagIdx, "yTile");
2153  int InBlockZIdx = a_NBT.FindChildByName(a_TagIdx, "zTile");
2154  if ((InBlockXIdx > 0) && (InBlockYIdx > 0) && (InBlockZIdx > 0))
2155  {
2156  eTagType typeX = a_NBT.GetType(InBlockXIdx);
2157  if ((typeX == a_NBT.GetType(InBlockYIdx)) && (typeX == a_NBT.GetType(InBlockZIdx)))
2158  {
2159  switch (typeX)
2160  {
2161  case TAG_Int:
2162  {
2163  // Old MCS code used this, keep reading it for compatibility reasons:
2164  Arrow->SetBlockHit(Vector3i(a_NBT.GetInt(InBlockXIdx), a_NBT.GetInt(InBlockYIdx), a_NBT.GetInt(InBlockZIdx)));
2165  break;
2166  }
2167  case TAG_Short:
2168  {
2169  // Vanilla uses this
2170  Arrow->SetBlockHit(Vector3i(a_NBT.GetShort(InBlockXIdx), a_NBT.GetShort(InBlockYIdx), a_NBT.GetShort(InBlockZIdx)));
2171  break;
2172  }
2173  default:
2174  {
2175  // No hit block, the arrow is still flying?
2176  break;
2177  }
2178  }
2179  }
2180  }
2181 
2182  // Store the new arrow in the entities list:
2183  a_Entities.emplace_back(std::move(Arrow));
2184 }
2185 
2186 
2187 
2188 
2189 
2190 void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2191 {
2192  auto SplashPotion = std::make_unique<cSplashPotionEntity>(nullptr, Vector3d(), Vector3d(), cItem());
2193  if (!LoadProjectileBaseFromNBT(*SplashPotion.get(), a_NBT, a_TagIdx))
2194  {
2195  return;
2196  }
2197 
2198  int EffectDuration = a_NBT.FindChildByName(a_TagIdx, "EffectDuration");
2199  int EffectIntensity = a_NBT.FindChildByName(a_TagIdx, "EffectIntensity");
2200  int EffectDistanceModifier = a_NBT.FindChildByName(a_TagIdx, "EffectDistanceModifier");
2201 
2202  SplashPotion->SetEntityEffectType(static_cast<cEntityEffect::eType>(a_NBT.FindChildByName(a_TagIdx, "EffectType")));
2203  SplashPotion->SetEntityEffect(cEntityEffect(EffectDuration, static_cast<Int16>(EffectIntensity), EffectDistanceModifier));
2204  SplashPotion->SetPotionColor(a_NBT.FindChildByName(a_TagIdx, "PotionName"));
2205 
2206  // Store the new splash potion in the entities list:
2207  a_Entities.emplace_back(std::move(SplashPotion));
2208 }
2209 
2210 
2211 
2212 
2213 
2214 void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2215 {
2216  auto Snowball = std::make_unique<cThrownSnowballEntity>(nullptr, Vector3d(), Vector3d());
2217  if (!LoadProjectileBaseFromNBT(*Snowball.get(), a_NBT, a_TagIdx))
2218  {
2219  return;
2220  }
2221 
2222  // Store the new snowball in the entities list:
2223  a_Entities.emplace_back(std::move(Snowball));
2224 }
2225 
2226 
2227 
2228 
2229 
2230 void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2231 {
2232  auto Egg = std::make_unique<cThrownEggEntity>(nullptr, Vector3d(), Vector3d());
2233  if (!LoadProjectileBaseFromNBT(*Egg.get(), a_NBT, a_TagIdx))
2234  {
2235  return;
2236  }
2237 
2238  // Store the new egg in the entities list:
2239  a_Entities.emplace_back(std::move(Egg));
2240 }
2241 
2242 
2243 
2244 
2245 
2246 void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2247 {
2248  auto Fireball = std::make_unique<cGhastFireballEntity>(nullptr, Vector3d(), Vector3d());
2249  if (!LoadProjectileBaseFromNBT(*Fireball.get(), a_NBT, a_TagIdx))
2250  {
2251  return;
2252  }
2253 
2254  // Store the new fireball in the entities list:
2255  a_Entities.emplace_back(std::move(Fireball));
2256 }
2257 
2258 
2259 
2260 
2261 
2262 void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2263 {
2264  auto FireCharge = std::make_unique<cFireChargeEntity>(nullptr, Vector3d(), Vector3d());
2265  if (!LoadProjectileBaseFromNBT(*FireCharge.get(), a_NBT, a_TagIdx))
2266  {
2267  return;
2268  }
2269 
2270  // Store the new FireCharge in the entities list:
2271  a_Entities.emplace_back(std::move(FireCharge));
2272 }
2273 
2274 
2275 
2276 
2277 
2278 void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2279 {
2280  auto Enderpearl = std::make_unique<cThrownEnderPearlEntity>(nullptr, Vector3d(), Vector3d());
2281  if (!LoadProjectileBaseFromNBT(*Enderpearl.get(), a_NBT, a_TagIdx))
2282  {
2283  return;
2284  }
2285 
2286  // Store the new enderpearl in the entities list:
2287  a_Entities.emplace_back(std::move(Enderpearl));
2288 }
2289 
2290 
2291 
2292 
2293 
2294 void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2295 {
2296  auto Monster = std::make_unique<cBat>();
2297  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2298  {
2299  return;
2300  }
2301 
2302  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2303  {
2304  return;
2305  }
2306 
2307  a_Entities.emplace_back(std::move(Monster));
2308 }
2309 
2310 
2311 
2312 
2313 
2314 void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2315 {
2316  std::unique_ptr<cBlaze> Monster = std::make_unique<cBlaze>();
2317  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2318  {
2319  return;
2320  }
2321 
2322  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2323  {
2324  return;
2325  }
2326 
2327  a_Entities.emplace_back(std::move(Monster));
2328 }
2329 
2330 
2331 
2332 
2333 
2334 void cWSSAnvil::LoadCatFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2335 {
2336  // TODO
2337 }
2338 
2339 
2340 
2341 
2342 
2343 void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2344 {
2345  std::unique_ptr<cCaveSpider> Monster = std::make_unique<cCaveSpider>();
2346  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2347  {
2348  return;
2349  }
2350 
2351  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2352  {
2353  return;
2354  }
2355 
2356  a_Entities.emplace_back(std::move(Monster));
2357 }
2358 
2359 
2360 
2361 
2362 
2363 void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2364 {
2365  std::unique_ptr<cChicken> Monster = std::make_unique<cChicken>();
2366  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2367  {
2368  return;
2369  }
2370 
2371  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2372  {
2373  return;
2374  }
2375 
2376  a_Entities.emplace_back(std::move(Monster));
2377 }
2378 
2379 
2380 
2381 
2382 
2383 void cWSSAnvil::LoadCodFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2384 {
2385  // TODO
2386 }
2387 
2388 
2389 
2390 
2391 
2392 void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2393 {
2394  std::unique_ptr<cCow> Monster = std::make_unique<cCow>();
2395  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2396  {
2397  return;
2398  }
2399 
2400  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2401  {
2402  return;
2403  }
2404 
2405  a_Entities.emplace_back(std::move(Monster));
2406 }
2407 
2408 
2409 
2410 
2411 
2412 void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2413 {
2414  std::unique_ptr<cCreeper> Monster = std::make_unique<cCreeper>();
2415  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2416  {
2417  return;
2418  }
2419 
2420  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2421  {
2422  return;
2423  }
2424 
2425  a_Entities.emplace_back(std::move(Monster));
2426 }
2427 
2428 
2429 
2430 
2431 
2432 void cWSSAnvil::LoadDolphinFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2433 {
2434  // TODO
2435 }
2436 
2437 
2438 
2439 
2440 
2441 void cWSSAnvil::LoadDonkeyFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2442 {
2443  // TODO
2444 }
2445 
2446 
2447 
2448 
2449 
2450 void cWSSAnvil::LoadDrownedFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2451 {
2452  // TODO
2453 }
2454 
2455 
2456 
2457 
2458 
2459 void cWSSAnvil::LoadElderGuardianFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2460 {
2461  // TODO
2462 }
2463 
2464 
2465 
2466 
2467 
2468 void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2469 {
2470  std::unique_ptr<cEnderDragon> Monster = std::make_unique<cEnderDragon>();
2471  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2472  {
2473  return;
2474  }
2475 
2476  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2477  {
2478  return;
2479  }
2480 
2481  a_Entities.emplace_back(std::move(Monster));
2482 }
2483 
2484 
2485 
2486 
2487 
2488 void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2489 {
2490  std::unique_ptr<cEnderman> Monster = std::make_unique<cEnderman>();
2491  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2492  {
2493  return;
2494  }
2495 
2496  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2497  {
2498  return;
2499  }
2500 
2501  a_Entities.emplace_back(std::move(Monster));
2502 }
2503 
2504 
2505 
2506 
2507 
2508 void cWSSAnvil::LoadEndermiteFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2509 {
2510  // TODO
2511 }
2512 
2513 
2514 
2515 
2516 
2517 void cWSSAnvil::LoadEvokerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2518 {
2519  // TODO
2520 }
2521 
2522 
2523 
2524 
2525 
2526 void cWSSAnvil::LoadFoxFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2527 {
2528  // TODO
2529 }
2530 
2531 
2532 
2533 
2534 
2535 void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2536 {
2537  std::unique_ptr<cGhast> Monster = std::make_unique<cGhast>();
2538  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2539  {
2540  return;
2541  }
2542 
2543  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2544  {
2545  return;
2546  }
2547 
2548  a_Entities.emplace_back(std::move(Monster));
2549 }
2550 
2551 
2552 
2553 
2554 
2555 void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2556 {
2557  std::unique_ptr<cGiant> Monster = std::make_unique<cGiant>();
2558  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2559  {
2560  return;
2561  }
2562 
2563  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2564  {
2565  return;
2566  }
2567 
2568  a_Entities.emplace_back(std::move(Monster));
2569 }
2570 
2571 
2572 
2573 
2574 
2575 void cWSSAnvil::LoadGuardianFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2576 {
2577  std::unique_ptr<cGuardian> Monster = std::make_unique<cGuardian>();
2578  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2579  {
2580  return;
2581  }
2582 
2583  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2584  {
2585  return;
2586  }
2587 
2588  a_Entities.emplace_back(std::move(Monster));
2589 }
2590 
2591 
2592 
2593 
2594 
2595 void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2596 {
2597  int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Type");
2598  int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color");
2599  int StyleIdx = a_NBT.FindChildByName(a_TagIdx, "Style");
2600  if ((TypeIdx < 0) || (ColorIdx < 0) || (StyleIdx < 0))
2601  {
2602  return;
2603  }
2604 
2605  int Type = a_NBT.GetInt(TypeIdx);
2606  int Color = a_NBT.GetInt(ColorIdx);
2607  int Style = a_NBT.GetInt(StyleIdx);
2608 
2609  std::unique_ptr<cHorse> Monster = std::make_unique<cHorse>(Type, Color, Style, 1);
2610 
2611  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2612  {
2613  return;
2614  }
2615 
2616  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2617  {
2618  return;
2619  }
2620 
2621  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
2622  if (AgeableIdx > 0)
2623  {
2624  int Age;
2625  switch (a_NBT.GetType(AgeableIdx))
2626  {
2627  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
2628  case TAG_Int: Age = a_NBT.GetInt (AgeableIdx); break;
2629  default: Age = 0; break;
2630  }
2631  Monster->SetAge(Age);
2632  }
2633 
2634  a_Entities.emplace_back(std::move(Monster));
2635 }
2636 
2637 
2638 
2639 
2640 
2641 void cWSSAnvil::LoadHoglinFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2642 {
2643  // TODO
2644 }
2645 
2646 
2647 
2648 
2649 
2650 void cWSSAnvil::LoadHuskFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2651 {
2652  // TODO
2653 }
2654 
2655 
2656 
2657 
2658 
2659 void cWSSAnvil::LoadIllusionerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2660 {
2661  // TODO
2662 }
2663 
2664 
2665 
2666 
2667 
2668 void cWSSAnvil::LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2669 {
2670  std::unique_ptr<cIronGolem> Monster = std::make_unique<cIronGolem>();
2671  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2672  {
2673  return;
2674  }
2675 
2676  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2677  {
2678  return;
2679  }
2680 
2681  a_Entities.emplace_back(std::move(Monster));
2682 }
2683 
2684 
2685 
2686 
2687 
2688 void cWSSAnvil::LoadLlamaFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2689 {
2690  // TODO
2691 }
2692 
2693 
2694 
2695 
2696 
2697 void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2698 {
2699  int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size");
2700 
2701  if (SizeIdx < 0)
2702  {
2703  return;
2704  }
2705 
2706  int Size = a_NBT.GetInt(SizeIdx);
2707 
2708  std::unique_ptr<cMagmaCube> Monster = std::make_unique<cMagmaCube>(Size);
2709  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2710  {
2711  return;
2712  }
2713 
2714  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2715  {
2716  return;
2717  }
2718 
2719  a_Entities.emplace_back(std::move(Monster));
2720 }
2721 
2722 
2723 
2724 
2725 
2726 void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2727 {
2728  std::unique_ptr<cMooshroom> Monster = std::make_unique<cMooshroom>();
2729  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2730  {
2731  return;
2732  }
2733 
2734  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2735  {
2736  return;
2737  }
2738 
2739  a_Entities.emplace_back(std::move(Monster));
2740 }
2741 
2742 
2743 
2744 
2745 
2746 void cWSSAnvil::LoadMuleFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2747 {
2748  // TODO
2749 }
2750 
2751 
2752 
2753 
2754 
2755 void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2756 {
2757  std::unique_ptr<cOcelot> Monster = std::make_unique<cOcelot>();
2758  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2759  {
2760  return;
2761  }
2762 
2763  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2764  {
2765  return;
2766  }
2767 
2768  auto OwnerInfo = LoadEntityOwner(a_NBT, a_TagIdx);
2769  if (!OwnerInfo.first.empty() && !OwnerInfo.second.IsNil())
2770  {
2771  Monster->SetOwner(OwnerInfo.first, OwnerInfo.second);
2772  Monster->SetIsTame(true);
2773  }
2774 
2775  int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "CatType");
2776  if (TypeIdx > 0)
2777  {
2778  int Type = a_NBT.GetInt(TypeIdx);
2779  Monster->SetCatType(static_cast<cOcelot::eCatType>(Type));
2780  }
2781 
2782  int SittingIdx = a_NBT.FindChildByName(a_TagIdx, "Sitting");
2783  if ((SittingIdx > 0) && (a_NBT.GetType(SittingIdx) == TAG_Byte))
2784  {
2785  bool Sitting = (a_NBT.GetByte(SittingIdx) == 1);
2786  Monster->SetIsSitting(Sitting);
2787  }
2788 
2789  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
2790  if (AgeableIdx > 0)
2791  {
2792  int Age;
2793  switch (a_NBT.GetType(AgeableIdx))
2794  {
2795  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
2796  case TAG_Int: Age = a_NBT.GetInt (AgeableIdx); break;
2797  default: Age = 0; break;
2798  }
2799  Monster->SetAge(Age);
2800  }
2801 
2802  a_Entities.emplace_back(std::move(Monster));
2803 }
2804 
2805 
2806 
2807 
2808 
2809 void cWSSAnvil::LoadPandaFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2810 {
2811  // TODO
2812 }
2813 
2814 
2815 
2816 
2817 
2818 void cWSSAnvil::LoadParrotFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2819 {
2820  // TODO
2821 }
2822 
2823 
2824 
2825 
2826 
2827 void cWSSAnvil::LoadPhantomFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2828 {
2829  // TODO
2830 }
2831 
2832 
2833 
2834 
2835 
2836 void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2837 {
2838  std::unique_ptr<cPig> Monster = std::make_unique<cPig>();
2839  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2840  {
2841  return;
2842  }
2843 
2844  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2845  {
2846  return;
2847  }
2848 
2849  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
2850  if (AgeableIdx > 0)
2851  {
2852  int Age;
2853  switch (a_NBT.GetType(AgeableIdx))
2854  {
2855  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
2856  case TAG_Int: Age = a_NBT.GetInt (AgeableIdx); break;
2857  default: Age = 0; break;
2858  }
2859  Monster->SetAge(Age);
2860  }
2861 
2862  a_Entities.emplace_back(std::move(Monster));
2863 }
2864 
2865 
2866 
2867 
2868 
2869 void cWSSAnvil::LoadPiglinFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2870 {
2871  // TODO
2872 }
2873 
2874 
2875 
2876 
2877 
2878 void cWSSAnvil::LoadPiglinBruteFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2879 {
2880  // TODO
2881 }
2882 
2883 
2884 
2885 
2886 
2887 void cWSSAnvil::LoadPillagerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2888 {
2889  // TODO
2890 }
2891 
2892 
2893 
2894 
2895 
2896 void cWSSAnvil::LoadPolarBearFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2897 {
2898  // TODO
2899 }
2900 
2901 
2902 
2903 
2904 
2905 void cWSSAnvil::LoadPufferfishFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2906 {
2907  // TODO
2908 }
2909 
2910 
2911 
2912 
2913 
2914 void cWSSAnvil::LoadRabbitFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2915 {
2916  int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "RabbitType");
2917  int MoreCarrotTicksIdx = a_NBT.FindChildByName(a_TagIdx, "MoreCarrotTicks");
2918 
2919  if ((TypeIdx < 0) || (MoreCarrotTicksIdx < 0))
2920  {
2921  return;
2922  }
2923 
2924  int Type = a_NBT.GetInt(TypeIdx);
2925  int MoreCarrotTicks = a_NBT.GetInt(MoreCarrotTicksIdx);
2926 
2927  std::unique_ptr<cRabbit> Monster = std::make_unique<cRabbit>(static_cast<eRabbitType>(Type), MoreCarrotTicks);
2928  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2929  {
2930  return;
2931  }
2932 
2933  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2934  {
2935  return;
2936  }
2937 
2938  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
2939  if (AgeableIdx > 0)
2940  {
2941  int Age;
2942  switch (a_NBT.GetType(AgeableIdx))
2943  {
2944  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
2945  case TAG_Int: Age = a_NBT.GetInt (AgeableIdx); break;
2946  default: Age = 0; break;
2947  }
2948  Monster->SetAge(Age);
2949  }
2950 
2951  a_Entities.emplace_back(std::move(Monster));
2952 }
2953 
2954 
2955 
2956 
2957 
2958 void cWSSAnvil::LoadRavagerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2959 {
2960  // TODO
2961 }
2962 
2963 
2964 
2965 
2966 
2967 void cWSSAnvil::LoadSalmonFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
2968 {
2969  // TODO
2970 }
2971 
2972 
2973 
2974 
2975 
2976 void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
2977 {
2978  int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color");
2979  int Color = -1;
2980  if (ColorIdx > 0)
2981  {
2982  Color = static_cast<int>(a_NBT.GetByte(ColorIdx));
2983  }
2984 
2985  std::unique_ptr<cSheep> Monster = std::make_unique<cSheep>(Color);
2986  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2987  {
2988  return;
2989  }
2990 
2991  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
2992  {
2993  return;
2994  }
2995 
2996  int ShearedIdx = a_NBT.FindChildByName(a_TagIdx, "Sheared");
2997  if (ShearedIdx > 0)
2998  {
2999  Monster->SetSheared(a_NBT.GetByte(ShearedIdx) != 0);
3000  }
3001 
3002  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
3003  if (AgeableIdx > 0)
3004  {
3005  int Age;
3006  switch (a_NBT.GetType(AgeableIdx))
3007  {
3008  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
3009  case TAG_Int: Age = a_NBT.GetInt (AgeableIdx); break;
3010  default: Age = 0; break;
3011  }
3012  Monster->SetAge(Age);
3013  }
3014 
3015  a_Entities.emplace_back(std::move(Monster));
3016 }
3017 
3018 
3019 
3020 
3021 
3022 void cWSSAnvil::LoadShulkerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3023 {
3024  // TODO
3025 }
3026 
3027 
3028 
3029 
3030 
3031 void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3032 {
3033  std::unique_ptr<cSilverfish> Monster = std::make_unique<cSilverfish>();
3034  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3035  {
3036  return;
3037  }
3038 
3039  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3040  {
3041  return;
3042  }
3043 
3044  a_Entities.emplace_back(std::move(Monster));
3045 }
3046 
3047 
3048 
3049 
3050 
3051 void cWSSAnvil::LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3052 {
3053  // Wither skeleton is a separate mob in Minecraft 1.11+, but we need this to
3054  // load them from older worlds where wither skeletons were only a skeleton with a flag
3055  int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "SkeletonType");
3056 
3057  std::unique_ptr<cMonster> Monster;
3058  if ((TypeIdx > 0) && (a_NBT.GetByte(TypeIdx) == 1))
3059  {
3060  Monster = std::make_unique<cWitherSkeleton>();
3061  }
3062  else
3063  {
3064  Monster = std::make_unique<cSkeleton>();
3065  }
3066 
3067  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3068  {
3069  return;
3070  }
3071 
3072  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3073  {
3074  return;
3075  }
3076 
3077  a_Entities.emplace_back(std::move(Monster));
3078 }
3079 
3080 
3081 
3082 
3083 
3084 void cWSSAnvil::LoadSkeletonHorseFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3085 {
3086  // TODO
3087 }
3088 
3089 
3090 
3091 
3092 
3093 void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3094 {
3095  int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size");
3096 
3097  if (SizeIdx < 0)
3098  {
3099  return;
3100  }
3101 
3102  int Size = a_NBT.GetInt(SizeIdx);
3103 
3104  std::unique_ptr<cSlime> Monster = std::make_unique<cSlime>(Size);
3105  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3106  {
3107  return;
3108  }
3109 
3110  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3111  {
3112  return;
3113  }
3114 
3115  a_Entities.emplace_back(std::move(Monster));
3116 }
3117 
3118 
3119 
3120 
3121 
3122 void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3123 {
3124  std::unique_ptr<cSnowGolem> Monster = std::make_unique<cSnowGolem>();
3125  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3126  {
3127  return;
3128  }
3129 
3130  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3131  {
3132  return;
3133  }
3134 
3135  a_Entities.emplace_back(std::move(Monster));
3136 }
3137 
3138 
3139 
3140 
3141 
3142 void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3143 {
3144  std::unique_ptr<cSpider> Monster = std::make_unique<cSpider>();
3145  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3146  {
3147  return;
3148  }
3149 
3150  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3151  {
3152  return;
3153  }
3154 
3155  a_Entities.emplace_back(std::move(Monster));
3156 }
3157 
3158 
3159 
3160 
3161 
3162 void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3163 {
3164  std::unique_ptr<cSquid> Monster = std::make_unique<cSquid>();
3165  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3166  {
3167  return;
3168  }
3169 
3170  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3171  {
3172  return;
3173  }
3174 
3175  a_Entities.emplace_back(std::move(Monster));
3176 }
3177 
3178 
3179 
3180 
3181 
3182 void cWSSAnvil::LoadStrayFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3183 {
3184  // TODO
3185 }
3186 
3187 
3188 
3189 
3190 
3191 void cWSSAnvil::LoadStriderFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3192 {
3193  // TODO
3194 }
3195 
3196 
3197 
3198 
3199 
3200 void cWSSAnvil::LoadTraderLlamaFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3201 {
3202  // TODO
3203 }
3204 
3205 
3206 
3207 
3208 
3209 void cWSSAnvil::LoadTropicalFishFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3210 {
3211  // TODO
3212 }
3213 
3214 
3215 
3216 
3217 
3218 void cWSSAnvil::LoadTurtleFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3219 {
3220  // TODO
3221 }
3222 
3223 
3224 
3225 
3226 
3227 void cWSSAnvil::LoadVexFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3228 {
3229  // TODO
3230 }
3231 
3232 
3233 
3234 
3235 
3236 void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3237 {
3238  int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Profession");
3239  if (TypeIdx < 0)
3240  {
3241  return;
3242  }
3243 
3244  int Type = a_NBT.GetInt(TypeIdx);
3245 
3246  std::unique_ptr<cVillager> Monster = std::make_unique<cVillager>(cVillager::eVillagerType(Type));
3247  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3248  {
3249  return;
3250  }
3251 
3252  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3253  {
3254  return;
3255  }
3256 
3257  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
3258  if (AgeableIdx > 0)
3259  {
3260  int Age;
3261  switch (a_NBT.GetType(AgeableIdx))
3262  {
3263  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
3264  case TAG_Int: Age = a_NBT.GetInt (AgeableIdx); break;
3265  default: Age = 0; break;
3266  }
3267  Monster->SetAge(Age);
3268  }
3269 
3270  int InventoryIdx = a_NBT.FindChildByName(a_TagIdx, "Inventory");
3271  if (InventoryIdx > 0)
3272  {
3273  LoadItemGridFromNBT(Monster->GetInventory(), a_NBT, InventoryIdx);
3274  }
3275 
3276 
3277  a_Entities.emplace_back(std::move(Monster));
3278 }
3279 
3280 
3281 
3282 
3283 
3284 void cWSSAnvil::LoadVindicatorFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3285 {
3286  // TODO
3287 }
3288 
3289 
3290 
3291 
3292 
3293 void cWSSAnvil::LoadWanderingTraderFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3294 {
3295  // TODO
3296 }
3297 
3298 
3299 
3300 
3301 
3302 void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3303 {
3304  std::unique_ptr<cWitch> Monster = std::make_unique<cWitch>();
3305  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3306  {
3307  return;
3308  }
3309 
3310  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3311  {
3312  return;
3313  }
3314 
3315  a_Entities.emplace_back(std::move(Monster));
3316 }
3317 
3318 
3319 
3320 
3321 
3322 void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3323 {
3324  std::unique_ptr<cWither> Monster = std::make_unique<cWither>();
3325  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3326  {
3327  return;
3328  }
3329 
3330  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3331  {
3332  return;
3333  }
3334 
3335  int CurrLine = a_NBT.FindChildByName(a_TagIdx, "Invul");
3336  if (CurrLine > 0)
3337  {
3338  Monster->SetWitherInvulnerableTicks(static_cast<unsigned int>(a_NBT.GetInt(CurrLine)));
3339  }
3340 
3341  a_Entities.emplace_back(std::move(Monster));
3342 }
3343 
3344 
3345 
3346 
3347 
3348 void cWSSAnvil::LoadWitherSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3349 {
3350  auto Monster = std::make_unique<cWitherSkeleton>();
3351  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3352  {
3353  return;
3354  }
3355 
3356  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3357  {
3358  return;
3359  }
3360 
3361  a_Entities.emplace_back(std::move(Monster));
3362 }
3363 
3364 
3365 
3366 
3367 
3368 void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3369 {
3370  std::unique_ptr<cWolf> Monster = std::make_unique<cWolf>();
3371  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3372  {
3373  return;
3374  }
3375  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3376  {
3377  return;
3378  }
3379 
3380  auto OwnerInfo = LoadEntityOwner(a_NBT, a_TagIdx);
3381  if (!OwnerInfo.first.empty() && !OwnerInfo.second.IsNil())
3382  {
3383  Monster->SetOwner(OwnerInfo.first, OwnerInfo.second);
3384  Monster->SetIsTame(true);
3385  }
3386 
3387  int SittingIdx = a_NBT.FindChildByName(a_TagIdx, "Sitting");
3388  if ((SittingIdx > 0) && (a_NBT.GetType(SittingIdx) == TAG_Byte))
3389  {
3390  bool Sitting = (a_NBT.GetByte(SittingIdx) == 1);
3391  Monster->SetIsSitting(Sitting);
3392  }
3393  int AngryIdx = a_NBT.FindChildByName(a_TagIdx, "Angry");
3394  if ((AngryIdx > 0) && (a_NBT.GetType(AngryIdx) == TAG_Byte))
3395  {
3396  bool Angry = (a_NBT.GetByte(AngryIdx) == 1);
3397  Monster->SetIsAngry(Angry);
3398  }
3399  int CollarColorIdx = a_NBT.FindChildByName(a_TagIdx, "CollarColor");
3400  if (CollarColorIdx > 0)
3401  {
3402  switch (a_NBT.GetType(CollarColorIdx))
3403  {
3404  case TAG_Byte:
3405  {
3406  // Vanilla uses this
3407  Monster->SetCollarColor(a_NBT.GetByte(CollarColorIdx));
3408  break;
3409  }
3410  case TAG_Int:
3411  {
3412  // Old MCS code used this, keep reading it for compatibility reasons:
3413  Monster->SetCollarColor(a_NBT.GetInt(CollarColorIdx));
3414  break;
3415  }
3416  default:
3417  {
3418  // No other values are interpreted
3419  break;
3420  }
3421  }
3422  }
3423 
3424  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
3425  if (AgeableIdx > 0)
3426  {
3427  int Age;
3428  switch (a_NBT.GetType(AgeableIdx))
3429  {
3430  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
3431  case TAG_Int: Age = a_NBT.GetInt (AgeableIdx); break;
3432  default: Age = 0; break;
3433  }
3434  Monster->SetAge(Age);
3435  }
3436 
3437  a_Entities.emplace_back(std::move(Monster));
3438 }
3439 
3440 
3441 
3442 
3443 
3444 void cWSSAnvil::LoadZoglinFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3445 {
3446  // TODO
3447 }
3448 
3449 
3450 
3451 
3452 
3453 void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3454 {
3455  std::unique_ptr<cZombie> Monster = std::make_unique<cZombie>();
3456  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3457  {
3458  return;
3459  }
3460 
3461  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3462  {
3463  return;
3464  }
3465 
3466  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
3467  if (AgeableIdx > 0)
3468  {
3469  int Age;
3470  switch (a_NBT.GetType(AgeableIdx))
3471  {
3472  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
3473  case TAG_Int: Age = a_NBT.GetInt(AgeableIdx); break;
3474  default: Age = 0; break;
3475  }
3476  Monster->SetAge(Age);
3477  }
3478 
3479  a_Entities.emplace_back(std::move(Monster));
3480 }
3481 
3482 
3483 
3484 
3485 
3486 void cWSSAnvil::LoadZombieHorseFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
3487 {
3488  // TODO
3489 }
3490 
3491 
3492 
3493 
3494 
3495 void cWSSAnvil::LoadZombifiedPiglinFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3496 {
3497  std::unique_ptr<cZombiePigman> Monster = std::make_unique<cZombiePigman>();
3498  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3499  {
3500  return;
3501  }
3502 
3503  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3504  {
3505  return;
3506  }
3507 
3508  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
3509  if (AgeableIdx > 0)
3510  {
3511  int Age;
3512  switch (a_NBT.GetType(AgeableIdx))
3513  {
3514  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
3515  case TAG_Int: Age = a_NBT.GetInt (AgeableIdx); break;
3516  default: Age = 0; break;
3517  }
3518  Monster->SetAge(Age);
3519  }
3520 
3521  a_Entities.emplace_back(std::move(Monster));
3522 }
3523 
3524 
3525 
3526 
3527 
3528 void cWSSAnvil::LoadZombieVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
3529 {
3530  int ProfessionIdx = a_NBT.FindChildByName(a_TagIdx, "Profession");
3531  if (ProfessionIdx < 0)
3532  {
3533  return;
3534  }
3535 
3536  cVillager::eVillagerType Profession = static_cast<cVillager::eVillagerType>(a_NBT.GetInt(ProfessionIdx));
3537 
3538  std::unique_ptr<cZombieVillager> Monster = std::make_unique<cZombieVillager>(Profession);
3539  if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3540  {
3541  return;
3542  }
3543 
3544  if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
3545  {
3546  return;
3547  }
3548 
3549  // TODO: Conversion time
3550 
3551  int AgeableIdx = a_NBT.FindChildByName(a_TagIdx, "Age");
3552  if (AgeableIdx > 0)
3553  {
3554  int Age;
3555  switch (a_NBT.GetType(AgeableIdx))
3556  {
3557  case TAG_Byte: Age = static_cast<int>(a_NBT.GetByte(AgeableIdx)); break;
3558  case TAG_Int: Age = a_NBT.GetInt (AgeableIdx); break;
3559  default: Age = 0; break;
3560  }
3561  Monster->SetAge(Age);
3562  }
3563 
3564  a_Entities.emplace_back(std::move(Monster));
3565 }
3566 
3567 
3568 
3569 
3570 
3571 std::pair<AString, cUUID> cWSSAnvil::LoadEntityOwner(const cParsedNBT & a_NBT, int a_TagIdx)
3572 {
3573  // Load the owner information. OwnerUUID or Owner may be specified, possibly both:
3574  AString OwnerName;
3575  cUUID OwnerUUID;
3576  int OwnerUUIDIdx = a_NBT.FindChildByName(a_TagIdx, "OwnerUUID");
3577  if (OwnerUUIDIdx > 0)
3578  {
3579  OwnerUUID.FromString(a_NBT.GetString(OwnerUUIDIdx));
3580  }
3581  int OwnerIdx = a_NBT.FindChildByName(a_TagIdx, "Owner");
3582  if (OwnerIdx > 0)
3583  {
3584  OwnerName = a_NBT.GetString(OwnerIdx);
3585  }
3586  if (OwnerName.empty() && OwnerUUID.IsNil())
3587  {
3588  // There is no owner, bail out:
3589  return {};
3590  }
3591 
3592  // Convert name to UUID, if needed:
3593  if (OwnerUUID.IsNil())
3594  {
3595  // This entity has only playername stored (pre-1.7.6), look up the UUID
3596  // The lookup is blocking, but we're running in a separate thread, so it's ok
3597  OwnerUUID = cRoot::Get()->GetMojangAPI().GetUUIDFromPlayerName(OwnerName);
3598  if (OwnerUUID.IsNil())
3599  {
3600  // Not a known player, un-tame the entity by bailing out
3601  return {};
3602  }
3603  }
3604 
3605  // Convert UUID to name, if needed:
3606  if (OwnerName.empty())
3607  {
3608  // The lookup is blocking, but we're running in a separate thread, so it's ok
3609  OwnerName = cRoot::Get()->GetMojangAPI().GetPlayerNameFromUUID(OwnerUUID);
3610  if (OwnerName.empty())
3611  {
3612  // Not a known player, un-tame the entity by bailing out
3613  return {};
3614  }
3615  }
3616 
3617  return { OwnerName, OwnerUUID };
3618 }
3619 
3620 
3621 
3622 
3623 
3624 bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
3625 {
3626  double Pos[3];
3627  if (!LoadDoublesListFromNBT(Pos, 3, a_NBT, a_NBT.FindChildByName(a_TagIdx, "Pos")))
3628  {
3629  return false;
3630  }
3631  a_Entity.SetPosition(Pos[0], Pos[1], Pos[2]);
3632 
3633  double Speed[3];
3634  if (!LoadDoublesListFromNBT(Speed, 3, a_NBT, a_NBT.FindChildByName(a_TagIdx, "Motion")))
3635  {
3636  // Provide default speed:
3637  Speed[0] = 0;
3638  Speed[1] = 0;
3639  Speed[2] = 0;
3640  }
3641  a_Entity.SetSpeed(Speed[0], Speed[1], Speed[2]);
3642 
3643  double Rotation[3];
3644  if (!LoadDoublesListFromNBT(Rotation, 2, a_NBT, a_NBT.FindChildByName(a_TagIdx, "Rotation")))
3645  {
3646  // Provide default rotation:
3647  Rotation[0] = 0;
3648  Rotation[1] = 0;
3649  }
3650  a_Entity.SetYaw(Rotation[0]);
3651  a_Entity.SetPitch(Rotation[1]);
3652 
3653  // Depending on the Minecraft version, the entity's health is
3654  // stored either as a float Health tag (HealF prior to 1.9) or
3655  // as a short Health tag. The float tags should be preferred.
3656  int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
3657  int HealF = a_NBT.FindChildByName(a_TagIdx, "HealF");
3658 
3659  if (Health > 0 && a_NBT.GetType(Health) == TAG_Float)
3660  {
3661  a_Entity.SetHealth(a_NBT.GetFloat(Health));
3662  }
3663  else if (HealF > 0)
3664  {
3665  a_Entity.SetHealth(a_NBT.GetFloat(HealF));
3666  }
3667  else if (Health > 0)
3668  {
3669  a_Entity.SetHealth(static_cast<float>(a_NBT.GetShort(Health)));
3670  }
3671  else
3672  {
3673  a_Entity.SetHealth(a_Entity.GetMaxHealth());
3674  }
3675 
3676  return true;
3677 }
3678 
3679 
3680 
3681 
3682 
3683 bool cWSSAnvil::LoadMonsterBaseFromNBT(cMonster & a_Monster, const cParsedNBT & a_NBT, int a_TagIdx)
3684 {
3685  float DropChance[5];
3686  if (LoadFloatsListFromNBT(DropChance, 5, a_NBT, a_NBT.FindChildByName(a_TagIdx, "DropChances")))
3687  {
3688  a_Monster.SetDropChanceWeapon(DropChance[0]);
3689  a_Monster.SetDropChanceHelmet(DropChance[1]);
3690  a_Monster.SetDropChanceChestplate(DropChance[2]);
3691  a_Monster.SetDropChanceLeggings(DropChance[3]);
3692  a_Monster.SetDropChanceBoots(DropChance[4]);
3693  }
3694  if (LoadFloatsListFromNBT(DropChance, 2, a_NBT, a_NBT.FindChildByName(a_TagIdx, "HandDropChances")))
3695  {
3696  a_Monster.SetDropChanceWeapon(DropChance[0]);
3697  }
3698  if (LoadFloatsListFromNBT(DropChance, 4, a_NBT, a_NBT.FindChildByName(a_TagIdx, "ArmorDropChances")))
3699  {
3700  a_Monster.SetDropChanceHelmet(DropChance[0]);
3701  a_Monster.SetDropChanceChestplate(DropChance[1]);
3702  a_Monster.SetDropChanceLeggings(DropChance[2]);
3703  a_Monster.SetDropChanceBoots(DropChance[3]);
3704  }
3705 
3706  int LootTag = a_NBT.FindChildByName(a_TagIdx, "CanPickUpLoot");
3707  if (LootTag > 0)
3708  {
3709  bool CanPickUpLoot = (a_NBT.GetByte(LootTag) == 1);
3710  a_Monster.SetCanPickUpLoot(CanPickUpLoot);
3711  }
3712 
3713  int CustomNameTag = a_NBT.FindChildByName(a_TagIdx, "CustomName");
3714  if ((CustomNameTag > 0) && (a_NBT.GetType(CustomNameTag) == TAG_String))
3715  {
3716  a_Monster.SetCustomName(a_NBT.GetString(CustomNameTag));
3717  }
3718 
3719  int CustomNameVisibleTag = a_NBT.FindChildByName(a_TagIdx, "CustomNameVisible");
3720  if ((CustomNameVisibleTag > 0) && (a_NBT.GetType(CustomNameVisibleTag) == TAG_Byte))
3721  {
3722  bool CustomNameVisible = (a_NBT.GetByte(CustomNameVisibleTag) == 1);
3723  a_Monster.SetCustomNameAlwaysVisible(CustomNameVisible);
3724  }
3725 
3726  // Leashed to a knot
3727  int LeashedIdx = a_NBT.FindChildByName(a_TagIdx, "Leashed");
3728  if ((LeashedIdx >= 0) && a_NBT.GetByte(LeashedIdx))
3729  {
3730  LoadLeashToPosition(a_Monster, a_NBT, a_TagIdx);
3731  }
3732 
3733  return true;
3734 }
3735 
3736 
3737 
3738 
3739 
3740 void cWSSAnvil::LoadLeashToPosition(cMonster & a_Monster, const cParsedNBT & a_NBT, int a_TagIdx)
3741 {
3742  int LeashIdx = a_NBT.FindChildByName(a_TagIdx, "Leash");
3743  if (LeashIdx < 0)
3744  {
3745  return;
3746  }
3747 
3748  double PosX = 0.0, PosY = 0.0, PosZ = 0.0;
3749  bool KnotPosPresent = true;
3750  int LeashDataLine = a_NBT.FindChildByName(LeashIdx, "X");
3751  if (LeashDataLine >= 0)
3752  {
3753  PosX = a_NBT.GetDouble(LeashDataLine);
3754  }
3755  else
3756  {
3757  KnotPosPresent = false;
3758  }
3759  LeashDataLine = a_NBT.FindChildByName(LeashIdx, "Y");
3760  if (LeashDataLine >= 0)
3761  {
3762  PosY = a_NBT.GetDouble(LeashDataLine);
3763  }
3764  else
3765  {
3766  KnotPosPresent = false;
3767  }
3768  LeashDataLine = a_NBT.FindChildByName(LeashIdx, "Z");
3769  if (LeashDataLine >= 0)
3770  {
3771  PosZ = a_NBT.GetDouble(LeashDataLine);
3772  }
3773  else
3774  {
3775  KnotPosPresent = false;
3776  }
3777  if (KnotPosPresent)
3778  {
3779  // Set leash pos for the mob
3780  a_Monster.SetLeashToPos(new Vector3d(PosX, PosY, PosZ));
3781  }
3782 }
3783 
3784 
3785 
3786 
3787 
3788 bool cWSSAnvil::LoadProjectileBaseFromNBT(cProjectileEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
3789 {
3790  if (!LoadEntityBaseFromNBT(a_Entity, a_NBT, a_TagIdx))
3791  {
3792  return false;
3793  }
3794 
3795  bool IsInGround = false;
3796  int InGroundIdx = a_NBT.FindChildByName(a_TagIdx, "inGround");
3797  if (InGroundIdx > 0)
3798  {
3799  IsInGround = (a_NBT.GetByte(InGroundIdx) != 0);
3800  }
3801  a_Entity.SetIsInGround(IsInGround);
3802 
3803  return true;
3804 }
3805 
3806 
3807 
3808 
3809 
3810 bool cWSSAnvil::LoadDoublesListFromNBT(double * a_Doubles, int a_NumDoubles, const cParsedNBT & a_NBT, int a_TagIdx)
3811 {
3812  if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List) || (a_NBT.GetChildrenType(a_TagIdx) != TAG_Double))
3813  {
3814  return false;
3815  }
3816  int idx = 0;
3817  for (int Tag = a_NBT.GetFirstChild(a_TagIdx); (Tag > 0) && (idx < a_NumDoubles); Tag = a_NBT.GetNextSibling(Tag), ++idx)
3818  {
3819  a_Doubles[idx] = a_NBT.GetDouble(Tag);
3820  } // for Tag - PosTag[]
3821  return (idx == a_NumDoubles); // Did we read enough doubles?
3822 }
3823 
3824 
3825 
3826 
3827 
3828 bool cWSSAnvil::LoadFloatsListFromNBT(float * a_Floats, int a_NumFloats, const cParsedNBT & a_NBT, int a_TagIdx)
3829 {
3830  if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List) || (a_NBT.GetChildrenType(a_TagIdx) != TAG_Float))
3831  {
3832  return false;
3833  }
3834  int idx = 0;
3835  for (int Tag = a_NBT.GetFirstChild(a_TagIdx); (Tag > 0) && (idx < a_NumFloats); Tag = a_NBT.GetNextSibling(Tag), ++idx)
3836  {
3837  a_Floats[idx] = a_NBT.GetFloat(Tag);
3838  } // for Tag - PosTag[]
3839  return (idx == a_NumFloats); // Did we read enough doubles?
3840 }
3841 
3842 
3843 
3844 
3845 
3846 bool cWSSAnvil::GetBlockEntityNBTPos(const cParsedNBT & a_NBT, int a_TagIdx, Vector3i & a_AbsPos)
3847 {
3848  int x = a_NBT.FindChildByName(a_TagIdx, "x");
3849  if ((x < 0) || (a_NBT.GetType(x) != TAG_Int))
3850  {
3851  return false;
3852  }
3853  int y = a_NBT.FindChildByName(a_TagIdx, "y");
3854  if ((y < 0) || (a_NBT.GetType(y) != TAG_Int))
3855  {
3856  return false;
3857  }
3858  int z = a_NBT.FindChildByName(a_TagIdx, "z");
3859  if ((z < 0) || (a_NBT.GetType(z) != TAG_Int))
3860  {
3861  return false;
3862  }
3863  a_AbsPos.Set(
3864  Clamp(a_NBT.GetInt(x), -40000000, 40000000), // World is limited to 30M blocks in XZ, we clamp to 40M
3865  Clamp(a_NBT.GetInt(y), -10000, 10000), // Y is limited to 0 .. 255, we clamp to 10K
3866  Clamp(a_NBT.GetInt(z), -40000000, 40000000)
3867  );
3868  return true;
3869 }
3870 
3871 
3872 
3873 
3874 
3876 // cWSSAnvil::cMCAFile:
3877 
3878 cWSSAnvil::cMCAFile::cMCAFile(cWSSAnvil & a_ParentSchema, const AString & a_FileName, int a_RegionX, int a_RegionZ) :
3879  m_ParentSchema(a_ParentSchema),
3880  m_RegionX(a_RegionX),
3881  m_RegionZ(a_RegionZ),
3882  m_FileName(a_FileName)
3883 {
3884 }
3885 
3886 
3887 
3888 
3889 
3890 bool cWSSAnvil::cMCAFile::OpenFile(bool a_IsForReading)
3891 {
3892  bool writeOutNeeded = false;
3893 
3894  if (m_File.IsOpen())
3895  {
3896  // Already open
3897  return true;
3898  }
3899 
3900  if (a_IsForReading)
3901  {
3902  if (!cFile::Exists(m_FileName))
3903  {
3904  // We want to read and the file doesn't exist. Fail.
3905  return false;
3906  }
3907  }
3908 
3909  if (!m_File.Open(m_FileName, cFile::fmReadWrite))
3910  {
3911  // The file failed to open
3912  return false;
3913  }
3914 
3915  // Load the header:
3916  if (m_File.Read(m_Header, sizeof(m_Header)) != sizeof(m_Header))
3917  {
3918  // Cannot read the header - perhaps the file has just been created?
3919  // Try writing a nullptr header for chunk offsets:
3920  memset(m_Header, 0, sizeof(m_Header));
3921  writeOutNeeded = true;
3922  }
3923 
3924  // Load the TimeStamps:
3925  if (m_File.Read(m_TimeStamps, sizeof(m_TimeStamps)) != sizeof(m_TimeStamps))
3926  {
3927  // Cannot read the time stamps - perhaps the file has just been created?
3928  // Try writing a nullptr header for timestamps:
3929  memset(m_TimeStamps, 0, sizeof(m_TimeStamps));
3930  writeOutNeeded = true;
3931  }
3932 
3933  if (writeOutNeeded)
3934  {
3935  m_File.Seek(0);
3936  if (
3937  (m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header)) || // Write chunk offsets
3938  (m_File.Write(m_TimeStamps, sizeof(m_TimeStamps)) != sizeof(m_TimeStamps)) // Write chunk timestamps
3939  )
3940  {
3941  LOGWARNING("Cannot process MCA header in file \"%s\", chunks in that file will be lost", m_FileName.c_str());
3942  m_File.Close();
3943  return false;
3944  }
3945  }
3946  return true;
3947 }
3948 
3949 
3950 
3951 
3952 
3954 {
3955  if (!OpenFile(true))
3956  {
3957  return false;
3958  }
3959 
3960  int LocalX = a_Chunk.m_ChunkX % 32;
3961  if (LocalX < 0)
3962  {
3963  LocalX = 32 + LocalX;
3964  }
3965  int LocalZ = a_Chunk.m_ChunkZ % 32;
3966  if (LocalZ < 0)
3967  {
3968  LocalZ = 32 + LocalZ;
3969  }
3970  unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]);
3971  unsigned ChunkOffset = ChunkLocation >> 8;
3972  if (ChunkOffset < 2)
3973  {
3974  return false;
3975  }
3976 
3977  m_File.Seek(static_cast<int>(ChunkOffset * 4096));
3978 
3979  UInt32 ChunkSize = 0;
3980  if (m_File.Read(&ChunkSize, 4) != 4)
3981  {
3982  m_ParentSchema.ChunkLoadFailed(a_Chunk, "Cannot read chunk size", {});
3983  return false;
3984  }
3985  ChunkSize = ntohl(ChunkSize);
3986  if (ChunkSize < 1)
3987  {
3988  // Chunk size too small
3989  m_ParentSchema.ChunkLoadFailed(a_Chunk, "Chunk size too small", {});
3990  return false;
3991  }
3992 
3993  char CompressionType = 0;
3994  if (m_File.Read(&CompressionType, 1) != 1)
3995  {
3996  m_ParentSchema.ChunkLoadFailed(a_Chunk, "Cannot read chunk compression", {});
3997  return false;
3998  }
3999  ChunkSize--;
4000 
4001  a_Data = m_File.Read(ChunkSize);
4002  if (a_Data.size() != ChunkSize)
4003  {
4004  m_ParentSchema.ChunkLoadFailed(a_Chunk, "Cannot read entire chunk data", a_Data);
4005  return false;
4006  }
4007 
4008  if (CompressionType != 2)
4009  {
4010  // Chunk is in an unknown compression
4011  m_ParentSchema.ChunkLoadFailed(a_Chunk, fmt::format(FMT_STRING("Unknown chunk compression: {}"), CompressionType), a_Data);
4012  return false;
4013  }
4014  return true;
4015 }
4016 
4017 
4018 
4019 
4020 
4021 const std::byte * cWSSAnvil::GetSectionData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, size_t a_Length)
4022 {
4023  int Child = a_NBT.FindChildByName(a_Tag, a_ChildName);
4024  if ((Child >= 0) && (a_NBT.GetType(Child) == TAG_ByteArray) && (a_NBT.GetDataLength(Child) == a_Length))
4025  {
4026  return a_NBT.GetData(Child);
4027  }
4028  return nullptr;
4029 }
4030 
4031 
4032 
4033 
4034 
4036 {
4037  if (!OpenFile(false))
4038  {
4039  LOGWARNING("Cannot save chunk [%d, %d], opening file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
4040  return false;
4041  }
4042 
4043  int LocalX = a_Chunk.m_ChunkX % 32;
4044  if (LocalX < 0)
4045  {
4046  LocalX = 32 + LocalX;
4047  }
4048  int LocalZ = a_Chunk.m_ChunkZ % 32;
4049  if (LocalZ < 0)
4050  {
4051  LocalZ = 32 + LocalZ;
4052  }
4053 
4054  unsigned ChunkSector = FindFreeLocation(LocalX, LocalZ, a_Data.size());
4055 
4056  // Store the chunk data:
4057  m_File.Seek(static_cast<int>(ChunkSector * 4096));
4058  UInt32 ChunkSize = htonl(static_cast<UInt32>(a_Data.size() + 1));
4059  if (m_File.Write(&ChunkSize, 4) != 4)
4060  {
4061  LOGWARNING("Cannot save chunk [%d, %d], writing(1) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
4062  return false;
4063  }
4064  char CompressionType = 2;
4065  if (m_File.Write(&CompressionType, 1) != 1)
4066  {
4067  LOGWARNING("Cannot save chunk [%d, %d], writing(2) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
4068  return false;
4069  }
4070  if (m_File.Write(a_Data.data(), a_Data.size()) != static_cast<int>(a_Data.size()))
4071  {
4072  LOGWARNING("Cannot save chunk [%d, %d], writing(3) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
4073  return false;
4074  }
4075 
4076  // Add padding to 4K boundary:
4077  size_t BytesWritten = a_Data.size() + MCA_CHUNK_HEADER_LENGTH;
4078  if (BytesWritten % 4096 != 0)
4079  {
4080  static const char Padding[4095] = {0};
4081  m_File.Write(Padding, 4096 - (BytesWritten % 4096));
4082  }
4083 
4084  // Store the header:
4085  ChunkSize = (static_cast<UInt32>(a_Data.size()) + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size up to nearest 4KB sector, make it a sector number
4086  if (ChunkSize > 255)
4087  {
4088  LOGWARNING("Cannot save chunk [%d, %d], the data is too large (%u KiB, maximum is 1024 KiB). Remove some entities and retry.",
4089  a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, static_cast<unsigned>(ChunkSize * 4)
4090  );
4091  return false;
4092  }
4093 
4094  // Store the header info in the table
4095  m_Header[LocalX + 32 * LocalZ] = htonl(static_cast<UInt32>((ChunkSector << 8) | ChunkSize));
4096 
4097  // Set the modification time
4098  m_TimeStamps[LocalX + 32 * LocalZ] = htonl(static_cast<UInt32>(time(nullptr)));
4099 
4100  if (m_File.Seek(0) < 0)
4101  {
4102  LOGWARNING("Cannot save chunk [%d, %d], seeking in file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
4103  return false;
4104  }
4105  if (m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header))
4106  {
4107  LOGWARNING("Cannot save chunk [%d, %d], writing header to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
4108  return false;
4109  }
4110  if (m_File.Write(m_TimeStamps, sizeof(m_TimeStamps)) != sizeof(m_TimeStamps))
4111  {
4112  LOGWARNING("Cannot save chunk [%d, %d], writing timestamps to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
4113  return false;
4114  }
4115 
4116  return true;
4117 }
4118 
4119 
4120 
4121 
4122 
4123 unsigned cWSSAnvil::cMCAFile::FindFreeLocation(int a_LocalX, int a_LocalZ, const size_t a_DataSize)
4124 {
4125  // See if it fits the current location:
4126  unsigned ChunkLocation = ntohl(m_Header[a_LocalX + 32 * a_LocalZ]);
4127  unsigned ChunkLen = ChunkLocation & 0xff;
4128  if (a_DataSize + MCA_CHUNK_HEADER_LENGTH <= (ChunkLen * 4096))
4129  {
4130  return ChunkLocation >> 8;
4131  }
4132 
4133  // Doesn't fit, append to the end of file (we're wasting a lot of space, TODO: fix this later)
4134  unsigned MaxLocation = 2 << 8; // Minimum sector is #2 - after the headers
4135  for (size_t i = 0; i < ARRAYCOUNT(m_Header); i++)
4136  {
4137  ChunkLocation = ntohl(m_Header[i]);
4138  ChunkLocation = ChunkLocation + ((ChunkLocation & 0xff) << 8); // Add the number of sectors used; don't care about the 4th byte
4139  if (MaxLocation < ChunkLocation)
4140  {
4141  MaxLocation = ChunkLocation;
4142  }
4143  } // for i - m_Header[]
4144  return MaxLocation >> 8;
4145 }
EMCSBiome
Biome IDs The first batch corresponds to the clientside biomes, used by MineCraft.
Definition: BiomeDef.h:18
@ biMaxVariantBiome
Definition: BiomeDef.h:100
bool StringToItem(const AString &a_ItemTypeString, cItem &a_Item)
Translates an itemtype string into an item.
Definition: BlockType.cpp:228
AString ItemTypeToString(short a_ItemType)
Translates itemtype into a string.
Definition: BlockType.cpp:252
@ E_META_WOOL_RED
Definition: BlockType.h:1006
@ E_BLOCK_HEAD
Definition: BlockType.h:159
@ E_BLOCK_STANDING_BANNER
Definition: BlockType.h:195
@ E_BLOCK_BREWING_STAND
Definition: BlockType.h:132
@ E_BLOCK_JUKEBOX
Definition: BlockType.h:99
@ E_BLOCK_ENCHANTMENT_TABLE
Definition: BlockType.h:131
@ E_BLOCK_FURNACE
Definition: BlockType.h:73
@ E_BLOCK_SIGN_POST
Definition: BlockType.h:76
@ E_BLOCK_BEACON
Definition: BlockType.h:153
@ E_BLOCK_CHEST
Definition: BlockType.h:64
@ E_BLOCK_LIT_FURNACE
Definition: BlockType.h:74
@ E_BLOCK_TRAPPED_CHEST
Definition: BlockType.h:161
@ E_BLOCK_COMMAND_BLOCK
Definition: BlockType.h:152
@ E_BLOCK_NOTE_BLOCK
Definition: BlockType.h:35
@ E_BLOCK_BED
Definition: BlockType.h:36
@ E_BLOCK_HOPPER
Definition: BlockType.h:171
@ E_BLOCK_DROPPER
Definition: BlockType.h:176
@ E_BLOCK_ENDER_CHEST
Definition: BlockType.h:145
@ E_BLOCK_END_PORTAL
Definition: BlockType.h:134
@ E_BLOCK_DISPENSER
Definition: BlockType.h:33
@ E_BLOCK_FLOWER_POT
Definition: BlockType.h:155
@ E_BLOCK_MOB_SPAWNER
Definition: BlockType.h:62
@ E_BLOCK_WALLSIGN
Definition: BlockType.h:82
@ E_BLOCK_WALL_BANNER
Definition: BlockType.h:196
ENUM_ITEM_TYPE
Definition: BlockType.h:295
@ E_ITEM_FIREWORK_STAR
Definition: BlockType.h:448
@ E_ITEM_BOOK
Definition: BlockType.h:385
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char HEIGHTTYPE
The type used by the heightmap.
Definition: ChunkDef.h:47
std::vector< OwnedEntity > cEntityList
Definition: ChunkDef.h:33
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
eMobHeadRotation
Definition: Defines.h:191
@ BLOCK_FACE_NONE
Definition: Defines.h:39
eMobHeadType
Definition: Defines.h:177
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
unsigned int UInt32
Definition: Globals.h:157
signed short Int16
Definition: Globals.h:153
std::basic_string_view< std::byte > ContiguousByteBufferView
Definition: Globals.h:376
#define FAST_FLOOR_DIV(x, div)
Faster than (int)floorf((float)x / (float)div)
Definition: Globals.h:238
T Clamp(T a_Value, T a_Min, T a_Max)
Clamp X to the specified range.
Definition: Globals.h:336
#define ASSERT(x)
Definition: Globals.h:276
std::basic_string< std::byte > ContiguousByteBuffer
Definition: Globals.h:375
unsigned char Byte
Definition: Globals.h:161
void FLOGINFO(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:35
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
void FLOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:41
eMonsterType
Identifies individual monster type.
Definition: MonsterTypes.h:11
@ mtZombieVillager
Definition: MonsterTypes.h:82
@ mtVindicator
Definition: MonsterTypes.h:72
@ mtElderGuardian
Definition: MonsterTypes.h:25
@ mtHoglin
Definition: MonsterTypes.h:35
@ mtSkeleton
Definition: MonsterTypes.h:59
@ mtSheep
Definition: MonsterTypes.h:56
@ mtEndermite
Definition: MonsterTypes.h:28
@ mtPiglin
Definition: MonsterTypes.h:48
@ mtTurtle
Definition: MonsterTypes.h:69
@ mtPolarBear
Definition: MonsterTypes.h:51
@ mtDolphin
Definition: MonsterTypes.h:22
@ mtMagmaCube
Definition: MonsterTypes.h:40
@ mtWanderingTrader
Definition: MonsterTypes.h:73
@ mtWolf
Definition: MonsterTypes.h:77
@ mtStray
Definition: MonsterTypes.h:65
@ mtRabbit
Definition: MonsterTypes.h:53
@ mtTraderLlama
Definition: MonsterTypes.h:67
@ mtCat
Definition: MonsterTypes.h:16
@ mtZombie
Definition: MonsterTypes.h:79
@ mtOcelot
Definition: MonsterTypes.h:43
@ mtRavager
Definition: MonsterTypes.h:54
@ mtDonkey
Definition: MonsterTypes.h:23
@ mtVex
Definition: MonsterTypes.h:70
@ mtEnderman
Definition: MonsterTypes.h:27
@ mtTropicalFish
Definition: MonsterTypes.h:68
@ mtHusk
Definition: MonsterTypes.h:36
@ mtCaveSpider
Definition: MonsterTypes.h:17
@ mtEvoker
Definition: MonsterTypes.h:29
@ mtPhantom
Definition: MonsterTypes.h:46
@ mtShulker
Definition: MonsterTypes.h:57
@ mtPufferfish
Definition: MonsterTypes.h:52
@ mtWither
Definition: MonsterTypes.h:75
@ mtSkeletonHorse
Definition: MonsterTypes.h:60
@ mtPig
Definition: MonsterTypes.h:47
@ mtDrowned
Definition: MonsterTypes.h:24
@ mtVillager
Definition: MonsterTypes.h:71
@ mtHorse
Definition: MonsterTypes.h:34
@ mtZombieHorse
Definition: MonsterTypes.h:80
@ mtWitch
Definition: MonsterTypes.h:74
@ mtCow
Definition: MonsterTypes.h:20
@ mtSalmon
Definition: MonsterTypes.h:55
@ mtEnderDragon
Definition: MonsterTypes.h:26
@ mtPiglinBrute
Definition: MonsterTypes.h:49
@ mtMooshroom
Definition: MonsterTypes.h:41
@ mtSquid
Definition: MonsterTypes.h:64
@ mtInvalidType
Definition: MonsterTypes.h:12
@ mtBat
Definition: MonsterTypes.h:14
@ mtIllusioner
Definition: MonsterTypes.h:37
@ mtChicken
Definition: MonsterTypes.h:18
@ mtGiant
Definition: MonsterTypes.h:32
@ mtSnowGolem
Definition: MonsterTypes.h:62
@ mtFox
Definition: MonsterTypes.h:30
@ mtBlaze
Definition: MonsterTypes.h:15
@ mtLlama
Definition: MonsterTypes.h:39
@ mtIronGolem
Definition: MonsterTypes.h:38
@ mtCreeper
Definition: MonsterTypes.h:21
@ mtSpider
Definition: MonsterTypes.h:63
@ mtMule
Definition: MonsterTypes.h:42
@ mtPillager
Definition: MonsterTypes.h:50
@ mtGhast
Definition: MonsterTypes.h:31
@ mtParrot
Definition: MonsterTypes.h:45
@ mtZombifiedPiglin
Definition: MonsterTypes.h:81
@ mtSilverfish
Definition: MonsterTypes.h:58
@ mtZoglin
Definition: MonsterTypes.h:78
@ mtPanda
Definition: MonsterTypes.h:44
@ mtCod
Definition: MonsterTypes.h:19
@ mtStrider
Definition: MonsterTypes.h:66
@ mtSlime
Definition: MonsterTypes.h:61
@ mtWitherSkeleton
Definition: MonsterTypes.h:76
@ mtGuardian
Definition: MonsterTypes.h:33
eRabbitType
Definition: Rabbit.h:11
BlockType
Definition: BlockTypes.h:4
Item
Definition: Items.h:4
@ SplashPotion
@ Painting
@ FireCharge
@ Snowball
@ Minecart
@ ItemFrame
int GetBEInt(const std::byte *const a_Mem)
Reads four bytes from the specified memory location and interprets them as BigEndian int.
AStringVector StringSplit(const AString &str, const AString &delim)
Split the string at any of the listed delimiters.
Definition: StringUtils.cpp:55
std::vector< AString > AStringVector
Definition: StringUtils.h:12
std::string AString
Definition: StringUtils.h:11
Vector3< double > Vector3d
Definition: Vector3.h:485
Vector3< int > Vector3i
Definition: Vector3.h:487
eTagType
Definition: FastNBT.h:30
@ TAG_IntArray
Definition: FastNBT.h:43
@ TAG_ByteArray
Definition: FastNBT.h:39
@ TAG_End
Definition: FastNBT.h:32
@ TAG_List
Definition: FastNBT.h:41
@ TAG_Float
Definition: FastNBT.h:37
@ TAG_String
Definition: FastNBT.h:40
@ TAG_Short
Definition: FastNBT.h:34
@ TAG_Byte
Definition: FastNBT.h:33
@ TAG_Compound
Definition: FastNBT.h:42
@ TAG_Int
Definition: FastNBT.h:35
@ TAG_Double
Definition: FastNBT.h:38
#define MAX_MCA_FILES
If defined, the BlockSkyLight values will be copied over to BlockLight upon chunk saving,...
Definition: WSSAnvil.cpp:74
bool ParseString(const AString &a_JsonStr, Json::Value &a_Root, AString *a_ErrorMsg)
Definition: JsonUtils.cpp:34
void Write(const std::string &a_FileName, ContiguousByteBufferView a_Contents)
Writes a_Contents into file, compressing it along the way.
Definition: GZipFile.cpp:27
eBlockFace Facing(const BlockState Block)
Definition: BlockStates.cpp:20
unsigned char Rotation(const BlockState Block)
unsigned char Age(const BlockState Block)
unsigned char Level(const BlockState Block)
void ParseFromNBT(cEnchantments &a_Enchantments, const cParsedNBT &a_NBT, int a_EnchListTagIdx)
Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments)
std::pair< Namespace, std::string_view > SplitNamespacedID(std::string_view ID)
eMonsterType ToMonsterType(std::string_view a_ID)
static constexpr size_t SectionBlockCount
Definition: ChunkData.h:59
NIBBLETYPE GetMeta(Vector3i a_Position) const
Definition: ChunkData.h:81
NIBBLETYPE[SectionMetaCount] SectionMetaType
Definition: ChunkData.h:66
static constexpr size_t SectionMetaCount
Definition: ChunkData.h:60
BLOCKTYPE GetBlock(Vector3i a_Position) const
Definition: ChunkData.h:80
BLOCKTYPE[SectionBlockCount] SectionType
Definition: ChunkData.h:65
NIBBLETYPE[SectionLightCount] SectionType
Definition: ChunkData.h:106
static constexpr size_t SectionLightCount
Definition: ChunkData.h:101
Wraps the chunk coords into a single structure.
Definition: ChunkDef.h:57
int m_ChunkZ
Definition: ChunkDef.h:60
int m_ChunkX
Definition: ChunkDef.h:59
static void AbsoluteToRelative(int &a_X, int &a_Y, int &a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords into relative (chunk + block) coords:
Definition: ChunkDef.h:147
static void SetHeight(HeightMap &a_HeightMap, int a_X, int a_Z, HEIGHTTYPE a_Height)
Definition: ChunkDef.h:311
HEIGHTTYPE HeightMap[Width *Width]
The type used for any heightmap operations and storage; idx = x + Width * z; Height points to the hig...
Definition: ChunkDef.h:132
static size_t MakeIndex(int x, int y, int z)
Definition: ChunkDef.h:227
static const int Width
Definition: ChunkDef.h:124
static const size_t NumSections
Definition: ChunkDef.h:129
static const int Height
Definition: ChunkDef.h:125
EMCSBiome BiomeMap[Width *Width]
The type used for any biomemap operations and storage inside Cuberite, using Cuberite biomes (need no...
Definition: ChunkDef.h:137
ePickupState
Determines when the arrow can be picked up (depending on player gamemode).
Definition: ArrowEntity.h:34
@ psInSurvivalOrCreative
Definition: ArrowEntity.h:36
static eMaterial StringToMaterial(const AString &a_Material)
Returns the boat material for the passed string.
Definition: Boat.cpp:293
@ bmOak
Definition: Boat.h:30
Definition: Entity.h:76
void SetPitch(double a_Pitch)
Definition: Entity.cpp:2136
void SetYaw(double a_Yaw)
Definition: Entity.cpp:2125
float GetMaxHealth(void) const
Definition: Entity.h:407
void SetHealth(float a_Health)
Sets the health of this entity; doesn't broadcast any hurt animation.
Definition: Entity.cpp:900
void SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ)
Sets the speed of the entity, measured in m / sec.
Definition: Entity.cpp:2157
void SetPosition(double a_PosX, double a_PosY, double a_PosZ)
Definition: Entity.h:218
eType
All types of entity effects (numbers correspond to protocol / storage types)
Definition: EntityEffect.h:12
void SetProtocolFacing(Byte a_Facing)
Set the direction in which the entity is facing.
Definition: HangingEntity.h:37
void SetIsInGround(bool a_IsInGround)
Sets the internal InGround flag.
Definition: Item.h:37
cEnchantments m_Enchantments
Definition: Item.h:166
char m_ItemCount
Definition: Item.h:164
AString m_CustomName
Definition: Item.h:167
AStringVector m_LoreTable
Definition: Item.h:171
short m_ItemType
Definition: Item.h:163
int m_RepairCost
Definition: Item.h:200
void Empty(void)
Empties the item and frees up any dynamic storage used by the internals.
Definition: Item.cpp:63
cFireworkItem m_FireworkItem
Definition: Item.h:201
short m_ItemDamage
Definition: Item.h:165
void SetSlot(int a_X, int a_Y, const cItem &a_Item)
Definition: ItemGrid.cpp:121
int GetNumSlots(void) const
Definition: ItemGrid.h:40
void SetDropChanceBoots(float a_DropChanceBoots)
Definition: Monster.h:141
void SetCustomName(const AString &a_CustomName)
Sets the custom name of the monster.
Definition: Monster.cpp:946
void SetCanPickUpLoot(bool a_CanPickUpLoot)
Definition: Monster.h:142
void SetDropChanceLeggings(float a_DropChanceLeggings)
Definition: Monster.h:140
void SetDropChanceHelmet(float a_DropChanceHelmet)
Definition: Monster.h:138
void SetLeashToPos(Vector3d *pos)
Sets entity position to where is leashed this mob.
Definition: Monster.h:103
void SetDropChanceWeapon(float a_DropChanceWeapon)
Definition: Monster.h:137
void SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible)
Sets the custom name visiblity of this monster.
Definition: Monster.cpp:966
void SetDropChanceChestplate(float a_DropChanceChestplate)
Definition: Monster.h:139
eCatType
Definition: Ocelot.h:19
eVillagerType
Definition: Villager.h:19
bool IsLocked(void)
Returns true if the CS is currently locked.
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
Definition: File.h:38
static bool CreateFolder(const AString &a_FolderPath)
Creates a new folder with the specified name.
Definition: File.cpp:454
static char PathSeparator()
Definition: File.h:42
@ fmWrite
Definition: File.h:55
@ fmReadWrite
Definition: File.h:56
static bool Exists(const AString &a_FileName)
Returns true if the file specified exists.
Definition: File.cpp:294
bool Open(const AString &iFileName, eMode iMode)
Definition: File.cpp:52
int Write(const void *a_Buffer, size_t a_NumBytes)
Writes up to a_NumBytes bytes from a_Buffer, returns the number of bytes actually written,...
Definition: File.cpp:180
void Close(void)
Definition: File.cpp:102
AString GetPlayerNameFromUUID(const cUUID &a_UUID, bool a_UseOnlyCached=false)
Converts a UUID into a playername.
Definition: MojangAPI.cpp:281
cUUID GetUUIDFromPlayerName(const AString &a_PlayerName, bool a_UseOnlyCached=false)
Converts a player name into a UUID.
Definition: MojangAPI.cpp:254
static cRoot * Get()
Definition: Root.h:52
cMojangAPI & GetMojangAPI(void)
Definition: Root.h:113
Contains the data for a loaded / generated chunk, ready to be set into a cWorld.
Definition: SetChunkData.h:12
ChunkBlockData BlockData
Definition: SetChunkData.h:22
Contains the result of a compression or extraction operation.
Result CompressZLib(ContiguousByteBufferView Input)
Result ExtractZLib(ContiguousByteBufferView Input)
Definition: UUID.h:11
bool FromString(const AString &a_StringUUID)
Tries to interpret the string as a short or long form UUID and assign from it.
Definition: UUID.cpp:102
bool IsNil() const
Returns true if this contains the "nil" UUID with all bits set to 0.
Definition: UUID.h:30
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
void Set(T a_x, T a_y, T a_z)
Definition: Vector3.h:42
T z
Definition: Vector3.h:17
Definition: World.h:53
const AString & GetDataPath(void) const
Returns the data path to the world data.
Definition: World.h:694
int GetSpawnX(void) const
Definition: World.h:585
bool IsWeatherRain(void) const
Returns true if the current weather is rainy.
Definition: World.h:817
virtual cTickTimeLong GetWorldAge(void) const override
Definition: World.cpp:491
const AString & GetName(void) const
Returns the name of the world.
Definition: World.h:691
int GetSpawnZ(void) const
Definition: World.h:587
eGameMode GetGameMode(void) const
Returns the current game mode.
Definition: World.h:108
int GetSpawnY(void) const
Definition: World.h:586
cTickTimeLong GetWorldDate() const
Definition: World.cpp:500
bool IsWeatherStorm(void) const
Returns true if the current weather is stormy.
Definition: World.h:826
Parses and contains the parsed data Also implements data accessor functions for tree traversal and va...
Definition: FastNBT.h:153
std::string_view GetStringView(int a_Tag) const
Returns the value stored in a String tag.
Definition: FastNBT.h:286
int GetNextSibling(int a_Tag) const
Returns the next sibling of the specified tag, or -1 if none.
Definition: FastNBT.h:175
size_t GetErrorPos() const
Returns the position where an error occurred while parsing.
Definition: FastNBT.h:163
std::error_code GetErrorCode() const
Returns the error code for the parsing of the NBT data.
Definition: FastNBT.h:160
Int16 GetShort(int a_Tag) const
Returns the value stored in a Short tag.
Definition: FastNBT.h:227
const std::byte * GetData(int a_Tag) const
Returns the data stored in this tag.
Definition: FastNBT.h:191
int GetFirstChild(int a_Tag) const
Returns the first child of the specified tag, or -1 if none / not applicable.
Definition: FastNBT.h:169
double GetDouble(int a_Tag) const
Returns the value stored in a Double tag.
Definition: FastNBT.h:266
bool IsValid(void) const
Definition: FastNBT.h:157
eTagType GetType(int a_Tag) const
Definition: FastNBT.h:210
int FindChildByName(int a_Tag, const AString &a_Name) const
Returns the direct child tag of the specified name, or -1 if no such tag.
Definition: FastNBT.h:199
unsigned char GetByte(int a_Tag) const
Returns the value stored in a Byte tag.
Definition: FastNBT.h:220
size_t GetDataLength(int a_Tag) const
Returns the length of the tag's data, in bytes.
Definition: FastNBT.h:182
float GetFloat(int a_Tag) const
Returns the value stored in a Float tag.
Definition: FastNBT.h:248
Int32 GetInt(int a_Tag) const
Returns the value stored in an Int tag.
Definition: FastNBT.h:234
AString GetString(int a_Tag) const
Returns the value stored in a String tag.
Definition: FastNBT.h:280
eTagType GetChildrenType(int a_Tag) const
Returns the children type for a List tag; undefined on other tags.
Definition: FastNBT.h:213
void AddByte(const AString &a_Name, unsigned char a_Value)
Definition: FastNBT.cpp:551
void AddInt(const AString &a_Name, Int32 a_Value)
Definition: FastNBT.cpp:572
void Finish(void)
Definition: FastNBT.cpp:674
void AddString(const AString &a_Name, std::string_view a_Value)
Definition: FastNBT.cpp:616
void EndCompound(void)
Definition: FastNBT.cpp:499
void BeginCompound(const AString &a_Name)
Definition: FastNBT.cpp:481
ContiguousByteBufferView GetResult(void) const
Definition: FastNBT.h:351
void AddLong(const AString &a_Name, Int64 a_Value)
Definition: FastNBT.cpp:583
static void ParseFromNBT(cFireworkItem &a_FireworkItem, const cParsedNBT &a_NBT, int a_TagIdx, const ENUM_ITEM_TYPE a_Type)
Reads NBT data from a NBT object and populates a FireworkItem with it.
static void Serialize(const cWorld &aWorld, cChunkCoords aCoords, cFastNBTWriter &aWriter)
Serializes the chunk into the specified writer.
Implements the Anvil world storage schema.
Definition: WSSAnvil.h:28
bool SetChunkData(const cChunkCoords &a_Chunk, ContiguousByteBufferView a_Data)
Sets chunk data into the correct file; locks file CS as needed.
Definition: WSSAnvil.cpp:239
bool LoadMonsterBaseFromNBT(cMonster &a_Monster, const cParsedNBT &a_NBT, int a_TagIdx)
Loads monster common data from the NBT compound; returns true if successful.
Definition: WSSAnvil.cpp:3683
void LoadLeashKnotFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2078
void LoadSnowGolemFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3122
void LoadLeashToPosition(cMonster &a_Monster, const cParsedNBT &a_NBT, int a_TagIdx)
Loads the position to where is leashed the monster.
Definition: WSSAnvil.cpp:3740
void LoadMinecartRFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1831
void LoadMooshroomFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2726
void LoadPillagerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2887
void LoadThrownEnderpearlFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2278
void LoadVindicatorFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3284
AString DecodeSignLine(const AString &a_Line)
Decodes the text contained within a sign.
Definition: WSSAnvil.cpp:807
virtual bool SaveChunk(const cChunkCoords &a_Chunk) override
Definition: WSSAnvil.cpp:149
OwnedBlockEntity LoadBedFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:959
void LoadLlamaFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2688
void LoadBlockEntitiesFromNBT(cBlockEntities &a_BlockEntitites, const cParsedNBT &a_NBT, int a_Tag, const ChunkBlockData &a_BlockData)
Loads the chunk's BlockEntities from NBT data (a_Tag is the Level\TileEntities list tag; may be -1)
Definition: WSSAnvil.cpp:566
void LoadTNTFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1962
void LoadZombieVillagerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3528
void LoadPigFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2836
void LoadArrowFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2119
void LoadSkeletonFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3051
bool CheckBlockEntityType(const cParsedNBT &a_NBT, int a_TagIdx, const AStringVector &a_ExpectedTypes, Vector3i a_Pos)
Returns true iff the "id" child tag inside the specified tag equals (case-sensitive) any of the speci...
Definition: WSSAnvil.cpp:836
const std::byte * GetSectionData(const cParsedNBT &a_NBT, int a_Tag, const AString &a_ChildName, size_t a_Length)
Copies a_Length bytes of data from the specified NBT Tag's Child into the a_Destination buffer.
Definition: WSSAnvil.cpp:4021
bool GetChunkData(const cChunkCoords &a_Chunk, ContiguousByteBuffer &a_Data)
Gets chunk data from the correct file; locks file CS as needed.
Definition: WSSAnvil.cpp:224
void LoadSilverfishFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3031
OwnedBlockEntity LoadEnderChestFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1175
Compression::Compressor m_Compressor
Definition: WSSAnvil.h:95
void LoadSalmonFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2967
void LoadHuskFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2650
void LoadCowFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2392
std::shared_ptr< cMCAFile > LoadMCAFile(const cChunkCoords &a_Chunk)
Gets the correct MCA file either from cache or from disk, manages the m_MCAFiles cache; assumes m_CS ...
Definition: WSSAnvil.cpp:254
void LoadMuleFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2746
void LoadHorseFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2595
void LoadMinecartFFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1877
OwnedBlockEntity LoadBlockEntityFromNBT(const cParsedNBT &a_NBT, int a_Tag, Vector3i a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Loads the data for a block entity from the specified NBT tag.
Definition: WSSAnvil.cpp:621
void LoadFallingBlockFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1806
void LoadMinecartHFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1911
void LoadDrownedFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2450
void LoadChickenFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2363
void LoadGiantFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2555
void LoadItemGridFromNBT(cItemGrid &a_ItemGrid, const cParsedNBT &a_NBT, int a_ItemsTagIdx, int s_SlotOffset=0)
Loads contentents of an Items[] list tag into a cItemGrid ItemGrid begins at the specified slot offse...
Definition: WSSAnvil.cpp:779
void LoadGuardianFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2575
void LoadDolphinFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2432
void LoadCreeperFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2412
void LoadBlazeFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2314
void LoadWanderingTraderFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3293
void LoadHoglinFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2641
OwnedBlockEntity LoadBeaconFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:916
void LoadTraderLlamaFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3200
void LoadZoglinFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3444
void LoadSkeletonHorseFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3084
bool GetBlockEntityNBTPos(const cParsedNBT &a_NBT, int a_TagIdx, Vector3i &a_AbsPos)
Helper function for extracting the X, Y, and Z int subtags of a NBT compound; returns true if success...
Definition: WSSAnvil.cpp:3846
OwnedBlockEntity LoadDropperFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1127
void LoadBatFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2294
void LoadEvokerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2517
void LoadPickupFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1928
void LoadWitherFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3322
void LoadShulkerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3022
void LoadPandaFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2809
bool LoadDoublesListFromNBT(double *a_Doubles, int a_NumDoubles, const cParsedNBT &a_NBT, int a_TagIdx)
Loads an array of doubles of the specified length from the specified NBT list tag a_TagIdx; returns t...
Definition: WSSAnvil.cpp:3810
void LoadWitchFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3302
bool LoadEntityBaseFromNBT(cEntity &a_Entity, const cParsedNBT &a_NBT, int a_TagIdx)
Loads entity common data from the NBT compound; returns true if successful.
Definition: WSSAnvil.cpp:3624
void LoadCodFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2383
OwnedBlockEntity LoadEnchantingTableFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1150
void LoadWolfFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3368
OwnedBlockEntity LoadCommandBlockFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1066
void LoadPolarBearFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2896
void LoadRavagerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2958
OwnedBlockEntity LoadNoteBlockFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1507
OwnedBlockEntity LoadMobSpawnerFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1349
void LoadStriderFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3191
void LoadExpOrbFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1984
void LoadZombieHorseFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3486
void LoadFoxFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2526
void LoadSheepFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2976
void LoadWitherSkeletonFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3348
void LoadCaveSpiderFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2343
void LoadHangingFromNBT(cHangingEntity &a_Hanging, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2013
void LoadZombifiedPiglinFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3495
std::pair< AString, cUUID > LoadEntityOwner(const cParsedNBT &a_NBT, int a_TagIdx)
Loads the owner name and UUID from the entity at the specified NBT tag.
Definition: WSSAnvil.cpp:3571
OwnedBlockEntity LoadFlowerPotFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1205
OwnedBlockEntity LoadBannerFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:885
OwnedBlockEntity LoadBrewingstandFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:984
void LoadItemFrameFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2041
void LoadEnderCrystalFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1760
virtual bool LoadChunk(const cChunkCoords &a_Chunk) override
Definition: WSSAnvil.cpp:133
OwnedBlockEntity LoadFurnaceFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1244
void LoadEggFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2230
void LoadEndermiteFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2508
Compression::Extractor m_Extractor
Definition: WSSAnvil.h:94
void LoadSquidFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3162
void LoadPiglinBruteFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2878
cCriticalSection m_CS
Protects m_Files against multithreaded access.
Definition: WSSAnvil.h:88
void LoadIllusionerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2659
void LoadMinecartCFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1845
Compression::Result SaveChunkToData(const cChunkCoords &a_Chunk)
Saves the chunk into datastream (no locking needed)
Definition: WSSAnvil.cpp:332
OwnedBlockEntity LoadMobHeadFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1433
void LoadSnowballFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2214
void LoadEndermanFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2488
void LoadBoatFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1740
OwnedBlockEntity LoadSignFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1529
void ChunkLoadFailed(const cChunkCoords a_ChunkCoords, const AString &a_Reason, ContiguousByteBufferView a_ChunkDataToSave)
Reports that the specified chunk failed to load and saves the chunk data to an external file.
Definition: WSSAnvil.cpp:173
std::list< std::shared_ptr< cMCAFile > > m_Files
A MRU cache of MCA files.
Definition: WSSAnvil.h:92
void LoadRabbitFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2914
void LoadTropicalFishFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3209
void LoadZombieFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3453
void LoadPaintingFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2096
bool LoadItemFromNBT(cItem &a_Item, const cParsedNBT &a_NBT, int a_TagIdx)
Loads a cItem contents from the specified NBT tag; returns true if successful.
Definition: WSSAnvil.cpp:673
OwnedBlockEntity LoadHopperFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1304
bool LoadProjectileBaseFromNBT(cProjectileEntity &a_Entity, const cParsedNBT &a_NBT, int a_TagIx)
Loads projectile common data from the NBT compound; returns true if successful.
Definition: WSSAnvil.cpp:3788
void LoadTurtleFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3218
void LoadMagmaCubeFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2697
void LoadDonkeyFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2441
OwnedBlockEntity LoadDispenserFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1104
bool LoadHeightMapFromNBT(cChunkDef::HeightMap &a_HeightMap, const cParsedNBT &a_NBT, int a_TagIdx)
Loads the chunk's height map into a_HeightMap if heights present and valid; returns false otherwise.
Definition: WSSAnvil.cpp:496
bool LoadBiomeMapFromNBT(cChunkDef::BiomeMap &a_BiomeMap, const cParsedNBT &a_NBT, int a_TagIdx)
Loads the chunk's biome map into a_BiomeMap if biomes present and valid; returns false otherwise.
Definition: WSSAnvil.cpp:466
bool LoadChunkFromData(const cChunkCoords &a_Chunk, ContiguousByteBufferView a_Data)
Loads the chunk from the data (no locking needed)
Definition: WSSAnvil.cpp:305
void LoadFireballFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2246
void LoadVillagerFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3236
void LoadParrotFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2818
void LoadVexFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3227
void LoadFireChargeFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2262
void LoadPufferfishFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2905
void LoadEntitiesFromNBT(cEntityList &a_Entitites, const cParsedNBT &a_NBT, int a_Tag)
Loads the chunk's entities from NBT data (a_Tag is the Level\Entities list tag; may be -1)
Definition: WSSAnvil.cpp:532
void LoadElderGuardianFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2459
cWSSchema Super
Definition: WSSAnvil.h:29
void LoadMinecartTFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1894
bool LoadChunkFromNBT(const cChunkCoords &a_Chunk, const cParsedNBT &a_NBT, ContiguousByteBufferView a_RawChunkData)
Loads the chunk from NBT data (no locking needed).
Definition: WSSAnvil.cpp:345
OwnedBlockEntity LoadChestFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1042
void LoadOcelotFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2755
void LoadGhastFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2535
@ MCA_CHUNK_HEADER_LENGTH
There are 5 bytes of header in front of each chunk.
Definition: WSSAnvil.h:47
void LoadSlimeFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3093
void LoadOldMinecartFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:1716
void LoadSplashPotionFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2190
cWSSAnvil(cWorld *a_World, int a_CompressionFactor)
Definition: WSSAnvil.cpp:83
void LoadEnderDragonFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2468
void LoadPhantomFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2827
OwnedBlockEntity LoadJukeboxFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1327
OwnedBlockEntity LoadEndPortalFromNBT(const cParsedNBT &a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos)
Definition: WSSAnvil.cpp:1190
virtual ~cWSSAnvil() override
Definition: WSSAnvil.cpp:123
void LoadStrayFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3182
void LoadSpiderFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:3142
void LoadPiglinFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2869
bool LoadFloatsListFromNBT(float *a_Floats, int a_NumFloats, const cParsedNBT &a_NBT, int a_TagIdx)
Loads an array of floats of the specified length from the specified NBT list tag a_TagIdx; returns tr...
Definition: WSSAnvil.cpp:3828
void LoadEntityFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_EntityTagIdx, std::string_view a_EntityName)
Definition: WSSAnvil.cpp:1571
void LoadIronGolemFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2668
void LoadCatFromNBT(cEntityList &a_Entities, const cParsedNBT &a_NBT, int a_TagIdx)
Definition: WSSAnvil.cpp:2334
bool OpenFile(bool a_IsForReading)
Opens a MCA file either for a Read operation (fails if doesn't exist) or for a Write operation (creat...
Definition: WSSAnvil.cpp:3890
bool GetChunkData(const cChunkCoords &a_Chunk, ContiguousByteBuffer &a_Data)
Definition: WSSAnvil.cpp:3953
cMCAFile(cWSSAnvil &a_ParentSchema, const AString &a_FileName, int a_RegionX, int a_RegionZ)
Definition: WSSAnvil.cpp:3878
bool SetChunkData(const cChunkCoords &a_Chunk, ContiguousByteBufferView a_Data)
Definition: WSSAnvil.cpp:4035
unsigned FindFreeLocation(int a_LocalX, int a_LocalZ, size_t a_DataSize)
Finds a free location large enough to hold a_Data.
Definition: WSSAnvil.cpp:4123
std::unordered_map< size_t, OwnedBlockEntity > cBlockEntities
Definition: BlockEntity.h:17
std::unique_ptr< cBlockEntity > OwnedBlockEntity
Definition: BlockEntity.h:16