Cuberite
A lightweight, fast and extensible game server for Minecraft
PrefabPiecePool.cpp
Go to the documentation of this file.
1 
2 // PrefabPiecePool.cpp
3 
4 // Implements the cPrefabPiecePool class that represents a cPiecePool descendant that uses cPrefab instances as the pieces
5 
6 #include "Globals.h"
7 #include "PrefabPiecePool.h"
8 #include "VerticalStrategy.h"
9 #include "../Bindings/LuaState.h"
10 #include "../WorldStorage/SchematicFileSerializer.h"
11 #include "../StringCompression.h"
12 
13 
15 static std::map<AString, cBlockArea::eMergeStrategy> & GetMergeStrategyMap(void)
16 {
17  static std::map<AString, cBlockArea::eMergeStrategy> msmap;
18  if (msmap.empty())
19  {
20  // This is the first use, initialize the map:
21  msmap["msOverwrite"] = cBlockArea::msOverwrite;
22  msmap["msFillAir"] = cBlockArea::msFillAir;
23  msmap["msImprint"] = cBlockArea::msImprint;
24  msmap["msLake"] = cBlockArea::msLake;
25  msmap["msSpongePrint"] = cBlockArea::msSpongePrint;
26  msmap["msDifference"] = cBlockArea::msDifference;
27  msmap["msSimpleCompare"] = cBlockArea::msSimpleCompare;
28  msmap["msMask"] = cBlockArea::msMask;
29  }
30  return msmap;
31 }
32 
33 
34 
35 
36 
38 // cPrefabPiecePool:
39 
41 {
42 }
43 
44 
45 
46 
47 
49  const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs,
50  const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs,
51  int a_DefaultStartingPieceHeight
52 )
53 {
54  AddPieceDefs(a_PieceDefs, a_NumPieceDefs);
55  if (a_StartingPieceDefs != nullptr)
56  {
57  AddStartingPieceDefs(a_StartingPieceDefs, a_NumStartingPieceDefs, a_DefaultStartingPieceHeight);
58  }
59 }
60 
61 
62 
63 
64 
66 {
67  Clear();
68 }
69 
70 
71 
72 
73 
75 {
76  m_PiecesByConnector.clear();
77  for (cPieces::iterator itr = m_AllPieces.begin(), end = m_AllPieces.end(); itr != end; ++itr)
78  {
79  delete *itr;
80  }
81  m_AllPieces.clear();
82  for (cPieces::iterator itr = m_StartingPieces.begin(), end = m_StartingPieces.end(); itr != end; ++itr)
83  {
84  delete *itr;
85  }
86  m_StartingPieces.clear();
87 }
88 
89 
90 
91 
92 
93 void cPrefabPiecePool::AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs)
94 {
95  ASSERT(a_PieceDefs != nullptr);
96  for (size_t i = 0; i < a_NumPieceDefs; i++)
97  {
98  cPrefab * Prefab = new cPrefab(a_PieceDefs[i]);
99  m_AllPieces.push_back(Prefab);
100  AddToPerConnectorMap(Prefab);
101  }
102 }
103 
104 
105 
106 
107 
109  const cPrefab::sDef * a_StartingPieceDefs,
110  size_t a_NumStartingPieceDefs,
111  int a_DefaultPieceHeight
112 )
113 {
114  ASSERT(a_StartingPieceDefs != nullptr);
115  auto verticalStrategy = CreateVerticalStrategyFromString(fmt::format(FMT_STRING("Fixed|{}"), a_DefaultPieceHeight), false);
116  for (size_t i = 0; i < a_NumStartingPieceDefs; i++)
117  {
118  cPrefab * Prefab = new cPrefab(a_StartingPieceDefs[i]);
119  if (a_DefaultPieceHeight >= 0)
120  {
121  Prefab->SetVerticalStrategy(verticalStrategy);
122  }
123  m_StartingPieces.push_back(Prefab);
124  }
125 }
126 
127 
128 
129 
130 
131 bool cPrefabPiecePool::LoadFromFile(const AString & a_FileName, bool a_LogWarnings)
132 {
133  // Read the file into a string buffer, load from string:
134  auto contents = cFile::ReadWholeFile(a_FileName);
135  if (contents.empty())
136  {
137  CONDWARNING(a_LogWarnings, "Cannot read data from file %s", a_FileName.c_str());
138  return false;
139  }
140  return LoadFromString(contents, a_FileName, a_LogWarnings);
141 }
142 
143 
144 
145 
146 
147 bool cPrefabPiecePool::LoadFromString(const AString & a_Contents, const AString & a_FileName, bool a_LogWarnings)
148 {
149  // If the contents start with GZip signature, ungzip and retry:
150  if (a_Contents.substr(0, 3) == "\x1f\x8b\x08")
151  {
152  try
153  {
154  const auto Extracted = Compression::Extractor().ExtractGZip(
155  {
156  reinterpret_cast<const std::byte *>(a_Contents.data()), a_Contents.size()
157  });
158 
159  // Here we do an extra std::string conversion, hardly efficient, but...
160  // Better would be refactor into LoadFromByteView for the GZip decompression path, and getting cFile to support std::byte.
161  // ...so it'll do for now.
162 
163  return LoadFromString(std::string(Extracted.GetStringView()), a_FileName, a_LogWarnings);
164  }
165  catch (const std::exception & Oops)
166  {
167  CONDWARNING(a_LogWarnings, "Failed to decompress Gzip data in file %s. %s", a_FileName.c_str(), Oops.what());
168  return false;
169  }
170  }
171 
172  // Search the first 8 KiB of the file for the format auto-detection string:
173  const auto Header = a_Contents.substr(0, 8 KiB);
174  if (Header.find("CubesetFormatVersion =") != AString::npos)
175  {
176  return LoadFromCubeset(a_Contents, a_FileName, a_LogWarnings);
177  }
178  CONDWARNING(a_LogWarnings, "Cannot load prefabs from file %s, unknown file format", a_FileName.c_str());
179  return false;
180 }
181 
182 
183 
184 
185 
186 bool cPrefabPiecePool::LoadFromCubeset(const AString & a_Contents, const AString & a_FileName, bool a_LogWarnings)
187 {
188  // Load the file in the Lua interpreter:
189  cLuaState Lua(fmt::format(FMT_STRING("LoadablePiecePool {}"), a_FileName));
190  Lua.Create();
191  cLuaState::cLock lock(Lua);
192  if (!Lua.LoadString(a_Contents, a_FileName, a_LogWarnings))
193  {
194  // Reason for failure has already been logged in LoadFile()
195  return false;
196  }
197 
198  // Check the version:
199  int Version = 0;
200  if (!Lua.GetNamedGlobal("Cubeset.Metadata.CubesetFormatVersion", Version))
201  {
202  CONDWARNING(a_LogWarnings, "Cannot load cubeset %s, it doesn't contain version information.", a_FileName);
203  return false;
204  }
205 
206  // Load the data, using the correct version loader:
207  if (Version == 1)
208  {
209  return LoadFromCubesetVer1(a_FileName, Lua, a_LogWarnings);
210  }
211 
212  // Unknown version:
213  CONDWARNING(a_LogWarnings, "Cannot load cubeset %s, version (%d) not supported.", a_FileName, Version);
214  return false;
215 }
216 
217 
218 
219 
220 
222 {
223  cPiece::cConnectors Connectors = (static_cast<const cPiece *>(a_Prefab))->GetConnectors();
224  for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
225  {
226  m_PiecesByConnector[itr->m_Type].push_back(a_Prefab);
227  }
228 }
229 
230 
231 
232 
233 
234 bool cPrefabPiecePool::LoadFromCubesetVer1(const AString & a_FileName, cLuaState & a_LuaState, bool a_LogWarnings)
235 {
236  // Load the metadata and apply the known ones:
237  ReadPoolMetadataCubesetVer1(a_FileName, a_LuaState, a_LogWarnings);
238  ApplyBaseMetadataCubesetVer1(a_FileName, a_LogWarnings);
239 
240  // Push the Cubeset.Pieces global value on the stack:
241  auto pieces = a_LuaState.WalkToNamedGlobal("Cubeset.Pieces");
242  if (!pieces.IsValid() || !lua_istable(a_LuaState, -1))
243  {
244  CONDWARNING(a_LogWarnings, "The cubeset file %s doesn't contain any pieces", a_FileName.c_str());
245  return false;
246  }
247 
248  // Iterate over all items in the Cubeset.Pieces value:
249  int idx = 1;
250  bool res = true;
251  while (true)
252  {
253  lua_pushinteger(a_LuaState, idx); // stk: [Pieces] [idx]
254  lua_gettable(a_LuaState, -2); // stk: [Pieces] [PieceItem]
255  if (!lua_istable(a_LuaState, -1))
256  {
257  // The PieceItem is not present, we've iterated over all items
258  lua_pop(a_LuaState, 1); // stk: [Pieces]
259  break;
260  }
261  if (!LoadCubesetPieceVer1(a_FileName, a_LuaState, idx, a_LogWarnings))
262  {
263  res = false;
264  }
265  lua_pop(a_LuaState, 1); // stk: [Pieces]
266  idx += 1;
267  }
268  return res;
269 }
270 
271 
272 
273 
274 
275 bool cPrefabPiecePool::LoadCubesetPieceVer1(const AString & a_FileName, cLuaState & a_LuaState, int a_PieceIndex, bool a_LogWarnings)
276 {
277  ASSERT(lua_istable(a_LuaState, -1));
278 
279  // The piece name is optional, but useful for debugging messages:
280  AString PieceName;
281  if (!a_LuaState.GetNamedValue("OriginData.ExportName", PieceName))
282  {
283  PieceName = fmt::format(FMT_STRING("Piece #{}"), a_PieceIndex);
284  }
285 
286  // Read the hitbox dimensions:
287  cCuboid Hitbox;
288  if (
289  !a_LuaState.GetNamedValue("Hitbox.MinX", Hitbox.p1.x) ||
290  !a_LuaState.GetNamedValue("Hitbox.MinY", Hitbox.p1.y) ||
291  !a_LuaState.GetNamedValue("Hitbox.MinZ", Hitbox.p1.z) ||
292  !a_LuaState.GetNamedValue("Hitbox.MaxX", Hitbox.p2.x) ||
293  !a_LuaState.GetNamedValue("Hitbox.MaxY", Hitbox.p2.y) ||
294  !a_LuaState.GetNamedValue("Hitbox.MaxZ", Hitbox.p2.z)
295  )
296  {
297  CONDWARNING(a_LogWarnings, "Cannot load piece %s from file %s, it's missing hitbox information", PieceName, a_FileName);
298  return false;
299  }
300 
301  // Load the prefab data:
302  auto prefab = LoadPrefabFromCubesetVer1(a_FileName, a_LuaState, PieceName, a_LogWarnings);
303  if (prefab == nullptr)
304  {
305  return false;
306  }
307  prefab->SetHitBox(Hitbox);
308 
309  // Read the connectors
310  if (!ReadConnectorsCubesetVer1(a_FileName, a_LuaState, PieceName, prefab.get(), a_LogWarnings))
311  {
312  return false;
313  }
314 
315  // Read the allowed rotations. It is an optional metadata value, default to 0:
316  int AllowedRotations = 0;
317  a_LuaState.GetNamedValue("Metadata.AllowedRotations", AllowedRotations);
318  prefab->SetAllowedRotations(AllowedRotations);
319 
320  // Read the relevant metadata for the piece:
321  if (!ReadPieceMetadataCubesetVer1(a_FileName, a_LuaState, PieceName, prefab.get(), a_LogWarnings))
322  {
323  return false;
324  }
325 
326  // If the piece is a starting piece, check that it has a vertical strategy:
327  int IsStartingPiece = 0;
328  a_LuaState.GetNamedValue("Metadata.IsStarting", IsStartingPiece);
329  if (IsStartingPiece != 0)
330  {
331  if (prefab->GetVerticalStrategy() == nullptr)
332  {
333  CONDWARNING(a_LogWarnings, "Starting prefab %s in file %s doesn't have its VerticalStrategy set. Setting to Fixed|150.",
334  PieceName, a_FileName
335  );
336  VERIFY(prefab->SetVerticalStrategyFromString("Fixed|150", false));
337  }
338  }
339 
340  // Add the prefab into the list of pieces:
341  if (IsStartingPiece != 0)
342  {
343  m_StartingPieces.push_back(prefab.release());
344  }
345  else
346  {
347  auto p = prefab.release();
348  m_AllPieces.push_back(p);
350  }
351 
352  return true;
353 }
354 
355 
356 
357 
358 
360  const AString & a_FileName,
361  cLuaState & a_LuaState,
362  const AString & a_PieceName,
363  bool a_LogWarnings
364 )
365 {
366  // First try loading a referenced schematic file, if any:
367  AString SchematicFileName;
368  if (a_LuaState.GetNamedValue("SchematicFileName", SchematicFileName))
369  {
370  auto PathEnd = a_FileName.find_last_of("/\\"); // Find the last path separator
371  if (PathEnd != AString::npos)
372  {
373  SchematicFileName = a_FileName.substr(0, PathEnd) + SchematicFileName;
374  }
375  cBlockArea area;
376  try
377  {
378  cSchematicFileSerializer::LoadFromSchematicFile(area, SchematicFileName);
379  }
380  catch (const std::exception & Oops)
381  {
382  CONDWARNING(a_LogWarnings, "Cannot load schematic file \"%s\" for piece %s in cubeset %s. %s",
383  SchematicFileName.c_str(), a_PieceName.c_str(), a_FileName.c_str(), Oops.what()
384  );
385  return nullptr;
386  }
387  return std::make_unique<cPrefab>(area);
388  } // if (SchematicFileName)
389 
390  // There's no referenced schematic file, load from BlockDefinitions / BlockData.
391  // Get references to the data and the table.concat function:
392  cLuaState::cRef TableConcat, BlockDefinitions, BlockData;
393  if (
394  !a_LuaState.GetNamedGlobal("table.concat", TableConcat) ||
395  !a_LuaState.GetNamedValue("BlockDefinitions", BlockDefinitions) ||
396  !a_LuaState.GetNamedValue("BlockData", BlockData)
397  )
398  {
399  CONDWARNING(a_LogWarnings, "Cannot parse block data for piece %s in cubeset %s", a_PieceName.c_str(), a_FileName.c_str());
400  return nullptr;
401  }
402 
403  // Call table.concat() on the BlockDefinitions:
404  AString BlockDefStr;
405  if (!a_LuaState.Call(TableConcat, BlockDefinitions, "\n", cLuaState::Return, BlockDefStr))
406  {
407  CONDWARNING(a_LogWarnings, "Cannot concat block definitions for piece %s in cubeset %s", a_PieceName.c_str(), a_FileName.c_str());
408  return nullptr;
409  }
410 
411  // Call table.concat() on the BlockData:
412  AString BlockDataStr;
413  if (!a_LuaState.Call(TableConcat, BlockData, "", cLuaState::Return, BlockDataStr))
414  {
415  CONDWARNING(a_LogWarnings, "Cannot concat block data for piece %s in cubeset %s", a_PieceName.c_str(), a_FileName.c_str());
416  return nullptr;
417  }
418 
419  // Read the size:
420  int SizeX = 0, SizeY = 0, SizeZ = 0;
421  if (
422  !a_LuaState.GetNamedValue("Size.x", SizeX) ||
423  !a_LuaState.GetNamedValue("Size.y", SizeY) ||
424  !a_LuaState.GetNamedValue("Size.z", SizeZ)
425  )
426  {
427  CONDWARNING(a_LogWarnings, "Cannot load piece %s from file %s, its size information is missing", a_PieceName.c_str(), a_FileName.c_str());
428  return nullptr;
429  }
430 
431  // Check that the size matches the data length:
432  if (static_cast<size_t>(SizeX * SizeY * SizeZ) != BlockDataStr.size())
433  {
434  CONDWARNING(a_LogWarnings, "Cannot create piece %s from file %s, its size (%d) doesn't match the blockdata length (%u)",
435  a_PieceName.c_str(), a_FileName.c_str(),
436  SizeX * SizeY * SizeZ, static_cast<unsigned>(BlockDataStr.size())
437  );
438  return nullptr;
439  }
440 
441  return std::make_unique<cPrefab>(BlockDefStr, BlockDataStr, SizeX, SizeY, SizeZ);
442 }
443 
444 
445 
446 
447 
449  const AString & a_FileName,
450  cLuaState & a_LuaState,
451  const AString & a_PieceName,
452  cPrefab * a_Prefab,
453  bool a_LogWarnings
454 )
455 {
456  // Get the Connectors subtable:
457  auto conns = a_LuaState.WalkToValue("Connectors");
458  if (!conns.IsValid())
459  {
460  CONDWARNING(a_LogWarnings, "Cannot load piece %s from file %s, it has no connectors definition.", a_PieceName.c_str(), a_FileName.c_str());
461  return false;
462  }
463 
464  // Iterate over all items in the Connectors table:
465  int idx = 1;
466  bool res = true;
467  while (true)
468  {
469  lua_pushinteger(a_LuaState, idx); // stk: [Connectors] [idx]
470  lua_gettable(a_LuaState, -2); // stk: [Connectors] [conn]
471  if (!lua_istable(a_LuaState, -1))
472  {
473  // The connector is not present, we've iterated over all items
474  lua_pop(a_LuaState, 1); // stk: [Connectors]
475  break;
476  }
477  int Type = 0, RelX = 0, RelY = 0, RelZ = 0;
478  AString DirectionStr;
480  if (
481  !a_LuaState.GetNamedValue("Type", Type) ||
482  !a_LuaState.GetNamedValue("RelX", RelX) ||
483  !a_LuaState.GetNamedValue("RelY", RelY) ||
484  !a_LuaState.GetNamedValue("RelZ", RelZ) ||
485  !a_LuaState.GetNamedValue("Direction", DirectionStr) ||
487  )
488  {
489  if (a_LogWarnings)
490  {
491  FLOGWARNING("Piece {0} in file {1} has a malformed Connector at index {2} ({3}, type {4}, direction {5}). Skipping the connector.",
492  a_PieceName, a_FileName, idx, Vector3i{RelX, RelY, RelZ}, Type, DirectionStr
493  );
494  }
495  res = false;
496  lua_pop(a_LuaState, 1); // stk: [Connectors]
497  idx += 1;
498  continue;
499  }
500  a_Prefab->AddConnector(RelX, RelY, RelZ, Direction, Type);
501  lua_pop(a_LuaState, 1); // stk: [Connectors]
502  idx += 1;
503  }
504  return res;
505 }
506 
507 
508 
509 
510 
512  const AString & a_FileName,
513  cLuaState & a_LuaState,
514  const AString & a_PieceName,
515  cPrefab * a_Prefab,
516  bool a_LogWarnings
517 )
518 {
519  // Push the Metadata table on top of the Lua stack:
520  auto md = a_LuaState.WalkToValue("Metadata");
521  if (!md.IsValid())
522  {
523  return false;
524  }
525 
526  // Get the values:
527  int AddWeightIfSame = 0, DefaultWeight = 100, MoveToGround = 0;
528  AString DepthWeight, MergeStrategy, VerticalLimit, VerticalStrategy;
529  a_LuaState.GetNamedValue("AddWeightIfSame", AddWeightIfSame);
530  a_LuaState.GetNamedValue("DefaultWeight", DefaultWeight);
531  a_LuaState.GetNamedValue("DepthWeight", DepthWeight);
532  a_LuaState.GetNamedValue("MergeStrategy", MergeStrategy);
533  a_LuaState.GetNamedValue("MoveToGround", MoveToGround);
534  a_LuaState.GetNamedValue("VerticalLimit", VerticalLimit);
535  a_LuaState.GetNamedValue("VerticalStrategy", VerticalStrategy);
536 
537  // Apply the values:
538  a_Prefab->SetAddWeightIfSame(AddWeightIfSame);
539  a_Prefab->SetDefaultWeight(DefaultWeight);
540  a_Prefab->ParseDepthWeight(DepthWeight.c_str());
541  auto msmap = GetMergeStrategyMap();
542  auto strategy = msmap.find(MergeStrategy);
543  if (strategy == msmap.end())
544  {
545  CONDWARNING(a_LogWarnings, "Unknown merge strategy (\"%s\") specified for piece %s in file %s. Using msSpongePrint instead.",
546  MergeStrategy.c_str(), a_PieceName.c_str(), a_FileName.c_str()
547  );
549  }
550  else
551  {
552  a_Prefab->SetMergeStrategy(strategy->second);
553  }
554  a_Prefab->SetMoveToGround(MoveToGround != 0);
555 
556  AString ExpandFloorStrategyStr;
557  if (!a_LuaState.GetNamedValue("ExpandFloorStrategy", ExpandFloorStrategyStr))
558  {
559  // Check the older variant for ExpandFloorStrategy, ShouldExpandFloor:
560  int ShouldExpandFloor;
561  if (a_LuaState.GetNamedValue("ShouldExpandFloor", ShouldExpandFloor))
562  {
563  LOG("Piece \"%s\" in file \"%s\" is using the old \"ShouldExpandFloor\" attribute. Use the new \"ExpandFloorStrategy\" attribute instead for more options.",
564  a_PieceName.c_str(), a_FileName.c_str()
565  );
566  a_Prefab->SetExtendFloorStrategy((ShouldExpandFloor != 0) ? cPrefab::efsRepeatBottomTillNonAir : cPrefab::efsNone);
567  }
568  }
569  else
570  {
571  auto lcExpandFloorStrategyStr = StrToLower(ExpandFloorStrategyStr);
572  if (lcExpandFloorStrategyStr == "repeatbottomtillnonair")
573  {
575  }
576  else if (lcExpandFloorStrategyStr == "repeatbottomtillsolid")
577  {
579  }
580  else
581  {
582  if (lcExpandFloorStrategyStr != "none")
583  {
584  LOGWARNING("Piece \"%s\" in file \"%s\" is using an unknown \"ExpandFloorStrategy\" attribute value: \"%s\"",
585  a_PieceName.c_str(), a_FileName.c_str(), ExpandFloorStrategyStr.c_str()
586  );
587  }
589  }
590  }
591  if (!VerticalLimit.empty())
592  {
593  if (!a_Prefab->SetVerticalLimitFromString(VerticalLimit, a_LogWarnings))
594  {
595  CONDWARNING(a_LogWarnings, "Unknown VerticalLimit (\"%s\") specified for piece %s in file %s. Using no limit instead.",
596  VerticalLimit.c_str(), a_PieceName.c_str(), a_FileName.c_str()
597  );
598  }
599  }
600  a_Prefab->SetVerticalStrategyFromString(VerticalStrategy, a_LogWarnings);
601 
602  AString ModifiersStr;
603  if (a_LuaState.GetNamedValue("Modifiers", ModifiersStr))
604  {
605  a_Prefab->SetPieceModifiersFromString(ModifiersStr, a_LogWarnings);
606  }
607 
608  return true;
609 }
610 
611 
612 
613 
614 
616  const AString & a_FileName,
617  bool a_LogWarnings
618 )
619 {
620  // Set the metadata values to defaults:
621  m_MinDensity = 100;
622  m_MaxDensity = 100;
627 
628  // Read the metadata values:
629  m_IntendedUse = GetMetadata("IntendedUse");
632  GetStringMapInteger(m_Metadata, "VillageRoadBlockType", m_VillageRoadBlockType);
633  GetStringMapInteger(m_Metadata, "VillageRoadBlockMeta", m_VillageRoadBlockMeta);
634  GetStringMapInteger(m_Metadata, "VillageWaterRoadBlockType", m_VillageWaterRoadBlockType);
635  GetStringMapInteger(m_Metadata, "VillageWaterRoadBlockMeta", m_VillageWaterRoadBlockMeta);
636 
637  // Read the allowed biomes:
638  AString allowedBiomes = GetMetadata("AllowedBiomes");
639  if (allowedBiomes.empty())
640  {
641  // All biomes are allowed:
642  for (int b = biFirstBiome; b <= biMaxBiome; b++)
643  {
644  m_AllowedBiomes.insert(static_cast<EMCSBiome>(b));
645  }
646  for (int b = biFirstVariantBiome; b <= biMaxVariantBiome; b++)
647  {
648  m_AllowedBiomes.insert(static_cast<EMCSBiome>(b));
649  }
650  }
651  else
652  {
653  auto biomes = StringSplitAndTrim(allowedBiomes, ",");
654  for (const auto & biome: biomes)
655  {
656  EMCSBiome b = StringToBiome(biome);
657  if (b == biInvalidBiome)
658  {
659  CONDWARNING(a_LogWarnings, "Invalid biome (\"%s\") specified in AllowedBiomes in cubeset file %s. Skipping the biome.",
660  biome.c_str(), a_FileName.c_str()
661  );
662  continue;
663  }
664  m_AllowedBiomes.insert(b);
665  }
666  }
667 }
668 
669 
670 
671 
672 
674  const AString & a_FileName,
675  cLuaState & a_LuaState,
676  bool a_LogWarnings
677 )
678 {
679  // Push the Cubeset.Metadata table on top of the Lua stack:
680  auto gp = a_LuaState.WalkToNamedGlobal("Cubeset.Metadata");
681  if (!gp.IsValid())
682  {
683  return true;
684  }
685 
686  // Iterate over elements in the table, put them into the m_GeneratorParams map:
687  lua_pushnil(a_LuaState); // Table is at index -2, starting key (nil) at index -1
688  while (lua_next(a_LuaState, -2) != 0)
689  {
690  // Table at index -3, key at index -2, value at index -1
691  AString key, val;
692  a_LuaState.GetStackValues(-2, key, val);
693  m_Metadata[key] = val;
694  lua_pop(a_LuaState, 1); // Table at index -2, key at index -1
695  }
696  return true;
697 }
698 
699 
700 
701 
702 
704 {
705  auto itr = m_Metadata.find(a_ParamName);
706  if (itr == m_Metadata.end())
707  {
708  return AString();
709  }
710  return itr->second;
711 }
712 
713 
714 
715 
716 
717 void cPrefabPiecePool::AssignGens(int a_Seed, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_SeaLevel)
718 {
719  // Assign the generator linkage to all starting pieces' VerticalStrategies:
720  for (auto & piece: m_StartingPieces)
721  {
722  auto verticalStrategy = piece->GetVerticalStrategy();
723  if (verticalStrategy != nullptr)
724  {
725  verticalStrategy->AssignGens(a_Seed, a_BiomeGen, a_HeightGen, a_SeaLevel);
726  }
727  } // for piece - m_StartingPieces[]
728 
729  // Assign the generator linkage to all pieces' VerticalLimits:
730  for (auto & piece: m_AllPieces)
731  {
732  auto verticalLimit = piece->GetVerticalLimit();
733  if (verticalLimit != nullptr)
734  {
735  verticalLimit->AssignGens(a_Seed, a_BiomeGen, a_HeightGen, a_SeaLevel);
736  }
737  auto modifiers = piece->GetModifiers();
738  if (modifiers.size() > 0)
739  {
740  for (size_t i = 0; i < modifiers.size(); i++)
741  {
742  modifiers[i]->AssignSeed(a_Seed);
743  }
744  }
745  } // for piece - m_AllPieces[]
746 }
747 
748 
749 
750 
751 
753 {
754  return m_PiecesByConnector[a_ConnectorType];
755 }
756 
757 
758 
759 
760 
762 {
763  if (m_StartingPieces.empty())
764  {
765  return m_AllPieces;
766  }
767  else
768  {
769  return m_StartingPieces;
770  }
771 }
772 
773 
774 
775 
776 
777 int cPrefabPiecePool::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece)
778 {
779  return (static_cast<const cPrefab &>(a_NewPiece)).GetPieceWeight(a_PlacedPiece, a_ExistingConnector);
780 }
781 
782 
783 
784 
785 
787 {
788  return (static_cast<const cPrefab &>(a_NewPiece)).GetDefaultWeight();
789 }
790 
791 
792 
793 
794 
796 {
797  // Do nothing
798  UNUSED(a_Piece);
799 }
800 
801 
802 
803 
804 
806 {
807  // Do nothing
808 }
EMCSBiome StringToBiome(const AString &a_BiomeString)
Translates a biome string to biome enum.
Definition: BiomeDef.cpp:94
EMCSBiome
Biome IDs The first batch corresponds to the clientside biomes, used by MineCraft.
Definition: BiomeDef.h:18
@ biMaxBiome
Definition: BiomeDef.h:70
@ biInvalidBiome
Definition: BiomeDef.h:19
@ biFirstVariantBiome
Definition: BiomeDef.h:76
@ biMaxVariantBiome
Definition: BiomeDef.h:100
@ biFirstBiome
Definition: BiomeDef.h:21
@ E_BLOCK_PLANKS
Definition: BlockType.h:15
@ E_BLOCK_GRAVEL
Definition: BlockType.h:23
std::vector< cPiece * > cPieces
Definition: PiecePool.h:262
static std::map< AString, cBlockArea::eMergeStrategy > & GetMergeStrategyMap(void)
Returns the map of string => eMergeStrategy used when translating cubeset file merge strategies.
cPiece::cVerticalStrategyPtr CreateVerticalStrategyFromString(const AString &a_StrategyDesc, bool a_LogWarnings)
Returns a new cPiece::cVerticalStrategy descendant based on the specified description.
#define VERIFY(x)
Definition: Globals.h:280
#define KiB
Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it,...
Definition: Globals.h:234
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
void LOG(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:55
void FLOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:41
#define CONDWARNING(ShouldLog,...)
Definition: LoggerSimple.h:99
Direction
AStringVector StringSplitAndTrim(const AString &str, const AString &delim)
Split the string at any of the listed delimiters and trim each value.
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
T GetStringMapInteger(const AStringMap &a_Map, const AString &a_Key, T a_Default)
Returns a number (of any integer type T) from a key-value string map.
Definition: StringUtils.h:216
std::string AString
Definition: StringUtils.h:11
Parses a string containing a range in which both values are optional ("<MinHeight>|<MaxHeight>") into...
Parses a string containing a range in which both values are optional ("<MinHeight>|<MaxHeight>") into...
Encapsulates a Lua state and provides some syntactic sugar for common operations.
Definition: LuaState.h:56
bool Call(const FnT &a_Function, Args &&... args)
Call the specified Lua function.
Definition: LuaState.h:751
bool GetNamedValue(const AString &a_Name, T &a_Value)
Retrieves the named value in the table at the top of the Lua stack.
Definition: LuaState.h:720
static const cRet Return
Definition: LuaState.h:445
cStackValue WalkToNamedGlobal(const AString &a_Name)
Pushes the named value in the global table to the top of the stack.
Definition: LuaState.cpp:1591
bool GetNamedGlobal(const AString &a_Name, T &a_Value)
Retrieves the named global value.
Definition: LuaState.h:733
cStackValue WalkToValue(const AString &a_Name)
Pushes the named value in the table at the top of the stack.
Definition: LuaState.cpp:1556
bool LoadString(const AString &a_StringToLoad, const AString &a_FileName, bool a_LogWarnings=true)
Loads the specified string.
Definition: LuaState.cpp:673
bool GetStackValues(int a_StartStackPos, Arg1 &&a_Arg1, Args &&... args)
Retrieves a list of values from the Lua stack, starting at the specified index.
Definition: LuaState.h:766
void Create(void)
Creates the m_LuaState, if not created already.
Definition: LuaState.cpp:480
Provides a RAII-style locking for the LuaState.
Definition: LuaState.h:145
Used for storing references to object in the global registry.
Definition: LuaState.h:160
@ msOverwrite
Definition: BlockArea.h:60
@ msSimpleCompare
Definition: BlockArea.h:66
@ msDifference
Definition: BlockArea.h:65
@ msSpongePrint
Definition: BlockArea.h:64
Definition: Cuboid.h:10
Vector3i p2
Definition: Cuboid.h:13
Vector3i p1
Definition: Cuboid.h:13
The interface that a biome generator must implement A biome generator takes chunk coords on input and...
The interface that is used to query terrain height from the shape generator.
Represents a single piece.
Definition: PiecePool.h:21
void SetVerticalStrategy(cVerticalStrategyPtr a_VerticalStrategy)
Definition: PiecePool.h:213
bool SetVerticalStrategyFromString(const AString &a_StrategyDesc, bool a_LogWarnings)
Sets the vertical strategy based on the description in the string.
Definition: PiecePool.cpp:20
bool SetVerticalLimitFromString(const AString &a_LimitDesc, bool a_LogWarnings)
Sets the vertical limit based on the description string.
Definition: PiecePool.cpp:35
bool SetPieceModifiersFromString(const AString &a_Definition, bool a_LogWarnings)
Sets the modifiers with their params in the string.
Definition: PiecePool.cpp:50
std::vector< cConnector > cConnectors
Definition: PiecePool.h:95
static bool StringToDirection(const AString &a_Value, eDirection &a_Out)
Converts the string representation of a direction into the eDirection enum value.
Definition: PiecePool.cpp:401
Represents a single piece that has been placed to specific coords in the world.
Definition: PiecePool.h:328
Definition: Prefab.h:33
void SetMergeStrategy(cBlockArea::eMergeStrategy a_MergeStrategy)
Sets the merge strategy to be used when drawing the piece.
Definition: Prefab.h:148
void SetMoveToGround(bool a_MoveToGround)
Sets the flag whether the prefab should be moved to ground level before being drawn.
Definition: Prefab.h:151
void SetExtendFloorStrategy(eExtendFloorStrategy a_Strategy)
Sets the strategy to use between the bottom of the prefab and the terrain top.
Definition: Prefab.h:154
void ParseDepthWeight(const char *a_DepthWeightDef)
Parses the per-depth weight into m_DepthWeight member.
Definition: Prefab.cpp:446
void AddConnector(int a_RelX, int a_RelY, int a_RelZ, cPiece::cConnector::eDirection a_Direction, int a_Type)
Adds the specified connector to the list of connectors this piece supports.
Definition: Prefab.cpp:320
void SetAddWeightIfSame(int a_AddWeightIfSame)
Sets the AddWeightIfSame member, that is used to modify the weight when the previous piece is the sam...
Definition: Prefab.h:132
@ efsRepeatBottomTillSolid
Repeat the bottom-most block down until the first solid block; non-solids are overwritten.
Definition: Prefab.h:40
@ efsRepeatBottomTillNonAir
Repeat the bottom-most block down until the first non-air block.
Definition: Prefab.h:39
@ efsNone
No processing, the prefab is left "floating in the air".
Definition: Prefab.h:38
void SetDefaultWeight(int a_DefaultWeight)
Sets the (unmodified) DefaultWeight property for this piece.
Definition: Prefab.cpp:311
void ApplyBaseMetadataCubesetVer1(const AString &a_FileName, bool a_LogWarnings)
Applies the base known metadata from the m_Metadata map into this pool.
BLOCKTYPE m_VillageWaterRoadBlockType
The block type used for the village roads if the road is on water.
cPrefabPiecePool(void)
Creates an empty instance.
int m_MaxDensity
The maximum density, as read from the metadata.
void Clear(void)
Removes and frees all pieces from this pool.
int m_MinDensity
The minimum density, as read from the metadata.
cPiecesMap m_PiecesByConnector
The map that has all pieces by their connector types The pieces are copies out of m_AllPieces and sho...
virtual int GetStartingPieceWeight(const cPiece &a_NewPiece) override
Returns the relative weight with which the a_NewPiece is to be selected for placing as the first piec...
BLOCKTYPE m_VillageRoadBlockType
The block type to use for the village roads.
bool ReadPoolMetadataCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, bool a_LogWarnings)
Reads the metadata for the entire pool from the cubeset file, stores it in the m_Metadata map.
bool LoadFromCubeset(const AString &a_Contents, const AString &a_FileName, bool a_LogWarnings)
Loads the pieces from the specified string containing Cubeset file data.
virtual ~cPrefabPiecePool() override
Destroys the pool, freeing all pieces.
std::unique_ptr< cPrefab > LoadPrefabFromCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, const AString &a_PieceName, bool a_LogWarnings)
Loads a single piece's prefab from the cubeset file parsed into the specified Lua state.
cPieces m_StartingPieces
The pieces that are used as starting pieces.
void AddPieceDefs(const cPrefab::sDef *a_PieceDefs, size_t a_NumPieceDefs)
Adds pieces from the specified definitions into m_AllPieces.
virtual int GetPieceWeight(const cPlacedPiece &a_PlacedPiece, const cPiece::cConnector &a_ExistingConnector, const cPiece &a_NewPiece) override
Returns the relative weight with which the a_NewPiece is to be selected for placing under a_PlacedPie...
virtual cPieces GetStartingPieces(void) override
Returns the pieces that should be used as the starting point.
AString m_IntendedUse
The intended use of this piece pool, as specified by the pool's metadata.
bool LoadFromFile(const AString &a_FileName, bool a_LogWarnings)
Loads the pieces from the specified file.
NIBBLETYPE m_VillageRoadBlockMeta
The block meta to use for the village roads.
cPieces m_AllPieces
All the pieces that are allowed for building.
void AddToPerConnectorMap(cPrefab *a_Prefab)
Adds the prefab to the m_PiecesByConnector map for all its connectors.
std::unordered_set< EMCSBiome, BiomeHasher > m_AllowedBiomes
A set of allowed biomes for the pool.
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override
Returns a list of pieces that contain the specified connector type.
virtual void Reset(void) override
Called when the pool has finished the current structure and should reset any piece-counters it has fo...
void AddStartingPieceDefs(const cPrefab::sDef *a_StartingPieceDefs, size_t a_NumStartingPieceDefs, int a_DefaultPieceHeight=-1)
Adds pieces from the specified definitions into m_StartingPieces.
void AssignGens(int a_Seed, cBiomeGen &a_BiomeGen, cTerrainHeightGen &a_HeightGen, int a_SeaLevel)
Called when the piece pool is assigned to a generator, so that the individual starting pieces' vertic...
bool LoadCubesetPieceVer1(const AString &a_FileName, cLuaState &a_LuaState, int a_PieceIndex, bool a_LogWarnings)
Loads a single piece from the cubeset file parsed into the specified Lua state.
bool ReadConnectorsCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, const AString &a_PieceName, cPrefab *a_Prefab, bool a_LogWarnings)
Reads a single piece's connectors from the cubeset file parsed into the specified Lua state.
AString GetMetadata(const AString &a_ParamName) const
Returns the specified value from the metadata map.
bool ReadPieceMetadataCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, const AString &a_PieceName, cPrefab *a_Prefab, bool a_LogWarnings)
Reads a single piece's metadata from the cubeset file parsed into the specified Lua state.
bool LoadFromString(const AString &a_Contents, const AString &a_FileName, bool a_LogWarnings)
Loads the pieces from the specified string.
AStringMap m_Metadata
A dictionary of pool-wide metadata, as read from the cubeset file.
bool LoadFromCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, bool a_LogWarnings)
Loads the pieces from the cubeset file parsed into the specified Lua state.
NIBBLETYPE m_VillageWaterRoadBlockMeta
The block meta used for the village roads if the road is on water.
virtual void PiecePlaced(const cPiece &a_Piece) override
Called after a piece is placed, to notify the pool that it has been used.
static AString ReadWholeFile(const AString &a_FileName)
Returns the entire contents of the specified file as a string.
Definition: File.cpp:573
Contains routines for data extraction.
Result ExtractGZip(ContiguousByteBufferView Input)
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
static void LoadFromSchematicFile(cBlockArea &a_BlockArea, const std::string &a_FileName)
Loads an area from a .schematic file.