80807eec2c
Changed a number of funcictions from using integers to store biomes to using EMCSBiome Note that switching from an int to an Enum is a non-breaking chang to the lua bindings
631 lines
12 KiB
C++
631 lines
12 KiB
C++
|
|
// 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"
|
|
#include "../Noise.h"
|
|
#include "../BlockEntities/BlockEntity.h"
|
|
|
|
|
|
|
|
|
|
|
|
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_bUseDefaultStructures(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);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cChunkDesc::SetBiome(int a_RelX, int a_RelZ, EMCSBiome a_BiomeID)
|
|
{
|
|
cChunkDef::SetBiome(m_BiomeMap, a_RelX, a_RelZ, a_BiomeID);
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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::SetUseDefaultStructures(bool a_bUseDefaultStructures)
|
|
{
|
|
m_bUseDefaultStructures = a_bUseDefaultStructures;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool cChunkDesc::IsUsingDefaultStructures(void) const
|
|
{
|
|
return m_bUseDefaultStructures;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
// 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;
|
|
}
|
|
else if (a_MinRelX >= cChunkDef::Width)
|
|
{
|
|
LOGWARNING("%s: MaxRelX more than chunk width, adjusting to chunk width", __FUNCTION__);
|
|
a_MaxRelX = cChunkDef::Width - 1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
else if (a_MinRelY >= cChunkDef::Height)
|
|
{
|
|
LOGWARNING("%s: MaxRelY more than chunk height, adjusting to chunk height", __FUNCTION__);
|
|
a_MaxRelY = cChunkDef::Height - 1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
else if (a_MinRelZ >= cChunkDef::Width)
|
|
{
|
|
LOGWARNING("%s: MaxRelZ more than chunk width, adjusting to chunk width", __FUNCTION__);
|
|
a_MaxRelZ = cChunkDef::Width - 1;
|
|
}
|
|
|
|
// 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();
|
|
a_Dest.m_OriginX = m_ChunkX * cChunkDef::Width + a_MinRelX;
|
|
a_Dest.m_OriginY = a_MinRelY;
|
|
a_Dest.m_OriginZ = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
|
|
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];
|
|
for (size_t i = 1; i < ARRAYCOUNT(m_HeightMap); i++)
|
|
{
|
|
if (m_HeightMap[i] > MaxHeight)
|
|
{
|
|
MaxHeight = m_HeightMap[i];
|
|
}
|
|
}
|
|
return MaxHeight;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ)
|
|
{
|
|
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))
|
|
{
|
|
// 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:
|
|
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);
|
|
if (be == NULL)
|
|
{
|
|
// No block entity for this block type
|
|
return NULL;
|
|
}
|
|
m_BlockEntities.push_back(be);
|
|
return be;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cChunkDesc::CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas)
|
|
{
|
|
const NIBBLETYPE * AreaMetas = m_BlockArea.GetBlockMetas();
|
|
for (size_t i = 0; i < ARRAYCOUNT(a_DestMetas); i++)
|
|
{
|
|
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
|
|
|
|
|
|
|
|
|
|
|