2013-07-29 07:13:03 -04:00
// ChunkDesc.cpp
// Implements the cChunkDesc class representing the chunk description used while generating a chunk. This class is also exported to Lua for HOOK_CHUNK_GENERATING.
# include "Globals.h"
# include "ChunkDesc.h"
# include "../BlockArea.h"
# include "../Cuboid.h"
2014-11-18 06:07:08 -05:00
# include "../Noise/Noise.h"
2013-11-14 09:37:09 -05:00
# include "../BlockEntities/BlockEntity.h"
2013-07-29 07:13:03 -04:00
cChunkDesc : : cChunkDesc ( int a_ChunkX , int a_ChunkZ ) :
m_ChunkX ( a_ChunkX ) ,
m_ChunkZ ( a_ChunkZ ) ,
m_bUseDefaultBiomes ( true ) ,
m_bUseDefaultHeight ( true ) ,
m_bUseDefaultComposition ( true ) ,
m_bUseDefaultFinish ( true )
{
m_BlockArea . Create ( cChunkDef : : Width , cChunkDef : : Height , cChunkDef : : Width ) ;
/*
memset ( m_BlockTypes , 0 , sizeof ( cChunkDef : : BlockTypes ) ) ;
memset ( m_BlockMeta , 0 , sizeof ( cChunkDef : : BlockNibbles ) ) ;
*/
memset ( m_BiomeMap , 0 , sizeof ( cChunkDef : : BiomeMap ) ) ;
memset ( m_HeightMap , 0 , sizeof ( cChunkDef : : HeightMap ) ) ;
}
cChunkDesc : : ~ cChunkDesc ( )
{
// Nothing needed yet
}
void cChunkDesc : : SetChunkCoords ( int a_ChunkX , int a_ChunkZ )
{
m_ChunkX = a_ChunkX ;
m_ChunkZ = a_ChunkZ ;
}
void cChunkDesc : : FillBlocks ( BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta )
{
m_BlockArea . Fill ( cBlockArea : : baTypes | cBlockArea : : baMetas , a_BlockType , a_BlockMeta ) ;
}
void cChunkDesc : : SetBlockTypeMeta ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta )
{
m_BlockArea . SetRelBlockTypeMeta ( a_RelX , a_RelY , a_RelZ , a_BlockType , a_BlockMeta ) ;
}
void cChunkDesc : : GetBlockTypeMeta ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE & a_BlockType , NIBBLETYPE & a_BlockMeta )
{
m_BlockArea . GetRelBlockTypeMeta ( a_RelX , a_RelY , a_RelZ , a_BlockType , a_BlockMeta ) ;
}
void cChunkDesc : : SetBlockType ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE a_BlockType )
{
cChunkDef : : SetBlock ( m_BlockArea . GetBlockTypes ( ) , a_RelX , a_RelY , a_RelZ , a_BlockType ) ;
}
BLOCKTYPE cChunkDesc : : GetBlockType ( int a_RelX , int a_RelY , int a_RelZ )
{
return cChunkDef : : GetBlock ( m_BlockArea . GetBlockTypes ( ) , a_RelX , a_RelY , a_RelZ ) ;
}
NIBBLETYPE cChunkDesc : : GetBlockMeta ( int a_RelX , int a_RelY , int a_RelZ )
{
return m_BlockArea . GetRelBlockMeta ( a_RelX , a_RelY , a_RelZ ) ;
}
void cChunkDesc : : SetBlockMeta ( int a_RelX , int a_RelY , int a_RelZ , NIBBLETYPE a_BlockMeta )
{
m_BlockArea . SetRelBlockMeta ( a_RelX , a_RelY , a_RelZ , a_BlockMeta ) ;
}
2014-02-03 15:26:17 -05:00
void cChunkDesc : : SetBiome ( int a_RelX , int a_RelZ , EMCSBiome a_BiomeID )
2013-07-29 07:13:03 -04:00
{
2014-02-03 15:26:17 -05:00
cChunkDef : : SetBiome ( m_BiomeMap , a_RelX , a_RelZ , a_BiomeID ) ;
2013-07-29 07:13:03 -04:00
}
EMCSBiome cChunkDesc : : GetBiome ( int a_RelX , int a_RelZ )
{
return cChunkDef : : GetBiome ( m_BiomeMap , a_RelX , a_RelZ ) ;
}
void cChunkDesc : : SetHeight ( int a_RelX , int a_RelZ , int a_Height )
{
cChunkDef : : SetHeight ( m_HeightMap , a_RelX , a_RelZ , a_Height ) ;
}
int cChunkDesc : : GetHeight ( int a_RelX , int a_RelZ )
{
return cChunkDef : : GetHeight ( m_HeightMap , a_RelX , a_RelZ ) ;
}
2014-11-12 15:24:26 -05:00
void cChunkDesc : : SetHeightFromShape ( const Shape & a_Shape )
{
for ( int z = 0 ; z < cChunkDef : : Width ; z + + )
{
for ( int x = 0 ; x < cChunkDef : : Width ; x + + )
{
for ( int y = cChunkDef : : Height - 1 ; y > 0 ; y - - )
{
if ( a_Shape [ y + x * 256 + z * 16 * 256 ] ! = 0 )
{
cChunkDef : : SetHeight ( m_HeightMap , x , z , y ) ;
break ;
}
} // for y
} // for x
} // for z
}
void cChunkDesc : : GetShapeFromHeight ( Shape & a_Shape ) const
{
for ( int z = 0 ; z < cChunkDef : : Width ; z + + )
{
for ( int x = 0 ; x < cChunkDef : : Width ; x + + )
{
int height = cChunkDef : : GetHeight ( m_HeightMap , x , z ) ;
for ( int y = 0 ; y < = height ; y + + )
{
a_Shape [ y + x * 256 + z * 16 * 256 ] = 1 ;
}
for ( int y = height + 1 ; y < cChunkDef : : Height ; y + + )
{
a_Shape [ y + x * 256 + z * 16 * 256 ] = 0 ;
} // for y
} // for x
} // for z
}
2013-07-29 07:13:03 -04:00
void cChunkDesc : : SetUseDefaultBiomes ( bool a_bUseDefaultBiomes )
{
m_bUseDefaultBiomes = a_bUseDefaultBiomes ;
}
bool cChunkDesc : : IsUsingDefaultBiomes ( void ) const
{
return m_bUseDefaultBiomes ;
}
void cChunkDesc : : SetUseDefaultHeight ( bool a_bUseDefaultHeight )
{
m_bUseDefaultHeight = a_bUseDefaultHeight ;
}
bool cChunkDesc : : IsUsingDefaultHeight ( void ) const
{
return m_bUseDefaultHeight ;
}
void cChunkDesc : : SetUseDefaultComposition ( bool a_bUseDefaultComposition )
{
m_bUseDefaultComposition = a_bUseDefaultComposition ;
}
bool cChunkDesc : : IsUsingDefaultComposition ( void ) const
{
return m_bUseDefaultComposition ;
}
void cChunkDesc : : SetUseDefaultFinish ( bool a_bUseDefaultFinish )
{
m_bUseDefaultFinish = a_bUseDefaultFinish ;
}
bool cChunkDesc : : IsUsingDefaultFinish ( void ) const
{
return m_bUseDefaultFinish ;
}
void cChunkDesc : : WriteBlockArea ( const cBlockArea & a_BlockArea , int a_RelX , int a_RelY , int a_RelZ , cBlockArea : : eMergeStrategy a_MergeStrategy )
{
m_BlockArea . Merge ( a_BlockArea , a_RelX , a_RelY , a_RelZ , a_MergeStrategy ) ;
}
void cChunkDesc : : ReadBlockArea ( cBlockArea & a_Dest , int a_MinRelX , int a_MaxRelX , int a_MinRelY , int a_MaxRelY , int a_MinRelZ , int a_MaxRelZ )
{
// Normalize the coords:
if ( a_MinRelX > a_MaxRelX )
{
std : : swap ( a_MinRelX , a_MaxRelX ) ;
}
if ( a_MinRelY > a_MaxRelY )
{
std : : swap ( a_MinRelY , a_MaxRelY ) ;
}
if ( a_MinRelZ > a_MaxRelZ )
{
std : : swap ( a_MinRelZ , a_MaxRelZ ) ;
}
// Include the Max coords:
a_MaxRelX + = 1 ;
a_MaxRelY + = 1 ;
a_MaxRelZ + = 1 ;
2013-11-16 13:58:17 -05:00
2013-07-29 07:13:03 -04:00
// Check coords validity:
if ( a_MinRelX < 0 )
{
LOGWARNING ( " %s: MinRelX less than zero, adjusting to zero " , __FUNCTION__ ) ;
a_MinRelX = 0 ;
}
else if ( a_MinRelX > = cChunkDef : : Width )
{
LOGWARNING ( " %s: MinRelX more than chunk width, adjusting to chunk width " , __FUNCTION__ ) ;
a_MinRelX = cChunkDef : : Width - 1 ;
}
if ( a_MaxRelX < 0 )
{
LOGWARNING ( " %s: MaxRelX less than zero, adjusting to zero " , __FUNCTION__ ) ;
a_MaxRelX = 0 ;
}
2014-10-20 13:36:16 -04:00
else if ( a_MaxRelX > cChunkDef : : Width )
2013-07-29 07:13:03 -04:00
{
LOGWARNING ( " %s: MaxRelX more than chunk width, adjusting to chunk width " , __FUNCTION__ ) ;
2014-10-20 13:36:16 -04:00
a_MaxRelX = cChunkDef : : Width ;
2013-07-29 07:13:03 -04:00
}
if ( a_MinRelY < 0 )
{
LOGWARNING ( " %s: MinRelY less than zero, adjusting to zero " , __FUNCTION__ ) ;
a_MinRelY = 0 ;
}
else if ( a_MinRelY > = cChunkDef : : Height )
{
LOGWARNING ( " %s: MinRelY more than chunk height, adjusting to chunk height " , __FUNCTION__ ) ;
a_MinRelY = cChunkDef : : Height - 1 ;
}
if ( a_MaxRelY < 0 )
{
LOGWARNING ( " %s: MaxRelY less than zero, adjusting to zero " , __FUNCTION__ ) ;
a_MaxRelY = 0 ;
}
2014-10-20 13:36:16 -04:00
else if ( a_MaxRelY > cChunkDef : : Height )
2013-07-29 07:13:03 -04:00
{
LOGWARNING ( " %s: MaxRelY more than chunk height, adjusting to chunk height " , __FUNCTION__ ) ;
2014-10-20 13:36:16 -04:00
a_MaxRelY = cChunkDef : : Height ;
2013-07-29 07:13:03 -04:00
}
2013-11-16 13:58:17 -05:00
2013-07-29 07:13:03 -04:00
if ( a_MinRelZ < 0 )
{
LOGWARNING ( " %s: MinRelZ less than zero, adjusting to zero " , __FUNCTION__ ) ;
a_MinRelZ = 0 ;
}
else if ( a_MinRelZ > = cChunkDef : : Width )
{
LOGWARNING ( " %s: MinRelZ more than chunk width, adjusting to chunk width " , __FUNCTION__ ) ;
a_MinRelZ = cChunkDef : : Width - 1 ;
}
if ( a_MaxRelZ < 0 )
{
LOGWARNING ( " %s: MaxRelZ less than zero, adjusting to zero " , __FUNCTION__ ) ;
a_MaxRelZ = 0 ;
}
2014-10-20 13:36:16 -04:00
else if ( a_MaxRelZ > cChunkDef : : Width )
2013-07-29 07:13:03 -04:00
{
LOGWARNING ( " %s: MaxRelZ more than chunk width, adjusting to chunk width " , __FUNCTION__ ) ;
2014-10-20 13:36:16 -04:00
a_MaxRelZ = cChunkDef : : Width ;
2013-07-29 07:13:03 -04:00
}
// Prepare the block area:
int SizeX = a_MaxRelX - a_MinRelX ;
int SizeY = a_MaxRelY - a_MinRelY ;
int SizeZ = a_MaxRelZ - a_MinRelZ ;
a_Dest . Clear ( ) ;
2014-03-25 16:59:25 -04:00
a_Dest . m_Origin . x = m_ChunkX * cChunkDef : : Width + a_MinRelX ;
a_Dest . m_Origin . y = a_MinRelY ;
a_Dest . m_Origin . z = m_ChunkZ * cChunkDef : : Width + a_MinRelZ ;
2013-07-29 07:13:03 -04:00
a_Dest . SetSize ( SizeX , SizeY , SizeZ , cBlockArea : : baTypes | cBlockArea : : baMetas ) ;
for ( int y = 0 ; y < SizeY ; y + + )
{
int CDY = a_MinRelY + y ;
for ( int z = 0 ; z < SizeZ ; z + + )
{
int CDZ = a_MinRelZ + z ;
for ( int x = 0 ; x < SizeX ; x + + )
{
int CDX = a_MinRelX + x ;
BLOCKTYPE BlockType ;
NIBBLETYPE BlockMeta ;
GetBlockTypeMeta ( CDX , CDY , CDZ , BlockType , BlockMeta ) ;
a_Dest . SetRelBlockTypeMeta ( x , y , z , BlockType , BlockMeta ) ;
} // for x
} // for z
} // for y
}
HEIGHTTYPE cChunkDesc : : GetMaxHeight ( void ) const
{
HEIGHTTYPE MaxHeight = m_HeightMap [ 0 ] ;
2013-12-20 10:01:34 -05:00
for ( size_t i = 1 ; i < ARRAYCOUNT ( m_HeightMap ) ; i + + )
2013-07-29 07:13:03 -04:00
{
if ( m_HeightMap [ i ] > MaxHeight )
{
MaxHeight = m_HeightMap [ i ] ;
}
}
return MaxHeight ;
}
2014-11-12 15:24:26 -05:00
HEIGHTTYPE cChunkDesc : : GetMinHeight ( void ) const
{
HEIGHTTYPE MinHeight = m_HeightMap [ 0 ] ;
for ( size_t i = 1 ; i < ARRAYCOUNT ( m_HeightMap ) ; i + + )
{
if ( m_HeightMap [ i ] < MinHeight )
{
MinHeight = m_HeightMap [ i ] ;
}
}
return MinHeight ;
}
2013-07-29 07:13:03 -04:00
void cChunkDesc : : FillRelCuboid (
int a_MinX , int a_MaxX ,
int a_MinY , int a_MaxY ,
int a_MinZ , int a_MaxZ ,
BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta
)
{
int MinX = std : : max ( a_MinX , 0 ) ;
int MinY = std : : max ( a_MinY , 0 ) ;
int MinZ = std : : max ( a_MinZ , 0 ) ;
int MaxX = std : : min ( a_MaxX , cChunkDef : : Width - 1 ) ;
int MaxY = std : : min ( a_MaxY , cChunkDef : : Height - 1 ) ;
int MaxZ = std : : min ( a_MaxZ , cChunkDef : : Width - 1 ) ;
2013-11-16 13:58:17 -05:00
2013-07-29 07:13:03 -04:00
for ( int y = MinY ; y < = MaxY ; y + + )
{
for ( int z = MinZ ; z < = MaxZ ; z + + )
{
for ( int x = MinX ; x < = MaxX ; x + + )
{
SetBlockTypeMeta ( x , y , z , a_BlockType , a_BlockMeta ) ;
}
} // for z
} // for y
}
void cChunkDesc : : ReplaceRelCuboid (
int a_MinX , int a_MaxX ,
int a_MinY , int a_MaxY ,
int a_MinZ , int a_MaxZ ,
BLOCKTYPE a_SrcType , NIBBLETYPE a_SrcMeta ,
BLOCKTYPE a_DstType , NIBBLETYPE a_DstMeta
)
{
int MinX = std : : max ( a_MinX , 0 ) ;
int MinY = std : : max ( a_MinY , 0 ) ;
int MinZ = std : : max ( a_MinZ , 0 ) ;
int MaxX = std : : min ( a_MaxX , cChunkDef : : Width - 1 ) ;
int MaxY = std : : min ( a_MaxY , cChunkDef : : Height - 1 ) ;
int MaxZ = std : : min ( a_MaxZ , cChunkDef : : Width - 1 ) ;
2013-11-16 13:58:17 -05:00
2013-07-29 07:13:03 -04:00
for ( int y = MinY ; y < = MaxY ; y + + )
{
for ( int z = MinZ ; z < = MaxZ ; z + + )
{
for ( int x = MinX ; x < = MaxX ; x + + )
{
BLOCKTYPE BlockType ;
NIBBLETYPE BlockMeta ;
GetBlockTypeMeta ( x , y , z , BlockType , BlockMeta ) ;
if ( ( BlockType = = a_SrcType ) & & ( BlockMeta = = a_SrcMeta ) )
{
SetBlockTypeMeta ( x , y , z , a_DstType , a_DstMeta ) ;
}
}
} // for z
} // for y
}
void cChunkDesc : : FloorRelCuboid (
int a_MinX , int a_MaxX ,
int a_MinY , int a_MaxY ,
int a_MinZ , int a_MaxZ ,
BLOCKTYPE a_DstType , NIBBLETYPE a_DstMeta
)
{
int MinX = std : : max ( a_MinX , 0 ) ;
int MinY = std : : max ( a_MinY , 0 ) ;
int MinZ = std : : max ( a_MinZ , 0 ) ;
int MaxX = std : : min ( a_MaxX , cChunkDef : : Width - 1 ) ;
int MaxY = std : : min ( a_MaxY , cChunkDef : : Height - 1 ) ;
int MaxZ = std : : min ( a_MaxZ , cChunkDef : : Width - 1 ) ;
2013-11-16 13:58:17 -05:00
2013-07-29 07:13:03 -04:00
for ( int y = MinY ; y < = MaxY ; y + + )
{
for ( int z = MinZ ; z < = MaxZ ; z + + )
{
for ( int x = MinX ; x < = MaxX ; x + + )
{
switch ( GetBlockType ( x , y , z ) )
{
case E_BLOCK_AIR :
case E_BLOCK_WATER :
case E_BLOCK_STATIONARY_WATER :
{
SetBlockTypeMeta ( x , y , z , a_DstType , a_DstMeta ) ;
break ;
}
} // switch (GetBlockType)
} // for x
} // for z
} // for y
}
void cChunkDesc : : RandomFillRelCuboid (
int a_MinX , int a_MaxX ,
int a_MinY , int a_MaxY ,
int a_MinZ , int a_MaxZ ,
BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta ,
int a_RandomSeed , int a_ChanceOutOf10k
)
{
cNoise Noise ( a_RandomSeed ) ;
int MinX = std : : max ( a_MinX , 0 ) ;
int MinY = std : : max ( a_MinY , 0 ) ;
int MinZ = std : : max ( a_MinZ , 0 ) ;
int MaxX = std : : min ( a_MaxX , cChunkDef : : Width - 1 ) ;
int MaxY = std : : min ( a_MaxY , cChunkDef : : Height - 1 ) ;
int MaxZ = std : : min ( a_MaxZ , cChunkDef : : Width - 1 ) ;
2013-11-16 13:58:17 -05:00
2013-07-29 07:13:03 -04:00
for ( int y = MinY ; y < = MaxY ; y + + )
{
for ( int z = MinZ ; z < = MaxZ ; z + + )
{
for ( int x = MinX ; x < = MaxX ; x + + )
{
int rnd = ( Noise . IntNoise3DInt ( x , y , z ) / 7 ) % 10000 ;
if ( rnd < = a_ChanceOutOf10k )
{
SetBlockTypeMeta ( x , y , z , a_BlockType , a_BlockMeta ) ;
}
}
} // for z
} // for y
}
2013-11-14 09:37:09 -05:00
cBlockEntity * cChunkDesc : : GetBlockEntity ( int a_RelX , int a_RelY , int a_RelZ )
2013-07-29 07:13:03 -04:00
{
2013-11-14 09:37:09 -05:00
int AbsX = a_RelX + m_ChunkX * cChunkDef : : Width ;
int AbsZ = a_RelZ + m_ChunkZ * cChunkDef : : Width ;
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , end = m_BlockEntities . end ( ) ; itr ! = end ; + + itr )
{
if ( ( ( * itr ) - > GetPosX ( ) = = AbsX ) & & ( ( * itr ) - > GetPosY ( ) = = a_RelY ) & & ( ( * itr ) - > GetPosZ ( ) = = AbsZ ) )
{
2013-11-15 05:33:24 -05:00
// Already in the list:
if ( ( * itr ) - > GetBlockType ( ) ! = GetBlockType ( a_RelX , a_RelY , a_RelZ ) )
{
// Wrong type, the block type has been overwritten. Erase and create new:
m_BlockEntities . erase ( itr ) ;
break ;
}
// Correct type, already present. Return it:
2013-11-14 09:37:09 -05:00
return * itr ;
}
} // for itr - m_BlockEntities[]
// The block entity is not created yet, try to create it and add to list:
cBlockEntity * be = cBlockEntity : : CreateByBlockType ( GetBlockType ( a_RelX , a_RelY , a_RelZ ) , GetBlockMeta ( a_RelX , a_RelY , a_RelZ ) , AbsX , a_RelY , AbsZ ) ;
2014-10-20 16:55:07 -04:00
if ( be = = nullptr )
2013-11-14 09:37:09 -05:00
{
// No block entity for this block type
2014-10-20 16:55:07 -04:00
return nullptr ;
2013-11-14 09:37:09 -05:00
}
m_BlockEntities . push_back ( be ) ;
return be ;
2013-07-29 07:13:03 -04:00
}
2014-01-30 11:41:57 -05:00
void cChunkDesc : : UpdateHeightmap ( void )
{
for ( int x = 0 ; x < cChunkDef : : Width ; x + + )
{
for ( int z = 0 ; z < cChunkDef : : Width ; z + + )
{
int Height = 0 ;
for ( int y = cChunkDef : : Height - 1 ; y > 0 ; y - - )
{
BLOCKTYPE BlockType = GetBlockType ( x , y , z ) ;
if ( BlockType ! = E_BLOCK_AIR )
{
Height = y ;
break ;
}
} // for y
SetHeight ( x , z , Height ) ;
} // for z
} // for x
}
2013-07-29 07:13:03 -04:00
void cChunkDesc : : CompressBlockMetas ( cChunkDef : : BlockNibbles & a_DestMetas )
{
const NIBBLETYPE * AreaMetas = m_BlockArea . GetBlockMetas ( ) ;
2013-12-20 10:01:34 -05:00
for ( size_t i = 0 ; i < ARRAYCOUNT ( a_DestMetas ) ; i + + )
2013-07-29 07:13:03 -04:00
{
a_DestMetas [ i ] = AreaMetas [ 2 * i ] | ( AreaMetas [ 2 * i + 1 ] < < 4 ) ;
}
}
# ifdef _DEBUG
void cChunkDesc : : VerifyHeightmap ( void )
{
for ( int x = 0 ; x < cChunkDef : : Width ; x + + )
{
for ( int z = 0 ; z < cChunkDef : : Width ; z + + )
{
for ( int y = cChunkDef : : Height - 1 ; y > 0 ; y - - )
{
BLOCKTYPE BlockType = GetBlockType ( x , y , z ) ;
if ( BlockType ! = E_BLOCK_AIR )
{
int Height = GetHeight ( x , z ) ;
ASSERT ( Height = = y ) ;
break ;
}
} // for y
} // for z
} // for x
}
# endif // _DEBUG