summaryrefslogtreecommitdiffstats
path: root/src/Generating
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Generating/BioGen.cpp373
-rw-r--r--src/Generating/BioGen.h41
-rw-r--r--src/Generating/CMakeLists.txt4
-rw-r--r--src/Generating/ChunkDesc.cpp16
-rw-r--r--src/Generating/ChunkDesc.h2
-rw-r--r--src/Generating/ChunkGenerator.cpp20
-rw-r--r--src/Generating/CompoGen.cpp12
-rw-r--r--src/Generating/CompoGen.h6
-rw-r--r--src/Generating/ComposableGenerator.cpp164
-rw-r--r--src/Generating/ComposableGenerator.h33
-rw-r--r--src/Generating/DistortedHeightmap.cpp45
-rw-r--r--src/Generating/DistortedHeightmap.h13
-rw-r--r--src/Generating/DungeonRoomsFinisher.cpp34
-rw-r--r--src/Generating/DungeonRoomsFinisher.h4
-rw-r--r--src/Generating/EndGen.cpp2
-rw-r--r--src/Generating/FinishGen.cpp17
-rw-r--r--src/Generating/GridStructGen.cpp2
-rw-r--r--src/Generating/HeiGen.cpp422
-rw-r--r--src/Generating/HeiGen.h13
-rw-r--r--src/Generating/IntGen.h1406
-rw-r--r--src/Generating/MineShafts.cpp18
-rw-r--r--src/Generating/Noise3DGenerator.cpp523
-rw-r--r--src/Generating/Noise3DGenerator.h134
-rw-r--r--src/Generating/PieceGenerator.cpp4
-rw-r--r--src/Generating/Prefab.cpp6
-rw-r--r--src/Generating/PrefabPiecePool.cpp6
-rw-r--r--src/Generating/Prefabs/CMakeLists.txt2
-rw-r--r--src/Generating/ProtIntGen.h1351
-rw-r--r--src/Generating/StructGen.cpp8
-rw-r--r--src/Generating/StructGen.h40
-rw-r--r--src/Generating/Trees.cpp80
-rw-r--r--src/Generating/UnderwaterBaseGen.cpp4
-rw-r--r--src/Generating/UnderwaterBaseGen.h4
-rw-r--r--src/Generating/VillageGen.cpp16
-rw-r--r--src/Generating/VillageGen.h6
35 files changed, 4322 insertions, 509 deletions
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp
index 3ee0bd4c5..2a4dbe794 100644
--- a/src/Generating/BioGen.cpp
+++ b/src/Generating/BioGen.cpp
@@ -5,7 +5,11 @@
#include "Globals.h"
#include "BioGen.h"
-#include "inifile/iniFile.h"
+#include <chrono>
+#include <iostream>
+#include "IntGen.h"
+#include "ProtIntGen.h"
+#include "../IniFile.h"
#include "../LinearUpscale.h"
@@ -45,7 +49,7 @@ void cBioGenConstant::InitializeBiomeGen(cIniFile & a_IniFile)
////////////////////////////////////////////////////////////////////////////////
// cBioGenCache:
-cBioGenCache::cBioGenCache(cBiomeGen * a_BioGenToCache, int a_CacheSize) :
+cBioGenCache::cBioGenCache(cBiomeGenPtr a_BioGenToCache, int a_CacheSize) :
m_BioGenToCache(a_BioGenToCache),
m_CacheSize(a_CacheSize),
m_CacheOrder(new int[a_CacheSize]),
@@ -69,9 +73,9 @@ cBioGenCache::cBioGenCache(cBiomeGen * a_BioGenToCache, int a_CacheSize) :
cBioGenCache::~cBioGenCache()
{
delete[] m_CacheData;
- m_CacheData = NULL;
+ m_CacheData = nullptr;
delete[] m_CacheOrder;
- m_CacheOrder = NULL;
+ m_CacheOrder = nullptr;
}
@@ -145,25 +149,13 @@ void cBioGenCache::InitializeBiomeGen(cIniFile & a_IniFile)
////////////////////////////////////////////////////////////////////////////////
// cBioGenMulticache:
-cBioGenMulticache::cBioGenMulticache(cBiomeGen * a_BioGenToCache, size_t a_CacheSize, size_t a_CachesLength) :
- m_CachesLength(a_CachesLength)
+cBioGenMulticache::cBioGenMulticache(cBiomeGenPtr a_BioGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches) :
+ m_NumSubCaches(a_NumSubCaches)
{
- m_Caches.reserve(a_CachesLength);
- for (size_t i = 0; i < a_CachesLength; i++)
+ m_Caches.reserve(a_NumSubCaches);
+ for (size_t i = 0; i < a_NumSubCaches; i++)
{
- m_Caches.push_back(new cBioGenCache(a_BioGenToCache, a_CacheSize));
- }
-}
-
-
-
-
-
-cBioGenMulticache::~cBioGenMulticache()
-{
- for (cBiomeGens::iterator it = m_Caches.begin(); it != m_Caches.end(); it++)
- {
- delete *it;
+ m_Caches.push_back(cBiomeGenPtr(new cBioGenCache(a_BioGenToCache, a_SubCacheSize)));
}
}
@@ -174,7 +166,7 @@ cBioGenMulticache::~cBioGenMulticache()
void cBioGenMulticache::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
{
const size_t coefficient = 3;
- const size_t cacheIdx = ((size_t)a_ChunkX + coefficient * (size_t)a_ChunkZ) % m_CachesLength;
+ const size_t cacheIdx = ((size_t)a_ChunkX + coefficient * (size_t)a_ChunkZ) % m_NumSubCaches;
m_Caches[cacheIdx]->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap);
}
@@ -185,10 +177,9 @@ void cBioGenMulticache::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMa
void cBioGenMulticache::InitializeBiomeGen(cIniFile & a_IniFile)
{
- for (cBiomeGens::iterator it = m_Caches.begin(); it != m_Caches.end(); it++)
+ for (auto itr : m_Caches)
{
- cBiomeGen * tmp = *it;
- tmp->InitializeBiomeGen(a_IniFile);
+ itr->InitializeBiomeGen(a_IniFile);
}
}
@@ -737,8 +728,6 @@ void cBioGenMultiStepMap::FreezeWaterBiomes(cChunkDef::BiomeMap & a_BiomeMap, co
cBioGenTwoLevel::cBioGenTwoLevel(int a_Seed) :
m_VoronoiLarge(a_Seed + 1000),
m_VoronoiSmall(a_Seed + 2000),
- m_DistortX(a_Seed + 3000),
- m_DistortZ(a_Seed + 4000),
m_Noise1(a_Seed + 5001),
m_Noise2(a_Seed + 5002),
m_Noise3(a_Seed + 5003),
@@ -762,19 +751,17 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap
int DistortZ[cChunkDef::Width + 1][cChunkDef::Width + 1];
for (int x = 0; x <= 4; x++) for (int z = 0; z <= 4; z++)
{
- int BlockX = BaseX + x * 4;
- int BlockZ = BaseZ + z * 4;
- float BlockXF = (float)(16 * BlockX) / 128;
- float BlockZF = (float)(16 * BlockZ) / 128;
- double NoiseX = m_Noise1.CubicNoise2D(BlockXF / 16, BlockZF / 16);
- NoiseX += 0.5 * m_Noise2.CubicNoise2D(BlockXF / 8, BlockZF / 8);
- NoiseX += 0.08 * m_Noise3.CubicNoise2D(BlockXF, BlockZF);
- double NoiseZ = m_Noise4.CubicNoise2D(BlockXF / 16, BlockZF / 16);
- NoiseZ += 0.5 * m_Noise5.CubicNoise2D(BlockXF / 8, BlockZF / 8);
- NoiseZ += 0.08 * m_Noise6.CubicNoise2D(BlockXF, BlockZF);
+ float BlockX = static_cast<float>(BaseX + x * 4);
+ float BlockZ = static_cast<float>(BaseZ + z * 4);
+ double NoiseX = m_AmpX1 * m_Noise1.CubicNoise2D(BlockX * m_FreqX1, BlockZ * m_FreqX1);
+ NoiseX += m_AmpX2 * m_Noise2.CubicNoise2D(BlockX * m_FreqX2, BlockZ * m_FreqX2);
+ NoiseX += m_AmpX3 * m_Noise3.CubicNoise2D(BlockX * m_FreqX3, BlockZ * m_FreqX3);
+ double NoiseZ = m_AmpZ1 * m_Noise4.CubicNoise2D(BlockX * m_FreqZ1, BlockZ * m_FreqZ1);
+ NoiseZ += m_AmpZ2 * m_Noise5.CubicNoise2D(BlockX * m_FreqZ2, BlockZ * m_FreqZ2);
+ NoiseZ += m_AmpZ3 * m_Noise6.CubicNoise2D(BlockX * m_FreqZ3, BlockZ * m_FreqZ3);
- DistortX[4 * x][4 * z] = BlockX + (int)(64 * NoiseX);
- DistortZ[4 * x][4 * z] = BlockZ + (int)(64 * NoiseZ);
+ DistortX[4 * x][4 * z] = (int)(BlockX + NoiseX);
+ DistortZ[4 * x][4 * z] = (int)(BlockZ + NoiseZ);
}
LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
@@ -789,7 +776,7 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap
int BiomeGroup = m_VoronoiLarge.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 7;
int BiomeIdx = m_VoronoiSmall.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 11;
int MinDist1 = (DistortX[x][z] - SeedX) * (DistortX[x][z] - SeedX) + (DistortZ[x][z] - SeedZ) * (DistortZ[x][z] - SeedZ);
- cChunkDef::SetBiome(a_BiomeMap, x, z, SelectBiome(BiomeGroup, BiomeIdx, (MinDist1 < MinDist2 / 4) ? 0 : 1));
+ cChunkDef::SetBiome(a_BiomeMap, x, z, SelectBiome(BiomeGroup, BiomeIdx, (MinDist1 < MinDist2 / 4) ? 1 : 0));
}
}
}
@@ -915,30 +902,18 @@ void cBioGenTwoLevel::InitializeBiomeGen(cIniFile & a_IniFile)
{
m_VoronoiLarge.SetCellSize(a_IniFile.GetValueSetI("Generator", "TwoLevelLargeCellSize", 1024));
m_VoronoiSmall.SetCellSize(a_IniFile.GetValueSetI("Generator", "TwoLevelSmallCellSize", 128));
- m_DistortX.AddOctave(
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Freq", 0.01),
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Amp", 16)
- );
- m_DistortX.AddOctave(
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Freq", 0.005),
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Amp", 8)
- );
- m_DistortX.AddOctave(
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Freq", 0.0025),
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Amp", 4)
- );
- m_DistortZ.AddOctave(
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Freq", 0.01),
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Amp", 16)
- );
- m_DistortZ.AddOctave(
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Freq", 0.005),
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Amp", 8)
- );
- m_DistortZ.AddOctave(
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Freq", 0.0025),
- (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Amp", 4)
- );
+ m_FreqX1 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Freq", 0.01);
+ m_AmpX1 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Amp", 80);
+ m_FreqX2 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Freq", 0.05);
+ m_AmpX2 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Amp", 20);
+ m_FreqX3 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Freq", 0.1),
+ m_AmpX3 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Amp", 8);
+ m_FreqZ1 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Freq", 0.01);
+ m_AmpZ1 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Amp", 80);
+ m_FreqZ2 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Freq", 0.05);
+ m_AmpZ2 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Amp", 20);
+ m_FreqZ3 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Freq", 0.1);
+ m_AmpZ3 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Amp", 8);
}
@@ -946,9 +921,217 @@ void cBioGenTwoLevel::InitializeBiomeGen(cIniFile & a_IniFile)
////////////////////////////////////////////////////////////////////////////////
+// cBioGenGrown:
+
+class cBioGenGrown:
+ public cBiomeGen
+{
+public:
+ cBioGenGrown(int a_Seed)
+ {
+ auto FinalRivers =
+ std::make_shared<cIntGenSmooth<8>> (a_Seed + 1,
+ std::make_shared<cIntGenZoom <10>> (a_Seed + 2,
+ std::make_shared<cIntGenRiver <7>> (a_Seed + 3,
+ std::make_shared<cIntGenZoom <9>> (a_Seed + 4,
+ std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
+ std::make_shared<cIntGenZoom <8>> (a_Seed + 8,
+ std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
+ std::make_shared<cIntGenZoom <8>> (a_Seed + 9,
+ std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
+ std::make_shared<cIntGenZoom <8>> (a_Seed + 10,
+ std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
+ std::make_shared<cIntGenSmooth<8>> (a_Seed + 6,
+ std::make_shared<cIntGenZoom <10>> (a_Seed + 11,
+ std::make_shared<cIntGenChoice<2, 7>>(a_Seed + 12
+ ))))))))))))));
+
+ auto alteration =
+ std::make_shared<cIntGenZoom <8>>(a_Seed,
+ std::make_shared<cIntGenLandOcean<6>>(a_Seed, 20
+ ));
+
+ auto alteration2 =
+ std::make_shared<cIntGenZoom <8>>(a_Seed + 1,
+ std::make_shared<cIntGenZoom <6>>(a_Seed + 2,
+ std::make_shared<cIntGenZoom <5>>(a_Seed + 1,
+ std::make_shared<cIntGenZoom <4>>(a_Seed + 2,
+ std::make_shared<cIntGenLandOcean<4>>(a_Seed + 1, 10
+ )))));
+
+ auto FinalBiomes =
+ std::make_shared<cIntGenSmooth <8>> (a_Seed + 1,
+ std::make_shared<cIntGenZoom <10>>(a_Seed + 15,
+ std::make_shared<cIntGenSmooth <7>> (a_Seed + 1,
+ std::make_shared<cIntGenZoom <9>> (a_Seed + 16,
+ std::make_shared<cIntGenBeaches <6>> (
+ std::make_shared<cIntGenZoom <8>> (a_Seed + 1,
+ std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2004, 10,
+ std::make_shared<cIntGenAddToOcean <6>> (a_Seed + 10, 500, biDeepOcean,
+ std::make_shared<cIntGenReplaceRandomly<8>> (a_Seed + 1, biPlains, biSunflowerPlains, 20,
+ std::make_shared<cIntGenMBiomes <8>> (a_Seed + 5, alteration2,
+ std::make_shared<cIntGenAlternateBiomes<8>> (a_Seed + 1, alteration,
+ std::make_shared<cIntGenBiomeEdges <8>> (a_Seed + 3,
+ std::make_shared<cIntGenZoom <10>>(a_Seed + 2,
+ std::make_shared<cIntGenZoom <7>> (a_Seed + 4,
+ std::make_shared<cIntGenReplaceRandomly<5>> (a_Seed + 99, biIcePlains, biIcePlainsSpikes, 50,
+ std::make_shared<cIntGenZoom <5>> (a_Seed + 8,
+ std::make_shared<cIntGenAddToOcean <4>> (a_Seed + 10, 300, biDeepOcean,
+ std::make_shared<cIntGenAddToOcean <6>> (a_Seed + 9, 8, biMushroomIsland,
+ std::make_shared<cIntGenBiomes <8>> (a_Seed + 3000,
+ std::make_shared<cIntGenAddIslands <8>> (a_Seed + 2000, 200,
+ std::make_shared<cIntGenZoom <8>> (a_Seed + 5,
+ std::make_shared<cIntGenRareBiomeGroups<6>> (a_Seed + 5, 50,
+ std::make_shared<cIntGenBiomeGroupEdges<6>> (
+ std::make_shared<cIntGenAddIslands <8>> (a_Seed + 2000, 200,
+ std::make_shared<cIntGenZoom <8>> (a_Seed + 7,
+ std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 8, 50, bgOcean,
+ std::make_shared<cIntGenReplaceRandomly<6>> (a_Seed + 101, bgIce, bgTemperate, 150,
+ std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2000, 200,
+ std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 9, 50, bgOcean,
+ std::make_shared<cIntGenZoom <6>> (a_Seed + 10,
+ std::make_shared<cIntGenLandOcean <5>> (a_Seed + 100, 30
+ )))))))))))))))))))))))))))))));
+
+ m_Gen =
+ std::make_shared<cIntGenSmooth <16>>(a_Seed,
+ std::make_shared<cIntGenZoom <18>>(a_Seed,
+ std::make_shared<cIntGenSmooth <11>>(a_Seed,
+ std::make_shared<cIntGenZoom <13>>(a_Seed,
+ std::make_shared<cIntGenMixRivers<8>> (
+ FinalBiomes, FinalRivers
+ )))));
+ }
+
+ virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override
+ {
+ cIntGen<16, 16>::Values vals;
+ m_Gen->GetInts(a_ChunkX * cChunkDef::Width, a_ChunkZ * cChunkDef::Width, vals);
+ for (int z = 0; z < cChunkDef::Width; z++)
+ {
+ for (int x = 0; x < cChunkDef::Width; x++)
+ {
+ cChunkDef::SetBiome(a_Biomes, x, z, (EMCSBiome)vals[x + cChunkDef::Width * z]);
+ }
+ }
+ }
+
+protected:
+ std::shared_ptr<cIntGen<16, 16>> m_Gen;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cBioGenGrown:
+
+class cBioGenProtGrown:
+ public cBiomeGen
+{
+public:
+ cBioGenProtGrown(int a_Seed)
+ {
+ auto FinalRivers =
+ std::make_shared<cProtIntGenSmooth>(a_Seed + 1,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 2,
+ std::make_shared<cProtIntGenRiver >(a_Seed + 3,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 4,
+ std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 8,
+ std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 9,
+ std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 10,
+ std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
+ std::make_shared<cProtIntGenSmooth>(a_Seed + 6,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 11,
+ std::make_shared<cProtIntGenChoice>(a_Seed + 12, 2
+ ))))))))))))));
+
+ auto alteration =
+ std::make_shared<cProtIntGenZoom >(a_Seed,
+ std::make_shared<cProtIntGenLandOcean>(a_Seed, 20
+ ));
+
+ auto alteration2 =
+ std::make_shared<cProtIntGenZoom >(a_Seed + 1,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 2,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 1,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 2,
+ std::make_shared<cProtIntGenLandOcean>(a_Seed + 1, 10
+ )))));
+
+ auto FinalBiomes =
+ std::make_shared<cProtIntGenSmooth >(a_Seed + 1,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 15,
+ std::make_shared<cProtIntGenSmooth >(a_Seed + 1,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 16,
+ std::make_shared<cProtIntGenBeaches >(
+ std::make_shared<cProtIntGenZoom >(a_Seed + 1,
+ std::make_shared<cProtIntGenAddIslands >(a_Seed + 2004, 10,
+ std::make_shared<cProtIntGenAddToOcean >(a_Seed + 10, 500, biDeepOcean,
+ std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 1, biPlains, biSunflowerPlains, 20,
+ std::make_shared<cProtIntGenMBiomes >(a_Seed + 5, alteration2,
+ std::make_shared<cProtIntGenAlternateBiomes>(a_Seed + 1, alteration,
+ std::make_shared<cProtIntGenBiomeEdges >(a_Seed + 3,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 2,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 4,
+ std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 99, biIcePlains, biIcePlainsSpikes, 50,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 8,
+ std::make_shared<cProtIntGenAddToOcean >(a_Seed + 10, 300, biDeepOcean,
+ std::make_shared<cProtIntGenAddToOcean >(a_Seed + 9, 8, biMushroomIsland,
+ std::make_shared<cProtIntGenBiomes >(a_Seed + 3000,
+ std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 5,
+ std::make_shared<cProtIntGenRareBiomeGroups>(a_Seed + 5, 50,
+ std::make_shared<cProtIntGenBiomeGroupEdges>(
+ std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 7,
+ std::make_shared<cProtIntGenSetRandomly >(a_Seed + 8, 50, bgOcean,
+ std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 101, bgIce, bgTemperate, 150,
+ std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200,
+ std::make_shared<cProtIntGenSetRandomly >(a_Seed + 9, 50, bgOcean,
+ std::make_shared<cProtIntGenZoom >(a_Seed + 10,
+ std::make_shared<cProtIntGenLandOcean >(a_Seed + 100, 30
+ )))))))))))))))))))))))))))))));
+
+ m_Gen =
+ std::make_shared<cProtIntGenSmooth >(a_Seed,
+ std::make_shared<cProtIntGenZoom >(a_Seed,
+ std::make_shared<cProtIntGenSmooth >(a_Seed,
+ std::make_shared<cProtIntGenZoom >(a_Seed,
+ std::make_shared<cProtIntGenMixRivers>(
+ FinalBiomes, FinalRivers
+ )))));
+ }
+
+ virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override
+ {
+ int vals[16 * 16];
+ m_Gen->GetInts(a_ChunkX * cChunkDef::Width, a_ChunkZ * cChunkDef::Width, 16, 16, vals);
+ for (int z = 0; z < cChunkDef::Width; z++)
+ {
+ for (int x = 0; x < cChunkDef::Width; x++)
+ {
+ cChunkDef::SetBiome(a_Biomes, x, z, (EMCSBiome)vals[x + cChunkDef::Width * z]);
+ }
+ }
+ }
+
+protected:
+ std::shared_ptr<cProtIntGen> m_Gen;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
// cBiomeGen:
-cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault)
+cBiomeGenPtr cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault)
{
AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", "");
if (BiomeGenName.empty())
@@ -957,7 +1140,7 @@ cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a
BiomeGenName = "MultiStepMap";
}
- cBiomeGen * res = NULL;
+ cBiomeGen * res = nullptr;
a_CacheOffByDefault = false;
if (NoCaseCompare(BiomeGenName, "constant") == 0)
{
@@ -981,6 +1164,14 @@ cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a
{
res = new cBioGenTwoLevel(a_Seed);
}
+ else if (NoCaseCompare(BiomeGenName, "grown") == 0)
+ {
+ res = new cBioGenGrown(a_Seed);
+ }
+ else if (NoCaseCompare(BiomeGenName, "grownprot") == 0)
+ {
+ res = new cBioGenProtGrown(a_Seed);
+ }
else
{
if (NoCaseCompare(BiomeGenName, "multistepmap") != 0)
@@ -1004,9 +1195,57 @@ cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a
}
res->InitializeBiomeGen(a_IniFile);
- return res;
+ return cBiomeGenPtr(res);
}
+
+////////////////////////////////////////////////////////////////////////////////
+// Performance tests:
+
+// Change to 1 to enable the perf test:
+#if 0
+
+class cBioGenPerfTest
+{
+public:
+ cBioGenPerfTest()
+ {
+ std::cout << "BioGen performance tests commencing, please wait..." << std::endl;
+ TestGen("MultiStepMap", std::make_unique<cBioGenMultiStepMap>(1).get());
+ TestGen("Grown", std::make_unique<cBioGenGrown>(1).get());
+ TestGen("GrownProt", std::make_unique<cBioGenProtGrown>(1).get());
+ std::cout << "BioGen performance tests complete." << std::endl;
+ }
+
+protected:
+ void TestGen(const AString && a_GenName, cBiomeGen * a_BioGen)
+ {
+ // Initialize the default settings for the generator:
+ cIniFile iniFile;
+ a_BioGen->InitializeBiomeGen(iniFile);
+
+ // Generate the biomes:
+ auto start = std::chrono::system_clock::now();
+ for (int z = 0; z < 100; z++)
+ {
+ for (int x = 0; x < 100; x++)
+ {
+ cChunkDef::BiomeMap biomes;
+ a_BioGen->GenBiomes(x, z, biomes);
+ } // for x
+ } // for z
+ auto dur = std::chrono::system_clock::now() - start;
+ double milliseconds = static_cast<double>((std::chrono::duration_cast<std::chrono::milliseconds>(dur)).count());
+
+ std::cout << a_GenName << ": " << 1000.0 * 100.0 * 100.0 / milliseconds << " chunks per second" << std::endl;
+ }
+} g_BioGenPerfTest;
+
+#endif
+
+
+
+
diff --git a/src/Generating/BioGen.h b/src/Generating/BioGen.h
index 20d199611..5fd0844d9 100644
--- a/src/Generating/BioGen.h
+++ b/src/Generating/BioGen.h
@@ -48,12 +48,12 @@ class cBioGenCache :
typedef cBiomeGen super;
public:
- cBioGenCache(cBiomeGen * a_BioGenToCache, int a_CacheSize); // Doesn't take ownership of a_BioGenToCache
- ~cBioGenCache();
+ cBioGenCache(cBiomeGenPtr a_BioGenToCache, int a_CacheSize);
+ virtual ~cBioGenCache();
protected:
- cBiomeGen * m_BioGenToCache;
+ cBiomeGenPtr m_BioGenToCache;
struct sCacheData
{
@@ -87,19 +87,21 @@ class cBioGenMulticache :
typedef cBiomeGen super;
public:
- /*
- a_CacheSize defines the size of each singular cache
- a_CachesLength defines how many caches are used for the multicache
- */
- cBioGenMulticache(cBiomeGen * a_BioGenToCache, size_t a_CacheSize, size_t a_CachesLength); // Doesn't take ownership of a_BioGenToCache
- ~cBioGenMulticache();
+ /* Creates a new multicache - a cache that divides the caching into several sub-caches based on the chunk coords.
+ This allows us to use shorter cache depths with faster lookups for more covered area. (#381)
+ a_SubCacheSize defines the size of each sub-cache
+ a_NumSubCaches defines how many sub-caches are used for the multicache. */
+ cBioGenMulticache(cBiomeGenPtr a_BioGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches);
protected:
- typedef std::vector<cBiomeGen *> cBiomeGens;
+ typedef std::vector<cBiomeGenPtr> cBiomeGenPtrs;
+
+ /** Number of sub-caches. Pulled out of m_Caches.size() for faster access. */
+ size_t m_NumSubCaches;
- size_t m_CachesLength;
- cBiomeGens m_Caches;
+ /** Individual sub-caches. */
+ cBiomeGenPtrs m_Caches;
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
@@ -285,12 +287,7 @@ protected:
/// The Voronoi map that decides biomes inside individual biome groups
cVoronoiMap m_VoronoiSmall;
- /// The noise used to distort the input X coord
- cPerlinNoise m_DistortX;
-
- /// The noise used to distort the inupt Z coord
- cPerlinNoise m_DistortZ;
-
+ // The noises used for the distortion:
cNoise m_Noise1;
cNoise m_Noise2;
cNoise m_Noise3;
@@ -298,6 +295,14 @@ protected:
cNoise m_Noise5;
cNoise m_Noise6;
+ // Frequencies and amplitudes for the distortion noises:
+ float m_FreqX1, m_AmpX1;
+ float m_FreqX2, m_AmpX2;
+ float m_FreqX3, m_AmpX3;
+ float m_FreqZ1, m_AmpZ1;
+ float m_FreqZ2, m_AmpZ2;
+ float m_FreqZ3, m_AmpZ3;
+
// cBiomeGen overrides:
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt
index 33d622b42..1a26bd0d5 100644
--- a/src/Generating/CMakeLists.txt
+++ b/src/Generating/CMakeLists.txt
@@ -46,6 +46,7 @@ SET (HDRS
FinishGen.h
GridStructGen.h
HeiGen.h
+ IntGen.h
MineShafts.h
NetherFortGen.h
Noise3DGenerator.h
@@ -53,6 +54,7 @@ SET (HDRS
PieceGenerator.h
Prefab.h
PrefabPiecePool.h
+ ProtIntGen.h
RainbowRoadsGen.h
Ravines.h
RoughRavines.h
@@ -65,5 +67,5 @@ SET (HDRS
if(NOT MSVC)
add_library(Generating ${SRCS} ${HDRS})
- target_link_libraries(Generating OSSupport iniFile Blocks)
+ target_link_libraries(Generating OSSupport Blocks)
endif()
diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp
index c0b646fd0..020d3bd0f 100644
--- a/src/Generating/ChunkDesc.cpp
+++ b/src/Generating/ChunkDesc.cpp
@@ -269,10 +269,10 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
LOGWARNING("%s: MaxRelX less than zero, adjusting to zero", __FUNCTION__);
a_MaxRelX = 0;
}
- else if (a_MaxRelX >= cChunkDef::Width)
+ else if (a_MaxRelX > cChunkDef::Width)
{
LOGWARNING("%s: MaxRelX more than chunk width, adjusting to chunk width", __FUNCTION__);
- a_MaxRelX = cChunkDef::Width - 1;
+ a_MaxRelX = cChunkDef::Width;
}
if (a_MinRelY < 0)
@@ -290,10 +290,10 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
LOGWARNING("%s: MaxRelY less than zero, adjusting to zero", __FUNCTION__);
a_MaxRelY = 0;
}
- else if (a_MaxRelY >= cChunkDef::Height)
+ else if (a_MaxRelY > cChunkDef::Height)
{
LOGWARNING("%s: MaxRelY more than chunk height, adjusting to chunk height", __FUNCTION__);
- a_MaxRelY = cChunkDef::Height - 1;
+ a_MaxRelY = cChunkDef::Height;
}
if (a_MinRelZ < 0)
@@ -311,10 +311,10 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
LOGWARNING("%s: MaxRelZ less than zero, adjusting to zero", __FUNCTION__);
a_MaxRelZ = 0;
}
- else if (a_MaxRelZ >= cChunkDef::Width)
+ else if (a_MaxRelZ > cChunkDef::Width)
{
LOGWARNING("%s: MaxRelZ more than chunk width, adjusting to chunk width", __FUNCTION__);
- a_MaxRelZ = cChunkDef::Width - 1;
+ a_MaxRelZ = cChunkDef::Width;
}
// Prepare the block area:
@@ -530,10 +530,10 @@ cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ)
// The block entity is not created yet, try to create it and add to list:
cBlockEntity * be = cBlockEntity::CreateByBlockType(GetBlockType(a_RelX, a_RelY, a_RelZ), GetBlockMeta(a_RelX, a_RelY, a_RelZ), AbsX, a_RelY, AbsZ);
- if (be == NULL)
+ if (be == nullptr)
{
// No block entity for this block type
- return NULL;
+ return nullptr;
}
m_BlockEntities.push_back(be);
return be;
diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h
index eeea0c957..570132790 100644
--- a/src/Generating/ChunkDesc.h
+++ b/src/Generating/ChunkDesc.h
@@ -172,7 +172,7 @@ public:
/** Returns the block entity at the specified coords.
If there is no block entity at those coords, tries to create one, based on the block type
- If the blocktype doesn't support a block entity, returns NULL. */
+ If the blocktype doesn't support a block entity, returns nullptr. */
cBlockEntity * GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ);
/** Updates the heightmap to match the current contents.
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index d615456c1..92e1bb31d 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -2,7 +2,7 @@
#include "Globals.h"
#include "ChunkGenerator.h"
-#include "inifile/iniFile.h"
+#include "../IniFile.h"
#include "ChunkDesc.h"
#include "ComposableGenerator.h"
#include "Noise3DGenerator.h"
@@ -28,9 +28,9 @@ const unsigned int QUEUE_SKIP_LIMIT = 500;
cChunkGenerator::cChunkGenerator(void) :
super("cChunkGenerator"),
m_Seed(0), // Will be overwritten by the actual generator
- m_Generator(NULL),
- m_PluginInterface(NULL),
- m_ChunkSink(NULL)
+ m_Generator(nullptr),
+ m_PluginInterface(nullptr),
+ m_ChunkSink(nullptr)
{
}
@@ -80,7 +80,7 @@ bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a
m_Generator = new cComposableGenerator(*this);
}
- if (m_Generator == NULL)
+ if (m_Generator == nullptr)
{
LOGERROR("Generator could not start, aborting the server");
return false;
@@ -103,7 +103,7 @@ void cChunkGenerator::Stop(void)
Wait();
delete m_Generator;
- m_Generator = NULL;
+ m_Generator = nullptr;
}
@@ -144,7 +144,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_Forc
void cChunkGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
{
- if (m_Generator != NULL)
+ if (m_Generator != nullptr)
{
m_Generator->GenerateBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap);
}
@@ -180,7 +180,7 @@ int cChunkGenerator::GetQueueLength(void)
EMCSBiome cChunkGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ)
{
- ASSERT(m_Generator != NULL);
+ ASSERT(m_Generator != nullptr);
return m_Generator->GetBiomeAt(a_BlockX, a_BlockZ);
}
@@ -283,8 +283,8 @@ void cChunkGenerator::Execute(void)
void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ)
{
- ASSERT(m_PluginInterface != NULL);
- ASSERT(m_ChunkSink != NULL);
+ ASSERT(m_PluginInterface != nullptr);
+ ASSERT(m_ChunkSink != nullptr);
ASSERT(m_ChunkSink->IsChunkQueued(a_ChunkX, a_ChunkZ));
cChunkDesc ChunkDesc(a_ChunkX, a_ChunkZ);
diff --git a/src/Generating/CompoGen.cpp b/src/Generating/CompoGen.cpp
index 178673e32..29b831dfd 100644
--- a/src/Generating/CompoGen.cpp
+++ b/src/Generating/CompoGen.cpp
@@ -12,7 +12,7 @@
#include "../BlockID.h"
#include "../Item.h"
#include "../LinearUpscale.h"
-#include "inifile/iniFile.h"
+#include "../IniFile.h"
@@ -663,7 +663,7 @@ void cCompoGenNether::InitializeCompoGen(cIniFile & a_IniFile)
////////////////////////////////////////////////////////////////////////////////
// cCompoGenCache:
-cCompoGenCache::cCompoGenCache(cTerrainCompositionGen & a_Underlying, int a_CacheSize) :
+cCompoGenCache::cCompoGenCache(cTerrainCompositionGenPtr a_Underlying, int a_CacheSize) :
m_Underlying(a_Underlying),
m_CacheSize(a_CacheSize),
m_CacheOrder(new int[a_CacheSize]),
@@ -687,9 +687,9 @@ cCompoGenCache::cCompoGenCache(cTerrainCompositionGen & a_Underlying, int a_Cach
cCompoGenCache::~cCompoGenCache()
{
delete[] m_CacheData;
- m_CacheData = NULL;
+ m_CacheData = nullptr;
delete[] m_CacheOrder;
- m_CacheOrder = NULL;
+ m_CacheOrder = nullptr;
}
@@ -739,7 +739,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
// Not in the cache:
m_NumMisses++;
- m_Underlying.ComposeTerrain(a_ChunkDesc);
+ m_Underlying->ComposeTerrain(a_ChunkDesc);
// Insert it as the first item in the MRU order:
int Idx = m_CacheOrder[m_CacheSize - 1];
@@ -760,7 +760,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
void cCompoGenCache::InitializeCompoGen(cIniFile & a_IniFile)
{
- m_Underlying.InitializeCompoGen(a_IniFile);
+ m_Underlying->InitializeCompoGen(a_IniFile);
}
diff --git a/src/Generating/CompoGen.h b/src/Generating/CompoGen.h
index 096b0fb5a..b145b6ba3 100644
--- a/src/Generating/CompoGen.h
+++ b/src/Generating/CompoGen.h
@@ -144,12 +144,12 @@ protected:
-/// Caches most-recently-used chunk composition of another composition generator. Caches only the types and metas
+/** Caches most-recently-used chunk composition of another composition generator. Caches only the types and metas */
class cCompoGenCache :
public cTerrainCompositionGen
{
public:
- cCompoGenCache(cTerrainCompositionGen & a_Underlying, int a_CacheSize); // Doesn't take ownership of a_Underlying
+ cCompoGenCache(cTerrainCompositionGenPtr a_Underlying, int a_CacheSize); // Doesn't take ownership of a_Underlying
~cCompoGenCache();
// cTerrainCompositionGen override:
@@ -158,7 +158,7 @@ public:
protected:
- cTerrainCompositionGen & m_Underlying;
+ cTerrainCompositionGenPtr m_Underlying;
struct sCacheData
{
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index 69068d231..5f46574c7 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -7,7 +7,7 @@
#include "ComposableGenerator.h"
#include "../World.h"
-#include "inifile/iniFile.h"
+#include "../IniFile.h"
#include "../Root.h"
// Individual composed algorithms:
@@ -39,7 +39,7 @@
////////////////////////////////////////////////////////////////////////////////
// cTerrainCompositionGen:
-cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed)
+cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed)
{
AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", "");
if (CompoGenName.empty())
@@ -48,7 +48,7 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile &
CompoGenName = "Biomal";
}
- cTerrainCompositionGen * res = NULL;
+ cTerrainCompositionGen * res = nullptr;
if (NoCaseCompare(CompoGenName, "sameblock") == 0)
{
res = new cCompoGenSameBlock;
@@ -73,6 +73,10 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile &
{
res = new cCompoGenNether(a_Seed);
}
+ else if (NoCaseCompare(CompoGenName, "BiomalNoise3D") == 0)
+ {
+ res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen);
+ }
else if (NoCaseCompare(CompoGenName, "Noise3D") == 0)
{
res = new cNoise3DComposable(a_Seed);
@@ -102,12 +106,12 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile &
a_IniFile.SetValue("Generator", "CompositionGen", "Biomal");
return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed);
}
- ASSERT(res != NULL);
+ ASSERT(res != nullptr);
// Read the settings from the ini file:
res->InitializeCompoGen(a_IniFile);
- return res;
+ return cTerrainCompositionGenPtr(res);
}
@@ -119,12 +123,9 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile &
cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
super(a_ChunkGenerator),
- m_BiomeGen(NULL),
- m_HeightGen(NULL),
- m_CompositionGen(NULL),
- m_UnderlyingBiomeGen(NULL),
- m_UnderlyingHeightGen(NULL),
- m_UnderlyingCompositionGen(NULL)
+ m_BiomeGen(),
+ m_HeightGen(),
+ m_CompositionGen()
{
}
@@ -132,33 +133,6 @@ cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
-cComposableGenerator::~cComposableGenerator()
-{
- // Delete the generating composition:
- for (cFinishGenList::const_iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr)
- {
- delete *itr;
- }
- m_FinishGens.clear();
-
- delete m_CompositionGen;
- m_CompositionGen = NULL;
- delete m_HeightGen;
- m_HeightGen = NULL;
- delete m_BiomeGen;
- m_BiomeGen = NULL;
- delete m_UnderlyingCompositionGen;
- m_UnderlyingCompositionGen = NULL;
- delete m_UnderlyingHeightGen;
- m_UnderlyingHeightGen = NULL;
- delete m_UnderlyingBiomeGen;
- m_UnderlyingBiomeGen = NULL;
-}
-
-
-
-
-
void cComposableGenerator::Initialize(cIniFile & a_IniFile)
{
super::Initialize(a_IniFile);
@@ -175,7 +149,7 @@ void cComposableGenerator::Initialize(cIniFile & a_IniFile)
void cComposableGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
{
- if (m_BiomeGen != NULL) // Quick fix for generator deinitializing before the world storage finishes loading
+ if (m_BiomeGen != nullptr) // Quick fix for generator deinitializing before the world storage finishes loading
{
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap);
}
@@ -245,15 +219,14 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
CacheSize = 4;
}
LOGD("Using a cache for biomegen of size %d.", CacheSize);
- m_UnderlyingBiomeGen = m_BiomeGen;
if (MultiCacheLength > 0)
{
LOGD("Enabling multicache for biomegen of length %d.", MultiCacheLength);
- m_BiomeGen = new cBioGenMulticache(m_UnderlyingBiomeGen, CacheSize, MultiCacheLength);
+ m_BiomeGen = cBiomeGenPtr(new cBioGenMulticache(m_BiomeGen, CacheSize, MultiCacheLength));
}
else
{
- m_BiomeGen = new cBioGenCache(m_UnderlyingBiomeGen, CacheSize);
+ m_BiomeGen = cBiomeGenPtr(new cBioGenCache(m_BiomeGen, CacheSize));
}
}
@@ -264,7 +237,7 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
{
bool CacheOffByDefault = false;
- m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, *m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
+ m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
// Add a cache, if requested:
int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64);
@@ -278,8 +251,7 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
CacheSize = 4;
}
LOGD("Using a cache for Heightgen of size %d.", CacheSize);
- m_UnderlyingHeightGen = m_HeightGen;
- m_HeightGen = new cHeiGenCache(*m_UnderlyingHeightGen, CacheSize);
+ m_HeightGen = cTerrainHeightGenPtr(new cHeiGenCache(m_HeightGen, CacheSize));
}
}
@@ -289,13 +261,12 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
{
- m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, *m_BiomeGen, *m_HeightGen, m_ChunkGenerator.GetSeed());
+ m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, m_BiomeGen, *m_HeightGen, m_ChunkGenerator.GetSeed());
int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64);
if (CompoGenCacheSize > 1)
{
- m_UnderlyingCompositionGen = m_CompositionGen;
- m_CompositionGen = new cCompoGenCache(*m_UnderlyingCompositionGen, 32);
+ m_CompositionGen = cTerrainCompositionGenPtr(new cCompoGenCache(m_CompositionGen, 32));
}
}
@@ -319,7 +290,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10;
int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
- m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenBottomLava(BottomLavaLevel)));
}
else if (NoCaseCompare(*itr, "DeadBushes") == 0)
{
@@ -341,20 +312,20 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
AllowedBlocks.push_back(E_BLOCK_HARDENED_CLAY);
AllowedBlocks.push_back(E_BLOCK_STAINED_CLAY);
- m_FinishGens.push_back(new cFinishGenSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, AllowedBiomes, 2, AllowedBlocks));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, AllowedBiomes, 2, AllowedBlocks)));
}
else if (NoCaseCompare(*itr, "DirectOverhangs") == 0)
{
- m_FinishGens.push_back(new cStructGenDirectOverhangs(Seed));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenDirectOverhangs(Seed)));
}
else if (NoCaseCompare(*itr, "DistortedMembraneOverhangs") == 0)
{
- m_FinishGens.push_back(new cStructGenDistortedMembraneOverhangs(Seed));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenDistortedMembraneOverhangs(Seed)));
}
else if (NoCaseCompare(*itr, "DualRidgeCaves") == 0)
{
float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3);
- m_FinishGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenDualRidgeCaves(Seed, Threshold)));
}
else if (NoCaseCompare(*itr, "DungeonRooms") == 0)
{
@@ -362,24 +333,24 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7);
int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5);
AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1");
- m_FinishGens.push_back(new cDungeonRoomsFinisher(*m_HeightGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib));
+ m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_HeightGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)));
}
else if (NoCaseCompare(*itr, "Ice") == 0)
{
- m_FinishGens.push_back(new cFinishGenIce);
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenIce));
}
else if (NoCaseCompare(*itr, "LavaLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
- m_FinishGens.push_back(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, *m_HeightGen, Probability));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, m_HeightGen, Probability)));
}
else if (NoCaseCompare(*itr, "LavaSprings") == 0)
{
- m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension)));
}
else if (NoCaseCompare(*itr, "MarbleCaves") == 0)
{
- m_FinishGens.push_back(new cStructGenMarbleCaves(Seed));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenMarbleCaves(Seed)));
}
else if (NoCaseCompare(*itr, "MineShafts") == 0)
{
@@ -389,10 +360,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int ChanceCorridor = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCorridor", 600);
int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200);
int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200);
- m_FinishGens.push_back(new cStructGenMineShafts(
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenMineShafts(
Seed, GridSize, MaxOffset, MaxSystemSize,
ChanceCorridor, ChanceCrossing, ChanceStaircase
- ));
+ )));
}
else if (NoCaseCompare(*itr, "Lilypads") == 0)
{
@@ -406,7 +377,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
AllowedBlocks.push_back(E_BLOCK_WATER);
AllowedBlocks.push_back(E_BLOCK_STATIONARY_WATER);
- m_FinishGens.push_back(new cFinishGenSingleTopBlock(Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSingleTopBlock(Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks)));
}
else if (NoCaseCompare(*itr, "NaturalPatches") == 0)
{
@@ -422,24 +393,51 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
// Gravel vein
cStructGenOreNests::OreInfo GravelVein;
- GravelVein.BlockType = E_BLOCK_DIRT;
+ GravelVein.BlockType = E_BLOCK_GRAVEL;
GravelVein.MaxHeight = 127;
GravelVein.NumNests = 20;
GravelVein.NestSize = 32;
Ores.push_back(GravelVein);
- m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE));
+ // Granite vein
+ cStructGenOreNests::OreInfo GraniteVein;
+ GraniteVein.BlockType = E_BLOCK_STONE;
+ GraniteVein.BlockMeta = 1;
+ GraniteVein.MaxHeight = 127;
+ GraniteVein.NumNests = 20;
+ GraniteVein.NestSize = 32;
+ Ores.push_back(GraniteVein);
+
+ // Diorite vein
+ cStructGenOreNests::OreInfo DioriteVein;
+ DioriteVein.BlockType = E_BLOCK_STONE;
+ DioriteVein.BlockMeta = 3;
+ DioriteVein.MaxHeight = 127;
+ DioriteVein.NumNests = 20;
+ DioriteVein.NestSize = 32;
+ Ores.push_back(DioriteVein);
+
+ // Andesite vein
+ cStructGenOreNests::OreInfo AndesiteVein;
+ AndesiteVein.BlockType = E_BLOCK_STONE;
+ AndesiteVein.BlockMeta = 5;
+ AndesiteVein.MaxHeight = 127;
+ AndesiteVein.NumNests = 20;
+ AndesiteVein.NestSize = 32;
+ Ores.push_back(AndesiteVein);
+
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE)));
}
else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0)
{
- m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenNetherClumpFoliage(Seed)));
}
else if (NoCaseCompare(*itr, "NetherForts") == 0)
{
int GridSize = a_IniFile.GetValueSetI("Generator", "NetherFortsGridSize", 512);
int MaxOffset = a_IniFile.GetValueSetI("Generator", "NetherFortMaxOffset", 128);
int MaxDepth = a_IniFile.GetValueSetI("Generator", "NetherFortsMaxDepth", 12);
- m_FinishGens.push_back(new cNetherFortGen(Seed, GridSize, MaxOffset, MaxDepth));
+ m_FinishGens.push_back(cFinishGenPtr(new cNetherFortGen(Seed, GridSize, MaxOffset, MaxDepth)));
}
else if (NoCaseCompare(*itr, "NetherOreNests") == 0)
{
@@ -453,7 +451,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
QuartzVein.NestSize = 8;
Ores.push_back(QuartzVein);
- m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_NETHERRACK));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenOreNests(Seed, Ores, E_BLOCK_NETHERRACK)));
}
else if (NoCaseCompare(*itr, "OreNests") == 0)
@@ -508,11 +506,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
DiamondVein.NestSize = 4;
Ores.push_back(DiamondVein);
- m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE)));
}
else if (NoCaseCompare(*itr, "POCPieces") == 0)
{
- m_FinishGens.push_back(new cPOCPieceGenerator(Seed));
+ m_FinishGens.push_back(cFinishGenPtr(new cPOCPieceGenerator(Seed)));
}
else if (NoCaseCompare(*itr, "PreSimulator") == 0)
{
@@ -521,7 +519,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
bool PreSimulateWater = a_IniFile.GetValueSetB("Generator", "PreSimulatorWater", true);
bool PreSimulateLava = a_IniFile.GetValueSetB("Generator", "PreSimulatorLava", true);
- m_FinishGens.push_back(new cFinishGenPreSimulator(PreSimulateFallingBlocks, PreSimulateWater, PreSimulateLava));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenPreSimulator(PreSimulateFallingBlocks, PreSimulateWater, PreSimulateLava)));
}
else if (NoCaseCompare(*itr, "RainbowRoads") == 0)
{
@@ -529,11 +527,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int MaxOffset = a_IniFile.GetValueSetI("Generator", "RainbowRoadsMaxOffset", 128);
int MaxDepth = a_IniFile.GetValueSetI("Generator", "RainbowRoadsMaxDepth", 30);
int MaxSize = a_IniFile.GetValueSetI("Generator", "RainbowRoadsMaxSize", 260);
- m_FinishGens.push_back(new cRainbowRoadsGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize));
+ m_FinishGens.push_back(cFinishGenPtr(new cRainbowRoadsGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize)));
}
else if (NoCaseCompare(*itr, "Ravines") == 0)
{
- m_FinishGens.push_back(new cStructGenRavines(Seed, 128));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenRavines(Seed, 128)));
}
else if (NoCaseCompare(*itr, "RoughRavines") == 0)
{
@@ -553,7 +551,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
double MinCeilingHeightEdge = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinCeilingHeightEdge", 38);
double MaxCeilingHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMaxCeilingHeightCenter", 58);
double MinCeilingHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinCeilingHeightCenter", 36);
- m_FinishGens.push_back(new cRoughRavines(
+ m_FinishGens.push_back(cFinishGenPtr(new cRoughRavines(
Seed, MaxSize, MinSize,
(float)MaxCenterWidth, (float)MinCenterWidth,
(float)MaxRoughness, (float)MinRoughness,
@@ -562,27 +560,27 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
(float)MaxCeilingHeightEdge, (float)MinCeilingHeightEdge,
(float)MaxCeilingHeightCenter, (float)MinCeilingHeightCenter,
GridSize, MaxOffset
- ));
+ )));
}
else if (NoCaseCompare(*itr, "Snow") == 0)
{
- m_FinishGens.push_back(new cFinishGenSnow);
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSnow));
}
else if (NoCaseCompare(*itr, "SprinkleFoliage") == 0)
{
- m_FinishGens.push_back(new cFinishGenSprinkleFoliage(Seed));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSprinkleFoliage(Seed)));
}
else if (NoCaseCompare(*itr, "TallGrass") == 0)
{
- m_FinishGens.push_back(new cFinishGenTallGrass(Seed));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenTallGrass(Seed)));
}
else if (NoCaseCompare(*itr, "TestRails") == 0)
{
- m_FinishGens.push_back(new cTestRailsGen(Seed, 100, 1, 7, 50));
+ m_FinishGens.push_back(cFinishGenPtr(new cTestRailsGen(Seed, 100, 1, 7, 50)));
}
else if (NoCaseCompare(*itr, "Trees") == 0)
{
- m_FinishGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen)));
}
else if (NoCaseCompare(*itr, "UnderwaterBases") == 0)
{
@@ -590,7 +588,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int MaxOffset = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxOffset", 128);
int MaxDepth = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxDepth", 7);
int MaxSize = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxSize", 128);
- m_FinishGens.push_back(new cUnderwaterBaseGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, *m_BiomeGen));
+ m_FinishGens.push_back(cFinishGenPtr(new cUnderwaterBaseGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, m_BiomeGen)));
}
else if (NoCaseCompare(*itr, "Villages") == 0)
{
@@ -600,23 +598,23 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128);
int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50);
int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
- m_FinishGens.push_back(new cVillageGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, *m_BiomeGen, *m_HeightGen));
+ m_FinishGens.push_back(cFinishGenPtr(new cVillageGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_HeightGen)));
}
else if (NoCaseCompare(*itr, "WaterLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
- m_FinishGens.push_back(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, *m_HeightGen, Probability));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, m_HeightGen, Probability)));
}
else if (NoCaseCompare(*itr, "WaterSprings") == 0)
{
- m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension)));
}
else if (NoCaseCompare(*itr, "WormNestCaves") == 0)
{
int Size = a_IniFile.GetValueSetI("Generator", "WormNestCavesSize", 64);
int Grid = a_IniFile.GetValueSetI("Generator", "WormNestCavesGrid", 96);
int MaxOffset = a_IniFile.GetValueSetI("Generator", "WormNestMaxOffset", 32);
- m_FinishGens.push_back(new cStructGenWormNestCaves(Seed, Size, Grid, MaxOffset));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenWormNestCaves(Seed, Size, Grid, MaxOffset)));
}
else
{
diff --git a/src/Generating/ComposableGenerator.h b/src/Generating/ComposableGenerator.h
index 6b7627d2e..a091f8d53 100644
--- a/src/Generating/ComposableGenerator.h
+++ b/src/Generating/ComposableGenerator.h
@@ -24,6 +24,16 @@ See http://forum.mc-server.org/showthread.php?tid=409 for details.
+// Forward-declare the shared pointers to subgenerator classes:
+class cBiomeGen;
+class cTerrainHeightGen;
+class cTerrainCompositionGen;
+class cFinishGen;
+typedef SharedPtr<cBiomeGen> cBiomeGenPtr;
+typedef SharedPtr<cTerrainHeightGen> cTerrainHeightGenPtr;
+typedef SharedPtr<cTerrainCompositionGen> cTerrainCompositionGenPtr;
+typedef SharedPtr<cFinishGen> cFinishGenPtr;
+
// fwd: Noise3DGenerator.h
class cNoise3DComposable;
@@ -53,8 +63,7 @@ public:
a_CacheOffByDefault gets set to whether the cache should be disabled by default.
Used in BiomeVisualiser, too.
Implemented in BioGen.cpp! */
- static cBiomeGen * CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault);
-
+ static cBiomeGenPtr CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault);
} ;
@@ -83,7 +92,7 @@ public:
a_CacheOffByDefault gets set to whether the cache should be disabled by default
Implemented in HeiGen.cpp!
*/
- static cTerrainHeightGen * CreateHeightGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
+ static cTerrainHeightGenPtr CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
} ;
@@ -109,7 +118,7 @@ public:
a_BiomeGen is the underlying biome generator, some composition generators may depend on it to generate more biomes
a_HeightGen is the underlying height generator, some composition generators may depend on it providing additional values
*/
- static cTerrainCompositionGen * CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed);
+ static cTerrainCompositionGenPtr CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed);
} ;
@@ -131,7 +140,7 @@ public:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) = 0;
} ;
-typedef std::list<cFinishGen *> cFinishGenList;
+typedef std::list<cFinishGenPtr> cFinishGenList;
@@ -144,7 +153,6 @@ class cComposableGenerator :
public:
cComposableGenerator(cChunkGenerator & a_ChunkGenerator);
- virtual ~cComposableGenerator();
virtual void Initialize(cIniFile & a_IniFile) override;
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
@@ -152,15 +160,10 @@ public:
protected:
// The generation composition:
- cBiomeGen * m_BiomeGen;
- cTerrainHeightGen * m_HeightGen;
- cTerrainCompositionGen * m_CompositionGen;
- cFinishGenList m_FinishGens;
-
- // Generators underlying the caches:
- cBiomeGen * m_UnderlyingBiomeGen;
- cTerrainHeightGen * m_UnderlyingHeightGen;
- cTerrainCompositionGen * m_UnderlyingCompositionGen;
+ cBiomeGenPtr m_BiomeGen;
+ cTerrainHeightGenPtr m_HeightGen;
+ cTerrainCompositionGenPtr m_CompositionGen;
+ cFinishGenList m_FinishGens;
/** Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly */
diff --git a/src/Generating/DistortedHeightmap.cpp b/src/Generating/DistortedHeightmap.cpp
index c18c402da..d5bc6ab55 100644
--- a/src/Generating/DistortedHeightmap.cpp
+++ b/src/Generating/DistortedHeightmap.cpp
@@ -7,7 +7,7 @@
#include "DistortedHeightmap.h"
#include "../OSSupport/File.h"
-#include "inifile/iniFile.h"
+#include "../IniFile.h"
#include "../LinearUpscale.h"
@@ -227,15 +227,15 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
/* biMesaPlateau */ { 2.0f, 2.0f}, // 39
// biomes 40 .. 128 are unused, 89 empty placeholders here:
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 40 .. 49
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 50 .. 59
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 60 .. 69
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 70 .. 79
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 80 .. 89
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 90 .. 99
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 100 .. 109
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 110 .. 119
- {}, {}, {}, {}, {}, {}, {}, {}, {}, // 120 .. 128
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 40 .. 49
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 50 .. 59
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 60 .. 69
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 70 .. 79
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 80 .. 89
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 90 .. 99
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 100 .. 109
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 110 .. 119
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 120 .. 128
// Release 1.7 /* biome variants:
/* biSunflowerPlains */ { 1.0f, 1.0f}, // 129
@@ -246,22 +246,22 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
/* biSwamplandM */ { 0.0f, 0.0f}, // 134
// Biomes 135 .. 139 unused, 5 empty placeholders here:
- {}, {}, {}, {}, {}, // 135 .. 139
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 135 .. 139
/* biIcePlainsSpikes */ { 1.0f, 1.0f}, // 140
// Biomes 141 .. 148 unused, 8 empty placeholders here:
- {}, {}, {}, {}, {}, {}, {}, {}, // 141 .. 148
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 141 .. 148
/* biJungleM */ { 4.0f, 4.0f}, // 149
- {}, // 150
+ {0.0f, 0.0f}, // 150
/* biJungleEdgeM */ { 3.0f, 3.0f}, // 151
- {}, {}, {}, // 152 .. 154
+ {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 152 .. 154
/* biBirchForestM */ { 3.0f, 3.0f}, // 155
/* biBirchForestHillsM */ { 5.0f, 5.0f}, // 156
/* biRoofedForestM */ { 2.0f, 2.0f}, // 157
/* biColdTaigaM */ { 1.0f, 1.0f}, // 158
- {}, // 159
+ {0.0f, 0.0f}, // 159
/* biMegaSpruceTaiga */ { 3.0f, 3.0f}, // 160
/* biMegaSpruceTaigaHills */ { 3.0f, 3.0f}, // 161
/* biExtremeHillsPlusM */ {32.0f, 32.0f}, // 162
@@ -276,13 +276,13 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
-cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGen & a_BiomeGen) :
+cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen) :
m_NoiseDistortX(a_Seed + 1000),
m_NoiseDistortZ(a_Seed + 2000),
m_OceanFloorSelect(a_Seed + 3000),
m_MesaFloor(a_Seed + 4000),
m_BiomeGen(a_BiomeGen),
- m_UnderlyingHeiGen(a_Seed, a_BiomeGen),
+ m_UnderlyingHeiGen(new cHeiGenBiomal(a_Seed, a_BiomeGen)),
m_HeightGen(m_UnderlyingHeiGen, 64),
m_IsInitialized(false)
{
@@ -540,10 +540,11 @@ void cDistortedHeightmap::InitializeCompoGen(cIniFile & a_IniFile)
int cDistortedHeightmap::GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z)
{
- int ChunkX = (int)floor(a_X / (NOISE_DATATYPE)16);
- int ChunkZ = (int)floor(a_Z / (NOISE_DATATYPE)16);
- int RelX = (int)(a_X - (NOISE_DATATYPE)ChunkX * cChunkDef::Width);
- int RelZ = (int)(a_Z - (NOISE_DATATYPE)ChunkZ * cChunkDef::Width);
+ int RelX = (int)std::floor(a_X);
+ int RelY = 0;
+ int RelZ = (int)std::floor(a_Z);
+ int ChunkX, ChunkZ;
+ cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
// If we're withing the same chunk, return the pre-cached heightmap:
if ((ChunkX == m_CurChunkX) && (ChunkZ == m_CurChunkZ))
@@ -576,7 +577,7 @@ void cDistortedHeightmap::UpdateDistortAmps(void)
{
for (int x = -1; x <= 1; x++)
{
- m_BiomeGen.GenBiomes(m_CurChunkX + x, m_CurChunkZ + z, Biomes[x + 1][z + 1]);
+ m_BiomeGen->GenBiomes(m_CurChunkX + x, m_CurChunkZ + z, Biomes[x + 1][z + 1]);
} // for x
} // for z
diff --git a/src/Generating/DistortedHeightmap.h b/src/Generating/DistortedHeightmap.h
index e6b3c9d3f..d073f29e4 100644
--- a/src/Generating/DistortedHeightmap.h
+++ b/src/Generating/DistortedHeightmap.h
@@ -35,7 +35,7 @@ public:
NIBBLETYPE BlockMeta;
} ;
- cDistortedHeightmap(int a_Seed, cBiomeGen & a_BiomeGen);
+ cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen);
protected:
typedef cChunkDef::BiomeMap BiomeNeighbors[3][3];
@@ -64,9 +64,14 @@ protected:
int m_CurChunkZ;
NOISE_DATATYPE m_DistortedHeightmap[17 * 257 * 17];
- cBiomeGen & m_BiomeGen;
- cHeiGenBiomal m_UnderlyingHeiGen; // This generator provides us with base heightmap (before distortion)
- cHeiGenCache m_HeightGen; // Cache above m_UnderlyingHeiGen
+ /** The bime generator to query for biomes. */
+ cBiomeGenPtr m_BiomeGen;
+
+ /** The generator that provides the base heightmap (before distortion). */
+ cTerrainHeightGenPtr m_UnderlyingHeiGen;
+
+ /** Cache for m_UnderlyingHeiGen. */
+ cHeiGenCache m_HeightGen;
/// Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization.
cChunkDef::HeightMap m_CurChunkHeights;
diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp
index f213455d6..3f328868d 100644
--- a/src/Generating/DungeonRoomsFinisher.cpp
+++ b/src/Generating/DungeonRoomsFinisher.cpp
@@ -6,6 +6,7 @@
#include "Globals.h"
#include "DungeonRoomsFinisher.h"
#include "../FastRandom.h"
+#include "../BlockEntities/ChestEntity.h"
@@ -175,7 +176,33 @@ protected:
}
a_ChunkDesc.SetBlockTypeMeta(RelX, m_FloorHeight + 1, RelZ, E_BLOCK_CHEST, (NIBBLETYPE)a_Chest.y);
- // TODO: Fill the chest with random loot
+ // Fill the chest with random loot
+ static const cLootProbab LootProbab[] =
+ {
+ // Item, MinAmount, MaxAmount, Weight
+ { cItem(E_ITEM_GOLDEN_APPLE), 1, 1, 1 },
+ { cItem(E_ITEM_DIAMOND_HORSE_ARMOR), 1, 1, 1 },
+ { cItem(E_ITEM_GOLD_HORSE_ARMOR), 1, 1, 2 },
+ { cItem(E_ITEM_13_DISC), 1, 1, 4 },
+ { cItem(E_ITEM_CAT_DISC), 1, 1, 4 },
+ { cItem(E_ITEM_IRON_HORSE_ARMOR), 1, 1, 5 },
+ { cItem(E_ITEM_IRON), 1, 4, 10 },
+ { cItem(E_ITEM_WHEAT), 1, 4, 10 },
+ { cItem(E_ITEM_GUNPOWDER), 1, 4, 10 },
+ { cItem(E_ITEM_STRING), 1, 4, 10 },
+ { cItem(E_ITEM_REDSTONE_DUST), 1, 4, 10 },
+ { cItem(E_ITEM_SADDLE), 1, 1, 10 },
+ { cItem(E_ITEM_BUCKET), 1, 1, 10 },
+ { cItem(E_ITEM_BREAD), 1, 1, 10 },
+ { cItem(E_ITEM_NAME_TAG), 1, 1, 10 },
+ } ;
+
+ cChestEntity * ChestEntity = (cChestEntity *)a_ChunkDesc.GetBlockEntity(RelX, m_FloorHeight + 1, RelZ);
+ ASSERT((ChestEntity != nullptr) && (ChestEntity->GetBlockType() == E_BLOCK_CHEST));
+ cNoise Noise(a_ChunkDesc.GetChunkX() ^ a_ChunkDesc.GetChunkZ());
+ int NumSlots = 3 + ((Noise.IntNoise3DInt(a_Chest.x, a_Chest.y, a_Chest.z) / 11) % 4);
+ int Seed = Noise.IntNoise2DInt(RelX, RelZ);
+ ChestEntity->GetContents().GenerateRandomLootWithBooks(LootProbab, ARRAYCOUNT(LootProbab), NumSlots, Seed);
}
@@ -193,6 +220,7 @@ protected:
// The chunk is not intersecting the room at all, bail out
return;
}
+
int b = m_FloorHeight + 1; // Bottom
int t = m_FloorHeight + 1 + ROOM_HEIGHT; // Top
ReplaceCuboidRandom(a_ChunkDesc, m_StartX, m_FloorHeight, m_StartZ, m_EndX + 1, b, m_EndZ + 1, E_BLOCK_MOSSY_COBBLESTONE, E_BLOCK_COBBLESTONE); // Floor
@@ -230,7 +258,7 @@ protected:
////////////////////////////////////////////////////////////////////////////////
// cDungeonRoomsFinisher:
-cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) :
+cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) :
super(a_Seed + 100, a_GridSize, a_GridSize, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 1024),
m_HeightGen(a_HeightGen),
m_MaxHalfSize((a_MaxSize + 1) / 2),
@@ -266,7 +294,7 @@ cDungeonRoomsFinisher::cStructurePtr cDungeonRoomsFinisher::CreateStructure(int
int RelX = a_OriginX, RelY = 0, RelZ = a_OriginZ;
cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
cChunkDef::HeightMap HeightMap;
- m_HeightGen.GenHeightMap(ChunkX, ChunkZ, HeightMap);
+ m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap);
int Height = cChunkDef::GetHeight(HeightMap, RelX, RelZ); // Max room height at {a_OriginX, a_OriginZ}
Height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, Height - 5);
diff --git a/src/Generating/DungeonRoomsFinisher.h b/src/Generating/DungeonRoomsFinisher.h
index 2b52c9de6..09dd0448a 100644
--- a/src/Generating/DungeonRoomsFinisher.h
+++ b/src/Generating/DungeonRoomsFinisher.h
@@ -26,12 +26,12 @@ public:
a_HeightGen is the underlying height generator, so that the rooms can always be placed under the terrain.
a_MaxSize and a_MinSize are the maximum and minimum sizes of the room's internal (air) area, in blocks across.
a_HeightDistrib is the string defining the height distribution for the rooms (cProbabDistrib format). */
- cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib);
+ cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib);
protected:
/** The height gen that is used for limiting the rooms' Y coords */
- cTerrainHeightGen & m_HeightGen;
+ cTerrainHeightGenPtr m_HeightGen;
/** Maximum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 3 (vanilla). */
int m_MaxHalfSize;
diff --git a/src/Generating/EndGen.cpp b/src/Generating/EndGen.cpp
index c94cd1eff..0111d2fa3 100644
--- a/src/Generating/EndGen.cpp
+++ b/src/Generating/EndGen.cpp
@@ -5,7 +5,7 @@
#include "Globals.h"
#include "EndGen.h"
-#include "inifile/iniFile.h"
+#include "../IniFile.h"
#include "../LinearUpscale.h"
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index 96e3dc26b..b8afac09a 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -15,7 +15,7 @@
#include "../Simulator/FluidSimulator.h" // for cFluidSimulator::CanWashAway()
#include "../Simulator/FireSimulator.h"
#include "../World.h"
-#include "inifile/iniFile.h"
+#include "../IniFile.h"
@@ -199,6 +199,11 @@ void cFinishGenTallGrass::GenFinish(cChunkDesc & a_ChunkDesc)
// Get the top block + 1. This is the place where the grass would finaly be placed:
int y = a_ChunkDesc.GetHeight(x, z) + 1;
+
+ if (y >= 255)
+ {
+ continue;
+ }
// Check if long grass can be placed:
if (
@@ -414,6 +419,11 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
}
break;
}
+ default:
+ {
+ // There's no snow in the other biomes.
+ break;
+ }
}
}
} // for z
@@ -454,6 +464,11 @@ void cFinishGenIce::GenFinish(cChunkDesc & a_ChunkDesc)
}
break;
}
+ default:
+ {
+ // No icy water in other biomes.
+ break;
+ }
}
}
} // for z
diff --git a/src/Generating/GridStructGen.cpp b/src/Generating/GridStructGen.cpp
index 7090f14b1..3c08c1a39 100644
--- a/src/Generating/GridStructGen.cpp
+++ b/src/Generating/GridStructGen.cpp
@@ -135,7 +135,7 @@ void cGridStructGen::GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructur
int OriginX = GridX + ((m_Noise.IntNoise2DInt(GridX + 3, GridZ + 5) / 7) % (m_MaxOffsetX * 2)) - m_MaxOffsetX;
int OriginZ = GridZ + ((m_Noise.IntNoise2DInt(GridX + 5, GridZ + 3) / 7) % (m_MaxOffsetZ * 2)) - m_MaxOffsetZ;
cStructurePtr Structure = CreateStructure(GridX, GridZ, OriginX, OriginZ);
- if (Structure.get() == NULL)
+ if (Structure.get() == nullptr)
{
Structure.reset(new cEmptyStructure(GridX, GridZ, OriginX, OriginZ));
}
diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp
index 79d529a6a..1d9f1e3aa 100644
--- a/src/Generating/HeiGen.cpp
+++ b/src/Generating/HeiGen.cpp
@@ -6,7 +6,7 @@
#include "Globals.h"
#include "HeiGen.h"
#include "../LinearUpscale.h"
-#include "inifile/iniFile.h"
+#include "../IniFile.h"
#include "DistortedHeightmap.h"
#include "EndGen.h"
#include "Noise3DGenerator.h"
@@ -17,81 +17,6 @@
////////////////////////////////////////////////////////////////////////////////
-// cTerrainHeightGen:
-
-cTerrainHeightGen * cTerrainHeightGen::CreateHeightGen(cIniFile &a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault)
-{
- AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", "");
- if (HeightGenName.empty())
- {
- LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\".");
- HeightGenName = "Biomal";
- }
-
- a_CacheOffByDefault = false;
- cTerrainHeightGen * res = NULL;
- if (NoCaseCompare(HeightGenName, "flat") == 0)
- {
- res = new cHeiGenFlat;
- a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
- }
- else if (NoCaseCompare(HeightGenName, "classic") == 0)
- {
- res = new cHeiGenClassic(a_Seed);
- }
- else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
- {
- res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
- }
- else if (NoCaseCompare(HeightGenName, "End") == 0)
- {
- res = new cEndGen(a_Seed);
- }
- else if (NoCaseCompare(HeightGenName, "Mountains") == 0)
- {
- res = new cHeiGenMountains(a_Seed);
- }
- else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
- {
- res = new cNoise3DComposable(a_Seed);
- }
- else if (NoCaseCompare(HeightGenName, "biomal") == 0)
- {
- res = new cHeiGenBiomal(a_Seed, a_BiomeGen);
-
- /*
- // Performance-testing:
- LOGINFO("Measuring performance of cHeiGenBiomal...");
- clock_t BeginTick = clock();
- for (int x = 0; x < 500; x++)
- {
- cChunkDef::HeightMap Heights;
- res->GenHeightMap(x * 5, x * 5, Heights);
- }
- clock_t Duration = clock() - BeginTick;
- LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
- //*/
- }
- else
- {
- // No match found, force-set the default and retry
- LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
- a_IniFile.DeleteValue("Generator", "HeightGen");
- a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
- return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
- }
-
- // Read the settings:
- res->InitializeHeightGen(a_IniFile);
-
- return res;
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
// cHeiGenFlat:
void cHeiGenFlat::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
@@ -118,7 +43,7 @@ void cHeiGenFlat::InitializeHeightGen(cIniFile & a_IniFile)
////////////////////////////////////////////////////////////////////////////////
// cHeiGenCache:
-cHeiGenCache::cHeiGenCache(cTerrainHeightGen & a_HeiGenToCache, int a_CacheSize) :
+cHeiGenCache::cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize) :
m_HeiGenToCache(a_HeiGenToCache),
m_CacheSize(a_CacheSize),
m_CacheOrder(new int[a_CacheSize]),
@@ -142,9 +67,9 @@ cHeiGenCache::cHeiGenCache(cTerrainHeightGen & a_HeiGenToCache, int a_CacheSize)
cHeiGenCache::~cHeiGenCache()
{
delete[] m_CacheData;
- m_CacheData = NULL;
+ m_CacheData = nullptr;
delete[] m_CacheOrder;
- m_CacheOrder = NULL;
+ m_CacheOrder = nullptr;
}
@@ -190,7 +115,7 @@ void cHeiGenCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap
// Not in the cache:
m_NumMisses++;
- m_HeiGenToCache.GenHeightMap(a_ChunkX, a_ChunkZ, a_HeightMap);
+ m_HeiGenToCache->GenHeightMap(a_ChunkX, a_ChunkZ, a_HeightMap);
// Insert it as the first item in the MRU order:
int Idx = m_CacheOrder[m_CacheSize - 1];
@@ -210,7 +135,7 @@ void cHeiGenCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap
void cHeiGenCache::InitializeHeightGen(cIniFile & a_IniFile)
{
- m_HeiGenToCache.InitializeHeightGen(a_IniFile);
+ m_HeiGenToCache->InitializeHeightGen(a_IniFile);
}
@@ -317,7 +242,9 @@ void cHeiGenClassic::InitializeHeightGen(cIniFile & a_IniFile)
cHeiGenMountains::cHeiGenMountains(int a_Seed) :
m_Seed(a_Seed),
- m_Noise(a_Seed)
+ m_MountainNoise(a_Seed + 100),
+ m_DitchNoise(a_Seed + 200),
+ m_Perlin(a_Seed + 300)
{
}
@@ -332,9 +259,11 @@ void cHeiGenMountains::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Heigh
NOISE_DATATYPE StartZ = (NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width);
NOISE_DATATYPE EndZ = (NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + cChunkDef::Width - 1);
NOISE_DATATYPE Workspace[16 * 16];
- NOISE_DATATYPE Noise[16 * 16];
+ NOISE_DATATYPE MountainNoise[16 * 16];
+ NOISE_DATATYPE DitchNoise[16 * 16];
NOISE_DATATYPE PerlinNoise[16 * 16];
- m_Noise.Generate2D(Noise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace);
+ m_MountainNoise.Generate2D(MountainNoise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace);
+ m_DitchNoise.Generate2D(DitchNoise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace);
m_Perlin.Generate2D(PerlinNoise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace);
for (int z = 0; z < cChunkDef::Width; z++)
{
@@ -342,7 +271,7 @@ void cHeiGenMountains::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Heigh
for (int x = 0; x < cChunkDef::Width; x++)
{
int idx = IdxZ + x;
- int hei = 100 - (int)((Noise[idx] + PerlinNoise[idx]) * 15);
+ int hei = 100 - (int)((MountainNoise[idx] - DitchNoise[idx] + PerlinNoise[idx]) * 15);
if (hei < 10)
{
hei = 10;
@@ -363,9 +292,12 @@ void cHeiGenMountains::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Heigh
void cHeiGenMountains::InitializeHeightGen(cIniFile & a_IniFile)
{
// TODO: Read the params from an INI file
- m_Noise.AddOctave(0.1f, 0.1f);
- m_Noise.AddOctave(0.05f, 0.5f);
- m_Noise.AddOctave(0.02f, 1.5f);
+ m_MountainNoise.AddOctave(0.1f, 0.2f);
+ m_MountainNoise.AddOctave(0.05f, 0.4f);
+ m_MountainNoise.AddOctave(0.02f, 1.0f);
+ m_DitchNoise.AddOctave(0.1f, 0.2f);
+ m_DitchNoise.AddOctave(0.05f, 0.4f);
+ m_DitchNoise.AddOctave(0.02f, 1.0f);
m_Perlin.AddOctave(0.01f, 1.5f);
}
@@ -423,15 +355,15 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] =
/* biMesaPlateau */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 80},
// biomes 40 .. 128 are unused, 89 empty placeholders here:
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 40 .. 49
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 50 .. 59
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 60 .. 69
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 70 .. 79
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 80 .. 89
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 90 .. 99
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 100 .. 109
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 110 .. 119
- {}, {}, {}, {}, {}, {}, {}, {}, {}, // 120 .. 128
+ {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
+ {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
+ {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
+ {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
+ {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
+ {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
+ {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
+ {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
+ {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
/* biSunflowerPlains */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 129
/* biDesertM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 130
@@ -441,22 +373,22 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] =
/* biSwamplandM */ { 1.0f, 3.0f, 1.10f, 7.0f, 0.01f, 0.01f, 60}, // 134
// Biomes 135 .. 139 unused, 5 empty placeholders here:
- {}, {}, {}, {}, {}, // 135 .. 139
+ {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
/* biIcePlainsSpikes */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 140
// Biomes 141 .. 148 unused, 8 empty placeholders here:
- {}, {}, {}, {}, {}, {}, {}, {}, // 141 .. 148
+ {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
/* biJungleM */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70}, // 149
- {}, // 150
+ {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 150
/* biJungleEdgeM */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70}, // 151
- {}, {}, {}, // 152 .. 154
+ {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
/* biBirchForestM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 155
/* biBirchForestHillsM */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80}, // 156
/* biRoofedForestM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 157
/* biColdTaigaM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 158
- {}, // 159
+ {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 159
/* biMegaSpruceTaiga */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 160
/* biMegaSpruceTaigaHills */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80}, // 161
/* biExtremeHillsPlusM */ { 0.2f, 4.0f, 0.05f, 20.0f, 0.01f, 16.0f, 120}, // 162
@@ -479,7 +411,7 @@ void cHeiGenBiomal::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMa
{
for (int x = -1; x <= 1; x++)
{
- m_BiomeGen.GenBiomes(a_ChunkX + x, a_ChunkZ + z, Biomes[x + 1][z + 1]);
+ m_BiomeGen->GenBiomes(a_ChunkX + x, a_ChunkZ + z, Biomes[x + 1][z + 1]);
} // for x
} // for z
@@ -604,3 +536,287 @@ NOISE_DATATYPE cHeiGenBiomal::GetHeightAt(int a_RelX, int a_RelZ, int a_ChunkX,
+////////////////////////////////////////////////////////////////////////////////
+// cHeiGenMinMax:
+
+class cHeiGenMinMax:
+ public cTerrainHeightGen
+{
+ typedef cTerrainHeightGen super;
+
+ /** Size of the averaging process, in columns (for each direction). Must be less than 16. */
+ static const int AVERAGING_SIZE = 4;
+
+public:
+ cHeiGenMinMax(int a_Seed, cBiomeGenPtr a_BiomeGen):
+ m_Noise(a_Seed),
+ m_BiomeGen(a_BiomeGen),
+ m_TotalWeight(0)
+ {
+ // Initialize the weights:
+ for (int z = 0; z <= AVERAGING_SIZE * 2; z++)
+ {
+ for (int x = 0; x <= AVERAGING_SIZE * 2; x++)
+ {
+ m_Weights[z][x] = 1 + 2 * AVERAGING_SIZE - std::abs(x - AVERAGING_SIZE) - std::abs(z - AVERAGING_SIZE);
+ m_TotalWeight += m_Weights[z][x];
+ }
+ }
+
+ // Initialize the Perlin generator:
+ m_Perlin.AddOctave(0.04f, 0.2f);
+ m_Perlin.AddOctave(0.02f, 0.1f);
+ m_Perlin.AddOctave(0.01f, 0.05f);
+ }
+
+
+ virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
+ {
+ // Generate the biomes for the 3*3 neighbors:
+ cChunkDef::BiomeMap neighborBiomes[3][3];
+ for (int z = 0; z < 3; z++) for (int x = 0; x < 3; x++)
+ {
+ m_BiomeGen->GenBiomes(a_ChunkX + x - 1, a_ChunkZ + z - 1, neighborBiomes[z][x]);
+ }
+
+ // Get the min and max heights based on the biomes:
+ double minHeight[cChunkDef::Width * cChunkDef::Width];
+ double maxHeight[cChunkDef::Width * cChunkDef::Width];
+ for (int z = 0; z < cChunkDef::Width; z++)
+ {
+ for (int x = 0; x < cChunkDef::Width; x++)
+ {
+ // For each column, sum the min and max values of the neighborhood around it:
+ double min = 0, max = 0;
+ for (int relz = 0; relz <= AVERAGING_SIZE * 2; relz++)
+ {
+ int bz = z + 16 + relz - AVERAGING_SIZE; // Biome Z coord relative to the neighborBiomes start
+ int cz = bz / 16; // Chunk Z coord relative to the neighborBiomes start
+ bz = bz % 16; // Biome Z coord relative to cz in neighborBiomes
+ for (int relx = 0; relx <= AVERAGING_SIZE * 2; relx++)
+ {
+ int bx = x + 16 + relx - AVERAGING_SIZE; // Biome X coord relative to the neighborBiomes start
+ int cx = bx / 16; // Chunk X coord relative to the neighborBiomes start
+ bx = bx % 16; // Biome X coord relative to cz in neighborBiomes
+
+ // Get the biome's min and max heights:
+ double bmin, bmax;
+ getBiomeMinMax(cChunkDef::GetBiome(neighborBiomes[cz][cx], bx, bz), bmin, bmax);
+
+ // Add them to the total, with the weight depending on their relative position to the column:
+ min += bmin * m_Weights[relz][relx];
+ max += bmax * m_Weights[relz][relx];
+ } // for relx
+ } // for relz
+ minHeight[x + z * cChunkDef::Width] = min / m_TotalWeight;
+ maxHeight[x + z * cChunkDef::Width] = max / m_TotalWeight;
+ } // for x
+ } // for z
+
+ // Generate the base noise:
+ NOISE_DATATYPE noise[cChunkDef::Width * cChunkDef::Width];
+ NOISE_DATATYPE workspace[cChunkDef::Width * cChunkDef::Width];
+ NOISE_DATATYPE startX = static_cast<float>(a_ChunkX * cChunkDef::Width);
+ NOISE_DATATYPE endX = startX + cChunkDef::Width - 1;
+ NOISE_DATATYPE startZ = static_cast<float>(a_ChunkZ * cChunkDef::Width);
+ NOISE_DATATYPE endZ = startZ + cChunkDef::Width - 1;
+ m_Perlin.Generate2D(noise, 16, 16, startX, endX, startZ, endZ, workspace);
+
+ // Make the height by ranging the noise between min and max:
+ for (int z = 0; z < cChunkDef::Width; z++)
+ {
+ for (int x = 0; x < cChunkDef::Width; x++)
+ {
+ double min = minHeight[x + z * cChunkDef::Width];
+ double max = maxHeight[x + z * cChunkDef::Width];
+ double h = (max + min) / 2 + noise[x + z * cChunkDef::Width] * (max - min);
+ cChunkDef::SetHeight(a_HeightMap, x, z, static_cast<HEIGHTTYPE>(h));
+ }
+ }
+ }
+
+
+ virtual void InitializeHeightGen(cIniFile & a_IniFile)
+ {
+ // No settings available
+ }
+
+protected:
+ cNoise m_Noise;
+
+ cPerlinNoise m_Perlin;
+
+ /** The biome generator to query for the underlying biomes. */
+ cBiomeGenPtr m_BiomeGen;
+
+ /** Weights applied to each of the min / max values in the neighborhood of the currently evaluated column. */
+ double m_Weights[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1];
+
+ /** Sum of all the m_Weights items. */
+ double m_TotalWeight;
+
+
+ /** Returns the minimum and maximum heights for the given biome. */
+ void getBiomeMinMax(EMCSBiome a_Biome, double & a_Min, double & a_Max)
+ {
+ switch (a_Biome)
+ {
+ case biBeach: a_Min = 61; a_Max = 64; break;
+ case biBirchForest: a_Min = 63; a_Max = 75; break;
+ case biBirchForestHills: a_Min = 63; a_Max = 90; break;
+ case biBirchForestHillsM: a_Min = 63; a_Max = 90; break;
+ case biBirchForestM: a_Min = 63; a_Max = 75; break;
+ case biColdBeach: a_Min = 61; a_Max = 64; break;
+ case biColdTaiga: a_Min = 63; a_Max = 75; break;
+ case biColdTaigaHills: a_Min = 63; a_Max = 90; break;
+ case biColdTaigaM: a_Min = 63; a_Max = 75; break;
+ case biDeepOcean: a_Min = 30; a_Max = 60; break;
+ case biDesert: a_Min = 63; a_Max = 70; break;
+ case biDesertHills: a_Min = 63; a_Max = 85; break;
+ case biDesertM: a_Min = 63; a_Max = 70; break;
+ case biEnd: a_Min = 10; a_Max = 100; break;
+ case biExtremeHills: a_Min = 60; a_Max = 120; break;
+ case biExtremeHillsEdge: a_Min = 63; a_Max = 100; break;
+ case biExtremeHillsM: a_Min = 60; a_Max = 120; break;
+ case biExtremeHillsPlus: a_Min = 60; a_Max = 140; break;
+ case biExtremeHillsPlusM: a_Min = 60; a_Max = 140; break;
+ case biFlowerForest: a_Min = 63; a_Max = 75; break;
+ case biForest: a_Min = 63; a_Max = 75; break;
+ case biForestHills: a_Min = 63; a_Max = 90; break;
+ case biFrozenOcean: a_Min = 45; a_Max = 64; break;
+ case biFrozenRiver: a_Min = 60; a_Max = 62; break;
+ case biIceMountains: a_Min = 63; a_Max = 90; break;
+ case biIcePlains: a_Min = 63; a_Max = 70; break;
+ case biIcePlainsSpikes: a_Min = 60; a_Max = 70; break;
+ case biJungle: a_Min = 60; a_Max = 80; break;
+ case biJungleEdge: a_Min = 62; a_Max = 75; break;
+ case biJungleEdgeM: a_Min = 62; a_Max = 75; break;
+ case biJungleHills: a_Min = 60; a_Max = 90; break;
+ case biJungleM: a_Min = 60; a_Max = 75; break;
+ case biMegaSpruceTaiga: a_Min = 63; a_Max = 75; break;
+ case biMegaSpruceTaigaHills: a_Min = 63; a_Max = 90; break;
+ case biMegaTaiga: a_Min = 63; a_Max = 75; break;
+ case biMegaTaigaHills: a_Min = 63; a_Max = 90; break;
+ case biMesa: a_Min = 63; a_Max = 90; break;
+ case biMesaBryce: a_Min = 60; a_Max = 67; break;
+ case biMesaPlateau: a_Min = 75; a_Max = 85; break;
+ case biMesaPlateauF: a_Min = 80; a_Max = 90; break;
+ case biMesaPlateauFM: a_Min = 80; a_Max = 90; break;
+ case biMesaPlateauM: a_Min = 75; a_Max = 85; break;
+ case biMushroomIsland: a_Min = 63; a_Max = 90; break;
+ case biMushroomShore: a_Min = 60; a_Max = 75; break;
+ case biNether: a_Min = 10; a_Max = 100; break;
+ case biOcean: a_Min = 45; a_Max = 64; break;
+ case biPlains: a_Min = 63; a_Max = 70; break;
+ case biRiver: a_Min = 60; a_Max = 62; break;
+ case biRoofedForest: a_Min = 63; a_Max = 75; break;
+ case biRoofedForestM: a_Min = 63; a_Max = 75; break;
+ case biSavanna: a_Min = 63; a_Max = 75; break;
+ case biSavannaM: a_Min = 63; a_Max = 80; break;
+ case biSavannaPlateau: a_Min = 75; a_Max = 100; break;
+ case biSavannaPlateauM: a_Min = 80; a_Max = 160; break;
+ case biStoneBeach: a_Min = 60; a_Max = 64; break;
+ case biSunflowerPlains: a_Min = 63; a_Max = 70; break;
+ case biSwampland: a_Min = 60; a_Max = 67; break;
+ case biSwamplandM: a_Min = 61; a_Max = 67; break;
+ case biTaiga: a_Min = 63; a_Max = 75; break;
+ case biTaigaHills: a_Min = 63; a_Max = 90; break;
+ case biTaigaM: a_Min = 63; a_Max = 80; break;
+ default:
+ {
+ ASSERT(!"Unknown biome");
+ a_Min = 10;
+ a_Max = 10;
+ break;
+ }
+ }
+ }
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cTerrainHeightGen:
+
+cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault)
+{
+ AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", "");
+ if (HeightGenName.empty())
+ {
+ LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\".");
+ HeightGenName = "Biomal";
+ }
+
+ a_CacheOffByDefault = false;
+ cTerrainHeightGen * res = nullptr;
+ if (NoCaseCompare(HeightGenName, "flat") == 0)
+ {
+ res = new cHeiGenFlat;
+ a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
+ }
+ else if (NoCaseCompare(HeightGenName, "classic") == 0)
+ {
+ res = new cHeiGenClassic(a_Seed);
+ }
+ else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
+ {
+ res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
+ }
+ else if (NoCaseCompare(HeightGenName, "End") == 0)
+ {
+ res = new cEndGen(a_Seed);
+ }
+ else if (NoCaseCompare(HeightGenName, "MinMax") == 0)
+ {
+ res = new cHeiGenMinMax(a_Seed, a_BiomeGen);
+ }
+ else if (NoCaseCompare(HeightGenName, "Mountains") == 0)
+ {
+ res = new cHeiGenMountains(a_Seed);
+ }
+ else if (NoCaseCompare(HeightGenName, "BiomalNoise3D") == 0)
+ {
+ res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen);
+ }
+ else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
+ {
+ res = new cNoise3DComposable(a_Seed);
+ }
+ else if (NoCaseCompare(HeightGenName, "biomal") == 0)
+ {
+ res = new cHeiGenBiomal(a_Seed, a_BiomeGen);
+
+ /*
+ // Performance-testing:
+ LOGINFO("Measuring performance of cHeiGenBiomal...");
+ clock_t BeginTick = clock();
+ for (int x = 0; x < 500; x++)
+ {
+ cChunkDef::HeightMap Heights;
+ res->GenHeightMap(x * 5, x * 5, Heights);
+ }
+ clock_t Duration = clock() - BeginTick;
+ LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
+ //*/
+ }
+ else
+ {
+ // No match found, force-set the default and retry
+ LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
+ a_IniFile.DeleteValue("Generator", "HeightGen");
+ a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
+ return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
+ }
+
+ // Read the settings:
+ res->InitializeHeightGen(a_IniFile);
+
+ return cTerrainHeightGenPtr(res);
+}
+
+
+
+
+
diff --git a/src/Generating/HeiGen.h b/src/Generating/HeiGen.h
index 5c106c7d9..6ae5ba362 100644
--- a/src/Generating/HeiGen.h
+++ b/src/Generating/HeiGen.h
@@ -45,7 +45,7 @@ class cHeiGenCache :
public cTerrainHeightGen
{
public:
- cHeiGenCache(cTerrainHeightGen & a_HeiGenToCache, int a_CacheSize); // Doesn't take ownership of a_HeiGenToCache
+ cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize);
~cHeiGenCache();
// cTerrainHeightGen overrides:
@@ -57,7 +57,7 @@ public:
protected:
- cTerrainHeightGen & m_HeiGenToCache;
+ cTerrainHeightGenPtr m_HeiGenToCache;
struct sCacheData
{
@@ -115,7 +115,8 @@ public:
protected:
int m_Seed;
- cRidgedMultiNoise m_Noise;
+ cRidgedMultiNoise m_MountainNoise;
+ cRidgedMultiNoise m_DitchNoise;
cPerlinNoise m_Perlin;
// cTerrainHeightGen overrides:
@@ -131,7 +132,7 @@ class cHeiGenBiomal :
public cTerrainHeightGen
{
public:
- cHeiGenBiomal(int a_Seed, cBiomeGen & a_BiomeGen) :
+ cHeiGenBiomal(int a_Seed, cBiomeGenPtr a_BiomeGen) :
m_Noise(a_Seed),
m_BiomeGen(a_BiomeGen)
{
@@ -141,8 +142,8 @@ protected:
typedef cChunkDef::BiomeMap BiomeNeighbors[3][3];
- cNoise m_Noise;
- cBiomeGen & m_BiomeGen;
+ cNoise m_Noise;
+ cBiomeGenPtr m_BiomeGen;
// Per-biome terrain generator parameters:
struct sGenParam
diff --git a/src/Generating/IntGen.h b/src/Generating/IntGen.h
new file mode 100644
index 000000000..b25e378c0
--- /dev/null
+++ b/src/Generating/IntGen.h
@@ -0,0 +1,1406 @@
+
+// IntGen.h
+
+// Declares the cIntGen class and descendants for generating and filtering various 2D arrays of ints
+
+/*
+The integers generated may be interpreted in several ways:
+- land/see designators
+ - 0 = ocean
+ - >0 = land
+- biome group
+ - 0 = ocean
+ - 1 = desert biomes
+ - 2 = temperate biomes
+ - 3 = mountains (hills and forests)
+ - 4 = ice biomes
+- biome group with "bgfRare" flag (for generating rare biomes for the group)
+- biome IDs
+The interpretation depends on the generator used and on the position in the chain.
+
+The generators can be chained together - one produces data that another one consumes.
+Some of such chain connections require changing the data dimensions between the two, which is handled automatically
+by using templates.
+*/
+
+
+
+
+
+#pragma once
+
+#include "../BiomeDef.h"
+
+
+
+
+
+/** Constants representing the biome group designators. */
+const int bgOcean = 0;
+const int bgDesert = 1;
+const int bgTemperate = 2;
+const int bgMountains = 3;
+const int bgIce = 4;
+const int bgLandOceanMax = 4; // Maximum biome group value generated in the landOcean generator
+const int bgfRare = 1024; // Flag added to values to generate rare biomes for the group
+
+
+
+
+
+/** Interface that all the generator classes provide. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGen
+{
+public:
+ /** Force a virtual destructor in all descendants.
+ Descendants contain virtual functions and are referred to via pointer-to-base, so they need a virtual destructor. */
+ virtual ~cIntGen() {}
+
+ /** Holds the array of values generated by this class (descendant). */
+ typedef int Values[SizeX * SizeZ];
+
+ /** Generates the array of templated size into a_Values, based on given min coords. */
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) = 0;
+};
+
+
+
+
+
+/** Provides additional cNoise member and its helper functions. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenWithNoise :
+ public cIntGen<SizeX, SizeZ>
+{
+ typedef cIntGen<SizeX, SizeZ> super;
+
+public:
+ cIntGenWithNoise(int a_Seed) :
+ m_Noise(a_Seed)
+ {
+ }
+
+protected:
+ cNoise m_Noise;
+
+ /** Chooses one of a_Val1 or a_Val2, based on m_Noise and the coordinates for querying the noise. */
+ int ChooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2)
+ {
+ int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7;
+ return ((rnd & 1) == 0) ? a_Val1 : a_Val2;
+ }
+
+ /** Chooses one of a_ValN, based on m_Noise and the coordinates for querying the noise. */
+ int ChooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2, int a_Val3, int a_Val4)
+ {
+ int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7;
+ switch (rnd % 4)
+ {
+ case 0: return a_Val1;
+ case 1: return a_Val2;
+ case 2: return a_Val3;
+ default: return a_Val4;
+ }
+ }
+};
+
+
+
+
+
+
+/** Generates a 2D array of random integers in the specified range [0 .. Range). */
+template <int Range, int SizeX, int SizeZ = SizeX>
+class cIntGenChoice :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ cIntGenChoice(int a_Seed) :
+ super(a_Seed)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int BaseZ = a_MinZ + z;
+ for (int x = 0; x < SizeX; x++)
+ {
+ a_Values[x + SizeX * z] = (super::m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7) % Range;
+ }
+ } // for z
+ }
+};
+
+
+
+
+
+
+/** Decides between the ocean and landmass biomes.
+Has a threshold (in percent) of how much land, the larger the threshold, the more land.
+Generates 0 for ocean, biome group ID for landmass. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenLandOcean :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ cIntGenLandOcean(int a_Seed, int a_Threshold) :
+ super(a_Seed),
+ m_Threshold(a_Threshold)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int BaseZ = a_MinZ + z;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int rnd = (super::m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7);
+ a_Values[x + SizeX * z] = ((rnd % 100) < m_Threshold) ? ((rnd / 101) % bgLandOceanMax + 1) : 0;
+ }
+ }
+
+ // If the centerpoint of the world is within the area, set it to bgTemperate, always:
+ if ((a_MinX <= 0) && (a_MinZ <= 0) && (a_MinX + SizeX > 0) && (a_MinZ + SizeZ > 0))
+ {
+ a_Values[-a_MinX - a_MinZ * SizeX] = bgTemperate;
+ }
+ }
+
+protected:
+ int m_Threshold;
+};
+
+
+
+
+
+/** Zooms the underlying value array to twice the size. Uses random-neighbor for the pixels in-between.
+This means that the zoome out image is randomly distorted. Applying zoom several times provides all
+the distortion that the generators need. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenZoom :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+protected:
+ static const int m_LowerSizeX = (SizeX / 2) + 2;
+ static const int m_LowerSizeZ = (SizeZ / 2) + 2;
+
+public:
+ typedef std::shared_ptr<cIntGen<m_LowerSizeX, m_LowerSizeZ>> Underlying;
+
+
+ cIntGenZoom(int a_Seed, Underlying a_UnderlyingGen) :
+ super(a_Seed),
+ m_UnderlyingGen(a_UnderlyingGen)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying data with half the resolution:
+ int lowerMinX = a_MinX >> 1;
+ int lowerMinZ = a_MinZ >> 1;
+ int lowerData[m_LowerSizeX * m_LowerSizeZ];
+ m_UnderlyingGen->GetInts(lowerMinX, lowerMinZ, lowerData);
+ const int lowStepX = (m_LowerSizeX - 1) * 2;
+ const int lowStepZ = (m_LowerSizeZ - 1) * 2;
+ int cache[lowStepX * lowStepZ];
+
+ // Discreet-interpolate the values into twice the size:
+ for (int z = 0; z < m_LowerSizeZ - 1; ++z)
+ {
+ int idx = (z * 2) * lowStepX;
+ int PrevZ0 = lowerData[z * m_LowerSizeX];
+ int PrevZ1 = lowerData[(z + 1) * m_LowerSizeX];
+
+ for (int x = 0; x < m_LowerSizeX - 1; ++x)
+ {
+ int ValX1Z0 = lowerData[x + 1 + z * m_LowerSizeX];
+ int ValX1Z1 = lowerData[x + 1 + (z + 1) * m_LowerSizeX];
+ int RndX = (x + lowerMinX) * 2;
+ int RndZ = (z + lowerMinZ) * 2;
+ cache[idx] = PrevZ0;
+ cache[idx + lowStepX] = super::ChooseRandomOne(RndX, RndZ + 1, PrevZ0, PrevZ1);
+ cache[idx + 1] = super::ChooseRandomOne(RndX, RndZ - 1, PrevZ0, ValX1Z0);
+ cache[idx + 1 + lowStepX] = super::ChooseRandomOne(RndX, RndZ, PrevZ0, ValX1Z0, PrevZ1, ValX1Z1);
+ idx += 2;
+ PrevZ0 = ValX1Z0;
+ PrevZ1 = ValX1Z1;
+ }
+ }
+
+ // Copy from Cache into a_Values; take into account the even/odd offsets in a_Min:
+ for (int z = 0; z < SizeZ; ++z)
+ {
+ memcpy(a_Values + z * SizeX, cache + (z + (a_MinZ & 1)) * lowStepX + (a_MinX & 1), SizeX * sizeof(int));
+ }
+ }
+
+protected:
+ Underlying m_UnderlyingGen;
+};
+
+
+
+
+
+/** Smoothes out some artifacts generated by the zooming - mostly single-pixel values.
+Compares each pixel to its neighbors and if the neighbors are equal, changes the pixel to their value. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenSmooth :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+ static const int m_LowerSizeX = SizeX + 2;
+ static const int m_LowerSizeZ = SizeZ + 2;
+
+public:
+ typedef std::shared_ptr<cIntGen<m_LowerSizeX, m_LowerSizeZ>> Underlying;
+
+
+ cIntGenSmooth(int a_Seed, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying values:
+ int lowerData[m_LowerSizeX * m_LowerSizeZ];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerData);
+
+ // Smooth - for each square check if the surroundings are the same, if so, expand them diagonally.
+ // Also get rid of single-pixel irregularities (A-B-A):
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int NoiseZ = a_MinZ + z;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int val = lowerData[x + 1 + (z + 1) * m_LowerSizeX];
+ int above = lowerData[x + 1 + z * m_LowerSizeX];
+ int below = lowerData[x + 1 + (z + 2) * m_LowerSizeX];
+ int left = lowerData[x + (z + 1) * m_LowerSizeX];
+ int right = lowerData[x + 2 + (z + 1) * m_LowerSizeX];
+
+ if ((left == right) && (above == below))
+ {
+ if (((super::m_Noise.IntNoise2DInt(a_MinX + x, NoiseZ) / 7) % 2) == 0)
+ {
+ val = left;
+ }
+ else
+ {
+ val = above;
+ }
+ }
+ else
+ {
+ if (left == right)
+ {
+ val = left;
+ }
+
+ if (above == below)
+ {
+ val = above;
+ }
+ }
+
+ a_Values[x + z * SizeX] = val;
+ }
+ }
+ }
+
+protected:
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Converts land biomes at the edge of an ocean into the respective beach biome. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenBeaches :
+ public cIntGen<SizeX, SizeZ>
+{
+ typedef cIntGen<SizeX, SizeZ> super;
+ static const int m_UnderlyingSizeX = SizeX + 2;
+ static const int m_UnderlyingSizeZ = SizeZ + 2;
+
+public:
+ typedef std::shared_ptr<cIntGen<m_UnderlyingSizeX, m_UnderlyingSizeZ>> Underlying;
+
+
+ cIntGenBeaches(Underlying a_Underlying) :
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Map for biome -> its beach:
+ static const int ToBeach[] =
+ {
+ /* biOcean */ biOcean,
+ /* biPlains */ biBeach,
+ /* biDesert */ biBeach,
+ /* biExtremeHills */ biStoneBeach,
+ /* biForest */ biBeach,
+ /* biTaiga */ biColdBeach,
+ /* biSwampland */ biSwampland,
+ /* biRiver */ biRiver,
+ /* biNether */ biNether,
+ /* biEnd */ biEnd,
+ /* biFrozenOcean */ biColdBeach,
+ /* biFrozenRiver */ biColdBeach,
+ /* biIcePlains */ biColdBeach,
+ /* biIceMountains */ biColdBeach,
+ /* biMushroomIsland */ biMushroomShore,
+ /* biMushroomShore */ biMushroomShore,
+ /* biBeach */ biBeach,
+ /* biDesertHills */ biBeach,
+ /* biForestHills */ biBeach,
+ /* biTaigaHills */ biColdBeach,
+ /* biExtremeHillsEdge */ biStoneBeach,
+ /* biJungle */ biBeach,
+ /* biJungleHills */ biBeach,
+ /* biJungleEdge */ biBeach,
+ /* biDeepOcean */ biOcean,
+ /* biStoneBeach */ biStoneBeach,
+ /* biColdBeach */ biColdBeach,
+ /* biBirchForest */ biBeach,
+ /* biBirchForestHills */ biBeach,
+ /* biRoofedForest */ biBeach,
+ /* biColdTaiga */ biColdBeach,
+ /* biColdTaigaHills */ biColdBeach,
+ /* biMegaTaiga */ biStoneBeach,
+ /* biMegaTaigaHills */ biStoneBeach,
+ /* biExtremeHillsPlus */ biStoneBeach,
+ /* biSavanna */ biBeach,
+ /* biSavannaPlateau */ biBeach,
+ /* biMesa */ biMesa,
+ /* biMesaPlateauF */ biMesa,
+ /* biMesaPlateau */ biMesa,
+ };
+
+ // Generate the underlying values:
+ int lowerValues[m_UnderlyingSizeX * m_UnderlyingSizeZ];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerValues);
+
+ // Add beaches between ocean and biomes:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int val = lowerValues[x + 1 + (z + 1) * m_UnderlyingSizeX];
+ int above = lowerValues[x + 1 + z * m_UnderlyingSizeX];
+ int below = lowerValues[x + 1 + (z + 2) * m_UnderlyingSizeX];
+ int left = lowerValues[x + (z + 1) * m_UnderlyingSizeX];
+ int right = lowerValues[x + 2 + (z + 1) * m_UnderlyingSizeX];
+ if (!IsBiomeOcean(val))
+ {
+ if (IsBiomeOcean(above) || IsBiomeOcean(below) || IsBiomeOcean(left) || IsBiomeOcean(right))
+ {
+ // First convert the value to a regular biome (drop the M flag), then modulo by our biome count:
+ val = ToBeach[(val % 128) % ARRAYCOUNT(ToBeach)];
+ }
+ }
+ a_Values[x + z * SizeX] = val;
+ }
+ }
+ }
+
+protected:
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Generates the underlying numbers and then randomly changes some ocean group pixels into random land
+biome group pixels, based on the predefined chance. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenAddIslands :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying;
+
+
+ cIntGenAddIslands(int a_Seed, int a_Chance, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Chance(a_Chance),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_Values);
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ if (a_Values[x + z * SizeX] == bgOcean)
+ {
+ int rnd = super::m_Noise.IntNoise2DInt(a_MinX + x, a_MinZ + z) / 7;
+ if (rnd % 1000 < m_Chance)
+ {
+ a_Values[x + z * SizeX] = (rnd / 1003) % bgLandOceanMax;
+ }
+ }
+ } // for x
+ } // for z
+ }
+
+protected:
+ /** Chance, in permille, of an island being generated in ocean. */
+ int m_Chance;
+
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** A filter that adds an edge biome group between two biome groups that need an edge between them. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenBiomeGroupEdges :
+ public cIntGen<SizeX, SizeZ>
+{
+ typedef cIntGen<SizeX, SizeZ> super;
+
+ static const int m_UnderlyingSizeX = SizeX + 2;
+ static const int m_UnderlyingSizeZ = SizeZ + 2;
+
+public:
+
+ typedef std::shared_ptr<cIntGen<m_UnderlyingSizeX, m_UnderlyingSizeZ>> Underlying;
+
+ cIntGenBiomeGroupEdges(Underlying a_Underlying) :
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values)
+ {
+ // Generate the underlying biome groups:
+ int lowerValues[m_UnderlyingSizeX * m_UnderlyingSizeZ];
+ m_Underlying->GetInts(a_MinX, a_MinZ, lowerValues);
+
+ // Change the biomes on incompatible edges into an edge biome:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int val = lowerValues[x + 1 + (z + 1) * m_UnderlyingSizeX];
+ int above = lowerValues[x + 1 + z * m_UnderlyingSizeX];
+ int below = lowerValues[x + 1 + (z + 2) * m_UnderlyingSizeX];
+ int left = lowerValues[x + (z + 1) * m_UnderlyingSizeX];
+ int right = lowerValues[x + 2 + (z + 1) * m_UnderlyingSizeX];
+ switch (val)
+ {
+ // Desert should neighbor only oceans, desert and temperates; change to temperate when another:
+ case bgDesert:
+ {
+ if (
+ !isDesertCompatible(above) ||
+ !isDesertCompatible(below) ||
+ !isDesertCompatible(left) ||
+ !isDesertCompatible(right)
+ )
+ {
+ val = bgTemperate;
+ }
+ break;
+ } // case bgDesert
+
+ // Ice should not neighbor deserts; change to temperate:
+ case bgIce:
+ {
+ if (
+ (above == bgDesert) ||
+ (below == bgDesert) ||
+ (left == bgDesert) ||
+ (right == bgDesert)
+ )
+ {
+ val = bgTemperate;
+ }
+ break;
+ } // case bgIce
+ }
+ a_Values[x + z * SizeX] = val;
+ } // for x
+ } // for z
+ }
+
+protected:
+ Underlying m_Underlying;
+
+
+ inline bool isDesertCompatible(int a_BiomeGroup)
+ {
+ switch (a_BiomeGroup)
+ {
+ case bgOcean:
+ case bgDesert:
+ case bgTemperate:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
+};
+
+
+
+
+
+/** Turns biome group indices into real biomes.
+For each pixel, takes its biome group and chooses a random biome from that group; replaces the value with
+that biome. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenBiomes :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying;
+
+
+ cIntGenBiomes(int a_Seed, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Define the per-biome-group biomes:
+ static const int oceanBiomes[] =
+ {
+ biOcean, // biDeepOcean,
+ };
+
+ // Same as oceanBiomes, there are no rare oceanic biomes (mushroom islands are handled separately)
+ static const int rareOceanBiomes[] =
+ {
+ biOcean,
+ };
+
+ static const int desertBiomes[] =
+ {
+ biDesert, biDesert, biDesert, biDesert, biDesert, biDesert, biSavanna, biSavanna, biPlains,
+ };
+
+ static const int rareDesertBiomes[] =
+ {
+ biMesaPlateau, biMesaPlateauF,
+ };
+
+ static const int temperateBiomes[] =
+ {
+ biForest, biForest, biRoofedForest, biExtremeHills, biPlains, biBirchForest, biSwampland,
+ };
+
+ static const int rareTemperateBiomes[] =
+ {
+ biJungle, // Jungle is not strictly temperate, but let's piggyback it here
+ };
+
+ static const int mountainBiomes[] =
+ {
+ biExtremeHills, biForest, biTaiga, biPlains,
+ };
+
+ static const int rareMountainBiomes[] =
+ {
+ biMegaTaiga,
+ };
+
+ static const int iceBiomes[] =
+ {
+ biIcePlains, biIcePlains, biIcePlains, biIcePlains, biColdTaiga,
+ };
+
+ // Same as iceBiomes, there's no rare ice biome
+ static const int rareIceBiomes[] =
+ {
+ biIcePlains, biIcePlains, biIcePlains, biIcePlains, biColdTaiga,
+ };
+
+ static const cBiomesInGroups biomesInGroups[] =
+ {
+ /* bgOcean */ { static_cast<int>(ARRAYCOUNT(oceanBiomes)), oceanBiomes},
+ /* bgDesert */ { static_cast<int>(ARRAYCOUNT(desertBiomes)), desertBiomes},
+ /* bgTemperate */ { static_cast<int>(ARRAYCOUNT(temperateBiomes)), temperateBiomes},
+ /* bgMountains */ { static_cast<int>(ARRAYCOUNT(mountainBiomes)), mountainBiomes},
+ /* bgIce */ { static_cast<int>(ARRAYCOUNT(iceBiomes)), iceBiomes},
+ };
+
+ static const cBiomesInGroups rareBiomesInGroups[] =
+ {
+ /* bgOcean */ { static_cast<int>(ARRAYCOUNT(rareOceanBiomes)), rareOceanBiomes},
+ /* bgDesert */ { static_cast<int>(ARRAYCOUNT(rareDesertBiomes)), rareDesertBiomes},
+ /* bgTemperate */ { static_cast<int>(ARRAYCOUNT(rareTemperateBiomes)), rareTemperateBiomes},
+ /* bgMountains */ { static_cast<int>(ARRAYCOUNT(rareMountainBiomes)), rareMountainBiomes},
+ /* bgIce */ { static_cast<int>(ARRAYCOUNT(rareIceBiomes)), rareIceBiomes},
+ };
+
+ // Generate the underlying values, representing biome groups:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_Values);
+
+ // Overwrite each biome group with a random biome from that group:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int IdxZ = z * SizeX;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int val = a_Values[x + IdxZ];
+ const cBiomesInGroups & Biomes = (val > bgfRare) ?
+ rareBiomesInGroups[(val & (bgfRare - 1)) % ARRAYCOUNT(rareBiomesInGroups)] :
+ biomesInGroups[val % ARRAYCOUNT(biomesInGroups)];
+ int rnd = (super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7);
+ a_Values[x + IdxZ] = Biomes.Biomes[rnd % Biomes.Count];
+ }
+ }
+ }
+
+protected:
+
+ struct cBiomesInGroups
+ {
+ const int Count;
+ const int * Biomes;
+ };
+
+
+ /** The underlying int generator */
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Randomly replaces pixels of one value to another value, using the given chance. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenReplaceRandomly :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying;
+
+
+ cIntGenReplaceRandomly(int a_From, int a_To, int a_Chance, int a_Seed, Underlying a_Underlying) :
+ super(a_Seed),
+ m_From(a_From),
+ m_To(a_To),
+ m_Chance(a_Chance),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying values:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_Values);
+
+ // Replace some of the values:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int idxZ = z * SizeX;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int idx = x + idxZ;
+ if (a_Values[idx] == m_From)
+ {
+ int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7;
+ if (rnd % 1000 < m_Chance)
+ {
+ a_Values[idx] = m_To;
+ }
+ }
+ }
+ } // for z
+ }
+
+
+protected:
+ /** The original value to be replaced. */
+ int m_From;
+
+ /** The destination value to which to replace. */
+ int m_To;
+
+ /** Chance, in permille, of replacing the value. */
+ int m_Chance;
+
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Mixer that joins together finalized biomes and rivers.
+It first checks for oceans, if there is an ocean in the Biomes, it keeps the ocean.
+If there's no ocean, it checks Rivers for a river, if there is a river, it uses the Biomes to select either
+regular river or frozen river, based on the biome. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenMixRivers:
+ public cIntGen<SizeX, SizeZ>
+{
+ typedef cIntGen<SizeX, SizeZ> super;
+
+public:
+ typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying;
+
+
+ cIntGenMixRivers(Underlying a_Biomes, Underlying a_Rivers):
+ m_Biomes(a_Biomes),
+ m_Rivers(a_Rivers)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying data:
+ m_Biomes->GetInts(a_MinX, a_MinZ, a_Values);
+ typename super::Values riverData;
+ m_Rivers->GetInts(a_MinX, a_MinZ, riverData);
+
+ // Mix the values:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int idxZ = z * SizeX;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int idx = x + idxZ;
+ if (IsBiomeOcean(a_Values[idx]))
+ {
+ // Oceans are kept without any changes
+ continue;
+ }
+ if (riverData[idx] != biRiver)
+ {
+ // There's no river, keep the current value
+ continue;
+ }
+
+ // There's a river, change the output to a river or a frozen river, based on the original biome:
+ if (IsBiomeVeryCold((EMCSBiome)a_Values[idx]))
+ {
+ a_Values[idx] = biFrozenRiver;
+ }
+ else
+ {
+ a_Values[idx] = biRiver;
+ }
+ } // for x
+ } // for z
+ }
+
+protected:
+ Underlying m_Biomes;
+ Underlying m_Rivers;
+};
+
+
+
+
+
+/** Generates a river based on the underlying data.
+This is basically an edge detector over the underlying data. The rivers are the edges where the underlying data
+changes from one pixel to its neighbor. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenRiver:
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+ static const int UnderlyingSizeX = SizeX + 2;
+ static const int UnderlyingSizeZ = SizeZ + 2;
+
+public:
+ typedef std::shared_ptr<cIntGen<UnderlyingSizeX, UnderlyingSizeZ>> Underlying;
+
+
+ cIntGenRiver(int a_Seed, Underlying a_Underlying):
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying data:
+ int Cache[UnderlyingSizeX * UnderlyingSizeZ];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, Cache);
+
+ // Detect the edges:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int Above = Cache[x + 1 + z * UnderlyingSizeX];
+ int Below = Cache[x + 1 + (z + 2) * UnderlyingSizeX];
+ int Left = Cache[x + (z + 1) * UnderlyingSizeX];
+ int Right = Cache[x + 2 + (z + 1) * UnderlyingSizeX];
+ int val = Cache[x + 1 + (z + 1) * UnderlyingSizeX];
+
+ if ((val == Above) && (val == Below) && (val == Left) && (val == Right))
+ {
+ val = 0;
+ }
+ else
+ {
+ val = biRiver;
+ }
+ a_Values[x + z * SizeX] = val;
+ } // for x
+ } // for z
+ }
+
+protected:
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Turns some of the oceans into the specified biome. Used for mushroom and deep ocean.
+The biome is only placed if at least 3 of its neighbors are ocean and only with the specified chance. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenAddToOcean:
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+ static const int UnderlyingSizeX = SizeX + 2;
+ static const int UnderlyingSizeZ = SizeZ + 2;
+
+public:
+ typedef std::shared_ptr<cIntGen<UnderlyingSizeX, UnderlyingSizeZ>> Underlying;
+
+
+ cIntGenAddToOcean(int a_Seed, int a_Chance, int a_ToValue, Underlying a_Underlying):
+ super(a_Seed),
+ m_Chance(a_Chance),
+ m_ToValue(a_ToValue),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying data:
+ int Cache[UnderlyingSizeX * UnderlyingSizeZ];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, Cache);
+
+ // Add the mushroom islands:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int val = Cache[x + 1 + (z + 1) * UnderlyingSizeX];
+ if (!IsBiomeOcean(val))
+ {
+ a_Values[x + z * SizeX] = val;
+ continue;
+ }
+
+ // Count the ocean neighbors:
+ int Above = Cache[x + 1 + z * UnderlyingSizeX];
+ int Below = Cache[x + 1 + (z + 2) * UnderlyingSizeX];
+ int Left = Cache[x + (z + 1) * UnderlyingSizeX];
+ int Right = Cache[x + 2 + (z + 1) * UnderlyingSizeX];
+ int NumOceanNeighbors = 0;
+ if (IsBiomeOcean(Above))
+ {
+ NumOceanNeighbors += 1;
+ }
+ if (IsBiomeOcean(Below))
+ {
+ NumOceanNeighbors += 1;
+ }
+ if (IsBiomeOcean(Left))
+ {
+ NumOceanNeighbors += 1;
+ }
+ if (IsBiomeOcean(Right))
+ {
+ NumOceanNeighbors += 1;
+ }
+
+ // If at least 3 ocean neighbors and the chance is right, change:
+ if (
+ (NumOceanNeighbors >= 3) &&
+ ((super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7) % 1000 < m_Chance)
+ )
+ {
+ a_Values[x + z * SizeX] = m_ToValue;
+ }
+ else
+ {
+ a_Values[x + z * SizeX] = val;
+ }
+ } // for x
+ } // for z
+ }
+
+protected:
+ /** Chance, in permille, of changing the biome. */
+ int m_Chance;
+
+ /** The value to change the ocean into. */
+ int m_ToValue;
+
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Changes random pixels of the underlying data to the specified value. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenSetRandomly :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying;
+
+ cIntGenSetRandomly(int a_Seed, int a_Chance, int a_ToValue, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Chance(a_Chance),
+ m_ToValue(a_ToValue),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying data:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_Values);
+
+ // Change random pixels to bgOcean:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7;
+ if (rnd % 1000 < m_Chance)
+ {
+ a_Values[x + z * SizeX] = m_ToValue;
+ }
+ }
+ }
+ }
+
+protected:
+ /** Chance, in permille, of changing each pixel. */
+ int m_Chance;
+
+ /** The value to which to set the pixel. */
+ int m_ToValue;
+
+ Underlying m_Underlying;
+};
+
+
+
+
+
+
+/** Adds a "rare" flag to random biome groups, based on the given chance. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenRareBiomeGroups:
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying;
+
+
+ cIntGenRareBiomeGroups(int a_Seed, int a_Chance, Underlying a_Underlying):
+ super(a_Seed),
+ m_Chance(a_Chance),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying data:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_Values);
+
+ // Change some of the biome groups into rare biome groups:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7;
+ if (rnd % 1000 < m_Chance)
+ {
+ int idx = x + SizeX * z;
+ a_Values[idx] = a_Values[idx] | bgfRare;
+ }
+ }
+ }
+ }
+
+protected:
+ /** Chance, in permille, of changing each pixel into the rare biome group. */
+ int m_Chance;
+
+ /** The underlying generator. */
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Changes biomes in the parent data into an alternate versions (usually "hill" variants), in such places
+that have their alterations set. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenAlternateBiomes:
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying;
+
+
+ cIntGenAlternateBiomes(int a_Seed, Underlying a_Alterations, Underlying a_BaseBiomes):
+ super(a_Seed),
+ m_Alterations(a_Alterations),
+ m_BaseBiomes(a_BaseBiomes)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the base biomes and the alterations:
+ m_BaseBiomes->GetInts(a_MinX, a_MinZ, a_Values);
+ typename super::Values alterations;
+ m_Alterations->GetInts(a_MinX, a_MinZ, alterations);
+
+ // Change the biomes into their alternate versions:
+ for (int idx = 0; idx < SizeX * SizeZ; ++idx)
+ {
+ if (alterations[idx] == 0)
+ {
+ // No change
+ continue;
+ }
+
+ // Change to alternate biomes:
+ int val = a_Values[idx];
+ switch (val)
+ {
+ case biBirchForest: val = biBirchForestHills; break;
+ case biDesert: val = biDesertHills; break;
+ case biExtremeHills: val = biExtremeHillsPlus; break;
+ case biForest: val = biForestHills; break;
+ case biIcePlains: val = biIceMountains; break;
+ case biJungle: val = biJungleHills; break;
+ case biMegaTaiga: val = biMegaTaigaHills; break;
+ case biMesaPlateau: val = biMesa; break;
+ case biMesaPlateauF: val = biMesa; break;
+ case biMesaPlateauM: val = biMesa; break;
+ case biMesaPlateauFM: val = biMesa; break;
+ case biPlains: val = biForest; break;
+ case biRoofedForest: val = biPlains; break;
+ case biSavanna: val = biSavannaPlateau; break;
+ case biTaiga: val = biTaigaHills; break;
+ }
+ a_Values[idx] = val;
+ } // for idx - a_Values[]
+ }
+
+protected:
+ Underlying m_Alterations;
+ Underlying m_BaseBiomes;
+};
+
+
+
+
+
+/** Adds an edge between two specifically incompatible biomes, such as mesa and forest. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenBiomeEdges:
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+ static const int m_LowerSizeX = SizeX + 2;
+ static const int m_LowerSizeZ = SizeZ + 2;
+
+public:
+ typedef std::shared_ptr<cIntGen<m_LowerSizeX, m_LowerSizeZ>> Underlying;
+
+
+ cIntGenBiomeEdges(int a_Seed, Underlying a_Underlying):
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying biomes:
+ typename Underlying::element_type::Values lowerValues;
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerValues);
+
+ // Convert incompatible edges into neutral biomes:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int biome = lowerValues[x + 1 + (z + 1) * m_LowerSizeX];
+ int above = lowerValues[x + 1 + z * m_LowerSizeX];
+ int below = lowerValues[x + 1 + (z + 2) * m_LowerSizeX];
+ int left = lowerValues[x + (z + 1) * m_LowerSizeX];
+ int right = lowerValues[x + 2 + (z + 1) * m_LowerSizeX];
+
+ switch (biome)
+ {
+ case biDesert:
+ case biDesertM:
+ case biDesertHills:
+ {
+ if (
+ IsBiomeVeryCold(static_cast<EMCSBiome>(above)) ||
+ IsBiomeVeryCold(static_cast<EMCSBiome>(below)) ||
+ IsBiomeVeryCold(static_cast<EMCSBiome>(left)) ||
+ IsBiomeVeryCold(static_cast<EMCSBiome>(right))
+ )
+ {
+ biome = biPlains;
+ }
+ break;
+ } // case biDesert
+
+ case biMesaPlateau:
+ case biMesaPlateauF:
+ case biMesaPlateauFM:
+ case biMesaPlateauM:
+ {
+ if (
+ !isMesaCompatible(above) ||
+ !isMesaCompatible(below) ||
+ !isMesaCompatible(left) ||
+ !isMesaCompatible(right)
+ )
+ {
+ biome = biDesert;
+ }
+ break;
+ } // Mesa biomes
+
+ case biJungle:
+ case biJungleM:
+ {
+ if (
+ !isJungleCompatible(above) ||
+ !isJungleCompatible(below) ||
+ !isJungleCompatible(left) ||
+ !isJungleCompatible(right)
+ )
+ {
+ biome = (biome == biJungle) ? biJungleEdge : biJungleEdgeM;
+ }
+ break;
+ } // Jungle biomes
+
+ case biSwampland:
+ case biSwamplandM:
+ {
+ if (
+ IsBiomeNoDownfall(static_cast<EMCSBiome>(above)) ||
+ IsBiomeNoDownfall(static_cast<EMCSBiome>(below)) ||
+ IsBiomeNoDownfall(static_cast<EMCSBiome>(left)) ||
+ IsBiomeNoDownfall(static_cast<EMCSBiome>(right))
+ )
+ {
+ biome = biPlains;
+ }
+ break;
+ } // Swampland biomes
+ } // switch (biome)
+
+ a_Values[x + z * SizeX] = biome;
+ } // for x
+ } // for z
+ }
+
+
+protected:
+ Underlying m_Underlying;
+
+
+ bool isMesaCompatible(int a_Biome)
+ {
+ switch (a_Biome)
+ {
+ case biDesert:
+ case biMesa:
+ case biMesaBryce:
+ case biMesaPlateau:
+ case biMesaPlateauF:
+ case biMesaPlateauFM:
+ case biMesaPlateauM:
+ case biOcean:
+ case biDeepOcean:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
+
+
+ bool isJungleCompatible(int a_Biome)
+ {
+ switch (a_Biome)
+ {
+ case biJungle:
+ case biJungleM:
+ case biJungleEdge:
+ case biJungleEdgeM:
+ case biJungleHills:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
+};
+
+
+
+
+
+/** Changes biomes in the parent data into their alternate versions ("M" variants), in such places that
+have their alterations set. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenMBiomes:
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying;
+
+
+ cIntGenMBiomes(int a_Seed, Underlying a_Alteration, Underlying a_Underlying):
+ super(a_Seed),
+ m_Underlying(a_Underlying),
+ m_Alteration(a_Alteration)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override
+ {
+ // Generate the underlying biomes and the alterations:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_Values);
+ typename super::Values alterations;
+ m_Alteration->GetInts(a_MinX, a_MinZ, alterations);
+
+ // Wherever alterations are nonzero, change into alternate biome, if available:
+ for (int idx = 0; idx < SizeX * SizeZ; ++idx)
+ {
+ if (alterations[idx] == 0)
+ {
+ continue;
+ }
+
+ // Ice spikes biome was removed from here, because it was generated way too often
+ switch (a_Values[idx])
+ {
+ case biPlains: a_Values[idx] = biSunflowerPlains; break;
+ case biDesert: a_Values[idx] = biDesertM; break;
+ case biExtremeHills: a_Values[idx] = biExtremeHillsM; break;
+ case biForest: a_Values[idx] = biFlowerForest; break;
+ case biTaiga: a_Values[idx] = biTaigaM; break;
+ case biSwampland: a_Values[idx] = biSwamplandM; break;
+ case biJungle: a_Values[idx] = biJungleM; break;
+ case biJungleEdge: a_Values[idx] = biJungleEdgeM; break;
+ case biBirchForest: a_Values[idx] = biBirchForestM; break;
+ case biBirchForestHills: a_Values[idx] = biBirchForestHillsM; break;
+ case biRoofedForest: a_Values[idx] = biRoofedForestM; break;
+ case biColdTaiga: a_Values[idx] = biColdTaigaM; break;
+ case biMegaSpruceTaiga: a_Values[idx] = biMegaSpruceTaiga; break;
+ case biMegaSpruceTaigaHills: a_Values[idx] = biMegaSpruceTaigaHills; break;
+ case biExtremeHillsPlus: a_Values[idx] = biExtremeHillsPlusM; break;
+ case biSavanna: a_Values[idx] = biSavannaM; break;
+ case biSavannaPlateau: a_Values[idx] = biSavannaPlateauM; break;
+ case biMesa: a_Values[idx] = biMesaBryce; break;
+ case biMesaPlateauF: a_Values[idx] = biMesaPlateauFM; break;
+ case biMesaPlateau: a_Values[idx] = biMesaBryce; break;
+ }
+ } // for idx - a_Values[] / alterations[]
+ }
+
+protected:
+ Underlying m_Underlying;
+ Underlying m_Alteration;
+};
+
+
+
+
diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp
index 0532aff39..55b3b64dd 100644
--- a/src/Generating/MineShafts.cpp
+++ b/src/Generating/MineShafts.cpp
@@ -112,7 +112,7 @@ class cMineShaftCorridor :
public:
/** Creates a new Corridor attached to the specified pivot point and direction.
Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit.
- May return NULL if cannot fit.
+ May return nullptr if cannot fit.
*/
static cMineShaft * CreateAndFit(
cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
@@ -165,7 +165,7 @@ class cMineShaftCrossing :
public:
/** Creates a new Crossing attached to the specified pivot point and direction.
Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit.
- May return NULL if cannot fit.
+ May return nullptr if cannot fit.
*/
static cMineShaft * CreateAndFit(
cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
@@ -199,7 +199,7 @@ public:
/** Creates a new Staircase attached to the specified pivot point and direction.
Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit.
- May return NULL if cannot fit.
+ May return nullptr if cannot fit.
*/
static cMineShaft * CreateAndFit(
cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
@@ -351,7 +351,7 @@ void cStructGenMineShafts::cMineShaftSystem::AppendBranch(
return;
}
- cMineShaft * Next = NULL;
+ cMineShaft * Next = nullptr;
int rnd = (a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_RecursionLevel * 16, a_PivotZ) / 13) % m_ProbLevelStaircase;
if (rnd < m_ProbLevelCorridor)
{
@@ -365,7 +365,7 @@ void cStructGenMineShafts::cMineShaftSystem::AppendBranch(
{
Next = cMineShaftStaircase::CreateAndFit(*this, a_PivotX, a_PivotY, a_PivotZ, a_Direction, a_Noise);
}
- if (Next == NULL)
+ if (Next == nullptr)
{
return;
}
@@ -552,7 +552,7 @@ cMineShaft * cMineShaftCorridor::CreateAndFit(
}
if (!a_ParentSystem.CanAppend(BoundingBox))
{
- return NULL;
+ return nullptr;
}
return new cMineShaftCorridor(a_ParentSystem, BoundingBox, NumSegments, a_Direction, a_Noise);
}
@@ -796,7 +796,7 @@ void cMineShaftCorridor::PlaceChest(cChunkDesc & a_ChunkDesc)
{
a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p1.y + 1, z, E_BLOCK_CHEST, Meta);
cChestEntity * ChestEntity = (cChestEntity *)a_ChunkDesc.GetBlockEntity(x, m_BoundingBox.p1.y + 1, z);
- ASSERT((ChestEntity != NULL) && (ChestEntity->GetBlockType() == E_BLOCK_CHEST));
+ ASSERT((ChestEntity != nullptr) && (ChestEntity->GetBlockType() == E_BLOCK_CHEST));
cNoise Noise(a_ChunkDesc.GetChunkX() ^ a_ChunkDesc.GetChunkZ());
int NumSlots = 3 + ((Noise.IntNoise3DInt(x, m_BoundingBox.p1.y, z) / 11) % 4);
int Seed = Noise.IntNoise2DInt(x, z);
@@ -1006,7 +1006,7 @@ cMineShaft * cMineShaftCrossing::CreateAndFit(
}
if (!a_ParentSystem.CanAppend(BoundingBox))
{
- return NULL;
+ return nullptr;
}
return new cMineShaftCrossing(a_ParentSystem, BoundingBox);
}
@@ -1157,7 +1157,7 @@ cMineShaft * cMineShaftStaircase::CreateAndFit(
}
if (!a_ParentSystem.CanAppend(Box))
{
- return NULL;
+ return nullptr;
}
return new cMineShaftStaircase(a_ParentSystem, Box, a_Direction, Slope);
}
diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp
index c3ca30384..f2af75999 100644
--- a/src/Generating/Noise3DGenerator.cpp
+++ b/src/Generating/Noise3DGenerator.cpp
@@ -6,7 +6,7 @@
#include "Globals.h"
#include "Noise3DGenerator.h"
#include "../OSSupport/File.h"
-#include "inifile/iniFile.h"
+#include "../IniFile.h"
#include "../LinearInterpolation.h"
#include "../LinearUpscale.h"
@@ -61,6 +61,35 @@ public:
+/** Linearly interpolates between two values.
+Assumes that a_Ratio is in range [0, 1]. */
+inline static NOISE_DATATYPE Lerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio)
+{
+ return a_Val1 + (a_Val2 - a_Val1) * a_Ratio;
+}
+
+
+
+
+
+/** Linearly interpolates between two values, clamping the ratio to [0, 1] first. */
+inline static NOISE_DATATYPE ClampedLerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio)
+{
+ if (a_Ratio < 0)
+ {
+ return a_Val1;
+ }
+ if (a_Ratio > 1)
+ {
+ return a_Val2;
+ }
+ return Lerp(a_Val1, a_Val2, a_Ratio);
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// cNoise3DGenerator:
@@ -346,9 +375,10 @@ void cNoise3DGenerator::ComposeTerrain(cChunkDesc & a_ChunkDesc)
// cNoise3DComposable:
cNoise3DComposable::cNoise3DComposable(int a_Seed) :
- m_Noise1(a_Seed + 1000),
- m_Noise2(a_Seed + 2000),
- m_Noise3(a_Seed + 3000)
+ m_ChoiceNoise(a_Seed),
+ m_DensityNoiseA(a_Seed + 1),
+ m_DensityNoiseB(a_Seed + 2),
+ m_BaseNoise(a_Seed + 3)
{
}
@@ -359,13 +389,51 @@ cNoise3DComposable::cNoise3DComposable(int a_Seed) :
void cNoise3DComposable::Initialize(cIniFile & a_IniFile)
{
// Params:
+ // The defaults generate extreme hills terrain
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62);
- m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0);
+ m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0.045);
m_MidPoint = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DMidPoint", 75);
- m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 10);
- m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyY", 10);
- m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyZ", 10);
- m_AirThreshold = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DAirThreshold", 0.5);
+ m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 40);
+ m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyY", 40);
+ m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyZ", 40);
+ m_BaseFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DBaseFrequencyX", 40);
+ m_BaseFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DBaseFrequencyZ", 40);
+ m_ChoiceFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DChoiceFrequencyX", 40);
+ m_ChoiceFrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DChoiceFrequencyY", 80);
+ m_ChoiceFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DChoiceFrequencyZ", 40);
+ m_AirThreshold = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DAirThreshold", 0);
+ int NumChoiceOctaves = a_IniFile.GetValueSetI("Generator", "Noise3DNumChoiceOctaves", 4);
+ int NumDensityOctaves = a_IniFile.GetValueSetI("Generator", "Noise3DNumDensityOctaves", 6);
+ int NumBaseOctaves = a_IniFile.GetValueSetI("Generator", "Noise3DNumBaseOctaves", 6);
+ NOISE_DATATYPE BaseNoiseAmplitude = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DBaseAmplitude", 1);
+
+ // Add octaves for the choice noise:
+ NOISE_DATATYPE wavlen = 1, ampl = 0.5;
+ for (int i = 0; i < NumChoiceOctaves; i++)
+ {
+ m_ChoiceNoise.AddOctave(wavlen, ampl);
+ wavlen = wavlen * 2;
+ ampl = ampl / 2;
+ }
+
+ // Add octaves for the density noises:
+ wavlen = 1, ampl = 1;
+ for (int i = 0; i < NumDensityOctaves; i++)
+ {
+ m_DensityNoiseA.AddOctave(wavlen, ampl);
+ m_DensityNoiseB.AddOctave(wavlen, ampl);
+ wavlen = wavlen * 2;
+ ampl = ampl / 2;
+ }
+
+ // Add octaves for the base noise:
+ wavlen = 1, ampl = BaseNoiseAmplitude;
+ for (int i = 0; i < NumBaseOctaves; i++)
+ {
+ m_BaseNoise.AddOctave(wavlen, ampl);
+ wavlen = wavlen * 2;
+ ampl = ampl / 2;
+ }
}
@@ -376,126 +444,399 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
{
if ((a_ChunkX == m_LastChunkX) && (a_ChunkZ == m_LastChunkZ))
{
- // The noise for this chunk is already generated in m_Noise
+ // The noise for this chunk is already generated in m_NoiseArray
return;
}
m_LastChunkX = a_ChunkX;
m_LastChunkZ = a_ChunkZ;
- // Upscaling parameters:
- const int UPSCALE_X = 8;
- const int UPSCALE_Y = 4;
- const int UPSCALE_Z = 8;
-
- // Precalculate a "height" array:
- NOISE_DATATYPE Height[17 * 17]; // x + 17 * z
- for (int z = 0; z < 17; z += UPSCALE_Z)
+ // Generate all the noises:
+ NOISE_DATATYPE ChoiceNoise[5 * 5 * 33];
+ NOISE_DATATYPE Workspace[5 * 5 * 33];
+ NOISE_DATATYPE DensityNoiseA[5 * 5 * 33];
+ NOISE_DATATYPE DensityNoiseB[5 * 5 * 33];
+ NOISE_DATATYPE BaseNoise[5 * 5];
+ NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width);
+ NOISE_DATATYPE BlockZ = static_cast<NOISE_DATATYPE>(a_ChunkZ * cChunkDef::Width);
+ // Note that we have to swap the coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "z":
+ m_ChoiceNoise.Generate3D (ChoiceNoise, 5, 5, 33, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, 0, 257 / m_ChoiceFrequencyY, Workspace);
+ m_DensityNoiseA.Generate3D(DensityNoiseA, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
+ m_DensityNoiseB.Generate3D(DensityNoiseB, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
+ m_BaseNoise.Generate2D (BaseNoise, 5, 5, BlockX / m_BaseFrequencyX, (BlockX + 17) / m_BaseFrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
+
+ // Calculate the final noise based on the partial noises:
+ for (int y = 0; y < 33; y++)
{
- NOISE_DATATYPE NoiseZ = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + z)) / m_FrequencyZ;
- for (int x = 0; x < 17; x += UPSCALE_X)
+ NOISE_DATATYPE AddHeight = (static_cast<NOISE_DATATYPE>(y * 8) - m_MidPoint) * m_HeightAmplification;
+
+ // If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope:
+ if (AddHeight < 0)
{
- NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX;
- NOISE_DATATYPE val = std::abs(m_Noise1.CubicNoise2D(NoiseX / 5, NoiseZ / 5)) * m_HeightAmplification + 1;
- Height[x + 17 * z] = val * val * val;
+ AddHeight *= 4;
}
- }
- for (int y = 0; y < 257; y += UPSCALE_Y)
- {
- NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)y) / m_FrequencyY;
- NOISE_DATATYPE AddHeight = (y - m_MidPoint) / 20;
- AddHeight *= AddHeight * AddHeight;
- NOISE_DATATYPE * CurFloor = &(m_NoiseArray[y * 17 * 17]);
- for (int z = 0; z < 17; z += UPSCALE_Z)
+ for (int z = 0; z < 5; z++)
{
- NOISE_DATATYPE NoiseZ = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + z)) / m_FrequencyZ;
- for (int x = 0; x < 17; x += UPSCALE_X)
+ for (int x = 0; x < 5; x++)
{
- NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX;
- CurFloor[x + 17 * z] = (
- m_Noise1.CubicNoise3D(NoiseX, NoiseY, NoiseZ) * (NOISE_DATATYPE)0.5 +
- m_Noise2.CubicNoise3D(NoiseX / 2, NoiseY / 2, NoiseZ / 2) +
- m_Noise3.CubicNoise3D(NoiseX / 4, NoiseY / 4, NoiseZ / 4) * 2 +
- AddHeight / Height[x + 17 * z]
- );
+ int idx = x + 5 * z + 5 * 5 * y;
+ Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[x + 5 * z];
}
}
- // Linear-interpolate this XZ floor:
- LinearUpscale2DArrayInPlace<17, 17, UPSCALE_X, UPSCALE_Z>(CurFloor);
}
+ LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8);
+}
+
+
- // Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis
- for (int y = 1; y < cChunkDef::Height; y++)
+
+
+void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
+{
+ GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
+
+ for (int z = 0; z < cChunkDef::Width; z++)
{
- if ((y % UPSCALE_Y) == 0)
+ for (int x = 0; x < cChunkDef::Width; x++)
{
- // This is the interpolation source floor, already calculated
- continue;
- }
- int LoFloorY = (y / UPSCALE_Y) * UPSCALE_Y;
- int HiFloorY = LoFloorY + UPSCALE_Y;
- NOISE_DATATYPE * LoFloor = &(m_NoiseArray[LoFloorY * 17 * 17]);
- NOISE_DATATYPE * HiFloor = &(m_NoiseArray[HiFloorY * 17 * 17]);
- NOISE_DATATYPE * CurFloor = &(m_NoiseArray[y * 17 * 17]);
- NOISE_DATATYPE Ratio = ((NOISE_DATATYPE)(y % UPSCALE_Y)) / UPSCALE_Y;
- int idx = 0;
- for (int z = 0; z < cChunkDef::Width; z++)
+ cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel);
+ for (int y = cChunkDef::Height - 1; y > m_SeaLevel; y--)
+ {
+ if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= m_AirThreshold)
+ {
+ cChunkDef::SetHeight(a_HeightMap, x, z, y);
+ break;
+ }
+ } // for y
+ } // for x
+ } // for z
+}
+
+
+
+
+
+void cNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
+{
+ GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
+
+ a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
+
+ // Make basic terrain composition:
+ for (int z = 0; z < cChunkDef::Width; z++)
+ {
+ for (int x = 0; x < cChunkDef::Width; x++)
{
- for (int x = 0; x < cChunkDef::Width; x++)
+ int LastAir = a_ChunkDesc.GetHeight(x, z) + 1;
+ bool HasHadWater = false;
+ for (int y = LastAir; y < m_SeaLevel; y++)
{
- CurFloor[idx] = LoFloor[idx] + (HiFloor[idx] - LoFloor[idx]) * Ratio;
- idx += 1;
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
}
- idx += 1; // Skipping one X column
+ for (int y = LastAir - 1; y > 0; y--)
+ {
+ if (m_NoiseArray[x + 17 * z + 17 * 17 * y] > m_AirThreshold)
+ {
+ // "air" part
+ LastAir = y;
+ if (y < m_SeaLevel)
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
+ HasHadWater = true;
+ }
+ continue;
+ }
+ // "ground" part:
+ if (LastAir - y > 4)
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STONE);
+ continue;
+ }
+ if (HasHadWater)
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_SAND);
+ }
+ else
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, (LastAir == y + 1) ? E_BLOCK_GRASS : E_BLOCK_DIRT);
+ }
+ } // for y
+ a_ChunkDesc.SetBlockType(x, 0, z, E_BLOCK_BEDROCK);
+ } // for x
+ } // for z
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cBiomalNoise3DComposable:
+
+cBiomalNoise3DComposable::cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_BiomeGen) :
+ m_ChoiceNoise(a_Seed),
+ m_DensityNoiseA(a_Seed + 1),
+ m_DensityNoiseB(a_Seed + 2),
+ m_BaseNoise(a_Seed + 3),
+ m_BiomeGen(a_BiomeGen)
+{
+ // Generate the weight distribution for summing up neighboring biomes:
+ m_WeightSum = 0;
+ for (int z = 0; z <= AVERAGING_SIZE * 2; z++)
+ {
+ for (int x = 0; x <= AVERAGING_SIZE * 2; x++)
+ {
+ m_Weight[z][x] = static_cast<NOISE_DATATYPE>((5 - std::abs(5 - x)) + (5 - std::abs(5 - z)));
+ m_WeightSum += m_Weight[z][x];
}
}
+}
+
+
+
+
+
+void cBiomalNoise3DComposable::Initialize(cIniFile & a_IniFile)
+{
+ // Params:
+ // The defaults generate extreme hills terrain
+ m_SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DSeaLevel", 62);
+ m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyX", 40);
+ m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyY", 40);
+ m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyZ", 40);
+ m_BaseFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DBaseFrequencyX", 40);
+ m_BaseFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DBaseFrequencyZ", 40);
+ m_ChoiceFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DChoiceFrequencyX", 40);
+ m_ChoiceFrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DChoiceFrequencyY", 80);
+ m_ChoiceFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DChoiceFrequencyZ", 40);
+ m_AirThreshold = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DAirThreshold", 0);
+ int NumChoiceOctaves = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DNumChoiceOctaves", 4);
+ int NumDensityOctaves = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DNumDensityOctaves", 6);
+ int NumBaseOctaves = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DNumBaseOctaves", 6);
+ NOISE_DATATYPE BaseNoiseAmplitude = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DBaseAmplitude", 1);
+
+ // Add octaves for the choice noise:
+ NOISE_DATATYPE wavlen = 1, ampl = 0.5;
+ for (int i = 0; i < NumChoiceOctaves; i++)
+ {
+ m_ChoiceNoise.AddOctave(wavlen, ampl);
+ wavlen = wavlen * 2;
+ ampl = ampl / 2;
+ }
- // The noise array is now fully interpolated
- /*
- // DEBUG: Output two images of the array, sliced by XY and XZ:
- cFile f1;
- if (f1.Open(Printf("Chunk_%d_%d_XY.raw", a_ChunkX, a_ChunkZ), cFile::fmWrite))
+ // Add octaves for the density noises:
+ wavlen = 1, ampl = 1;
+ for (int i = 0; i < NumDensityOctaves; i++)
{
- for (int z = 0; z < cChunkDef::Width; z++)
+ m_DensityNoiseA.AddOctave(wavlen, ampl);
+ m_DensityNoiseB.AddOctave(wavlen, ampl);
+ wavlen = wavlen * 2;
+ ampl = ampl / 2;
+ }
+
+ // Add octaves for the base noise:
+ wavlen = 1, ampl = BaseNoiseAmplitude;
+ for (int i = 0; i < NumBaseOctaves; i++)
+ {
+ m_BaseNoise.AddOctave(wavlen, ampl);
+ wavlen = wavlen * 2;
+ ampl = ampl / 2;
+ }
+}
+
+
+
+
+
+void cBiomalNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
+{
+ if ((a_ChunkX == m_LastChunkX) && (a_ChunkZ == m_LastChunkZ))
+ {
+ // The noise for this chunk is already generated in m_NoiseArray
+ return;
+ }
+ m_LastChunkX = a_ChunkX;
+ m_LastChunkZ = a_ChunkZ;
+
+ // Calculate the parameters for the biomes:
+ ChunkParam MidPoint;
+ ChunkParam HeightAmp;
+ CalcBiomeParamArrays(a_ChunkX, a_ChunkZ, HeightAmp, MidPoint);
+
+ // Generate all the noises:
+ NOISE_DATATYPE ChoiceNoise[5 * 5 * 33];
+ NOISE_DATATYPE Workspace[5 * 5 * 33];
+ NOISE_DATATYPE DensityNoiseA[5 * 5 * 33];
+ NOISE_DATATYPE DensityNoiseB[5 * 5 * 33];
+ NOISE_DATATYPE BaseNoise[5 * 5];
+ NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width);
+ NOISE_DATATYPE BlockZ = static_cast<NOISE_DATATYPE>(a_ChunkZ * cChunkDef::Width);
+ // Note that we have to swap the coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "z":
+ m_ChoiceNoise.Generate3D (ChoiceNoise, 5, 5, 33, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, 0, 257 / m_ChoiceFrequencyY, Workspace);
+ m_DensityNoiseA.Generate3D(DensityNoiseA, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
+ m_DensityNoiseB.Generate3D(DensityNoiseB, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
+ m_BaseNoise.Generate2D (BaseNoise, 5, 5, BlockX / m_BaseFrequencyX, (BlockX + 17) / m_BaseFrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
+
+ // Calculate the final noise based on the partial noises:
+ for (int y = 0; y < 33; y++)
+ {
+ NOISE_DATATYPE BlockHeight = static_cast<NOISE_DATATYPE>(y * 8);
+ for (int z = 0; z < 5; z++)
{
- for (int y = 0; y < cChunkDef::Height; y++)
+ for (int x = 0; x < 5; x++)
{
- int idx = y * 17 * 17 + z * 17;
- unsigned char buf[16];
- for (int x = 0; x < cChunkDef::Width; x++)
+ NOISE_DATATYPE AddHeight = (BlockHeight - MidPoint[x + 5 * z]) * HeightAmp[x + 5 * z];
+
+ // If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope:
+ if (AddHeight < 0)
{
- buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 128 * m_Noise[idx++]))));
+ AddHeight *= 4;
}
- f1.Write(buf, 16);
- } // for y
- } // for z
- } // if (XY file open)
- cFile f2;
- if (f2.Open(Printf("Chunk_%d_%d_XZ.raw", a_ChunkX, a_ChunkZ), cFile::fmWrite))
+ int idx = x + 5 * z + 5 * 5 * y;
+ Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[x + 5 * z];
+ }
+ }
+ }
+ LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8);
+}
+
+
+
+
+
+void cBiomalNoise3DComposable::CalcBiomeParamArrays(int a_ChunkX, int a_ChunkZ, ChunkParam & a_HeightAmp, ChunkParam & a_MidPoint)
+{
+ // Generate the 3*3 chunks of biomes around this chunk:
+ cChunkDef::BiomeMap neighborBiomes[3 * 3];
+ for (int z = 0; z < 3; z++)
{
- for (int y = 0; y < cChunkDef::Height; y++)
+ for (int x = 0; x < 3; x++)
{
- for (int z = 0; z < cChunkDef::Width; z++)
+ m_BiomeGen->GenBiomes(a_ChunkX + x - 1, a_ChunkZ + z - 1, neighborBiomes[x + 3 * z]);
+ }
+ }
+
+ // Sum up the biome values:
+ for (int z = 0; z < 5; z++)
+ {
+ for (int x = 0; x < 5; x++)
+ {
+ NOISE_DATATYPE totalHeightAmp = 0;
+ NOISE_DATATYPE totalMidPoint = 0;
+ // Add up the biomes around this point:
+ for (int relz = 0; relz <= AVERAGING_SIZE * 2; ++relz)
{
- int idx = y * 17 * 17 + z * 17;
- unsigned char buf[16];
- for (int x = 0; x < cChunkDef::Width; x++)
+ int colz = 16 + z * 4 + relz - AVERAGING_SIZE; // Biome Z coord relative to the neighborBiomes start
+ int neicellz = colz / 16; // Chunk Z coord relative to the neighborBiomes start
+ int neirelz = colz % 16; // Biome Z coord relative to cz in neighborBiomes
+ for (int relx = 0; relx <= AVERAGING_SIZE * 2; ++relx)
{
- buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 128 * m_Noise[idx++]))));
- }
- f2.Write(buf, 16);
- } // for z
- } // for y
- } // if (XZ file open)
- */
+ int colx = 16 + x * 4 + relx - AVERAGING_SIZE; // Biome X coord relative to the neighborBiomes start
+ int neicellx = colx / 16; // Chunk X coord relative to the neighborBiomes start
+ int neirelx = colx % 16; // Biome X coord relative to cz in neighborBiomes
+ EMCSBiome biome = cChunkDef::GetBiome(neighborBiomes[neicellx + neicellz * 3], neirelx, neirelz);
+ NOISE_DATATYPE heightAmp, midPoint;
+ GetBiomeParams(biome, heightAmp, midPoint);
+ totalHeightAmp += heightAmp * m_Weight[relz][relx];
+ totalMidPoint += midPoint * m_Weight[relz][relx];
+ } // for relx
+ } // for relz
+ a_HeightAmp[x + 5 * z] = totalHeightAmp / m_WeightSum;
+ a_MidPoint[x + 5 * z] = totalMidPoint / m_WeightSum;
+ } // for x
+ } // for z
}
-void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
+void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE & a_HeightAmp, NOISE_DATATYPE & a_MidPoint)
+{
+ switch (a_Biome)
+ {
+ case biBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
+ case biBirchForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
+ case biBirchForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
+ case biBirchForestHillsM: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
+ case biBirchForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
+ case biColdBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
+ case biDesertHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
+ case biDeepOcean: a_HeightAmp = 0.17f; a_MidPoint = 35; break;
+ case biDesert: a_HeightAmp = 0.29f; a_MidPoint = 62; break;
+ case biEnd: a_HeightAmp = 0.15f; a_MidPoint = 64; break;
+ case biExtremeHills: a_HeightAmp = 0.045f; a_MidPoint = 75; break;
+ case biExtremeHillsPlus: a_HeightAmp = 0.04f; a_MidPoint = 80; break;
+ case biFlowerForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
+ case biForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
+ case biForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
+ case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 53; break;
+ case biFrozenOcean: a_HeightAmp = 0.17f; a_MidPoint = 47; break;
+ case biIceMountains: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
+ case biIcePlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
+ case biIcePlainsSpikes: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
+ case biJungle: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
+ case biJungleHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
+ case biJungleM: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
+ case biMegaSpruceTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
+ case biMegaTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
+ case biMushroomShore: a_HeightAmp = 0.15f; a_MidPoint = 15; break;
+ case biOcean: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
+ case biPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
+ case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 53; break;
+ case biSwampland: a_HeightAmp = 0.25f; a_MidPoint = 59; break;
+ case biSwamplandM: a_HeightAmp = 0.11f; a_MidPoint = 59; break;
+ case biTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
+
+ /*
+ // Still missing:
+ case biColdTaiga: a_HeightAmp = 0.15f; a_MidPoint = 30; break;
+ case biColdTaigaHills: a_HeightAmp = 0.15f; a_MidPoint = 31; break;
+ case biColdTaigaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biDesertM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biExtremeHillsEdge: a_HeightAmp = 0.15f; a_MidPoint = 20; break;
+ case biExtremeHillsM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biExtremeHillsPlusM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biJungleEdge: a_HeightAmp = 0.15f; a_MidPoint = 23; break;
+ case biJungleEdgeM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biMegaSpruceTaiga: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biMegaTaiga: a_HeightAmp = 0.15f; a_MidPoint = 32; break;
+ case biMesa: a_HeightAmp = 0.15f; a_MidPoint = 37; break;
+ case biMesaBryce: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biMesaPlateau: a_HeightAmp = 0.15f; a_MidPoint = 39; break;
+ case biMesaPlateauF: a_HeightAmp = 0.15f; a_MidPoint = 38; break;
+ case biMesaPlateauFM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biMesaPlateauM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biMushroomIsland: a_HeightAmp = 0.15f; a_MidPoint = 14; break;
+ case biNether: a_HeightAmp = 0.15f; a_MidPoint = 68; break;
+ case biRoofedForest: a_HeightAmp = 0.15f; a_MidPoint = 29; break;
+ case biRoofedForestM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biSavanna: a_HeightAmp = 0.15f; a_MidPoint = 35; break;
+ case biSavannaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biSavannaPlateau: a_HeightAmp = 0.15f; a_MidPoint = 36; break;
+ case biSavannaPlateauM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biStoneBeach: a_HeightAmp = 0.15f; a_MidPoint = 25; break;
+ case biSunflowerPlains: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ case biTaiga: a_HeightAmp = 0.15f; a_MidPoint = 65; break;
+ case biTaigaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
+ */
+
+ default:
+ {
+ // Make a crazy terrain so that it stands out
+ a_HeightAmp = 0.001f;
+ a_MidPoint = 90;
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cBiomalNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
{
GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
@@ -520,7 +861,7 @@ void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Hei
-void cNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
+void cBiomalNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
{
GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
diff --git a/src/Generating/Noise3DGenerator.h b/src/Generating/Noise3DGenerator.h
index 42f61a854..ba541fbcc 100644
--- a/src/Generating/Noise3DGenerator.h
+++ b/src/Generating/Noise3DGenerator.h
@@ -1,7 +1,11 @@
// Noise3DGenerator.h
-// Generates terrain using 3D noise, rather than composing. Is a test.
+// Declares cNoise3DGenerator and cNoise3DComposable classes, representing 3D-noise-based generators.
+// They generate terrain shape by combining a lerp of two 3D noises with a vertical linear gradient
+// cNoise3DGenerator is obsolete and unmaintained.
+// cNoise3DComposable is used to test parameter combinations for single-biome worlds.
+
@@ -74,31 +78,147 @@ public:
void Initialize(cIniFile & a_IniFile);
protected:
- cNoise m_Noise1;
- cNoise m_Noise2;
- cNoise m_Noise3;
+ /** The noise that is used to choose between density noise A and B. */
+ cPerlinNoise m_ChoiceNoise;
+
+ /** Density 3D noise, variant A. */
+ cPerlinNoise m_DensityNoiseA;
+
+ /** Density 3D noise, variant B. */
+ cPerlinNoise m_DensityNoiseB;
+
+ /** Heightmap-like noise used to provide variance for low-amplitude biomes. */
+ cPerlinNoise m_BaseNoise;
- int m_SeaLevel;
+ /** Block height of the sealevel, used for composing the terrain. */
+ int m_SeaLevel;
+
+ /** The main parameter of the generator, specifies the slope of the vertical linear gradient.
+ A higher value means a steeper slope and a smaller total amplitude of the generated terrain. */
NOISE_DATATYPE m_HeightAmplification;
- NOISE_DATATYPE m_MidPoint; // Where the vertical "center" of the noise should be
+
+ /** Where the vertical "center" of the noise should be, as block height. */
+ NOISE_DATATYPE m_MidPoint;
+
+ // Frequency of the 3D noise's first octave:
NOISE_DATATYPE m_FrequencyX;
NOISE_DATATYPE m_FrequencyY;
NOISE_DATATYPE m_FrequencyZ;
+
+ // Frequency of the base terrain noise:
+ NOISE_DATATYPE m_BaseFrequencyX;
+ NOISE_DATATYPE m_BaseFrequencyZ;
+
+ // Frequency of the choice noise:
+ NOISE_DATATYPE m_ChoiceFrequencyX;
+ NOISE_DATATYPE m_ChoiceFrequencyY;
+ NOISE_DATATYPE m_ChoiceFrequencyZ;
+
+ // Threshold for when the values are considered air:
NOISE_DATATYPE m_AirThreshold;
+ // Cache for the last calculated chunk (reused between heightmap and composition queries):
int m_LastChunkX;
int m_LastChunkZ;
NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // x + 17 * z + 17 * 17 * y
- /// Generates the 3D noise array used for terrain generation, unless the LastChunk coords are equal to coords given
+ /** Generates the 3D noise array used for terrain generation (m_NoiseArray), unless the LastChunk coords are equal to coords given */
void GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ);
// cTerrainHeightGen overrides:
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
+ virtual void InitializeHeightGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
+
+ // cTerrainCompositionGen overrides:
+ virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
+ virtual void InitializeCompoGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
+} ;
+
+
+
+
+
+class cBiomalNoise3DComposable :
+ public cTerrainHeightGen,
+ public cTerrainCompositionGen
+{
+public:
+ cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_BiomeGen);
+
+ void Initialize(cIniFile & a_IniFile);
+
+protected:
+ /** Number of columns around the pixel to query for biomes for averaging. */
+ static const int AVERAGING_SIZE = 5;
+
+ /** Type used for a single parameter across the entire (downscaled) chunk. */
+ typedef NOISE_DATATYPE ChunkParam[5 * 5];
+
+
+ /** The noise that is used to choose between density noise A and B. */
+ cPerlinNoise m_ChoiceNoise;
+
+ /** Density 3D noise, variant A. */
+ cPerlinNoise m_DensityNoiseA;
+
+ /** Density 3D noise, variant B. */
+ cPerlinNoise m_DensityNoiseB;
+
+ /** Heightmap-like noise used to provide variance for low-amplitude biomes. */
+ cPerlinNoise m_BaseNoise;
+
+ /** The underlying biome generator. */
+ cBiomeGenPtr m_BiomeGen;
+
+ /** Block height of the sealevel, used for composing the terrain. */
+ int m_SeaLevel;
+
+ // Frequency of the 3D noise's first octave:
+ NOISE_DATATYPE m_FrequencyX;
+ NOISE_DATATYPE m_FrequencyY;
+ NOISE_DATATYPE m_FrequencyZ;
+
+ // Frequency of the base terrain noise:
+ NOISE_DATATYPE m_BaseFrequencyX;
+ NOISE_DATATYPE m_BaseFrequencyZ;
+
+ // Frequency of the choice noise:
+ NOISE_DATATYPE m_ChoiceFrequencyX;
+ NOISE_DATATYPE m_ChoiceFrequencyY;
+ NOISE_DATATYPE m_ChoiceFrequencyZ;
+
+ // Threshold for when the values are considered air:
+ NOISE_DATATYPE m_AirThreshold;
+
+ // Cache for the last calculated chunk (reused between heightmap and composition queries):
+ int m_LastChunkX;
+ int m_LastChunkZ;
+ NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // x + 17 * z + 17 * 17 * y
+
+ /** Weights for summing up neighboring biomes. */
+ NOISE_DATATYPE m_Weight[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1];
+
+ /** The sum of m_Weight[]. */
+ NOISE_DATATYPE m_WeightSum;
+
+
+ /** Generates the 3D noise array used for terrain generation (m_NoiseArray), unless the LastChunk coords are equal to coords given */
+ void GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ);
+
+ /** Calculates the biome-related parameters for the chunk. */
+ void CalcBiomeParamArrays(int a_ChunkX, int a_ChunkZ, ChunkParam & a_HeightAmp, ChunkParam & a_MidPoint);
+
+ /** Returns the parameters for the specified biome. */
+ void GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE & a_HeightAmp, NOISE_DATATYPE & a_MidPoint);
+
+ // cTerrainHeightGen overrides:
+ virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
+ virtual void InitializeHeightGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
// cTerrainCompositionGen overrides:
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
+ virtual void InitializeCompoGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
} ;
diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp
index ae4b6e36c..97aa646fc 100644
--- a/src/Generating/PieceGenerator.cpp
+++ b/src/Generating/PieceGenerator.cpp
@@ -289,7 +289,7 @@ cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece
m_NumCCWRotations(a_NumCCWRotations),
m_HasBeenMovedToGround(false)
{
- m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1);
+ m_Depth = (m_Parent == nullptr) ? 0 : (m_Parent->GetDepth() + 1);
m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z);
m_HitBox.Sort();
}
@@ -402,7 +402,7 @@ cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, i
}
int Rotation = Rotations[rnd % NumRotations];
- cPlacedPiece * res = new cPlacedPiece(NULL, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation);
+ cPlacedPiece * res = new cPlacedPiece(nullptr, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation);
// Place the piece's connectors into a_OutConnectors:
const cPiece::cConnectors & Conn = StartingPiece->GetConnectors();
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
index 6da3c3d10..761986690 100644
--- a/src/Generating/Prefab.cpp
+++ b/src/Generating/Prefab.cpp
@@ -328,7 +328,7 @@ void cPrefab::AddConnector(int a_RelX, int a_RelY, int a_RelZ, eBlockFace a_Dire
void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
{
- ASSERT(a_CharMapDef != NULL);
+ ASSERT(a_CharMapDef != nullptr);
// Initialize the charmap to all-invalid values:
for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++)
@@ -389,7 +389,7 @@ void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockIma
void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
{
- ASSERT(a_ConnectorsDef != NULL);
+ ASSERT(a_ConnectorsDef != nullptr);
AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n");
for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
@@ -436,7 +436,7 @@ void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
void cPrefab::ParseDepthWeight(const char * a_DepthWeightDef)
{
// The member needn't be defined at all, if so, skip:
- if (a_DepthWeightDef == NULL)
+ if (a_DepthWeightDef == nullptr)
{
return;
}
diff --git a/src/Generating/PrefabPiecePool.cpp b/src/Generating/PrefabPiecePool.cpp
index 122b9d2af..895555ef8 100644
--- a/src/Generating/PrefabPiecePool.cpp
+++ b/src/Generating/PrefabPiecePool.cpp
@@ -16,7 +16,7 @@ cPrefabPiecePool::cPrefabPiecePool(
)
{
AddPieceDefs(a_PieceDefs, a_NumPieceDefs);
- if (a_StartingPieceDefs != NULL)
+ if (a_StartingPieceDefs != nullptr)
{
AddStartingPieceDefs(a_StartingPieceDefs, a_NumStartingPieceDefs);
}
@@ -56,7 +56,7 @@ void cPrefabPiecePool::Clear(void)
void cPrefabPiecePool::AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs)
{
- ASSERT(a_PieceDefs != NULL);
+ ASSERT(a_PieceDefs != nullptr);
for (size_t i = 0; i < a_NumPieceDefs; i++)
{
cPrefab * Prefab = new cPrefab(a_PieceDefs[i]);
@@ -71,7 +71,7 @@ void cPrefabPiecePool::AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_
void cPrefabPiecePool::AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs)
{
- ASSERT(a_StartingPieceDefs != NULL);
+ ASSERT(a_StartingPieceDefs != nullptr);
for (size_t i = 0; i < a_NumStartingPieceDefs; i++)
{
cPrefab * Prefab = new cPrefab(a_StartingPieceDefs[i]);
diff --git a/src/Generating/Prefabs/CMakeLists.txt b/src/Generating/Prefabs/CMakeLists.txt
index 2c62aa73d..68f6491c4 100644
--- a/src/Generating/Prefabs/CMakeLists.txt
+++ b/src/Generating/Prefabs/CMakeLists.txt
@@ -29,5 +29,5 @@ SET (HDRS
if(NOT MSVC)
add_library(Generating_Prefabs ${SRCS} ${HDRS})
- target_link_libraries(Generating_Prefabs OSSupport iniFile Blocks)
+ target_link_libraries(Generating_Prefabs OSSupport Blocks)
endif()
diff --git a/src/Generating/ProtIntGen.h b/src/Generating/ProtIntGen.h
new file mode 100644
index 000000000..73ed27096
--- /dev/null
+++ b/src/Generating/ProtIntGen.h
@@ -0,0 +1,1351 @@
+
+// ProtIntGen.h
+
+// Declares the prototyping integer generators - cProtIntGen class and its descendants
+
+/*
+These classes generate 2D arrays of integers that have various interpretations. The main purpose of these
+classes is to provide fast prototyping for cIntGen classes - unlike cIntGen classes, these are not
+template-based and so they take care of the underlying sizes automatically. This makes them easier to chain
+and re-chain, since the size parameters don't need to be adjusted after each such case. Their performance is,
+however, slightly worse, which is why we use cIntGen classes in the final generator.
+
+Because there is no SizeX / SizeZ template param, the generators would have to either alloc memory for each
+underlying generator's values, or use a maximum-size buffer. We chose the latter, to avoid memory allocation
+overhead; this however means that there's (an arbitrary) limit to the size of the generated data.
+*/
+
+
+
+
+
+#pragma once
+
+// We need the biome group constants defined there:
+#include "IntGen.h"
+
+
+
+
+
+/** Interface that all the generator classes provide. */
+class cProtIntGen
+{
+protected:
+ /** Maximum size of the generated area.
+ Adjust the constant if you need larger areas, these are just so that we can use fixed-size buffers. */
+ static const int m_BufferSize = 900;
+
+public:
+
+ /** Type of the generic interface used for storing links to the underlying generators. */
+ typedef std::shared_ptr<cProtIntGen> Underlying;
+
+
+ /** Force a virtual destructor in all descendants.
+ Descendants contain virtual functions and are referred to via pointer-to-base, so they need a virtual destructor. */
+ virtual ~cProtIntGen() {}
+
+ /** Generates the array of specified size into a_Values, based on given min coords. */
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) = 0;
+};
+
+
+
+
+
+/** Provides additional cNoise member and its helper functions. */
+class cProtIntGenWithNoise :
+ public cProtIntGen
+{
+ typedef cProtIntGen super;
+
+public:
+ cProtIntGenWithNoise(int a_Seed) :
+ m_Noise(a_Seed)
+ {
+ }
+
+protected:
+ cNoise m_Noise;
+
+ /** Chooses one of a_Val1 or a_Val2, based on m_Noise and the coordinates for querying the noise. */
+ int chooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2)
+ {
+ int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7;
+ return ((rnd & 1) == 0) ? a_Val1 : a_Val2;
+ }
+
+ /** Chooses one of a_ValN, based on m_Noise and the coordinates for querying the noise. */
+ int chooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2, int a_Val3, int a_Val4)
+ {
+ int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7;
+ switch (rnd % 4)
+ {
+ case 0: return a_Val1;
+ case 1: return a_Val2;
+ case 2: return a_Val3;
+ default: return a_Val4;
+ }
+ }
+};
+
+
+
+
+
+
+/** Generates a 2D array of random integers in the specified range [0 .. Range). */
+class cProtIntGenChoice :
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenChoice(int a_Seed, int a_Range) :
+ super(a_Seed),
+ m_Range(a_Range)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ int BaseZ = a_MinZ + z;
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ a_Values[x + a_SizeX * z] = (super::m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7) % m_Range;
+ }
+ } // for z
+ }
+
+protected:
+ int m_Range;
+};
+
+
+
+
+
+
+/** Decides between the ocean and landmass biomes.
+Has a threshold (in percent) of how much land, the larger the threshold, the more land.
+Generates 0 for ocean, biome group ID for landmass. */
+class cProtIntGenLandOcean :
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenLandOcean(int a_Seed, int a_Threshold) :
+ super(a_Seed),
+ m_Threshold(a_Threshold)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ int BaseZ = a_MinZ + z;
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int rnd = (super::m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7);
+ a_Values[x + a_SizeX * z] = ((rnd % 100) < m_Threshold) ? ((rnd / 101) % bgLandOceanMax + 1) : 0;
+ }
+ }
+
+ // If the centerpoint of the world is within the area, set it to bgTemperate, always:
+ if ((a_MinX <= 0) && (a_MinZ <= 0) && (a_MinX + a_SizeX > 0) && (a_MinZ + a_SizeZ > 0))
+ {
+ a_Values[-a_MinX - a_MinZ * a_SizeX] = bgTemperate;
+ }
+ }
+
+protected:
+ int m_Threshold;
+};
+
+
+
+
+
+/** Zooms the underlying value array to twice the size. Uses random-neighbor for the pixels in-between.
+This means that the zoome out image is randomly distorted. Applying zoom several times provides all
+the distortion that the generators need. */
+class cProtIntGenZoom :
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenZoom(int a_Seed, Underlying a_UnderlyingGen) :
+ super(a_Seed),
+ m_UnderlyingGen(a_UnderlyingGen)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Get the coords for the lower generator:
+ int lowerMinX = a_MinX >> 1;
+ int lowerMinZ = a_MinZ >> 1;
+ int lowerSizeX = a_SizeX / 2 + 2;
+ int lowerSizeZ = a_SizeZ / 2 + 2;
+ ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize);
+ ASSERT(lowerSizeX > 0);
+ ASSERT(lowerSizeZ > 0);
+
+ // Generate the underlying data with half the resolution:
+ int lowerData[m_BufferSize];
+ m_UnderlyingGen->GetInts(lowerMinX, lowerMinZ, lowerSizeX, lowerSizeZ, lowerData);
+ const int lowStepX = (lowerSizeX - 1) * 2;
+ int cache[m_BufferSize];
+
+ // Discreet-interpolate the values into twice the size:
+ for (int z = 0; z < lowerSizeZ - 1; ++z)
+ {
+ int idx = (z * 2) * lowStepX;
+ int PrevZ0 = lowerData[z * lowerSizeX];
+ int PrevZ1 = lowerData[(z + 1) * lowerSizeX];
+
+ for (int x = 0; x < lowerSizeX - 1; ++x)
+ {
+ int ValX1Z0 = lowerData[x + 1 + z * lowerSizeX];
+ int ValX1Z1 = lowerData[x + 1 + (z + 1) * lowerSizeX];
+ int RndX = (x + lowerMinX) * 2;
+ int RndZ = (z + lowerMinZ) * 2;
+ cache[idx] = PrevZ0;
+ cache[idx + lowStepX] = super::chooseRandomOne(RndX, RndZ + 1, PrevZ0, PrevZ1);
+ cache[idx + 1] = super::chooseRandomOne(RndX, RndZ - 1, PrevZ0, ValX1Z0);
+ cache[idx + 1 + lowStepX] = super::chooseRandomOne(RndX, RndZ, PrevZ0, ValX1Z0, PrevZ1, ValX1Z1);
+ idx += 2;
+ PrevZ0 = ValX1Z0;
+ PrevZ1 = ValX1Z1;
+ }
+ }
+
+ // Copy from Cache into a_Values; take into account the even/odd offsets in a_Min:
+ for (int z = 0; z < a_SizeZ; ++z)
+ {
+ memcpy(a_Values + z * a_SizeX, cache + (z + (a_MinZ & 1)) * lowStepX + (a_MinX & 1), a_SizeX * sizeof(int));
+ }
+ }
+
+protected:
+ Underlying m_UnderlyingGen;
+};
+
+
+
+
+
+/** Smoothes out some artifacts generated by the zooming - mostly single-pixel values.
+Compares each pixel to its neighbors and if the neighbors are equal, changes the pixel to their value. */
+class cProtIntGenSmooth :
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenSmooth(int a_Seed, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the underlying values:
+ int lowerSizeX = a_SizeX + 2;
+ int lowerSizeZ = a_SizeZ + 2;
+ ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize);
+ int lowerData[m_BufferSize];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerData);
+
+ // Smooth - for each square check if the surroundings are the same, if so, expand them diagonally.
+ // Also get rid of single-pixel irregularities (A-B-A):
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ int NoiseZ = a_MinZ + z;
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int val = lowerData[x + 1 + (z + 1) * lowerSizeX];
+ int above = lowerData[x + 1 + z * lowerSizeX];
+ int below = lowerData[x + 1 + (z + 2) * lowerSizeX];
+ int left = lowerData[x + (z + 1) * lowerSizeX];
+ int right = lowerData[x + 2 + (z + 1) * lowerSizeX];
+
+ if ((left == right) && (above == below))
+ {
+ if (((super::m_Noise.IntNoise2DInt(a_MinX + x, NoiseZ) / 7) % 2) == 0)
+ {
+ val = left;
+ }
+ else
+ {
+ val = above;
+ }
+ }
+ else
+ {
+ if (left == right)
+ {
+ val = left;
+ }
+
+ if (above == below)
+ {
+ val = above;
+ }
+ }
+
+ a_Values[x + z * a_SizeX] = val;
+ }
+ }
+ }
+
+protected:
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Converts land biomes at the edge of an ocean into the respective beach biome. */
+class cProtIntGenBeaches :
+ public cProtIntGen
+{
+ typedef cProtIntGen super;
+
+public:
+ cProtIntGenBeaches(Underlying a_Underlying) :
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Map for biome -> its beach:
+ static const int ToBeach[] =
+ {
+ /* biOcean */ biOcean,
+ /* biPlains */ biBeach,
+ /* biDesert */ biBeach,
+ /* biExtremeHills */ biStoneBeach,
+ /* biForest */ biBeach,
+ /* biTaiga */ biColdBeach,
+ /* biSwampland */ biSwampland,
+ /* biRiver */ biRiver,
+ /* biNether */ biNether,
+ /* biEnd */ biEnd,
+ /* biFrozenOcean */ biColdBeach,
+ /* biFrozenRiver */ biColdBeach,
+ /* biIcePlains */ biColdBeach,
+ /* biIceMountains */ biColdBeach,
+ /* biMushroomIsland */ biMushroomShore,
+ /* biMushroomShore */ biMushroomShore,
+ /* biBeach */ biBeach,
+ /* biDesertHills */ biBeach,
+ /* biForestHills */ biBeach,
+ /* biTaigaHills */ biColdBeach,
+ /* biExtremeHillsEdge */ biStoneBeach,
+ /* biJungle */ biBeach,
+ /* biJungleHills */ biBeach,
+ /* biJungleEdge */ biBeach,
+ /* biDeepOcean */ biOcean,
+ /* biStoneBeach */ biStoneBeach,
+ /* biColdBeach */ biColdBeach,
+ /* biBirchForest */ biBeach,
+ /* biBirchForestHills */ biBeach,
+ /* biRoofedForest */ biBeach,
+ /* biColdTaiga */ biColdBeach,
+ /* biColdTaigaHills */ biColdBeach,
+ /* biMegaTaiga */ biStoneBeach,
+ /* biMegaTaigaHills */ biStoneBeach,
+ /* biExtremeHillsPlus */ biStoneBeach,
+ /* biSavanna */ biBeach,
+ /* biSavannaPlateau */ biBeach,
+ /* biMesa */ biMesa,
+ /* biMesaPlateauF */ biMesa,
+ /* biMesaPlateau */ biMesa,
+ };
+
+ // Generate the underlying values:
+ int lowerSizeX = a_SizeX + 2;
+ int lowerSizeZ = a_SizeZ + 2;
+ ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize);
+ int lowerValues[m_BufferSize];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerValues);
+
+ // Add beaches between ocean and biomes:
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int val = lowerValues[x + 1 + (z + 1) * lowerSizeX];
+ int above = lowerValues[x + 1 + z * lowerSizeX];
+ int below = lowerValues[x + 1 + (z + 2) * lowerSizeX];
+ int left = lowerValues[x + (z + 1) * lowerSizeX];
+ int right = lowerValues[x + 2 + (z + 1) * lowerSizeX];
+ if (!IsBiomeOcean(val))
+ {
+ if (IsBiomeOcean(above) || IsBiomeOcean(below) || IsBiomeOcean(left) || IsBiomeOcean(right))
+ {
+ // First convert the value to a regular biome (drop the M flag), then modulo by our biome count:
+ val = ToBeach[(val % 128) % ARRAYCOUNT(ToBeach)];
+ }
+ }
+ a_Values[x + z * a_SizeX] = val;
+ }
+ }
+ }
+
+protected:
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Generates the underlying numbers and then randomly changes some ocean group pixels into random land
+biome group pixels, based on the predefined chance. */
+class cProtIntGenAddIslands :
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ typedef std::shared_ptr<cProtIntGen> Underlying;
+
+
+ cProtIntGenAddIslands(int a_Seed, int a_Chance, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Chance(a_Chance),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values);
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ if (a_Values[x + z * a_SizeX] == bgOcean)
+ {
+ int rnd = super::m_Noise.IntNoise2DInt(a_MinX + x, a_MinZ + z) / 7;
+ if (rnd % 1000 < m_Chance)
+ {
+ a_Values[x + z * a_SizeX] = (rnd / 1003) % bgLandOceanMax;
+ }
+ }
+ }
+ }
+ }
+
+protected:
+ /** Chance of each ocean pixel being converted, in permille. */
+ int m_Chance;
+
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** A filter that adds an edge biome group between two biome groups that need an edge between them. */
+class cProtIntGenBiomeGroupEdges :
+ public cProtIntGen
+{
+ typedef cProtIntGen super;
+
+public:
+ cProtIntGenBiomeGroupEdges(Underlying a_Underlying) :
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values)
+ {
+ // Generate the underlying biome groups:
+ int lowerSizeX = a_SizeX + 2;
+ int lowerSizeZ = a_SizeZ + 2;
+ ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize);
+ int lowerValues[m_BufferSize];
+ m_Underlying->GetInts(a_MinX, a_MinZ, lowerSizeX, lowerSizeZ, lowerValues);
+
+ // Change the biomes on incompatible edges into an edge biome:
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int val = lowerValues[x + 1 + (z + 1) * lowerSizeX];
+ int Above = lowerValues[x + 1 + z * lowerSizeX];
+ int Below = lowerValues[x + 1 + (z + 2) * lowerSizeX];
+ int Left = lowerValues[x + (z + 1) * lowerSizeX];
+ int Right = lowerValues[x + 2 + (z + 1) * lowerSizeX];
+ switch (val)
+ {
+ // Desert should neighbor only oceans, desert and temperates; change to temperate when another:
+ case bgDesert:
+ {
+ if (
+ !isDesertCompatible(Above) ||
+ !isDesertCompatible(Below) ||
+ !isDesertCompatible(Left) ||
+ !isDesertCompatible(Right)
+ )
+ {
+ val = bgTemperate;
+ }
+ break;
+ } // case bgDesert
+
+ // Ice should not neighbor deserts; change to temperate:
+ case bgIce:
+ {
+ if (
+ (Above == bgDesert) ||
+ (Below == bgDesert) ||
+ (Left == bgDesert) ||
+ (Right == bgDesert)
+ )
+ {
+ val = bgTemperate;
+ }
+ break;
+ } // case bgIce
+ }
+ a_Values[x + z * a_SizeX] = val;
+ } // for x
+ } // for z
+ }
+
+protected:
+ Underlying m_Underlying;
+
+
+ inline bool isDesertCompatible(int a_BiomeGroup)
+ {
+ switch (a_BiomeGroup)
+ {
+ case bgOcean:
+ case bgDesert:
+ case bgTemperate:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
+};
+
+
+
+
+
+/** Turns biome group indices into real biomes.
+For each pixel, takes its biome group and chooses a random biome from that group; replaces the value with
+that biome. */
+class cProtIntGenBiomes :
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenBiomes(int a_Seed, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Define the per-biome-group biomes:
+ static const int oceanBiomes[] =
+ {
+ biOcean, // biDeepOcean,
+ };
+
+ // Same as oceanBiomes, there are no rare oceanic biomes (mushroom islands are handled separately)
+ static const int rareOceanBiomes[] =
+ {
+ biOcean,
+ };
+
+ static const int desertBiomes[] =
+ {
+ biDesert, biDesert, biDesert, biDesert, biDesert, biDesert, biSavanna, biSavanna, biPlains,
+ };
+
+ static const int rareDesertBiomes[] =
+ {
+ biMesaPlateau, biMesaPlateauF,
+ };
+
+ static const int temperateBiomes[] =
+ {
+ biForest, biForest, biRoofedForest, biExtremeHills, biPlains, biBirchForest, biSwampland,
+ };
+
+ static const int rareTemperateBiomes[] =
+ {
+ biJungle, // Jungle is not strictly temperate, but let's piggyback it here
+ };
+
+ static const int mountainBiomes[] =
+ {
+ biExtremeHills, biForest, biTaiga, biPlains,
+ };
+
+ static const int rareMountainBiomes[] =
+ {
+ biMegaTaiga,
+ };
+
+ static const int iceBiomes[] =
+ {
+ biIcePlains, biIcePlains, biIcePlains, biIcePlains, biColdTaiga,
+ };
+
+ // Same as iceBiomes, there's no rare ice biome
+ static const int rareIceBiomes[] =
+ {
+ biIcePlains, biIcePlains, biIcePlains, biIcePlains, biColdTaiga,
+ };
+
+ static const cBiomesInGroups biomesInGroups[] =
+ {
+ /* bgOcean */ { static_cast<int>(ARRAYCOUNT(oceanBiomes)), oceanBiomes},
+ /* bgDesert */ { static_cast<int>(ARRAYCOUNT(desertBiomes)), desertBiomes},
+ /* bgTemperate */ { static_cast<int>(ARRAYCOUNT(temperateBiomes)), temperateBiomes},
+ /* bgMountains */ { static_cast<int>(ARRAYCOUNT(mountainBiomes)), mountainBiomes},
+ /* bgIce */ { static_cast<int>(ARRAYCOUNT(iceBiomes)), iceBiomes},
+ };
+
+ static const cBiomesInGroups rareBiomesInGroups[] =
+ {
+ /* bgOcean */ { static_cast<int>(ARRAYCOUNT(rareOceanBiomes)), rareOceanBiomes},
+ /* bgDesert */ { static_cast<int>(ARRAYCOUNT(rareDesertBiomes)), rareDesertBiomes},
+ /* bgTemperate */ { static_cast<int>(ARRAYCOUNT(rareTemperateBiomes)), rareTemperateBiomes},
+ /* bgMountains */ { static_cast<int>(ARRAYCOUNT(rareMountainBiomes)), rareMountainBiomes},
+ /* bgIce */ { static_cast<int>(ARRAYCOUNT(rareIceBiomes)), rareIceBiomes},
+ };
+
+ // Generate the underlying values, representing biome groups:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values);
+
+ // Overwrite each biome group with a random biome from that group:
+ // Take care of the bgfRare flag
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ int IdxZ = z * a_SizeX;
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int val = a_Values[x + IdxZ];
+ const cBiomesInGroups & Biomes = (val > bgfRare) ?
+ rareBiomesInGroups[(val & (bgfRare - 1)) % ARRAYCOUNT(rareBiomesInGroups)] :
+ biomesInGroups[val % ARRAYCOUNT(biomesInGroups)];
+ int rnd = (super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7);
+ a_Values[x + IdxZ] = Biomes.Biomes[rnd % Biomes.Count];
+ }
+ }
+ }
+
+protected:
+
+ struct cBiomesInGroups
+ {
+ const int Count;
+ const int * Biomes;
+ };
+
+
+ /** The underlying int generator */
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Randomly replaces pixels of one value to another value, using the given chance. */
+class cProtIntGenReplaceRandomly :
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ typedef std::shared_ptr<cProtIntGen> Underlying;
+
+
+ cProtIntGenReplaceRandomly(int a_Seed, int a_From, int a_To, int a_Chance, Underlying a_Underlying) :
+ super(a_Seed),
+ m_From(a_From),
+ m_To(a_To),
+ m_Chance(a_Chance),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the underlying values:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values);
+
+ // Replace some of the values:
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ int idxZ = z * a_SizeX;
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int idx = x + idxZ;
+ if (a_Values[idx] == m_From)
+ {
+ int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7;
+ if (rnd % 1000 < m_Chance)
+ {
+ a_Values[idx] = m_To;
+ }
+ }
+ }
+ } // for z
+ }
+
+
+protected:
+ /** The original value to be replaced. */
+ int m_From;
+
+ /** The destination value to which to replace. */
+ int m_To;
+
+ /** Chance, in permille, of replacing the value. */
+ int m_Chance;
+
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Mixer that joins together finalized biomes and rivers.
+It first checks for oceans, if there is an ocean in the Biomes, it keeps the ocean.
+If there's no ocean, it checks Rivers for a river, if there is a river, it uses the Biomes to select either
+regular river or frozen river, based on the biome. */
+class cProtIntGenMixRivers:
+ public cProtIntGen
+{
+ typedef cProtIntGen super;
+
+public:
+ cProtIntGenMixRivers(Underlying a_Biomes, Underlying a_Rivers):
+ m_Biomes(a_Biomes),
+ m_Rivers(a_Rivers)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the underlying data:
+ ASSERT(a_SizeX * a_SizeZ <= m_BufferSize);
+ m_Biomes->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values);
+ int riverData[m_BufferSize];
+ m_Rivers->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, riverData);
+
+ // Mix the values:
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ int idxZ = z * a_SizeX;
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int idx = x + idxZ;
+ if (IsBiomeOcean(a_Values[idx]))
+ {
+ // Oceans are kept without any changes
+ continue;
+ }
+ if (riverData[idx] != biRiver)
+ {
+ // There's no river, keep the current value
+ continue;
+ }
+
+ // There's a river, change the output to a river or a frozen river, based on the original biome:
+ if (IsBiomeVeryCold((EMCSBiome)a_Values[idx]))
+ {
+ a_Values[idx] = biFrozenRiver;
+ }
+ else
+ {
+ a_Values[idx] = biRiver;
+ }
+ } // for x
+ } // for z
+ }
+
+protected:
+ Underlying m_Biomes;
+ Underlying m_Rivers;
+};
+
+
+
+
+
+/** Generates a river based on the underlying data.
+This is basically an edge detector over the underlying data. The rivers are the edges where the underlying
+data changes from one pixel to its neighbor. */
+class cProtIntGenRiver:
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenRiver(int a_Seed, Underlying a_Underlying):
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the underlying data:
+ int lowerSizeX = a_SizeX + 2;
+ int lowerSizeZ = a_SizeZ + 2;
+ ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize);
+ int lowerValues[m_BufferSize];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerValues);
+
+ // Detect the edges:
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int Above = lowerValues[x + 1 + z * lowerSizeX];
+ int Below = lowerValues[x + 1 + (z + 2) * lowerSizeX];
+ int Left = lowerValues[x + (z + 1) * lowerSizeX];
+ int Right = lowerValues[x + 2 + (z + 1) * lowerSizeX];
+ int val = lowerValues[x + 1 + (z + 1) * lowerSizeX];
+
+ if ((val == Above) && (val == Below) && (val == Left) && (val == Right))
+ {
+ val = 0;
+ }
+ else
+ {
+ val = biRiver;
+ }
+ a_Values[x + z * a_SizeX] = val;
+ } // for x
+ } // for z
+ }
+
+protected:
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Turns some of the oceans into the specified biome. Used for mushroom and deep ocean.
+The biome is only placed if at least 3 of its neighbors are ocean and only with the specified chance. */
+class cProtIntGenAddToOcean:
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenAddToOcean(int a_Seed, int a_Chance, int a_ToValue, Underlying a_Underlying):
+ super(a_Seed),
+ m_Chance(a_Chance),
+ m_ToValue(a_ToValue),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the underlying data:
+ int lowerSizeX = a_SizeX + 2;
+ int lowerSizeZ = a_SizeZ + 2;
+ ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize);
+ int lowerValues[m_BufferSize];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerValues);
+
+ // Add the mushroom islands:
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int val = lowerValues[x + 1 + (z + 1) * lowerSizeX];
+ if (!IsBiomeOcean(val))
+ {
+ a_Values[x + z * a_SizeX] = val;
+ continue;
+ }
+
+ // Count the ocean neighbors:
+ int Above = lowerValues[x + 1 + z * lowerSizeX];
+ int Below = lowerValues[x + 1 + (z + 2) * lowerSizeX];
+ int Left = lowerValues[x + (z + 1) * lowerSizeX];
+ int Right = lowerValues[x + 2 + (z + 1) * lowerSizeX];
+ int NumOceanNeighbors = 0;
+ if (IsBiomeOcean(Above))
+ {
+ NumOceanNeighbors += 1;
+ }
+ if (IsBiomeOcean(Below))
+ {
+ NumOceanNeighbors += 1;
+ }
+ if (IsBiomeOcean(Left))
+ {
+ NumOceanNeighbors += 1;
+ }
+ if (IsBiomeOcean(Right))
+ {
+ NumOceanNeighbors += 1;
+ }
+
+ // If at least 3 ocean neighbors and the chance is right, change:
+ if (
+ (NumOceanNeighbors >= 3) &&
+ ((super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7) % 1000 < m_Chance)
+ )
+ {
+ a_Values[x + z * a_SizeX] = m_ToValue;
+ }
+ else
+ {
+ a_Values[x + z * a_SizeX] = val;
+ }
+ } // for x
+ } // for z
+ }
+
+protected:
+ /** Chance, in permille, of changing the biome. */
+ int m_Chance;
+
+ /** The value to change the ocean into. */
+ int m_ToValue;
+
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Changes random pixels of the underlying data to the specified value. */
+class cProtIntGenSetRandomly :
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenSetRandomly(int a_Seed, int a_Chance, int a_ToValue, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Chance(a_Chance),
+ m_ToValue(a_ToValue),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the underlying data:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values);
+
+ // Change random pixels to bgOcean:
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7;
+ if (rnd % 1000 < m_Chance)
+ {
+ a_Values[x + z * a_SizeX] = m_ToValue;
+ }
+ }
+ }
+ }
+
+protected:
+ /** Chance, in permille, of changing each pixel. */
+ int m_Chance;
+
+ /** The value to which to set the pixel. */
+ int m_ToValue;
+
+ Underlying m_Underlying;
+};
+
+
+
+
+
+
+/** Adds a "rare" flag to random biome groups, based on the given chance. */
+class cProtIntGenRareBiomeGroups:
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenRareBiomeGroups(int a_Seed, int a_Chance, Underlying a_Underlying):
+ super(a_Seed),
+ m_Chance(a_Chance),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the underlying data:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values);
+
+ // Change some of the biome groups into rare biome groups:
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7;
+ if (rnd % 1000 < m_Chance)
+ {
+ int idx = x + a_SizeX * z;
+ a_Values[idx] = a_Values[idx] | bgfRare;
+ }
+ }
+ }
+ }
+
+protected:
+ /** Chance, in permille, of changing each pixel into the rare biome group. */
+ int m_Chance;
+
+ /** The underlying generator. */
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Changes biomes in the parent data into an alternate versions (usually "hill" variants), in such places
+that have their alterations set. */
+class cProtIntGenAlternateBiomes:
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenAlternateBiomes(int a_Seed, Underlying a_Alterations, Underlying a_BaseBiomes):
+ super(a_Seed),
+ m_Alterations(a_Alterations),
+ m_BaseBiomes(a_BaseBiomes)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the base biomes and the alterations:
+ m_BaseBiomes->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values);
+ int alterations[m_BufferSize];
+ m_Alterations->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, alterations);
+
+ // Change the biomes into their alternate versions:
+ int len = a_SizeX * a_SizeZ;
+ for (int idx = 0; idx < len; ++idx)
+ {
+ if (alterations[idx] == 0)
+ {
+ // No change
+ continue;
+ }
+
+ // Change to alternate biomes:
+ int val = a_Values[idx];
+ switch (val)
+ {
+ case biBirchForest: val = biBirchForestHills; break;
+ case biDesert: val = biDesertHills; break;
+ case biExtremeHills: val = biExtremeHillsPlus; break;
+ case biForest: val = biForestHills; break;
+ case biIcePlains: val = biIceMountains; break;
+ case biJungle: val = biJungleHills; break;
+ case biMegaTaiga: val = biMegaTaigaHills; break;
+ case biMesaPlateau: val = biMesa; break;
+ case biMesaPlateauF: val = biMesa; break;
+ case biMesaPlateauM: val = biMesa; break;
+ case biMesaPlateauFM: val = biMesa; break;
+ case biPlains: val = biForest; break;
+ case biRoofedForest: val = biPlains; break;
+ case biSavanna: val = biSavannaPlateau; break;
+ case biTaiga: val = biTaigaHills; break;
+ }
+ a_Values[idx] = val;
+ } // for idx - a_Values[]
+ }
+
+protected:
+ Underlying m_Alterations;
+ Underlying m_BaseBiomes;
+};
+
+
+
+
+
+/** Adds an edge between two specifically incompatible biomes, such as mesa and forest. */
+class cProtIntGenBiomeEdges:
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenBiomeEdges(int a_Seed, Underlying a_Underlying):
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the underlying biomes:
+ int lowerSizeX = a_SizeX + 2;
+ int lowerSizeZ = a_SizeZ + 2;
+ ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize);
+ int lowerValues[m_BufferSize];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerValues);
+
+ // Convert incompatible edges into neutral biomes:
+ for (int z = 0; z < a_SizeZ; z++)
+ {
+ for (int x = 0; x < a_SizeX; x++)
+ {
+ int biome = lowerValues[x + 1 + (z + 1) * lowerSizeX];
+ int above = lowerValues[x + 1 + z * lowerSizeX];
+ int below = lowerValues[x + 1 + (z + 2) * lowerSizeX];
+ int left = lowerValues[x + (z + 1) * lowerSizeX];
+ int right = lowerValues[x + 2 + (z + 1) * lowerSizeX];
+
+ switch (biome)
+ {
+ case biDesert:
+ case biDesertM:
+ case biDesertHills:
+ {
+ if (
+ IsBiomeVeryCold(static_cast<EMCSBiome>(above)) ||
+ IsBiomeVeryCold(static_cast<EMCSBiome>(below)) ||
+ IsBiomeVeryCold(static_cast<EMCSBiome>(left)) ||
+ IsBiomeVeryCold(static_cast<EMCSBiome>(right))
+ )
+ {
+ biome = biPlains;
+ }
+ break;
+ } // case biDesert
+
+ case biMesaPlateau:
+ case biMesaPlateauF:
+ case biMesaPlateauFM:
+ case biMesaPlateauM:
+ {
+ if (
+ !isMesaCompatible(above) ||
+ !isMesaCompatible(below) ||
+ !isMesaCompatible(left) ||
+ !isMesaCompatible(right)
+ )
+ {
+ biome = biDesert;
+ }
+ break;
+ } // Mesa biomes
+
+ case biJungle:
+ case biJungleM:
+ {
+ if (
+ !isJungleCompatible(above) ||
+ !isJungleCompatible(below) ||
+ !isJungleCompatible(left) ||
+ !isJungleCompatible(right)
+ )
+ {
+ biome = (biome == biJungle) ? biJungleEdge : biJungleEdgeM;
+ }
+ break;
+ } // Jungle biomes
+
+ case biSwampland:
+ case biSwamplandM:
+ {
+ if (
+ IsBiomeNoDownfall(static_cast<EMCSBiome>(above)) ||
+ IsBiomeNoDownfall(static_cast<EMCSBiome>(below)) ||
+ IsBiomeNoDownfall(static_cast<EMCSBiome>(left)) ||
+ IsBiomeNoDownfall(static_cast<EMCSBiome>(right))
+ )
+ {
+ biome = biPlains;
+ }
+ break;
+ } // Swampland biomes
+ } // switch (biome)
+
+ a_Values[x + z * a_SizeX] = biome;
+ } // for x
+ } // for z
+ }
+
+
+protected:
+ Underlying m_Underlying;
+
+
+ bool isMesaCompatible(int a_Biome)
+ {
+ switch (a_Biome)
+ {
+ case biDesert:
+ case biMesa:
+ case biMesaBryce:
+ case biMesaPlateau:
+ case biMesaPlateauF:
+ case biMesaPlateauFM:
+ case biMesaPlateauM:
+ case biOcean:
+ case biDeepOcean:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
+
+
+ bool isJungleCompatible(int a_Biome)
+ {
+ switch (a_Biome)
+ {
+ case biJungle:
+ case biJungleM:
+ case biJungleEdge:
+ case biJungleEdgeM:
+ case biJungleHills:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
+};
+
+
+
+
+
+/** Changes biomes in the parent data into their alternate versions ("M" variants), in such places that
+have their alterations set. */
+class cProtIntGenMBiomes:
+ public cProtIntGenWithNoise
+{
+ typedef cProtIntGenWithNoise super;
+
+public:
+ cProtIntGenMBiomes(int a_Seed, Underlying a_Alteration, Underlying a_Underlying):
+ super(a_Seed),
+ m_Underlying(a_Underlying),
+ m_Alteration(a_Alteration)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override
+ {
+ // Generate the underlying biomes and the alterations:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values);
+ int alterations[m_BufferSize];
+ m_Alteration->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, alterations);
+
+ // Wherever alterations are nonzero, change into alternate biome, if available:
+ int len = a_SizeX * a_SizeZ;
+ for (int idx = 0; idx < len; ++idx)
+ {
+ if (alterations[idx] == 0)
+ {
+ continue;
+ }
+
+ // Ice spikes biome was removed from here, because it was generated way too often
+ switch (a_Values[idx])
+ {
+ case biPlains: a_Values[idx] = biSunflowerPlains; break;
+ case biDesert: a_Values[idx] = biDesertM; break;
+ case biExtremeHills: a_Values[idx] = biExtremeHillsM; break;
+ case biForest: a_Values[idx] = biFlowerForest; break;
+ case biTaiga: a_Values[idx] = biTaigaM; break;
+ case biSwampland: a_Values[idx] = biSwamplandM; break;
+ case biJungle: a_Values[idx] = biJungleM; break;
+ case biJungleEdge: a_Values[idx] = biJungleEdgeM; break;
+ case biBirchForest: a_Values[idx] = biBirchForestM; break;
+ case biBirchForestHills: a_Values[idx] = biBirchForestHillsM; break;
+ case biRoofedForest: a_Values[idx] = biRoofedForestM; break;
+ case biColdTaiga: a_Values[idx] = biColdTaigaM; break;
+ case biMegaSpruceTaiga: a_Values[idx] = biMegaSpruceTaiga; break;
+ case biMegaSpruceTaigaHills: a_Values[idx] = biMegaSpruceTaigaHills; break;
+ case biExtremeHillsPlus: a_Values[idx] = biExtremeHillsPlusM; break;
+ case biSavanna: a_Values[idx] = biSavannaM; break;
+ case biSavannaPlateau: a_Values[idx] = biSavannaPlateauM; break;
+ case biMesa: a_Values[idx] = biMesaBryce; break;
+ case biMesaPlateauF: a_Values[idx] = biMesaPlateauFM; break;
+ case biMesaPlateau: a_Values[idx] = biMesaBryce; break;
+ }
+ } // for idx - a_Values[] / alterations[]
+ }
+
+protected:
+ Underlying m_Underlying;
+ Underlying m_Alteration;
+};
+
+
+
+
diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp
index 731324b0d..bdefcd8c1 100644
--- a/src/Generating/StructGen.cpp
+++ b/src/Generating/StructGen.cpp
@@ -272,13 +272,14 @@ void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc)
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes();
+ cChunkDesc::BlockNibbleBytes & BlockMetas = a_ChunkDesc.GetBlockMetasUncompressed();
int seq = 1;
// Generate the ores from the ore list.
for (OreList::const_iterator itr = m_OreList.begin(); itr != m_OreList.end(); ++itr)
{
- GenerateOre(ChunkX, ChunkZ, itr->BlockType, itr->MaxHeight, itr->NumNests, itr->NestSize, BlockTypes, seq);
+ GenerateOre(ChunkX, ChunkZ, itr->BlockType, itr->BlockMeta, itr->MaxHeight, itr->NumNests, itr->NestSize, BlockTypes, BlockMetas, seq);
seq++;
}
}
@@ -287,7 +288,7 @@ void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc)
-void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq)
+void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, NIBBLETYPE a_BlockMeta, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, cChunkDesc::BlockNibbleBytes & a_BlockMetas, int a_Seq)
{
// This function generates several "nests" of ore, each nest consisting of number of ore blocks relatively adjacent to each other.
// It does so by making a random XYZ walk and adding ore along the way in cuboids of different (random) sizes
@@ -341,6 +342,7 @@ void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_Ore
if (a_BlockTypes[Index] == m_ToReplace)
{
a_BlockTypes[Index] = a_OreType;
+ a_BlockMetas[Index] = a_BlockMeta;
}
Num++;
} // for z
@@ -409,7 +411,7 @@ void cStructGenLakes::CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a
// Find the minimum height in this chunk:
cChunkDef::HeightMap HeightMap;
- m_HeiGen.GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap);
+ m_HeiGen->GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap);
HEIGHTTYPE MinHeight = HeightMap[0];
for (size_t i = 1; i < ARRAYCOUNT(HeightMap); i++)
{
diff --git a/src/Generating/StructGen.h b/src/Generating/StructGen.h
index 55d5bc1c7..906fdd722 100644
--- a/src/Generating/StructGen.h
+++ b/src/Generating/StructGen.h
@@ -24,7 +24,7 @@ class cStructGenTrees :
public cFinishGen
{
public:
- cStructGenTrees(int a_Seed, cBiomeGen * a_BiomeGen, cTerrainHeightGen * a_HeightGen, cTerrainCompositionGen * a_CompositionGen) :
+ cStructGenTrees(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen, cTerrainCompositionGenPtr a_CompositionGen) :
m_Seed(a_Seed),
m_Noise(a_Seed),
m_BiomeGen(a_BiomeGen),
@@ -36,9 +36,9 @@ protected:
int m_Seed;
cNoise m_Noise;
- cBiomeGen * m_BiomeGen;
- cTerrainHeightGen * m_HeightGen;
- cTerrainCompositionGen * m_CompositionGen;
+ cBiomeGenPtr m_BiomeGen;
+ cTerrainHeightGenPtr m_HeightGen;
+ cTerrainCompositionGenPtr m_CompositionGen;
/** Generates and applies an image of a single tree.
Parts of the tree inside the chunk are applied to a_BlockX.
@@ -78,10 +78,20 @@ class cStructGenOreNests :
public:
struct OreInfo
{
- BLOCKTYPE BlockType; // The type of the nest.
- int MaxHeight; // The highest possible a nest can occur
- int NumNests; // How many nests per chunk
- int NestSize; // The amount of blocks a nest can have.
+ BLOCKTYPE BlockType; // The type of the nest.
+ NIBBLETYPE BlockMeta; // The block meta
+ int MaxHeight; // The highest possible a nest can occur
+ int NumNests; // How many nests per chunk
+ int NestSize; // The amount of blocks a nest can have.
+
+ OreInfo() :
+ BlockType(0),
+ BlockMeta(0),
+ MaxHeight(0),
+ NumNests(0),
+ NestSize(0)
+ {
+ }
};
typedef std::vector<OreInfo> OreList;
@@ -103,7 +113,7 @@ protected:
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
- void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq);
+ void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, NIBBLETYPE a_BlockMeta, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, cChunkDesc::BlockNibbleBytes & a_BlockMetas, int a_Seq);
} ;
@@ -114,7 +124,7 @@ class cStructGenLakes :
public cFinishGen
{
public:
- cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGen & a_HeiGen, int a_Probability) :
+ cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGenPtr a_HeiGen, int a_Probability) :
m_Noise(a_Seed),
m_Seed(a_Seed),
m_Fluid(a_Fluid),
@@ -124,11 +134,11 @@ public:
}
protected:
- cNoise m_Noise;
- int m_Seed;
- BLOCKTYPE m_Fluid;
- cTerrainHeightGen & m_HeiGen;
- int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake
+ cNoise m_Noise;
+ int m_Seed;
+ BLOCKTYPE m_Fluid;
+ cTerrainHeightGenPtr m_HeiGen;
+ int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp
index 1b0f2dc14..7fd6d6f07 100644
--- a/src/Generating/Trees.cpp
+++ b/src/Generating/Trees.cpp
@@ -224,8 +224,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
case biMegaTaiga:
case biMegaTaigaHills:
case biExtremeHillsPlus:
- case biSavanna:
- case biSavannaPlateau:
case biMesa:
case biMesaPlateauF:
case biMesaPlateau:
@@ -241,8 +239,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
case biMegaSpruceTaiga:
case biMegaSpruceTaigaHills:
case biExtremeHillsPlusM:
- case biSavannaM:
- case biSavannaPlateauM:
case biMesaBryce:
case biMesaPlateauFM:
case biMesaPlateauM:
@@ -252,6 +248,15 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
return;
}
+ case biSavanna:
+ case biSavannaPlateau:
+ case biSavannaM:
+ case biSavannaPlateauM:
+ {
+ GetAcaciaTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
+ return;
+ }
+
case biRoofedForest:
case biRoofedForestM:
{
@@ -403,7 +408,72 @@ void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Nois
void GetAcaciaTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks)
{
- // TODO
+ // Calculate a base height
+ int Height = 2 + (a_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) / 11 % 3);
+
+ // Create the trunk
+ for (int i = 0; i < Height; i++)
+ {
+ a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_ACACIA_WOOD));
+ }
+
+ // Array with possible directions for a branch to go to.
+ const Vector3i AvailableDirections[] =
+ {
+ { -1, 1, 0 }, { 0, 1, -1 },
+ { -1, 1, 1 }, { -1, 1, -1 },
+ { 1, 1, 1 }, { 1, 1, -1 },
+ { 1, 1, 0 }, { 0, 1, 1 },
+ };
+
+ // Set the starting point of the branch
+ Vector3i BranchPos = Vector3i(a_BlockX, a_BlockY + Height - 1, a_BlockZ);
+
+ // Get a direction for the trunk to go to.
+ Vector3i BranchDirection = AvailableDirections[a_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) % 8];
+
+ // Calculate a height for the branch between 1 and 3
+ int BranchHeight = a_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) % 3 + 1;
+
+ // Place the logs of the branch.
+ for (int i = 0; i < BranchHeight; i++)
+ {
+ BranchPos = BranchPos + BranchDirection;
+ a_LogBlocks.push_back(sSetBlock(BranchPos.x, BranchPos.y, BranchPos.z, E_BLOCK_NEW_LOG, E_META_NEW_LOG_ACACIA_WOOD));
+ }
+
+ // Add the leaves to the top of the branch
+ PushCoordBlocks(BranchPos.x, BranchPos.y, BranchPos.z, a_OtherBlocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD);
+ PushCoordBlocks(BranchPos.x, BranchPos.y + 1, BranchPos.z, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD);
+ a_OtherBlocks.push_back(sSetBlock(BranchPos.x, BranchPos.y + 1, BranchPos.z, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD));
+
+ // Choose if we have to add another branch
+ bool TwoTop = (a_Noise.IntNoise3D(a_BlockX, a_BlockY, a_BlockZ) < 0 ? true : false);
+ if (!TwoTop)
+ {
+ return;
+ }
+
+ // Reset the starting point of the branch
+ BranchPos = Vector3i(a_BlockX, a_BlockY + Height - 1, a_BlockZ);
+
+ // Invert the direction of the previous branch.
+ BranchDirection = Vector3d(-BranchDirection.x, 1, -BranchDirection.z);
+
+ // Calculate a new height for the second branch
+ BranchHeight = a_Noise.IntNoise3DInt(a_BlockX * a_Seq, a_BlockY * a_Seq * 10, a_BlockZ * a_Seq) % 3 + 1;
+
+ // Place the logs in the same way as the first branch
+ for (int i = 0; i < BranchHeight; i++)
+ {
+ BranchPos = BranchPos + BranchDirection;
+ a_LogBlocks.push_back(sSetBlock(BranchPos.x, BranchPos.y, BranchPos.z, E_BLOCK_NEW_LOG, E_META_NEW_LOG_ACACIA_WOOD));
+ }
+
+ // And add the leaves ontop of the second branch
+ PushCoordBlocks(BranchPos.x, BranchPos.y, BranchPos.z, a_OtherBlocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD);
+ PushCoordBlocks(BranchPos.x, BranchPos.y + 1, BranchPos.z, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD);
+ a_OtherBlocks.push_back(sSetBlock(BranchPos.x, BranchPos.y + 1, BranchPos.z, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD));
}
diff --git a/src/Generating/UnderwaterBaseGen.cpp b/src/Generating/UnderwaterBaseGen.cpp
index 9278ea546..8916f4b5f 100644
--- a/src/Generating/UnderwaterBaseGen.cpp
+++ b/src/Generating/UnderwaterBaseGen.cpp
@@ -93,7 +93,7 @@ protected:
-cUnderwaterBaseGen::cUnderwaterBaseGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, cBiomeGen & a_BiomeGen) :
+cUnderwaterBaseGen::cUnderwaterBaseGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, cBiomeGenPtr a_BiomeGen) :
super(a_Seed, a_GridSize, a_GridSize, a_MaxOffset, a_MaxOffset, a_MaxSize, a_MaxSize, 100),
m_Noise(a_Seed + 1000),
m_MaxDepth(a_MaxDepth),
@@ -112,7 +112,7 @@ cGridStructGen::cStructurePtr cUnderwaterBaseGen::CreateStructure(int a_GridX, i
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(a_OriginX, a_OriginZ, ChunkX, ChunkZ);
cChunkDef::BiomeMap Biomes;
- m_BiomeGen.GenBiomes(ChunkX, ChunkZ, Biomes);
+ m_BiomeGen->GenBiomes(ChunkX, ChunkZ, Biomes);
// Check if all the biomes are ocean:
// If just one is not, no base is created, because it's likely that an unfriendly biome is too close
diff --git a/src/Generating/UnderwaterBaseGen.h b/src/Generating/UnderwaterBaseGen.h
index d6267b602..b24eb1075 100644
--- a/src/Generating/UnderwaterBaseGen.h
+++ b/src/Generating/UnderwaterBaseGen.h
@@ -22,7 +22,7 @@ class cUnderwaterBaseGen :
typedef cGridStructGen super;
public:
- cUnderwaterBaseGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, cBiomeGen & a_BiomeGen);
+ cUnderwaterBaseGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, cBiomeGenPtr a_BiomeGen);
protected:
class cUnderwaterBase; // fwd: UnderwaterBaseGen.cpp
@@ -38,7 +38,7 @@ protected:
int m_MaxSize;
/** The underlying biome generator that defines whether the base is created or not */
- cBiomeGen & m_BiomeGen;
+ cBiomeGenPtr m_BiomeGen;
// cGridStructGen overrides:
diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp
index a7f66b75e..a9b359b6a 100644
--- a/src/Generating/VillageGen.cpp
+++ b/src/Generating/VillageGen.cpp
@@ -116,7 +116,7 @@ public:
int a_MaxSize,
int a_Density,
cPiecePool & a_Prefabs,
- cTerrainHeightGen & a_HeightGen,
+ cTerrainHeightGenPtr a_HeightGen,
BLOCKTYPE a_RoadBlock,
BLOCKTYPE a_WaterRoadBlock
) :
@@ -175,7 +175,7 @@ protected:
cPiecePool & m_Prefabs;
/** The underlying height generator, used for placing the structures on top of the terrain. */
- cTerrainHeightGen & m_HeightGen;
+ cTerrainHeightGenPtr m_HeightGen;
/** The village pieces, placed by the generator. */
cPlacedPieces m_Pieces;
@@ -194,7 +194,7 @@ protected:
// Each intersecting prefab is placed on ground, then drawn
// Each intersecting road is drawn by replacing top soil blocks with gravel / sandstone blocks
cChunkDef::HeightMap HeightMap; // Heightmap for this chunk, used by roads
- m_HeightGen.GenHeightMap(a_Chunk.GetChunkX(), a_Chunk.GetChunkZ(), HeightMap);
+ m_HeightGen->GenHeightMap(a_Chunk.GetChunkX(), a_Chunk.GetChunkZ(), HeightMap);
for (cPlacedPieces::iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
{
cPrefab & Prefab = (cPrefab &)((*itr)->GetPiece());
@@ -224,7 +224,7 @@ protected:
int BlockY;
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cChunkDef::HeightMap HeightMap;
- m_HeightGen.GenHeightMap(ChunkX, ChunkZ, HeightMap);
+ m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap);
int TerrainHeight = cChunkDef::GetHeight(HeightMap, BlockX, BlockZ);
a_Piece.MoveToGroundBy(TerrainHeight - FirstConnector.m_Pos.y + 1);
}
@@ -359,7 +359,7 @@ static cVillagePiecePool * g_PlainsVillagePools[] =
-cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) :
+cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen) :
super(a_Seed, a_GridSize, a_GridSize, a_MaxOffset, a_MaxOffset, a_MaxSize, a_MaxSize, 100),
m_Noise(a_Seed + 1000),
m_MaxDepth(a_MaxDepth),
@@ -381,11 +381,11 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_GridX, int a_Gr
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(a_OriginX, a_OriginZ, ChunkX, ChunkZ);
cChunkDef::BiomeMap Biomes;
- m_BiomeGen.GenBiomes(ChunkX, ChunkZ, Biomes);
+ m_BiomeGen->GenBiomes(ChunkX, ChunkZ, Biomes);
// Check if all the biomes are village-friendly:
// If just one is not, no village is created, because it's likely that an unfriendly biome is too close
- cVillagePiecePool * VillagePrefabs = NULL;
+ cVillagePiecePool * VillagePrefabs = nullptr;
BLOCKTYPE RoadBlock = E_BLOCK_GRAVEL;
BLOCKTYPE WaterRoadBlock = E_BLOCK_PLANKS;
int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 11;
@@ -432,7 +432,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_GridX, int a_Gr
}
// Create a village based on the chosen prefabs:
- if (VillagePrefabs == NULL)
+ if (VillagePrefabs == nullptr)
{
return cStructurePtr();
}
diff --git a/src/Generating/VillageGen.h b/src/Generating/VillageGen.h
index 694ea2358..ed8d739df 100644
--- a/src/Generating/VillageGen.h
+++ b/src/Generating/VillageGen.h
@@ -21,7 +21,7 @@ class cVillageGen :
{
typedef cGridStructGen super;
public:
- cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen);
+ cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen);
protected:
class cVillage; // fwd: VillageGen.cpp
@@ -42,10 +42,10 @@ protected:
int m_MaxDensity;
/** The underlying biome generator that defines whether the village is created or not */
- cBiomeGen & m_BiomeGen;
+ cBiomeGenPtr m_BiomeGen;
/** The underlying height generator, used to position the prefabs crossing chunk borders */
- cTerrainHeightGen & m_HeightGen;
+ cTerrainHeightGenPtr m_HeightGen;
// cGridStructGen overrides: