diff options
Diffstat (limited to 'src/Generating/VerticalStrategy.cpp')
-rw-r--r-- | src/Generating/VerticalStrategy.cpp | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/src/Generating/VerticalStrategy.cpp b/src/Generating/VerticalStrategy.cpp new file mode 100644 index 000000000..08af5b272 --- /dev/null +++ b/src/Generating/VerticalStrategy.cpp @@ -0,0 +1,342 @@ + +// VerticalStrategy.cpp + +// Implements the various classes descending from cPiece::cVerticalStrategy + +#include "Globals.h" +#include "VerticalStrategy.h" + + + + + +// Constant that is added to random seed +static const int SEED_OFFSET = 135; + + + + + +// Emit a warning if the first param is true +#define CONDWARNING(ShouldLog, Fmt, ...) \ + if (ShouldLog) \ + { \ + LOGWARNING(Fmt, __VA_ARGS__); \ + } + + + + + +//////////////////////////////////////////////////////////////////////////////// +// Globals: + +/** Parses a string containing a range in which both values are optional ("<MinHeight>|<MaxHeight>") into Min, Range. +Returns true if successful, false on failure. +If a_LogWarnings is true, outputs failure reasons to console. +The range is returned in a_Min and a_Range, they are left unchanged if the range value is not present in the string. */ +static bool ParseRange(const AString & a_Params, int & a_Min, int & a_Range, bool a_LogWarnings) +{ + auto params = StringSplitAndTrim(a_Params, "|"); + if (params.size() == 0) + { + // No params, generate directly on top: + return true; + } + if (!StringToInteger(params[0], a_Min)) + { + // Failed to parse the min rel height: + CONDWARNING(a_LogWarnings, "Cannot parse minimum height from string \"%s\"!", params[0].c_str()); + return false; + } + if (params.size() == 1) + { + // Only one param was given, there's no range + return true; + } + int maxHeight = a_Min; + if (!StringToInteger(params[1], maxHeight)) + { + CONDWARNING(a_LogWarnings, "Cannot parse maximum height from string \"%s\"!", params[1].c_str()); + return false; + } + if (maxHeight < a_Min) + { + std::swap(maxHeight, a_Min); + } + a_Range = maxHeight - a_Min + 1; + return true; +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +/** A vertical strategy that places the piece at a predefined height. */ +class cVerticalStrategyFixed: + public cPiece::cVerticalStrategy +{ +public: + cVerticalStrategyFixed(void): + m_Height(-1000) // Default to "unassigned" height + { + } + + + virtual int GetVerticalPlacement(int a_BlockX, int a_BlockZ) override + { + return m_Height; + } + + + virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override + { + // Params: "<Height>", compulsory + if (!StringToInteger(a_Params, m_Height)) + { + CONDWARNING(a_LogWarnings, "Cannot parse the fixed height from string \"%s\"!", a_Params.c_str()); + return false; + } + return true; + } + +protected: + /** Height at which the pieces are placed. + Note that this height may be outside the world, so that only a part of the piece is generated. */ + int m_Height; +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// +/** A vertical strategy that places the piece in a random height between two heights. */ +class cVerticalStrategyRange: + public cPiece::cVerticalStrategy +{ +public: + cVerticalStrategyRange(void): + m_Seed(0), + m_Min(-1), // Default to "unassigned" height + m_Range(1) + { + } + + + virtual int GetVerticalPlacement(int a_BlockX, int a_BlockZ) override + { + cNoise Noise(m_Seed); + return m_Min + (Noise.IntNoise2DInt(a_BlockX, a_BlockZ) / 7) % m_Range; + } + + + virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override + { + // Params: "<MinHeight>|<MaxHeight>", all compulsory + auto params = StringSplitAndTrim(a_Params, "|"); + if (params.size() != 2) + { + CONDWARNING(a_LogWarnings, "Cannot parse the range parameters from string \"%s\"!", a_Params.c_str()); + return false; + } + int Max = 0; + if (!StringToInteger(params[0], m_Min) || !StringToInteger(params[1], Max)) + { + CONDWARNING(a_LogWarnings, "Cannot parse the minimum or maximum height from string \"%s\"!", a_Params.c_str()); + return false; + } + if (m_Min > Max) + { + std::swap(m_Min, Max); + } + m_Range = Max - m_Min + 1; + return true; + } + + + virtual void AssignGens(int a_Seed, cBiomeGenPtr & a_BiomeGen, cTerrainHeightGenPtr & a_TerrainHeightGen, int a_SeaLevel) override + { + m_Seed = a_Seed + SEED_OFFSET; + } + +protected: + /** Seed for the random generator. Received in AssignGens(). */ + int m_Seed; + + /** Range for the random generator. Received in InitializeFromString(). */ + int m_Min, m_Range; +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// +/** A vertical strategy that places the piece in a specified range relative to the top of the terrain. */ +class cVerticalStrategyTerrainTop: + public cPiece::cVerticalStrategy +{ +public: + + virtual int GetVerticalPlacement(int a_BlockX, int a_BlockZ) override + { + ASSERT(m_HeightGen != nullptr); + + int ChunkX, ChunkZ; + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); + cChunkDef::HeightMap HeightMap; + m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap); + cNoise noise(m_Seed); + int rel = m_MinRelHeight + (noise.IntNoise2DInt(a_BlockX, a_BlockZ) / 7) % m_RelHeightRange + 1; + return cChunkDef::GetHeight(HeightMap, a_BlockX - ChunkX * cChunkDef::Width, a_BlockZ - ChunkZ * cChunkDef::Width) + rel; + } + + + virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override + { + // Params: "<MinRelativeHeight>|<MaxRelativeHeight>", all optional + m_MinRelHeight = 0; + m_RelHeightRange = 1; + return ParseRange(a_Params, m_MinRelHeight, m_RelHeightRange, a_LogWarnings); + } + + + virtual void AssignGens(int a_Seed, cBiomeGenPtr & a_BiomeGen, cTerrainHeightGenPtr & a_HeightGen, int a_SeaLevel) override + { + m_Seed = a_Seed + SEED_OFFSET; + m_HeightGen = a_HeightGen; + } + +protected: + /** Seed for the random generator. */ + int m_Seed; + + /** Height generator from which the top of the terrain is read. */ + cTerrainHeightGenPtr m_HeightGen; + + /** Minimum relative height at which the prefab is placed. */ + int m_MinRelHeight; + + /** Range of the relative heights at which the prefab can be placed above the minimum. */ + int m_RelHeightRange; +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// +/** A vertical strategy that places the piece within a range on top of the terrain or ocean, whichever's higher. */ +class cVerticalStrategyTerrainOrOceanTop: + public cPiece::cVerticalStrategy +{ +public: + + virtual int GetVerticalPlacement(int a_BlockX, int a_BlockZ) override + { + ASSERT(m_HeightGen != nullptr); + + int ChunkX, ChunkZ; + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); + cChunkDef::HeightMap HeightMap; + m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap); + int terrainHeight = static_cast<int>(cChunkDef::GetHeight(HeightMap, a_BlockX - ChunkX * cChunkDef::Width, a_BlockZ - ChunkZ * cChunkDef::Width)); + terrainHeight = std::max(1 + terrainHeight, m_SeaLevel); + cNoise noise(m_Seed); + int rel = m_MinRelHeight + (noise.IntNoise2DInt(a_BlockX, a_BlockZ) / 7) % m_RelHeightRange + 1; + return terrainHeight + rel; + } + + + virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override + { + // Params: "<MinRelativeHeight>|<MaxRelativeHeight>", all optional + m_MinRelHeight = 0; + m_RelHeightRange = 1; + return ParseRange(a_Params, m_MinRelHeight, m_RelHeightRange, a_LogWarnings); + } + + + virtual void AssignGens(int a_Seed, cBiomeGenPtr & a_BiomeGen, cTerrainHeightGenPtr & a_HeightGen, int a_SeaLevel) override + { + m_Seed = a_Seed + SEED_OFFSET; + m_HeightGen = a_HeightGen; + m_SeaLevel = a_SeaLevel; + } + +protected: + /** Seed for the random generator. */ + int m_Seed; + + /** Height generator from which the top of the terrain is read. */ + cTerrainHeightGenPtr m_HeightGen; + + /** The sea level used by the world. */ + int m_SeaLevel; + + /** Minimum relative height at which the prefab is placed. */ + int m_MinRelHeight; + + /** Range of the relative heights at which the prefab can be placed above the minimum. */ + int m_RelHeightRange; +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// +// CreateVerticalStrategyFromString: + +cPiece::cVerticalStrategyPtr CreateVerticalStrategyFromString(const AString & a_StrategyDesc, bool a_LogWarnings) +{ + // Break apart the strategy class, the first parameter before the first pipe char: + auto idxPipe = a_StrategyDesc.find('|'); + if (idxPipe == AString::npos) + { + idxPipe = a_StrategyDesc.length(); + } + AString StrategyClass = a_StrategyDesc.substr(0, idxPipe); + + // Create a strategy class based on the class string: + cPiece::cVerticalStrategyPtr Strategy; + if (NoCaseCompare(StrategyClass, "Fixed") == 0) + { + Strategy = std::make_shared<cVerticalStrategyFixed>(); + } + else if (NoCaseCompare(StrategyClass, "Range") == 0) + { + Strategy = std::make_shared<cVerticalStrategyRange>(); + } + else if (NoCaseCompare(StrategyClass, "TerrainTop") == 0) + { + Strategy = std::make_shared<cVerticalStrategyTerrainTop>(); + } + else if (NoCaseCompare(StrategyClass, "TerrainOrOceanTop") == 0) + { + Strategy = std::make_shared<cVerticalStrategyTerrainOrOceanTop>(); + } + else + { + return nullptr; + } + + // Initialize the strategy's parameters: + AString Params; + if (idxPipe < a_StrategyDesc.length()) + { + Params = a_StrategyDesc.substr(idxPipe + 1); + } + if (!Strategy->InitializeFromString(Params, a_LogWarnings)) + { + return nullptr; + } + + return Strategy; +} + + + + |