1
0
Fork 0

Gen: Moved PiecePool into a separate file.

Also rewritten the PieceGenerator to use std::unique_ptr.
This commit is contained in:
Mattes D 2017-02-26 22:49:23 +01:00
parent f709f74aeb
commit 187abe3f5e
20 changed files with 635 additions and 636 deletions

View File

@ -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

View 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)
{
}

View 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);
} ;

View File

@ -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;
}
}
}

View File

@ -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;
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);
};

View File

@ -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);
}

View File

@ -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;

View File

@ -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"

View File

@ -10,7 +10,7 @@
#pragma once
#include <unordered_set>
#include "PieceGenerator.h"
#include "PiecePool.h"
#include "Prefab.h"

View File

@ -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[]
}

View File

@ -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;

View File

@ -9,7 +9,7 @@
#pragma once
#include "PieceGenerator.h"
#include "PiecePool.h"

View File

@ -5,6 +5,7 @@
#include "Globals.h"
#include "VerticalStrategy.h"
#include "../Noise/Noise.h"

View File

@ -9,7 +9,7 @@
#pragma once
#include "PieceGenerator.h"
#include "PiecePool.h"

View File

@ -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
)
{

View File

@ -17,7 +17,7 @@ set (SHARED_SRCS
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.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/PrefabPiecePool.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/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/PrefabPiecePool.h
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h

View File

@ -17,7 +17,7 @@ set (SHARED_SRCS
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.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/PrefabPiecePool.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/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/PrefabPiecePool.h
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h

View File

@ -17,7 +17,7 @@ set (SHARED_SRCS
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.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/PrefabPiecePool.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/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/PrefabPiecePool.h
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h

View File

@ -5,7 +5,7 @@
#include "Globals.h"
#include <exception>
#include <map>
#include "Generating/PieceGenerator.h"
#include "Generating/PiecePool.h"

View File

@ -38,7 +38,7 @@ set (SHARED_HDRS
${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.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/PrefabPiecePool.h
${CMAKE_SOURCE_DIR}/src/Generating/VerticalLimit.h