diff options
author | madmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6> | 2013-01-25 11:12:29 +0100 |
---|---|---|
committer | madmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6> | 2013-01-25 11:12:29 +0100 |
commit | 2960f43782f0ec46e5ad494544a0f76c6a6741df (patch) | |
tree | c0cfc25589990f7f85d01002db95dd0093e84d71 /source/Generating | |
parent | AnvilStats: ignoring png files (diff) | |
download | cuberite-2960f43782f0ec46e5ad494544a0f76c6a6741df.tar cuberite-2960f43782f0ec46e5ad494544a0f76c6a6741df.tar.gz cuberite-2960f43782f0ec46e5ad494544a0f76c6a6741df.tar.bz2 cuberite-2960f43782f0ec46e5ad494544a0f76c6a6741df.tar.lz cuberite-2960f43782f0ec46e5ad494544a0f76c6a6741df.tar.xz cuberite-2960f43782f0ec46e5ad494544a0f76c6a6741df.tar.zst cuberite-2960f43782f0ec46e5ad494544a0f76c6a6741df.zip |
Diffstat (limited to 'source/Generating')
-rw-r--r-- | source/Generating/BioGen.h | 2 | ||||
-rw-r--r-- | source/Generating/Caves.h | 2 | ||||
-rw-r--r-- | source/Generating/ChunkDesc.h | 191 | ||||
-rw-r--r-- | source/Generating/ChunkGenerator.cpp | 450 | ||||
-rw-r--r-- | source/Generating/ChunkGenerator.h | 187 | ||||
-rw-r--r-- | source/Generating/CompoGen.h | 2 | ||||
-rw-r--r-- | source/Generating/ComposableGenerator.cpp | 405 | ||||
-rw-r--r-- | source/Generating/ComposableGenerator.h | 178 | ||||
-rw-r--r-- | source/Generating/FinishGen.h | 2 | ||||
-rw-r--r-- | source/Generating/HeiGen.h | 2 | ||||
-rw-r--r-- | source/Generating/Ravines.h | 2 | ||||
-rw-r--r-- | source/Generating/StructGen.h | 2 |
12 files changed, 903 insertions, 522 deletions
diff --git a/source/Generating/BioGen.h b/source/Generating/BioGen.h index 307009a2b..5979ade8b 100644 --- a/source/Generating/BioGen.h +++ b/source/Generating/BioGen.h @@ -14,7 +14,7 @@ Interfaces to the various biome generators: #pragma once -#include "ChunkGenerator.h" +#include "ComposableGenerator.h" #include "../Noise.h" diff --git a/source/Generating/Caves.h b/source/Generating/Caves.h index 2e66c909c..58213abe2 100644 --- a/source/Generating/Caves.h +++ b/source/Generating/Caves.h @@ -12,7 +12,7 @@ #pragma once
-#include "ChunkGenerator.h"
+#include "ComposableGenerator.h"
#include "../Noise.h"
diff --git a/source/Generating/ChunkDesc.h b/source/Generating/ChunkDesc.h new file mode 100644 index 000000000..02b67998a --- /dev/null +++ b/source/Generating/ChunkDesc.h @@ -0,0 +1,191 @@ + +// ChunkDesc.h + +// Declares the cChunkDesc class representing the chunk description used while generating a chunk. This class is also exported to Lua for HOOK_CHUNK_GENERATING. + + + + + +#pragma once + +#include "../ChunkDef.h" + + + + + +class cChunkDesc // tolua_export +{ // tolua_export +public: + cChunkDesc( + cChunkDef::BlockTypes & a_BlockTypes, + cChunkDef::BlockNibbles & a_BlockNibbles , + cChunkDef::HeightMap & a_HeightMap, + cChunkDef::BiomeMap & a_BiomeMap + ) + : m_BiomeMap(a_BiomeMap) + , m_BlockTypes(a_BlockTypes) + , m_BlockMeta(a_BlockNibbles) + , m_HeightMap(a_HeightMap) + , m_bUseDefaultBiomes(true) + , m_bUseDefaultHeight(true) + , m_bUseDefaultComposition(true) + , m_bUseDefaultStructures(true) + , m_bUseDefaultFinish(true) + { + memset(m_BlockTypes, 0, sizeof(cChunkDef::BlockTypes)); + memset(m_BlockMeta, 0, sizeof(cChunkDef::BlockNibbles)); + memset(m_BiomeMap, 0, sizeof(cChunkDef::BiomeMap)); + memset(m_HeightMap, 0, sizeof(cChunkDef::HeightMap)); + } + + ~cChunkDesc() + {} + + // tolua_begin + + + + // Block functions: + void FillBlocks(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) + { + const NIBBLETYPE CompressedMeta = a_BlockMeta | a_BlockMeta << 4; + memset(m_BlockTypes, a_BlockType, sizeof(cChunkDef::BlockTypes)); + memset(m_BlockMeta, CompressedMeta, sizeof(cChunkDef::BlockNibbles)); + } + + + void SetBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) + { + cChunkDef::SetBlock( m_BlockTypes, a_X, a_Y, a_Z, a_BlockType ); + cChunkDef::SetNibble( m_BlockMeta, a_X, a_Y, a_Z, a_BlockMeta ); + } + + + BLOCKTYPE GetBlock( int a_X, int a_Y, int a_Z ) + { + return cChunkDef::GetBlock( m_BlockTypes, a_X, a_Y, a_Z ); + } + + + NIBBLETYPE GetBlockMeta( int a_X, int a_Y, int a_Z ) + { + return cChunkDef::GetNibble( m_BlockMeta, a_X, a_Y, a_Z ); + } + + + + // Biome functinos + void SetBiome( int a_X, int a_Z, int a_BiomeID ) + { + cChunkDef::SetBiome( m_BiomeMap, a_X, a_Z, (EMCSBiome)a_BiomeID ); + } + + + int GetBiome( int a_X, int a_Z ) + { + return cChunkDef::GetBiome( m_BiomeMap, a_X, a_Z ); + } + + + + // Height functions + void SetHeight( int a_X, int a_Z, int a_Height ) + { + cChunkDef::SetHeight( m_HeightMap, a_X, a_Z, a_Height ); + } + + + int GetHeight( int a_X, int a_Z ) + { + return cChunkDef::GetHeight( m_HeightMap, a_X, a_Z ); + } + + + + // Functions to explicitly tell the server to use default behavior for certain parts of generating terrain + void SetUseDefaultBiomes(bool a_bUseDefaultBiomes) + { + m_bUseDefaultBiomes = a_bUseDefaultBiomes; + } + + + bool IsUsingDefaultBiomes(void) const + { + return m_bUseDefaultBiomes; + } + + + void SetUseDefaultHeight(bool a_bUseDefaultHeight) + { + m_bUseDefaultHeight = a_bUseDefaultHeight; + } + + + bool IsUsingDefaultHeight(void) const + { + return m_bUseDefaultHeight; + } + + + void SetUseDefaultComposition(bool a_bUseDefaultComposition) + { + m_bUseDefaultComposition = a_bUseDefaultComposition; + } + + + bool IsUsingDefaultComposition(void) const + { + return m_bUseDefaultComposition; + } + + + void SetUseDefaultStructures(bool a_bUseDefaultStructures) + { + m_bUseDefaultStructures = a_bUseDefaultStructures; + } + + + bool IsUsingDefaultStructures(void) const + { + return m_bUseDefaultStructures; + } + + + void SetUseDefaultFinish(bool a_bUseDefaultFinish) + { + m_bUseDefaultFinish = a_bUseDefaultFinish; + } + + + bool IsUsingDefaultFinish(void) const + { + return m_bUseDefaultFinish; + } + + // tolua_end + + + // Accessors used by cChunkGenerator::Generator descendants: + cChunkDef::BiomeMap & GetBiomeMap (void) { return m_BiomeMap; } + cChunkDef::BlockTypes & GetBlockTypes(void) { return m_BlockTypes; } + cChunkDef::BlockNibbles & GetBlockMetas(void) { return m_BlockMeta; } + cChunkDef::HeightMap & GetHeightMap (void) { return m_HeightMap; } + +private: + bool m_bUseDefaultBiomes; + bool m_bUseDefaultHeight; + bool m_bUseDefaultComposition; + bool m_bUseDefaultStructures; + bool m_bUseDefaultFinish; + + cChunkDef::BiomeMap & m_BiomeMap; + cChunkDef::BlockTypes & m_BlockTypes; + cChunkDef::BlockNibbles & m_BlockMeta; + cChunkDef::HeightMap & m_HeightMap; +} ; // tolua_export + + + + diff --git a/source/Generating/ChunkGenerator.cpp b/source/Generating/ChunkGenerator.cpp index 8af4f7be7..b4781fbda 100644 --- a/source/Generating/ChunkGenerator.cpp +++ b/source/Generating/ChunkGenerator.cpp @@ -4,16 +4,10 @@ #include "ChunkGenerator.h" #include "../World.h" #include "../../iniFile/iniFile.h" -#include "BioGen.h" -#include "HeiGen.h" -#include "CompoGen.h" -#include "StructGen.h" -#include "FinishGen.h" #include "../Root.h" #include "../PluginManager.h" -#include "../LuaChunk.h" -#include "Ravines.h" -#include "Caves.h" +#include "ChunkDesc.h" +#include "ComposableGenerator.h" @@ -29,31 +23,13 @@ const int QUEUE_SKIP_LIMIT = 500; -static BLOCKTYPE GetIniBlock(cIniFile & a_IniFile, const AString & a_SectionName, const AString & a_ValueName, const AString & a_Default) -{ - AString BlockType = a_IniFile.GetValueSet(a_SectionName, a_ValueName, a_Default); - BLOCKTYPE Block = BlockStringToType(BlockType); - if (Block < 0) - { - LOGWARN("[&s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str()); - return BlockStringToType(a_Default); - } - return Block; -} - - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cChunkGenerator: -cChunkGenerator::cChunkGenerator(void) - : super("cChunkGenerator") - , m_World(NULL) - , m_BiomeGen(NULL) - , m_HeightGen(NULL) - , m_CompositionGen(NULL) +cChunkGenerator::cChunkGenerator(void) : + super("cChunkGenerator"), + m_World(NULL), + m_Generator(NULL) { } @@ -75,312 +51,47 @@ bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) MTRand rnd; m_World = a_World; m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", rnd.randInt()); - - InitBiomeGen(a_IniFile); - InitHeightGen(a_IniFile); - InitCompositionGen(a_IniFile); - InitStructureGens(a_IniFile); - InitFinishGens(a_IniFile); - - a_IniFile.WriteFile(); + AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable"); - return super::Start(); -} - - - - - -void cChunkGenerator::Stop(void) -{ - m_ShouldTerminate = true; - m_Event.Set(); - m_evtRemoved.Set(); // Wake up anybody waiting for empty queue - Wait(); - - // Delete the generating composition: - for (cFinishGenList::const_iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr) - { - delete *itr; - } - m_FinishGens.clear(); - for (cStructureGenList::const_iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr) - { - delete *itr; - } - m_StructureGens.clear(); - delete m_CompositionGen; - m_CompositionGen = NULL; - delete m_HeightGen; - m_HeightGen = NULL; - delete m_BiomeGen; - m_BiomeGen = NULL; -} - - - - - -void cChunkGenerator::InitBiomeGen(cIniFile & a_IniFile) -{ - AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", ""); - if (BiomeGenName.empty()) - { - LOGWARN("[Generator]::BiomeGen value not found in world.ini, using \"DistortedVoronoi\"."); - BiomeGenName = "DistortedVoronoi"; - } - - bool CacheOffByDefault = false; - if (NoCaseCompare(BiomeGenName, "constant") == 0) - { - AString Biome = a_IniFile.GetValueSet("Generator", "ConstantBiome", "Plains"); - EMCSBiome b = StringToBiome(Biome); - if (b == -1) - { - LOGWARN("[Generator]::ConstantBiome value \"%s\" not recognized, using \"Plains\".", Biome.c_str()); - b = biPlains; - } - m_BiomeGen = new cBioGenConstant(b); - CacheOffByDefault = true; // we're generating faster than a cache would retrieve data :) - } - else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0) - { - int BiomeSize = a_IniFile.GetValueSetI("Generator", "CheckerboardBiomeSize", 64); - AString Biomes = a_IniFile.GetValueSet ("Generator", "CheckerBoardBiomes", ""); - m_BiomeGen = new cBioGenCheckerboard(BiomeSize, Biomes); - CacheOffByDefault = true; // we're (probably) generating faster than a cache would retrieve data - } - else if (NoCaseCompare(BiomeGenName, "voronoi") == 0) - { - int CellSize = a_IniFile.GetValueSetI("Generator", "VoronoiCellSize", 64); - AString Biomes = a_IniFile.GetValueSet ("Generator", "VoronoiBiomes", ""); - m_BiomeGen = new cBioGenVoronoi(m_Seed, CellSize, Biomes); - } - else if (NoCaseCompare(BiomeGenName, "multistepmap") == 0) + if (NoCaseCompare(GeneratorName, "RoughHills") == 0) { - m_BiomeGen = new cBioGenMultiStepMap(m_Seed); - ((cBioGenMultiStepMap *)m_BiomeGen)->Init(a_IniFile); + // TODO } else { - if (NoCaseCompare(BiomeGenName, "distortedvoronoi") != 0) + if (NoCaseCompare(GeneratorName, "composable") != 0) { - LOGWARNING("Unknown BiomeGen \"%s\", using \"DistortedVoronoi\" instead.", BiomeGenName.c_str()); - } - int CellSize = a_IniFile.GetValueSetI("Generator", "DistortedVoronoiCellSize", 96); - AString Biomes = a_IniFile.GetValueSet ("Generator", "DistortedVoronoiBiomes", ""); - m_BiomeGen = new cBioGenDistortedVoronoi(m_Seed, CellSize, Biomes); - } - - // Add a cache, if requested: - int CacheSize = a_IniFile.GetValueSetI("Generator", "BiomeGenCacheSize", CacheOffByDefault ? 0 : 64); - if (CacheSize > 0) - { - 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; + LOGWARN("[Generator]::Generator value \"%s\" not recognized, using \"Composable\".", GeneratorName.c_str()); } - LOGINFO("Using a cache for biomegen of size %d.", CacheSize); - m_BiomeGen = new cBioGenCache(m_BiomeGen, CacheSize); + m_Generator = new cComposableGenerator(*this); } -} - - - - -void cChunkGenerator::InitHeightGen(cIniFile & a_IniFile) -{ - AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", ""); - if (HeightGenName.empty()) + if (m_Generator == NULL) { - LOGWARN("[Generator]::HeightGen value not found in world.ini, using \"Biomal\"."); - HeightGenName = "Biomal"; + LOGERROR("Generator could not start, aborting the server"); + return false; } - bool CacheOffByDefault = false; - if (NoCaseCompare(HeightGenName, "flat") == 0) - { - int Height = a_IniFile.GetValueSetI("Generator", "FlatHeight", 5); - m_HeightGen = new cHeiGenFlat(Height); - CacheOffByDefault = true; // We're generating faster than a cache would retrieve data - } - else if (NoCaseCompare(HeightGenName, "classic") == 0) - { - // These used to be in terrain.ini, but now they are in world.ini (so that multiple worlds can have different values): - float HeightFreq1 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightFreq1", 0.1); - float HeightFreq2 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightFreq2", 1.0); - float HeightFreq3 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightFreq3", 2.0); - float HeightAmp1 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightAmp1", 1.0); - float HeightAmp2 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightAmp2", 0.5); - float HeightAmp3 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightAmp3", 0.5); - m_HeightGen = new cHeiGenClassic(m_Seed, HeightFreq1, HeightAmp1, HeightFreq2, HeightAmp2, HeightFreq3, HeightAmp3); - } - else // "biomal" or <not found> - { - if (NoCaseCompare(HeightGenName, "biomal") != 0) - { - LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str()); - } - m_HeightGen = new cHeiGenBiomal(m_Seed, *m_BiomeGen); - } + m_Generator->Initialize(a_World, a_IniFile); - // Add a cache, if requested: - int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64); - if (CacheSize > 0) - { - if (CacheSize < 4) - { - LOGWARNING("Heightgen cache size set too low, would hurt performance instead of helping. Increasing from %d to %d", - CacheSize, 4 - ); - CacheSize = 4; - } - LOGINFO("Using a cache for Heightgen of size %d.", CacheSize); - m_HeightGen = new cHeiGenCache(m_HeightGen, CacheSize); - } -} - - - - - -void cChunkGenerator::InitCompositionGen(cIniFile & a_IniFile) -{ - AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", ""); - if (CompoGenName.empty()) - { - LOGWARN("[Generator]::CompositionGen value not found in world.ini, using \"Biomal\"."); - CompoGenName = "Biomal"; - } - if (NoCaseCompare(CompoGenName, "sameblock") == 0) - { - int Block = GetIniBlock(a_IniFile, "Generator", "SameBlockType", "stone"); - bool Bedrocked = (a_IniFile.GetValueSetI("Generator", "SameBlockBedrocked", 1) != 0); - m_CompositionGen = new cCompoGenSameBlock((BLOCKTYPE)Block, Bedrocked); - } - else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0) - { - m_CompositionGen = new cCompoGenDebugBiomes; - } - else if (NoCaseCompare(CompoGenName, "classic") == 0) - { - int SeaLevel = a_IniFile.GetValueSetI("Generator", "ClassicSeaLevel", 60); - int BeachHeight = a_IniFile.GetValueSetI("Generator", "ClassicBeachHeight", 2); - int BeachDepth = a_IniFile.GetValueSetI("Generator", "ClassicBeachDepth", 4); - BLOCKTYPE BlockTop = GetIniBlock(a_IniFile, "Generator", "ClassicBlockTop", "grass"); - BLOCKTYPE BlockMiddle = GetIniBlock(a_IniFile, "Generator", "ClassicBlockMiddle", "dirt"); - BLOCKTYPE BlockBottom = GetIniBlock(a_IniFile, "Generator", "ClassicBlockBottom", "stone"); - BLOCKTYPE BlockBeach = GetIniBlock(a_IniFile, "Generator", "ClassicBlockBeach", "sand"); - BLOCKTYPE BlockBeachBottom = GetIniBlock(a_IniFile, "Generator", "ClassicBlockBeachBottom", "sandstone"); - BLOCKTYPE BlockSea = GetIniBlock(a_IniFile, "Generator", "ClassicBlockSea", "stationarywater"); - m_CompositionGen = new cCompoGenClassic( - SeaLevel, BeachHeight, BeachDepth, BlockTop, BlockMiddle, BlockBottom, BlockBeach, - BlockBeachBottom, BlockSea - ); - } - else - { - if (NoCaseCompare(CompoGenName, "biomal") != 0) - { - LOGWARN("Unknown CompositionGen \"%s\", using \"biomal\" instead.", CompoGenName.c_str()); - } - int SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalSeaLevel", 62); - m_CompositionGen = new cCompoGenBiomal(m_Seed, SeaLevel); - } -} - - - - - -void cChunkGenerator::InitStructureGens(cIniFile & a_IniFile) -{ - AString Structures = a_IniFile.GetValueSet("Generator", "Structures", "Ravines,WormNestCaves,OreNests,Trees"); - - AStringVector Str = StringSplit(Structures, ","); - for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr) - { - if (NoCaseCompare(*itr, "trees") == 0) - { - m_StructureGens.push_back(new cStructGenTrees(m_Seed, m_BiomeGen, m_HeightGen, m_CompositionGen)); - } - else if (NoCaseCompare(*itr, "marblecaves") == 0) - { - m_StructureGens.push_back(new cStructGenMarbleCaves(m_Seed)); - } - else if (NoCaseCompare(*itr, "dualridgecaves") == 0) - { - float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3); - m_StructureGens.push_back(new cStructGenDualRidgeCaves(m_Seed, Threshold)); - } - else if (NoCaseCompare(*itr, "orenests") == 0) - { - m_StructureGens.push_back(new cStructGenOreNests(m_Seed)); - } - else if (NoCaseCompare(*itr, "ravines") == 0) - { - m_StructureGens.push_back(new cStructGenRavines(m_Seed, 128)); - } - //* - // TODO: Not implemented yet; need a name - else if (NoCaseCompare(*itr, "wormnestcaves") == 0) - { - m_StructureGens.push_back(new cStructGenWormNestCaves(m_Seed)); - } - //*/ - else - { - LOGWARNING("Unknown structure generator: \"%s\". Ignoring.", itr->c_str()); - } - } // for itr - Str[] + a_IniFile.WriteFile(); + + return super::Start(); } -void cChunkGenerator::InitFinishGens(cIniFile & a_IniFile) +void cChunkGenerator::Stop(void) { - AString Structures = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator"); + m_ShouldTerminate = true; + m_Event.Set(); + m_evtRemoved.Set(); // Wake up anybody waiting for empty queue + Wait(); - AStringVector Str = StringSplit(Structures, ","); - for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr) - { - // Finishers, alpha-sorted: - if (NoCaseCompare(*itr, "BottomLava") == 0) - { - int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", 10); - m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel)); - } - else if (NoCaseCompare(*itr, "DeadBushes") == 0) - { - m_FinishGens.push_back(new cFinishGenDeadBushes(m_Seed)); - } - else if (NoCaseCompare(*itr, "Ice") == 0) - { - m_FinishGens.push_back(new cFinishGenIce); - } - else if (NoCaseCompare(*itr, "Lilypads") == 0) - { - m_FinishGens.push_back(new cFinishGenLilypads(m_Seed)); - } - else if (NoCaseCompare(*itr, "PreSimulator") == 0) - { - m_FinishGens.push_back(new cFinishGenPreSimulator); - } - else if (NoCaseCompare(*itr, "Snow") == 0) - { - m_FinishGens.push_back(new cFinishGenSnow); - } - else if (NoCaseCompare(*itr, "SprinkleFoliage") == 0) - { - m_FinishGens.push_back(new cFinishGenSprinkleFoliage(m_Seed)); - } - } // for itr - Str[] + delete m_Generator; + m_Generator = NULL; } @@ -419,9 +130,9 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk void cChunkGenerator::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_Generator != NULL) { - m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap); + m_Generator->GenerateBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap); } } @@ -455,12 +166,24 @@ int cChunkGenerator::GetQueueLength(void) EMCSBiome cChunkGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ) { - cChunkDef::BiomeMap Biomes; - int Y = 0; - int ChunkX, ChunkZ; - cWorld::AbsoluteToRelative(a_BlockX, Y, a_BlockZ, ChunkX, Y, ChunkZ); - m_BiomeGen->GenBiomes(ChunkX, ChunkZ, Biomes); - return cChunkDef::GetBiome(Biomes, a_BlockX, a_BlockZ); + ASSERT(m_Generator != NULL); + return m_Generator->GetBiomeAt(a_BlockX, a_BlockZ); +} + + + + + +BLOCKTYPE cChunkGenerator::GetIniBlock(cIniFile & a_IniFile, const AString & a_SectionName, const AString & a_ValueName, const AString & a_Default) +{ + AString BlockType = a_IniFile.GetValueSet(a_SectionName, a_ValueName, a_Default); + BLOCKTYPE Block = BlockStringToType(BlockType); + if (Block < 0) + { + LOGWARN("[&s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str()); + return BlockStringToType(a_Default); + } + return Block; } @@ -550,48 +273,9 @@ void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) cEntityList Entities; cBlockEntityList BlockEntities; - cLuaChunk LuaChunk( BlockTypes, BlockMeta, HeightMap, BiomeMap ); - if( cRoot::Get()->GetPluginManager()->CallHookChunkGenerating(m_World, a_ChunkX, a_ChunkZ, &LuaChunk ) ) - { - // A plugin interrupted generation, handle something plugin specific - if( LuaChunk.IsUsingDefaultBiomes() ) - { - m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, BiomeMap); - } - if( LuaChunk.IsUsingDefaultComposition() ) - { - m_CompositionGen->ComposeTerrain(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, BiomeMap, Entities, BlockEntities); - } - if( LuaChunk.IsUsingDefaultStructures() ) - { - for (cStructureGenList::iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr) - { - (*itr)->GenStructures(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, Entities, BlockEntities); - } // for itr - m_StructureGens[] - } - if( LuaChunk.IsUsingDefaultFinish() ) - { - for (cFinishGenList::iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr) - { - (*itr)->GenFinish(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, BiomeMap, Entities, BlockEntities); - } // for itr - m_FinishGens[] - } - } - else - { - // Use the composed generator: - m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, BiomeMap); - m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap); - m_CompositionGen->ComposeTerrain(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, BiomeMap, Entities, BlockEntities); - for (cStructureGenList::iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr) - { - (*itr)->GenStructures(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, Entities, BlockEntities); - } // for itr - m_StructureGens[] - for (cFinishGenList::iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr) - { - (*itr)->GenFinish(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, BiomeMap, Entities, BlockEntities); - } // for itr - m_FinishGens[] - } + cChunkDesc LuaChunk(BlockTypes, BlockMeta, HeightMap, BiomeMap); + cRoot::Get()->GetPluginManager()->CallHookChunkGenerating(m_World, a_ChunkX, a_ChunkZ, &LuaChunk); + m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, LuaChunk, Entities, BlockEntities); m_World->SetChunkData( a_ChunkX, a_ChunkY, a_ChunkZ, @@ -608,3 +292,39 @@ void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cChunkGenerator::cGenerator: + +cChunkGenerator::cGenerator::cGenerator(cChunkGenerator & a_ChunkGenerator) : + m_ChunkGenerator(a_ChunkGenerator) +{ +} + + + + + +void cChunkGenerator::cGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) +{ + m_World = a_World; + UNUSED(a_IniFile); +} + + + + + +EMCSBiome cChunkGenerator::cGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ) +{ + cChunkDef::BiomeMap Biomes; + int Y = 0; + int ChunkX, ChunkZ; + cWorld::AbsoluteToRelative(a_BlockX, Y, a_BlockZ, ChunkX, Y, ChunkZ); + GenerateBiomes(ChunkX, ChunkZ, Biomes); + return cChunkDef::GetBiome(Biomes, a_BlockX, a_BlockZ); +} + + + + diff --git a/source/Generating/ChunkGenerator.h b/source/Generating/ChunkGenerator.h index 287ce1108..e89e9def8 100644 --- a/source/Generating/ChunkGenerator.h +++ b/source/Generating/ChunkGenerator.h @@ -1,5 +1,5 @@ -// cChunkGenerator.h +// ChunkGenerator.h // Interfaces to the cChunkGenerator class representing the thread that generates chunks @@ -10,12 +10,6 @@ Before generating, the thread checks if the chunk hasn't been already generated. It is theoretically possible to have multiple generator threads by having multiple instances of this object, but then it MAY happen that the chunk is generated twice. If the generator queue is overloaded, the generator skips chunks with no clients in them - -Generating works by composing several algorithms: -Biome, TerrainHeight, TerrainComposition, Ores, Structures and SmallFoliage -Each algorithm may be chosen from a pool of available algorithms in the same class and combined with others, -based on user's preferences in the world.ini. -See http://forum.mc-server.org/showthread.php?tid=409 for details. */ @@ -34,134 +28,42 @@ See http://forum.mc-server.org/showthread.php?tid=409 for details. // fwd: class cWorld; class cIniFile; - -// TODO: remove this: -class cWorldGenerator; - - - - - -/** The interface that a biome generator must implement -A biome generator takes chunk coords on input and outputs an array of biome indices for that chunk on output. -The output array is sequenced in the same way as the MapChunk packet's biome data. -*/ -class cBiomeGen -{ -public: - virtual ~cBiomeGen() {} // Force a virtual destructor in descendants - - /// Generates biomes for the given chunk - virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0; -} ; - - - - - -/** The interface that a terrain height generator must implement -A terrain height generator takes chunk coords on input and outputs an array of terrain heights for that chunk. -The output array is sequenced in the same way as the BiomeGen's biome data. -The generator may request biome information from the underlying BiomeGen, it may even request information for -other chunks than the one it's currently generating (possibly neighbors - for averaging) -*/ -class cTerrainHeightGen -{ -public: - virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants - - /// Generates heightmap for the given chunk - virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0; -} ; - - - - - -/** The interface that a terrain composition generator must implement -Terrain composition takes chunk coords on input and outputs the blockdata for that entire chunk, along with -the list of entities. It is supposed to make use of the underlying TerrainHeightGen and BiomeGen for that purpose, -but it may request information for other chunks than the one it's currently generating from them. -*/ -class cTerrainCompositionGen -{ -public: - virtual ~cTerrainCompositionGen() {} // Force a virtual destructor in descendants - - virtual void ComposeTerrain( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated (the whole array gets initialized, even air) - cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated (the whole array gets initialized) - const cChunkDef::HeightMap & a_HeightMap, // The height map to fit - const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to - cEntityList & a_Entities, // Entitites may be generated along with the terrain - cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...) - ) = 0; -} ; +class cChunkDesc; -/** The interface that a structure generator must implement -Structures are generated after the terrain composition took place. It should modify the blocktype data to account -for whatever structures the generator is generating. -Note that ores are considered structures too, at least from the interface point of view. -Also note that a worldgenerator may contain multiple structure generators, one for each type of structure -*/ -class cStructureGen -{ -public: - virtual ~cStructureGen() {} // Force a virtual destructor in descendants - - virtual void GenStructures( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change - cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change - cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data - cEntityList & a_Entities, // Entities may be added or deleted - cBlockEntityList & a_BlockEntities // Block entities may be added or deleted - ) = 0; -} ; - -typedef std::list<cStructureGen *> cStructureGenList; - - - - - -/** The interface that a finisher must implement -Finisher implements small additions after all structures have been generated. -*/ -class cFinishGen -{ -public: - virtual ~cFinishGen() {} // Force a virtual destructor in descendants - - virtual void GenFinish( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change - cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change - cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data - const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to - cEntityList & a_Entities, // Entities may be added or deleted - cBlockEntityList & a_BlockEntities // Block entities may be added or deleted - ) = 0; -} ; - -typedef std::list<cFinishGen *> cFinishGenList; - - - - - -/// The chunk generator itself class cChunkGenerator : cIsThread { typedef cIsThread super; public: + /// The interface that a class has to implement to become a generator + class cGenerator + { + public: + cGenerator(cChunkGenerator & a_ChunkGenerator); + virtual ~cGenerator() {} ; // Force a virtual destructor + + /// Called to initialize the generator on server startup. + virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile); + + /// Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading. + virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0; + + /// Returns the biome at the specified coords. Used by ChunkMap if an invalid chunk is queried for biome. Default implementation uses GenerateBiomes(). + virtual EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ); + + /// Called in a separate thread to do the actual chunk generation. Generator should generate into a_ChunkDesc, a_Entities and a_BlockEntities. + virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) = 0; + + protected: + cChunkGenerator & m_ChunkGenerator; + cWorld * m_World; + } ; + cChunkGenerator (void); ~cChunkGenerator(); @@ -169,9 +71,10 @@ public: bool Start(cWorld * a_World, cIniFile & a_IniFile); void Stop(void); - void QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Queues the chunk for generation; removes duplicate requests + /// Queues the chunk for generation; removes duplicate requests + void QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - /// Generates the biomes for the specified chunk (directly, not in a separate thread) + /// 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); void WaitForQueueEmpty(void); @@ -180,41 +83,25 @@ public: int GetSeed(void) const { return m_Seed; } + /// Returns the biome at the specified coords. Used by ChunkMap if an invalid chunk is queried for biome EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ); + /// Reads a block type from the ini file; returns the blocktype on success, emits a warning and returns a_Default's representation on failure. + static BLOCKTYPE GetIniBlock(cIniFile & a_IniFile, const AString & a_SectionName, const AString & a_ValueName, const AString & a_Default); + private: cWorld * m_World; - // The generation composition: - cBiomeGen * m_BiomeGen; - cTerrainHeightGen * m_HeightGen; - cTerrainCompositionGen * m_CompositionGen; - cStructureGenList m_StructureGens; - cFinishGenList m_FinishGens; - 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 - - /// Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly - void InitBiomeGen(cIniFile & a_IniFile); - - /// Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly - void InitHeightGen(cIniFile & a_IniFile); - - /// Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly - void InitCompositionGen(cIniFile & a_IniFile); - - /// Reads the structures to generate from the ini and initializes m_StructureGens accordingly - void InitStructureGens(cIniFile & a_IniFile); - - /// Reads the finishers from the ini and initializes m_FinishGens accordingly - void InitFinishGens(cIniFile & a_IniFile); + 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 + // cIsThread override: virtual void Execute(void) override; diff --git a/source/Generating/CompoGen.h b/source/Generating/CompoGen.h index f6dfa6131..39f57735f 100644 --- a/source/Generating/CompoGen.h +++ b/source/Generating/CompoGen.h @@ -14,7 +14,7 @@ #pragma once -#include "ChunkGenerator.h" +#include "ComposableGenerator.h" #include "../Noise.h" diff --git a/source/Generating/ComposableGenerator.cpp b/source/Generating/ComposableGenerator.cpp new file mode 100644 index 000000000..680c2e204 --- /dev/null +++ b/source/Generating/ComposableGenerator.cpp @@ -0,0 +1,405 @@ +
+// ComposableGenerator.cpp
+
+// Implements the cComposableGenerator class representing the chunk generator that takes the composition approach to generating chunks
+
+#include "Globals.h"
+
+#include "ComposableGenerator.h"
+#include "../World.h"
+#include "../../iniFile/iniFile.h"
+#include "../Root.h"
+#include "ChunkDesc.h"
+
+// Individual composed algorithms:
+#include "BioGen.h"
+#include "HeiGen.h"
+#include "CompoGen.h"
+#include "StructGen.h"
+#include "FinishGen.h"
+#include "Ravines.h"
+#include "Caves.h"
+
+
+
+
+
+cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
+ super(a_ChunkGenerator),
+ m_BiomeGen(NULL),
+ m_HeightGen(NULL),
+ m_CompositionGen(NULL)
+{
+}
+
+
+
+
+
+cComposableGenerator::~cComposableGenerator()
+{
+ // Delete the generating composition:
+ for (cFinishGenList::const_iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr)
+ {
+ delete *itr;
+ }
+ m_FinishGens.clear();
+ for (cStructureGenList::const_iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
+ {
+ delete *itr;
+ }
+ m_StructureGens.clear();
+ delete m_CompositionGen;
+ m_CompositionGen = NULL;
+ delete m_HeightGen;
+ m_HeightGen = NULL;
+ delete m_BiomeGen;
+ m_BiomeGen = NULL;
+}
+
+
+
+
+
+void cComposableGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile)
+{
+ super::Initialize(a_World, a_IniFile);
+
+ InitBiomeGen(a_IniFile);
+ InitHeightGen(a_IniFile);
+ InitCompositionGen(a_IniFile);
+ InitStructureGens(a_IniFile);
+ InitFinishGens(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
+ {
+ m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap);
+ }
+}
+
+
+
+
+
+void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
+{
+ cChunkDef::BiomeMap & BiomeMap = a_ChunkDesc.GetBiomeMap();
+ cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes();
+ cChunkDef::BlockNibbles & BlockMeta = a_ChunkDesc.GetBlockMetas();
+ cChunkDef::HeightMap & HeightMap = a_ChunkDesc.GetHeightMap();
+ cEntityList & Entities = a_Entities;
+ cBlockEntityList & BlockEntities = a_BlockEntities;
+
+ if (a_ChunkDesc.IsUsingDefaultBiomes())
+ {
+ m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, BiomeMap);
+ }
+
+ if (a_ChunkDesc.IsUsingDefaultHeight())
+ {
+ m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap);
+ }
+
+ if (a_ChunkDesc.IsUsingDefaultComposition())
+ {
+ m_CompositionGen->ComposeTerrain(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, BiomeMap, a_Entities, a_BlockEntities);
+ }
+
+ if (a_ChunkDesc.IsUsingDefaultStructures())
+ {
+ for (cStructureGenList::iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
+ {
+ (*itr)->GenStructures(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, Entities, BlockEntities);
+ } // for itr - m_StructureGens[]
+ }
+
+ if (a_ChunkDesc.IsUsingDefaultFinish())
+ {
+ for (cFinishGenList::iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr)
+ {
+ (*itr)->GenFinish(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, BiomeMap, Entities, BlockEntities);
+ } // for itr - m_FinishGens[]
+ }
+}
+
+
+
+
+
+void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
+{
+ AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", "");
+ if (BiomeGenName.empty())
+ {
+ LOGWARN("[Generator]::BiomeGen value not found in world.ini, using \"DistortedVoronoi\".");
+ BiomeGenName = "DistortedVoronoi";
+ }
+
+ int Seed = m_ChunkGenerator.GetSeed();
+ bool CacheOffByDefault = false;
+ if (NoCaseCompare(BiomeGenName, "constant") == 0)
+ {
+ AString Biome = a_IniFile.GetValueSet("Generator", "ConstantBiome", "Plains");
+ EMCSBiome b = StringToBiome(Biome);
+ if (b == -1)
+ {
+ LOGWARN("[Generator]::ConstantBiome value \"%s\" not recognized, using \"Plains\".", Biome.c_str());
+ b = biPlains;
+ }
+ m_BiomeGen = new cBioGenConstant(b);
+ CacheOffByDefault = true; // we're generating faster than a cache would retrieve data :)
+ }
+ else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0)
+ {
+ int BiomeSize = a_IniFile.GetValueSetI("Generator", "CheckerboardBiomeSize", 64);
+ AString Biomes = a_IniFile.GetValueSet ("Generator", "CheckerBoardBiomes", "");
+ m_BiomeGen = new cBioGenCheckerboard(BiomeSize, Biomes);
+ CacheOffByDefault = true; // we're (probably) generating faster than a cache would retrieve data
+ }
+ else if (NoCaseCompare(BiomeGenName, "voronoi") == 0)
+ {
+ int CellSize = a_IniFile.GetValueSetI("Generator", "VoronoiCellSize", 64);
+ AString Biomes = a_IniFile.GetValueSet ("Generator", "VoronoiBiomes", "");
+ m_BiomeGen = new cBioGenVoronoi(Seed, CellSize, Biomes);
+ }
+ else if (NoCaseCompare(BiomeGenName, "multistepmap") == 0)
+ {
+ m_BiomeGen = new cBioGenMultiStepMap(Seed);
+ ((cBioGenMultiStepMap *)m_BiomeGen)->Init(a_IniFile);
+ }
+ else
+ {
+ if (NoCaseCompare(BiomeGenName, "distortedvoronoi") != 0)
+ {
+ LOGWARNING("Unknown BiomeGen \"%s\", using \"DistortedVoronoi\" instead.", BiomeGenName.c_str());
+ }
+ int CellSize = a_IniFile.GetValueSetI("Generator", "DistortedVoronoiCellSize", 96);
+ AString Biomes = a_IniFile.GetValueSet ("Generator", "DistortedVoronoiBiomes", "");
+ m_BiomeGen = new cBioGenDistortedVoronoi(Seed, CellSize, Biomes);
+ }
+
+ // Add a cache, if requested:
+ int CacheSize = a_IniFile.GetValueSetI("Generator", "BiomeGenCacheSize", CacheOffByDefault ? 0 : 64);
+ if (CacheSize > 0)
+ {
+ 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;
+ }
+ LOGINFO("Using a cache for biomegen of size %d.", CacheSize);
+ m_BiomeGen = new cBioGenCache(m_BiomeGen, CacheSize);
+ }
+}
+
+
+
+
+
+void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
+{
+ AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", "");
+ if (HeightGenName.empty())
+ {
+ LOGWARN("[Generator]::HeightGen value not found in world.ini, using \"Biomal\".");
+ HeightGenName = "Biomal";
+ }
+
+ int Seed = m_ChunkGenerator.GetSeed();
+ bool CacheOffByDefault = false;
+ if (NoCaseCompare(HeightGenName, "flat") == 0)
+ {
+ int Height = a_IniFile.GetValueSetI("Generator", "FlatHeight", 5);
+ m_HeightGen = new cHeiGenFlat(Height);
+ CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
+ }
+ else if (NoCaseCompare(HeightGenName, "classic") == 0)
+ {
+ // These used to be in terrain.ini, but now they are in world.ini (so that multiple worlds can have different values):
+ float HeightFreq1 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightFreq1", 0.1);
+ float HeightFreq2 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightFreq2", 1.0);
+ float HeightFreq3 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightFreq3", 2.0);
+ float HeightAmp1 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightAmp1", 1.0);
+ float HeightAmp2 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightAmp2", 0.5);
+ float HeightAmp3 = (float)a_IniFile.GetValueSetF("Generator", "ClassicHeightAmp3", 0.5);
+ m_HeightGen = new cHeiGenClassic(Seed, HeightFreq1, HeightAmp1, HeightFreq2, HeightAmp2, HeightFreq3, HeightAmp3);
+ }
+ else // "biomal" or <not found>
+ {
+ if (NoCaseCompare(HeightGenName, "biomal") != 0)
+ {
+ LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
+ }
+ m_HeightGen = new cHeiGenBiomal(Seed, *m_BiomeGen);
+ }
+
+ // Add a cache, if requested:
+ int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64);
+ if (CacheSize > 0)
+ {
+ if (CacheSize < 4)
+ {
+ LOGWARNING("Heightgen cache size set too low, would hurt performance instead of helping. Increasing from %d to %d",
+ CacheSize, 4
+ );
+ CacheSize = 4;
+ }
+ LOGINFO("Using a cache for Heightgen of size %d.", CacheSize);
+ m_HeightGen = new cHeiGenCache(m_HeightGen, CacheSize);
+ }
+}
+
+
+
+
+
+void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
+{
+ AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", "");
+ if (CompoGenName.empty())
+ {
+ LOGWARN("[Generator]::CompositionGen value not found in world.ini, using \"Biomal\".");
+ CompoGenName = "Biomal";
+ }
+ if (NoCaseCompare(CompoGenName, "sameblock") == 0)
+ {
+ int Block = m_ChunkGenerator.GetIniBlock(a_IniFile, "Generator", "SameBlockType", "stone");
+ bool Bedrocked = (a_IniFile.GetValueSetI("Generator", "SameBlockBedrocked", 1) != 0);
+ m_CompositionGen = new cCompoGenSameBlock((BLOCKTYPE)Block, Bedrocked);
+ }
+ else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0)
+ {
+ m_CompositionGen = new cCompoGenDebugBiomes;
+ }
+ else if (NoCaseCompare(CompoGenName, "classic") == 0)
+ {
+ int SeaLevel = a_IniFile.GetValueSetI("Generator", "ClassicSeaLevel", 60);
+ int BeachHeight = a_IniFile.GetValueSetI("Generator", "ClassicBeachHeight", 2);
+ int BeachDepth = a_IniFile.GetValueSetI("Generator", "ClassicBeachDepth", 4);
+ BLOCKTYPE BlockTop = m_ChunkGenerator.GetIniBlock(a_IniFile, "Generator", "ClassicBlockTop", "grass");
+ BLOCKTYPE BlockMiddle = m_ChunkGenerator.GetIniBlock(a_IniFile, "Generator", "ClassicBlockMiddle", "dirt");
+ BLOCKTYPE BlockBottom = m_ChunkGenerator.GetIniBlock(a_IniFile, "Generator", "ClassicBlockBottom", "stone");
+ BLOCKTYPE BlockBeach = m_ChunkGenerator.GetIniBlock(a_IniFile, "Generator", "ClassicBlockBeach", "sand");
+ BLOCKTYPE BlockBeachBottom = m_ChunkGenerator.GetIniBlock(a_IniFile, "Generator", "ClassicBlockBeachBottom", "sandstone");
+ BLOCKTYPE BlockSea = m_ChunkGenerator.GetIniBlock(a_IniFile, "Generator", "ClassicBlockSea", "stationarywater");
+ m_CompositionGen = new cCompoGenClassic(
+ SeaLevel, BeachHeight, BeachDepth, BlockTop, BlockMiddle, BlockBottom, BlockBeach,
+ BlockBeachBottom, BlockSea
+ );
+ }
+ else
+ {
+ if (NoCaseCompare(CompoGenName, "biomal") != 0)
+ {
+ LOGWARN("Unknown CompositionGen \"%s\", using \"biomal\" instead.", CompoGenName.c_str());
+ }
+ int SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalSeaLevel", 62);
+ int Seed = m_ChunkGenerator.GetSeed();
+ m_CompositionGen = new cCompoGenBiomal(Seed, SeaLevel);
+ }
+}
+
+
+
+
+
+void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile)
+{
+ AString Structures = a_IniFile.GetValueSet("Generator", "Structures", "Ravines,WormNestCaves,OreNests,Trees");
+
+ int Seed = m_ChunkGenerator.GetSeed();
+ AStringVector Str = StringSplit(Structures, ",");
+ for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
+ {
+ if (NoCaseCompare(*itr, "trees") == 0)
+ {
+ m_StructureGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
+ }
+ else if (NoCaseCompare(*itr, "marblecaves") == 0)
+ {
+ m_StructureGens.push_back(new cStructGenMarbleCaves(Seed));
+ }
+ else if (NoCaseCompare(*itr, "dualridgecaves") == 0)
+ {
+ float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3);
+ m_StructureGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold));
+ }
+ else if (NoCaseCompare(*itr, "orenests") == 0)
+ {
+ m_StructureGens.push_back(new cStructGenOreNests(Seed));
+ }
+ else if (NoCaseCompare(*itr, "ravines") == 0)
+ {
+ m_StructureGens.push_back(new cStructGenRavines(Seed, 128));
+ }
+ //*
+ // TODO: Not implemented yet; need a name
+ else if (NoCaseCompare(*itr, "wormnestcaves") == 0)
+ {
+ m_StructureGens.push_back(new cStructGenWormNestCaves(Seed));
+ }
+ //*/
+ else
+ {
+ LOGWARNING("Unknown structure generator: \"%s\". Ignoring.", itr->c_str());
+ }
+ } // for itr - Str[]
+}
+
+
+
+
+
+void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
+{
+ int Seed = m_ChunkGenerator.GetSeed();
+ AString Structures = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator");
+
+ AStringVector Str = StringSplit(Structures, ",");
+ for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
+ {
+ // Finishers, alpha-sorted:
+ if (NoCaseCompare(*itr, "BottomLava") == 0)
+ {
+ int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", 10);
+ m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel));
+ }
+ else if (NoCaseCompare(*itr, "DeadBushes") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenDeadBushes(Seed));
+ }
+ else if (NoCaseCompare(*itr, "Ice") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenIce);
+ }
+ else if (NoCaseCompare(*itr, "Lilypads") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenLilypads(Seed));
+ }
+ else if (NoCaseCompare(*itr, "PreSimulator") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenPreSimulator);
+ }
+ else if (NoCaseCompare(*itr, "Snow") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenSnow);
+ }
+ else if (NoCaseCompare(*itr, "SprinkleFoliage") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenSprinkleFoliage(Seed));
+ }
+ } // for itr - Str[]
+}
+
+
+
+
diff --git a/source/Generating/ComposableGenerator.h b/source/Generating/ComposableGenerator.h new file mode 100644 index 000000000..e3a37d57c --- /dev/null +++ b/source/Generating/ComposableGenerator.h @@ -0,0 +1,178 @@ +
+// ComposableGenerator.h
+
+// Declares the cComposableGenerator class representing the chunk generator that takes the composition approach to generating chunks
+
+/*
+Generating works by composing several algorithms:
+Biome, TerrainHeight, TerrainComposition, Ores, Structures and SmallFoliage
+Each algorithm may be chosen from a pool of available algorithms in the same class and combined with others,
+based on user's preferences in the world.ini.
+See http://forum.mc-server.org/showthread.php?tid=409 for details.
+*/
+
+
+
+
+
+#pragma once
+
+#include "ChunkGenerator.h"
+
+
+
+
+
+/** The interface that a biome generator must implement
+A biome generator takes chunk coords on input and outputs an array of biome indices for that chunk on output.
+The output array is sequenced in the same way as the MapChunk packet's biome data.
+*/
+class cBiomeGen
+{
+public:
+ virtual ~cBiomeGen() {} // Force a virtual destructor in descendants
+
+ /// Generates biomes for the given chunk
+ virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0;
+} ;
+
+
+
+
+
+/** The interface that a terrain height generator must implement
+A terrain height generator takes chunk coords on input and outputs an array of terrain heights for that chunk.
+The output array is sequenced in the same way as the BiomeGen's biome data.
+The generator may request biome information from the underlying BiomeGen, it may even request information for
+other chunks than the one it's currently generating (possibly neighbors - for averaging)
+*/
+class cTerrainHeightGen
+{
+public:
+ virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants
+
+ /// Generates heightmap for the given chunk
+ virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0;
+} ;
+
+
+
+
+
+/** The interface that a terrain composition generator must implement
+Terrain composition takes chunk coords on input and outputs the blockdata for that entire chunk, along with
+the list of entities. It is supposed to make use of the underlying TerrainHeightGen and BiomeGen for that purpose,
+but it may request information for other chunks than the one it's currently generating from them.
+*/
+class cTerrainCompositionGen
+{
+public:
+ virtual ~cTerrainCompositionGen() {} // Force a virtual destructor in descendants
+
+ virtual void ComposeTerrain(
+ int a_ChunkX, int a_ChunkZ,
+ cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated (the whole array gets initialized, even air)
+ cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated (the whole array gets initialized)
+ const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
+ const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
+ cEntityList & a_Entities, // Entitites may be generated along with the terrain
+ cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
+ ) = 0;
+} ;
+
+
+
+
+
+/** The interface that a structure generator must implement
+Structures are generated after the terrain composition took place. It should modify the blocktype data to account
+for whatever structures the generator is generating.
+Note that ores are considered structures too, at least from the interface point of view.
+Also note that a worldgenerator may contain multiple structure generators, one for each type of structure
+*/
+class cStructureGen
+{
+public:
+ virtual ~cStructureGen() {} // Force a virtual destructor in descendants
+
+ virtual void GenStructures(
+ int a_ChunkX, int a_ChunkZ,
+ cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
+ cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
+ cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
+ cEntityList & a_Entities, // Entities may be added or deleted
+ cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
+ ) = 0;
+} ;
+
+typedef std::list<cStructureGen *> cStructureGenList;
+
+
+
+
+
+/** The interface that a finisher must implement
+Finisher implements small additions after all structures have been generated.
+*/
+class cFinishGen
+{
+public:
+ virtual ~cFinishGen() {} // Force a virtual destructor in descendants
+
+ virtual void GenFinish(
+ int a_ChunkX, int a_ChunkZ,
+ cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
+ cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
+ cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
+ const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
+ cEntityList & a_Entities, // Entities may be added or deleted
+ cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
+ ) = 0;
+} ;
+
+typedef std::list<cFinishGen *> cFinishGenList;
+
+
+
+
+
+class cComposableGenerator :
+ public cChunkGenerator::cGenerator
+{
+ typedef cChunkGenerator::cGenerator super;
+
+public:
+ cComposableGenerator(cChunkGenerator & a_ChunkGenerator);
+ virtual ~cComposableGenerator();
+
+ virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile) override;
+ virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
+ virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) override;
+
+protected:
+ // The generation composition:
+ cBiomeGen * m_BiomeGen;
+ cTerrainHeightGen * m_HeightGen;
+ cTerrainCompositionGen * m_CompositionGen;
+ cStructureGenList m_StructureGens;
+ cFinishGenList m_FinishGens;
+
+ /// Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly
+ void InitBiomeGen(cIniFile & a_IniFile);
+
+ /// Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly
+ void InitHeightGen(cIniFile & a_IniFile);
+
+ /// Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly
+ void InitCompositionGen(cIniFile & a_IniFile);
+
+ /// Reads the structures to generate from the ini and initializes m_StructureGens accordingly
+ void InitStructureGens(cIniFile & a_IniFile);
+
+ /// Reads the finishers from the ini and initializes m_FinishGens accordingly
+ void InitFinishGens(cIniFile & a_IniFile);
+} ;
+
+
+
+
diff --git a/source/Generating/FinishGen.h b/source/Generating/FinishGen.h index 6a2367f38..573060843 100644 --- a/source/Generating/FinishGen.h +++ b/source/Generating/FinishGen.h @@ -15,7 +15,7 @@ -#include "ChunkGenerator.h" +#include "ComposableGenerator.h" #include "../Noise.h" diff --git a/source/Generating/HeiGen.h b/source/Generating/HeiGen.h index 101179bfc..042f7afc2 100644 --- a/source/Generating/HeiGen.h +++ b/source/Generating/HeiGen.h @@ -14,7 +14,7 @@ Interfaces to the various height generators: #pragma once -#include "ChunkGenerator.h" +#include "ComposableGenerator.h" #include "../Noise.h" diff --git a/source/Generating/Ravines.h b/source/Generating/Ravines.h index d2d2b9391..79db697d0 100644 --- a/source/Generating/Ravines.h +++ b/source/Generating/Ravines.h @@ -9,7 +9,7 @@ #pragma once
-#include "ChunkGenerator.h"
+#include "ComposableGenerator.h"
#include "../Noise.h"
diff --git a/source/Generating/StructGen.h b/source/Generating/StructGen.h index fafd0f85d..1b2941649 100644 --- a/source/Generating/StructGen.h +++ b/source/Generating/StructGen.h @@ -13,7 +13,7 @@ #pragma once -#include "ChunkGenerator.h" +#include "ComposableGenerator.h" #include "../Noise.h" |