Cuberite
A lightweight, fast and extensible game server for Minecraft
HeiGen.cpp
Go to the documentation of this file.
1 
2 // HeiGen.cpp
3 
4 // Implements the various terrain height generators
5 
6 #include "Globals.h"
7 #include "HeiGen.h"
8 #include "../LinearUpscale.h"
9 #include "../IniFile.h"
10 #include "DistortedHeightmap.h"
11 #include "EndGen.h"
12 #include "Noise3DGenerator.h"
13 #include "ProtIntGen.h"
14 
15 
16 
17 
18 
20 // cHeiGenSteppy:
21 
23  public cTerrainHeightGen
24 {
25 public:
26  cHeiGenSteppy(int a_Seed) :
27  m_Seed(a_Seed)
28  {
29  m_Gen =
30  std::make_shared<cProtIntGenWeightAvg<16, 1, 0>>(
31  std::make_shared<cProtIntGenSmooth> (a_Seed + 1,
32  std::make_shared<cProtIntGenZoom> (a_Seed + 2,
33  std::make_shared<cProtIntGenSmooth> (a_Seed + 3,
34  std::make_shared<cProtIntGenZoom> (a_Seed + 4,
35  std::make_shared<cProtIntGenAddRnd> (a_Seed + 5, 1,
36  std::make_shared<cProtIntGenSmooth> (a_Seed + 6,
37  std::make_shared<cProtIntGenZoom> (a_Seed + 7,
38  std::make_shared<cProtIntGenRndBetween> (a_Seed + 8, 60,
39  std::make_shared<cProtIntGenAddRnd> (a_Seed + 9, 1,
40  std::make_shared<cProtIntGenSmooth> (a_Seed + 1,
41  std::make_shared<cProtIntGenZoom> (a_Seed + 2,
42  std::make_shared<cProtIntGenRndBetween> (a_Seed + 3, 60,
43  std::make_shared<cProtIntGenSmooth> (a_Seed + 4,
44  std::make_shared<cProtIntGenZoom> (a_Seed + 5,
45  std::make_shared<cProtIntGenRndBetween> (a_Seed + 6, 60,
46  std::make_shared<cProtIntGenRndChoice> (a_Seed + 7, 10, 50, 50,
47  std::make_shared<cProtIntGenSmooth> (a_Seed + 8,
48  std::make_shared<cProtIntGenZoom> (a_Seed + 9,
49  std::make_shared<cProtIntGenRndChoice> (a_Seed + 1, 10, 50, 50,
50  std::make_shared<cProtIntGenAddRnd> (a_Seed + 2, 2,
51  std::make_shared<cProtIntGenZoom> (a_Seed + 3,
52  std::make_shared<cProtIntGenZoom> (a_Seed + 4,
53  std::make_shared<cProtIntGenChoice> (a_Seed + 5, 10)
54  )))))))))))))))))))))));
55  }
56 
57  // cTerrainHeightGen overrides:
58  virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap & a_HeightMap) override
59  {
60  int heights[cChunkDef::Width * cChunkDef::Width];
61  m_Gen->GetInts(
62  a_ChunkCoords.m_ChunkX * cChunkDef::Width, a_ChunkCoords.m_ChunkZ * cChunkDef::Width,
63  static_cast<size_t>(cChunkDef::Width), static_cast<size_t>(cChunkDef::Width), heights
64  );
65  for (size_t i = 0; i < ARRAYCOUNT(heights); i++)
66  {
67  a_HeightMap[i] = static_cast<HEIGHTTYPE>(std::max(std::min(60 + heights[i], cChunkDef::Height - 60), 40));
68  }
69  }
70 
71 protected:
72  int m_Seed;
73 
74  std::shared_ptr<cProtIntGen> m_Gen;
75 };
76 
77 
78 
79 
80 
82 // cHeiGenFlat:
83 
85 {
86  UNUSED(a_ChunkCoords);
87  for (size_t i = 0; i < ARRAYCOUNT(a_HeightMap); i++)
88  {
89  a_HeightMap[i] = m_Height;
90  }
91 }
92 
93 
94 
95 
96 
98 {
99  m_Height = static_cast<HEIGHTTYPE>(a_IniFile.GetValueSetI("Generator", "FlatHeight", m_Height));
100 }
101 
102 
103 
104 
105 
107 // cHeiGenCache:
108 
109 cHeiGenCache::cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, size_t a_CacheSize) :
110  m_HeiGenToCache(a_HeiGenToCache),
111  m_CacheSize(a_CacheSize),
112  m_NumHits(0),
113  m_NumMisses(0),
114  m_TotalChain(0)
115 {
116  m_CacheOrder.resize(a_CacheSize);
117  m_CacheData.resize(a_CacheSize);
118  for (size_t i = 0; i < m_CacheSize; i++)
119  {
120  m_CacheOrder[i] = i;
121  }
122 }
123 
124 
125 
126 
127 
129 {
130  /*
131  if (((m_NumHits + m_NumMisses) % 1024) == 10)
132  {
133  LOGD("HeiGenCache: %d hits, %d misses, saved %.2f %%", m_NumHits, m_NumMisses, 100.0 * m_NumHits / (m_NumHits + m_NumMisses));
134  LOGD("HeiGenCache: Avg cache chain length: %.2f", static_cast<double>(m_TotalChain) / m_NumHits);
135  }
136  //*/
137 
138  for (size_t i = 0; i < m_CacheSize; i++)
139  {
140  if (m_CacheData[m_CacheOrder[i]].m_Coords != a_ChunkCoords)
141  {
142  continue;
143  }
144  // Found it in the cache
145  auto Idx = m_CacheOrder[i];
146 
147  // Move to front:
148  for (size_t j = i; j > 0; j--)
149  {
150  m_CacheOrder[j] = m_CacheOrder[j - 1];
151  }
152  m_CacheOrder[0] = Idx;
153 
154  // Use the cached data:
155  memcpy(a_HeightMap, m_CacheData[Idx].m_HeightMap, sizeof(a_HeightMap));
156 
157  m_NumHits++;
158  m_TotalChain += i;
159  return;
160  } // for i - cache
161 
162  // Not in the cache:
163  m_NumMisses++;
164  m_HeiGenToCache->GenHeightMap(a_ChunkCoords, a_HeightMap);
165 
166  // Insert it as the first item in the MRU order:
167  auto Idx = m_CacheOrder[m_CacheSize - 1];
168  for (auto i = m_CacheSize - 1; i > 0; i--)
169  {
170  m_CacheOrder[i] = m_CacheOrder[i - 1];
171  } // for i - m_CacheOrder[]
172  m_CacheOrder[0] = Idx;
173  memcpy(m_CacheData[Idx].m_HeightMap, a_HeightMap, sizeof(a_HeightMap));
174  m_CacheData[Idx].m_Coords = a_ChunkCoords;
175 }
176 
177 
178 
179 
180 
181 HEIGHTTYPE cHeiGenCache::GetHeightAt(int a_BlockX, int a_BlockZ)
182 {
183  // First try if the chunk is already in the cache:
184  int chunkX, chunkZ;
185  cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, chunkX, chunkZ);
186  HEIGHTTYPE res;
187  if (GetHeightAt(chunkX, chunkZ, a_BlockX - chunkX * cChunkDef::Width, a_BlockZ - chunkZ * cChunkDef::Width, res))
188  {
189  return res;
190  }
191 
192  // Chunk not in cache, generate the chunk and ask again:
193  cChunkDef::HeightMap heightMap;
194  GenHeightMap({chunkX, chunkZ}, heightMap);
195  return cChunkDef::GetHeight(heightMap, a_BlockX - chunkX * cChunkDef::Width, a_BlockZ - chunkZ * cChunkDef::Width);
196 }
197 
198 
199 
200 
201 
202 bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height)
203 {
204  for (size_t i = 0; i < m_CacheSize; i++)
205  {
206  if ((m_CacheData[i].m_Coords.m_ChunkX == a_ChunkX) && (m_CacheData[i].m_Coords.m_ChunkZ == a_ChunkZ))
207  {
208  a_Height = cChunkDef::GetHeight(m_CacheData[i].m_HeightMap, a_RelX, a_RelZ);
209  return true;
210  }
211  } // for i - m_CacheData[]
212  return false;
213 }
214 
215 
216 
217 
218 
220 // cHeiGenMultiCache:
221 
222 cHeiGenMultiCache::cHeiGenMultiCache(cTerrainHeightGenPtr a_HeiGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches):
223  m_NumSubCaches(a_NumSubCaches)
224 {
225  // Create the individual sub-caches:
226  m_SubCaches.reserve(a_NumSubCaches);
227  for (size_t i = 0; i < a_NumSubCaches; i++)
228  {
229  m_SubCaches.push_back(std::make_shared<cHeiGenCache>(a_HeiGenToCache, a_SubCacheSize));
230  }
231 }
232 
233 
234 
235 
236 
238 {
239  // Get the subcache responsible for this chunk:
240  const size_t cacheIdx = (static_cast<size_t>(a_ChunkCoords.m_ChunkX) + m_CoeffZ * static_cast<size_t>(a_ChunkCoords.m_ChunkZ)) % m_NumSubCaches;
241 
242  // Ask the subcache:
243  m_SubCaches[cacheIdx]->GenHeightMap(a_ChunkCoords, a_HeightMap);
244 }
245 
246 
247 
248 
249 
250 HEIGHTTYPE cHeiGenMultiCache::GetHeightAt(int a_BlockX, int a_BlockZ)
251 {
252  // First try if the chunk is already in the cache:
253  int chunkX, chunkZ;
254  cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, chunkX, chunkZ);
255  HEIGHTTYPE res;
256  if (GetHeightAt(chunkX, chunkZ, a_BlockX - chunkX * cChunkDef::Width, a_BlockZ - chunkZ * cChunkDef::Width, res))
257  {
258  return res;
259  }
260 
261  // Chunk not in cache, generate the chunk and ask again:
262  cChunkDef::HeightMap heightMap;
263  GenHeightMap({chunkX, chunkZ}, heightMap);
264  return cChunkDef::GetHeight(heightMap, a_BlockX - chunkX * cChunkDef::Width, a_BlockZ - chunkZ * cChunkDef::Width);
265 }
266 
267 
268 
269 
270 
271 bool cHeiGenMultiCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height)
272 {
273  // Get the subcache responsible for this chunk:
274  const size_t cacheIdx = (static_cast<size_t>(a_ChunkX) + m_CoeffZ * static_cast<size_t>(a_ChunkZ)) % m_NumSubCaches;
275 
276  // Ask the subcache:
277  return m_SubCaches[cacheIdx]->GetHeightAt(a_ChunkX, a_ChunkZ, a_RelX, a_RelZ, a_Height);
278 }
279 
280 
281 
282 
283 
285 // cHeiGenClassic:
286 
288  m_Seed(a_Seed),
289  m_Noise(a_Seed),
290  m_HeightFreq1(1.0f),
291  m_HeightAmp1(1.0f),
292  m_HeightFreq2(0.5f),
293  m_HeightAmp2(0.5f),
294  m_HeightFreq3(0.1f),
295  m_HeightAmp3(0.1f)
296 {
297 }
298 
299 
300 
301 
302 
303 float cHeiGenClassic::GetNoise(float x, float y)
304 {
305  float oct1 = m_Noise.CubicNoise2D(x * m_HeightFreq1, y * m_HeightFreq1) * m_HeightAmp1;
306  float oct2 = m_Noise.CubicNoise2D(x * m_HeightFreq2, y * m_HeightFreq2) * m_HeightAmp2;
307  float oct3 = m_Noise.CubicNoise2D(x * m_HeightFreq3, y * m_HeightFreq3) * m_HeightAmp3;
308 
309  float height = m_Noise.CubicNoise2D(x * 0.1f, y * 0.1f) * 2;
310 
311  float flatness = ((m_Noise.CubicNoise2D(x * 0.5f, y * 0.5f) + 1.f) * 0.5f) * 1.1f; // 0 ... 1.5
312  flatness *= flatness * flatness;
313 
314  return (oct1 + oct2 + oct3) * flatness + height;
315 }
316 
317 
318 
319 
320 
322 {
323  for (int z = 0; z < cChunkDef::Width; z++)
324  {
325  const float zz = static_cast<float>(a_ChunkCoords.m_ChunkZ * cChunkDef::Width + z);
326  for (int x = 0; x < cChunkDef::Width; x++)
327  {
328  const float xx = static_cast<float>(a_ChunkCoords.m_ChunkX * cChunkDef::Width + x);
329 
330  HEIGHTTYPE hei = static_cast<HEIGHTTYPE>(Clamp(static_cast<int>(64 + (GetNoise(xx * 0.05f, zz * 0.05f) * 16)), 10, 250));
331  cChunkDef::SetHeight(a_HeightMap, x, z, hei);
332  } // for x
333  } // for z
334 }
335 
336 
337 
338 
339 
341 {
342  m_HeightFreq1 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "ClassicHeightFreq1", 0.1));
343  m_HeightFreq2 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "ClassicHeightFreq2", 1.0));
344  m_HeightFreq3 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "ClassicHeightFreq3", 2.0));
345  m_HeightAmp1 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "ClassicHeightAmp1", 1.0));
346  m_HeightAmp2 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "ClassicHeightAmp2", 0.5));
347  m_HeightAmp3 = static_cast<float>(a_IniFile.GetValueSetF("Generator", "ClassicHeightAmp3", 0.5));
348 }
349 
350 
351 
352 
353 
355 // cHeiGenMountains:
356 
358  m_Seed(a_Seed),
359  m_MountainNoise(a_Seed + 100),
360  m_DitchNoise(a_Seed + 200),
361  m_Perlin(a_Seed + 300)
362 {
363 }
364 
365 
366 
367 
368 
370 {
371  NOISE_DATATYPE StartX = static_cast<NOISE_DATATYPE>(a_ChunkCoords.m_ChunkX * cChunkDef::Width);
372  NOISE_DATATYPE EndX = static_cast<NOISE_DATATYPE>(a_ChunkCoords.m_ChunkX * cChunkDef::Width + cChunkDef::Width - 1);
373  NOISE_DATATYPE StartZ = static_cast<NOISE_DATATYPE>(a_ChunkCoords.m_ChunkZ * cChunkDef::Width);
374  NOISE_DATATYPE EndZ = static_cast<NOISE_DATATYPE>(a_ChunkCoords.m_ChunkZ * cChunkDef::Width + cChunkDef::Width - 1);
375  NOISE_DATATYPE Workspace[16 * 16];
376  NOISE_DATATYPE MountainNoise[16 * 16];
377  NOISE_DATATYPE DitchNoise[16 * 16];
378  NOISE_DATATYPE PerlinNoise[16 * 16];
379  m_MountainNoise.Generate2D(MountainNoise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace);
380  m_DitchNoise.Generate2D(DitchNoise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace);
381  m_Perlin.Generate2D(PerlinNoise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace);
382  for (int z = 0; z < cChunkDef::Width; z++)
383  {
384  int IdxZ = z * cChunkDef::Width;
385  for (int x = 0; x < cChunkDef::Width; x++)
386  {
387  int idx = IdxZ + x;
388  HEIGHTTYPE hei = static_cast<HEIGHTTYPE>(Clamp(100 - static_cast<int>((MountainNoise[idx] - DitchNoise[idx] + PerlinNoise[idx]) * 15), 10, 250));
389  cChunkDef::SetHeight(a_HeightMap, x, z, hei);
390  } // for x
391  } // for z
392 }
393 
394 
395 
396 
397 
399 {
400  // TODO: Read the params from an INI file
401  m_MountainNoise.AddOctave(0.1f, 0.2f);
402  m_MountainNoise.AddOctave(0.05f, 0.4f);
403  m_MountainNoise.AddOctave(0.02f, 1.0f);
404  m_DitchNoise.AddOctave(0.1f, 0.2f);
405  m_DitchNoise.AddOctave(0.05f, 0.4f);
406  m_DitchNoise.AddOctave(0.02f, 1.0f);
407 
408  m_Perlin.AddOctave(0.01f, 1.5f);
409 }
410 
411 
412 
413 
414 
416 // cHeiGenBiomal:
417 
419 {
420  /* Fast-changing | Middle-changing | Slow-changing | */
421  /* Biome | Freq1 | Amp1 | Freq2 | Amp2 | Freq3 | Amp3 | BaseHeight */
422  /* biOcean */ { 0.1f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 50},
423  /* biPlains */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 68},
424  /* biDesert */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 68},
425  /* biExtremeHills */ { 0.2f, 4.0f, 0.05f, 20.0f, 0.01f, 16.0f, 100},
426  /* biForest */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70},
427  /* biTaiga */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70},
428  /* biSwampland */ { 0.1f, 1.1f, 0.05f, 1.5f, 0.02f, 2.5f, 61.5},
429  /* biRiver */ { 0.2f, 0.1f, 0.05f, 0.1f, 0.01f, 0.1f, 56},
430  /* biNether */ { 0.1f, 0.0f, 0.01f, 0.0f, 0.01f, 0.0f, 0}, // Unused, but must be here due to indexing
431  /* biSky */ { 0.1f, 0.0f, 0.01f, 0.0f, 0.01f, 0.0f, 0}, // Unused, but must be here due to indexing
432  /* biFrozenOcean */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40},
433  /* biFrozenRiver */ { 0.2f, 0.1f, 0.05f, 0.1f, 0.01f, 0.1f, 56},
434  /* biIcePlains */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 68},
435  /* biIceMountains */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80},
436  /* biMushroomIsland */ { 0.1f, 2.0f, 0.05f, 8.0f, 0.01f, 6.0f, 80},
437  /* biMushroomShore */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 64},
438  /* biBeach */ { 0.1f, 0.5f, 0.05f, 1.0f, 0.01f, 1.0f, 64},
439  /* biDesertHills */ { 0.2f, 2.0f, 0.05f, 5.0f, 0.01f, 4.0f, 75},
440  /* biForestHills */ { 0.2f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 80},
441  /* biTaigaHills */ { 0.2f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 80},
442  /* biExtremeHillsEdge */ { 0.2f, 3.0f, 0.05f, 16.0f, 0.01f, 12.0f, 80},
443  /* biJungle */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70},
444  /* biJungleHills */ { 0.2f, 3.0f, 0.05f, 12.0f, 0.01f, 10.0f, 80},
445  /* biJungleEdge */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70},
446  /* biDeepOcean */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40},
447  /* biStoneBeach */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40},
448  /* biColdBeach */ { 0.1f, 0.5f, 0.05f, 1.0f, 0.01f, 1.0f, 64},
449  /* biBirchForest */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70},
450  /* biBirchForestHills */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80},
451  /* biRoofedForest */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70},
452  /* biColdTaiga */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70},
453  /* biColdTaigaHills */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80},
454  /* biMegaTaiga */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70},
455  /* biMegaTaigaHills */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80},
456  /* biExtremeHillsPlus */ { 0.2f, 4.0f, 0.05f, 20.0f, 0.01f, 16.0f, 120},
457  /* biSavanna */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 68},
458  /* biSavannaPlateau */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 80},
459  /* biMesa */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 70}, // 165
460  /* biMesaPlateauF */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 80},
461  /* biMesaPlateau */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 80},
462 
463  // biomes 40 .. 128 are unused, 89 empty placeholders here:
464  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 40 .. 49
465  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 50 .. 59
466  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 60 .. 69
467  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 70 .. 79
468  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 80 .. 89
469  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 90 .. 99
470  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 100 .. 109
471  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 110 .. 119
472  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 120 .. 128
473 
474  /* biSunflowerPlains */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 129
475  /* biDesertM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 130
476  /* biExtremeHillsM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 131
477  /* biFlowerForest */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 132
478  /* biTaigaM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 133
479  /* biSwamplandM */ { 1.0f, 3.0f, 1.10f, 7.0f, 0.01f, 0.01f, 60}, // 134
480 
481  // Biomes 135 .. 139 unused, 5 empty placeholders here:
482  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 135 .. 139
483 
484  /* biIcePlainsSpikes */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 140
485 
486  // Biomes 141 .. 148 unused, 8 empty placeholders here:
487  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 141 .. 148
488 
489  /* biJungleM */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70}, // 149
490  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 150
491  /* biJungleEdgeM */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70}, // 151
492  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 152 .. 154
493  /* biBirchForestM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 155
494  /* biBirchForestHillsM */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80}, // 156
495  /* biRoofedForestM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 157
496  /* biColdTaigaM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 158
497  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 159
498  /* biMegaSpruceTaiga */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 160
499  /* biMegaSpruceTaigaHills */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80}, // 161
500  /* biExtremeHillsPlusM */ { 0.2f, 4.0f, 0.05f, 20.0f, 0.01f, 16.0f, 120}, // 162
501  /* biSavannaM */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 68}, // 163
502  /* biSavannaPlateauM */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 80}, // 164
503  /* biMesaBryce */ { 0.2f, 2.0f, 0.1f, 30.0f, 0.01f, 8.0f, 80},
504  /* biMesaPlateauFM */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 80}, // 166
505  /* biMesaPlateauM */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 80}, // 167
506 } ;
507 
508 
509 
510 
511 
513 {
514  // Generate a 3x3 chunk area of biomes around this chunk:
515  BiomeNeighbors Biomes;
516  for (int z = -1; z <= 1; z++)
517  {
518  for (int x = -1; x <= 1; x++)
519  {
520  m_BiomeGen->GenBiomes({a_ChunkCoords.m_ChunkX + x, a_ChunkCoords.m_ChunkZ + z}, Biomes[x + 1][z + 1]);
521  } // for x
522  } // for z
523 
524  // Linearly interpolate 4x4 blocks of heightmap:
525  // Must be done on a floating point datatype, otherwise the results are ugly!
526  const int STEPZ = 4; // Must be a divisor of 16
527  const int STEPX = 4; // Must be a divisor of 16
528  NOISE_DATATYPE Height[17 * 17];
529  for (int z = 0; z < 17; z += STEPZ)
530  {
531  for (int x = 0; x < 17; x += STEPX)
532  {
533  Height[x + 17 * z] = GetHeightAt(x, z, a_ChunkCoords.m_ChunkX, a_ChunkCoords.m_ChunkZ, Biomes);
534  }
535  }
536  LinearUpscale2DArrayInPlace<17, 17, STEPX, STEPZ>(Height);
537 
538  // Copy into the heightmap
539  for (int z = 0; z < cChunkDef::Width; z++)
540  {
541  for (int x = 0; x < cChunkDef::Width; x++)
542  {
543  cChunkDef::SetHeight(a_HeightMap, x, z, static_cast<HEIGHTTYPE>(Height[x + 17 * z]));
544  }
545  }
546 }
547 
548 
549 
550 
551 
553 {
554  // No user-settable params
555 }
556 
557 
558 
559 
560 
561 NOISE_DATATYPE cHeiGenBiomal::GetHeightAt(int a_RelX, int a_RelZ, int a_ChunkX, int a_ChunkZ, const cHeiGenBiomal::BiomeNeighbors & a_BiomeNeighbors)
562 {
563  // Sum up how many biomes of each type there are in the neighborhood:
564  int BiomeCounts[256];
565  memset(BiomeCounts, 0, sizeof(BiomeCounts));
566  int Sum = 0;
567  for (int z = -8; z <= 8; z++)
568  {
569  int FinalZ = a_RelZ + z + cChunkDef::Width;
570  int IdxZ = FinalZ / cChunkDef::Width;
571  int ModZ = FinalZ % cChunkDef::Width;
572  int WeightZ = 9 - abs(z);
573  for (int x = -8; x <= 8; x++)
574  {
575  int FinalX = a_RelX + x + cChunkDef::Width;
576  int IdxX = FinalX / cChunkDef::Width;
577  int ModX = FinalX % cChunkDef::Width;
578  EMCSBiome Biome = cChunkDef::GetBiome(a_BiomeNeighbors[IdxX][IdxZ], ModX, ModZ);
579  int WeightX = 9 - abs(x);
580  BiomeCounts[Biome] += WeightX + WeightZ;
581  Sum += WeightX + WeightZ;
582  } // for x
583  } // for z
584 
585  // For each biome type that has a nonzero count, calc its height and add it:
586  if (Sum > 0)
587  {
588  NOISE_DATATYPE Height = 0;
589  int BlockX = a_ChunkX * cChunkDef::Width + a_RelX;
590  int BlockZ = a_ChunkZ * cChunkDef::Width + a_RelZ;
591  for (size_t i = 0; i < ARRAYCOUNT(BiomeCounts); i++)
592  {
593  if (BiomeCounts[i] == 0)
594  {
595  continue;
596  }
597 
598  /*
599  // Sanity checks for biome parameters, enable them to check the biome param table in runtime (slow):
600  ASSERT(m_GenParam[i].m_HeightFreq1 >= 0);
601  ASSERT(m_GenParam[i].m_HeightFreq1 < 1000);
602  ASSERT(m_GenParam[i].m_HeightFreq2 >= 0);
603  ASSERT(m_GenParam[i].m_HeightFreq2 < 1000);
604  ASSERT(m_GenParam[i].m_HeightFreq3 >= 0);
605  ASSERT(m_GenParam[i].m_HeightFreq3 < 1000);
606  */
607 
608  NOISE_DATATYPE oct1 = m_Noise.CubicNoise2D(BlockX * m_GenParam[i].m_HeightFreq1, BlockZ * m_GenParam[i].m_HeightFreq1) * m_GenParam[i].m_HeightAmp1;
609  NOISE_DATATYPE oct2 = m_Noise.CubicNoise2D(BlockX * m_GenParam[i].m_HeightFreq2, BlockZ * m_GenParam[i].m_HeightFreq2) * m_GenParam[i].m_HeightAmp2;
610  NOISE_DATATYPE oct3 = m_Noise.CubicNoise2D(BlockX * m_GenParam[i].m_HeightFreq3, BlockZ * m_GenParam[i].m_HeightFreq3) * m_GenParam[i].m_HeightAmp3;
611  Height += BiomeCounts[i] * (m_GenParam[i].m_BaseHeight + oct1 + oct2 + oct3);
612  }
613  NOISE_DATATYPE res = Height / Sum;
614  return std::min(static_cast<NOISE_DATATYPE>(250), std::max(res, static_cast<NOISE_DATATYPE>(5)));
615  }
616 
617  // No known biome around? Weird. Return a bogus value:
618  ASSERT(!"cHeiGenBiomal: Biome sum failed, no known biome around");
619  return 5;
620 }
621 
622 
623 
624 
625 
627 // cHeiGenMinMax:
628 
630  public cTerrainHeightGen
631 {
633 
635  static const int AVERAGING_SIZE = 4;
636 
637 public:
638  cHeiGenMinMax(int a_Seed, cBiomeGenPtr a_BiomeGen):
639  m_Noise(a_Seed),
640  m_BiomeGen(a_BiomeGen),
641  m_TotalWeight(0)
642  {
643  // Initialize the weights:
644  for (int z = 0; z <= AVERAGING_SIZE * 2; z++)
645  {
646  for (int x = 0; x <= AVERAGING_SIZE * 2; x++)
647  {
648  m_Weights[z][x] = 1 + 2 * AVERAGING_SIZE - std::abs(x - AVERAGING_SIZE) - std::abs(z - AVERAGING_SIZE);
649  m_TotalWeight += m_Weights[z][x];
650  }
651  }
652 
653  // Initialize the Perlin generator:
654  m_Perlin.AddOctave(0.04f, 0.2f);
655  m_Perlin.AddOctave(0.02f, 0.1f);
656  m_Perlin.AddOctave(0.01f, 0.05f);
657  }
658 
659 
660  virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap & a_HeightMap) override
661  {
662  // Generate the biomes for the 3 * 3 neighbors:
663  cChunkDef::BiomeMap neighborBiomes[3][3];
664  for (int z = 0; z < 3; z++) for (int x = 0; x < 3; x++)
665  {
666  m_BiomeGen->GenBiomes({a_ChunkCoords.m_ChunkX + x - 1, a_ChunkCoords.m_ChunkZ + z - 1}, neighborBiomes[z][x]);
667  }
668 
669  // Get the min and max heights based on the biomes:
670  double minHeight[cChunkDef::Width * cChunkDef::Width];
671  double maxHeight[cChunkDef::Width * cChunkDef::Width];
672  for (int z = 0; z < cChunkDef::Width; z++)
673  {
674  for (int x = 0; x < cChunkDef::Width; x++)
675  {
676  // For each column, sum the min and max values of the neighborhood around it:
677  double min = 0, max = 0;
678  for (int relz = 0; relz <= AVERAGING_SIZE * 2; relz++)
679  {
680  int bz = z + 16 + relz - AVERAGING_SIZE; // Biome Z coord relative to the neighborBiomes start
681  int cz = bz / 16; // Chunk Z coord relative to the neighborBiomes start
682  bz = bz % 16; // Biome Z coord relative to cz in neighborBiomes
683  for (int relx = 0; relx <= AVERAGING_SIZE * 2; relx++)
684  {
685  int bx = x + 16 + relx - AVERAGING_SIZE; // Biome X coord relative to the neighborBiomes start
686  int cx = bx / 16; // Chunk X coord relative to the neighborBiomes start
687  bx = bx % 16; // Biome X coord relative to cz in neighborBiomes
688 
689  // Get the biome's min and max heights:
690  double bmin, bmax;
691  getBiomeMinMax(cChunkDef::GetBiome(neighborBiomes[cz][cx], bx, bz), bmin, bmax);
692 
693  // Add them to the total, with the weight depending on their relative position to the column:
694  min += bmin * m_Weights[relz][relx];
695  max += bmax * m_Weights[relz][relx];
696  } // for relx
697  } // for relz
698  minHeight[x + z * cChunkDef::Width] = min / m_TotalWeight;
699  maxHeight[x + z * cChunkDef::Width] = max / m_TotalWeight;
700  } // for x
701  } // for z
702 
703  // Generate the base noise:
704  NOISE_DATATYPE noise[cChunkDef::Width * cChunkDef::Width];
705  NOISE_DATATYPE workspace[cChunkDef::Width * cChunkDef::Width];
706  NOISE_DATATYPE startX = static_cast<float>(a_ChunkCoords.m_ChunkX * cChunkDef::Width);
707  NOISE_DATATYPE endX = startX + cChunkDef::Width - 1;
708  NOISE_DATATYPE startZ = static_cast<float>(a_ChunkCoords.m_ChunkZ * cChunkDef::Width);
709  NOISE_DATATYPE endZ = startZ + cChunkDef::Width - 1;
710  m_Perlin.Generate2D(noise, 16, 16, startX, endX, startZ, endZ, workspace);
711 
712  // Make the height by ranging the noise between min and max:
713  for (int z = 0; z < cChunkDef::Width; z++)
714  {
715  for (int x = 0; x < cChunkDef::Width; x++)
716  {
717  double min = minHeight[x + z * cChunkDef::Width];
718  double max = maxHeight[x + z * cChunkDef::Width];
719  double h = (max + min) / 2 + noise[x + z * cChunkDef::Width] * (max - min);
720  cChunkDef::SetHeight(a_HeightMap, x, z, static_cast<HEIGHTTYPE>(h));
721  }
722  }
723  }
724 
725 
726  virtual void InitializeHeightGen(cIniFile & a_IniFile) override
727  {
728  // No settings available
729  }
730 
731 protected:
733 
735 
738 
740  double m_Weights[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1];
741 
744 
745 
747  void getBiomeMinMax(EMCSBiome a_Biome, double & a_Min, double & a_Max)
748  {
749  switch (a_Biome)
750  {
751  case biBeach: a_Min = 61; a_Max = 64; break;
752  case biBirchForest: a_Min = 63; a_Max = 75; break;
753  case biBirchForestHills: a_Min = 63; a_Max = 90; break;
754  case biBirchForestHillsM: a_Min = 63; a_Max = 90; break;
755  case biBirchForestM: a_Min = 63; a_Max = 75; break;
756  case biColdBeach: a_Min = 61; a_Max = 64; break;
757  case biColdTaiga: a_Min = 63; a_Max = 75; break;
758  case biColdTaigaHills: a_Min = 63; a_Max = 90; break;
759  case biColdTaigaM: a_Min = 63; a_Max = 75; break;
760  case biDeepOcean: a_Min = 30; a_Max = 60; break;
761  case biDesert: a_Min = 63; a_Max = 70; break;
762  case biDesertHills: a_Min = 63; a_Max = 85; break;
763  case biDesertM: a_Min = 63; a_Max = 70; break;
764  case biEnd: a_Min = 10; a_Max = 100; break;
765  case biExtremeHills: a_Min = 60; a_Max = 120; break;
766  case biExtremeHillsEdge: a_Min = 63; a_Max = 100; break;
767  case biExtremeHillsM: a_Min = 60; a_Max = 120; break;
768  case biExtremeHillsPlus: a_Min = 60; a_Max = 140; break;
769  case biExtremeHillsPlusM: a_Min = 60; a_Max = 140; break;
770  case biFlowerForest: a_Min = 63; a_Max = 75; break;
771  case biForest: a_Min = 63; a_Max = 75; break;
772  case biForestHills: a_Min = 63; a_Max = 90; break;
773  case biFrozenOcean: a_Min = 45; a_Max = 64; break;
774  case biFrozenRiver: a_Min = 60; a_Max = 62; break;
775  case biIceMountains: a_Min = 63; a_Max = 90; break;
776  case biIcePlains: a_Min = 63; a_Max = 70; break;
777  case biIcePlainsSpikes: a_Min = 60; a_Max = 70; break;
778  case biJungle: a_Min = 60; a_Max = 80; break;
779  case biJungleEdge: a_Min = 62; a_Max = 75; break;
780  case biJungleEdgeM: a_Min = 62; a_Max = 75; break;
781  case biJungleHills: a_Min = 60; a_Max = 90; break;
782  case biJungleM: a_Min = 60; a_Max = 75; break;
783  case biMegaSpruceTaiga: a_Min = 63; a_Max = 75; break;
784  case biMegaSpruceTaigaHills: a_Min = 63; a_Max = 90; break;
785  case biMegaTaiga: a_Min = 63; a_Max = 75; break;
786  case biMegaTaigaHills: a_Min = 63; a_Max = 90; break;
787  case biMesa: a_Min = 63; a_Max = 90; break;
788  case biMesaBryce: a_Min = 60; a_Max = 67; break;
789  case biMesaPlateau: a_Min = 75; a_Max = 85; break;
790  case biMesaPlateauF: a_Min = 80; a_Max = 90; break;
791  case biMesaPlateauFM: a_Min = 80; a_Max = 90; break;
792  case biMesaPlateauM: a_Min = 75; a_Max = 85; break;
793  case biMushroomIsland: a_Min = 63; a_Max = 90; break;
794  case biMushroomShore: a_Min = 60; a_Max = 75; break;
795  case biNether: a_Min = 10; a_Max = 100; break;
796  case biOcean: a_Min = 45; a_Max = 64; break;
797  case biPlains: a_Min = 63; a_Max = 70; break;
798  case biRiver: a_Min = 60; a_Max = 62; break;
799  case biRoofedForest: a_Min = 63; a_Max = 75; break;
800  case biRoofedForestM: a_Min = 63; a_Max = 75; break;
801  case biSavanna: a_Min = 63; a_Max = 75; break;
802  case biSavannaM: a_Min = 63; a_Max = 80; break;
803  case biSavannaPlateau: a_Min = 75; a_Max = 100; break;
804  case biSavannaPlateauM: a_Min = 80; a_Max = 160; break;
805  case biStoneBeach: a_Min = 60; a_Max = 64; break;
806  case biSunflowerPlains: a_Min = 63; a_Max = 70; break;
807  case biSwampland: a_Min = 60; a_Max = 67; break;
808  case biSwamplandM: a_Min = 61; a_Max = 67; break;
809  case biTaiga: a_Min = 63; a_Max = 75; break;
810  case biTaigaHills: a_Min = 63; a_Max = 90; break;
811  case biTaigaM: a_Min = 63; a_Max = 80; break;
812  case biInvalidBiome:
813  case biNumBiomes:
814  case biVariant:
815  case biNumVariantBiomes:
816  {
817  ASSERT(!"Unknown biome");
818  a_Min = 10;
819  a_Max = 10;
820  break;
821  }
822  }
823  }
824 };
825 
826 
827 
828 
829 
831 // cTerrainHeightGen:
832 
833 cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault)
834 {
835  AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", "");
836  if (HeightGenName.empty())
837  {
838  LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\".");
839  HeightGenName = "Biomal";
840  }
841 
842  a_CacheOffByDefault = false;
844  if (NoCaseCompare(HeightGenName, "Flat") == 0)
845  {
846  res = std::make_shared<cHeiGenFlat>();
847  a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
848  }
849  else if (NoCaseCompare(HeightGenName, "classic") == 0)
850  {
851  res = std::make_shared<cHeiGenClassic>(a_Seed);
852  }
853  else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
854  {
855  // Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
856  // Return an empty pointer, the caller will create the proper generator:
857  return cTerrainHeightGenPtr();
858  }
859  else if (NoCaseCompare(HeightGenName, "End") == 0)
860  {
861  // Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
862  // Return an empty pointer, the caller will create the proper generator:
863  return cTerrainHeightGenPtr();
864  }
865  else if (NoCaseCompare(HeightGenName, "MinMax") == 0)
866  {
867  res = std::make_shared<cHeiGenMinMax>(a_Seed, a_BiomeGen);
868  }
869  else if (NoCaseCompare(HeightGenName, "Mountains") == 0)
870  {
871  res = std::make_shared<cHeiGenMountains>(a_Seed);
872  }
873  else if (NoCaseCompare(HeightGenName, "BiomalNoise3D") == 0)
874  {
875  // Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
876  // Return an empty pointer, the caller will create the proper generator:
877  return cTerrainHeightGenPtr();
878  }
879  else if (NoCaseCompare(HeightGenName, "Steppy") == 0)
880  {
881  res = std::make_shared<cHeiGenSteppy>(a_Seed);
882  }
883  else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
884  {
885  // Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
886  // Return an empty pointer, the caller will create the proper generator:
887  return cTerrainHeightGenPtr();
888  }
889  else if (NoCaseCompare(HeightGenName, "Biomal") == 0)
890  {
891  res = std::make_shared<cHeiGenBiomal>(a_Seed, a_BiomeGen);
892 
893  /*
894  // Performance-testing:
895  LOGINFO("Measuring performance of cHeiGenBiomal...");
896  clock_t BeginTick = clock();
897  for (int x = 0; x < 500; x++)
898  {
899  cChunkDef::HeightMap Heights;
900  res->GenHeightMap(x * 5, x * 5, Heights);
901  }
902  clock_t Duration = clock() - BeginTick;
903  LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
904  //*/
905  }
906  else
907  {
908  // No match found, force-set the default and retry
909  LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
910  a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
911  return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
912  }
913 
914  // Read the settings:
915  res->InitializeHeightGen(a_IniFile);
916 
917  return res;
918 }
919 
920 
921 
922 
923 
std::vector< size_t > m_CacheOrder
Definition: HeiGen.h:58
static const size_t m_CoeffZ
The coefficient used to turn Z coords into index (x + Coeff * z).
Definition: HeiGen.h:91
virtual void InitializeHeightGen(cIniFile &a_IniFile) override
Initializes the generator, reading its parameters from the INI file.
Definition: HeiGen.cpp:552
virtual void InitializeHeightGen(cIniFile &a_IniFile) override
Initializes the generator, reading its parameters from the INI file.
Definition: HeiGen.cpp:97
float m_HeightAmp3
Definition: HeiGen.h:135
double GetValueSetF(const AString &keyname, const AString &valuename, const double defValue=0.0)
Definition: IniFile.cpp:547
cBiomeGenPtr m_BiomeGen
The biome generator to query for the underlying biomes.
Definition: HeiGen.cpp:737
cRidgedMultiNoise m_DitchNoise
Definition: HeiGen.h:158
cPerlinNoise m_Perlin
Definition: HeiGen.cpp:734
float m_HeightFreq3
Definition: HeiGen.h:135
std::shared_ptr< cTerrainHeightGen > cTerrainHeightGenPtr
size_t m_NumHits
Definition: HeiGen.h:62
#define LOGWARN
Definition: LoggerSimple.h:43
static const int Width
Definition: ChunkDef.h:134
The interface that is used to query terrain height from the shape generator.
size_t m_NumSubCaches
Number of sub-caches, pulled out of m_SubCaches.size() for performance reasons.
Definition: HeiGen.h:94
static HEIGHTTYPE GetHeight(const HeightMap &a_HeightMap, int a_X, int a_Z)
Definition: ChunkDef.h:351
Definition: BiomeDef.h:37
cHeiGenMultiCache(cTerrainHeightGenPtr a_HeightGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches)
Definition: HeiGen.cpp:222
cHeiGenCachePtrs m_SubCaches
The individual sub-caches.
Definition: HeiGen.h:97
EMCSBiome
Biome IDs The first batch corresponds to the clientside biomes, used by MineCraft.
Definition: BiomeDef.h:21
unsigned char HEIGHTTYPE
The type used by the heightmap.
Definition: ChunkDef.h:48
float GetNoise(float x, float y)
Definition: HeiGen.cpp:303
virtual void InitializeHeightGen(cIniFile &a_IniFile) override
Initializes the generator, reading its parameters from the INI file.
Definition: HeiGen.cpp:726
static const int Height
Definition: ChunkDef.h:135
size_t m_CacheSize
Definition: HeiGen.h:57
cNoise m_Noise
Definition: HeiGen.cpp:732
static void BlockToChunk(int a_X, int a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords to chunk coords:
Definition: ChunkDef.h:234
cChunkDef::BiomeMap BiomeNeighbors[3][3]
Definition: HeiGen.h:192
virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap &a_HeightMap) override
Retrieves the heightmap for the specified chunk.
Definition: HeiGen.cpp:660
virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap &a_HeightMap) override
Retrieves the heightmap for the specified chunk.
Definition: HeiGen.cpp:321
float m_HeightAmp2
Definition: HeiGen.h:134
bool SetValue(const int keyID, const int valueID, const AString &value)
Definition: IniFile.cpp:393
int NoCaseCompare(const AString &s1, const AString &s2)
Case-insensitive string comparison.
virtual HEIGHTTYPE GetHeightAt(int a_BlockX, int a_BlockZ) override
Returns the height at the specified column.
Definition: HeiGen.cpp:181
static const sGenParam m_GenParam[256]
Definition: HeiGen.h:205
double m_TotalWeight
Sum of all the m_Weights items.
Definition: HeiGen.cpp:743
static cTerrainHeightGenPtr CreateHeightGen(cIniFile &a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool &a_CacheOffByDefault)
Creates a cTerrainHeightGen descendant based on the INI file settings.
Definition: HeiGen.cpp:833
virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap &a_HeightMap) override
Retrieves the heightmap for the specified chunk.
Definition: HeiGen.cpp:237
cHeiGenMountains(int a_Seed)
Definition: HeiGen.cpp:357
float NOISE_DATATYPE
The datatype used by all the noise generators.
Definition: Noise.h:9
cPerlinNoise m_Perlin
Definition: HeiGen.h:159
std::vector< sCacheData > m_CacheData
Definition: HeiGen.h:59
#define ASSERT(x)
Definition: Globals.h:335
cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, size_t a_CacheSize)
Definition: HeiGen.cpp:109
virtual void InitializeHeightGen(cIniFile &a_IniFile) override
Initializes the generator, reading its parameters from the INI file.
Definition: HeiGen.cpp:340
std::shared_ptr< cProtIntGen > m_Gen
Definition: HeiGen.cpp:74
float m_HeightFreq1
Definition: HeiGen.h:133
int m_ChunkZ
Definition: ChunkDef.h:60
#define UNUSED
Definition: Globals.h:152
Definition: Noise.h:19
virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap &a_HeightMap) override
Retrieves the heightmap for the specified chunk.
Definition: HeiGen.cpp:369
cNoise m_Noise
Definition: HeiGen.h:132
T Clamp(T a_Value, T a_Min, T a_Max)
Clamp X to the specified range.
Definition: Globals.h:351
virtual HEIGHTTYPE GetHeightAt(int a_BlockX, int a_BlockZ) override
Returns the height at the specified column.
Definition: HeiGen.h:184
cTerrainHeightGenPtr m_HeiGenToCache
The terrain height generator that is being cached.
Definition: HeiGen.h:54
cRidgedMultiNoise m_MountainNoise
Definition: HeiGen.h:157
static void SetHeight(HeightMap &a_HeightMap, int a_X, int a_Z, HEIGHTTYPE a_Height)
Definition: ChunkDef.h:359
int m_ChunkX
Definition: ChunkDef.h:59
void getBiomeMinMax(EMCSBiome a_Biome, double &a_Min, double &a_Max)
Returns the minimum and maximum heights for the given biome.
Definition: HeiGen.cpp:747
std::string AString
Definition: StringUtils.h:13
virtual void InitializeHeightGen(cIniFile &a_IniFile) override
Initializes the generator, reading its parameters from the INI file.
Definition: HeiGen.cpp:398
cHeiGenClassic(int a_Seed)
Definition: HeiGen.cpp:287
size_t m_NumMisses
Definition: HeiGen.h:63
void AddOctave(NOISE_DATATYPE a_Frequency, NOISE_DATATYPE a_Amplitude)
Adds a new octave to the list of octaves that compose this noise.
Definition: OctavedNoise.h:38
virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap &a_HeightMap) override
Retrieves the heightmap for the specified chunk.
Definition: HeiGen.cpp:512
int GetValueSetI(const AString &keyname, const AString &valuename, const int defValue=0) override
Definition: IniFile.cpp:558
cHeiGenMinMax(int a_Seed, cBiomeGenPtr a_BiomeGen)
Definition: HeiGen.cpp:638
cHeiGenSteppy(int a_Seed)
Definition: HeiGen.cpp:26
float m_HeightFreq2
Definition: HeiGen.h:134
void Generate2D(NOISE_DATATYPE *a_Array, int a_SizeX, int a_SizeY, NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, NOISE_DATATYPE *a_Workspace=nullptr) const
Fills a 2D array with the values of the noise.
Definition: OctavedNoise.h:45
virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap &a_HeightMap) override
Retrieves the heightmap for the specified chunk.
Definition: HeiGen.cpp:58
cTerrainHeightGen Super
Definition: HeiGen.cpp:632
virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap &a_HeightMap) override
Retrieves the heightmap for the specified chunk.
Definition: HeiGen.cpp:84
float m_HeightAmp1
Definition: HeiGen.h:133
HEIGHTTYPE HeightMap[Width *Width]
The type used for any heightmap operations and storage; idx = x + Width * z; Height points to the hig...
Definition: ChunkDef.h:142
NOISE_DATATYPE CubicNoise2D(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y) const
Definition: Noise.cpp:593
EMCSBiome BiomeMap[Width *Width]
The type used for any biomemap operations and storage inside Cuberite, using Cuberite biomes (need no...
Definition: ChunkDef.h:147
virtual HEIGHTTYPE GetHeightAt(int a_BlockX, int a_BlockZ) override
Returns the height at the specified column.
Definition: HeiGen.cpp:250
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:290
virtual HEIGHTTYPE GetHeightAt(int a_BlockX, int a_BlockZ)
Returns the height at the specified column.
virtual void GenHeightMap(cChunkCoords a_ChunkCoords, cChunkDef::HeightMap &a_HeightMap) override
Retrieves the heightmap for the specified chunk.
Definition: HeiGen.cpp:128
size_t m_TotalChain
Definition: HeiGen.h:64
static EMCSBiome GetBiome(const BiomeMap &a_BiomeMap, int a_X, int a_Z)
Definition: ChunkDef.h:367
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:524
std::shared_ptr< cBiomeGen > cBiomeGenPtr