summaryrefslogtreecommitdiffstats
path: root/src/Generating/VerticalLimit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Generating/VerticalLimit.cpp')
-rw-r--r--src/Generating/VerticalLimit.cpp414
1 files changed, 414 insertions, 0 deletions
diff --git a/src/Generating/VerticalLimit.cpp b/src/Generating/VerticalLimit.cpp
new file mode 100644
index 000000000..5cc003749
--- /dev/null
+++ b/src/Generating/VerticalLimit.cpp
@@ -0,0 +1,414 @@
+
+// VerticalLimit.cpp
+
+#include "Globals.h"
+#include "VerticalLimit.h"
+
+
+
+
+
+// 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, Max.
+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_Max.
+If no value is in the string, both values are left unchanged.
+If only the minimum is in the string, it is assigned to both a_Min and a_Max. */
+static bool ParseRange(const AString & a_Params, int & a_Min, int & a_Max, 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
+ a_Max = a_Min;
+ return true;
+ }
+ if (!StringToInteger(params[1], a_Max))
+ {
+ CONDWARNING(a_LogWarnings, "Cannot parse maximum height from string \"%s\"!", params[1].c_str());
+ return false;
+ }
+ if (a_Max < a_Min)
+ {
+ std::swap(a_Max, a_Min);
+ }
+ return true;
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/** Limit that accepts any height. The default for all pieces. */
+class cVerticalLimitNone:
+ public cPiece::cVerticalLimit
+{
+public:
+ virtual bool CanBeAtHeight(int a_BlockX, int a_BlockZ, int a_Height) override
+ {
+ // Any height is okay
+ return true;
+ }
+
+
+ virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override
+ {
+ // No parameters to read, no checks being done
+ return true;
+ }
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/** Limit that accepts heights above the specified minimum fixed height. */
+class cVerticalLimitAbove:
+ public cPiece::cVerticalLimit
+{
+public:
+ virtual bool CanBeAtHeight(int a_BlockX, int a_BlockZ, int a_Height) override
+ {
+ return (a_Height >= m_MinHeight);
+ }
+
+
+ virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override
+ {
+ // Parameters: "<MinHeight>", compulsory
+ if (!StringToInteger(a_Params, m_MinHeight))
+ {
+ CONDWARNING(a_LogWarnings, "Cannot parse the minimum height from string \"%s\"!", a_Params.c_str());
+ return false;
+ }
+ return true;
+ }
+
+protected:
+ /** The minimum accepted height. */
+ int m_MinHeight;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/** Limit that accepts heights that are a specified number of blocks above terrain. */
+class cVerticalLimitAboveTerrain:
+ public cPiece::cVerticalLimit
+{
+public:
+ virtual bool CanBeAtHeight(int a_BlockX, int a_BlockZ, int a_Height) override
+ {
+ auto terrainHeight = m_TerrainHeightGen->GetHeightAt(a_BlockX, a_BlockZ);
+ int compareHeight = a_Height - terrainHeight;
+ return (
+ (compareHeight >= m_MinBlocksAbove) && // Above the minimum
+ (compareHeight <= m_MaxBlocksAbove) // and below the maximum
+ );
+ }
+
+
+ virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override
+ {
+ // Parameters: "<MinBlocksAbove>|<MaxBlocksAbove>", both optional
+ m_MinBlocksAbove = 0;
+ m_MaxBlocksAbove = 0;
+ return ParseRange(a_Params, m_MinBlocksAbove, m_MaxBlocksAbove, a_LogWarnings);
+ }
+
+
+ virtual void AssignGens(int a_Seed, cBiomeGenPtr & a_BiomeGen, cTerrainHeightGenPtr & a_TerrainHeightGen, int a_SeaLevel) override
+ {
+ m_TerrainHeightGen = a_TerrainHeightGen;
+ }
+
+protected:
+ /** The underlying height generator. */
+ cTerrainHeightGenPtr m_TerrainHeightGen;
+
+ /** How many blocks above the terrain level do we accept on minimum. */
+ int m_MinBlocksAbove;
+
+ /** How many blocks above the terrain level do we accept on maximum. */
+ int m_MaxBlocksAbove;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/** Limit that accepts heights that are a specified number of blocks above terrain and sealevel, whichever is higher. */
+class cVerticalLimitAboveTerrainAndOcean:
+ public cPiece::cVerticalLimit
+{
+public:
+ virtual bool CanBeAtHeight(int a_BlockX, int a_BlockZ, int a_Height) override
+ {
+ ASSERT(m_TerrainHeightGen != nullptr);
+ int terrainHeight = m_TerrainHeightGen->GetHeightAt(a_BlockX, a_BlockZ);
+ int compareHeight = a_Height - std::max(terrainHeight, m_SeaLevel);
+ return (
+ (compareHeight >= m_MinBlocksAbove) && // Above the minimum
+ (compareHeight <= m_MaxBlocksAbove) // and below the maximum
+ );
+ }
+
+
+ virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override
+ {
+ // Parameters: "<MinBlocksAbove>|<MaxBlocksAbove>", both optional
+ m_MinBlocksAbove = 0;
+ m_MaxBlocksAbove = 0;
+ return ParseRange(a_Params, m_MinBlocksAbove, m_MaxBlocksAbove, a_LogWarnings);
+ }
+
+
+ virtual void AssignGens(int a_Seed, cBiomeGenPtr & a_BiomeGen, cTerrainHeightGenPtr & a_TerrainHeightGen, int a_SeaLevel) override
+ {
+ m_TerrainHeightGen = a_TerrainHeightGen;
+ m_SeaLevel = a_SeaLevel;
+ }
+
+protected:
+ /** The underlying height generator. */
+ cTerrainHeightGenPtr m_TerrainHeightGen;
+
+ /** The sealevel for the current world. */
+ int m_SeaLevel;
+
+ /** How many blocks above the terrain level / ocean do we accept on minimum. */
+ int m_MinBlocksAbove;
+
+ /** How many blocks above the terrain level / ocean do we accept on maximum. */
+ int m_MaxBlocksAbove;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/** Limit that accepts heights below the specified fixed height.
+NOTE that the query height is the BOTTOM of the piece. */
+class cVerticalLimitBelow:
+ public cPiece::cVerticalLimit
+{
+public:
+ virtual bool CanBeAtHeight(int a_BlockX, int a_BlockZ, int a_Height) override
+ {
+ return (a_Height <= m_MaxHeight);
+ }
+
+
+ virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override
+ {
+ // Parameters: "<MaxHeight>"
+ if (!StringToInteger(a_Params, m_MaxHeight))
+ {
+ CONDWARNING(a_LogWarnings, "Cannot parse the maximum height from string \"%s\"!", a_Params.c_str());
+ return false;
+ }
+ return true;
+ }
+
+protected:
+ /** The maximum accepted height. */
+ int m_MaxHeight;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/** Limit that accepts heights that are within a specified range below terrain.
+NOTE that the query height is the BOTTOM of the piece. */
+class cVerticalLimitBelowTerrain:
+ public cPiece::cVerticalLimit
+{
+public:
+ virtual bool CanBeAtHeight(int a_BlockX, int a_BlockZ, int a_Height) override
+ {
+ auto terrainHeight = m_TerrainHeightGen->GetHeightAt(a_BlockX, a_BlockZ);
+ auto compareHeight = terrainHeight - a_Height;
+ return (
+ (compareHeight >= m_MinBlocksBelow) &&
+ (compareHeight <= m_MaxBlocksBelow)
+ );
+ }
+
+
+ virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override
+ {
+ // Parameters: "<MinBlocksBelow>|<MaxBlocksBelow>", both optional
+ m_MinBlocksBelow = 0;
+ m_MaxBlocksBelow = 0;
+ return ParseRange(a_Params, m_MinBlocksBelow, m_MaxBlocksBelow, a_LogWarnings);
+ }
+
+
+ virtual void AssignGens(int a_Seed, cBiomeGenPtr & a_BiomeGen, cTerrainHeightGenPtr & a_TerrainHeightGen, int a_SeaLevel) override
+ {
+ m_TerrainHeightGen = a_TerrainHeightGen;
+ }
+
+protected:
+ /** The underlying height generator. */
+ cTerrainHeightGenPtr m_TerrainHeightGen;
+
+ /** How many blocks below the terrain level do we accept on minimum. */
+ int m_MinBlocksBelow;
+
+ /** How many blocks below the terrain level do we accept on maximum. */
+ int m_MaxBlocksBelow;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/** Limit that accepts heights that are a specified number of blocks below terrain or sealevel, whichever is higher. */
+class cVerticalLimitBelowTerrainOrOcean:
+ public cPiece::cVerticalLimit
+{
+public:
+ virtual bool CanBeAtHeight(int a_BlockX, int a_BlockZ, int a_Height) override
+ {
+ int terrainHeight = m_TerrainHeightGen->GetHeightAt(a_BlockX, a_BlockZ);
+ auto compareHeight = std::max(terrainHeight, m_SeaLevel) - a_Height;
+ return (
+ (compareHeight >= m_MinBlocksBelow) &&
+ (compareHeight <= m_MaxBlocksBelow)
+ );
+ }
+
+
+ virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) override
+ {
+ // Parameters: "<MinBlocksBelow>|<MaxBlocksBelow>", both optional
+ m_MinBlocksBelow = 0;
+ m_MaxBlocksBelow = 0;
+ return ParseRange(a_Params, m_MinBlocksBelow, m_MaxBlocksBelow, a_LogWarnings);
+ }
+
+
+ virtual void AssignGens(int a_Seed, cBiomeGenPtr & a_BiomeGen, cTerrainHeightGenPtr & a_TerrainHeightGen, int a_SeaLevel) override
+ {
+ m_TerrainHeightGen = a_TerrainHeightGen;
+ m_SeaLevel = a_SeaLevel;
+ }
+
+protected:
+ /** The underlying height generator. */
+ cTerrainHeightGenPtr m_TerrainHeightGen;
+
+ /** The sealevel for the current world. */
+ int m_SeaLevel;
+
+ /** How many blocks below the terrain level do we accept on minimum. */
+ int m_MinBlocksBelow;
+
+ /** How many blocks below the terrain level do we accept on maximum. */
+ int m_MaxBlocksBelow;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// CreateVerticalLimitFromString:
+
+cPiece::cVerticalLimitPtr CreateVerticalLimitFromString(const AString & a_LimitDesc, bool a_LogWarnings)
+{
+ // Break apart the limit class, the first parameter before the first pipe char:
+ auto idxPipe = a_LimitDesc.find('|');
+ if (idxPipe == AString::npos)
+ {
+ idxPipe = a_LimitDesc.length();
+ }
+ AString LimitClass = a_LimitDesc.substr(0, idxPipe);
+
+ // Create a strategy class based on the class string:
+ cPiece::cVerticalLimitPtr Limit;
+ if ((LimitClass == "") || (NoCaseCompare(LimitClass, "None") == 0))
+ {
+ Limit = std::make_shared<cVerticalLimitNone>();
+ }
+ else if (NoCaseCompare(LimitClass, "Above") == 0)
+ {
+ Limit = std::make_shared<cVerticalLimitAbove>();
+ }
+ else if (NoCaseCompare(LimitClass, "AboveTerrain") == 0)
+ {
+ Limit = std::make_shared<cVerticalLimitAboveTerrain>();
+ }
+ else if (NoCaseCompare(LimitClass, "AboveTerrainAndOcean") == 0)
+ {
+ Limit = std::make_shared<cVerticalLimitAboveTerrainAndOcean>();
+ }
+ else if (NoCaseCompare(LimitClass, "Below") == 0)
+ {
+ Limit = std::make_shared<cVerticalLimitBelow>();
+ }
+ else if (NoCaseCompare(LimitClass, "BelowTerrain") == 0)
+ {
+ Limit = std::make_shared<cVerticalLimitBelowTerrain>();
+ }
+ else if (NoCaseCompare(LimitClass, "BelowTerrainOrOcean") == 0)
+ {
+ Limit = std::make_shared<cVerticalLimitBelowTerrainOrOcean>();
+ }
+ else
+ {
+ return nullptr;
+ }
+
+ // Initialize the limit's parameters:
+ AString Params;
+ if (idxPipe < a_LimitDesc.length())
+ {
+ Params = a_LimitDesc.substr(idxPipe + 1);
+ }
+ if (!Limit->InitializeFromString(Params, a_LogWarnings))
+ {
+ return nullptr;
+ }
+
+ return Limit;
+}
+
+
+
+