summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Generating/CMakeLists.txt6
-rw-r--r--src/Generating/PieceGeneratorBFSTree.cpp345
-rw-r--r--src/Generating/PieceGeneratorBFSTree.h102
-rw-r--r--src/Generating/PiecePool.cpp (renamed from src/Generating/PieceGenerator.cpp)419
-rw-r--r--src/Generating/PiecePool.h (renamed from src/Generating/PieceGenerator.h)137
-rw-r--r--src/Generating/PieceStructuresGen.cpp165
-rw-r--r--src/Generating/PieceStructuresGen.h37
-rw-r--r--src/Generating/Prefab.h2
-rw-r--r--src/Generating/PrefabPiecePool.h2
-rw-r--r--src/Generating/PrefabStructure.cpp15
-rw-r--r--src/Generating/PrefabStructure.h6
-rw-r--r--src/Generating/VerticalLimit.h2
-rw-r--r--src/Generating/VerticalStrategy.cpp1
-rw-r--r--src/Generating/VerticalStrategy.h2
-rw-r--r--src/Generating/VillageGen.cpp14
15 files changed, 627 insertions, 628 deletions
diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt
index 2cd923a99..67e0e8b22 100644
--- a/src/Generating/CMakeLists.txt
+++ b/src/Generating/CMakeLists.txt
@@ -18,7 +18,8 @@ SET (SRCS
HeiGen.cpp
MineShafts.cpp
Noise3DGenerator.cpp
- PieceGenerator.cpp
+ PieceGeneratorBFSTree.cpp
+ PiecePool.cpp
PieceStructuresGen.cpp
Prefab.cpp
PrefabPiecePool.cpp
@@ -51,7 +52,8 @@ SET (HDRS
IntGen.h
MineShafts.h
Noise3DGenerator.h
- PieceGenerator.h
+ PieceGeneratorBFSTree.h
+ PiecePool.h
PieceStructuresGen.h
Prefab.h
PrefabPiecePool.h
diff --git a/src/Generating/PieceGeneratorBFSTree.cpp b/src/Generating/PieceGeneratorBFSTree.cpp
new file mode 100644
index 000000000..0078d53c9
--- /dev/null
+++ b/src/Generating/PieceGeneratorBFSTree.cpp
@@ -0,0 +1,345 @@
+
+// PieceGeneratorBFSTree.cpp
+
+// Implements the cPieceGeneratorBFSTree class for generating structures composed of individual "pieces" in a simple tree
+/*
+The generator keeps a pool of currently-open connectors, chooses one at random and tries to place a piece on it,
+thus possibly extending the pool of open connectors with the new piece's ones (like breadth-first search).
+*/
+
+#include "Globals.h"
+#include "PieceGeneratorBFSTree.h"
+#include "VerticalStrategy.h"
+#include "VerticalLimit.h"
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cPieceGeneratorBFSTree:
+
+cPieceGeneratorBFSTree::cPieceGeneratorBFSTree(cPiecePool & a_PiecePool, int a_Seed):
+ m_PiecePool(a_PiecePool),
+ m_Noise(a_Seed),
+ m_Seed(a_Seed)
+{
+}
+
+
+
+
+
+cPlacedPiecePtr cPieceGeneratorBFSTree::PlaceStartingPiece(int a_BlockX, int a_BlockZ, cFreeConnectors & a_OutConnectors)
+{
+ m_PiecePool.Reset();
+ int rnd = m_Noise.IntNoise2DInt(a_BlockX, a_BlockZ) / 7;
+
+ // Choose a random one of the starting pieces:
+ cPieces StartingPieces = m_PiecePool.GetStartingPieces();
+ int Total = 0;
+ for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr)
+ {
+ Total += m_PiecePool.GetStartingPieceWeight(**itr);
+ }
+ cPiece * StartingPiece;
+ if (Total > 0)
+ {
+ int Chosen = rnd % Total;
+ StartingPiece = StartingPieces.front();
+ for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr)
+ {
+ Chosen -= m_PiecePool.GetStartingPieceWeight(**itr);
+ if (Chosen <= 0)
+ {
+ StartingPiece = *itr;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // All pieces returned zero weight, but we need one to start. Choose with equal chance:
+ StartingPiece = StartingPieces[static_cast<size_t>(rnd) % StartingPieces.size()];
+ }
+ rnd = rnd >> 16;
+
+ // Choose a random supported rotation:
+ int Rotations[4] = {0};
+ int NumRotations = 1;
+ for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++)
+ {
+ if (StartingPiece->CanRotateCCW(static_cast<int>(i)))
+ {
+ Rotations[NumRotations] = static_cast<int>(i);
+ NumRotations += 1;
+ }
+ }
+ int Rotation = Rotations[rnd % NumRotations];
+ int BlockY = StartingPiece->GetStartingPieceHeight(a_BlockX, a_BlockZ);
+ ASSERT(BlockY >= 0); // The vertical strategy should have been provided and should give valid coords
+
+ cPlacedPiece * res = new cPlacedPiece(nullptr, *StartingPiece, Vector3i(a_BlockX, BlockY, a_BlockZ), Rotation);
+
+ // Place the piece's connectors into a_OutConnectors:
+ const cPiece::cConnectors & Conn = StartingPiece->GetConnectors();
+ for (cPiece::cConnectors::const_iterator itr = Conn.begin(), end = Conn.end(); itr != end; ++itr)
+ {
+ a_OutConnectors.push_back(
+ cFreeConnector(res, StartingPiece->RotateMoveConnector(*itr, Rotation, a_BlockX, BlockY, a_BlockZ))
+ );
+ }
+
+ return cPlacedPiecePtr(res);
+}
+
+
+
+
+
+bool cPieceGeneratorBFSTree::TryPlacePieceAtConnector(
+ const cPlacedPiece & a_ParentPiece,
+ const cPiece::cConnector & a_Connector,
+ cPlacedPieces & a_OutPieces,
+ cPieceGeneratorBFSTree::cFreeConnectors & a_OutConnectors
+)
+{
+ // Get a list of available connections:
+ cConnections Connections;
+ int WantedConnectorType = -a_Connector.m_Type;
+ cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(WantedConnectorType);
+ Connections.reserve(AvailablePieces.size());
+ Vector3i ConnPos = cPiece::cConnector::AddDirection(a_Connector.m_Pos, a_Connector.m_Direction); // The position at which the new connector should be placed - 1 block away from the current connector
+ int WeightTotal = 0;
+ for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP)
+ {
+ // Get the relative chance of this piece being generated in this path:
+ int Weight = m_PiecePool.GetPieceWeight(a_ParentPiece, a_Connector, **itrP);
+ if (Weight <= 0)
+ {
+ continue;
+ }
+
+ // Try fitting each of the piece's connector:
+ cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
+ auto verticalLimit = (*itrP)->GetVerticalLimit();
+ for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC)
+ {
+ if (itrC->m_Type != WantedConnectorType)
+ {
+ continue;
+ }
+ // This is a same-type connector, find out how to rotate to it:
+ int NumCCWRotations = cPiece::cConnector::GetNumCCWRotationsToFit(a_Connector.m_Direction, itrC->m_Direction);
+ if ((NumCCWRotations < 0) || !(*itrP)->CanRotateCCW(NumCCWRotations))
+ {
+ // Doesn't support this rotation
+ continue;
+ }
+
+ // Check if the piece's VerticalLimit allows this connection:
+ if ((verticalLimit != nullptr) && (!verticalLimit->CanBeAtHeight(ConnPos.x, ConnPos.z, ConnPos.y - itrC->m_Pos.y)))
+ {
+ continue;
+ }
+
+ if (!CheckConnection(a_Connector, ConnPos, **itrP, *itrC, NumCCWRotations, a_OutPieces))
+ {
+ // Doesn't fit in this rotation
+ continue;
+ }
+ // Fits, add it to list of possibile connections:
+ Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations, Weight));
+ WeightTotal += Weight;
+ } // for itrC - Connectors[]
+ } // for itrP - AvailablePieces[]
+ if (Connections.empty())
+ {
+ // No available connections, bail out
+ return false;
+ }
+ ASSERT(WeightTotal > 0);
+
+ // Choose a random connection from the list, based on the weights:
+ int rnd = (m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7) % WeightTotal;
+ size_t ChosenIndex = 0;
+ for (cConnections::const_iterator itr = Connections.begin(), end = Connections.end(); itr != end; ++itr, ++ChosenIndex)
+ {
+ rnd -= itr->m_Weight;
+ if (rnd <= 0)
+ {
+ // This is the piece to choose
+ break;
+ }
+ }
+ cConnection & Conn = Connections[ChosenIndex];
+
+ // Place the piece:
+ Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
+ ConnPos -= NewPos;
+ auto PlacedPiece = cpp14::make_unique<cPlacedPiece>(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations);
+
+ // Add the new piece's connectors to the list of free connectors:
+ cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
+ for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
+ {
+ if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
+ {
+ // This is the connector through which we have been connected to the parent, don't add
+ continue;
+ }
+ a_OutConnectors.push_back(cFreeConnector(PlacedPiece.get(), Conn.m_Piece->RotateMoveConnector(*itr, Conn.m_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z)));
+ }
+ a_OutPieces.push_back(std::move(PlacedPiece));
+
+ return true;
+}
+
+
+
+
+
+bool cPieceGeneratorBFSTree::CheckConnection(
+ const cPiece::cConnector & a_ExistingConnector,
+ const Vector3i & a_ToPos,
+ const cPiece & a_Piece,
+ const cPiece::cConnector & a_NewConnector,
+ int a_NumCCWRotations,
+ const cPlacedPieces & a_OutPieces
+)
+{
+ // For each placed piece, test the hitbox against the new piece:
+ cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ToPos, a_NumCCWRotations);
+ RotatedHitBox.Sort();
+ for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr)
+ {
+ if ((*itr)->GetHitBox().DoesIntersect(RotatedHitBox))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+
+void cPieceGeneratorBFSTree::PlacePieces(int a_BlockX, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces)
+{
+ a_OutPieces.clear();
+ cFreeConnectors ConnectorPool;
+
+ // Place the starting piece:
+ a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockZ, ConnectorPool));
+
+ /*
+ // DEBUG:
+ printf("Placed the starting piece at {%d, %d, %d}\n", a_BlockX, a_BlockY, a_BlockZ);
+ cCuboid Hitbox = a_OutPieces[0]->GetHitBox();
+ Hitbox.Sort();
+ printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ DebugConnectorPool(ConnectorPool, 0);
+ //*/
+
+ // Place pieces at the available connectors:
+ /*
+ Instead of removing them one by one from the pool, we process them sequentially and take note of the last
+ processed one. To save on memory, once the number of processed connectors reaches a big number, a chunk
+ of the connectors is removed.
+ */
+ size_t NumProcessed = 0;
+ while (ConnectorPool.size() > NumProcessed)
+ {
+ cFreeConnector & Conn = ConnectorPool[NumProcessed];
+ if (Conn.m_Piece->GetDepth() < a_MaxDepth)
+ {
+ if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool))
+ {
+ /*
+ // DEBUG:
+ const cPlacedPiece * NewPiece = a_OutPieces.back();
+ const Vector3i & Coords = NewPiece->GetCoords();
+ printf("Placed a new piece at {%d, %d, %d}, rotation %d\n", Coords.x, Coords.y, Coords.z, NewPiece->GetNumCCWRotations());
+ cCuboid Hitbox = NewPiece->GetHitBox();
+ Hitbox.Sort();
+ printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ DebugConnectorPool(ConnectorPool, NumProcessed + 1);
+ //*/
+ }
+ }
+ NumProcessed++;
+ if (NumProcessed > 1000)
+ {
+ typedef cPieceGeneratorBFSTree::cFreeConnectors::difference_type difType;
+ ConnectorPool.erase(ConnectorPool.begin(), ConnectorPool.begin() + static_cast<difType>(NumProcessed));
+ NumProcessed = 0;
+ }
+ }
+}
+
+
+
+
+
+//*
+// DEBUG:
+void cPieceGeneratorBFSTree::DebugConnectorPool(const cPieceGeneratorBFSTree::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed)
+{
+ printf(" Connector pool: " SIZE_T_FMT " items\n", a_ConnectorPool.size() - a_NumProcessed);
+ size_t idx = 0;
+
+ typedef cPieceGeneratorBFSTree::cFreeConnectors::difference_type difType;
+
+ for (auto itr = a_ConnectorPool.cbegin() + static_cast<difType>(a_NumProcessed), end = a_ConnectorPool.cend(); itr != end; ++itr, ++idx)
+ {
+ printf(" " SIZE_T_FMT ": {%d, %d, %d}, type %d, direction %s, depth %d\n",
+ idx,
+ itr->m_Connector.m_Pos.x, itr->m_Connector.m_Pos.y, itr->m_Connector.m_Pos.z,
+ itr->m_Connector.m_Type,
+ cPiece::cConnector::DirectionToString(itr->m_Connector.m_Direction),
+ itr->m_Piece->GetDepth()
+ );
+ } // for itr - a_ConnectorPool[]
+}
+//*/
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cPieceGeneratorBFSTree::cConnection:
+
+cPieceGeneratorBFSTree::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight) :
+ m_Piece(&a_Piece),
+ m_Connector(a_Connector),
+ m_NumCCWRotations(a_NumCCWRotations),
+ m_Weight(a_Weight)
+{
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cPieceGeneratorBFSTree::cFreeConnector:
+
+cPieceGeneratorBFSTree::cFreeConnector::cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector) :
+ m_Piece(a_Piece),
+ m_Connector(a_Connector)
+{
+}
+
+
+
+
diff --git a/src/Generating/PieceGeneratorBFSTree.h b/src/Generating/PieceGeneratorBFSTree.h
new file mode 100644
index 000000000..5efb8a1f4
--- /dev/null
+++ b/src/Generating/PieceGeneratorBFSTree.h
@@ -0,0 +1,102 @@
+
+// PieceGeneratorBFSTree.h
+
+// Declares the cPieceGeneratorBFSTree class for generating structures composed of individual "pieces" in a simple tree
+
+
+
+
+
+#pragma once
+
+#include "ComposableGenerator.h"
+#include "PiecePool.h"
+#include "../Noise/Noise.h"
+
+
+
+
+
+class cPieceGeneratorBFSTree
+{
+public:
+ /** Creates a new object tied to the specified PiecePool, using the specified seed. */
+ cPieceGeneratorBFSTree(cPiecePool & a_PiecePool, int a_Seed);
+
+
+ /** Generates a placement for pieces at the specified coords.
+ The Y coord is generated automatically based on the starting piece that is chosen. */
+ void PlacePieces(int a_BlockX, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces);
+
+
+protected:
+
+ /** The type used for storing a connection from one piece to another, while building the piece tree. */
+ struct cConnection
+ {
+ cPiece * m_Piece; // The piece being connected
+ cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords)
+ int m_NumCCWRotations; // Number of rotations necessary to match the two connectors
+ int m_Weight; // Relative chance that this connection will be chosen
+
+ cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight);
+ };
+ typedef std::vector<cConnection> cConnections;
+
+
+ /** The type used for storing a pool of connectors that will be attempted to expand by another piece. */
+ struct cFreeConnector
+ {
+ cPlacedPiece * m_Piece;
+ cPiece::cConnector m_Connector;
+
+ cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector);
+ };
+ typedef std::vector<cFreeConnector> cFreeConnectors;
+
+
+ /** The pool from which pieces are taken. */
+ cPiecePool & m_PiecePool;
+
+ /** The noise used for random number generation. */
+ cNoise m_Noise;
+
+ /** The seed used by this generator. */
+ int m_Seed;
+
+
+ /** Selects a starting piece and places it, including its height and rotation.
+ Also puts the piece's connectors in a_OutConnectors. */
+ cPlacedPiecePtr PlaceStartingPiece(int a_BlockX, int a_BlockZ, cFreeConnectors & a_OutConnectors);
+
+ /** Tries to place a new piece at the specified (placed) connector. Returns true if successful. */
+ bool TryPlacePieceAtConnector(
+ const cPlacedPiece & a_ParentPiece, // The existing piece to a new piece should be placed
+ const cPiece::cConnector & a_Connector, // The existing connector (world-coords) to which a new piece should be placed
+ cPlacedPieces & a_OutPieces, // Already placed pieces, to be checked for intersections
+ cFreeConnectors & a_OutConnectors // List of free connectors to which the new connectors will be placed
+ );
+
+ /** Checks if the specified piece would fit with the already-placed pieces, using the specified connector
+ and number of CCW rotations.
+ a_ExistingConnector is in world-coords and is already rotated properly
+ a_ToPos is the world-coords position on which the new connector should be placed (1 block away from a_ExistingConnector, in its Direction)
+ a_NewConnector is in the original (non-rotated) coords.
+ Returns true if the piece fits, false if not. */
+ bool CheckConnection(
+ const cPiece::cConnector & a_ExistingConnector, // The existing connector
+ const Vector3i & a_ToPos, // The position on which the new connector should be placed
+ const cPiece & a_Piece, // The new piece
+ const cPiece::cConnector & a_NewConnector, // The connector of the new piece
+ int a_NumCCWRotations, // Number of rotations for the new piece to align the connector
+ const cPlacedPieces & a_OutPieces // All the already-placed pieces to check
+ );
+
+ /** DEBUG: Outputs all the connectors in the pool into stdout.
+ a_NumProcessed signals the number of connectors from the pool that should be considered processed (not listed). */
+ void DebugConnectorPool(const cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed);
+} ;
+
+
+
+
diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PiecePool.cpp
index f8ae1d961..201c70afd 100644
--- a/src/Generating/PieceGenerator.cpp
+++ b/src/Generating/PiecePool.cpp
@@ -1,11 +1,11 @@
+// PiecePool.cpp
-// PieceGenerator.cpp
-
-// Implements the cBFSPieceGenerator class and cDFSPieceGenerator class
-// representing base classes for generating structures composed of individual "pieces"
+// Implements the cPiecePool class representing a pool of cPieces - "parts" of a structure, used in piece-generators
+// A cPiece is a single static part of a structure that can rotate around the Y axis, has connectors to other pieces and knows how to draw itself into the world.
+// The pool manages the pieces and provides lists of its pieces matching criteria, and provides relative weights for the random distribution of pieces.
#include "Globals.h"
-#include "PieceGenerator.h"
+#include "PiecePool.h"
#include "VerticalStrategy.h"
#include "VerticalLimit.h"
@@ -358,6 +358,37 @@ cPiece::cConnector::eDirection cPiece::cConnector::RotateDirectionCW(eDirection
+int cPiece::cConnector::GetNumCCWRotationsToFit(eDirection a_FixedDir, eDirection a_RotatingDir)
+{
+ // Translation of direction - direction -> number of CCW rotations needed:
+ // You need DirectionRotationTable[fixed][rot] CCW turns to connect rot to fixed (they are opposite)
+ // -1 if not possible
+ static const int DirectionRotationTable[14][14] =
+ {
+ /* YM, YP, ZM, ZP, XM, XP, YM-XM-ZM, YM-XM-ZP, YM-XP-ZM, YM-XP-ZP, YP-XM-ZM, YP-XM-ZP, YP-XP-ZM, YP-XP-ZP */
+ /* YM */ { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ /* YP */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ /* ZM */ {-1, -1, 2, 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1},
+ /* ZP */ {-1, -1, 0, 2, 3, 1, -1, -1, -1, -1, -1, -1, -1, -1},
+ /* XM */ {-1, -1, 3, 1, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1},
+ /* XP */ {-1, -1, 1, 3, 0, 2, -1, -1, -1, -1, -1, -1, -1, -1},
+ /* YM-XM-ZM */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 1, 2},
+ /* YM-XM-ZP */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 0, 2, 3},
+ /* YM-XP-ZM */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 2, 0, 1},
+ /* YM-XP-ZP */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 1, 3, 0},
+ /* YP-XM-ZM */ {-1, -1, -1, -1, -1, -1, 0, 3, 1, 2, -1, -1, -1, -1},
+ /* YP-XM-ZP */ {-1, -1, -1, -1, -1, -1, 1, 0, 2, 3, -1, -1, -1, -1},
+ /* YP-XP-ZM */ {-1, -1, -1, -1, -1, -1, 3, 2, 0, 1, -1, -1, -1, -1},
+ /* YP-XP-ZP */ {-1, -1, -1, -1, -1, -1, 2, 1, 3, 0, -1, -1, -1, -1},
+ };
+
+ return DirectionRotationTable[a_FixedDir][a_RotatingDir];
+}
+
+
+
+
+
bool cPiece::cConnector::StringToDirection(const AString & a_Value, eDirection & a_Out)
{
// First try converting as a number:
@@ -470,381 +501,3 @@ void cPlacedPiece::MoveToGroundBy(int a_OffsetY)
-
-////////////////////////////////////////////////////////////////////////////////
-// cPieceGenerator:
-
-cPieceGenerator::cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
- m_PiecePool(a_PiecePool),
- m_Noise(a_Seed),
- m_Seed(a_Seed)
-{
-}
-
-
-
-
-
-void cPieceGenerator::FreePieces(cPlacedPieces & a_PlacedPieces)
-{
- for (cPlacedPieces::iterator itr = a_PlacedPieces.begin(), end = a_PlacedPieces.end(); itr != end; ++itr)
- {
- delete *itr;
- } // for itr - a_PlacedPieces[]
- a_PlacedPieces.clear();
-}
-
-
-
-
-
-cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockZ, cFreeConnectors & a_OutConnectors)
-{
- m_PiecePool.Reset();
- int rnd = m_Noise.IntNoise2DInt(a_BlockX, a_BlockZ) / 7;
-
- // Choose a random one of the starting pieces:
- cPieces StartingPieces = m_PiecePool.GetStartingPieces();
- int Total = 0;
- for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr)
- {
- Total += m_PiecePool.GetStartingPieceWeight(**itr);
- }
- cPiece * StartingPiece;
- if (Total > 0)
- {
- int Chosen = rnd % Total;
- StartingPiece = StartingPieces.front();
- for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr)
- {
- Chosen -= m_PiecePool.GetStartingPieceWeight(**itr);
- if (Chosen <= 0)
- {
- StartingPiece = *itr;
- break;
- }
- }
- }
- else
- {
- // All pieces returned zero weight, but we need one to start. Choose with equal chance:
- StartingPiece = StartingPieces[static_cast<size_t>(rnd) % StartingPieces.size()];
- }
- rnd = rnd >> 16;
-
- // Choose a random supported rotation:
- int Rotations[4] = {0};
- int NumRotations = 1;
- for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++)
- {
- if (StartingPiece->CanRotateCCW(static_cast<int>(i)))
- {
- Rotations[NumRotations] = static_cast<int>(i);
- NumRotations += 1;
- }
- }
- int Rotation = Rotations[rnd % NumRotations];
- int BlockY = StartingPiece->GetStartingPieceHeight(a_BlockX, a_BlockZ);
- ASSERT(BlockY >= 0); // The vertical strategy should have been provided and should give valid coords
-
- cPlacedPiece * res = new cPlacedPiece(nullptr, *StartingPiece, Vector3i(a_BlockX, BlockY, a_BlockZ), Rotation);
-
- // Place the piece's connectors into a_OutConnectors:
- const cPiece::cConnectors & Conn = StartingPiece->GetConnectors();
- for (cPiece::cConnectors::const_iterator itr = Conn.begin(), end = Conn.end(); itr != end; ++itr)
- {
- a_OutConnectors.push_back(
- cFreeConnector(res, StartingPiece->RotateMoveConnector(*itr, Rotation, a_BlockX, BlockY, a_BlockZ))
- );
- }
-
- return res;
-}
-
-
-
-
-
-bool cPieceGenerator::TryPlacePieceAtConnector(
- const cPlacedPiece & a_ParentPiece,
- const cPiece::cConnector & a_Connector,
- cPlacedPieces & a_OutPieces,
- cPieceGenerator::cFreeConnectors & a_OutConnectors
-)
-{
- // Translation of direction - direction -> number of CCW rotations needed:
- // You need DirectionRotationTable[rot2][rot1] CCW turns to connect rot1 to rot2 (they are opposite)
- // -1 if not possible
- static const int DirectionRotationTable[14][14] =
- {
- /* YM, YP, ZM, ZP, XM, XP, YM-XM-ZM, YM-XM-ZP, YM-XP-ZM, YM-XP-ZP, YP-XM-ZM, YP-XM-ZP, YP-XP-ZM, YP-XP-ZP */
- /* YM */ { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- /* YP */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- /* ZM */ {-1, -1, 2, 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1},
- /* ZP */ {-1, -1, 0, 2, 3, 1, -1, -1, -1, -1, -1, -1, -1, -1},
- /* XM */ {-1, -1, 3, 1, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1},
- /* XP */ {-1, -1, 1, 3, 0, 2, -1, -1, -1, -1, -1, -1, -1, -1},
- /* YM-XM-ZM */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 1, 2},
- /* YM-XM-ZP */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 0, 2, 3},
- /* YM-XP-ZM */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 2, 0, 1},
- /* YM-XP-ZP */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 1, 3, 0},
- /* YP-XM-ZM */ {-1, -1, -1, -1, -1, -1, 0, 3, 1, 2, -1, -1, -1, -1},
- /* YP-XM-ZP */ {-1, -1, -1, -1, -1, -1, 1, 0, 2, 3, -1, -1, -1, -1},
- /* YP-XP-ZM */ {-1, -1, -1, -1, -1, -1, 3, 2, 0, 1, -1, -1, -1, -1},
- /* YP-XP-ZP */ {-1, -1, -1, -1, -1, -1, 2, 1, 3, 0, -1, -1, -1, -1},
- };
-
- // Get a list of available connections:
- ASSERT(a_Connector.m_Direction < ARRAYCOUNT(DirectionRotationTable));
- const int * RotTable = DirectionRotationTable[a_Connector.m_Direction];
- cConnections Connections;
- int WantedConnectorType = -a_Connector.m_Type;
- cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(WantedConnectorType);
- Connections.reserve(AvailablePieces.size());
- Vector3i ConnPos = cPiece::cConnector::AddDirection(a_Connector.m_Pos, a_Connector.m_Direction); // The position at which the new connector should be placed - 1 block away from the current connector
- int WeightTotal = 0;
- for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP)
- {
- // Get the relative chance of this piece being generated in this path:
- int Weight = m_PiecePool.GetPieceWeight(a_ParentPiece, a_Connector, **itrP);
- if (Weight <= 0)
- {
- continue;
- }
-
- // Try fitting each of the piece's connector:
- cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
- auto verticalLimit = (*itrP)->GetVerticalLimit();
- for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC)
- {
- if (itrC->m_Type != WantedConnectorType)
- {
- continue;
- }
- // This is a same-type connector, find out how to rotate to it:
- ASSERT(itrC->m_Direction < ARRAYCOUNT(DirectionRotationTable[0]));
- int NumCCWRotations = RotTable[itrC->m_Direction];
- if ((NumCCWRotations < 0) || !(*itrP)->CanRotateCCW(NumCCWRotations))
- {
- // Doesn't support this rotation
- continue;
- }
-
- // Check if the piece's VerticalLimit allows this connection:
- if ((verticalLimit != nullptr) && (!verticalLimit->CanBeAtHeight(ConnPos.x, ConnPos.z, ConnPos.y - itrC->m_Pos.y)))
- {
- continue;
- }
-
- if (!CheckConnection(a_Connector, ConnPos, **itrP, *itrC, NumCCWRotations, a_OutPieces))
- {
- // Doesn't fit in this rotation
- continue;
- }
- // Fits, add it to list of possibile connections:
- Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations, Weight));
- WeightTotal += Weight;
- } // for itrC - Connectors[]
- } // for itrP - AvailablePieces[]
- if (Connections.empty())
- {
- // No available connections, bail out
- return false;
- }
- ASSERT(WeightTotal > 0);
-
- // Choose a random connection from the list, based on the weights:
- int rnd = (m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7) % WeightTotal;
- size_t ChosenIndex = 0;
- for (cConnections::const_iterator itr = Connections.begin(), end = Connections.end(); itr != end; ++itr, ++ChosenIndex)
- {
- rnd -= itr->m_Weight;
- if (rnd <= 0)
- {
- // This is the piece to choose
- break;
- }
- }
- cConnection & Conn = Connections[ChosenIndex];
-
- // Place the piece:
- Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
- ConnPos -= NewPos;
- cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations);
- a_OutPieces.push_back(PlacedPiece);
-
- // Add the new piece's connectors to the list of free connectors:
- cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
- for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
- {
- if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
- {
- // This is the connector through which we have been connected to the parent, don't add
- continue;
- }
- a_OutConnectors.push_back(cFreeConnector(PlacedPiece, Conn.m_Piece->RotateMoveConnector(*itr, Conn.m_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z)));
- }
-
- return true;
-}
-
-
-
-
-
-bool cPieceGenerator::CheckConnection(
- const cPiece::cConnector & a_ExistingConnector,
- const Vector3i & a_ToPos,
- const cPiece & a_Piece,
- const cPiece::cConnector & a_NewConnector,
- int a_NumCCWRotations,
- const cPlacedPieces & a_OutPieces
-)
-{
- // For each placed piece, test the hitbox against the new piece:
- cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ToPos, a_NumCCWRotations);
- RotatedHitBox.Sort();
- for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr)
- {
- if ((*itr)->GetHitBox().DoesIntersect(RotatedHitBox))
- {
- return false;
- }
- }
- return true;
-}
-
-
-
-
-
-//*
-// DEBUG:
-void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed)
-{
- printf(" Connector pool: " SIZE_T_FMT " items\n", a_ConnectorPool.size() - a_NumProcessed);
- size_t idx = 0;
-
- typedef cPieceGenerator::cFreeConnectors::difference_type difType;
-
- for (auto itr = a_ConnectorPool.cbegin() + static_cast<difType>(a_NumProcessed), end = a_ConnectorPool.cend(); itr != end; ++itr, ++idx)
- {
- printf(" " SIZE_T_FMT ": {%d, %d, %d}, type %d, direction %s, depth %d\n",
- idx,
- itr->m_Connector.m_Pos.x, itr->m_Connector.m_Pos.y, itr->m_Connector.m_Pos.z,
- itr->m_Connector.m_Type,
- cPiece::cConnector::DirectionToString(itr->m_Connector.m_Direction),
- itr->m_Piece->GetDepth()
- );
- } // for itr - a_ConnectorPool[]
-}
-//*/
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cPieceGenerator::cConnection:
-
-cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight) :
- m_Piece(&a_Piece),
- m_Connector(a_Connector),
- m_NumCCWRotations(a_NumCCWRotations),
- m_Weight(a_Weight)
-{
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cPieceGenerator::cFreeConnector:
-
-cPieceGenerator::cFreeConnector::cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector) :
- m_Piece(a_Piece),
- m_Connector(a_Connector)
-{
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cBFSPieceGenerator:
-
-cBFSPieceGenerator::cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
- super(a_PiecePool, a_Seed)
-{
-}
-
-
-
-
-
-void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces)
-{
- a_OutPieces.clear();
- cFreeConnectors ConnectorPool;
-
- // Place the starting piece:
- a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockZ, ConnectorPool));
-
- /*
- // DEBUG:
- printf("Placed the starting piece at {%d, %d, %d}\n", a_BlockX, a_BlockY, a_BlockZ);
- cCuboid Hitbox = a_OutPieces[0]->GetHitBox();
- Hitbox.Sort();
- printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
- Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
- Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
- Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
- );
- DebugConnectorPool(ConnectorPool, 0);
- //*/
-
- // Place pieces at the available connectors:
- /*
- Instead of removing them one by one from the pool, we process them sequentially and take note of the last
- processed one. To save on memory, once the number of processed connectors reaches a big number, a chunk
- of the connectors is removed.
- */
- size_t NumProcessed = 0;
- while (ConnectorPool.size() > NumProcessed)
- {
- cFreeConnector & Conn = ConnectorPool[NumProcessed];
- if (Conn.m_Piece->GetDepth() < a_MaxDepth)
- {
- if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool))
- {
- /*
- // DEBUG:
- const cPlacedPiece * NewPiece = a_OutPieces.back();
- const Vector3i & Coords = NewPiece->GetCoords();
- printf("Placed a new piece at {%d, %d, %d}, rotation %d\n", Coords.x, Coords.y, Coords.z, NewPiece->GetNumCCWRotations());
- cCuboid Hitbox = NewPiece->GetHitBox();
- Hitbox.Sort();
- printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
- Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
- Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
- Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
- );
- DebugConnectorPool(ConnectorPool, NumProcessed + 1);
- //*/
- }
- }
- NumProcessed++;
- if (NumProcessed > 1000)
- {
- typedef cPieceGenerator::cFreeConnectors::difference_type difType;
- ConnectorPool.erase(ConnectorPool.begin(), ConnectorPool.begin() + static_cast<difType>(NumProcessed));
- NumProcessed = 0;
- }
- }
-}
-
-
-
-
diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PiecePool.h
index 1900d9d02..84f511950 100644
--- a/src/Generating/PieceGenerator.h
+++ b/src/Generating/PiecePool.h
@@ -1,16 +1,6 @@
+// PiecePool.h
-// PieceGenerator.h
-
-// Declares the cBFSPieceGenerator class and cDFSPieceGenerator class
-// representing base classes for generating structures composed of individual "pieces"
-
-/*
-Each uses a slightly different approach to generating:
- - DFS extends pieces one by one until it hits the configured depth (or can't connect another piece anymore),
- then starts looking at adjacent connectors (like depth-first search).
- - BFS keeps a pool of currently-open connectors, chooses one at random and tries to place a piece on it,
- thus possibly extending the pool of open connectors (like breadth-first search).
-*/
+// Declares the cPiecePool class representing a pool of cPieces - "parts" of a structure, used in piece-generators
@@ -21,7 +11,6 @@ Each uses a slightly different approach to generating:
#include "ComposableGenerator.h"
#include "../Defines.h"
#include "../Cuboid.h"
-#include "../Noise/Noise.h"
@@ -91,6 +80,12 @@ public:
/** 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+". */
@@ -229,7 +224,6 @@ typedef std::vector<cPiece *> cPieces;
-
// fwd:
class cPlacedPiece;
@@ -237,8 +231,9 @@ class cPlacedPiece;
-/** This class is an interface that provides pieces for the generator. It can keep track of what pieces were
-placed and adjust the returned piece vectors. */
+/** 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:
@@ -331,116 +326,10 @@ protected:
bool m_HasBeenMovedToGround;
};
-typedef std::vector<cPlacedPiece *> cPlacedPieces;
-
-
-
-
-
-class cPieceGenerator
-{
-public:
- cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
-
- /** Cleans up all the memory used by the placed pieces.
- Call this utility function instead of freeing the items on your own. */
- static void FreePieces(cPlacedPieces & a_PlacedPieces);
-
-protected:
- /** The type used for storing a connection from one piece to another, while building the piece tree. */
- struct cConnection
- {
- cPiece * m_Piece; // The piece being connected
- cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords)
- int m_NumCCWRotations; // Number of rotations necessary to match the two connectors
- int m_Weight; // Relative chance that this connection will be chosen
-
- cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight);
- };
- typedef std::vector<cConnection> cConnections;
-
- /** The type used for storing a pool of connectors that will be attempted to expand by another piece. */
- struct cFreeConnector
- {
- cPlacedPiece * m_Piece;
- cPiece::cConnector m_Connector;
-
- cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector);
- };
- typedef std::vector<cFreeConnector> cFreeConnectors;
-
-
- cPiecePool & m_PiecePool;
- cNoise m_Noise;
- int m_Seed;
-
-
- /** Selects a starting piece and places it, including its height and rotation.
- Also puts the piece's connectors in a_OutConnectors. */
- cPlacedPiece * PlaceStartingPiece(int a_BlockX, int a_BlockZ, cFreeConnectors & a_OutConnectors);
-
- /** Tries to place a new piece at the specified (placed) connector. Returns true if successful. */
- bool TryPlacePieceAtConnector(
- const cPlacedPiece & a_ParentPiece, // The existing piece to a new piece should be placed
- const cPiece::cConnector & a_Connector, // The existing connector (world-coords) to which a new piece should be placed
- cPlacedPieces & a_OutPieces, // Already placed pieces, to be checked for intersections
- cFreeConnectors & a_OutConnectors // List of free connectors to which the new connectors will be placed
- );
-
- /** Checks if the specified piece would fit with the already-placed pieces, using the specified connector
- and number of CCW rotations.
- a_ExistingConnector is in world-coords and is already rotated properly
- a_ToPos is the world-coords position on which the new connector should be placed (1 block away from a_ExistingConnector, in its Direction)
- a_NewConnector is in the original (non-rotated) coords.
- Returns true if the piece fits, false if not. */
- bool CheckConnection(
- const cPiece::cConnector & a_ExistingConnector, // The existing connector
- const Vector3i & a_ToPos, // The position on which the new connector should be placed
- const cPiece & a_Piece, // The new piece
- const cPiece::cConnector & a_NewConnector, // The connector of the new piece
- int a_NumCCWRotations, // Number of rotations for the new piece to align the connector
- const cPlacedPieces & a_OutPieces // All the already-placed pieces to check
- );
-
- /** DEBUG: Outputs all the connectors in the pool into stdout.
- a_NumProcessed signals the number of connectors from the pool that should be considered processed (not listed). */
- void DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed);
-} ;
-
-
-
-
-
-class cBFSPieceGenerator :
- public cPieceGenerator
-{
- typedef cPieceGenerator super;
-
-public:
- cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
-
- /** Generates a placement for pieces at the specified coords.
- The Y coord is generated automatically based on the starting piece that is chosen.
- Caller must free each individual cPlacedPiece in a_OutPieces using cPieceGenerator::FreePieces(). */
- void PlacePieces(int a_BlockX, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces);
-};
-
-
-
+typedef std::unique_ptr<cPlacedPiece> cPlacedPiecePtr;
+typedef std::vector<cPlacedPiecePtr> cPlacedPieces;
-class cDFSPieceGenerator :
- public cPieceGenerator
-{
-public:
- cDFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
-
- /** Generates a placement for pieces at the specified coords.
- The Y coord is generated automatically based on the starting piece that is chosen.
- Caller must free each individual cPlacedPiece in a_OutPieces using cPieceGenerator::FreePieces(). */
- void PlacePieces(int a_BlockX, int a_BlockZ, cPlacedPieces & a_OutPieces);
-};
-
diff --git a/src/Generating/PieceStructuresGen.cpp b/src/Generating/PieceStructuresGen.cpp
index e35048cb0..c8630fa13 100644
--- a/src/Generating/PieceStructuresGen.cpp
+++ b/src/Generating/PieceStructuresGen.cpp
@@ -6,6 +6,7 @@
#include "Globals.h"
#include "PieceStructuresGen.h"
#include "PrefabStructure.h"
+#include "PieceGeneratorBFSTree.h"
#include "IniFile.h"
#include "../Stopwatch.h"
@@ -14,6 +15,114 @@
+class cPieceStructuresGen::cGen:
+ public cGridStructGen
+{
+ typedef cGridStructGen Super;
+
+public:
+ cGen(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen, int a_SeaLevel, const AString & a_Name):
+ Super(a_Seed),
+ m_BiomeGen(a_BiomeGen),
+ m_HeightGen(a_HeightGen),
+ m_SeaLevel(a_SeaLevel),
+ m_Name(a_Name),
+ m_MaxDepth(5)
+ {
+ }
+
+
+
+ /** Loads the piecepool from a file.
+ Returns true on success, logs warning and returns false on failure. */
+ bool LoadFromFile(const AString & a_FileName)
+ {
+ // Load the piecepool from the file, log any warnings:
+ if (!m_PiecePool.LoadFromFile(a_FileName, true))
+ {
+ return false;
+ }
+ if (NoCaseCompare(m_PiecePool.GetIntendedUse(), "PieceStructures") != 0)
+ {
+ LOGWARNING("PieceStructures generator: File %s is intended for use in \"%s\", rather than piece structures. Loading the file, but the generator may behave unexpectedly.",
+ a_FileName.c_str(), m_PiecePool.GetIntendedUse().c_str()
+ );
+ }
+ m_PiecePool.AssignGens(m_Seed, m_BiomeGen, m_HeightGen, m_SeaLevel);
+
+ // Apply generator params from the piecepool (in the metadata) into the generator:
+ auto & generatorParams = m_PiecePool.GetAllMetadata();
+ SetGeneratorParams(generatorParams);
+ m_MaxDepth = GetStringMapInteger<int>(generatorParams, "MaxDepth", m_MaxDepth);
+
+ return true;
+ }
+
+
+
+ // cGridStructGen overrides:
+ virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override
+ {
+ cStopwatch sw(Printf("CreateStructure for %s at <%d, %d>", m_Name.c_str(), a_GridX, a_GridZ));
+ cPlacedPieces outPieces;
+ cPieceGeneratorBFSTree pg(m_PiecePool, m_Seed);
+ pg.PlacePieces(a_OriginX, a_OriginZ, m_MaxDepth, outPieces);
+ return std::make_shared<cPrefabStructure>(a_GridX, a_GridZ, a_OriginX, a_OriginZ, std::move(outPieces), m_HeightGen);
+ }
+
+
+protected:
+
+ /** The type used for storing a connection from one piece to another, while building the piece tree. */
+ struct cConnection
+ {
+ cPiece * m_Piece; // The piece being connected
+ cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords)
+ int m_NumCCWRotations; // Number of rotations necessary to match the two connectors
+ int m_Weight; // Relative chance that this connection will be chosen
+
+ cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight);
+ };
+ typedef std::vector<cConnection> cConnections;
+
+
+ /** The type used for storing a pool of connectors that will be attempted to expand by another piece. */
+ struct cFreeConnector
+ {
+ cPlacedPiece * m_Piece;
+ cPiece::cConnector m_Connector;
+
+ cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector);
+ };
+ typedef std::vector<cFreeConnector> cFreeConnectors;
+
+ /** The underlying biome generator that defines whether the structure is created or not */
+ cBiomeGenPtr m_BiomeGen;
+
+ /** The underlying height generator, used to position the prefabs crossing chunk borders if they are set to FitGround. */
+ cTerrainHeightGenPtr m_HeightGen;
+
+ /** The world's sea level, if available. Used for some cVerticalStrategy descendants. */
+ int m_SeaLevel;
+
+ /** The name that is used for reporting. */
+ AString m_Name;
+
+ /** All available prefabs. */
+ cPrefabPiecePool m_PiecePool;
+
+ /** Maximum depth of the generated piece tree. */
+ int m_MaxDepth;
+};
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cPieceStructuresGen:
+
cPieceStructuresGen::cPieceStructuresGen(int a_Seed):
m_Seed(a_Seed)
{
@@ -71,59 +180,3 @@ void cPieceStructuresGen::GenFinish(cChunkDesc & a_Chunk)
-////////////////////////////////////////////////////////////////////////////////
-// cPieceStructuresGen::cGen:
-
-cPieceStructuresGen::cGen::cGen(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen, int a_SeaLevel, const AString & a_Name):
- Super(a_Seed),
- m_BiomeGen(a_BiomeGen),
- m_HeightGen(a_HeightGen),
- m_SeaLevel(a_SeaLevel),
- m_Name(a_Name),
- m_MaxDepth(5)
-{
-}
-
-
-
-
-
-bool cPieceStructuresGen::cGen::LoadFromFile(const AString & a_FileName)
-{
- // Load the piecepool from the file, log any warnings:
- if (!m_Pool.LoadFromFile(a_FileName, true))
- {
- return false;
- }
- if (NoCaseCompare(m_Pool.GetIntendedUse(), "PieceStructures") != 0)
- {
- LOGWARNING("PieceStructures generator: File %s is intended for use in \"%s\", rather than piece structures. Loading the file, but the generator may behave unexpectedly.",
- a_FileName.c_str(), m_Pool.GetIntendedUse().c_str()
- );
- }
- m_Pool.AssignGens(m_Seed, m_BiomeGen, m_HeightGen, m_SeaLevel);
-
- // Apply generator params from the piecepool (in the metadata) into the generator:
- auto & generatorParams = m_Pool.GetAllMetadata();
- SetGeneratorParams(generatorParams);
- m_MaxDepth = GetStringMapInteger<int>(generatorParams, "MaxDepth", m_MaxDepth);
-
- return true;
-}
-
-
-
-
-
-cGridStructGen::cStructurePtr cPieceStructuresGen::cGen::CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ)
-{
- cStopwatch sw(Printf("CreateStructure for %s at <%d, %d>", m_Name.c_str(), a_GridX, a_GridZ));
- cBFSPieceGenerator pg(m_Pool, m_Seed);
- cPlacedPieces outPieces;
- pg.PlacePieces(a_OriginX, a_OriginZ, m_MaxDepth, outPieces);
- return std::make_shared<cPrefabStructure>(a_GridX, a_GridZ, a_OriginX, a_OriginZ, outPieces, m_HeightGen);
-}
-
-
-
-
diff --git a/src/Generating/PieceStructuresGen.h b/src/Generating/PieceStructuresGen.h
index c8e2f2b0c..0e36fe9d5 100644
--- a/src/Generating/PieceStructuresGen.h
+++ b/src/Generating/PieceStructuresGen.h
@@ -40,40 +40,9 @@ public:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
protected:
- class cGen:
- public cGridStructGen
- {
- typedef cGridStructGen Super;
- public:
- cGen(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen, int a_SeaLevel, const AString & a_Name);
-
- /** Loads the piecepool from a file.
- Returns true on success, logs warning and returns false on failure. */
- bool LoadFromFile(const AString & a_FileName);
-
- // cGridStructGen overrides:
- virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override;
-
- protected:
-
- /** The underlying biome generator that defines whether the structure is created or not */
- cBiomeGenPtr m_BiomeGen;
-
- /** The underlying height generator, used to position the prefabs crossing chunk borders if they are set to FitGround. */
- cTerrainHeightGenPtr m_HeightGen;
-
- /** The world's sea level, if available. Used for some cVerticalStrategy descendants. */
- int m_SeaLevel;
-
- /** The name that is used for reporting. */
- AString m_Name;
-
- /** All available prefabs. */
- cPrefabPiecePool m_Pool;
-
- /** Maximum depth of the generated piece tree. */
- int m_MaxDepth;
- };
+ /** The generator doing the work for a single prefab set.
+ Forward-declared so that its implementation changes don't affect the header. */
+ class cGen;
typedef SharedPtr<cGen> cGenPtr;
typedef std::vector<cGenPtr> cGenPtrs;
diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h
index 59b80a8a8..6cec8caa0 100644
--- a/src/Generating/Prefab.h
+++ b/src/Generating/Prefab.h
@@ -14,7 +14,7 @@ declared in this file as well; the Gallery server exports areas in this format.
#pragma once
-#include "PieceGenerator.h"
+#include "PiecePool.h"
#include "../BlockArea.h"
diff --git a/src/Generating/PrefabPiecePool.h b/src/Generating/PrefabPiecePool.h
index af342f023..ff0446b56 100644
--- a/src/Generating/PrefabPiecePool.h
+++ b/src/Generating/PrefabPiecePool.h
@@ -10,7 +10,7 @@
#pragma once
#include <unordered_set>
-#include "PieceGenerator.h"
+#include "PiecePool.h"
#include "Prefab.h"
diff --git a/src/Generating/PrefabStructure.cpp b/src/Generating/PrefabStructure.cpp
index 3ebbe8143..c37398be9 100644
--- a/src/Generating/PrefabStructure.cpp
+++ b/src/Generating/PrefabStructure.cpp
@@ -14,11 +14,11 @@
cPrefabStructure::cPrefabStructure(
int a_GridX, int a_GridZ,
int a_OriginX, int a_OriginZ,
- cPlacedPieces & a_Pieces,
+ cPlacedPieces && a_Pieces,
cTerrainHeightGenPtr a_HeightGen
):
Super(a_GridX, a_GridZ, a_OriginX, a_OriginZ),
- m_Pieces(a_Pieces),
+ m_Pieces(std::move(a_Pieces)),
m_HeightGen(a_HeightGen)
{
}
@@ -27,15 +27,6 @@ cPrefabStructure::cPrefabStructure(
-cPrefabStructure::~cPrefabStructure()
-{
- cPieceGenerator::FreePieces(m_Pieces);
-}
-
-
-
-
-
void cPrefabStructure::DrawIntoChunk(cChunkDesc & a_Chunk)
{
// Iterate over all items
@@ -47,7 +38,7 @@ void cPrefabStructure::DrawIntoChunk(cChunkDesc & a_Chunk)
{
PlacePieceOnGround(**itr);
}
- Prefab.Draw(a_Chunk, *itr);
+ Prefab.Draw(a_Chunk, itr->get());
} // for itr - m_PlacedPieces[]
}
diff --git a/src/Generating/PrefabStructure.h b/src/Generating/PrefabStructure.h
index 29a506494..423408396 100644
--- a/src/Generating/PrefabStructure.h
+++ b/src/Generating/PrefabStructure.h
@@ -10,7 +10,7 @@
#pragma once
#include "GridStructGen.h"
-#include "PieceGenerator.h"
+#include "PiecePool.h"
@@ -25,12 +25,10 @@ public:
cPrefabStructure(
int a_GridX, int a_GridZ,
int a_OriginX, int a_OriginZ,
- cPlacedPieces & a_Pieces,
+ cPlacedPieces && a_Pieces,
cTerrainHeightGenPtr a_HeightGen
);
- virtual ~cPrefabStructure();
-
protected:
/** The pieces placed by the generator. */
cPlacedPieces m_Pieces;
diff --git a/src/Generating/VerticalLimit.h b/src/Generating/VerticalLimit.h
index 0e36424ac..aeb41c1e8 100644
--- a/src/Generating/VerticalLimit.h
+++ b/src/Generating/VerticalLimit.h
@@ -9,7 +9,7 @@
#pragma once
-#include "PieceGenerator.h"
+#include "PiecePool.h"
diff --git a/src/Generating/VerticalStrategy.cpp b/src/Generating/VerticalStrategy.cpp
index 08af5b272..4021dc4bb 100644
--- a/src/Generating/VerticalStrategy.cpp
+++ b/src/Generating/VerticalStrategy.cpp
@@ -5,6 +5,7 @@
#include "Globals.h"
#include "VerticalStrategy.h"
+#include "../Noise/Noise.h"
diff --git a/src/Generating/VerticalStrategy.h b/src/Generating/VerticalStrategy.h
index 77e86f660..d42f85d4b 100644
--- a/src/Generating/VerticalStrategy.h
+++ b/src/Generating/VerticalStrategy.h
@@ -9,7 +9,7 @@
#pragma once
-#include "PieceGenerator.h"
+#include "PiecePool.h"
diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp
index 6d5216a16..11617c9ec 100644
--- a/src/Generating/VillageGen.cpp
+++ b/src/Generating/VillageGen.cpp
@@ -5,7 +5,7 @@
#include "Globals.h"
#include "VillageGen.h"
-#include "PieceGenerator.h"
+#include "PieceGeneratorBFSTree.h"
@@ -133,7 +133,7 @@ public:
m_HeightGen(a_HeightGen)
{
// Generate the pieces for this village; don't care about the Y coord:
- cBFSPieceGenerator pg(*this, a_Seed);
+ cPieceGeneratorBFSTree pg(*this, a_Seed);
pg.PlacePieces(a_OriginX, a_OriginZ, a_MaxRoadDepth + 1, m_Pieces);
if (m_Pieces.empty())
{
@@ -141,10 +141,6 @@ public:
}
}
- ~cVillage()
- {
- cPieceGenerator::FreePieces(m_Pieces);
- }
protected:
/** Seed for the random functions */
@@ -193,7 +189,7 @@ protected:
{
PlacePieceOnGround(**itr);
}
- Prefab.Draw(a_Chunk, *itr);
+ Prefab.Draw(a_Chunk, itr->get());
} // for itr - m_PlacedPieces[]
}
@@ -304,11 +300,11 @@ protected:
void MoveAllDescendants(cPlacedPieces & a_PlacedPieces, size_t a_Pivot, int a_HeightDifference)
{
size_t num = a_PlacedPieces.size();
- cPlacedPiece * Pivot = a_PlacedPieces[a_Pivot];
+ auto & Pivot = a_PlacedPieces[a_Pivot];
for (size_t i = a_Pivot + 1; i < num; i++)
{
if (
- (a_PlacedPieces[i]->GetParent() == Pivot) && // It is a direct dependant of the pivot
+ (a_PlacedPieces[i]->GetParent() == Pivot.get()) && // It is a direct dependant of the pivot
!(static_cast<const cPrefab &>(a_PlacedPieces[i]->GetPiece())).ShouldMoveToGround() // It attaches strictly by connectors
)
{