Cuberite
A lightweight, fast and extensible game server for Minecraft
ComposableGenerator.cpp
Go to the documentation of this file.
1 
2 // ComposableGenerator.cpp
3 
4 // Implements the cComposableGenerator class representing the chunk generator that takes the composition approach to generating chunks
5 
6 #include "Globals.h"
7 
8 #include "ComposableGenerator.h"
9 #include "../IniFile.h"
10 
11 // Individual composed algorithms:
12 #include "BioGen.h"
13 #include "HeiGen.h"
14 #include "CompoGen.h"
15 #include "StructGen.h"
16 #include "FinishGen.h"
17 
18 #include "CompoGenBiomal.h"
19 
20 #include "CompositedHeiGen.h"
21 
22 #include "Caves.h"
23 #include "DistortedHeightmap.h"
24 #include "DungeonRoomsFinisher.h"
25 #include "EndGen.h"
27 #include "MineShafts.h"
28 #include "Noise3DGenerator.h"
29 #include "Ravines.h"
30 #include "RoughRavines.h"
32 #include "VillageGen.h"
33 #include "PieceStructuresGen.h"
34 
35 
36 
37 
38 
40 // cTerrainCompositionGen:
41 
42 std::unique_ptr<cTerrainCompositionGen> cTerrainCompositionGen::CreateCompositionGen(
43  cIniFile & a_IniFile,
44  cBiomeGen & a_BiomeGen,
45  cTerrainShapeGen & a_ShapeGen,
46  int a_Seed
47 )
48 {
49  AString CompoGenName = a_IniFile.GetValue("Generator", "CompositionGen");
50  if (CompoGenName.empty())
51  {
52  LOGWARN("[Generator] CompositionGen value not set in world.ini, using \"Biomal\".");
53  CompoGenName = "Biomal";
54  }
55 
56  // Compositor list is alpha-sorted
57  std::unique_ptr<cTerrainCompositionGen> res;
58  if (NoCaseCompare(CompoGenName, "Biomal") == 0)
59  {
60  res = CreateCompoGenBiomal(a_Seed);
61  }
62  else if (NoCaseCompare(CompoGenName, "BiomalNoise3D") == 0)
63  {
64  // The composition that used to be provided with BiomalNoise3D is now provided by the Biomal compositor:
65  res = CreateCompoGenBiomal(a_Seed);
66  }
67  else if (NoCaseCompare(CompoGenName, "Classic") == 0)
68  {
69  res = std::make_unique<cCompoGenClassic>();
70  }
71  else if (NoCaseCompare(CompoGenName, "DebugBiomes") == 0)
72  {
73  res = std::make_unique<cCompoGenDebugBiomes>();
74  }
75  else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0)
76  {
77  // The composition that used to be provided with DistortedHeightmap is now provided by the Biomal compositor:
78  res = CreateCompoGenBiomal(a_Seed);
79  }
80  else if (NoCaseCompare(CompoGenName, "End") == 0)
81  {
82  res = std::make_unique<cEndGen>(a_Seed);
83  }
84  else if (NoCaseCompare(CompoGenName, "Nether") == 0)
85  {
86  res = std::make_unique<cCompoGenNether>(a_Seed);
87  }
88  else if (NoCaseCompare(CompoGenName, "Noise3D") == 0)
89  {
90  // The composition that used to be provided with Noise3D is now provided by the Biomal compositor:
91  res = CreateCompoGenBiomal(a_Seed);
92  }
93  else if (NoCaseCompare(CompoGenName, "SameBlock") == 0)
94  {
95  res = std::make_unique<cCompoGenSameBlock>();
96  }
97  else
98  {
99  LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str());
100  a_IniFile.SetValue("Generator", "CompositionGen", "Biomal");
101  return CreateCompositionGen(a_IniFile, a_BiomeGen, a_ShapeGen, a_Seed);
102  }
103  ASSERT(res != nullptr);
104 
105  // Read the settings from the ini file:
106  res->InitializeCompoGen(a_IniFile);
107 
108  return res;
109 }
110 
111 
112 
113 
114 
116 // cComposableGenerator:
117 
119  m_BiomeGen(),
120  m_ShapeGen(),
121  m_CompositionGen()
122 {
123 }
124 
125 
126 
127 
128 
130 {
131  Super::Initialize(a_IniFile);
132 
133  // Add the defaults, if they're not overridden:
135 
136  InitBiomeGen(a_IniFile);
137  InitShapeGen(a_IniFile);
138  InitCompositionGen(a_IniFile);
139  InitFinishGens(a_IniFile);
140 }
141 
142 
143 
144 
145 
147 {
148  if (m_BiomeGen != nullptr) // Quick fix for generator deinitializing before the world storage finishes loading
149  {
150  m_BiomeGen->GenBiomes(a_ChunkCoords, a_BiomeMap);
151  }
152 }
153 
154 
155 
156 
157 
159 {
160  if (a_ChunkDesc.IsUsingDefaultBiomes())
161  {
162  m_BiomeGen->GenBiomes(a_ChunkDesc.GetChunkCoords(), a_ChunkDesc.GetBiomeMap());
163  }
164 
165  cChunkDesc::Shape shape;
166  if (a_ChunkDesc.IsUsingDefaultHeight())
167  {
168  m_ShapeGen->GenShape(a_ChunkDesc.GetChunkCoords(), shape);
169  a_ChunkDesc.SetHeightFromShape(shape);
170  }
171  else
172  {
173  // Convert the heightmap in a_ChunkDesc into shape:
174  a_ChunkDesc.GetShapeFromHeight(shape);
175  }
176 
177  bool ShouldUpdateHeightmap = false;
178  if (a_ChunkDesc.IsUsingDefaultComposition())
179  {
180  m_CompositionGen->ComposeTerrain(a_ChunkDesc, shape);
181  }
182 
183  if (a_ChunkDesc.IsUsingDefaultFinish())
184  {
185  for (const auto & Finisher : m_FinishGens)
186  {
187  Finisher->GenFinish(a_ChunkDesc);
188  }
189  ShouldUpdateHeightmap = true;
190  }
191 
192  if (ShouldUpdateHeightmap)
193  {
194  a_ChunkDesc.UpdateHeightmap();
195  }
196 }
197 
198 
199 
200 
201 
203 {
204  switch (a_Dimension)
205  {
206  case dimOverworld:
207  {
208  a_IniFile.GetValueSet("Generator", "BiomeGen", "Grown");
209  a_IniFile.GetValueSet("Generator", "ShapeGen", "BiomalNoise3D");
210  a_IniFile.GetValueSet("Generator", "CompositionGen", "Biomal");
211  a_IniFile.GetValueSet("Generator", "Finishers",
212  "RoughRavines, "
213  "WormNestCaves, "
214  "WaterLakes, "
215  "WaterSprings, "
216  "LavaLakes, "
217  "LavaSprings, "
218  "OreNests, "
219  "Mineshafts, "
220  "Trees, "
221  "Villages, "
222  "SinglePieceStructures: JungleTemple|WitchHut|DesertPyramid|DesertWell, "
223  "TallGrass, "
224  "SprinkleFoliage, "
225  "Ice, "
226  "Snow, "
227  "Lilypads, "
228  "BottomLava, "
229  "DeadBushes, "
230  "NaturalPatches, "
231  "PreSimulator, "
232  "Animals, "
233  "OverworldClumpFlowers, "
234  "ForestRocks"
235  );
236  break;
237  } // dimOverworld
238 
239  case dimNether:
240  {
241  a_IniFile.GetValueSet("Generator", "Generator", "Composable");
242  a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
243  a_IniFile.GetValueSet("Generator", "ConstantBiome", "Nether");
244  a_IniFile.GetValueSet("Generator", "ShapeGen", "HeightMap");
245  a_IniFile.GetValueSet("Generator", "HeightGen", "Flat");
246  a_IniFile.GetValueSet("Generator", "FlatHeight", "128");
247  a_IniFile.GetValueSet("Generator", "CompositionGen", "Nether");
248  a_IniFile.GetValueSet("Generator", "Finishers",
249  "SoulsandRims, "
250  "WormNestCaves, "
251  "BottomLava, "
252  "LavaSprings, "
253  "NetherClumpFoliage, "
254  "NetherOreNests, "
255  "PieceStructures: NetherFort, "
256  "GlowStone, "
257  "PreSimulator");
258  break;
259  } // dimNether
260 
261  case dimEnd:
262  {
263  a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
264  a_IniFile.GetValueSet("Generator", "ConstantBiome", "End");
265  a_IniFile.GetValueSet("Generator", "ShapeGen", "End");
266  a_IniFile.GetValueSet("Generator", "CompositionGen", "End");
267  a_IniFile.GetValueSet("Generator", "Finishers", "EnderDragonFightStructures");
268  break;
269  } // dimEnd
270 
271  default:
272  {
273  ASSERT(!"Unhandled dimension");
274  break;
275  }
276  }
277 }
278 
279 
280 
281 
282 
284 {
285  bool CacheOffByDefault = false;
286  m_BiomeGen = cBiomeGen::CreateBiomeGen(a_IniFile, m_Seed, CacheOffByDefault);
287 
288  // Add a cache, if requested:
289  // The default is 16 * 128 caches, which is 2 MiB of RAM. Reasonable, for the amount of work this is saving.
290  int CacheSize = a_IniFile.GetValueSetI("Generator", "BiomeGenCacheSize", CacheOffByDefault ? 0 : 16);
291  if (CacheSize <= 0)
292  {
293  return;
294  }
295  int MultiCacheLength = a_IniFile.GetValueSetI("Generator", "BiomeGenMultiCacheLength", 128);
296  if (CacheSize < 4)
297  {
298  LOGWARNING("Biomegen cache size set too low, would hurt performance instead of helping. Increasing from %d to %d",
299  CacheSize, 4
300  );
301  CacheSize = 4;
302  }
303  LOGD("Using a cache for biomegen of size %d.", CacheSize);
304  if (MultiCacheLength > 0)
305  {
306  LOGD("Enabling multicache for biomegen of length %d.", MultiCacheLength);
307  m_BiomeGen = std::make_unique<cBioGenMulticache>(std::move(m_BiomeGen), static_cast<size_t>(CacheSize), static_cast<size_t>(MultiCacheLength));
308  }
309  else
310  {
311  m_BiomeGen = std::make_unique<cBioGenMulticache>(std::move(m_BiomeGen), static_cast<size_t>(CacheSize), 1);
312  }
313 }
314 
315 
316 
317 
318 
320 {
321  bool CacheOffByDefault = false;
323  a_IniFile,
324  *m_BiomeGen,
325  m_Seed,
326  CacheOffByDefault
327  );
328 
329  /*
330  // TODO
331  // Add a cache, if requested:
332  int CacheSize = a_IniFile.GetValueSetI("Generator", "ShapeGenCacheSize", CacheOffByDefault ? 0 : 64);
333  if (CacheSize > 0)
334  {
335  if (CacheSize < 4)
336  {
337  LOGWARNING("Heightgen cache size set too low, would hurt performance instead of helping. Increasing from %d to %d",
338  CacheSize, 4
339  );
340  CacheSize = 4;
341  }
342  LOGD("Using a cache for Heightgen of size %d.", CacheSize);
343  m_HeightGen = cTerrainHeightGenPtr(new cHeiGenCache(m_HeightGen, CacheSize));
344  }
345  */
346 }
347 
348 
349 
350 
351 
353 {
355  a_IniFile,
356  *m_BiomeGen,
357  *m_ShapeGen,
358  m_Seed
359  );
360 
361  // Add a cache over the composition generator:
362  // Even a cache of size 1 is useful due to the CompositedHeiGen cache after us doing re-composition on its misses
363  int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64);
364  if (CompoGenCacheSize > 0)
365  {
366  m_CompositionGen = std::make_unique<cCompoGenCache>(std::move(m_CompositionGen), CompoGenCacheSize);
367  }
368 
369  // Create a cache of the composited heightmaps, so that finishers may use it:
370  m_CompositedHeightCache = std::make_unique<cHeiGenMultiCache>(std::make_unique<cCompositedHeiGen>(*m_BiomeGen, *m_ShapeGen, *m_CompositionGen), 16, 128);
371  // 128 subcaches of depth 16 each = 0.5 MiB of RAM. Acceptable, for the amount of work this saves.
372 }
373 
374 
375 
376 
377 
379 {
380  auto seaLevel = a_IniFile.GetValueI("Generator", "SeaLevel");
381 
382  AString Finishers = a_IniFile.GetValue("Generator", "Finishers");
383 
384  // Create all requested finishers:
385  AStringVector Str = StringSplitAndTrim(Finishers, ",");
386  for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
387  {
388  auto split = StringSplitAndTrim(*itr, ":");
389  if (split.empty())
390  {
391  continue;
392  }
393  const auto & finisher = split[0];
394  // Finishers, alpha-sorted:
395  if (NoCaseCompare(finisher, "Animals") == 0)
396  {
397  m_FinishGens.push_back(std::make_unique<cFinishGenPassiveMobs>(m_Seed, a_IniFile, m_Dimension));
398  }
399  else if (NoCaseCompare(finisher, "BottomLava") == 0)
400  {
401  int DefaultBottomLavaLevel = (m_Dimension == dimNether) ? 30 : 10;
402  int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
403  m_FinishGens.push_back(std::make_unique<cFinishGenBottomLava>(BottomLavaLevel));
404  }
405  else if (NoCaseCompare(finisher, "DeadBushes") == 0)
406  {
407  // A list with all the allowed biomes.
409  AllowedBiomes.push_back(biDesert);
410  AllowedBiomes.push_back(biDesertHills);
411  AllowedBiomes.push_back(biDesertM);
412  AllowedBiomes.push_back(biMesa);
413  AllowedBiomes.push_back(biMesaBryce);
414  AllowedBiomes.push_back(biMesaPlateau);
415  AllowedBiomes.push_back(biMesaPlateauF);
416  AllowedBiomes.push_back(biMesaPlateauFM);
417  AllowedBiomes.push_back(biMesaPlateauM);
418  AllowedBiomes.push_back(biMegaTaiga);
419 
420  // A list with all the allowed blocks that can be below the dead bush.
422  AllowedBlocks.push_back(E_BLOCK_SAND);
423  AllowedBlocks.push_back(E_BLOCK_HARDENED_CLAY);
424  AllowedBlocks.push_back(E_BLOCK_STAINED_CLAY);
425 
426  m_FinishGens.push_back(std::make_unique<cFinishGenSingleTopBlock>(m_Seed, E_BLOCK_DEAD_BUSH, AllowedBiomes, 2, AllowedBlocks));
427  }
428  else if (NoCaseCompare(finisher, "DirectOverhangs") == 0)
429  {
430  m_FinishGens.push_back(std::make_unique<cStructGenDirectOverhangs>(m_Seed));
431  }
432  else if (NoCaseCompare(finisher, "DirtPockets") == 0)
433  {
434  auto Gen = std::make_unique<cFinishGenOrePockets>(m_Seed + 1, cFinishGenOrePockets::DefaultNaturalPatches());
435  Gen->Initialize(a_IniFile, "DirtPockets");
436  m_FinishGens.push_back(std::move(Gen));
437  }
438  else if (NoCaseCompare(finisher, "DistortedMembraneOverhangs") == 0)
439  {
440  m_FinishGens.push_back(std::make_unique<cStructGenDistortedMembraneOverhangs>(m_Seed));
441  }
442  else if (NoCaseCompare(finisher, "DualRidgeCaves") == 0)
443  {
444  float Threshold = static_cast<float>(a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3));
445  m_FinishGens.push_back(std::make_unique<cStructGenDualRidgeCaves>(m_Seed, Threshold));
446  }
447  else if (NoCaseCompare(finisher, "DungeonRooms") == 0)
448  {
449  int GridSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsGridSize", 48);
450  int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7);
451  int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5);
452  AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1");
453  m_FinishGens.push_back(std::make_unique<cDungeonRoomsFinisher>(*m_ShapeGen, m_Seed, GridSize, MaxSize, MinSize, HeightDistrib));
454  }
455  else if (NoCaseCompare(finisher, "EnderDragonFightStructures") == 0)
456  {
457  AString Pillars = a_IniFile.GetValueSet("Generator", "ObsidianPillars",
458  "76|3|false; 79|3|true; 82|3|true; "
459  "85|4|false; 88|4|false; 91|4|false; "
460  "94|5|false; 97|5|false; 100|5|false; "
461  "103|6|false");
462  int Radius = a_IniFile.GetValueSetI("Generator", "ObsidianPillarsRadius", 43);
463  auto Gen = std::make_unique<cEnderDragonFightStructuresGen>(m_Seed);
464  Gen->Init(Pillars, Radius);
465  m_FinishGens.push_back(std::move(Gen));
466  }
467  else if (NoCaseCompare(finisher, "ForestRocks") == 0)
468  {
469  m_FinishGens.push_back(std::make_unique<cFinishGenForestRocks>(m_Seed, a_IniFile));
470  }
471  else if (NoCaseCompare(finisher, "GlowStone") == 0)
472  {
473  m_FinishGens.push_back(std::make_unique<cFinishGenGlowStone>(m_Seed));
474  }
475  else if (NoCaseCompare(finisher, "Ice") == 0)
476  {
477  m_FinishGens.push_back(std::make_unique<cFinishGenIce>());
478  }
479  else if (NoCaseCompare(finisher, "LavaLakes") == 0)
480  {
481  int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
482  m_FinishGens.push_back(std::make_unique<cStructGenLakes>(m_Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, *m_ShapeGen, Probability));
483  }
484  else if (NoCaseCompare(finisher, "LavaSprings") == 0)
485  {
486  m_FinishGens.push_back(std::make_unique<cFinishGenFluidSprings>(m_Seed, E_BLOCK_LAVA, a_IniFile, m_Dimension));
487  }
488  else if (NoCaseCompare(finisher, "Lilypads") == 0)
489  {
490  // A list with all the allowed biomes.
492  AllowedBiomes.push_back(biSwampland);
493  AllowedBiomes.push_back(biSwamplandM);
494 
495  // A list with all the allowed blocks that can be below the lilypad.
497  AllowedBlocks.push_back(E_BLOCK_WATER);
498  AllowedBlocks.push_back(E_BLOCK_STATIONARY_WATER);
499 
500  m_FinishGens.push_back(std::make_unique<cFinishGenSingleTopBlock>(m_Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks));
501  }
502  else if (NoCaseCompare(finisher, "MarbleCaves") == 0)
503  {
504  m_FinishGens.push_back(std::make_unique<cStructGenMarbleCaves>(m_Seed));
505  }
506  else if (NoCaseCompare(finisher, "MineShafts") == 0)
507  {
508  int GridSize = a_IniFile.GetValueSetI("Generator", "MineShaftsGridSize", 512);
509  int MaxOffset = a_IniFile.GetValueSetI("Generator", "MineShaftsMaxOffset", 256);
510  int MaxSystemSize = a_IniFile.GetValueSetI("Generator", "MineShaftsMaxSystemSize", 160);
511  int ChanceCorridor = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCorridor", 600);
512  int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200);
513  int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200);
514  m_FinishGens.push_back(std::make_unique<cStructGenMineShafts>(
515  m_Seed, GridSize, MaxOffset, MaxSystemSize,
516  ChanceCorridor, ChanceCrossing, ChanceStaircase
517  ));
518  }
519  else if (NoCaseCompare(finisher, "NaturalPatches") == 0)
520  {
521  m_FinishGens.push_back(std::make_unique<cFinishGenOreNests>(m_Seed + 1, cFinishGenOreNests::DefaultNaturalPatches()));
522  }
523  else if (NoCaseCompare(finisher, "NetherClumpFoliage") == 0)
524  {
525  m_FinishGens.push_back(std::make_unique<cFinishGenNetherClumpFoliage>(m_Seed));
526  }
527  else if (NoCaseCompare(finisher, "NetherOreNests") == 0)
528  {
529  m_FinishGens.push_back(std::make_unique<cFinishGenOreNests>(m_Seed + 2, cFinishGenOreNests::DefaultNetherOres()));
530  }
531  else if (NoCaseCompare(finisher, "OreNests") == 0)
532  {
533  m_FinishGens.push_back(std::make_unique<cFinishGenOreNests>(m_Seed + 3, cFinishGenOreNests::DefaultOverworldOres()));
534  }
535  else if (NoCaseCompare(finisher, "OrePockets") == 0)
536  {
537  auto Gen = std::make_unique<cFinishGenOrePockets>(m_Seed + 2, cFinishGenOrePockets::DefaultOverworldOres());
538  Gen->Initialize(a_IniFile, "OrePockets");
539  m_FinishGens.push_back(std::move(Gen));
540  }
541  else if (NoCaseCompare(finisher, "OverworldClumpFlowers") == 0)
542  {
543  auto flowers = cFinishGenClumpTopBlock::ParseIniFile(a_IniFile, "OverworldClumpFlowers");
544  m_FinishGens.push_back(std::make_unique<cFinishGenClumpTopBlock>(m_Seed, flowers));
545  }
546  else if (NoCaseCompare(finisher, "PieceStructures") == 0)
547  {
548  if (split.size() < 2)
549  {
550  LOGWARNING("The PieceStructures generator needs the structures to use. Example: \"PieceStructures: NetherFort\".");
551  continue;
552  }
553 
554  auto Gen = std::make_unique<cPieceStructuresGen>(m_Seed);
555  if (Gen->Initialize(split[1], seaLevel, *m_BiomeGen, *m_CompositedHeightCache))
556  {
557  m_FinishGens.push_back(std::move(Gen));
558  }
559  }
560  else if (NoCaseCompare(finisher, "PreSimulator") == 0)
561  {
562  // Load the settings
563  bool PreSimulateFallingBlocks = a_IniFile.GetValueSetB("Generator", "PreSimulatorFallingBlocks", true);
564  bool PreSimulateWater = a_IniFile.GetValueSetB("Generator", "PreSimulatorWater", true);
565  bool PreSimulateLava = a_IniFile.GetValueSetB("Generator", "PreSimulatorLava", true);
566 
567  m_FinishGens.push_back(std::make_unique<cFinishGenPreSimulator>(PreSimulateFallingBlocks, PreSimulateWater, PreSimulateLava));
568  }
569  else if (NoCaseCompare(finisher, "Ravines") == 0)
570  {
571  m_FinishGens.push_back(std::make_unique<cStructGenRavines>(m_Seed, 128));
572  }
573  else if (NoCaseCompare(finisher, "RoughRavines") == 0)
574  {
575  int GridSize = a_IniFile.GetValueSetI("Generator", "RoughRavinesGridSize", 256);
576  int MaxOffset = a_IniFile.GetValueSetI("Generator", "RoughRavinesMaxOffset", 128);
577  int MaxSize = a_IniFile.GetValueSetI("Generator", "RoughRavinesMaxSize", 128);
578  int MinSize = a_IniFile.GetValueSetI("Generator", "RoughRavinesMinSize", 64);
579  double MaxCenterWidth = a_IniFile.GetValueSetF("Generator", "RoughRavinesMaxCenterWidth", 8);
580  double MinCenterWidth = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinCenterWidth", 2);
581  double MaxRoughness = a_IniFile.GetValueSetF("Generator", "RoughRavinesMaxRoughness", 0.2);
582  double MinRoughness = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinRoughness", 0.05);
583  double MaxFloorHeightEdge = a_IniFile.GetValueSetF("Generator", "RoughRavinesMaxFloorHeightEdge", 8);
584  double MinFloorHeightEdge = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinFloorHeightEdge", 30);
585  double MaxFloorHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMaxFloorHeightCenter", 20);
586  double MinFloorHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinFloorHeightCenter", 6);
587  double MaxCeilingHeightEdge = a_IniFile.GetValueSetF("Generator", "RoughRavinesMaxCeilingHeightEdge", 56);
588  double MinCeilingHeightEdge = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinCeilingHeightEdge", 38);
589  double MaxCeilingHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMaxCeilingHeightCenter", 58);
590  double MinCeilingHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinCeilingHeightCenter", 36);
591  m_FinishGens.push_back(std::make_unique<cRoughRavines>(
592  m_Seed, MaxSize, MinSize,
593  static_cast<float>(MaxCenterWidth),
594  static_cast<float>(MinCenterWidth),
595  static_cast<float>(MaxRoughness),
596  static_cast<float>(MinRoughness),
597  static_cast<float>(MaxFloorHeightEdge),
598  static_cast<float>(MinFloorHeightEdge),
599  static_cast<float>(MaxFloorHeightCenter),
600  static_cast<float>(MinFloorHeightCenter),
601  static_cast<float>(MaxCeilingHeightEdge),
602  static_cast<float>(MinCeilingHeightEdge),
603  static_cast<float>(MaxCeilingHeightCenter),
604  static_cast<float>(MinCeilingHeightCenter),
605  GridSize, MaxOffset
606  ));
607  }
608  else if (NoCaseCompare(finisher, "SinglePieceStructures") == 0)
609  {
610  if (split.size() < 2)
611  {
612  LOGWARNING("The SinglePieceStructures generator needs the structures to use. Example: \"SinglePieceStructures: DesertPyramid\".");
613  continue;
614  }
615 
616  auto Gen = std::make_unique<cSinglePieceStructuresGen>(m_Seed);
617  if (Gen->Initialize(split[1], seaLevel, *m_BiomeGen, *m_CompositedHeightCache))
618  {
619  m_FinishGens.push_back(std::move(Gen));
620  }
621  }
622  else if (NoCaseCompare(finisher, "SoulsandRims") == 0)
623  {
624  m_FinishGens.push_back(std::make_unique<cFinishGenSoulsandRims>(m_Seed));
625  }
626  else if (NoCaseCompare(finisher, "Snow") == 0)
627  {
628  m_FinishGens.push_back(std::make_unique<cFinishGenSnow>());
629  }
630  else if (NoCaseCompare(finisher, "SprinkleFoliage") == 0)
631  {
632  int MaxCactusHeight = a_IniFile.GetValueI("Plants", "MaxCactusHeight", 3);
633  int MaxSugarcaneHeight = a_IniFile.GetValueI("Plants", "MaxSugarcaneHeight", 3);
634  m_FinishGens.push_back(std::make_unique<cFinishGenSprinkleFoliage>(m_Seed, MaxCactusHeight, MaxSugarcaneHeight));
635  }
636  else if (NoCaseCompare(finisher, "TallGrass") == 0)
637  {
638  m_FinishGens.push_back(std::make_unique<cFinishGenTallGrass>(m_Seed));
639  }
640  else if (NoCaseCompare(finisher, "Trees") == 0)
641  {
642  m_FinishGens.push_back(std::make_unique<cStructGenTrees>(m_Seed, *m_BiomeGen, *m_ShapeGen, *m_CompositionGen));
643  }
644  else if (NoCaseCompare(finisher, "Villages") == 0)
645  {
646  int GridSize = a_IniFile.GetValueSetI("Generator", "VillageGridSize", 384);
647  int MaxOffset = a_IniFile.GetValueSetI("Generator", "VillageMaxOffset", 128);
648  int MaxDepth = a_IniFile.GetValueSetI("Generator", "VillageMaxDepth", 2);
649  int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128);
650  int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50);
651  int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
652  AString PrefabList = a_IniFile.GetValueSet("Generator", "VillagePrefabs", "PlainsVillage, SandVillage");
653  auto Prefabs = StringSplitAndTrim(PrefabList, ",");
654  m_FinishGens.push_back(std::make_unique<cVillageGen>(m_Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, *m_BiomeGen, *m_CompositedHeightCache, seaLevel, Prefabs));
655  }
656  else if (NoCaseCompare(finisher, "Vines") == 0)
657  {
658  int Level = a_IniFile.GetValueSetI("Generator", "VinesLevel", 40);
659  m_FinishGens.push_back(std::make_unique<cFinishGenVines>(m_Seed, Level));
660  }
661  else if (NoCaseCompare(finisher, "WaterLakes") == 0)
662  {
663  int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
664  m_FinishGens.push_back(std::make_unique<cStructGenLakes>(m_Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, *m_ShapeGen, Probability));
665  }
666  else if (NoCaseCompare(finisher, "WaterSprings") == 0)
667  {
668  m_FinishGens.push_back(std::make_unique<cFinishGenFluidSprings>(m_Seed, E_BLOCK_WATER, a_IniFile, m_Dimension));
669  }
670  else if (NoCaseCompare(finisher, "WormNestCaves") == 0)
671  {
672  int Size = a_IniFile.GetValueSetI("Generator", "WormNestCavesSize", 64);
673  int Grid = a_IniFile.GetValueSetI("Generator", "WormNestCavesGrid", 96);
674  int MaxOffset = a_IniFile.GetValueSetI("Generator", "WormNestMaxOffset", 32);
675  m_FinishGens.push_back(std::make_unique<cStructGenWormNestCaves>(m_Seed, Size, Grid, MaxOffset));
676  }
677  else
678  {
679  LOGWARNING("Unknown Finisher in the [Generator] section: \"%s\". Ignoring.", finisher.c_str());
680  }
681  } // for itr - Str[]
682 }
@ biMesa
Definition: BiomeDef.h:64
@ biMesaPlateau
Definition: BiomeDef.h:66
@ biDesert
Definition: BiomeDef.h:24
@ biMesaPlateauF
Definition: BiomeDef.h:65
@ biMegaTaiga
Definition: BiomeDef.h:59
@ biDesertHills
Definition: BiomeDef.h:42
@ biMesaPlateauFM
Definition: BiomeDef.h:96
@ biMesaBryce
Definition: BiomeDef.h:95
@ biSwamplandM
Definition: BiomeDef.h:82
@ biDesertM
Definition: BiomeDef.h:78
@ biMesaPlateauM
Definition: BiomeDef.h:97
@ biSwampland
Definition: BiomeDef.h:28
@ E_BLOCK_DEAD_BUSH
Definition: BlockType.h:42
@ E_BLOCK_WATER
Definition: BlockType.h:18
@ E_BLOCK_STATIONARY_LAVA
Definition: BlockType.h:21
@ E_BLOCK_LILY_PAD
Definition: BlockType.h:126
@ E_BLOCK_STAINED_CLAY
Definition: BlockType.h:177
@ E_BLOCK_HARDENED_CLAY
Definition: BlockType.h:191
@ E_BLOCK_SAND
Definition: BlockType.h:22
@ E_BLOCK_STATIONARY_WATER
Definition: BlockType.h:19
@ E_BLOCK_LAVA
Definition: BlockType.h:20
eDimension
Dimension of a world.
Definition: Defines.h:231
@ dimEnd
Definition: Defines.h:234
@ dimNether
Definition: Defines.h:232
@ dimOverworld
Definition: Defines.h:233
std::unique_ptr< cTerrainCompositionGen > CreateCompoGenBiomal(int a_Seed)
Returns a new instance of the Biomal composition generator.
#define ASSERT(x)
Definition: Globals.h:276
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
#define LOGWARN
Definition: LoggerSimple.h:88
#define LOGD
Definition: LoggerSimple.h:83
AStringVector StringSplitAndTrim(const AString &str, const AString &delim)
Split the string at any of the listed delimiters and trim each value.
int NoCaseCompare(const AString &s1, const AString &s2)
Case-insensitive string comparison.
std::vector< AString > AStringVector
Definition: StringUtils.h:12
std::string AString
Definition: StringUtils.h:11
unsigned char Level(const BlockState Block)
Wraps the chunk coords into a single structure.
Definition: ChunkDef.h:57
EMCSBiome BiomeMap[Width *Width]
The type used for any biomemap operations and storage inside Cuberite, using Cuberite biomes (need no...
Definition: ChunkDef.h:137
bool IsUsingDefaultHeight(void) const
Definition: ChunkDesc.cpp:226
bool IsUsingDefaultBiomes(void) const
Definition: ChunkDesc.cpp:208
Byte Shape[256 *16 *16]
The datatype used to represent the entire chunk worth of shape.
Definition: ChunkDesc.h:36
bool IsUsingDefaultFinish(void) const
Definition: ChunkDesc.cpp:262
void GetShapeFromHeight(Shape &a_Shape) const
Sets the shape in a_Shape to match the heightmap stored currently in m_HeightMap.
Definition: ChunkDesc.cpp:175
bool IsUsingDefaultComposition(void) const
Definition: ChunkDesc.cpp:244
cChunkCoords GetChunkCoords() const
Definition: ChunkDesc.h:54
cChunkDef::BiomeMap & GetBiomeMap(void)
Definition: ChunkDesc.h:234
void UpdateHeightmap(void)
Updates the heightmap to match the current contents.
Definition: ChunkDesc.cpp:612
void SetHeightFromShape(const Shape &a_Shape)
Sets the heightmap to match the given shape data.
Definition: ChunkDesc.cpp:153
virtual void Initialize(cIniFile &a_IniFile)
Called to initialize the generator on server startup.
eDimension m_Dimension
The dimension, read from the INI file.
int m_Seed
The main seed, read from the INI file, used for the entire generator.
The interface that a biome generator must implement A biome generator takes chunk coords on input and...
static std::unique_ptr< cBiomeGen > CreateBiomeGen(cIniFile &a_IniFile, int a_Seed, bool &a_CacheOffByDefault)
Creates the correct BiomeGen descendant based on the ini file settings.
Definition: BioGen.cpp:1136
The interface that a terrain shape generator must implement A terrain shape generator takes chunk coo...
static std::unique_ptr< cTerrainShapeGen > CreateShapeGen(cIniFile &a_IniFile, cBiomeGen &a_BiomeGen, int a_Seed, bool &a_CacheOffByDefault)
Creates the correct TerrainShapeGen descendant based on the ini file settings and the seed provided.
Definition: ShapeGen.cpp:78
static std::unique_ptr< cTerrainCompositionGen > CreateCompositionGen(cIniFile &a_IniFile, cBiomeGen &a_BiomeGen, cTerrainShapeGen &a_ShapeGen, int a_Seed)
Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed prov...
virtual void GenerateBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap) override
Generates the biomes for the specified chunk.
virtual void Initialize(cIniFile &a_IniFile) override
Called to initialize the generator on server startup.
void InitFinishGens(cIniFile &a_IniFile)
Reads the finishers from the ini and initializes m_FinishGens accordingly.
static void InitializeGeneratorDefaults(cIniFile &a_IniFile, eDimension a_Dimension)
If there's no particular sub-generator set in the INI file, adds the default one, based on the dimens...
std::unique_ptr< cBiomeGen > m_BiomeGen
The biome generator.
std::vector< std::unique_ptr< cFinishGen > > m_FinishGens
The finisher generators, in the order in which they are applied.
std::unique_ptr< cTerrainShapeGen > m_ShapeGen
The terrain shape generator.
std::unique_ptr< cTerrainHeightGen > m_CompositedHeightCache
The cache for the heights of the composited terrain.
void InitShapeGen(cIniFile &a_IniFile)
Reads the ShapeGen settings from the ini and initializes m_ShapeGen accordingly.
void InitBiomeGen(cIniFile &a_IniFile)
Reads the BiomeGen settings from the ini and initializes m_BiomeGen accordingly.
std::unique_ptr< cTerrainCompositionGen > m_CompositionGen
The terrain composition generator.
virtual void Generate(cChunkDesc &a_ChunkDesc) override
Does the actual chunk generation.
void InitCompositionGen(cIniFile &a_IniFile)
Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly.
static std::vector< BiomeInfo > ParseIniFile(cIniFile &a_IniFile, const AString &a_ClumpPrefix)
Parses an inifile in search for all clumps.
Definition: FinishGen.cpp:372
std::vector< EMCSBiome > BiomeList
Definition: FinishGen.h:281
std::vector< BLOCKTYPE > BlockList
Definition: FinishGen.h:278
static const OreInfos & DefaultOverworldOres(void)
Returns a vector of OreInfo structures describing the default Overworld ores, usable in the construct...
Definition: FinishGen.cpp:1755
static const OreInfos & DefaultNetherOres(void)
Returns a vector of OreInfo structures describing the default Nether ores, usable in the constructor.
Definition: FinishGen.cpp:1776
static const OreInfos & DefaultNaturalPatches(void)
Returns a vector of OreInfo structures describing the default Overworld non-ore pockets (dirt,...
Definition: FinishGen.cpp:1790
AString GetValue(const AString &keyname, const AString &valuename, const AString &defValue="") const override
Get the value at the specified key and value, returns defValue on failure.
Definition: IniFile.cpp:485
int GetValueI(const AString &keyname, const AString &valuename, const int defValue=0) const
Definition: IniFile.cpp:506
int GetValueSetI(const AString &keyname, const AString &valuename, const int defValue=0) override
Definition: IniFile.cpp:559
bool SetValue(const int keyID, const int valueID, const AString &value)
Definition: IniFile.cpp:397
AString GetValueSet(const AString &keyname, const AString &valuename, const AString &defValue="") override
Gets the value; if not found, write the default to the repository.
Definition: IniFile.cpp:526
bool GetValueSetB(const AString &keyname, const AString &valuename, const bool defValue=false) override
Definition: IniFile.h:150
double GetValueSetF(const AString &keyname, const AString &valuename, const double defValue=0.0)
Definition: IniFile.cpp:549