Cuberite
A lightweight, fast and extensible game server for Minecraft
BioGen.cpp
Go to the documentation of this file.
1 
2 // BioGen.cpp
3 
4 // Implements the various biome generators
5 
6 #include "Globals.h"
7 #include "BioGen.h"
8 #include "IntGen.h"
9 #include "ProtIntGen.h"
10 #include "../IniFile.h"
11 #include "../LinearUpscale.h"
12 
13 
14 
15 
16 
18 // cBioGenConstant:
19 
21 {
22  UNUSED(a_ChunkCoords);
23  for (size_t i = 0; i < ARRAYCOUNT(a_BiomeMap); i++)
24  {
25  a_BiomeMap[i] = m_Biome;
26  }
27 }
28 
29 
30 
31 
32 
34 {
35  AString defaultBiome;
36  switch (StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld")))
37  {
38  case dimOverworld: defaultBiome = "Plains"; break;
39  case dimNether: defaultBiome = "Nether"; break;
40  case dimEnd: defaultBiome = "End"; break;
41  case dimNotSet: defaultBiome = "Swampland"; break;
42  }
43  AString Biome = a_IniFile.GetValueSet("Generator", "ConstantBiome", defaultBiome);
44  m_Biome = StringToBiome(Biome);
45  if (m_Biome == biInvalidBiome)
46  {
47  LOGWARN("[Generator]::ConstantBiome value \"%s\" not recognized, using \"Plains\".", Biome.c_str());
48  m_Biome = biPlains;
49  }
50 }
51 
52 
53 
54 
55 
57 // cBioGenCache:
58 
59 cBioGenCache::cBioGenCache(cBiomeGen & a_BioGenToCache, size_t a_CacheSize) :
60  m_BioGenToCache(a_BioGenToCache),
61  m_CacheSize(a_CacheSize),
62  m_NumHits(0),
63  m_NumMisses(0),
64  m_TotalChain(0)
65 {
66  m_CacheData.resize(m_CacheSize);
67  m_CacheOrder.resize(m_CacheSize);
68  for (size_t i = 0; i < m_CacheSize; i++)
69  {
70  m_CacheOrder[i] = i;
71  }
72 }
73 
74 
75 
76 
77 
78 void cBioGenCache::GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap & a_BiomeMap)
79 {
80  if (((m_NumHits + m_NumMisses) % 1024) == 10)
81  {
82  // LOGD("BioGenCache: %u hits, %u misses, saved %.2f %%", static_cast<unsigned>(m_NumHits), static_cast<unsigned>(m_NumMisses), 100.0 * m_NumHits / (m_NumHits + m_NumMisses));
83  // LOGD("BioGenCache: Avg cache chain length: %.2f", static_cast<double>(m_TotalChain) / m_NumHits);
84  }
85 
86  for (size_t i = 0; i < m_CacheSize; i++)
87  {
88  if (m_CacheData[m_CacheOrder[i]].m_Coords != a_ChunkCoords)
89  {
90  continue;
91  }
92  // Found it in the cache
93  size_t Idx = m_CacheOrder[i];
94 
95  // Move to front:
96  for (size_t j = i; j > 0; j--)
97  {
98  m_CacheOrder[j] = m_CacheOrder[j - 1];
99  }
100  m_CacheOrder[0] = Idx;
101 
102  // Use the cached data:
103  memcpy(a_BiomeMap, m_CacheData[Idx].m_BiomeMap, sizeof(a_BiomeMap));
104 
105  m_NumHits++;
106  m_TotalChain += i;
107  return;
108  } // for i - cache
109 
110  // Not in the cache:
111  m_NumMisses++;
112  m_BioGenToCache.GenBiomes(a_ChunkCoords, a_BiomeMap);
113 
114  // Insert it as the first item in the MRU order:
115  size_t Idx = m_CacheOrder[m_CacheSize - 1];
116  for (size_t i = m_CacheSize - 1; i > 0; i--)
117  {
118  m_CacheOrder[i] = m_CacheOrder[i - 1];
119  } // for i - m_CacheOrder[]
120  m_CacheOrder[0] = Idx;
121  memcpy(m_CacheData[Idx].m_BiomeMap, a_BiomeMap, sizeof(a_BiomeMap));
122  m_CacheData[Idx].m_Coords = a_ChunkCoords;
123 }
124 
125 
126 
127 
128 
130 {
131  Super::InitializeBiomeGen(a_IniFile);
133 }
134 
135 
136 
137 
139 // cBioGenMulticache:
140 
141 cBioGenMulticache::cBioGenMulticache(std::unique_ptr<cBiomeGen> a_BioGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches) :
142  m_NumSubCaches(a_NumSubCaches),
143  m_Underlying(std::move(a_BioGenToCache))
144 {
145  m_Caches.reserve(a_NumSubCaches);
146  for (size_t i = 0; i < a_NumSubCaches; i++)
147  {
148  m_Caches.push_back(std::make_unique<cBioGenCache>(*m_Underlying, a_SubCacheSize));
149  }
150 }
151 
152 
153 
154 
155 
157 {
158  const size_t coefficient = 3;
159  const size_t cacheIdx = (static_cast<size_t>(a_ChunkCoords.m_ChunkX) + coefficient * static_cast<size_t>(a_ChunkCoords.m_ChunkZ)) % m_NumSubCaches;
160 
161  m_Caches[cacheIdx]->GenBiomes(a_ChunkCoords, a_BiomeMap);
162 }
163 
164 
165 
166 
167 
169 {
170  for (auto & itr : m_Caches)
171  {
172  itr->InitializeBiomeGen(a_IniFile);
173  }
174 }
175 
176 
177 
178 
179 
181 // cBiomeGenList:
182 
184 {
185  AStringVector Split = StringSplitAndTrim(a_Biomes, ",");
186 
187  // Convert each string in the list into biome:
188  for (AStringVector::const_iterator itr = Split.begin(); itr != Split.end(); ++itr)
189  {
190  AStringVector Split2 = StringSplit(*itr, ":");
191  if (Split2.size() < 1)
192  {
193  continue;
194  }
195  int Count = 1;
196  if (Split2.size() >= 2)
197  {
198  if (!StringToInteger(Split2[1], Count))
199  {
200  LOGWARNING("Cannot decode biome count: \"%s\"; using 1.", Split2[1].c_str());
201  Count = 1;
202  }
203  }
204  EMCSBiome Biome = StringToBiome(Split2[0]);
205  if (Biome != biInvalidBiome)
206  {
207  for (int i = 0; i < Count; i++)
208  {
209  m_Biomes.push_back(Biome);
210  }
211  }
212  else
213  {
214  LOGWARNING("Cannot decode biome name: \"%s\"; skipping", Split2[0].c_str());
215  }
216  } // for itr - Split[]
217  if (!m_Biomes.empty())
218  {
219  m_BiomesCount = static_cast<int>(m_Biomes.size());
220  return;
221  }
222 
223  // There were no biomes, add default biomes:
224  static EMCSBiome Biomes[] =
225  {
226  biOcean,
227  biPlains,
228  biDesert,
230  biForest,
231  biTaiga,
232  biSwampland,
233  biRiver,
236  biIcePlains,
240  biBeach,
243  biTaigaHills,
245  biJungle,
247  } ;
248  m_Biomes.reserve(ARRAYCOUNT(Biomes));
249  for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++)
250  {
251  m_Biomes.push_back(Biomes[i]);
252  }
253  m_BiomesCount = static_cast<int>(m_Biomes.size());
254 }
255 
256 
257 
258 
259 
261 // cBioGenCheckerboard:
262 
264 {
265  for (int z = 0; z < cChunkDef::Width; z++)
266  {
267  int Base = (cChunkDef::Width * a_ChunkCoords.m_ChunkZ + z) / m_BiomeSize;
268  for (int x = 0; x < cChunkDef::Width; x++)
269  {
270  int Add = cChunkDef::Width * a_ChunkCoords.m_ChunkX + x;
271  size_t BiomeIdx = static_cast<size_t>((((Base + Add / m_BiomeSize) % m_BiomesCount) + m_BiomesCount) % m_BiomesCount); // Need to add and modulo twice because of negative numbers
272  a_BiomeMap[x + cChunkDef::Width * z] = m_Biomes[BiomeIdx];
273  }
274  }
275 }
276 
277 
278 
279 
280 
282 {
283  Super::InitializeBiomeGen(a_IniFile);
284  AString Biomes = a_IniFile.GetValueSet ("Generator", "CheckerBoardBiomes", "");
285  m_BiomeSize = a_IniFile.GetValueSetI("Generator", "CheckerboardBiomeSize", 64);
286  m_BiomeSize = (m_BiomeSize < 8) ? 8 : m_BiomeSize;
287  InitializeBiomes(Biomes);
288 }
289 
290 
291 
292 
293 
295 // cBioGenVoronoi :
296 
298 {
299  int BaseZ = cChunkDef::Width * a_ChunkCoords.m_ChunkZ;
300  int BaseX = cChunkDef::Width * a_ChunkCoords.m_ChunkX;
301  for (int z = 0; z < cChunkDef::Width; z++)
302  {
303  int AbsoluteZ = BaseZ + z;
304  for (int x = 0; x < cChunkDef::Width; x++)
305  {
306  int VoronoiCellValue = m_Voronoi.GetValueAt(BaseX + x, AbsoluteZ) / 8;
307  cChunkDef::SetBiome(a_BiomeMap, x, z, m_Biomes[static_cast<size_t>(VoronoiCellValue % m_BiomesCount)]);
308  } // for x
309  } // for z
310 }
311 
312 
313 
314 
315 
317 {
318  Super::InitializeBiomeGen(a_IniFile);
319  int CellSize = a_IniFile.GetValueSetI("Generator", "VoronoiCellSize", 128);
320  int JitterSize = a_IniFile.GetValueSetI("Generator", "VoronoiJitterSize", CellSize);
321  int OddRowOffset = a_IniFile.GetValueSetI("Generator", "VoronoiOddRowOffset", 0);
322  m_Voronoi.SetCellSize(CellSize);
323  m_Voronoi.SetJitterSize(JitterSize);
324  m_Voronoi.SetOddRowOffset(OddRowOffset);
325  InitializeBiomes(a_IniFile.GetValueSet ("Generator", "VoronoiBiomes", ""));
326 }
327 
328 
329 
330 
331 
333 // cBioGenDistortedVoronoi:
334 
336 {
337  int BaseZ = cChunkDef::Width * a_ChunkCoords.m_ChunkZ;
338  int BaseX = cChunkDef::Width * a_ChunkCoords.m_ChunkX;
339 
340  // Distortions for linear interpolation:
341  int DistortX[cChunkDef::Width + 1][cChunkDef::Width + 1];
342  int DistortZ[cChunkDef::Width + 1][cChunkDef::Width + 1];
343  for (int x = 0; x <= 4; x++) for (int z = 0; z <= 4; z++)
344  {
345  Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z]);
346  }
347 
348  LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
349  LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
350 
351  for (int z = 0; z < cChunkDef::Width; z++)
352  {
353  for (int x = 0; x < cChunkDef::Width; x++)
354  {
355  int VoronoiCellValue = m_Voronoi.GetValueAt(DistortX[x][z], DistortZ[x][z]) / 8;
356  cChunkDef::SetBiome(a_BiomeMap, x, z, m_Biomes[static_cast<size_t>(VoronoiCellValue % m_BiomesCount)]);
357  } // for x
358  } // for z
359 }
360 
361 
362 
363 
364 
366 {
367  Super::InitializeBiomeGen(a_IniFile);
368  m_CellSize = a_IniFile.GetValueSetI("Generator", "DistortedVoronoiCellSize", 96);
370  InitializeBiomes(a_IniFile.GetValueSet("Generator", "DistortedVoronoiBiomes", ""));
371 }
372 
373 
374 
375 
376 
377 void cBioGenDistortedVoronoi::Distort(int a_BlockX, int a_BlockZ, int & a_DistortedX, int & a_DistortedZ)
378 {
379  double NoiseX = m_Noise.CubicNoise3D(static_cast<float>(a_BlockX / m_CellSize), static_cast<float>(a_BlockZ / m_CellSize), 1000);
380  NoiseX += 0.5 * m_Noise.CubicNoise3D(2 * static_cast<float>(a_BlockX / m_CellSize), 2 * static_cast<float>(a_BlockZ / m_CellSize), 2000);
381  NoiseX += 0.08 * m_Noise.CubicNoise3D(16 * static_cast<float>(a_BlockX / m_CellSize), 16 * static_cast<float>(a_BlockZ / m_CellSize), 3000);
382  double NoiseZ = m_Noise.CubicNoise3D(static_cast<float>(a_BlockX / m_CellSize), static_cast<float>(a_BlockZ / m_CellSize), 4000);
383  NoiseZ += 0.5 * m_Noise.CubicNoise3D(2 * static_cast<float>(a_BlockX / m_CellSize), 2 * static_cast<float>(a_BlockZ / m_CellSize), 5000);
384  NoiseZ += 0.08 * m_Noise.CubicNoise3D(16 * static_cast<float>(a_BlockX / m_CellSize), 16 * static_cast<float>(a_BlockZ / m_CellSize), 6000);
385 
386  a_DistortedX = a_BlockX + static_cast<int>(m_CellSize * 0.5 * NoiseX);
387  a_DistortedZ = a_BlockZ + static_cast<int>(m_CellSize * 0.5 * NoiseZ);
388 }
389 
390 
391 
392 
393 
395 // cBioGenMultiStepMap :
396 
398  m_Noise1(a_Seed + 1000),
399  m_Noise2(a_Seed + 2000),
400  m_Noise3(a_Seed + 3000),
401  m_Noise4(a_Seed + 4000),
402  m_Noise5(a_Seed + 5000),
403  m_Noise6(a_Seed + 6000),
404  m_Seed(a_Seed),
405  m_OceanCellSize(384),
406  m_MushroomIslandSize(64),
407  m_RiverCellSize(384),
408  m_RiverWidthThreshold(0.125),
409  m_LandBiomesSize(1024)
410 {
411 }
412 
413 
414 
415 
416 
418 {
419  m_OceanCellSize = a_IniFile.GetValueSetI("Generator", "MultiStepMapOceanCellSize", m_OceanCellSize);
420  m_MushroomIslandSize = a_IniFile.GetValueSetI("Generator", "MultiStepMapMushroomIslandSize", m_MushroomIslandSize);
421  m_RiverCellSize = a_IniFile.GetValueSetI("Generator", "MultiStepMapRiverCellSize", m_RiverCellSize);
422  m_RiverWidthThreshold = a_IniFile.GetValueSetF("Generator", "MultiStepMapRiverWidth", m_RiverWidthThreshold);
423  m_LandBiomesSize = static_cast<float>(a_IniFile.GetValueSetI("Generator", "MultiStepMapLandBiomeSize", static_cast<int>(m_LandBiomesSize)));
424 }
425 
426 
427 
428 
429 
431 {
432  DecideOceanLandMushroom(a_ChunkCoords, a_BiomeMap);
433  AddRivers(a_ChunkCoords, a_BiomeMap);
434  ApplyTemperatureHumidity(a_ChunkCoords, a_BiomeMap);
435 }
436 
437 
438 
439 
440 
442 {
443  // Distorted Voronoi over 3 biomes, with mushroom having only a special occurence.
444 
445  // Prepare a distortion lookup table, by distorting a 5x5 area and using that as 1:4 zoom (linear interpolate):
446  int BaseZ = cChunkDef::Width * a_ChunkCoords.m_ChunkZ;
447  int BaseX = cChunkDef::Width * a_ChunkCoords.m_ChunkX;
448  int DistortX[cChunkDef::Width + 1][cChunkDef::Width + 1];
449  int DistortZ[cChunkDef::Width + 1][cChunkDef::Width + 1];
450  int DistortSize = m_OceanCellSize / 2;
451  for (int x = 0; x <= 4; x++) for (int z = 0; z <= 4; z++)
452  {
453  Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z], DistortSize);
454  }
455  LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
456  LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
457 
458  // Prepare a 9x9 area of neighboring cell seeds
459  // (assuming that 7x7 cell area is larger than a chunk being generated)
460  const int NEIGHBORHOOD_SIZE = 4; // How many seeds in each direction to check
461  int CellX = BaseX / m_OceanCellSize;
462  int CellZ = BaseZ / m_OceanCellSize;
463  int SeedX[2 * NEIGHBORHOOD_SIZE + 1][2 * NEIGHBORHOOD_SIZE + 1];
464  int SeedZ[2 * NEIGHBORHOOD_SIZE + 1][2 * NEIGHBORHOOD_SIZE + 1];
465  EMCSBiome SeedV[2 * NEIGHBORHOOD_SIZE + 1][2 * NEIGHBORHOOD_SIZE + 1];
466  for (int xc = 0; xc < 2 * NEIGHBORHOOD_SIZE + 1; xc++)
467  {
468  int RealCellX = xc + CellX - NEIGHBORHOOD_SIZE;
469  int CellBlockX = RealCellX * m_OceanCellSize;
470  for (int zc = 0; zc < 2 * NEIGHBORHOOD_SIZE + 1; zc++)
471  {
472  int RealCellZ = zc + CellZ - NEIGHBORHOOD_SIZE;
473  int CellBlockZ = RealCellZ * m_OceanCellSize;
474  int OffsetX = (m_Noise2.IntNoise3DInt(RealCellX, 16 * RealCellX + 32 * RealCellZ, RealCellZ) / 8) % m_OceanCellSize;
475  int OffsetZ = (m_Noise4.IntNoise3DInt(RealCellX, 32 * RealCellX - 16 * RealCellZ, RealCellZ) / 8) % m_OceanCellSize;
476  SeedX[xc][zc] = CellBlockX + OffsetX;
477  SeedZ[xc][zc] = CellBlockZ + OffsetZ;
478  SeedV[xc][zc] = (((m_Noise6.IntNoise3DInt(RealCellX, RealCellX - RealCellZ + 1000, RealCellZ) / 11) % 256) > 90) ? biOcean : (biInvalidBiome);
479  } // for z
480  } // for x
481 
482  for (int xc = 1; xc < 2 * NEIGHBORHOOD_SIZE; xc++) for (int zc = 1; zc < 2 * NEIGHBORHOOD_SIZE; zc++)
483  {
484  if (
485  (SeedV[xc ][zc] == biOcean) &&
486  (SeedV[xc - 1][zc] == biOcean) &&
487  (SeedV[xc + 1][zc] == biOcean) &&
488  (SeedV[xc ][zc - 1] == biOcean) &&
489  (SeedV[xc ][zc + 1] == biOcean) &&
490  (SeedV[xc - 1][zc - 1] == biOcean) &&
491  (SeedV[xc + 1][zc - 1] == biOcean) &&
492  (SeedV[xc - 1][zc + 1] == biOcean) &&
493  (SeedV[xc + 1][zc + 1] == biOcean)
494  )
495  {
496  SeedV[xc][zc] = biMushroomIsland;
497  }
498  }
499 
500  // For each column find the nearest distorted cell and use its value as the biome:
501  int MushroomOceanThreshold = m_OceanCellSize * m_OceanCellSize * m_MushroomIslandSize / 1024;
502  int MushroomShoreThreshold = m_OceanCellSize * m_OceanCellSize * m_MushroomIslandSize / 2048;
503  for (int z = 0; z < cChunkDef::Width; z++)
504  {
505  for (int x = 0; x < cChunkDef::Width; x++)
506  {
507  int AbsoluteZ = DistortZ[x][z];
508  int AbsoluteX = DistortX[x][z];
509  int MinDist = m_OceanCellSize * m_OceanCellSize * 16; // There has to be a cell closer than this
510  EMCSBiome Biome = biPlains;
511  // Find the nearest cell seed:
512  for (int xs = 1; xs < 2 * NEIGHBORHOOD_SIZE; xs++) for (int zs = 1; zs < 2 * NEIGHBORHOOD_SIZE; zs++)
513  {
514  int Dist = (SeedX[xs][zs] - AbsoluteX) * (SeedX[xs][zs] - AbsoluteX) + (SeedZ[xs][zs] - AbsoluteZ) * (SeedZ[xs][zs] - AbsoluteZ);
515  if (Dist >= MinDist)
516  {
517  continue;
518  }
519  MinDist = Dist;
520  Biome = SeedV[xs][zs];
521  // Shrink mushroom biome and add a shore:
522  if (Biome == biMushroomIsland)
523  {
524  if (Dist > MushroomOceanThreshold)
525  {
526  Biome = biOcean;
527  }
528  else if (Dist > MushroomShoreThreshold)
529  {
530  Biome = biMushroomShore;
531  }
532  }
533  } // for zs, xs
534 
535  cChunkDef::SetBiome(a_BiomeMap, x, z, Biome);
536  } // for x
537  } // for z
538 }
539 
540 
541 
542 
543 
545 {
546  for (int z = 0; z < cChunkDef::Width; z++)
547  {
548  float NoiseCoordZ = static_cast<float>(a_ChunkCoords.m_ChunkZ * cChunkDef::Width + z) / m_RiverCellSize;
549  for (int x = 0; x < cChunkDef::Width; x++)
550  {
551  if (cChunkDef::GetBiome(a_BiomeMap, x, z) != biInvalidBiome)
552  {
553  // Biome already set, skip this column
554  continue;
555  }
556 
557  float NoiseCoordX = static_cast<float>(a_ChunkCoords.m_ChunkX * cChunkDef::Width + x) / m_RiverCellSize;
558 
559  double Noise = m_Noise1.CubicNoise2D( NoiseCoordX, NoiseCoordZ);
560  Noise += 0.5 * m_Noise3.CubicNoise2D(2 * NoiseCoordX, 2 * NoiseCoordZ);
561  Noise += 0.1 * m_Noise5.CubicNoise2D(8 * NoiseCoordX, 8 * NoiseCoordZ);
562 
563  if ((Noise > 0) && (Noise < m_RiverWidthThreshold))
564  {
565  cChunkDef::SetBiome(a_BiomeMap, x, z, biRiver);
566  }
567  } // for x
568  } // for z
569 }
570 
571 
572 
573 
574 
576 {
577  IntMap TemperatureMap;
578  IntMap HumidityMap;
579  BuildTemperatureHumidityMaps(a_ChunkCoords, TemperatureMap, HumidityMap);
580 
581  FreezeWaterBiomes(a_BiomeMap, TemperatureMap);
582  DecideLandBiomes(a_BiomeMap, TemperatureMap, HumidityMap);
583 }
584 
585 
586 
587 
588 
589 void cBioGenMultiStepMap::Distort(int a_BlockX, int a_BlockZ, int & a_DistortedX, int & a_DistortedZ, int a_CellSize)
590 {
591  double NoiseX = m_Noise3.CubicNoise2D( static_cast<float>(a_BlockX / a_CellSize), static_cast<float>(a_BlockZ / a_CellSize));
592  NoiseX += 0.5 * m_Noise2.CubicNoise2D(2 * static_cast<float>(a_BlockX / a_CellSize), 2 * static_cast<float>(a_BlockZ / a_CellSize));
593  NoiseX += 0.1 * m_Noise1.CubicNoise2D(16 * static_cast<float>(a_BlockX / a_CellSize), 16 * static_cast<float>(a_BlockZ / a_CellSize));
594  double NoiseZ = m_Noise6.CubicNoise2D( static_cast<float>(a_BlockX / a_CellSize), static_cast<float>(a_BlockZ / a_CellSize));
595  NoiseZ += 0.5 * m_Noise5.CubicNoise2D(2 * static_cast<float>(a_BlockX / a_CellSize), 2 * static_cast<float>(a_BlockZ / a_CellSize));
596  NoiseZ += 0.1 * m_Noise4.CubicNoise2D(16 * static_cast<float>(a_BlockX / a_CellSize), 16 * static_cast<float>(a_BlockZ / a_CellSize));
597 
598  a_DistortedX = a_BlockX + static_cast<int>(a_CellSize * 0.5 * NoiseX);
599  a_DistortedZ = a_BlockZ + static_cast<int>(a_CellSize * 0.5 * NoiseZ);
600 }
601 
602 
603 
604 
605 
606 void cBioGenMultiStepMap::BuildTemperatureHumidityMaps(cChunkCoords a_ChunkCoords, IntMap & a_TemperatureMap, IntMap & a_HumidityMap)
607 {
608  // Linear interpolation over 8x8 blocks; use double for better precision:
609  DblMap TemperatureMap;
610  DblMap HumidityMap;
611  for (int z = 0; z < 17; z += 8)
612  {
613  float NoiseCoordZ = static_cast<float>(a_ChunkCoords.m_ChunkZ * cChunkDef::Width + z) / m_LandBiomesSize;
614  for (int x = 0; x < 17; x += 8)
615  {
616  float NoiseCoordX = static_cast<float>(a_ChunkCoords.m_ChunkX * cChunkDef::Width + x) / m_LandBiomesSize;
617 
618  double NoiseT = m_Noise1.CubicNoise2D( NoiseCoordX, NoiseCoordZ);
619  NoiseT += 0.5 * m_Noise2.CubicNoise2D(2 * NoiseCoordX, 2 * NoiseCoordZ);
620  NoiseT += 0.1 * m_Noise3.CubicNoise2D(8 * NoiseCoordX, 8 * NoiseCoordZ);
621  TemperatureMap[x + 17 * z] = NoiseT;
622 
623  double NoiseH = m_Noise4.CubicNoise2D( NoiseCoordX, NoiseCoordZ);
624  NoiseH += 0.5 * m_Noise5.CubicNoise2D(2 * NoiseCoordX, 2 * NoiseCoordZ);
625  NoiseH += 0.1 * m_Noise6.CubicNoise2D(8 * NoiseCoordX, 8 * NoiseCoordZ);
626  HumidityMap[x + 17 * z] = NoiseH;
627  } // for x
628  } // for z
629  LinearUpscale2DArrayInPlace<17, 17, 8, 8>(TemperatureMap);
630  LinearUpscale2DArrayInPlace<17, 17, 8, 8>(HumidityMap);
631 
632  // Re-map into integral values in [0 .. 255] range:
633  for (size_t idx = 0; idx < ARRAYCOUNT(a_TemperatureMap); idx++)
634  {
635  a_TemperatureMap[idx] = Clamp(static_cast<int>(128 + TemperatureMap[idx] * 128), 0, 255);
636  a_HumidityMap[idx] = Clamp(static_cast<int>(128 + HumidityMap[idx] * 128), 0, 255);
637  }
638 }
639 
640 
641 
642 
643 
644 void cBioGenMultiStepMap::DecideLandBiomes(cChunkDef::BiomeMap & a_BiomeMap, const IntMap & a_TemperatureMap, const IntMap & a_HumidityMap)
645 {
646  static const EMCSBiome BiomeMap[] =
647  {
648  // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
665  } ;
666  for (int z = 0; z < cChunkDef::Width; z++)
667  {
668  int idxZ = 17 * z;
669  for (int x = 0; x < cChunkDef::Width; x++)
670  {
671  if (cChunkDef::GetBiome(a_BiomeMap, x, z) != biInvalidBiome)
672  {
673  // Already set before
674  continue;
675  }
676  int idx = idxZ + x;
677  int Temperature = a_TemperatureMap[idx] / 16; // -> [0..15] range
678  int Humidity = a_HumidityMap[idx] / 16; // -> [0..15] range
679  cChunkDef::SetBiome(a_BiomeMap, x, z, BiomeMap[Temperature + 16 * Humidity]);
680  } // for x
681  } // for z
682 }
683 
684 
685 
686 
687 
688 void cBioGenMultiStepMap::FreezeWaterBiomes(cChunkDef::BiomeMap & a_BiomeMap, const IntMap & a_TemperatureMap)
689 {
690  int idx = 0;
691  for (int z = 0; z < cChunkDef::Width; z++)
692  {
693  for (int x = 0; x < cChunkDef::Width; x++, idx++)
694  {
695  if (a_TemperatureMap[idx] > 4 * 16)
696  {
697  // Not frozen
698  continue;
699  }
700  switch (cChunkDef::GetBiome(a_BiomeMap, x, z))
701  {
702  case biRiver: cChunkDef::SetBiome(a_BiomeMap, x, z, biFrozenRiver); break;
703  case biOcean: cChunkDef::SetBiome(a_BiomeMap, x, z, biFrozenOcean); break;
704  default: break;
705  }
706  } // for x
707  idx += 1;
708  } // for z
709 }
710 
711 
712 
713 
714 
716 // cBioGenTwoLevel:
717 
719  m_VoronoiLarge(a_Seed + 1000),
720  m_VoronoiSmall(a_Seed + 2000),
721  m_Noise1(a_Seed + 5001),
722  m_Noise2(a_Seed + 5002),
723  m_Noise3(a_Seed + 5003),
724  m_Noise4(a_Seed + 5004),
725  m_Noise5(a_Seed + 5005),
726  m_Noise6(a_Seed + 5006),
727  m_FreqX1(0.0),
728  m_AmpX1(0.0),
729  m_FreqX2(0.0),
730  m_AmpX2(0.0),
731  m_FreqX3(0.0),
732  m_AmpX3(0.0),
733  m_FreqZ1(0.0),
734  m_AmpZ1(0.0),
735  m_FreqZ2(0.0),
736  m_AmpZ2(0.0),
737  m_FreqZ3(0.0),
738  m_AmpZ3(0.0)
739 {
740 }
741 
742 
743 
744 
745 
747 {
748  int BaseZ = cChunkDef::Width * a_ChunkCoords.m_ChunkZ;
749  int BaseX = cChunkDef::Width * a_ChunkCoords.m_ChunkX;
750 
751  // Distortions for linear interpolation:
752  int DistortX[cChunkDef::Width + 1][cChunkDef::Width + 1];
753  int DistortZ[cChunkDef::Width + 1][cChunkDef::Width + 1];
754  for (int x = 0; x <= 4; x++) for (int z = 0; z <= 4; z++)
755  {
756  float BlockX = static_cast<float>(BaseX + x * 4);
757  float BlockZ = static_cast<float>(BaseZ + z * 4);
758  double NoiseX = m_AmpX1 * m_Noise1.CubicNoise2D(BlockX * m_FreqX1, BlockZ * m_FreqX1);
759  NoiseX += m_AmpX2 * m_Noise2.CubicNoise2D(BlockX * m_FreqX2, BlockZ * m_FreqX2);
760  NoiseX += m_AmpX3 * m_Noise3.CubicNoise2D(BlockX * m_FreqX3, BlockZ * m_FreqX3);
761  double NoiseZ = m_AmpZ1 * m_Noise4.CubicNoise2D(BlockX * m_FreqZ1, BlockZ * m_FreqZ1);
762  NoiseZ += m_AmpZ2 * m_Noise5.CubicNoise2D(BlockX * m_FreqZ2, BlockZ * m_FreqZ2);
763  NoiseZ += m_AmpZ3 * m_Noise6.CubicNoise2D(BlockX * m_FreqZ3, BlockZ * m_FreqZ3);
764 
765  DistortX[4 * x][4 * z] = static_cast<int>(BlockX + NoiseX);
766  DistortZ[4 * x][4 * z] = static_cast<int>(BlockZ + NoiseZ);
767  }
768 
769  LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
770  LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
771 
772  // Apply distortion to each block coord, then query the voronoi maps for biome group and biome index and choose biome based on that:
773  for (int z = 0; z < cChunkDef::Width; z++)
774  {
775  for (int x = 0; x < cChunkDef::Width; x++)
776  {
777  int SeedX, SeedZ, MinDist2;
778  int BiomeGroup = m_VoronoiLarge.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 7;
779  size_t BiomeIdx = static_cast<size_t>(m_VoronoiSmall.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 11);
780  int MinDist1 = (DistortX[x][z] - SeedX) * (DistortX[x][z] - SeedX) + (DistortZ[x][z] - SeedZ) * (DistortZ[x][z] - SeedZ);
781  cChunkDef::SetBiome(a_BiomeMap, x, z, SelectBiome(BiomeGroup, BiomeIdx, (MinDist1 < MinDist2 / 4) ? 1 : 0));
782  }
783  }
784 }
785 
786 
787 
788 
789 
790 EMCSBiome cBioGenTwoLevel::SelectBiome(int a_BiomeGroup, size_t a_BiomeIdx, int a_DistLevel)
791 {
792  // TODO: Move this into settings
793  struct BiomeLevels
794  {
795  EMCSBiome InnerBiome;
796  EMCSBiome OuterBiome;
797  } ;
798 
799  static BiomeLevels bgOceanBlocks[] =
800  {
801  { biOcean, biOcean, },
802  { biOcean, biOcean, },
803  { biOcean, biOcean, },
804  { biOcean, biOcean, },
805  { biOcean, biDeepOcean, },
806  { biOcean, biDeepOcean, },
807  { biDeepOcean, biDeepOcean, },
808  { biDeepOcean, biDeepOcean, },
809  { biDeepOcean, biDeepOcean, },
810  { biDeepOcean, biDeepOcean, },
812  } ;
813  static BiomeLevels bgFrozenBlocks[] =
814  {
815  { biIcePlains, biIcePlains, },
818  { biColdTaiga, biColdTaiga, },
825  } ;
826  static BiomeLevels bgTemperateBlocks[] =
827  {
832  { biForest, biForestHills, },
834  { biRoofedForest, biForest, },
837  { biPlains, biPlains, },
839  { biSwampland, biSwampland, },
841  } ;
842  static BiomeLevels bgWarmBlocks[] =
843  {
844  { biDesertHills, biDesert, },
845  { biDesert, biDesert, },
846  { biDesertM, biDesertM, },
848  { biSavanna, biSavanna, },
849  { biSavannaM, biSavannaM, },
850  } ;
851  static BiomeLevels bgMesaBlocks[] =
852  {
853  { biMesaPlateau, biMesa, },
854  { biMesaPlateauF, biMesa, },
855  { biMesaPlateauFM, biMesa, },
856  { biMesaPlateauM, biMesa, },
857  { biMesaBryce, biMesaBryce, },
858  { biSavanna, biSavanna, },
860  } ;
861  static BiomeLevels bgConifersBlocks[] =
862  {
863  { biTaiga, biTaiga, },
864  { biTaigaM, biTaigaM, },
865  { biMegaTaiga, biMegaTaiga, },
868  } ;
869  static BiomeLevels bgDenseTreesBlocks[] =
870  {
871  { biJungleHills, biJungle, },
872  { biJungle, biJungleEdge, },
873  { biJungleM, biJungleEdgeM, },
874  } ;
875  static struct
876  {
877  BiomeLevels * Biomes;
878  size_t Count;
879  } BiomeGroups[] =
880  {
881  { bgOceanBlocks, ARRAYCOUNT(bgOceanBlocks), },
882  { bgOceanBlocks, ARRAYCOUNT(bgOceanBlocks), },
883  { bgFrozenBlocks, ARRAYCOUNT(bgFrozenBlocks), },
884  { bgFrozenBlocks, ARRAYCOUNT(bgFrozenBlocks), },
885  { bgTemperateBlocks, ARRAYCOUNT(bgTemperateBlocks), },
886  { bgTemperateBlocks, ARRAYCOUNT(bgTemperateBlocks), },
887  { bgConifersBlocks, ARRAYCOUNT(bgConifersBlocks), },
888  { bgConifersBlocks, ARRAYCOUNT(bgConifersBlocks), },
889  { bgWarmBlocks, ARRAYCOUNT(bgWarmBlocks), },
890  { bgWarmBlocks, ARRAYCOUNT(bgWarmBlocks), },
891  { bgMesaBlocks, ARRAYCOUNT(bgMesaBlocks), },
892  { bgDenseTreesBlocks, ARRAYCOUNT(bgDenseTreesBlocks), },
893  } ;
894  size_t Group = static_cast<size_t>(a_BiomeGroup) % ARRAYCOUNT(BiomeGroups);
895  size_t Index = a_BiomeIdx % BiomeGroups[Group].Count;
896  return (a_DistLevel > 0) ? BiomeGroups[Group].Biomes[Index].InnerBiome : BiomeGroups[Group].Biomes[Index].OuterBiome;
897 }
898 
899 
900 
901 
902 
904 {
905  m_VoronoiLarge.SetCellSize(a_IniFile.GetValueSetI("Generator", "TwoLevelLargeCellSize", 1024));
906  m_VoronoiSmall.SetCellSize(a_IniFile.GetValueSetI("Generator", "TwoLevelSmallCellSize", 128));
907  m_FreqX1 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Freq", 0.01));
908  m_AmpX1 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Amp", 80));
909  m_FreqX2 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Freq", 0.05));
910  m_AmpX2 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Amp", 20));
911  m_FreqX3 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Freq", 0.1));
912  m_AmpX3 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Amp", 8));
913  m_FreqZ1 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Freq", 0.01));
914  m_AmpZ1 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Amp", 80));
915  m_FreqZ2 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Freq", 0.05));
916  m_AmpZ2 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Amp", 20));
917  m_FreqZ3 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Freq", 0.1));
918  m_AmpZ3 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Amp", 8));
919 }
920 
921 
922 
923 
924 
926 // cBioGenGrown:
927 
929  public cBiomeGen
930 {
931 public:
932  cBioGenGrown(int a_Seed)
933  {
934  auto FinalRivers =
935 
936  std::make_shared<cIntGenChoice<2, 7>>(a_Seed + 12)
937  | MakeIntGen<cIntGenZoom <10>>(a_Seed + 11)
938  | MakeIntGen<cIntGenSmooth<8>>(a_Seed + 6)
939  | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
940  | MakeIntGen<cIntGenZoom <8>>(a_Seed + 10)
941  | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
942  | MakeIntGen<cIntGenZoom <8>>(a_Seed + 9)
943  | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
944  | MakeIntGen<cIntGenZoom <8>>(a_Seed + 8)
945  | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
946  | MakeIntGen<cIntGenZoom <9>>(a_Seed + 4)
947  | MakeIntGen<cIntGenRiver <7>>(a_Seed + 3)
948  | MakeIntGen<cIntGenZoom <10>>(a_Seed + 2)
949  | MakeIntGen<cIntGenSmooth<8>>(a_Seed + 1);
950 
951  auto alteration =
952  std::make_shared<cIntGenZoom <8>>(a_Seed,
953  std::make_shared<cIntGenLandOcean<6>>(a_Seed, 20
954  ));
955 
956  auto alteration2 =
957  std::make_shared<cIntGenZoom <8>>(a_Seed + 1,
958  std::make_shared<cIntGenZoom <6>>(a_Seed + 2,
959  std::make_shared<cIntGenZoom <5>>(a_Seed + 1,
960  std::make_shared<cIntGenZoom <4>>(a_Seed + 2,
961  std::make_shared<cIntGenLandOcean<4>>(a_Seed + 1, 10
962  )))));
963 
964  auto FinalBiomes =
965  std::make_shared<cIntGenSmooth <8>> (a_Seed + 1,
966  std::make_shared<cIntGenZoom <10>>(a_Seed + 15,
967  std::make_shared<cIntGenSmooth <7>> (a_Seed + 1,
968  std::make_shared<cIntGenZoom <9>> (a_Seed + 16,
969  std::make_shared<cIntGenBeaches <6>> (
970  std::make_shared<cIntGenZoom <8>> (a_Seed + 1,
971  std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2004, 10,
972  std::make_shared<cIntGenAddToOcean <6>> (a_Seed + 10, 500, biDeepOcean,
973  std::make_shared<cIntGenReplaceRandomly<8>> (a_Seed + 1, biPlains, biSunflowerPlains, 20,
974  std::make_shared<cIntGenMBiomes <8>> (a_Seed + 5, alteration2,
975  std::make_shared<cIntGenAlternateBiomes<8>> (a_Seed + 1, alteration,
976  std::make_shared<cIntGenBiomeEdges <8>> (a_Seed + 3,
977  std::make_shared<cIntGenZoom <10>>(a_Seed + 2,
978  std::make_shared<cIntGenZoom <7>> (a_Seed + 4,
979  std::make_shared<cIntGenReplaceRandomly<5>> (a_Seed + 99, biIcePlains, biIcePlainsSpikes, 50,
980  std::make_shared<cIntGenZoom <5>> (a_Seed + 8,
981  std::make_shared<cIntGenAddToOcean <4>> (a_Seed + 10, 300, biDeepOcean,
982  std::make_shared<cIntGenAddToOcean <6>> (a_Seed + 9, 8, biMushroomIsland,
983  std::make_shared<cIntGenBiomes <8>> (a_Seed + 3000,
984  std::make_shared<cIntGenAddIslands <8>> (a_Seed + 2000, 200,
985  std::make_shared<cIntGenZoom <8>> (a_Seed + 5,
986  std::make_shared<cIntGenRareBiomeGroups<6>> (a_Seed + 5, 50,
987  std::make_shared<cIntGenBiomeGroupEdges<6>> (
988  std::make_shared<cIntGenAddIslands <8>> (a_Seed + 2000, 200,
989  std::make_shared<cIntGenZoom <8>> (a_Seed + 7,
990  std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 8, 50, bgOcean,
991  std::make_shared<cIntGenReplaceRandomly<6>> (a_Seed + 101, bgIce, bgTemperate, 150,
992  std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2000, 200,
993  std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 9, 50, bgOcean,
994  std::make_shared<cIntGenLandOcean <5>> (a_Seed + 100, 30)
995  | MakeIntGen<cIntGenZoom <6>> (a_Seed + 10)
996  )))))))))))))))))))))))))))));
997 
998  m_Gen =
999  std::make_shared<cIntGenSmooth <16>>(a_Seed,
1000  std::make_shared<cIntGenZoom <18>>(a_Seed,
1001  std::make_shared<cIntGenSmooth <11>>(a_Seed,
1002  std::make_shared<cIntGenZoom <13>>(a_Seed,
1003  std::make_shared<cIntGenMixRivers<8>> (
1004  FinalBiomes, FinalRivers
1005  )))));
1006  }
1007 
1008  virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap & a_Biomes) override
1009  {
1011  m_Gen->GetInts(a_ChunkCoords.m_ChunkX * cChunkDef::Width, a_ChunkCoords.m_ChunkZ * cChunkDef::Width, vals);
1012  for (int z = 0; z < cChunkDef::Width; z++)
1013  {
1014  for (int x = 0; x < cChunkDef::Width; x++)
1015  {
1016  cChunkDef::SetBiome(a_Biomes, x, z, static_cast<EMCSBiome>(vals[x + cChunkDef::Width * z]));
1017  }
1018  }
1019  }
1020 
1021 protected:
1022  std::shared_ptr<cIntGen<16, 16>> m_Gen;
1023 };
1024 
1025 
1026 
1027 
1028 
1030 // cBioGenProtGrown:
1031 
1033  public cBiomeGen
1034 {
1035 public:
1036  cBioGenProtGrown(int a_Seed)
1037  {
1038  auto FinalRivers =
1039  std::make_shared<cProtIntGenSmooth>(a_Seed + 1,
1040  std::make_shared<cProtIntGenZoom >(a_Seed + 2,
1041  std::make_shared<cProtIntGenRiver >(a_Seed + 3,
1042  std::make_shared<cProtIntGenZoom >(a_Seed + 4,
1043  std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
1044  std::make_shared<cProtIntGenZoom >(a_Seed + 8,
1045  std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
1046  std::make_shared<cProtIntGenZoom >(a_Seed + 9,
1047  std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
1048  std::make_shared<cProtIntGenZoom >(a_Seed + 10,
1049  std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
1050  std::make_shared<cProtIntGenSmooth>(a_Seed + 6,
1051  std::make_shared<cProtIntGenZoom >(a_Seed + 11,
1052  std::make_shared<cProtIntGenChoice>(a_Seed + 12, 2
1053  ))))))))))))));
1054 
1055  auto alteration =
1056  std::make_shared<cProtIntGenZoom >(a_Seed,
1057  std::make_shared<cProtIntGenLandOcean>(a_Seed, 20
1058  ));
1059 
1060  auto alteration2 =
1061  std::make_shared<cProtIntGenZoom >(a_Seed + 1,
1062  std::make_shared<cProtIntGenZoom >(a_Seed + 2,
1063  std::make_shared<cProtIntGenZoom >(a_Seed + 1,
1064  std::make_shared<cProtIntGenZoom >(a_Seed + 2,
1065  std::make_shared<cProtIntGenLandOcean>(a_Seed + 1, 10
1066  )))));
1067 
1068  auto FinalBiomes =
1069  std::make_shared<cProtIntGenSmooth >(a_Seed + 1,
1070  std::make_shared<cProtIntGenZoom >(a_Seed + 15,
1071  std::make_shared<cProtIntGenSmooth >(a_Seed + 1,
1072  std::make_shared<cProtIntGenZoom >(a_Seed + 16,
1073  std::make_shared<cProtIntGenBeaches >(
1074  std::make_shared<cProtIntGenZoom >(a_Seed + 1,
1075  std::make_shared<cProtIntGenAddIslands >(a_Seed + 2004, 10,
1076  std::make_shared<cProtIntGenAddToOcean >(a_Seed + 10, 500, biDeepOcean,
1077  std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 1, biPlains, biSunflowerPlains, 20,
1078  std::make_shared<cProtIntGenMBiomes >(a_Seed + 5, alteration2,
1079  std::make_shared<cProtIntGenAlternateBiomes>(a_Seed + 1, alteration,
1080  std::make_shared<cProtIntGenBiomeEdges >(a_Seed + 3,
1081  std::make_shared<cProtIntGenZoom >(a_Seed + 2,
1082  std::make_shared<cProtIntGenZoom >(a_Seed + 4,
1083  std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 99, biIcePlains, biIcePlainsSpikes, 50,
1084  std::make_shared<cProtIntGenZoom >(a_Seed + 8,
1085  std::make_shared<cProtIntGenAddToOcean >(a_Seed + 10, 300, biDeepOcean,
1086  std::make_shared<cProtIntGenAddToOcean >(a_Seed + 9, 8, biMushroomIsland,
1087  std::make_shared<cProtIntGenBiomes >(a_Seed + 3000,
1088  std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200,
1089  std::make_shared<cProtIntGenZoom >(a_Seed + 5,
1090  std::make_shared<cProtIntGenRareBiomeGroups>(a_Seed + 5, 50,
1091  std::make_shared<cProtIntGenBiomeGroupEdges>(
1092  std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200,
1093  std::make_shared<cProtIntGenZoom >(a_Seed + 7,
1094  std::make_shared<cProtIntGenSetRandomly >(a_Seed + 8, 50, bgOcean,
1095  std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 101, bgIce, bgTemperate, 150,
1096  std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200,
1097  std::make_shared<cProtIntGenSetRandomly >(a_Seed + 9, 50, bgOcean,
1098  std::make_shared<cProtIntGenZoom >(a_Seed + 10,
1099  std::make_shared<cProtIntGenLandOcean >(a_Seed + 100, 30
1100  )))))))))))))))))))))))))))))));
1101 
1102  m_Gen =
1103  std::make_shared<cProtIntGenSmooth >(a_Seed,
1104  std::make_shared<cProtIntGenZoom >(a_Seed,
1105  std::make_shared<cProtIntGenSmooth >(a_Seed,
1106  std::make_shared<cProtIntGenZoom >(a_Seed,
1107  std::make_shared<cProtIntGenMixRivers>(
1108  FinalBiomes, FinalRivers
1109  )))));
1110  }
1111 
1112  virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap & a_Biomes) override
1113  {
1114  int vals[16 * 16];
1115  m_Gen->GetInts(a_ChunkCoords.m_ChunkX * cChunkDef::Width, a_ChunkCoords.m_ChunkZ * cChunkDef::Width, 16, 16, vals);
1116  for (int z = 0; z < cChunkDef::Width; z++)
1117  {
1118  for (int x = 0; x < cChunkDef::Width; x++)
1119  {
1120  cChunkDef::SetBiome(a_Biomes, x, z, static_cast<EMCSBiome>(vals[x + cChunkDef::Width * z]));
1121  }
1122  }
1123  }
1124 
1125 protected:
1126  std::shared_ptr<cProtIntGen> m_Gen;
1127 };
1128 
1129 
1130 
1131 
1132 
1134 // cBiomeGen:
1135 
1136 std::unique_ptr<cBiomeGen> cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault)
1137 {
1138  AString BiomeGenName = a_IniFile.GetValue("Generator", "BiomeGen");
1139  if (BiomeGenName.empty())
1140  {
1141  LOGWARN("[Generator] BiomeGen value not set in world.ini, using \"Grown\".");
1142  BiomeGenName = "Grown";
1143  }
1144 
1145  std::unique_ptr<cBiomeGen> res;
1146  a_CacheOffByDefault = false;
1147  if (NoCaseCompare(BiomeGenName, "constant") == 0)
1148  {
1149  res = std::make_unique<cBioGenConstant>();
1150  a_CacheOffByDefault = true; // we're generating faster than a cache would retrieve data :)
1151  }
1152  else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0)
1153  {
1154  res = std::make_unique<cBioGenCheckerboard>();
1155  a_CacheOffByDefault = true; // we're (probably) generating faster than a cache would retrieve data
1156  }
1157  else if (NoCaseCompare(BiomeGenName, "voronoi") == 0)
1158  {
1159  res = std::make_unique<cBioGenVoronoi>(a_Seed);
1160  }
1161  else if (NoCaseCompare(BiomeGenName, "distortedvoronoi") == 0)
1162  {
1163  res = std::make_unique<cBioGenDistortedVoronoi>(a_Seed);
1164  }
1165  else if (NoCaseCompare(BiomeGenName, "twolevel") == 0)
1166  {
1167  res = std::make_unique<cBioGenTwoLevel>(a_Seed);
1168  }
1169  else if (NoCaseCompare(BiomeGenName, "multistepmap") == 0)
1170  {
1171  res = std::make_unique<cBioGenMultiStepMap>(a_Seed);
1172  }
1173  else if (NoCaseCompare(BiomeGenName, "grownprot") == 0)
1174  {
1175  res = std::make_unique<cBioGenProtGrown>(a_Seed);
1176  }
1177  else
1178  {
1179  if (NoCaseCompare(BiomeGenName, "grown") != 0)
1180  {
1181  LOGWARNING("Unknown BiomeGen \"%s\", using \"Grown\" instead.", BiomeGenName.c_str());
1182  }
1183  res = std::make_unique<cBioGenGrown>(a_Seed);
1184  }
1185  res->InitializeBiomeGen(a_IniFile);
1186 
1187  return res;
1188 }
1189 
1190 
1191 
1192 
1193 
1195 // Performance tests:
1196 
1197 // Change to 1 to enable the perf test:
1198 #if 0
1199 
1200 #include <iostream>
1201 
1202 class cBioGenPerfTest
1203 {
1204 public:
1205  cBioGenPerfTest()
1206  {
1207  std::cout << "BioGen performance tests commencing, please wait..." << std::endl;
1208  TestGen("MultiStepMap", std::make_unique<cBioGenMultiStepMap>(1).get());
1209  TestGen("Grown", std::make_unique<cBioGenGrown>(1).get());
1210  TestGen("GrownProt", std::make_unique<cBioGenProtGrown>(1).get());
1211  std::cout << "BioGen performance tests complete." << std::endl;
1212  }
1213 
1214 protected:
1215  void TestGen(const AString && a_GenName, cBiomeGen * a_BioGen)
1216  {
1217  // Initialize the default settings for the generator:
1218  cIniFile iniFile;
1219  a_BioGen->InitializeBiomeGen(iniFile);
1220 
1221  // Generate the biomes:
1222  auto start = std::chrono::system_clock::now();
1223  for (int z = 0; z < 100; z++)
1224  {
1225  for (int x = 0; x < 100; x++)
1226  {
1227  cChunkDef::BiomeMap biomes;
1228  a_BioGen->GenBiomes(x, z, biomes);
1229  } // for x
1230  } // for z
1231  auto dur = std::chrono::system_clock::now() - start;
1232  double milliseconds = static_cast<double>((std::chrono::duration_cast<std::chrono::milliseconds>(dur)).count());
1233 
1234  std::cout << a_GenName << ": " << 1000.0 * 100.0 * 100.0 / milliseconds << " chunks per second" << std::endl;
1235  }
1236 } g_BioGenPerfTest;
1237 
1238 #endif
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
@ biJungleEdge
Definition: BiomeDef.h:50
@ biIceMountains
Definition: BiomeDef.h:38
@ biMesa
Definition: BiomeDef.h:64
@ biMesaPlateau
Definition: BiomeDef.h:66
@ biForestHills
Definition: BiomeDef.h:43
@ biBirchForest
Definition: BiomeDef.h:54
@ biBirchForestM
Definition: BiomeDef.h:86
@ biDesert
Definition: BiomeDef.h:24
@ biMesaPlateauF
Definition: BiomeDef.h:65
@ biSunflowerPlains
Definition: BiomeDef.h:77
@ biExtremeHillsPlusM
Definition: BiomeDef.h:92
@ biColdTaigaHills
Definition: BiomeDef.h:58
@ biFlowerForest
Definition: BiomeDef.h:80
@ biInvalidBiome
Definition: BiomeDef.h:19
@ biMegaSpruceTaiga
Definition: BiomeDef.h:90
@ biMushroomShore
Definition: BiomeDef.h:40
@ biSavanna
Definition: BiomeDef.h:62
@ biTaigaHills
Definition: BiomeDef.h:44
@ biExtremeHillsPlus
Definition: BiomeDef.h:61
@ biJungle
Definition: BiomeDef.h:46
@ biMegaTaiga
Definition: BiomeDef.h:59
@ biJungleHills
Definition: BiomeDef.h:47
@ biOcean
Definition: BiomeDef.h:22
@ biDesertHills
Definition: BiomeDef.h:42
@ biBeach
Definition: BiomeDef.h:41
@ biForest
Definition: BiomeDef.h:26
@ biJungleEdgeM
Definition: BiomeDef.h:85
@ biTaigaM
Definition: BiomeDef.h:81
@ biBirchForestHillsM
Definition: BiomeDef.h:87
@ biJungleM
Definition: BiomeDef.h:84
@ biExtremeHillsEdge
Definition: BiomeDef.h:45
@ biFrozenRiver
Definition: BiomeDef.h:35
@ biRiver
Definition: BiomeDef.h:29
@ biMesaPlateauFM
Definition: BiomeDef.h:96
@ biMushroomIsland
Definition: BiomeDef.h:39
@ biDeepOcean
Definition: BiomeDef.h:51
@ biMesaBryce
Definition: BiomeDef.h:95
@ biPlains
Definition: BiomeDef.h:23
@ biRoofedForestM
Definition: BiomeDef.h:88
@ biBirchForestHills
Definition: BiomeDef.h:55
@ biMegaSpruceTaigaHills
Definition: BiomeDef.h:91
@ biSavannaM
Definition: BiomeDef.h:93
@ biSwamplandM
Definition: BiomeDef.h:82
@ biIcePlainsSpikes
Definition: BiomeDef.h:83
@ biFrozenOcean
Definition: BiomeDef.h:34
@ biExtremeHills
Definition: BiomeDef.h:25
@ biColdTaiga
Definition: BiomeDef.h:57
@ biRoofedForest
Definition: BiomeDef.h:56
@ biIcePlains
Definition: BiomeDef.h:36
@ biTaiga
Definition: BiomeDef.h:27
@ biDesertM
Definition: BiomeDef.h:78
@ biSavannaPlateau
Definition: BiomeDef.h:63
@ biMesaPlateauM
Definition: BiomeDef.h:97
@ biTundra
Definition: BiomeDef.h:37
@ biColdTaigaM
Definition: BiomeDef.h:89
@ biSwampland
Definition: BiomeDef.h:28
eDimension StringToDimension(const AString &a_DimensionString)
Translates a dimension string to dimension enum.
Definition: Defines.cpp:194
@ dimEnd
Definition: Defines.h:234
@ dimNether
Definition: Defines.h:232
@ dimOverworld
Definition: Defines.h:233
@ dimNotSet
Definition: Defines.h:235
cIntGenFactory< Gen, Args... > MakeIntGen(Args &&... a_Args)
Definition: IntGen.h:129
const int bgIce
Definition: IntGen.h:44
const int bgOcean
Constants representing the biome group designators.
Definition: IntGen.h:40
const int bgTemperate
Definition: IntGen.h:42
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
T Clamp(T a_Value, T a_Min, T a_Max)
Clamp X to the specified range.
Definition: Globals.h:336
#define UNUSED
Definition: Globals.h:72
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
#define LOGWARN
Definition: LoggerSimple.h:88
AStringVector StringSplitAndTrim(const AString &str, const AString &delim)
Split the string at any of the listed delimiters and trim each value.
AStringVector StringSplit(const AString &str, const AString &delim)
Split the string at any of the listed delimiters.
Definition: StringUtils.cpp:55
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
bool StringToInteger(const AString &a_str, T &a_Num)
Parses any integer type.
Definition: StringUtils.h:143
Definition: FastNBT.h:132
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 const int Width
Definition: ChunkDef.h:124
static EMCSBiome GetBiome(const BiomeMap &a_BiomeMap, int a_X, int a_Z)
Definition: ChunkDef.h:319
static void SetBiome(BiomeMap &a_BiomeMap, int a_X, int a_Z, EMCSBiome a_Biome)
Definition: ChunkDef.h:327
EMCSBiome BiomeMap[Width *Width]
The type used for any biomemap operations and storage inside Cuberite, using Cuberite biomes (need no...
Definition: ChunkDef.h:137
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_Biomes) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:1008
cBioGenGrown(int a_Seed)
Definition: BioGen.cpp:932
std::shared_ptr< cIntGen< 16, 16 > > m_Gen
Definition: BioGen.cpp:1022
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_Biomes) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:1112
std::shared_ptr< cProtIntGen > m_Gen
Definition: BioGen.cpp:1126
cBioGenProtGrown(int a_Seed)
Definition: BioGen.cpp:1036
virtual void InitializeBiomeGen(cIniFile &a_IniFile) override
Reads parameters from the ini file, prepares generator for use.
Definition: BioGen.cpp:33
EMCSBiome m_Biome
Definition: BioGen.h:33
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:20
std::vector< size_t > m_CacheOrder
Definition: BioGen.h:74
size_t m_NumHits
Definition: BioGen.h:78
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:78
virtual void InitializeBiomeGen(cIniFile &a_IniFile) override
Reads parameters from the ini file, prepares generator for use.
Definition: BioGen.cpp:129
std::vector< sCacheData > m_CacheData
Definition: BioGen.h:75
size_t m_TotalChain
Definition: BioGen.h:80
size_t m_NumMisses
Definition: BioGen.h:79
cBiomeGen & m_BioGenToCache
Definition: BioGen.h:58
cBioGenCache(cBiomeGen &a_BioGenToCache, size_t a_CacheSize)
Definition: BioGen.cpp:59
size_t m_CacheSize
Definition: BioGen.h:73
std::vector< std::unique_ptr< cBioGenCache > > m_Caches
Individual sub-caches.
Definition: BioGen.h:108
std::unique_ptr< cBiomeGen > m_Underlying
The underlying biome generator.
Definition: BioGen.h:111
size_t m_NumSubCaches
Number of sub-caches.
Definition: BioGen.h:105
cBioGenMulticache(std::unique_ptr< cBiomeGen > a_BioGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches)
Definition: BioGen.cpp:141
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:156
virtual void InitializeBiomeGen(cIniFile &a_IniFile) override
Reads parameters from the ini file, prepares generator for use.
Definition: BioGen.cpp:168
EMCSBiomes m_Biomes
Definition: BioGen.h:132
void InitializeBiomes(const AString &a_Biomes)
Parses the INI file setting string into m_Biomes.
Definition: BioGen.cpp:183
int m_BiomesCount
Definition: BioGen.h:133
virtual void InitializeBiomeGen(cIniFile &a_IniFile) override
Reads parameters from the ini file, prepares generator for use.
Definition: BioGen.cpp:281
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:263
cVoronoiMap m_Voronoi
Definition: BioGen.h:175
virtual void InitializeBiomeGen(cIniFile &a_IniFile) override
Reads parameters from the ini file, prepares generator for use.
Definition: BioGen.cpp:316
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:297
virtual void InitializeBiomeGen(cIniFile &a_IniFile) override
Reads parameters from the ini file, prepares generator for use.
Definition: BioGen.cpp:365
void Distort(int a_BlockX, int a_BlockZ, int &a_DistortedX, int &a_DistortedZ)
Distorts the coords using a Perlin-like noise.
Definition: BioGen.cpp:377
cVoronoiMap m_Voronoi
The underlying Voronoi map of the biomes.
Definition: BioGen.h:207
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:335
int m_CellSize
Size of the Voronoi cells, also used for distortion amplitude.
Definition: BioGen.h:210
cNoise m_Noise
Noise used for the distortion.
Definition: BioGen.h:204
void BuildTemperatureHumidityMaps(cChunkCoords a_ChunkCoords, IntMap &a_TemperatureMap, IntMap &a_HumidityMap)
Builds two Perlin-noise maps, one for temperature, the other for humidity.
Definition: BioGen.cpp:606
float m_LandBiomesSize
Definition: BioGen.h:247
void DecideOceanLandMushroom(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap)
Step 1: Decides between ocean, land and mushroom, using a DistVoronoi with special conditions and pos...
Definition: BioGen.cpp:441
double DblMap[17 *17]
Definition: BioGen.h:250
cBioGenMultiStepMap(int a_Seed)
Definition: BioGen.cpp:397
void Distort(int a_BlockX, int a_BlockZ, int &a_DistortedX, int &a_DistortedZ, int a_CellSize)
Distorts the coords using a Perlin-like noise, with a specified cell-size.
Definition: BioGen.cpp:589
int m_MushroomIslandSize
Definition: BioGen.h:244
double m_RiverWidthThreshold
Definition: BioGen.h:246
virtual void InitializeBiomeGen(cIniFile &a_IniFile) override
Reads parameters from the ini file, prepares generator for use.
Definition: BioGen.cpp:417
void FreezeWaterBiomes(cChunkDef::BiomeMap &a_BiomeMap, const IntMap &a_TemperatureMap)
Flips biOcean and biRiver into biFrozenOcean and biFrozenRiver if the temperature is too low.
Definition: BioGen.cpp:688
void DecideLandBiomes(cChunkDef::BiomeMap &a_BiomeMap, const IntMap &a_TemperatureMap, const IntMap &a_HumidityMap)
Flips all remaining "-1" biomes into land biomes using the two maps.
Definition: BioGen.cpp:644
int IntMap[17 *17]
Definition: BioGen.h:249
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:430
void AddRivers(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap)
Step 2: Add rivers to the land Flips some "-1" biomes into biRiver.
Definition: BioGen.cpp:544
void ApplyTemperatureHumidity(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap)
Step 3: Decide land biomes using a temperature / humidity map; freeze ocean / river in low temperatur...
Definition: BioGen.cpp:575
float m_AmpZ1
Definition: BioGen.h:313
float m_AmpX2
Definition: BioGen.h:311
float m_AmpZ2
Definition: BioGen.h:314
cBioGenTwoLevel(int a_Seed)
Definition: BioGen.cpp:718
float m_FreqZ2
Definition: BioGen.h:314
cNoise m_Noise6
Definition: BioGen.h:307
cVoronoiMap m_VoronoiSmall
The Voronoi map that decides biomes inside individual biome groups.
Definition: BioGen.h:299
cNoise m_Noise5
Definition: BioGen.h:306
EMCSBiome SelectBiome(int a_BiomeGroup, size_t a_BiomeIdx, int a_DistLevel)
Selects biome from the specified biome group, based on the specified index.
Definition: BioGen.cpp:790
cNoise m_Noise1
Definition: BioGen.h:302
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap) override
Generates biomes for the given chunk.
Definition: BioGen.cpp:746
float m_AmpX3
Definition: BioGen.h:312
float m_AmpX1
Definition: BioGen.h:310
cNoise m_Noise2
Definition: BioGen.h:303
cNoise m_Noise4
Definition: BioGen.h:305
float m_FreqZ1
Definition: BioGen.h:313
float m_FreqX3
Definition: BioGen.h:312
float m_AmpZ3
Definition: BioGen.h:315
float m_FreqZ3
Definition: BioGen.h:315
cVoronoiMap m_VoronoiLarge
The Voronoi map that decides the groups of biomes.
Definition: BioGen.h:296
float m_FreqX1
Definition: BioGen.h:310
cNoise m_Noise3
Definition: BioGen.h:304
virtual void InitializeBiomeGen(cIniFile &a_IniFile) override
Reads parameters from the ini file, prepares generator for use.
Definition: BioGen.cpp:903
float m_FreqX2
Definition: BioGen.h:311
The interface that a biome generator must implement A biome generator takes chunk coords on input and...
virtual void InitializeBiomeGen(cIniFile &a_IniFile)
Reads parameters from the ini file, prepares generator for use.
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
virtual void GenBiomes(cChunkCoords a_ChunkCoords, cChunkDef::BiomeMap &a_BiomeMap)=0
Generates biomes for the given chunk.
int[SizeX *SizeZ] Values
Holds the array of values generated by this class (descendant).
Definition: IntGen.h:65
Zooms the underlying value array to twice the size.
Definition: IntGen.h:261
Smoothes out some artifacts generated by the zooming - mostly single-pixel values.
Definition: IntGen.h:335
Generates a river based on the underlying data.
Definition: IntGen.h:932
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 GetValueSetI(const AString &keyname, const AString &valuename, const int defValue=0) override
Definition: IniFile.cpp:559
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
double GetValueSetF(const AString &keyname, const AString &valuename, const double defValue=0.0)
Definition: IniFile.cpp:549
NOISE_DATATYPE CubicNoise2D(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y) const
Definition: Noise.cpp:593
NOISE_DATATYPE CubicNoise3D(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y, NOISE_DATATYPE a_Z) const
Definition: Noise.cpp:621
int IntNoise3DInt(int a_X, int a_Y, int a_Z) const
Definition: Noise.h:254
void SetCellSize(int a_CellSize)
Sets both the cell size and jitter size used for generating the Voronoi seeds.
Definition: VoronoiMap.cpp:29
void SetJitterSize(int a_JitterSize)
Sets the jitter size.
Definition: VoronoiMap.cpp:42
void SetOddRowOffset(int a_OddRowOffset)
Sets the offset that is added to each odd row of cells.
Definition: VoronoiMap.cpp:51
int GetValueAt(int a_X, int a_Y)
Returns the value in the cell into which the specified point lies.
Definition: VoronoiMap.cpp:60