1
0

Added support for per-piece per-placement weights in cPieceGenerator.

Ref.: #753.
This commit is contained in:
madmaxoft 2014-04-13 17:27:36 +02:00
parent 146824cb68
commit b5ea5fbf90
2 changed files with 48 additions and 28 deletions

View File

@ -392,14 +392,17 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
Connections.reserve(AvailablePieces.size());
Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector
AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
/*
// DEBUG:
printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str());
//*/
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();
for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC)
{
@ -419,7 +422,9 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// Doesn't fit in this rotation
continue;
}
Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations));
// 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())
@ -427,21 +432,23 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// No available connections, bail out
return false;
}
ASSERT(WeightTotal > 0);
// Choose a random connection from the list:
int rnd = m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7;
cConnection & Conn = Connections[rnd % Connections.size()];
// 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:
/*
// DEBUG
printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n",
Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z,
BlockFaceToString(Conn.m_Connector.m_Direction).c_str(),
Conn.m_NumCCWRotations
);
//*/
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);
@ -449,12 +456,6 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// Add the new piece's connectors to the list of free connectors:
cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
/*
// DEBUG:
printf("Adding %u connectors to the pool\n", Connectors.size() - 1);
//*/
for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
{
if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
@ -524,10 +525,11 @@ void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cPieceGenerator::cConnection:
cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) :
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_NumCCWRotations(a_NumCCWRotations),
m_Weight(a_Weight)
{
}

View File

@ -85,6 +85,13 @@ typedef std::vector<cPiece *> cPieces;
// fwd:
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. */
class cPiecePool
@ -101,6 +108,16 @@ public:
Multiple starting points are supported, one of the returned piece will be chosen. */
virtual cPieces GetStartingPieces(void) = 0;
/** Returns the relative weight with which the a_NewPiece is to be selected for placing under a_PlacedPiece through a_ExistingConnector.
This allows the pool to tweak the piece's chances, based on the previous pieces in the tree and the connector used.
The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will never be chosen.
*/
virtual int GetPieceWeight(
const cPlacedPiece & a_PlacedPiece,
const cPiece::cConnector & a_ExistingConnector,
const cPiece & a_NewPiece
) { return 1; }
/** Called after a piece is placed, to notify the pool that it has been used.
The pool may adjust the pieces it will return the next time. */
virtual void PiecePlaced(const cPiece & a_Piece) = 0;
@ -157,8 +174,9 @@ protected:
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);
cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight);
};
typedef std::vector<cConnection> cConnections;