summaryrefslogtreecommitdiffstats
path: root/src/Generating/PiecePool.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/Generating/PiecePool.h')
-rw-r--r--src/Generating/PiecePool.h335
1 files changed, 335 insertions, 0 deletions
diff --git a/src/Generating/PiecePool.h b/src/Generating/PiecePool.h
new file mode 100644
index 000000000..84f511950
--- /dev/null
+++ b/src/Generating/PiecePool.h
@@ -0,0 +1,335 @@
+// PiecePool.h
+
+// Declares the cPiecePool class representing a pool of cPieces - "parts" of a structure, used in piece-generators
+
+
+
+
+
+#pragma once
+
+#include "ComposableGenerator.h"
+#include "../Defines.h"
+#include "../Cuboid.h"
+
+
+
+
+
+/** Represents a single piece. Can have multiple connectors of different types where other pieces can connect. */
+class cPiece
+{
+public:
+ // Force a virtual destructor in all descendants
+ virtual ~cPiece() {}
+
+ struct cConnector
+ {
+ enum eDirection
+ {
+ // The following values correspond to equivalent eBlockFace values:
+ dirXM = BLOCK_FACE_XM, // Pointing towards the X- side of the prefab
+ dirXP = BLOCK_FACE_XP, // Pointing towards the X+ side of the prefab
+ dirYM = BLOCK_FACE_YM, // Pointing towards the Y- side of the prefab, doesn't change with rotation around the Y axis
+ dirYP = BLOCK_FACE_YP, // Pointing towards the Y+ side of the prefab, doesn't change with rotation around the Y axis
+ dirZM = BLOCK_FACE_ZM, // Pointing towards the Z- side of the prefab
+ dirZP = BLOCK_FACE_ZP, // Pointing towards the Z+ side of the prefab
+
+ // Special kind of the vertical connectors (changes with rotation around the Y axis)
+ dirYM_XM_ZM = BLOCK_FACE_MAX + 1, // Pointing towards the Y- side of the prefab, conceptually at the X- Z- corner of the block
+ dirYM_XM_ZP, // Pointing towards the Y- side of the prefab, conceptually at the X- Z+ corner of the block
+ dirYM_XP_ZM, // Pointing towards the Y- side of the prefab, conceptually at the X+ Z- corner of the block
+ dirYM_XP_ZP, // Pointing towards the Y- side of the prefab, conceptually at the X+ Z+ corner of the block
+ dirYP_XM_ZM, // Pointing towards the Y+ side of the prefab, conceptually at the X- Z- corner of the block
+ dirYP_XM_ZP, // Pointing towards the Y+ side of the prefab, conceptually at the X- Z+ corner of the block
+ dirYP_XP_ZM, // Pointing towards the Y+ side of the prefab, conceptually at the X+ Z- corner of the block
+ dirYP_XP_ZP, // Pointing towards the Y+ side of the prefab, conceptually at the X+ Z+ corner of the block
+ };
+
+ /** Position relative to the piece */
+ Vector3i m_Pos;
+
+ /** Type of the connector. Any arbitrary number; the generator connects only connectors of opposite
+ (negative) types. */
+ int m_Type;
+
+ /** Direction in which the connector is facing.
+ Will be matched by the opposite direction for the connecting connector. */
+ eDirection m_Direction;
+
+ cConnector(int a_X, int a_Y, int a_Z, int a_Type, eDirection a_Direction);
+ cConnector(const Vector3i & a_Pos, int a_Type, eDirection a_Direction);
+
+ /** Returns the position of the block that has the specified direction from the specified position.
+ Similar to ::AddFaceDirection() */
+ static Vector3i AddDirection(const Vector3i & a_Pos, eDirection a_Direction);
+
+ /** Returns the string representation of the direction.
+ For debugging purposes. */
+ static const char * DirectionToString(eDirection a_Direction);
+
+ /** Returns true if the specified number corresponds to a valid eDirection. */
+ static bool IsValidDirection(int a_Direction);
+
+ /** Returns the direction corresponding to the given direction rotated 180 degrees around the Y axis. */
+ static eDirection RotateDirection(eDirection a_Direction);
+
+ /** Returns the direction corresponding to the given direction rotated 90 degrees CCW around the Y axis. */
+ static eDirection RotateDirectionCCW(eDirection a_Direction);
+
+ /** Returns the direction corresponding to the given direction rotated 90 degrees CW around the Y axis. */
+ static eDirection RotateDirectionCW(eDirection a_Direction);
+
+ /** Returns the number of CCW rotations that a_RotatingDir requires in order to be the counter-direction of a_FixedDir.
+ Ie. if you have a connector with a_FixedDir and you're rotating a piece that has a connector with a_RotatingDir,
+ how many CCW rotations it needs to make the connectors compatible.
+ Returns -1 if it is impossible to fit the two directions. */
+ static int GetNumCCWRotationsToFit(eDirection a_FixedDir, eDirection a_RotatingDir);
+
+ /** Converts the string representation of a direction into the eDirection enum value.
+ Returns true if successful, false on failure.
+ Accepts both numbers and string representations such as "x+" or "Y+X-Z+". */
+ static bool StringToDirection(const AString & a_Value, eDirection & a_Out);
+ };
+
+ typedef std::vector<cConnector> cConnectors;
+
+
+ /** Base class (interface) for strategies for placing the starting pieces vertically.
+ Descendants can override the GetVerticalPlacement() method to provide custom placement decisions. */
+ class cVerticalStrategy
+ {
+ public:
+ // Force a virtual destructor in descendants
+ virtual ~cVerticalStrategy() {}
+
+ /** Returns the Y coord of the piece */
+ virtual int GetVerticalPlacement(int a_BlockX, int a_BlockZ) = 0;
+
+ /** Initializes the strategy's parameters from the string representation.
+ a_Params is the string containing only the parameters (substring after the first pipe character in the strategy description string).
+ If a_LogWarnings is true, logs any problems to the console.
+ Returns true if successful, false if the string parsing failed.
+ Used when loading the strategy from a file. */
+ virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) = 0;
+
+ /** Called when the piece pool is assigned to a generator,
+ so that the strategies may bind to the underlying subgenerators. */
+ virtual void AssignGens(int a_Seed, cBiomeGenPtr & a_BiomeGen, cTerrainHeightGenPtr & a_TerrainHeightGen, int a_SeaLevel) {}
+ };
+
+ typedef SharedPtr<cVerticalStrategy> cVerticalStrategyPtr;
+
+
+ /** Base class (interface) for the vertical limit of piece placement.
+ Each placed piece can have a limit, represented by this class, that gets queried for validity of the placement. */
+ class cVerticalLimit
+ {
+ public:
+ virtual ~cVerticalLimit() {}
+
+ /** Called to inquire whether the specified piece can be placed at the specified height.
+ a_BlockX, a_BlockZ is the column of the connector that is being queried.
+ a_Height is the requested height of the piece's lowest block. */
+ virtual bool CanBeAtHeight(int a_BlockX, int a_BlockZ, int a_Height) = 0;
+
+ /** Initializes the limit's parameters from the string representation.
+ a_Params is the string containing only the parameters (substring after the first pipe character in the limit description string).
+ Returns true if successful, false if the string parsing failed.
+ If a_LogWarnings is true, any error while parsing the string is output to the server console.
+ Used when loading the limit from a file. */
+ virtual bool InitializeFromString(const AString & a_Params, bool a_LogWarnings) = 0;
+
+ /** Called when the piece pool is assigned to a generator,
+ so that the limits may bind to the underlying subgenerators. */
+ virtual void AssignGens(int a_Seed, cBiomeGenPtr & a_BiomeGen, cTerrainHeightGenPtr & a_TerrainHeightGen, int a_SeaLevel) {}
+ };
+
+ typedef SharedPtr<cVerticalLimit> cVerticalLimitPtr;
+
+
+ /** The strategy used for vertical placement of this piece when it is used as a starting piece. */
+ cVerticalStrategyPtr m_VerticalStrategy;
+
+ /** The checker that verifies each placement's vertical position. */
+ cVerticalLimitPtr m_VerticalLimit;
+
+
+ /** Returns all of the available connectors that the piece has.
+ Each connector has a (relative) position in the piece, and a type associated with it. */
+ virtual cConnectors GetConnectors(void) const = 0;
+
+ /** Returns the dimensions of this piece.
+ The dimensions cover the entire piece, there is no block that the piece generates outside of this size. */
+ virtual Vector3i GetSize(void) const = 0;
+
+ /** Returns the "hitbox" of this piece.
+ A hitbox is what is compared and must not intersect other pieces' hitboxes when generating. */
+ virtual cCuboid GetHitBox(void) const = 0;
+
+ /** Returns true if the piece can be rotated CCW the specific number of 90-degree turns. */
+ virtual bool CanRotateCCW(int a_NumRotations) const = 0;
+
+ /** Returns the height, based on m_VerticalStrategy, for this piece when used as the starting piece.
+ If there's no strategy assigned to this piece, returns -1. */
+ int GetStartingPieceHeight(int a_BlockX, int a_BlockZ)
+ {
+ if (m_VerticalStrategy != nullptr)
+ {
+ return m_VerticalStrategy->GetVerticalPlacement(a_BlockX, a_BlockZ);
+ }
+ return -1;
+ }
+
+ void SetVerticalStrategy(cVerticalStrategyPtr a_VerticalStrategy)
+ {
+ m_VerticalStrategy = a_VerticalStrategy;
+ }
+
+ cVerticalStrategyPtr GetVerticalStrategy(void) const
+ {
+ return m_VerticalStrategy;
+ }
+
+ cVerticalLimitPtr GetVerticalLimit(void) const
+ {
+ return m_VerticalLimit;
+ }
+
+ /** Sets the vertical strategy based on the description in the string.
+ If a_LogWarnings is true, logs the parsing problems into the server console.
+ Returns true if successful, false if strategy parsing failed (no strategy assigned). */
+ bool SetVerticalStrategyFromString(const AString & a_StrategyDesc, bool a_LogWarnings);
+
+ /** Sets the vertical limit based on the description string.
+ Returns true if successful, false if limit parsing failed (no limit assigned).
+ If a_LogWarnings is true, any problem is reported into the server console. */
+ bool SetVerticalLimitFromString(const AString & a_LimitDesc, bool a_LogWarnings);
+
+ /** Returns a copy of the a_Pos after rotating the piece the specified number of CCW rotations. */
+ Vector3i RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const;
+
+ /** Returns a copy of the connector that is rotated and then moved by the specified amounts. */
+ cConnector RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
+
+ /** Returns the hitbox after the specified number of rotations and moved so that a_MyConnector is placed at a_ToConnectorPos. */
+ cCuboid RotateHitBoxToConnector(const cConnector & a_MyConnector, const Vector3i & a_ToConnectorPos, int a_NumCCWRotations) const;
+
+ /** Returns the hitbox after the specified number of CCW rotations and moved by the specified amounts. */
+ cCuboid RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
+};
+
+typedef std::vector<cPiece *> cPieces;
+
+
+
+
+// fwd:
+class cPlacedPiece;
+
+
+
+
+
+/** This class is an interface that stores pieces for a generator.
+Provides lists of pieces based on criteria (IsStarting, HasConnector).
+Provides per-piece weights for random distribution of individual pieces. */
+class cPiecePool
+{
+public:
+ // Force a virtual destructor in all descendants:
+ virtual ~cPiecePool() {}
+
+ /** Returns a list of pieces that contain the specified connector type.
+ The cPiece pointers returned are managed by the pool and the caller doesn't free them. */
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) = 0;
+
+ /** Returns the pieces that should be used as the starting point.
+ Multiple starting points are supported, one of the returned piece will be chosen. */
+ virtual cPieces GetStartingPieces(void) = 0;
+
+ /** Returns the relative weight with which the a_NewPiece is to be selected for placing under a_PlacedPiece through a_ExistingConnector.
+ a_ExistingConnector is the original connector, before any movement or rotation is applied to it.
+ This allows the pool to tweak the piece's chances, based on the previous pieces in the tree and the connector used.
+ The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will never be chosen. */
+ virtual int GetPieceWeight(
+ const cPlacedPiece & a_PlacedPiece,
+ const cPiece::cConnector & a_ExistingConnector,
+ const cPiece & a_NewPiece
+ )
+ {
+ return 1;
+ }
+
+ /** Returns the relative weight with which the a_NewPiece is to be selected for placing as the first piece.
+ This allows the pool to tweak the piece's chances.
+ The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will not be chosen.
+ If all pieces return 0, a random piece is chosen, with all equal chances. */
+ virtual int GetStartingPieceWeight(const cPiece & a_NewPiece)
+ {
+ return 1;
+ }
+
+ /** Called after a piece is placed, to notify the pool that it has been used.
+ The pool may adjust the pieces it will return the next time. */
+ virtual void PiecePlaced(const cPiece & a_Piece) = 0;
+
+ /** Called when the pool has finished the current structure and should reset any piece-counters it has
+ for a new structure. */
+ virtual void Reset(void) = 0;
+};
+
+
+
+
+
+/** Represents a single piece that has been placed to specific coords in the world. */
+class cPlacedPiece
+{
+public:
+ cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations);
+
+ const cPlacedPiece * GetParent (void) const { return m_Parent; }
+ const cPiece & GetPiece (void) const { return *m_Piece; }
+ const Vector3i & GetCoords (void) const { return m_Coords; }
+ int GetNumCCWRotations (void) const { return m_NumCCWRotations; }
+ const cCuboid & GetHitBox (void) const { return m_HitBox; }
+ int GetDepth (void) const { return m_Depth; }
+ bool HasBeenMovedToGround(void) const { return m_HasBeenMovedToGround; }
+
+ /** Returns the coords as a modifiable object. */
+ Vector3i & GetCoords(void) { return m_Coords; }
+
+ /** Returns the connector at the specified index, rotated in the actual placement.
+ Undefined behavior if a_Index is out of range. */
+ cPiece::cConnector GetRotatedConnector(size_t a_Index) const;
+
+ /** Returns a copy of the specified connector, modified to account for the translation and rotation for
+ this placement. */
+ cPiece::cConnector GetRotatedConnector(const cPiece::cConnector & a_Connector) const;
+
+ /** Moves the placed piece Y-wise by the specified offset.
+ Sets m_HasBeenMovedToGround to true, too.
+ Used eg. by village houses. */
+ void MoveToGroundBy(int a_OffsetY);
+
+protected:
+ const cPlacedPiece * m_Parent;
+ const cPiece * m_Piece;
+ Vector3i m_Coords;
+ int m_NumCCWRotations;
+ cCuboid m_HitBox; // Hitbox of the placed piece, in world coords
+ int m_Depth; // Depth in the generated piece tree
+
+ /** Set to true once the piece has been moved Y-wise.
+ Used eg. by village houses. */
+ bool m_HasBeenMovedToGround;
+};
+
+typedef std::unique_ptr<cPlacedPiece> cPlacedPiecePtr;
+typedef std::vector<cPlacedPiecePtr> cPlacedPieces;
+
+
+
+
+