Gen: Moved PiecePool into a separate file.
Also rewritten the PieceGenerator to use std::unique_ptr.
This commit is contained in:
parent
f709f74aeb
commit
187abe3f5e
@ -18,7 +18,8 @@ SET (SRCS
|
|||||||
HeiGen.cpp
|
HeiGen.cpp
|
||||||
MineShafts.cpp
|
MineShafts.cpp
|
||||||
Noise3DGenerator.cpp
|
Noise3DGenerator.cpp
|
||||||
PieceGenerator.cpp
|
PieceGeneratorBFSTree.cpp
|
||||||
|
PiecePool.cpp
|
||||||
PieceStructuresGen.cpp
|
PieceStructuresGen.cpp
|
||||||
Prefab.cpp
|
Prefab.cpp
|
||||||
PrefabPiecePool.cpp
|
PrefabPiecePool.cpp
|
||||||
@ -51,7 +52,8 @@ SET (HDRS
|
|||||||
IntGen.h
|
IntGen.h
|
||||||
MineShafts.h
|
MineShafts.h
|
||||||
Noise3DGenerator.h
|
Noise3DGenerator.h
|
||||||
PieceGenerator.h
|
PieceGeneratorBFSTree.h
|
||||||
|
PiecePool.h
|
||||||
PieceStructuresGen.h
|
PieceStructuresGen.h
|
||||||
Prefab.h
|
Prefab.h
|
||||||
PrefabPiecePool.h
|
PrefabPiecePool.h
|
||||||
|
345
src/Generating/PieceGeneratorBFSTree.cpp
Normal file
345
src/Generating/PieceGeneratorBFSTree.cpp
Normal file
@ -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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
102
src/Generating/PieceGeneratorBFSTree.h
Normal file
102
src/Generating/PieceGeneratorBFSTree.h
Normal file
@ -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);
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
|||||||
|
// PiecePool.cpp
|
||||||
|
|
||||||
// PieceGenerator.cpp
|
// 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.
|
||||||
// Implements the cBFSPieceGenerator class and cDFSPieceGenerator class
|
// The pool manages the pieces and provides lists of its pieces matching criteria, and provides relative weights for the random distribution of pieces.
|
||||||
// representing base classes for generating structures composed of individual "pieces"
|
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "PieceGenerator.h"
|
#include "PiecePool.h"
|
||||||
#include "VerticalStrategy.h"
|
#include "VerticalStrategy.h"
|
||||||
#include "VerticalLimit.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)
|
bool cPiece::cConnector::StringToDirection(const AString & a_Value, eDirection & a_Out)
|
||||||
{
|
{
|
||||||
// First try converting as a number:
|
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,16 +1,6 @@
|
|||||||
|
// PiecePool.h
|
||||||
|
|
||||||
// PieceGenerator.h
|
// Declares the cPiecePool class representing a pool of cPieces - "parts" of a structure, used in piece-generators
|
||||||
|
|
||||||
// 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).
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -21,7 +11,6 @@ Each uses a slightly different approach to generating:
|
|||||||
#include "ComposableGenerator.h"
|
#include "ComposableGenerator.h"
|
||||||
#include "../Defines.h"
|
#include "../Defines.h"
|
||||||
#include "../Cuboid.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. */
|
/** Returns the direction corresponding to the given direction rotated 90 degrees CW around the Y axis. */
|
||||||
static eDirection RotateDirectionCW(eDirection a_Direction);
|
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.
|
/** Converts the string representation of a direction into the eDirection enum value.
|
||||||
Returns true if successful, false on failure.
|
Returns true if successful, false on failure.
|
||||||
Accepts both numbers and string representations such as "x+" or "Y+X-Z+". */
|
Accepts both numbers and string representations such as "x+" or "Y+X-Z+". */
|
||||||
@ -229,7 +224,6 @@ typedef std::vector<cPiece *> cPieces;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fwd:
|
// fwd:
|
||||||
class cPlacedPiece;
|
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
|
/** This class is an interface that stores pieces for a generator.
|
||||||
placed and adjust the returned piece vectors. */
|
Provides lists of pieces based on criteria (IsStarting, HasConnector).
|
||||||
|
Provides per-piece weights for random distribution of individual pieces. */
|
||||||
class cPiecePool
|
class cPiecePool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -331,116 +326,10 @@ protected:
|
|||||||
bool m_HasBeenMovedToGround;
|
bool m_HasBeenMovedToGround;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<cPlacedPiece *> cPlacedPieces;
|
typedef std::unique_ptr<cPlacedPiece> cPlacedPiecePtr;
|
||||||
|
typedef std::vector<cPlacedPiecePtr> 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);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "PieceStructuresGen.h"
|
#include "PieceStructuresGen.h"
|
||||||
#include "PrefabStructure.h"
|
#include "PrefabStructure.h"
|
||||||
|
#include "PieceGeneratorBFSTree.h"
|
||||||
#include "IniFile.h"
|
#include "IniFile.h"
|
||||||
#include "../Stopwatch.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):
|
cPieceStructuresGen::cPieceStructuresGen(int a_Seed):
|
||||||
m_Seed(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,40 +40,9 @@ public:
|
|||||||
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
|
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class cGen:
|
/** The generator doing the work for a single prefab set.
|
||||||
public cGridStructGen
|
Forward-declared so that its implementation changes don't affect the header. */
|
||||||
{
|
class cGen;
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef SharedPtr<cGen> cGenPtr;
|
typedef SharedPtr<cGen> cGenPtr;
|
||||||
typedef std::vector<cGenPtr> cGenPtrs;
|
typedef std::vector<cGenPtr> cGenPtrs;
|
||||||
|
@ -14,7 +14,7 @@ declared in this file as well; the Gallery server exports areas in this format.
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "PieceGenerator.h"
|
#include "PiecePool.h"
|
||||||
#include "../BlockArea.h"
|
#include "../BlockArea.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include "PieceGenerator.h"
|
#include "PiecePool.h"
|
||||||
#include "Prefab.h"
|
#include "Prefab.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
cPrefabStructure::cPrefabStructure(
|
cPrefabStructure::cPrefabStructure(
|
||||||
int a_GridX, int a_GridZ,
|
int a_GridX, int a_GridZ,
|
||||||
int a_OriginX, int a_OriginZ,
|
int a_OriginX, int a_OriginZ,
|
||||||
cPlacedPieces & a_Pieces,
|
cPlacedPieces && a_Pieces,
|
||||||
cTerrainHeightGenPtr a_HeightGen
|
cTerrainHeightGenPtr a_HeightGen
|
||||||
):
|
):
|
||||||
Super(a_GridX, a_GridZ, a_OriginX, a_OriginZ),
|
Super(a_GridX, a_GridZ, a_OriginX, a_OriginZ),
|
||||||
m_Pieces(a_Pieces),
|
m_Pieces(std::move(a_Pieces)),
|
||||||
m_HeightGen(a_HeightGen)
|
m_HeightGen(a_HeightGen)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -27,15 +27,6 @@ cPrefabStructure::cPrefabStructure(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
cPrefabStructure::~cPrefabStructure()
|
|
||||||
{
|
|
||||||
cPieceGenerator::FreePieces(m_Pieces);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPrefabStructure::DrawIntoChunk(cChunkDesc & a_Chunk)
|
void cPrefabStructure::DrawIntoChunk(cChunkDesc & a_Chunk)
|
||||||
{
|
{
|
||||||
// Iterate over all items
|
// Iterate over all items
|
||||||
@ -47,7 +38,7 @@ void cPrefabStructure::DrawIntoChunk(cChunkDesc & a_Chunk)
|
|||||||
{
|
{
|
||||||
PlacePieceOnGround(**itr);
|
PlacePieceOnGround(**itr);
|
||||||
}
|
}
|
||||||
Prefab.Draw(a_Chunk, *itr);
|
Prefab.Draw(a_Chunk, itr->get());
|
||||||
} // for itr - m_PlacedPieces[]
|
} // for itr - m_PlacedPieces[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "GridStructGen.h"
|
#include "GridStructGen.h"
|
||||||
#include "PieceGenerator.h"
|
#include "PiecePool.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -25,12 +25,10 @@ public:
|
|||||||
cPrefabStructure(
|
cPrefabStructure(
|
||||||
int a_GridX, int a_GridZ,
|
int a_GridX, int a_GridZ,
|
||||||
int a_OriginX, int a_OriginZ,
|
int a_OriginX, int a_OriginZ,
|
||||||
cPlacedPieces & a_Pieces,
|
cPlacedPieces && a_Pieces,
|
||||||
cTerrainHeightGenPtr a_HeightGen
|
cTerrainHeightGenPtr a_HeightGen
|
||||||
);
|
);
|
||||||
|
|
||||||
virtual ~cPrefabStructure();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** The pieces placed by the generator. */
|
/** The pieces placed by the generator. */
|
||||||
cPlacedPieces m_Pieces;
|
cPlacedPieces m_Pieces;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "PieceGenerator.h"
|
#include "PiecePool.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "VerticalStrategy.h"
|
#include "VerticalStrategy.h"
|
||||||
|
#include "../Noise/Noise.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "PieceGenerator.h"
|
#include "PiecePool.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "VillageGen.h"
|
#include "VillageGen.h"
|
||||||
#include "PieceGenerator.h"
|
#include "PieceGeneratorBFSTree.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ public:
|
|||||||
m_HeightGen(a_HeightGen)
|
m_HeightGen(a_HeightGen)
|
||||||
{
|
{
|
||||||
// Generate the pieces for this village; don't care about the Y coord:
|
// 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);
|
pg.PlacePieces(a_OriginX, a_OriginZ, a_MaxRoadDepth + 1, m_Pieces);
|
||||||
if (m_Pieces.empty())
|
if (m_Pieces.empty())
|
||||||
{
|
{
|
||||||
@ -141,10 +141,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~cVillage()
|
|
||||||
{
|
|
||||||
cPieceGenerator::FreePieces(m_Pieces);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Seed for the random functions */
|
/** Seed for the random functions */
|
||||||
@ -193,7 +189,7 @@ protected:
|
|||||||
{
|
{
|
||||||
PlacePieceOnGround(**itr);
|
PlacePieceOnGround(**itr);
|
||||||
}
|
}
|
||||||
Prefab.Draw(a_Chunk, *itr);
|
Prefab.Draw(a_Chunk, itr->get());
|
||||||
} // for itr - m_PlacedPieces[]
|
} // for itr - m_PlacedPieces[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,11 +300,11 @@ protected:
|
|||||||
void MoveAllDescendants(cPlacedPieces & a_PlacedPieces, size_t a_Pivot, int a_HeightDifference)
|
void MoveAllDescendants(cPlacedPieces & a_PlacedPieces, size_t a_Pivot, int a_HeightDifference)
|
||||||
{
|
{
|
||||||
size_t num = a_PlacedPieces.size();
|
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++)
|
for (size_t i = a_Pivot + 1; i < num; i++)
|
||||||
{
|
{
|
||||||
if (
|
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
|
!(static_cast<const cPrefab &>(a_PlacedPieces[i]->GetPiece())).ShouldMoveToGround() // It attaches strictly by connectors
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ set (SHARED_SRCS
|
|||||||
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.cpp
|
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.cpp
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PieceGenerator.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/PiecePool.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.cpp
|
||||||
@ -47,7 +47,7 @@ set (SHARED_HDRS
|
|||||||
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.h
|
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.h
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.h
|
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PieceGenerator.h
|
${CMAKE_SOURCE_DIR}/src/Generating/PiecePool.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.h
|
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.h
|
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h
|
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h
|
||||||
|
@ -17,7 +17,7 @@ set (SHARED_SRCS
|
|||||||
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.cpp
|
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.cpp
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PieceGenerator.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/PiecePool.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.cpp
|
||||||
@ -47,7 +47,7 @@ set (SHARED_HDRS
|
|||||||
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.h
|
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.h
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.h
|
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PieceGenerator.h
|
${CMAKE_SOURCE_DIR}/src/Generating/PiecePool.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.h
|
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.h
|
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h
|
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h
|
||||||
|
@ -17,7 +17,7 @@ set (SHARED_SRCS
|
|||||||
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.cpp
|
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.cpp
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PieceGenerator.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/PiecePool.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.cpp
|
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.cpp
|
||||||
@ -47,7 +47,7 @@ set (SHARED_HDRS
|
|||||||
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.h
|
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.h
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.h
|
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PieceGenerator.h
|
${CMAKE_SOURCE_DIR}/src/Generating/PiecePool.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.h
|
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.h
|
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h
|
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "Generating/PieceGenerator.h"
|
#include "Generating/PiecePool.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ set (SHARED_HDRS
|
|||||||
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.h
|
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.h
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.h
|
${CMAKE_SOURCE_DIR}/src/Generating/ChunkDesc.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PieceGenerator.h
|
${CMAKE_SOURCE_DIR}/src/Generating/PiecePool.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.h
|
${CMAKE_SOURCE_DIR}/src/Generating/Prefab.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.h
|
${CMAKE_SOURCE_DIR}/src/Generating/PrefabPiecePool.h
|
||||||
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h
|
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h
|
||||||
|
Loading…
Reference in New Issue
Block a user