2014-03-07 18:37:18 +01:00
// PieceGenerator.cpp
2014-07-17 22:50:58 +02:00
// Implements the cBFSPieceGenerator class and cDFSPieceGenerator class
2014-03-07 18:37:18 +01:00
// representing base classes for generating structures composed of individual "pieces"
# include "Globals.h"
# include "PieceGenerator.h"
2015-11-11 10:32:42 +01:00
# include "VerticalStrategy.h"
# include "VerticalLimit.h"
2014-03-07 18:37:18 +01:00
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2015-11-11 10:32:42 +01:00
// cPiece:
2014-03-09 10:11:33 +01:00
2015-11-11 10:32:42 +01:00
bool cPiece : : SetVerticalStrategyFromString ( const AString & a_StrategyDesc , bool a_LogWarnings )
2014-03-09 10:11:33 +01:00
{
2015-11-11 10:32:42 +01:00
auto strategy = CreateVerticalStrategyFromString ( a_StrategyDesc , a_LogWarnings ) ;
if ( strategy = = nullptr )
2015-06-11 22:20:04 +02:00
{
2015-11-11 10:32:42 +01:00
return false ;
2015-06-11 22:20:04 +02:00
}
2015-11-11 10:32:42 +01:00
m_VerticalStrategy = strategy ;
return true ;
}
2015-06-11 22:20:04 +02:00
2014-03-09 10:11:33 +01:00
2014-03-09 22:04:29 +01:00
2015-11-11 10:32:42 +01:00
bool cPiece : : SetVerticalLimitFromString ( const AString & a_LimitDesc , bool a_LogWarnings )
{
auto limit = CreateVerticalLimitFromString ( a_LimitDesc , a_LogWarnings ) ;
if ( limit = = nullptr )
{
return false ;
}
m_VerticalLimit = limit ;
return true ;
}
2014-03-09 10:11:33 +01:00
2014-03-07 18:37:18 +01:00
2014-03-09 10:11:33 +01:00
Vector3i cPiece : : RotatePos ( const Vector3i & a_Pos , int a_NumCCWRotations ) const
{
Vector3i Size = GetSize ( ) ;
switch ( a_NumCCWRotations )
{
case 0 :
{
// No rotation needed
return a_Pos ;
}
case 1 :
{
// 1 CCW rotation:
return Vector3i ( a_Pos . z , a_Pos . y , Size . x - a_Pos . x - 1 ) ;
}
case 2 :
{
// 2 rotations ( = axis flip):
return Vector3i ( Size . x - a_Pos . x - 1 , a_Pos . y , Size . z - a_Pos . z - 1 ) ;
}
case 3 :
{
// 1 CW rotation:
return Vector3i ( Size . z - a_Pos . z - 1 , a_Pos . y , a_Pos . x ) ;
}
}
ASSERT ( ! " Unhandled rotation " ) ;
return a_Pos ;
}
2014-03-07 18:37:18 +01:00
cPiece : : cConnector cPiece : : RotateMoveConnector ( const cConnector & a_Connector , int a_NumCCWRotations , int a_MoveX , int a_MoveY , int a_MoveZ ) const
{
cPiece : : cConnector res ( a_Connector ) ;
2016-02-05 23:45:45 +02:00
2014-03-07 18:37:18 +01:00
// Rotate the res connector:
switch ( a_NumCCWRotations )
{
case 0 :
{
// No rotation needed
break ;
}
case 1 :
{
// 1 CCW rotation:
2017-02-13 16:50:35 +01:00
res . m_Direction = cConnector : : RotateDirectionCCW ( res . m_Direction ) ;
2014-03-07 18:37:18 +01:00
break ;
}
case 2 :
{
// 2 rotations ( = axis flip):
2017-02-13 16:50:35 +01:00
res . m_Direction = cConnector : : RotateDirection ( res . m_Direction ) ;
2014-03-07 18:37:18 +01:00
break ;
}
case 3 :
{
// 1 CW rotation:
2017-02-13 16:50:35 +01:00
res . m_Direction = cConnector : : RotateDirectionCW ( res . m_Direction ) ;
2014-03-07 18:37:18 +01:00
break ;
}
}
2014-03-09 10:11:33 +01:00
res . m_Pos = RotatePos ( a_Connector . m_Pos , a_NumCCWRotations ) ;
2016-02-05 23:45:45 +02:00
2014-03-07 18:37:18 +01:00
// Move the res connector:
2014-03-09 10:11:33 +01:00
res . m_Pos . x + = a_MoveX ;
res . m_Pos . y + = a_MoveY ;
res . m_Pos . z + = a_MoveZ ;
2016-02-05 23:45:45 +02:00
2014-03-07 18:37:18 +01:00
return res ;
}
cCuboid cPiece : : RotateHitBoxToConnector (
const cPiece : : cConnector & a_MyConnector ,
2014-03-09 10:11:33 +01:00
const Vector3i & a_ToConnectorPos ,
2014-03-07 18:37:18 +01:00
int a_NumCCWRotations
) const
{
2014-03-09 10:11:33 +01:00
ASSERT ( a_NumCCWRotations = = ( a_NumCCWRotations % 4 ) ) ;
Vector3i ConnPos = RotatePos ( a_MyConnector . m_Pos , a_NumCCWRotations ) ;
ConnPos = a_ToConnectorPos - ConnPos ;
return RotateMoveHitBox ( a_NumCCWRotations , ConnPos . x , ConnPos . y , ConnPos . z ) ;
}
cCuboid cPiece : : RotateMoveHitBox ( int a_NumCCWRotations , int a_MoveX , int a_MoveY , int a_MoveZ ) const
{
ASSERT ( a_NumCCWRotations = = ( a_NumCCWRotations % 4 ) ) ;
2014-03-07 18:37:18 +01:00
cCuboid res = GetHitBox ( ) ;
2014-03-09 10:11:33 +01:00
res . p1 = RotatePos ( res . p1 , a_NumCCWRotations ) ;
res . p2 = RotatePos ( res . p2 , a_NumCCWRotations ) ;
res . p1 . Move ( a_MoveX , a_MoveY , a_MoveZ ) ;
res . p2 . Move ( a_MoveX , a_MoveY , a_MoveZ ) ;
2014-03-07 18:37:18 +01:00
return res ;
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2014-03-09 10:11:33 +01:00
// cPiece::cConnector:
2017-02-13 16:50:35 +01:00
cPiece : : cConnector : : cConnector ( int a_X , int a_Y , int a_Z , int a_Type , eDirection a_Direction ) :
2014-03-09 10:11:33 +01:00
m_Pos ( a_X , a_Y , a_Z ) ,
m_Type ( a_Type ) ,
m_Direction ( a_Direction )
{
}
2017-02-13 16:50:35 +01:00
cPiece : : cConnector : : cConnector ( const Vector3i & a_Pos , int a_Type , eDirection a_Direction ) :
2014-03-09 10:11:33 +01:00
m_Pos ( a_Pos ) ,
m_Type ( a_Type ) ,
m_Direction ( a_Direction )
{
}
2017-02-13 16:50:35 +01:00
Vector3i cPiece : : cConnector : : AddDirection ( const Vector3i & a_Pos , eDirection a_Direction )
{
switch ( a_Direction )
{
case dirXM : return Vector3i ( a_Pos . x - 1 , a_Pos . y , a_Pos . z ) ;
case dirXP : return Vector3i ( a_Pos . x + 1 , a_Pos . y , a_Pos . z ) ;
case dirYM : return Vector3i ( a_Pos . x , a_Pos . y - 1 , a_Pos . z ) ;
case dirYP : return Vector3i ( a_Pos . x , a_Pos . y + 1 , a_Pos . z ) ;
case dirZM : return Vector3i ( a_Pos . x , a_Pos . y , a_Pos . z - 1 ) ;
case dirZP : return Vector3i ( a_Pos . x , a_Pos . y , a_Pos . z + 1 ) ;
case dirYM_XM_ZM : return Vector3i ( a_Pos . x , a_Pos . y - 1 , a_Pos . z ) ;
case dirYM_XM_ZP : return Vector3i ( a_Pos . x , a_Pos . y - 1 , a_Pos . z ) ;
case dirYM_XP_ZM : return Vector3i ( a_Pos . x , a_Pos . y - 1 , a_Pos . z ) ;
case dirYM_XP_ZP : return Vector3i ( a_Pos . x , a_Pos . y - 1 , a_Pos . z ) ;
case dirYP_XM_ZM : return Vector3i ( a_Pos . x , a_Pos . y + 1 , a_Pos . z ) ;
case dirYP_XM_ZP : return Vector3i ( a_Pos . x , a_Pos . y + 1 , a_Pos . z ) ;
case dirYP_XP_ZM : return Vector3i ( a_Pos . x , a_Pos . y + 1 , a_Pos . z ) ;
case dirYP_XP_ZP : return Vector3i ( a_Pos . x , a_Pos . y + 1 , a_Pos . z ) ;
}
# if !defined(__clang__)
ASSERT ( ! " Unknown connector direction " ) ;
return a_Pos ;
# endif
}
const char * cPiece : : cConnector : : DirectionToString ( eDirection a_Direction )
{
switch ( a_Direction )
{
case dirXM : return " x- " ;
case dirXP : return " x+ " ;
case dirYM : return " y- " ;
case dirYP : return " y+ " ;
case dirZM : return " z- " ;
case dirZP : return " z+ " ;
case dirYM_XM_ZM : return " y-x-z- " ;
case dirYM_XM_ZP : return " y-x-z+ " ;
case dirYM_XP_ZM : return " y-x+z- " ;
case dirYM_XP_ZP : return " y-x+z+ " ;
case dirYP_XM_ZM : return " y+x-z- " ;
case dirYP_XM_ZP : return " y+x-z+ " ;
case dirYP_XP_ZM : return " y+x+z- " ;
case dirYP_XP_ZP : return " y+x+z+ " ;
}
# if !defined(__clang__)
ASSERT ( ! " Unknown connector direction " ) ;
return " <unknown> " ;
# endif
}
bool cPiece : : cConnector : : IsValidDirection ( int a_Direction )
{
switch ( a_Direction )
{
case dirXM :
case dirXP :
case dirYM :
case dirYP :
case dirZM :
case dirZP :
case dirYM_XM_ZM :
case dirYM_XM_ZP :
case dirYM_XP_ZM :
case dirYM_XP_ZP :
case dirYP_XM_ZM :
case dirYP_XM_ZP :
case dirYP_XP_ZM :
case dirYP_XP_ZP :
{
return true ;
}
}
return false ;
}
cPiece : : cConnector : : eDirection cPiece : : cConnector : : RotateDirection ( eDirection a_Direction )
{
// 180-degree rotation:
switch ( a_Direction )
{
case dirXM : return dirXP ;
case dirXP : return dirXM ;
case dirYM : return dirYM ;
case dirYP : return dirYP ;
case dirZM : return dirZM ;
case dirZP : return dirZP ;
case dirYM_XM_ZM : return dirYM_XP_ZP ;
case dirYM_XM_ZP : return dirYM_XP_ZM ;
case dirYM_XP_ZM : return dirYM_XM_ZP ;
case dirYM_XP_ZP : return dirYM_XM_ZM ;
case dirYP_XM_ZM : return dirYP_XP_ZP ;
case dirYP_XM_ZP : return dirYP_XP_ZM ;
case dirYP_XP_ZM : return dirYP_XM_ZP ;
case dirYP_XP_ZP : return dirYP_XM_ZM ;
}
# if !defined(__clang__)
ASSERT ( ! " Unknown connector direction " ) ;
return a_Direction ;
# endif
}
cPiece : : cConnector : : eDirection cPiece : : cConnector : : RotateDirectionCCW ( eDirection a_Direction )
{
// 90 degrees CCW rotation:
switch ( a_Direction )
{
case dirXM : return dirZP ;
case dirXP : return dirZM ;
case dirYM : return dirYM ;
case dirYP : return dirYP ;
case dirZM : return dirXM ;
case dirZP : return dirXP ;
case dirYM_XM_ZM : return dirYM_XM_ZP ;
case dirYM_XM_ZP : return dirYM_XP_ZP ;
case dirYM_XP_ZM : return dirYM_XM_ZM ;
case dirYM_XP_ZP : return dirYM_XP_ZM ;
case dirYP_XM_ZM : return dirYP_XM_ZP ;
case dirYP_XM_ZP : return dirYP_XP_ZP ;
case dirYP_XP_ZM : return dirYP_XM_ZM ;
case dirYP_XP_ZP : return dirYP_XP_ZM ;
}
# if !defined(__clang__)
ASSERT ( ! " Unknown connector direction " ) ;
return a_Direction ;
# endif
}
cPiece : : cConnector : : eDirection cPiece : : cConnector : : RotateDirectionCW ( eDirection a_Direction )
{
// 90 degrees CW rotation:
switch ( a_Direction )
{
case dirXM : return dirZM ;
case dirXP : return dirZP ;
case dirYM : return dirYM ;
case dirYP : return dirYP ;
case dirZM : return dirXP ;
case dirZP : return dirXM ;
case dirYM_XM_ZM : return dirYM_XP_ZM ;
case dirYM_XM_ZP : return dirYM_XM_ZM ;
case dirYM_XP_ZM : return dirYM_XP_ZP ;
case dirYM_XP_ZP : return dirYM_XM_ZP ;
case dirYP_XM_ZM : return dirYP_XP_ZM ;
case dirYP_XM_ZP : return dirYP_XM_ZM ;
case dirYP_XP_ZM : return dirYP_XP_ZP ;
case dirYP_XP_ZP : return dirYP_XM_ZP ;
}
# if !defined(__clang__)
ASSERT ( ! " Unknown connector direction " ) ;
return a_Direction ;
# endif
}
bool cPiece : : cConnector : : StringToDirection ( const AString & a_Value , eDirection & a_Out )
{
// First try converting as a number:
int dirInt ;
if ( StringToInteger ( a_Value , dirInt ) )
{
if ( ! IsValidDirection ( dirInt ) )
{
return false ;
}
a_Out = static_cast < eDirection > ( dirInt ) ;
return true ;
}
// Compare to string representation:
static const struct
{
const char * m_String ;
eDirection m_Value ;
} StringDirections [ ] =
{
{ " x- " , dirXM } ,
{ " x+ " , dirXP } ,
{ " y- " , dirYM } ,
{ " y+ " , dirYP } ,
{ " z- " , dirZM } ,
{ " z+ " , dirZP } ,
{ " y-x-z- " , dirYM_XM_ZM } ,
{ " y-x-z+ " , dirYM_XM_ZP } ,
{ " y-x+z- " , dirYM_XP_ZM } ,
{ " y-x+z+ " , dirYM_XP_ZP } ,
{ " y+x-z- " , dirYP_XM_ZM } ,
{ " y+x-z+ " , dirYP_XM_ZP } ,
{ " y+x+z- " , dirYP_XP_ZM } ,
{ " y+x+z+ " , dirYP_XP_ZP } ,
// Alternate names, with slashes:
{ " y-/x-/z- " , dirYM_XM_ZM } ,
{ " y-/x-/z+ " , dirYM_XM_ZP } ,
{ " y-/x+/z- " , dirYM_XP_ZM } ,
{ " y-/x+/z+ " , dirYM_XP_ZP } ,
{ " y+/x-/z- " , dirYP_XM_ZM } ,
{ " y+/x-/z+ " , dirYP_XM_ZP } ,
{ " y+/x+/z- " , dirYP_XP_ZM } ,
{ " y+/x+/z+ " , dirYP_XP_ZP } ,
} ;
auto lcValue = StrToLower ( a_Value ) ;
for ( size_t i = 0 ; i < ARRAYCOUNT ( StringDirections ) ; i + + )
{
if ( strcmp ( lcValue . c_str ( ) , StringDirections [ i ] . m_String ) = = 0 )
{
a_Out = StringDirections [ i ] . m_Value ;
return true ;
}
}
// Not understood, failure:
return false ;
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2014-03-07 18:37:18 +01:00
// cPlacedPiece:
cPlacedPiece : : cPlacedPiece ( const cPlacedPiece * a_Parent , const cPiece & a_Piece , const Vector3i & a_Coords , int a_NumCCWRotations ) :
m_Parent ( a_Parent ) ,
m_Piece ( & a_Piece ) ,
m_Coords ( a_Coords ) ,
2014-05-25 23:50:16 +02:00
m_NumCCWRotations ( a_NumCCWRotations ) ,
m_HasBeenMovedToGround ( false )
2014-03-07 18:37:18 +01:00
{
2014-10-20 21:55:07 +01:00
m_Depth = ( m_Parent = = nullptr ) ? 0 : ( m_Parent - > GetDepth ( ) + 1 ) ;
2014-03-09 10:11:33 +01:00
m_HitBox = a_Piece . RotateMoveHitBox ( a_NumCCWRotations , a_Coords . x , a_Coords . y , a_Coords . z ) ;
2014-03-09 22:04:29 +01:00
m_HitBox . Sort ( ) ;
2014-03-07 18:37:18 +01:00
}
2014-05-17 21:54:04 +02:00
cPiece : : cConnector cPlacedPiece : : GetRotatedConnector ( size_t a_Index ) const
{
cPiece : : cConnectors Connectors = m_Piece - > GetConnectors ( ) ;
ASSERT ( Connectors . size ( ) > = a_Index ) ;
return m_Piece - > RotateMoveConnector ( Connectors [ a_Index ] , m_NumCCWRotations , m_Coords . x , m_Coords . y , m_Coords . z ) ;
2014-05-22 21:47:56 +02:00
}
cPiece : : cConnector cPlacedPiece : : GetRotatedConnector ( const cPiece : : cConnector & a_Connector ) const
{
return m_Piece - > RotateMoveConnector ( a_Connector , m_NumCCWRotations , m_Coords . x , m_Coords . y , m_Coords . z ) ;
2014-05-17 21:54:04 +02:00
}
2014-05-25 23:50:16 +02:00
void cPlacedPiece : : MoveToGroundBy ( int a_OffsetY )
{
m_Coords . y + = a_OffsetY ;
m_HasBeenMovedToGround = true ;
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2014-03-07 18:37:18 +01:00
// cPieceGenerator:
cPieceGenerator : : cPieceGenerator ( cPiecePool & a_PiecePool , int a_Seed ) :
m_PiecePool ( a_PiecePool ) ,
m_Noise ( a_Seed ) ,
m_Seed ( a_Seed )
{
}
2014-03-09 10:11:33 +01:00
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 ( ) ;
}
2015-11-11 10:32:42 +01:00
cPlacedPiece * cPieceGenerator : : PlaceStartingPiece ( int a_BlockX , int a_BlockZ , cFreeConnectors & a_OutConnectors )
2014-03-07 18:37:18 +01:00
{
m_PiecePool . Reset ( ) ;
2015-11-11 10:32:42 +01:00
int rnd = m_Noise . IntNoise2DInt ( a_BlockX , a_BlockZ ) / 7 ;
2016-02-05 23:45:45 +02:00
2014-03-07 18:37:18 +01:00
// Choose a random one of the starting pieces:
cPieces StartingPieces = m_PiecePool . GetStartingPieces ( ) ;
2014-05-27 22:05:50 +02:00
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:
2015-05-19 13:34:52 +01:00
StartingPiece = StartingPieces [ static_cast < size_t > ( rnd ) % StartingPieces . size ( ) ] ;
2014-05-27 22:05:50 +02:00
}
2014-03-07 18:37:18 +01:00
rnd = rnd > > 16 ;
2016-02-05 23:45:45 +02:00
2014-03-07 18:37:18 +01:00
// Choose a random supported rotation:
int Rotations [ 4 ] = { 0 } ;
int NumRotations = 1 ;
2014-03-11 12:35:44 -07:00
for ( size_t i = 1 ; i < ARRAYCOUNT ( Rotations ) ; i + + )
2014-03-07 18:37:18 +01:00
{
2015-05-24 12:56:56 +01:00
if ( StartingPiece - > CanRotateCCW ( static_cast < int > ( i ) ) )
2014-03-07 18:37:18 +01:00
{
2015-05-24 12:56:56 +01:00
Rotations [ NumRotations ] = static_cast < int > ( i ) ;
2014-03-07 18:37:18 +01:00
NumRotations + = 1 ;
}
}
int Rotation = Rotations [ rnd % NumRotations ] ;
2015-11-11 10:32:42 +01:00
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 ) ;
2014-03-07 18:37:18 +01:00
// 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 (
2015-11-11 10:32:42 +01:00
cFreeConnector ( res , StartingPiece - > RotateMoveConnector ( * itr , Rotation , a_BlockX , BlockY , a_BlockZ ) )
2014-03-07 18:37:18 +01:00
) ;
}
return res ;
}
2014-03-09 19:30:38 +01:00
bool cPieceGenerator : : TryPlacePieceAtConnector (
const cPlacedPiece & a_ParentPiece ,
const cPiece : : cConnector & a_Connector ,
cPlacedPieces & a_OutPieces ,
cPieceGenerator : : cFreeConnectors & a_OutConnectors
)
2014-03-07 18:37:18 +01:00
{
// Translation of direction - direction -> number of CCW rotations needed:
2017-02-13 16:50:35 +01:00
// 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 ] =
2014-03-07 18:37:18 +01:00
{
2017-02-13 16:50:35 +01:00
/* 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 } ,
2014-03-07 18:37:18 +01:00
} ;
2016-02-05 23:45:45 +02:00
2014-03-07 18:37:18 +01:00
// Get a list of available connections:
2017-02-13 16:50:35 +01:00
ASSERT ( a_Connector . m_Direction < ARRAYCOUNT ( DirectionRotationTable ) ) ;
2014-03-07 18:37:18 +01:00
const int * RotTable = DirectionRotationTable [ a_Connector . m_Direction ] ;
cConnections Connections ;
2014-05-05 23:05:30 +02:00
int WantedConnectorType = - a_Connector . m_Type ;
cPieces AvailablePieces = m_PiecePool . GetPiecesWithConnector ( WantedConnectorType ) ;
2014-03-07 18:37:18 +01:00
Connections . reserve ( AvailablePieces . size ( ) ) ;
2017-02-13 16:50:35 +01:00
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
2014-04-13 17:27:36 +02:00
int WeightTotal = 0 ;
2014-03-07 18:37:18 +01:00
for ( cPieces : : iterator itrP = AvailablePieces . begin ( ) , endP = AvailablePieces . end ( ) ; itrP ! = endP ; + + itrP )
{
2014-04-13 17:27:36 +02:00
// 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 ;
}
2016-02-05 23:45:45 +02:00
2014-04-13 17:27:36 +02:00
// Try fitting each of the piece's connector:
2014-03-07 18:37:18 +01:00
cPiece : : cConnectors Connectors = ( * itrP ) - > GetConnectors ( ) ;
2015-11-11 10:32:42 +01:00
auto verticalLimit = ( * itrP ) - > GetVerticalLimit ( ) ;
2014-03-07 18:37:18 +01:00
for ( cPiece : : cConnectors : : iterator itrC = Connectors . begin ( ) , endC = Connectors . end ( ) ; itrC ! = endC ; + + itrC )
{
2014-05-05 23:05:30 +02:00
if ( itrC - > m_Type ! = WantedConnectorType )
2014-03-07 18:37:18 +01:00
{
continue ;
}
// This is a same-type connector, find out how to rotate to it:
2017-02-13 16:50:35 +01:00
ASSERT ( itrC - > m_Direction < ARRAYCOUNT ( DirectionRotationTable [ 0 ] ) ) ;
2014-03-07 18:37:18 +01:00
int NumCCWRotations = RotTable [ itrC - > m_Direction ] ;
2017-02-13 16:50:35 +01:00
if ( ( NumCCWRotations < 0 ) | | ! ( * itrP ) - > CanRotateCCW ( NumCCWRotations ) )
2014-03-07 18:37:18 +01:00
{
// Doesn't support this rotation
continue ;
}
2015-11-11 10:32:42 +01:00
// 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 ;
}
2014-03-09 10:11:33 +01:00
if ( ! CheckConnection ( a_Connector , ConnPos , * * itrP , * itrC , NumCCWRotations , a_OutPieces ) )
2014-03-07 18:37:18 +01:00
{
// Doesn't fit in this rotation
continue ;
}
2014-04-13 17:27:36 +02:00
// Fits, add it to list of possibile connections:
Connections . push_back ( cConnection ( * * itrP , * itrC , NumCCWRotations , Weight ) ) ;
WeightTotal + = Weight ;
2014-03-07 18:37:18 +01:00
} // for itrC - Connectors[]
} // for itrP - AvailablePieces[]
if ( Connections . empty ( ) )
{
// No available connections, bail out
return false ;
}
2014-04-13 17:27:36 +02:00
ASSERT ( WeightTotal > 0 ) ;
2016-02-05 23:45:45 +02:00
2014-04-13 17:27:36 +02:00
// 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 ] ;
2016-02-05 23:45:45 +02:00
2014-03-07 18:37:18 +01:00
// Place the piece:
2014-03-09 10:11:33 +01:00
Vector3i NewPos = Conn . m_Piece - > RotatePos ( Conn . m_Connector . m_Pos , Conn . m_NumCCWRotations ) ;
ConnPos - = NewPos ;
2014-03-09 19:30:38 +01:00
cPlacedPiece * PlacedPiece = new cPlacedPiece ( & a_ParentPiece , * ( Conn . m_Piece ) , ConnPos , Conn . m_NumCCWRotations ) ;
a_OutPieces . push_back ( PlacedPiece ) ;
2016-02-05 23:45:45 +02:00
2014-03-09 10:11:33 +01:00
// Add the new piece's connectors to the list of free connectors:
2014-03-09 19:30:38 +01:00
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 ) ) ) ;
}
2016-02-05 23:45:45 +02:00
2014-03-09 10:11:33 +01:00
return true ;
2014-03-07 18:37:18 +01:00
}
bool cPieceGenerator : : CheckConnection (
const cPiece : : cConnector & a_ExistingConnector ,
2014-03-09 10:11:33 +01:00
const Vector3i & a_ToPos ,
2014-03-07 18:37:18 +01:00
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:
2014-03-09 10:11:33 +01:00
cCuboid RotatedHitBox = a_Piece . RotateHitBoxToConnector ( a_NewConnector , a_ToPos , a_NumCCWRotations ) ;
2014-03-09 22:04:29 +01:00
RotatedHitBox . Sort ( ) ;
2014-03-07 18:37:18 +01:00
for ( cPlacedPieces : : const_iterator itr = a_OutPieces . begin ( ) , end = a_OutPieces . end ( ) ; itr ! = end ; + + itr )
{
2014-03-09 10:11:33 +01:00
if ( ( * itr ) - > GetHitBox ( ) . DoesIntersect ( RotatedHitBox ) )
2014-03-07 18:37:18 +01:00
{
return false ;
}
}
return true ;
}
2014-03-09 22:04:29 +01:00
//*
2014-03-09 10:11:33 +01:00
// DEBUG:
void cPieceGenerator : : DebugConnectorPool ( const cPieceGenerator : : cFreeConnectors & a_ConnectorPool , size_t a_NumProcessed )
{
2014-03-12 10:09:08 -07:00
printf ( " Connector pool: " SIZE_T_FMT " items \n " , a_ConnectorPool . size ( ) - a_NumProcessed ) ;
2014-03-09 10:11:33 +01:00
size_t idx = 0 ;
2015-05-19 13:34:52 +01:00
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 )
2014-03-09 10:11:33 +01:00
{
2014-03-12 10:09:08 -07:00
printf ( " " SIZE_T_FMT " : {%d, %d, %d}, type %d, direction %s, depth %d \n " ,
2014-03-09 10:11:33 +01:00
idx ,
itr - > m_Connector . m_Pos . x , itr - > m_Connector . m_Pos . y , itr - > m_Connector . m_Pos . z ,
itr - > m_Connector . m_Type ,
2017-02-13 16:50:35 +01:00
cPiece : : cConnector : : DirectionToString ( itr - > m_Connector . m_Direction ) ,
2014-03-09 19:30:38 +01:00
itr - > m_Piece - > GetDepth ( )
2014-03-09 10:11:33 +01:00
) ;
} // for itr - a_ConnectorPool[]
}
2014-03-09 22:04:29 +01:00
//*/
2014-03-09 10:11:33 +01:00
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2014-03-07 18:37:18 +01:00
// cPieceGenerator::cConnection:
2014-04-13 17:27:36 +02:00
cPieceGenerator : : cConnection : : cConnection ( cPiece & a_Piece , cPiece : : cConnector & a_Connector , int a_NumCCWRotations , int a_Weight ) :
2014-03-07 18:37:18 +01:00
m_Piece ( & a_Piece ) ,
2014-03-09 10:11:33 +01:00
m_Connector ( a_Connector ) ,
2014-04-13 17:27:36 +02:00
m_NumCCWRotations ( a_NumCCWRotations ) ,
m_Weight ( a_Weight )
2014-03-07 18:37:18 +01:00
{
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2014-03-07 18:37:18 +01:00
// cPieceGenerator::cFreeConnector:
2014-03-09 10:11:33 +01:00
cPieceGenerator : : cFreeConnector : : cFreeConnector ( cPlacedPiece * a_Piece , const cPiece : : cConnector & a_Connector ) :
m_Piece ( a_Piece ) ,
2014-03-07 18:37:18 +01:00
m_Connector ( a_Connector )
{
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2014-03-07 18:37:18 +01:00
// cBFSPieceGenerator:
cBFSPieceGenerator : : cBFSPieceGenerator ( cPiecePool & a_PiecePool , int a_Seed ) :
super ( a_PiecePool , a_Seed )
{
}
2015-11-11 10:32:42 +01:00
void cBFSPieceGenerator : : PlacePieces ( int a_BlockX , int a_BlockZ , int a_MaxDepth , cPlacedPieces & a_OutPieces )
2014-03-07 18:37:18 +01:00
{
a_OutPieces . clear ( ) ;
cFreeConnectors ConnectorPool ;
2016-02-05 23:45:45 +02:00
2014-03-07 18:37:18 +01:00
// Place the starting piece:
2015-11-11 10:32:42 +01:00
a_OutPieces . push_back ( PlaceStartingPiece ( a_BlockX , a_BlockZ , ConnectorPool ) ) ;
2016-02-05 23:45:45 +02:00
2014-03-09 22:04:29 +01:00
/*
2014-03-09 10:11:33 +01:00
// 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 ) ;
2014-03-09 22:04:29 +01:00
//*/
2016-02-05 23:45:45 +02:00
2014-03-07 18:37:18 +01:00
// 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 ] ;
2014-03-09 10:11:33 +01:00
if ( Conn . m_Piece - > GetDepth ( ) < a_MaxDepth )
{
2014-03-09 19:30:38 +01:00
if ( TryPlacePieceAtConnector ( * Conn . m_Piece , Conn . m_Connector , a_OutPieces , ConnectorPool ) )
2014-03-09 10:11:33 +01:00
{
2014-03-09 22:04:29 +01:00
/*
// DEBUG:
2014-03-09 10:11:33 +01:00
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 ) ;
2014-03-09 22:04:29 +01:00
//*/
2014-03-09 10:11:33 +01:00
}
}
2014-03-07 18:37:18 +01:00
NumProcessed + + ;
if ( NumProcessed > 1000 )
{
2015-05-19 13:34:52 +01:00
typedef cPieceGenerator : : cFreeConnectors : : difference_type difType ;
ConnectorPool . erase ( ConnectorPool . begin ( ) , ConnectorPool . begin ( ) + static_cast < difType > ( NumProcessed ) ) ;
2014-03-07 18:37:18 +01:00
NumProcessed = 0 ;
}
}
}