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()); 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 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); AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
int WeightTotal = 0;
/*
// 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());
//*/
for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP) 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(); cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC) 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 // Doesn't fit in this rotation
continue; 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 itrC - Connectors[]
} // for itrP - AvailablePieces[] } // for itrP - AvailablePieces[]
if (Connections.empty()) if (Connections.empty())
@ -427,21 +432,23 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// No available connections, bail out // No available connections, bail out
return false; return false;
} }
ASSERT(WeightTotal > 0);
// Choose a random connection from the list: // 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; int rnd = (m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7) % WeightTotal;
cConnection & Conn = Connections[rnd % Connections.size()]; 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: // 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); Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
ConnPos -= NewPos; ConnPos -= NewPos;
cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations); 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: // Add the new piece's connectors to the list of free connectors:
cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors(); 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) for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
{ {
if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos)) if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
@ -524,10 +525,11 @@ void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cPieceGenerator::cConnection: // 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_Piece(&a_Piece),
m_Connector(a_Connector), 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 /** 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. */ placed and adjust the returned piece vectors. */
class cPiecePool class cPiecePool
@ -101,6 +108,16 @@ public:
Multiple starting points are supported, one of the returned piece will be chosen. */ Multiple starting points are supported, one of the returned piece will be chosen. */
virtual cPieces GetStartingPieces(void) = 0; 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. /** 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. */ The pool may adjust the pieces it will return the next time. */
virtual void PiecePlaced(const cPiece & a_Piece) = 0; virtual void PiecePlaced(const cPiece & a_Piece) = 0;
@ -157,8 +174,9 @@ protected:
cPiece * m_Piece; // The piece being connected cPiece * m_Piece; // The piece being connected
cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords) 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_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; typedef std::vector<cConnection> cConnections;