diff options
Diffstat (limited to 'src/Generating')
-rw-r--r-- | src/Generating/BioGen.cpp | 250 | ||||
-rw-r--r-- | src/Generating/BioGen.h | 45 | ||||
-rw-r--r-- | src/Generating/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/Generating/Caves.cpp | 29 | ||||
-rw-r--r-- | src/Generating/ChunkGenerator.cpp | 44 | ||||
-rw-r--r-- | src/Generating/ChunkGenerator.h | 16 | ||||
-rw-r--r-- | src/Generating/ComposableGenerator.cpp | 164 | ||||
-rw-r--r-- | src/Generating/DistortedHeightmap.cpp | 9 | ||||
-rw-r--r-- | src/Generating/DungeonRoomsFinisher.cpp | 279 | ||||
-rw-r--r-- | src/Generating/DungeonRoomsFinisher.h | 52 | ||||
-rw-r--r-- | src/Generating/FinishGen.cpp | 25 | ||||
-rw-r--r-- | src/Generating/FinishGen.h | 11 | ||||
-rw-r--r-- | src/Generating/HeiGen.cpp | 10 | ||||
-rw-r--r-- | src/Generating/Noise3DGenerator.cpp | 9 | ||||
-rw-r--r-- | src/Generating/RoughRavines.cpp | 26 | ||||
-rw-r--r-- | src/Generating/StructGen.cpp | 68 | ||||
-rw-r--r-- | src/Generating/StructGen.h | 38 | ||||
-rw-r--r-- | src/Generating/Trees.cpp | 146 | ||||
-rw-r--r-- | src/Generating/Trees.h | 2 | ||||
-rw-r--r-- | src/Generating/VillageGen.cpp | 2 |
20 files changed, 962 insertions, 265 deletions
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp index 8fad9f5c9..8924a7999 100644 --- a/src/Generating/BioGen.cpp +++ b/src/Generating/BioGen.cpp @@ -13,72 +13,6 @@ //////////////////////////////////////////////////////////////////////////////// -// cBiomeGen: - -cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault) -{ - AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", ""); - if (BiomeGenName.empty()) - { - LOGWARN("[Generator] BiomeGen value not set in world.ini, using \"MultiStepMap\"."); - BiomeGenName = "MultiStepMap"; - } - - cBiomeGen * res = NULL; - a_CacheOffByDefault = false; - if (NoCaseCompare(BiomeGenName, "constant") == 0) - { - res = new cBioGenConstant; - a_CacheOffByDefault = true; // we're generating faster than a cache would retrieve data :) - } - else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0) - { - res = new cBioGenCheckerboard; - a_CacheOffByDefault = true; // we're (probably) generating faster than a cache would retrieve data - } - else if (NoCaseCompare(BiomeGenName, "voronoi") == 0) - { - res = new cBioGenVoronoi(a_Seed); - } - else if (NoCaseCompare(BiomeGenName, "distortedvoronoi") == 0) - { - res = new cBioGenDistortedVoronoi(a_Seed); - } - else if (NoCaseCompare(BiomeGenName, "twolevel") == 0) - { - res = new cBioGenTwoLevel(a_Seed); - } - else - { - if (NoCaseCompare(BiomeGenName, "multistepmap") != 0) - { - LOGWARNING("Unknown BiomeGen \"%s\", using \"MultiStepMap\" instead.", BiomeGenName.c_str()); - } - res = new cBioGenMultiStepMap(a_Seed); - - /* - // Performance-testing: - LOGINFO("Measuring performance of cBioGenMultiStepMap..."); - clock_t BeginTick = clock(); - for (int x = 0; x < 5000; x++) - { - cChunkDef::BiomeMap Biomes; - res->GenBiomes(x * 5, x * 5, Biomes); - } - clock_t Duration = clock() - BeginTick; - LOGINFO("cBioGenMultiStepMap for 5000 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); - //*/ - } - res->InitializeBiomeGen(a_IniFile); - - return res; -} - - - - - -//////////////////////////////////////////////////////////////////////////////// // cBioGenConstant: void cBioGenConstant::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) @@ -151,7 +85,7 @@ void cBioGenCache::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a LOGD("BioGenCache: %d hits, %d misses, saved %.2f %%", m_NumHits, m_NumMisses, 100.0 * m_NumHits / (m_NumHits + m_NumMisses)); LOGD("BioGenCache: Avg cache chain length: %.2f", (float)m_TotalChain / m_NumHits); } - + for (int i = 0; i < m_CacheSize; i++) { if ( @@ -208,6 +142,59 @@ void cBioGenCache::InitializeBiomeGen(cIniFile & a_IniFile) +//////////////////////////////////////////////////////////////////////////////// +// cBioGenMulticache: + +cBioGenMulticache::cBioGenMulticache(cBiomeGen * a_BioGenToCache, size_t a_CacheSize, size_t a_CachesLength) : + m_CachesLength(a_CachesLength) +{ + m_Caches.reserve(a_CachesLength); + for (size_t i = 0; i < a_CachesLength; 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; + } +} + + + + + +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; + + m_Caches[cacheIdx]->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap); +} + + + + + +void cBioGenMulticache::InitializeBiomeGen(cIniFile & a_IniFile) +{ + for (cBiomeGens::iterator it = m_Caches.begin(); it != m_Caches.end(); it++) + { + cBiomeGen * tmp = *it; + tmp->InitializeBiomeGen(a_IniFile); + } +} + + + + //////////////////////////////////////////////////////////////////////////////// // cBiomeGenList: @@ -349,8 +336,13 @@ void cBioGenVoronoi::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & void cBioGenVoronoi::InitializeBiomeGen(cIniFile & a_IniFile) { super::InitializeBiomeGen(a_IniFile); - m_Voronoi.SetCellSize(a_IniFile.GetValueSetI("Generator", "VoronoiCellSize", 64)); - InitializeBiomes (a_IniFile.GetValueSet ("Generator", "VoronoiBiomes", "")); + int CellSize = a_IniFile.GetValueSetI("Generator", "VoronoiCellSize", 128); + int JitterSize = a_IniFile.GetValueSetI("Generator", "VoronoiJitterSize", CellSize); + int OddRowOffset = a_IniFile.GetValueSetI("Generator", "VoronoiOddRowOffset", 0); + m_Voronoi.SetCellSize(CellSize); + m_Voronoi.SetJitterSize(JitterSize); + m_Voronoi.SetOddRowOffset(OddRowOffset); + InitializeBiomes(a_IniFile.GetValueSet ("Generator", "VoronoiBiomes", "")); } @@ -745,8 +737,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), @@ -770,19 +760,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 = BaseX + x * 4; + float BlockZ = 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]); @@ -793,9 +781,10 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap { for (int x = 0; x < cChunkDef::Width; x++) { - int MinDist1, MinDist2; - int BiomeGroup = m_VoronoiLarge.GetValueAt(DistortX[x][z], DistortZ[x][z], MinDist1, MinDist2) / 7; - int BiomeIdx = m_VoronoiSmall.GetValueAt(DistortX[x][z], DistortZ[x][z], MinDist1, MinDist2) / 11; + int SeedX, SeedZ, MinDist2; + 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)); } } @@ -920,15 +909,86 @@ EMCSBiome cBioGenTwoLevel::SelectBiome(int a_BiomeGroup, int a_BiomeIdx, int a_D void cBioGenTwoLevel::InitializeBiomeGen(cIniFile & a_IniFile) { - // TODO: Read these from a file - m_VoronoiLarge.SetCellSize(1024); - m_VoronoiSmall.SetCellSize(128); - m_DistortX.AddOctave(0.01f, 16); - m_DistortX.AddOctave(0.005f, 8); - m_DistortX.AddOctave(0.0025f, 4); - m_DistortZ.AddOctave(0.01f, 16); - m_DistortZ.AddOctave(0.005f, 8); - m_DistortZ.AddOctave(0.0025f, 4); + m_VoronoiLarge.SetCellSize(a_IniFile.GetValueSetI("Generator", "TwoLevelLargeCellSize", 1024)); + m_VoronoiSmall.SetCellSize(a_IniFile.GetValueSetI("Generator", "TwoLevelSmallCellSize", 128)); + 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); +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cBiomeGen: + +cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault) +{ + AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", ""); + if (BiomeGenName.empty()) + { + LOGWARN("[Generator] BiomeGen value not set in world.ini, using \"MultiStepMap\"."); + BiomeGenName = "MultiStepMap"; + } + + cBiomeGen * res = NULL; + a_CacheOffByDefault = false; + if (NoCaseCompare(BiomeGenName, "constant") == 0) + { + res = new cBioGenConstant; + a_CacheOffByDefault = true; // we're generating faster than a cache would retrieve data :) + } + else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0) + { + res = new cBioGenCheckerboard; + a_CacheOffByDefault = true; // we're (probably) generating faster than a cache would retrieve data + } + else if (NoCaseCompare(BiomeGenName, "voronoi") == 0) + { + res = new cBioGenVoronoi(a_Seed); + } + else if (NoCaseCompare(BiomeGenName, "distortedvoronoi") == 0) + { + res = new cBioGenDistortedVoronoi(a_Seed); + } + else if (NoCaseCompare(BiomeGenName, "twolevel") == 0) + { + res = new cBioGenTwoLevel(a_Seed); + } + else + { + if (NoCaseCompare(BiomeGenName, "multistepmap") != 0) + { + LOGWARNING("Unknown BiomeGen \"%s\", using \"MultiStepMap\" instead.", BiomeGenName.c_str()); + } + res = new cBioGenMultiStepMap(a_Seed); + + /* + // Performance-testing: + LOGINFO("Measuring performance of cBioGenMultiStepMap..."); + clock_t BeginTick = clock(); + for (int x = 0; x < 5000; x++) + { + cChunkDef::BiomeMap Biomes; + res->GenBiomes(x * 5, x * 5, Biomes); + } + clock_t Duration = clock() - BeginTick; + LOGINFO("cBioGenMultiStepMap for 5000 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); + //*/ + } + res->InitializeBiomeGen(a_IniFile); + + return res; } diff --git a/src/Generating/BioGen.h b/src/Generating/BioGen.h index 227ec97d7..22ddfae5c 100644 --- a/src/Generating/BioGen.h +++ b/src/Generating/BioGen.h @@ -80,6 +80,36 @@ protected: +class cBioGenMulticache : + public cBiomeGen +{ + + 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(); + +protected: + typedef std::vector<cBiomeGen *> cBiomeGens; + + + size_t m_CachesLength; + cBiomeGens m_Caches; + + + virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override; + virtual void InitializeBiomeGen(cIniFile & a_IniFile) override; +}; + + + + + /// Base class for generators that use a list of available biomes. This class takes care of the list. class cBiomeGenList : public cBiomeGen @@ -255,12 +285,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; @@ -268,6 +293,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 58df9d421..33d622b42 100644 --- a/src/Generating/CMakeLists.txt +++ b/src/Generating/CMakeLists.txt @@ -12,6 +12,7 @@ SET (SRCS CompoGen.cpp ComposableGenerator.cpp DistortedHeightmap.cpp + DungeonRoomsFinisher.cpp EndGen.cpp FinishGen.cpp GridStructGen.cpp @@ -40,6 +41,7 @@ SET (HDRS CompoGen.h ComposableGenerator.h DistortedHeightmap.h + DungeonRoomsFinisher.h EndGen.h FinishGen.h GridStructGen.h diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp index 3b71efb57..fc925a150 100644 --- a/src/Generating/Caves.cpp +++ b/src/Generating/Caves.cpp @@ -166,6 +166,9 @@ cCaveTunnel::cCaveTunnel( if ((a_BlockStartY <= 0) && (a_BlockEndY <= 0)) { // Don't bother detailing this cave, it's under the world anyway + m_MinBlockX = m_MaxBlockX = 0; + m_MinBlockY = m_MaxBlockY = -1; + m_MinBlockZ = m_MaxBlockZ = 0; return; } @@ -497,29 +500,9 @@ void cCaveTunnel::ProcessChunk( int SqDist = (DifX - x) * (DifX - x) + (DifY - y) * (DifY - y) + (DifZ - z) * (DifZ - z); if (4 * SqDist <= SqRad) { - switch (cChunkDef::GetBlock(a_BlockTypes, x, y, z)) + if (cBlockInfo::CanBeTerraformed(cChunkDef::GetBlock(a_BlockTypes, x, y, z))) { - // Only carve out these specific block types - case E_BLOCK_DIRT: - case E_BLOCK_GRASS: - case E_BLOCK_STONE: - case E_BLOCK_COBBLESTONE: - case E_BLOCK_GRAVEL: - case E_BLOCK_SAND: - case E_BLOCK_SANDSTONE: - case E_BLOCK_SOULSAND: - case E_BLOCK_NETHERRACK: - case E_BLOCK_COAL_ORE: - case E_BLOCK_IRON_ORE: - case E_BLOCK_GOLD_ORE: - case E_BLOCK_DIAMOND_ORE: - case E_BLOCK_REDSTONE_ORE: - case E_BLOCK_REDSTONE_ORE_GLOWING: - { - cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR); - break; - } - default: break; + cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR); } } } // for y @@ -772,7 +755,7 @@ void cStructGenDualRidgeCaves::GenFinish(cChunkDesc & a_ChunkDesc) float n2 = m_Noise2.CubicNoise3D(xx, yy, zz); float n3 = m_Noise1.CubicNoise3D(xx * 4, yy * 4, zz * 4) / 4; float n4 = m_Noise2.CubicNoise3D(xx * 4, yy * 4, zz * 4) / 4; - if ((abs(n1 + n3) * abs(n2 + n4)) > m_Threshold) + if ((std::abs(n1 + n3) * std::abs(n2 + n4)) > m_Threshold) { a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR); } diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index 3d5af152c..d615456c1 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -27,6 +27,7 @@ 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) @@ -51,10 +52,21 @@ bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a m_PluginInterface = &a_PluginInterface; m_ChunkSink = &a_ChunkSink; - MTRand rnd; - m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", (int)rnd.randInt()); + // Get the seed; create a new one and log it if not found in the INI file: + if (a_IniFile.HasValue("Seed", "Seed")) + { + m_Seed = a_IniFile.GetValueI("Seed", "Seed"); + } + else + { + MTRand rnd; + m_Seed = rnd.randInt(); + LOGINFO("Chosen a new random seed for world: %d", m_Seed); + a_IniFile.SetValueI("Seed", "Seed", m_Seed); + } + + // Get the generator engine based on the INI file settings: AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable"); - if (NoCaseCompare(GeneratorName, "Noise3D") == 0) { m_Generator = new cNoise3DGenerator(*this); @@ -98,15 +110,17 @@ void cChunkGenerator::Stop(void) -void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate) { + ASSERT(m_ChunkSink->IsChunkQueued(a_ChunkX, a_ChunkZ)); + { cCSLock Lock(m_CS); // Check if it is already in the queue: - for (cChunkCoordsList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr) + for (cChunkCoordsWithBoolList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr) { - if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ)) + if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ)) { // Already in the queue, bail out return; @@ -118,7 +132,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk { LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size()); } - m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + m_Queue.push_back(cChunkCoordsWithBool(a_ChunkX, a_ChunkZ, a_ForceGenerate)); } m_Event.Set(); @@ -228,9 +242,9 @@ void cChunkGenerator::Execute(void) continue; } - cChunkCoords coords = m_Queue.front(); // Get next coord from queue - m_Queue.erase( m_Queue.begin()); // Remove coordinate from queue + cChunkCoordsWithBool coords = m_Queue.front(); // Get next coord from queue bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT); + m_Queue.erase(m_Queue.begin()); // Remove coordinate from queue Lock.Unlock(); // Unlock ASAP m_evtRemoved.Set(); @@ -244,8 +258,7 @@ void cChunkGenerator::Execute(void) LastReportTick = clock(); } - // Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set - if ((coords.m_ChunkY == 0) && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) + if (!coords.m_ForceGenerate && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) { LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ); // Already generated, ignore request @@ -258,8 +271,8 @@ void cChunkGenerator::Execute(void) continue; } - LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); + LOGD("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); + DoGenerate(coords.m_ChunkX, coords.m_ChunkZ); NumChunksGenerated++; } // while (!bStop) @@ -268,11 +281,12 @@ void cChunkGenerator::Execute(void) -void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ) { ASSERT(m_PluginInterface != NULL); ASSERT(m_ChunkSink != NULL); - + ASSERT(m_ChunkSink->IsChunkQueued(a_ChunkX, a_ChunkZ)); + cChunkDesc ChunkDesc(a_ChunkX, a_ChunkZ); m_PluginInterface->CallHookChunkGenerating(ChunkDesc); m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc); diff --git a/src/Generating/ChunkGenerator.h b/src/Generating/ChunkGenerator.h index 88d71f3f9..190d9e616 100644 --- a/src/Generating/ChunkGenerator.h +++ b/src/Generating/ChunkGenerator.h @@ -106,6 +106,10 @@ public: If this callback returns false, the chunk is not generated. */ virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) = 0; + + /** Called to check whether the specified chunk is in the queued state. + Currently used only in Debug-mode asserts. */ + virtual bool IsChunkQueued(int a_ChunkX, int a_ChunkZ) = 0; } ; @@ -116,7 +120,7 @@ public: void Stop(void); /// Queues the chunk for generation; removes duplicate requests - void QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate); /// Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading. void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap); @@ -137,10 +141,10 @@ private: int m_Seed; - cCriticalSection m_CS; - cChunkCoordsList m_Queue; - cEvent m_Event; ///< Set when an item is added to the queue or the thread should terminate - cEvent m_evtRemoved; ///< Set when an item is removed from the queue + cCriticalSection m_CS; + cChunkCoordsWithBoolList m_Queue; + cEvent m_Event; ///< Set when an item is added to the queue or the thread should terminate + cEvent m_evtRemoved; ///< Set when an item is removed from the queue cGenerator * m_Generator; ///< The actual generator engine used to generate chunks @@ -154,7 +158,7 @@ private: // cIsThread override: virtual void Execute(void) override; - void DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void DoGenerate(int a_ChunkX, int a_ChunkZ); }; diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index a7659149a..87461b944 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -19,6 +19,7 @@ #include "Caves.h" #include "DistortedHeightmap.h" +#include "DungeonRoomsFinisher.h" #include "EndGen.h" #include "MineShafts.h" #include "NetherFortGen.h" @@ -229,17 +230,29 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile) // Add a cache, if requested: int CacheSize = a_IniFile.GetValueSetI("Generator", "BiomeGenCacheSize", CacheOffByDefault ? 0 : 64); - if (CacheSize > 0) + + if (CacheSize <= 0) + { + return; + } + + int MultiCacheLength = a_IniFile.GetValueSetI("Generator", "BiomeGenMultiCacheLength", 4); + if (CacheSize < 4) + { + LOGWARNING("Biomegen cache size set too low, would hurt performance instead of helping. Increasing from %d to %d", + CacheSize, 4 + ); + 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); + } + else { - if (CacheSize < 4) - { - LOGWARNING("Biomegen cache size set too low, would hurt performance instead of helping. Increasing from %d to %d", - CacheSize, 4 - ); - CacheSize = 4; - } - LOGD("Using a cache for biomegen of size %d.", CacheSize); - m_UnderlyingBiomeGen = m_BiomeGen; m_BiomeGen = new cBioGenCache(m_UnderlyingBiomeGen, CacheSize); } } @@ -343,6 +356,14 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3); m_FinishGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold)); } + else if (NoCaseCompare(*itr, "DungeonRooms") == 0) + { + int GridSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsGridSize", 48); + 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)); + } else if (NoCaseCompare(*itr, "Ice") == 0) { m_FinishGens.push_back(new cFinishGenIce); @@ -387,6 +408,55 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) m_FinishGens.push_back(new cFinishGenSingleTopBlock(Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks)); } + else if (NoCaseCompare(*itr, "NaturalPatches") == 0) + { + cStructGenOreNests::OreList Ores; + + // Dirt vein + cStructGenOreNests::OreInfo DirtVein; + DirtVein.BlockType = E_BLOCK_DIRT; + DirtVein.MaxHeight = 127; + DirtVein.NumNests = 20; + DirtVein.NestSize = 32; + Ores.push_back(DirtVein); + + // Gravel vein + cStructGenOreNests::OreInfo GravelVein; + GravelVein.BlockType = E_BLOCK_GRAVEL; + GravelVein.MaxHeight = 127; + GravelVein.NumNests = 20; + GravelVein.NestSize = 32; + Ores.push_back(GravelVein); + + // 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(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE)); + } else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0) { m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed)); @@ -398,9 +468,74 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) int MaxDepth = a_IniFile.GetValueSetI("Generator", "NetherFortsMaxDepth", 12); m_FinishGens.push_back(new cNetherFortGen(Seed, GridSize, MaxOffset, MaxDepth)); } + else if (NoCaseCompare(*itr, "NetherOreNests") == 0) + { + cStructGenOreNests::OreList Ores; + + // Quartz vein + cStructGenOreNests::OreInfo QuartzVein; + QuartzVein.BlockType = E_BLOCK_NETHER_QUARTZ_ORE; + QuartzVein.MaxHeight = 255; + QuartzVein.NumNests = 80; + QuartzVein.NestSize = 8; + Ores.push_back(QuartzVein); + + m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_NETHERRACK)); + + } else if (NoCaseCompare(*itr, "OreNests") == 0) { - m_FinishGens.push_back(new cStructGenOreNests(Seed)); + cStructGenOreNests::OreList Ores; + + // Coal vein + cStructGenOreNests::OreInfo CoalVein; + CoalVein.BlockType = E_BLOCK_COAL_ORE; + CoalVein.MaxHeight = 127; + CoalVein.NumNests = 50; + CoalVein.NestSize = 10; + Ores.push_back(CoalVein); + + // Iron vein + cStructGenOreNests::OreInfo IronVein; + IronVein.BlockType = E_BLOCK_IRON_ORE; + IronVein.MaxHeight = 64; + IronVein.NumNests = 14; + IronVein.NestSize = 6; + Ores.push_back(IronVein); + + // Gold vein + cStructGenOreNests::OreInfo GoldVein; + GoldVein.BlockType = E_BLOCK_GOLD_ORE; + GoldVein.MaxHeight = 32; + GoldVein.NumNests = 2; + GoldVein.NestSize = 6; + Ores.push_back(GoldVein); + + // Redstone vein + cStructGenOreNests::OreInfo RedstoneVein; + RedstoneVein.BlockType = E_BLOCK_REDSTONE_ORE; + RedstoneVein.MaxHeight = 16; + RedstoneVein.NumNests = 4; + RedstoneVein.NestSize = 6; + Ores.push_back(RedstoneVein); + + // Lapis vein + cStructGenOreNests::OreInfo LapisVein; + LapisVein.BlockType = E_BLOCK_LAPIS_ORE; + LapisVein.MaxHeight = 30; + LapisVein.NumNests = 2; + LapisVein.NestSize = 5; + Ores.push_back(LapisVein); + + // Diamond vein + cStructGenOreNests::OreInfo DiamondVein; + DiamondVein.BlockType = E_BLOCK_DIAMOND_ORE; + DiamondVein.MaxHeight = 15; + DiamondVein.NumNests = 1; + DiamondVein.NestSize = 4; + Ores.push_back(DiamondVein); + + m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE)); } else if (NoCaseCompare(*itr, "POCPieces") == 0) { @@ -408,7 +543,12 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "PreSimulator") == 0) { - m_FinishGens.push_back(new cFinishGenPreSimulator); + // Load the settings + bool PreSimulateFallingBlocks = a_IniFile.GetValueSetB("Generator", "PreSimulatorFallingBlocks", true); + 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)); } else if (NoCaseCompare(*itr, "RainbowRoads") == 0) { diff --git a/src/Generating/DistortedHeightmap.cpp b/src/Generating/DistortedHeightmap.cpp index c18c402da..bf8995dcb 100644 --- a/src/Generating/DistortedHeightmap.cpp +++ b/src/Generating/DistortedHeightmap.cpp @@ -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)) diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp new file mode 100644 index 000000000..f213455d6 --- /dev/null +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -0,0 +1,279 @@ + +// DungeonRoomsFinisher.cpp + +// Declares the cDungeonRoomsFinisher class representing the finisher that generates dungeon rooms + +#include "Globals.h" +#include "DungeonRoomsFinisher.h" +#include "../FastRandom.h" + + + + + +/** Height, in blocks, of the internal dungeon room open space. This many air blocks Y-wise. */ +static const int ROOM_HEIGHT = 4; + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cDungeonRoom: + +class cDungeonRoom : + public cGridStructGen::cStructure +{ + typedef cGridStructGen::cStructure super; + +public: + + cDungeonRoom( + int a_GridX, int a_GridZ, + int a_OriginX, int a_OriginZ, + int a_HalfSizeX, int a_HalfSizeZ, + int a_FloorHeight, + cNoise & a_Noise + ) : + super(a_GridX, a_GridZ, a_OriginX, a_OriginZ), + m_StartX(a_OriginX - a_HalfSizeX), + m_EndX(a_OriginX + a_HalfSizeX), + m_StartZ(a_OriginZ - a_HalfSizeZ), + m_EndZ(a_OriginZ + a_HalfSizeZ), + m_FloorHeight(a_FloorHeight) + { + /* + Pick coords next to the wall for the chests. + This is done by indexing the possible coords, picking any one for the first chest + and then picking another position for the second chest that is not adjacent to the first pos + */ + int rnd = a_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 7; + int SizeX = m_EndX - m_StartX - 1; + int SizeZ = m_EndZ - m_StartZ - 1; + int NumPositions = 2 * SizeX + 2 * SizeZ; + int FirstChestPos = rnd % NumPositions; // The corner positions are a bit more likely, but we don't mind + rnd = rnd / 512; + int SecondChestPos = (FirstChestPos + 2 + (rnd % (NumPositions - 3))) % NumPositions; + m_Chest1 = DecodeChestCoords(FirstChestPos, SizeX, SizeZ); + m_Chest2 = DecodeChestCoords(SecondChestPos, SizeX, SizeZ); + } + +protected: + + // The X range of the room, start inclusive, end exclusive: + int m_StartX, m_EndX; + + // The Z range of the room, start inclusive, end exclusive: + int m_StartZ, m_EndZ; + + /** The Y coord of the floor of the room */ + int m_FloorHeight; + + /** The (absolute) coords of the first chest. The Y coord represents the chest's Meta value (facing). */ + Vector3i m_Chest1; + + /** The (absolute) coords of the second chest. The Y coord represents the chest's Meta value (facing). */ + Vector3i m_Chest2; + + + + /** Decodes the position index along the room walls into a proper 2D position for a chest. */ + Vector3i DecodeChestCoords(int a_PosIdx, int a_SizeX, int a_SizeZ) + { + if (a_PosIdx < a_SizeX) + { + // Return a coord on the ZM side of the room: + return Vector3i(m_StartX + a_PosIdx + 1, E_META_CHEST_FACING_ZP, m_StartZ + 1); + } + a_PosIdx -= a_SizeX; + if (a_PosIdx < a_SizeZ) + { + // Return a coord on the XP side of the room: + return Vector3i(m_EndX - 1, E_META_CHEST_FACING_XM, m_StartZ + a_PosIdx + 1); + } + a_PosIdx -= a_SizeZ; + if (a_PosIdx < a_SizeX) + { + // Return a coord on the ZP side of the room: + return Vector3i(m_StartX + a_PosIdx + 1, E_META_CHEST_FACING_ZM, m_StartZ + 1); + } + a_PosIdx -= a_SizeX; + // Return a coord on the XM side of the room: + return Vector3i(m_StartX + 1, E_META_CHEST_FACING_XP, m_StartZ + a_PosIdx + 1); + } + + + + /** Fills the specified area of blocks in the chunk with the specified blocktype if they are one of the overwritten block types. + The coords are absolute, start coords are inclusive, end coords are exclusive. */ + void ReplaceCuboid(cChunkDesc & a_ChunkDesc, int a_StartX, int a_StartY, int a_StartZ, int a_EndX, int a_EndY, int a_EndZ, BLOCKTYPE a_DstBlockType) + { + int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + int RelStartX = Clamp(a_StartX - BlockX, 0, cChunkDef::Width - 1); + int RelStartZ = Clamp(a_StartZ - BlockZ, 0, cChunkDef::Width - 1); + int RelEndX = Clamp(a_EndX - BlockX, 0, cChunkDef::Width); + int RelEndZ = Clamp(a_EndZ - BlockZ, 0, cChunkDef::Width); + for (int y = a_StartY; y < a_EndY; y++) + { + for (int z = RelStartZ; z < RelEndZ; z++) + { + for (int x = RelStartX; x < RelEndX; x++) + { + if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z))) + { + a_ChunkDesc.SetBlockType(x, y, z, a_DstBlockType); + } + } // for x + } // for z + } // for z + } + + + + /** Fills the specified area of blocks in the chunk with a random pattern of the specified blocktypes, if they are one of the overwritten block types. + The coords are absolute, start coords are inclusive, end coords are exclusive. The first blocktype uses 75% chance, the second 25% chance. */ + void ReplaceCuboidRandom(cChunkDesc & a_ChunkDesc, int a_StartX, int a_StartY, int a_StartZ, int a_EndX, int a_EndY, int a_EndZ, BLOCKTYPE a_DstBlockType1, BLOCKTYPE a_DstBlockType2) + { + int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + int RelStartX = Clamp(a_StartX - BlockX, 0, cChunkDef::Width - 1); + int RelStartZ = Clamp(a_StartZ - BlockZ, 0, cChunkDef::Width - 1); + int RelEndX = Clamp(a_EndX - BlockX, 0, cChunkDef::Width); + int RelEndZ = Clamp(a_EndZ - BlockZ, 0, cChunkDef::Width); + cFastRandom rnd; + for (int y = a_StartY; y < a_EndY; y++) + { + for (int z = RelStartZ; z < RelEndZ; z++) + { + for (int x = RelStartX; x < RelEndX; x++) + { + if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z))) + { + BLOCKTYPE BlockType = (rnd.NextInt(101) < 75) ? a_DstBlockType1 : a_DstBlockType2; + a_ChunkDesc.SetBlockType(x, y, z, BlockType); + } + } // for x + } // for z + } // for z + } + + + + /** Tries to place a chest at the specified (absolute) coords. + Does nothing if the coords are outside the chunk. */ + void TryPlaceChest(cChunkDesc & a_ChunkDesc, const Vector3i & a_Chest) + { + int RelX = a_Chest.x - a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int RelZ = a_Chest.z - a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + if ( + (RelX < 0) || (RelX >= cChunkDef::Width) || // The X coord is not in this chunk + (RelZ < 0) || (RelZ >= cChunkDef::Width) // The Z coord is not in this chunk + ) + { + return; + } + a_ChunkDesc.SetBlockTypeMeta(RelX, m_FloorHeight + 1, RelZ, E_BLOCK_CHEST, (NIBBLETYPE)a_Chest.y); + + // TODO: Fill the chest with random loot + } + + + + // cGridStructGen::cStructure override: + virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override + { + if ( + (m_EndX < a_ChunkDesc.GetChunkX() * cChunkDef::Width) || + (m_StartX >= a_ChunkDesc.GetChunkX() * cChunkDef::Width + cChunkDef::Width) || + (m_EndZ < a_ChunkDesc.GetChunkZ() * cChunkDef::Width) || + (m_StartZ >= a_ChunkDesc.GetChunkZ() * cChunkDef::Width + cChunkDef::Width) + ) + { + // 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 + ReplaceCuboid(a_ChunkDesc, m_StartX + 1, b, m_StartZ + 1, m_EndX, t, m_EndZ, E_BLOCK_AIR); // Insides + + // Walls: + ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_StartX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XM wall + ReplaceCuboid(a_ChunkDesc, m_EndX, b, m_StartZ, m_EndX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XP wall + ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_EndX + 1, t, m_StartZ + 1, E_BLOCK_COBBLESTONE); // ZM wall + ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_EndZ, m_EndX + 1, t, m_EndZ + 1, E_BLOCK_COBBLESTONE); // ZP wall + + // Place chests: + TryPlaceChest(a_ChunkDesc, m_Chest1); + TryPlaceChest(a_ChunkDesc, m_Chest2); + + // Place the spawner: + int CenterX = (m_StartX + m_EndX) / 2 - a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int CenterZ = (m_StartZ + m_EndZ) / 2 - a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + if ( + (CenterX >= 0) && (CenterX < cChunkDef::Width) && + (CenterZ >= 0) && (CenterZ < cChunkDef::Width) + ) + { + a_ChunkDesc.SetBlockTypeMeta(CenterX, b, CenterZ, E_BLOCK_MOB_SPAWNER, 0); + // TODO: Set the spawned mob + } + } +} ; + + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cDungeonRoomsFinisher: + +cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGen & 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), + m_MinHalfSize((a_MinSize + 1) / 2), + m_HeightProbability(cChunkDef::Height) +{ + // Initialize the height probability distribution: + m_HeightProbability.SetDefString(a_HeightDistrib); + + // Normalize the min and max size: + if (m_MinHalfSize > m_MaxHalfSize) + { + std::swap(m_MinHalfSize, m_MaxHalfSize); + } +} + + + + + + +cDungeonRoomsFinisher::cStructurePtr cDungeonRoomsFinisher::CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) +{ + // Select a random room size in each direction: + int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 7; + int HalfSizeX = m_MinHalfSize + (rnd % (m_MaxHalfSize - m_MinHalfSize + 1)); + rnd = rnd / 32; + int HalfSizeZ = m_MinHalfSize + (rnd % (m_MaxHalfSize - m_MinHalfSize + 1)); + rnd = rnd / 32; + + // Select a random floor height for the room, based on the height generator: + int ChunkX, ChunkZ; + 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); + 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); + + // Create the dungeon room descriptor: + return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, Height, m_Noise)); +} + + + + diff --git a/src/Generating/DungeonRoomsFinisher.h b/src/Generating/DungeonRoomsFinisher.h new file mode 100644 index 000000000..2b52c9de6 --- /dev/null +++ b/src/Generating/DungeonRoomsFinisher.h @@ -0,0 +1,52 @@ + +// DungeonRoomsFinisher.h + +// Declares the cDungeonRoomsFinisher class representing the finisher that generates dungeon rooms + + + + + +#pragma once + +#include "GridStructGen.h" +#include "../ProbabDistrib.h" + + + + + +class cDungeonRoomsFinisher : + public cGridStructGen +{ + typedef cGridStructGen super; + +public: + /** Creates a new dungeon room finisher. + 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); + +protected: + + /** The height gen that is used for limiting the rooms' Y coords */ + cTerrainHeightGen & m_HeightGen; + + /** Maximum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 3 (vanilla). */ + int m_MaxHalfSize; + + /** Minimum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 2 (vanilla). */ + int m_MinHalfSize; + + /** The height probability distribution to make the spawners more common in layers 10 - 40, less common outside this range. */ + cProbabDistrib m_HeightProbability; + + + // cGridStructGen overrides: + virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override; +} ; + + + + diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index f53addb68..96e3dc26b 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -15,6 +15,7 @@ #include "../Simulator/FluidSimulator.h" // for cFluidSimulator::CanWashAway() #include "../Simulator/FireSimulator.h" #include "../World.h" +#include "inifile/iniFile.h" @@ -484,8 +485,6 @@ int cFinishGenSingleTopBlock::GetNumToGen(const cChunkDef::BiomeMap & a_BiomeMap void cFinishGenSingleTopBlock::GenFinish(cChunkDesc & a_ChunkDesc) { - // Add Lilypads on top of water surface in Swampland - int NumToGen = GetNumToGen(a_ChunkDesc.GetBiomeMap()); int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkZ = a_ChunkDesc.GetChunkZ(); @@ -555,7 +554,10 @@ void cFinishGenBottomLava::GenFinish(cChunkDesc & a_ChunkDesc) //////////////////////////////////////////////////////////////////////////////// // cFinishGenPreSimulator: -cFinishGenPreSimulator::cFinishGenPreSimulator(void) +cFinishGenPreSimulator::cFinishGenPreSimulator(bool a_PreSimulateFallingBlocks, bool a_PreSimulateWater, bool a_PreSimulateLava) : + m_PreSimulateFallingBlocks(a_PreSimulateFallingBlocks), + m_PreSimulateWater(a_PreSimulateWater), + m_PreSimulateLava(a_PreSimulateLava) { // Nothing needed yet } @@ -566,9 +568,20 @@ cFinishGenPreSimulator::cFinishGenPreSimulator(void) void cFinishGenPreSimulator::GenFinish(cChunkDesc & a_ChunkDesc) { - CollapseSandGravel(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap()); - StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER); - StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA); + if (m_PreSimulateFallingBlocks) + { + CollapseSandGravel(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap()); + } + + if (m_PreSimulateWater) + { + StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER); + } + + if (m_PreSimulateLava) + { + StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA); + } // TODO: other operations } diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index ed32768b3..4a08d70c8 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -163,7 +163,7 @@ public: m_Amount(a_Amount) { // Initialize all the block types. - for (int idx = 0; idx < ARRAYCOUNT(m_IsAllowedBelow); ++idx) + for (size_t idx = 0; idx < ARRAYCOUNT(m_IsAllowedBelow); ++idx) { m_IsAllowedBelow[idx] = false; } @@ -175,7 +175,7 @@ public: } // Initialize all the biome types. - for (int idx = 0; idx < ARRAYCOUNT(m_IsBiomeAllowed); ++idx) + for (size_t idx = 0; idx < ARRAYCOUNT(m_IsBiomeAllowed); ++idx) { m_IsBiomeAllowed[idx] = false; } @@ -240,9 +240,14 @@ class cFinishGenPreSimulator : public cFinishGen { public: - cFinishGenPreSimulator(void); + cFinishGenPreSimulator(bool a_PreSimulateFallingBlocks, bool a_PreSimulateWater, bool a_PreSimulateLava); protected: + + bool m_PreSimulateFallingBlocks; + bool m_PreSimulateWater; + bool m_PreSimulateLava; + // Drops hanging sand and gravel down to the ground, recalculates heightmap void CollapseSandGravel( cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp index 870ceef7f..79d529a6a 100644 --- a/src/Generating/HeiGen.cpp +++ b/src/Generating/HeiGen.cpp @@ -239,7 +239,13 @@ bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_Rel cHeiGenClassic::cHeiGenClassic(int a_Seed) : m_Seed(a_Seed), - m_Noise(a_Seed) + m_Noise(a_Seed), + m_HeightFreq1(1.0f), + m_HeightAmp1(1.0f), + m_HeightFreq2(0.5f), + m_HeightAmp2(0.5f), + m_HeightFreq3(0.1f), + m_HeightAmp3(0.1f) { } @@ -432,7 +438,7 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] = /* biExtremeHillsM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 131 /* biFlowerForest */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 132 /* biTaigaM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 133 - /* biSwamplandM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 134 + /* 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 diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp index b879349ee..c3ca30384 100644 --- a/src/Generating/Noise3DGenerator.cpp +++ b/src/Generating/Noise3DGenerator.cpp @@ -236,7 +236,7 @@ void cNoise3DGenerator::GenerateNoiseArray(int a_ChunkX, int a_ChunkZ, NOISE_DAT m_Cubic.Generate2D(Height, DIM_X, DIM_Z, StartX / 25, EndX / 25, StartZ / 25, EndZ / 25); for (size_t i = 0; i < ARRAYCOUNT(Height); i++) { - Height[i] = abs(Height[i]) * m_HeightAmplification + 1; + Height[i] = std::abs(Height[i]) * m_HeightAmplification + 1; } // Modify the noise by height data: @@ -395,7 +395,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) for (int x = 0; x < 17; x += UPSCALE_X) { NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX; - NOISE_DATATYPE val = abs(m_Noise1.CubicNoise2D(NoiseX / 5, NoiseZ / 5)) * m_HeightAmplification + 1; + NOISE_DATATYPE val = std::abs(m_Noise1.CubicNoise2D(NoiseX / 5, NoiseZ / 5)) * m_HeightAmplification + 1; Height[x + 17 * z] = val * val * val; } } @@ -412,11 +412,12 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) for (int x = 0; x < 17; x += UPSCALE_X) { NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX; - CurFloor[x + 17 * z] = + 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]; + AddHeight / Height[x + 17 * z] + ); } } // Linear-interpolate this XZ floor: diff --git a/src/Generating/RoughRavines.cpp b/src/Generating/RoughRavines.cpp index badc7768e..2ee3704b3 100644 --- a/src/Generating/RoughRavines.cpp +++ b/src/Generating/RoughRavines.cpp @@ -201,29 +201,11 @@ protected: { continue; } - switch (a_ChunkDesc.GetBlockType(x, y, z)) + + if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z))) { - // Only carve out these specific block types - case E_BLOCK_DIRT: - case E_BLOCK_GRASS: - case E_BLOCK_STONE: - case E_BLOCK_COBBLESTONE: - case E_BLOCK_GRAVEL: - case E_BLOCK_SAND: - case E_BLOCK_SANDSTONE: - case E_BLOCK_NETHERRACK: - case E_BLOCK_COAL_ORE: - case E_BLOCK_IRON_ORE: - case E_BLOCK_GOLD_ORE: - case E_BLOCK_DIAMOND_ORE: - case E_BLOCK_REDSTONE_ORE: - case E_BLOCK_REDSTONE_ORE_GLOWING: - { - a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR); - break; - } - default: break; - } // switch (BlockType) + a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR); + } } // for y } // for x, z - a_BlockTypes } // for itr - m_Points[] diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp index 054eec345..c23a72621 100644 --- a/src/Generating/StructGen.cpp +++ b/src/Generating/StructGen.cpp @@ -13,45 +13,6 @@ //////////////////////////////////////////////////////////////////////////////// -// cStructGenOreNests configuration: - -const int MAX_HEIGHT_COAL = 127; -const int NUM_NESTS_COAL = 50; -const int NEST_SIZE_COAL = 10; - -const int MAX_HEIGHT_IRON = 64; -const int NUM_NESTS_IRON = 14; -const int NEST_SIZE_IRON = 6; - -const int MAX_HEIGHT_REDSTONE = 16; -const int NUM_NESTS_REDSTONE = 4; -const int NEST_SIZE_REDSTONE = 6; - -const int MAX_HEIGHT_GOLD = 32; -const int NUM_NESTS_GOLD = 2; -const int NEST_SIZE_GOLD = 6; - -const int MAX_HEIGHT_DIAMOND = 15; -const int NUM_NESTS_DIAMOND = 1; -const int NEST_SIZE_DIAMOND = 4; - -const int MAX_HEIGHT_LAPIS = 30; -const int NUM_NESTS_LAPIS = 2; -const int NEST_SIZE_LAPIS = 5; - -const int MAX_HEIGHT_DIRT = 127; -const int NUM_NESTS_DIRT = 20; -const int NEST_SIZE_DIRT = 32; - -const int MAX_HEIGHT_GRAVEL = 70; -const int NUM_NESTS_GRAVEL = 15; -const int NEST_SIZE_GRAVEL = 32; - - - - - -//////////////////////////////////////////////////////////////////////////////// // cStructGenTrees: void cStructGenTrees::GenFinish(cChunkDesc & a_ChunkDesc) @@ -311,21 +272,23 @@ void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc) int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkZ = a_ChunkDesc.GetChunkZ(); cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes(); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_COAL_ORE, MAX_HEIGHT_COAL, NUM_NESTS_COAL, NEST_SIZE_COAL, BlockTypes, 1); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_IRON_ORE, MAX_HEIGHT_IRON, NUM_NESTS_IRON, NEST_SIZE_IRON, BlockTypes, 2); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_REDSTONE_ORE, MAX_HEIGHT_REDSTONE, NUM_NESTS_REDSTONE, NEST_SIZE_REDSTONE, BlockTypes, 3); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_GOLD_ORE, MAX_HEIGHT_GOLD, NUM_NESTS_GOLD, NEST_SIZE_GOLD, BlockTypes, 4); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_DIAMOND_ORE, MAX_HEIGHT_DIAMOND, NUM_NESTS_DIAMOND, NEST_SIZE_DIAMOND, BlockTypes, 5); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_LAPIS_ORE, MAX_HEIGHT_LAPIS, NUM_NESTS_LAPIS, NEST_SIZE_LAPIS, BlockTypes, 6); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_DIRT, MAX_HEIGHT_DIRT, NUM_NESTS_DIRT, NEST_SIZE_DIRT, BlockTypes, 10); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_GRAVEL, MAX_HEIGHT_GRAVEL, NUM_NESTS_GRAVEL, NEST_SIZE_GRAVEL, BlockTypes, 11); + 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->BlockMeta, itr->MaxHeight, itr->NumNests, itr->NestSize, BlockTypes, BlockMetas, seq); + seq++; + } } -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 @@ -376,9 +339,10 @@ void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_Ore } int Index = cChunkDef::MakeIndexNoCheck(BlockX, BlockY, BlockZ); - if (a_BlockTypes[Index] == E_BLOCK_STONE) + if (a_BlockTypes[Index] == m_ToReplace) { a_BlockTypes[Index] = a_OreType; + a_BlockMetas[Index] = a_BlockMeta; } Num++; } // for z @@ -585,10 +549,10 @@ void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc) // First update the high floor: for (int z = 0; z <= 16 / INTERPOL_Z; z++) for (int x = 0; x <= 16 / INTERPOL_X; x++) { - FloorHi[INTERPOL_X * x + 17 * INTERPOL_Z * z] = + FloorHi[INTERPOL_X * x + 17 * INTERPOL_Z * z] = ( m_Noise1.IntNoise3DInt(BaseX + INTERPOL_X * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) * - m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) / - 256; + m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) / 256 + ); } // for x, z - FloorLo[] LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorHi); diff --git a/src/Generating/StructGen.h b/src/Generating/StructGen.h index 9176bc192..96aa3e437 100644 --- a/src/Generating/StructGen.h +++ b/src/Generating/StructGen.h @@ -76,16 +76,44 @@ class cStructGenOreNests : public cFinishGen { public: - cStructGenOreNests(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {} - + struct OreInfo + { + 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; + + cStructGenOreNests(int a_Seed, OreList a_OreList, BLOCKTYPE a_ToReplace) : + m_Noise(a_Seed), + m_Seed(a_Seed), + m_OreList(a_OreList), + m_ToReplace(a_ToReplace) + {} + protected: - cNoise m_Noise; - int m_Seed; + cNoise m_Noise; + int m_Seed; + + OreList m_OreList; // A list of possible ores. + BLOCKTYPE m_ToReplace; // 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); } ; diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index c40322630..7fd6d6f07 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -181,6 +181,7 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No return; } + case biSwamplandM: case biSwampland: { // Swamp trees: @@ -218,14 +219,11 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No return; } - case biRoofedForest: case biColdTaiga: case biColdTaigaHills: case biMegaTaiga: case biMegaTaigaHills: case biExtremeHillsPlus: - case biSavanna: - case biSavannaPlateau: case biMesa: case biMesaPlateauF: case biMesaPlateau: @@ -234,17 +232,13 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No case biExtremeHillsM: case biFlowerForest: case biTaigaM: - case biSwamplandM: case biIcePlainsSpikes: case biJungleM: case biJungleEdgeM: - case biRoofedForestM: case biColdTaigaM: case biMegaSpruceTaiga: case biMegaSpruceTaigaHills: case biExtremeHillsPlusM: - case biSavannaM: - case biSavannaPlateauM: case biMesaBryce: case biMesaPlateauFM: case biMesaPlateauM: @@ -253,6 +247,22 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); 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: + { + GetDarkoakTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); + return; + } case biDesert: case biDesertHills: @@ -398,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)); } @@ -407,7 +482,60 @@ void GetAcaciaTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noi void GetDarkoakTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) { - // TODO + // Pick a height + int Height = 5 + (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY, a_BlockZ + 32 * a_Seq) / 11) % 4; + + // 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_DARK_OAK_WOOD)); + a_LogBlocks.push_back(sSetBlock(a_BlockX + 1, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ + 1, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + a_LogBlocks.push_back(sSetBlock(a_BlockX + 1, a_BlockY + i, a_BlockZ + 1, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + } + + // Create branches + for (int i = 0; i < 3; i++) + { + int x = (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY * i, a_BlockZ + 32 * a_Seq) % 3) - 1; + int z = (a_Noise.IntNoise3DInt(a_BlockX - 32 * a_Seq, a_BlockY * i, a_BlockZ - 32 * a_Seq) % 3) - 1; + + // The branches would end up in the trunk. + if ((x >= a_BlockX) && (x <= a_BlockX + 1) && (z >= a_BlockZ) && (z <= a_BlockZ + 1)) + { + NOISE_DATATYPE Val1 = a_Noise.IntNoise2D(x, z); + if (Val1 < 0) + { + x = a_BlockX + ((Val1 < -0.5) ? -1 : 3); + } + else + { + z = a_BlockZ + ((Val1 < 0.5) ? -1 : 3); + } + } + + int y = Height - (a_Noise.IntNoise3DInt(a_BlockX + x, a_BlockY * i, a_BlockZ - z) % (Height - (Height / 4))); + + for (int Y = y; Y < Height; Y++) + { + a_LogBlocks.push_back(sSetBlock(a_BlockX + x, a_BlockY + Y, a_BlockZ + z, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + } + } + + int hei = a_BlockY + Height - 2; + + // The lower two leaves layers are BigO4 with log in the middle and possibly corners: + for (int i = 0; i < 2; i++) + { + PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO4, ARRAYCOUNT(BigO4), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 3, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + hei++; + } // for i < 2 + + // The top leaves layer is a BigO3 with leaves in the middle and possibly corners: + PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO3, ARRAYCOUNT(BigO3), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 3, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + a_OtherBlocks.push_back(sSetBlock(a_BlockX, hei, a_BlockZ, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD)); } diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h index 1f6ac4dff..c9eb7de80 100644 --- a/src/Generating/Trees.h +++ b/src/Generating/Trees.h @@ -28,6 +28,7 @@ logs can overwrite others(leaves), but others shouldn't overwrite logs. This is #define CASE_TREE_ALLOWED_BLOCKS \ case E_BLOCK_AIR: \ case E_BLOCK_LEAVES: \ + case E_BLOCK_NEW_LEAVES: \ case E_BLOCK_SNOW: \ case E_BLOCK_TALL_GRASS: \ case E_BLOCK_DEAD_BUSH: \ @@ -40,6 +41,7 @@ logs can overwrite others(leaves), but others shouldn't overwrite logs. This is /* case E_BLOCK_LEAVES: LEAVES are a special case, they can be overwritten only by log. Handled in cChunkMap::ReplaceTreeBlocks(). */ \ case E_BLOCK_SNOW: \ case E_BLOCK_TALL_GRASS: \ + case E_BLOCK_BIG_FLOWER: \ case E_BLOCK_DEAD_BUSH: \ case E_BLOCK_SAPLING: \ case E_BLOCK_VINES diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index cade923c9..a7f66b75e 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -168,7 +168,7 @@ protected: /** The density for this village. Used to refrain from populating all house connectors. Range [0, 100] */ int m_Density; - /** Borders of the vilalge - no item may reach out of this cuboid. */ + /** Borders of the village - no item may reach out of this cuboid. */ cCuboid m_Borders; /** Prefabs to use for buildings */ |