1
0

Implemented Chunk Sparsing with segments

This commit is contained in:
Tycho 2014-04-26 10:50:23 -07:00
parent 01546020fc
commit e40f9d6e5b
17 changed files with 612 additions and 403 deletions

View File

@ -9,7 +9,7 @@
#include "OSSupport/GZipFile.h" #include "OSSupport/GZipFile.h"
#include "Blocks/BlockHandler.h" #include "Blocks/BlockHandler.h"
#include "Cuboid.h" #include "Cuboid.h"
#include "ChunkBuffer.h"
@ -1909,14 +1909,11 @@ bool cBlockArea::cChunkReader::Coords(int a_ChunkX, int a_ChunkZ)
void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes) void cBlockArea::cChunkReader::ChunkBuffer(const cChunkBuffer & a_BlockBuffer)
{ {
if (m_Area.m_BlockTypes == NULL) { // BlockTypes
if (!(m_Area.m_BlockTypes == NULL))
{ {
// Don't want BlockTypes
return;
}
int SizeY = m_Area.m_Size.y; int SizeY = m_Area.m_Size.y;
int MinY = m_Origin.y; int MinY = m_Origin.y;
@ -1971,54 +1968,29 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
{ {
int ChunkX = BaseX + x; int ChunkX = BaseX + x;
int AreaX = OffX + x; int AreaX = OffX + x;
m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetBlock(a_BlockTypes, ChunkX, ChunkY, ChunkZ); m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = a_BlockBuffer.GetBlock(ChunkX, ChunkY, ChunkZ);
} // for x } // for x
} // for z } // for z
} // for y } // for y
} }
void cBlockArea::cChunkReader::BlockMeta(const NIBBLETYPE * a_BlockMetas)
{
if (m_Area.m_BlockMetas == NULL)
{
// Don't want metas
return;
}
CopyNibbles(m_Area.m_BlockMetas, a_BlockMetas);
} }
if (m_Area.m_BlockMetas)
void cBlockArea::cChunkReader::BlockLight(const NIBBLETYPE * a_BlockLight)
{ {
if (m_Area.m_BlockLight == NULL) a_BlockBuffer.CopyMeta(m_Area.m_BlockMetas);
{
// Don't want light
return;
}
CopyNibbles(m_Area.m_BlockLight, a_BlockLight);
} }
if (m_Area.m_BlockLight)
void cBlockArea::cChunkReader::BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight)
{ {
if (m_Area.m_BlockSkyLight == NULL) a_BlockBuffer.CopyLight(m_Area.m_BlockLight);
{
// Don't want skylight
return;
}
CopyNibbles(m_Area.m_BlockSkyLight, a_BlockSkyLight);
} }
if (m_Area.m_BlockSkyLight)
{
a_BlockBuffer.CopySkyLight(m_Area.m_BlockSkyLight);
}
}

View File

@ -317,10 +317,7 @@ protected:
// cChunkDataCallback overrides: // cChunkDataCallback overrides:
virtual bool Coords (int a_ChunkX, int a_ChunkZ) override; virtual bool Coords (int a_ChunkX, int a_ChunkZ) override;
virtual void BlockTypes (const BLOCKTYPE * a_BlockTypes) override; virtual void ChunkBuffer (const cChunkBuffer & a_BlockTypes) override;
virtual void BlockMeta (const NIBBLETYPE * a_BlockMetas) override;
virtual void BlockLight (const NIBBLETYPE * a_BlockLight) override;
virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override;
} ; } ;
typedef NIBBLETYPE * NIBBLEARRAY; typedef NIBBLETYPE * NIBBLEARRAY;

View File

@ -241,23 +241,9 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback)
a_Callback.HeightMap (&m_HeightMap); a_Callback.HeightMap (&m_HeightMap);
a_Callback.BiomeData (&m_BiomeMap); a_Callback.BiomeData (&m_BiomeMap);
std::vector<BLOCKTYPE> Blocks = m_BlockTypes;
Blocks.resize(NumBlocks);
a_Callback.BlockTypes (&Blocks[0]);
std::vector<NIBBLETYPE> Metas = m_BlockMeta;
Metas.resize(NumBlocks / 2);
a_Callback.BlockMeta (&Metas[0]);
a_Callback.LightIsValid (m_IsLightValid); a_Callback.LightIsValid (m_IsLightValid);
std::vector<NIBBLETYPE> BlockLights = m_BlockLight; a_Callback.ChunkBuffer (m_ChunkBuffer);
BlockLights.resize(NumBlocks / 2);
a_Callback.BlockLight (&BlockLights[0]);
std::vector<NIBBLETYPE> BlockSkyLights = m_BlockSkyLight;
BlockSkyLights.resize(NumBlocks / 2, 0xff);
a_Callback.BlockSkyLight(&BlockSkyLights[0]);
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
{ {
@ -296,48 +282,10 @@ void cChunk::SetAllData(
CalculateHeightmap(a_BlockTypes); CalculateHeightmap(a_BlockTypes);
} }
int IdxWhereNonEmptyStarts = 0; m_ChunkBuffer.SetBlocks (a_BlockTypes);
{ // Blocktype compression m_ChunkBuffer.SetMeta (a_BlockMeta);
unsigned char Highest = 0; m_ChunkBuffer.SetLight (a_BlockLight);
int X = 0, Z = 0; m_ChunkBuffer.SetSkyLight (a_BlockSkyLight);
m_BlockTypes.clear();
for (int x = 0; x < Width; x++)
{
for (int z = 0; z < Width; z++)
{
unsigned char Height = m_HeightMap[x + z * Width];
if (Height > Highest)
{
Highest = Height;
X = x; Z = z;
}
}
}
IdxWhereNonEmptyStarts = MakeIndexNoCheck(X, Highest + 1, Z);
m_BlockTypes.insert(m_BlockTypes.end(), &a_BlockTypes[0], &a_BlockTypes[IdxWhereNonEmptyStarts]);
}
{ // Blockmeta compression
m_BlockMeta.clear();
m_BlockMeta.insert(m_BlockMeta.end(), &a_BlockMeta[0], &a_BlockMeta[IdxWhereNonEmptyStarts / 2]);
}
if (a_BlockLight != NULL)
{
// Compress blocklight
m_BlockLight.clear();
m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[IdxWhereNonEmptyStarts / 2]);
}
if (a_BlockSkyLight != NULL)
{
// Compress skylight
m_BlockSkyLight.clear();
m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_BlockSkyLight[0], &a_BlockSkyLight[IdxWhereNonEmptyStarts / 2]);
}
m_IsLightValid = (a_BlockLight != NULL) && (a_BlockSkyLight != NULL); m_IsLightValid = (a_BlockLight != NULL) && (a_BlockSkyLight != NULL);
@ -378,39 +326,9 @@ void cChunk::SetLight(
// TODO: We might get cases of wrong lighting when a chunk changes in the middle of a lighting calculation. // TODO: We might get cases of wrong lighting when a chunk changes in the middle of a lighting calculation.
// Postponing until we see how bad it is :) // Postponing until we see how bad it is :)
{ // Compress blocklight m_ChunkBuffer.SetLight (a_BlockLight);
bool FoundNonEmpty = false;
int IdxWhereNonEmptyStarts = 0;
m_BlockLight.clear();
for (int Idx = (NumBlocks / 2) - 1; Idx >= 0; Idx--) m_ChunkBuffer.SetSkyLight (a_SkyLight);
{
if (a_BlockLight[Idx] != 0)
{
FoundNonEmpty = true;
IdxWhereNonEmptyStarts = Idx;
break;
}
}
m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[IdxWhereNonEmptyStarts + 1]);
}
{ // Compress skylight
bool FoundNonEmpty = false;
int IdxWhereNonEmptyStarts = 0;
m_BlockSkyLight.clear();
for (int Idx = (NumBlocks / 2) - 1; Idx >= 0; Idx--)
{
if (a_SkyLight[Idx] != 0xff)
{
FoundNonEmpty = true;
IdxWhereNonEmptyStarts = Idx;
break;
}
}
m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[IdxWhereNonEmptyStarts + 1]);
}
m_IsLightValid = true; m_IsLightValid = true;
} }
@ -421,10 +339,7 @@ void cChunk::SetLight(
void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes) void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes)
{ {
std::vector<BLOCKTYPE> Blocks = m_BlockTypes; m_ChunkBuffer.CopyBlocks(a_BlockTypes);
Blocks.resize(NumBlocks);
memcpy(a_BlockTypes, &Blocks[0], NumBlocks);
} }
@ -710,8 +625,7 @@ void cChunk::Tick(float a_Dt)
void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ) void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ)
{ {
unsigned Index = MakeIndex(a_RelX, a_RelY, a_RelZ); cBlockHandler * Handler = BlockHandler(GetBlock(a_RelX, a_RelY, a_RelZ));
cBlockHandler * Handler = BlockHandler(GetBlock(Index));
ASSERT(Handler != NULL); // Happenned on server restart, FS #243 ASSERT(Handler != NULL); // Happenned on server restart, FS #243
cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap()); cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*this->GetWorld()); cBlockInServerPluginInterface PluginInterface(*this->GetWorld());
@ -836,19 +750,18 @@ void cChunk::CheckBlocks()
{ {
return; return;
} }
std::vector<unsigned int> ToTickBlocks; std::vector<Vector3i> ToTickBlocks;
std::swap(m_ToTickBlocks, ToTickBlocks); std::swap(m_ToTickBlocks, ToTickBlocks);
cChunkInterface ChunkInterface(m_World->GetChunkMap()); cChunkInterface ChunkInterface(m_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*m_World); cBlockInServerPluginInterface PluginInterface(*m_World);
for (std::vector<unsigned int>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr) for (std::vector<Vector3i>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr)
{ {
unsigned int index = (*itr); Vector3i Pos = (*itr);
Vector3i BlockPos = IndexToCoordinate(index);
cBlockHandler * Handler = BlockHandler(GetBlock(index)); cBlockHandler * Handler = BlockHandler(GetBlock(Pos));
Handler->Check(ChunkInterface, PluginInterface, BlockPos.x, BlockPos.y, BlockPos.z, *this); Handler->Check(ChunkInterface, PluginInterface, Pos.x, Pos.y, Pos.z, *this);
} // for itr - ToTickBlocks[] } // for itr - ToTickBlocks[]
} }
@ -891,8 +804,7 @@ void cChunk::TickBlocks(void)
continue; // It's all air up here continue; // It's all air up here
} }
unsigned int Index = MakeIndexNoCheck(m_BlockTickX, m_BlockTickY, m_BlockTickZ); cBlockHandler * Handler = BlockHandler(GetBlock(m_BlockTickX, m_BlockTickY, m_BlockTickZ));
cBlockHandler * Handler = BlockHandler(GetBlock(Index));
ASSERT(Handler != NULL); // Happenned on server restart, FS #243 ASSERT(Handler != NULL); // Happenned on server restart, FS #243
Handler->OnUpdate(ChunkInterface, *this->GetWorld(), PluginInterface, *this, m_BlockTickX, m_BlockTickY, m_BlockTickZ); Handler->OnUpdate(ChunkInterface, *this->GetWorld(), PluginInterface, *this, m_BlockTickX, m_BlockTickY, m_BlockTickZ);
} // for i - tickblocks } // for i - tickblocks
@ -1284,9 +1196,8 @@ bool cChunk::UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBB
// The chunk is not available, bail out // The chunk is not available, bail out
return false; return false;
} }
int idx = Chunk->MakeIndex(a_RelX, a_RelY, a_RelZ); a_BlockLight = Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ);
a_BlockLight = Chunk->GetBlockLight(idx); a_SkyLight = Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ);
a_SkyLight = Chunk->GetSkyLight(idx);
return true; return true;
} }
@ -1491,10 +1402,8 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
{ {
FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta);
const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
// Tick this block and its neighbors: // Tick this block and its neighbors:
m_ToTickBlocks.push_back(index); m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ); QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ);
// If there was a block entity, remove it: // If there was a block entity, remove it:
@ -1557,7 +1466,7 @@ void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
return; return;
} }
m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)); m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
} }
@ -1595,9 +1504,8 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
ASSERT(IsValid()); ASSERT(IsValid());
const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); const BLOCKTYPE OldBlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
const BLOCKTYPE OldBlockType = GetBlock(index); const BLOCKTYPE OldBlockMeta = m_ChunkBuffer.GetMeta(a_RelX, a_RelY, a_RelZ);
const BLOCKTYPE OldBlockMeta = GetNibble(m_BlockMeta, index);
if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta)) if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta))
{ {
return; return;
@ -1605,11 +1513,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
MarkDirty(); MarkDirty();
if (m_BlockTypes.empty() || ((size_t)index > m_BlockTypes.size() - 1) /* Vector starts from zero, .size() starts from 1 */) m_ChunkBuffer.SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType);
{
m_BlockTypes.resize(index + 1);
}
m_BlockTypes[index] = a_BlockType;
// The client doesn't need to distinguish between stationary and nonstationary fluids: // The client doesn't need to distinguish between stationary and nonstationary fluids:
if ( if (
@ -1625,7 +1529,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta)); m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta));
} }
SetNibble(m_BlockMeta, index, a_BlockMeta); m_ChunkBuffer.SetMeta(a_RelX, a_RelY, a_RelZ, a_BlockMeta);
// ONLY recalculate lighting if it's necessary! // ONLY recalculate lighting if it's necessary!
if ( if (
@ -1648,7 +1552,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
{ {
for (int y = a_RelY - 1; y > 0; --y) for (int y = a_RelY - 1; y > 0; --y)
{ {
if (GetBlock(MakeIndexNoCheck(a_RelX, y, a_RelZ)) != E_BLOCK_AIR) if (GetBlock(a_RelX, y, a_RelZ) != E_BLOCK_AIR)
{ {
m_HeightMap[a_RelX + a_RelZ * Width] = (unsigned char)y; m_HeightMap[a_RelX + a_RelZ * Width] = (unsigned char)y;
break; break;
@ -1665,18 +1569,16 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client) void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client)
{ {
// The coords must be valid, because the upper level already does chunk lookup. No need to check them again. // The coords must be valid, because the upper level already does chunk lookup. No need to check them again.
// There's an debug-time assert in MakeIndexNoCheck anyway
unsigned int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
if (a_Client == NULL) if (a_Client == NULL)
{ {
// Queue the block for all clients in the chunk (will be sent in Tick()) // Queue the block for all clients in the chunk (will be sent in Tick())
m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(index), GetMeta(index))); m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ)));
return; return;
} }
Vector3i wp = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ); Vector3i wp = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ);
a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(index), GetMeta(index)); a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ));
// FS #268 - if a BlockEntity digging is cancelled by a plugin, the entire block entity must be re-sent to the client: // FS #268 - if a BlockEntity digging is cancelled by a plugin, the entire block entity must be re-sent to the client:
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), end = m_BlockEntities.end(); itr != end; ++itr) for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), end = m_BlockEntities.end(); itr != end; ++itr)
@ -2535,27 +2437,7 @@ BLOCKTYPE cChunk::GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
return 0; // Clip return 0; // Clip
} }
return GetBlock(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)); return m_ChunkBuffer.GetBlock(a_RelX, a_RelY, a_RelZ);
}
BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const
{
if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks))
{
ASSERT(!"GetBlock(idx) out of bounds!");
return 0;
}
if (m_BlockTypes.empty() || ((size_t)a_BlockIdx > m_BlockTypes.size() - 1) /* Vector starts from zero, .size() starts from 1 */)
{
return E_BLOCK_AIR;
}
return m_BlockTypes[a_BlockIdx];
} }
@ -2564,9 +2446,8 @@ BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const
void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
{ {
int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
a_BlockType = GetBlock(Idx); a_BlockMeta = m_ChunkBuffer.GetMeta(a_RelX, a_RelY, a_RelZ);
a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Idx);
} }
@ -2575,11 +2456,10 @@ void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_
void cChunk::GetBlockInfo(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight) void cChunk::GetBlockInfo(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight)
{ {
int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
a_BlockType = GetBlock(Idx); a_Meta = m_ChunkBuffer.GetMeta(a_RelX, a_RelY, a_RelZ);
a_Meta = cChunkDef::GetNibble(m_BlockMeta, Idx); a_SkyLight = m_ChunkBuffer.GetSkyLight(a_RelX, a_RelY, a_RelZ);
a_SkyLight = cChunkDef::GetNibble(m_BlockSkyLight, Idx); a_BlockLight = m_ChunkBuffer.GetBlockLight(a_RelX, a_RelY, a_RelZ);
a_BlockLight = cChunkDef::GetNibble(m_BlockLight, Idx);
} }

View File

@ -3,6 +3,7 @@
#include "Entities/Entity.h" #include "Entities/Entity.h"
#include "ChunkDef.h" #include "ChunkDef.h"
#include "ChunkBuffer.h"
#include "Simulator/FireSimulator.h" #include "Simulator/FireSimulator.h"
#include "Simulator/SandSimulator.h" #include "Simulator/SandSimulator.h"
@ -66,6 +67,7 @@ public:
cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects
cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP // Neighbor chunks cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP // Neighbor chunks
); );
cChunk(cChunk& other);
~cChunk(); ~cChunk();
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk block data is valid (loaded / generated) bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk block data is valid (loaded / generated)
@ -154,7 +156,7 @@ public:
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc. void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const; BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const;
BLOCKTYPE GetBlock(int a_BlockIdx) const; BLOCKTYPE GetBlock(Vector3i a_cords) const { return GetBlock(a_cords.x,a_cords.y,a_cords.z);}
void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
@ -320,15 +322,17 @@ public:
m_BlockTickZ = a_RelZ; m_BlockTickZ = a_RelZ;
} }
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); } inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
inline NIBBLETYPE GetMeta(int a_BlockIdx) const {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); } {
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); } return m_ChunkBuffer.GetMeta(a_RelX, a_RelY, a_RelZ);
inline void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_BlockIdx, a_Meta); } }
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
{
m_ChunkBuffer.SetMeta(a_RelX, a_RelY, a_RelZ, a_Meta);
}
inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); } inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkBuffer.GetBlockLight(a_RelX, a_RelY, a_RelZ); }
inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ, true); } inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkBuffer.GetSkyLight(a_RelX, a_RelY, a_RelZ); }
inline NIBBLETYPE GetBlockLight(int a_Idx) const {return cChunkDef::GetNibble(m_BlockLight, a_Idx); }
inline NIBBLETYPE GetSkyLight (int a_Idx) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_Idx, true); }
/** Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */ /** Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
@ -403,7 +407,7 @@ private:
bool m_IsSaving; // True if the chunk is being saved bool m_IsSaving; // True if the chunk is being saved
bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then
std::vector<unsigned int> m_ToTickBlocks; std::vector<Vector3i> m_ToTickBlocks;
sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients
sSetBlockQueueVector m_SetBlockQueue; ///< Block changes that are queued to a specific tick sSetBlockQueueVector m_SetBlockQueue; ///< Block changes that are queued to a specific tick
@ -420,11 +424,7 @@ private:
cWorld * m_World; cWorld * m_World;
cChunkMap * m_ChunkMap; cChunkMap * m_ChunkMap;
// TODO: Make these pointers and don't allocate what isn't needed cChunkBuffer m_ChunkBuffer;
std::vector<BLOCKTYPE> m_BlockTypes;
std::vector<NIBBLETYPE> m_BlockMeta;
std::vector<NIBBLETYPE> m_BlockLight;
std::vector<NIBBLETYPE> m_BlockSkyLight;
cChunkDef::HeightMap m_HeightMap; cChunkDef::HeightMap m_HeightMap;
cChunkDef::BiomeMap m_BiomeMap; cChunkDef::BiomeMap m_BiomeMap;

146
src/ChunkBuffer.cpp Normal file
View File

@ -0,0 +1,146 @@
#include "Globals.h"
#include "ChunkBuffer.h"
cChunkBuffer cChunkBuffer::Copy() const
{
cChunkBuffer copy;
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
if(m_Sections[i])
{
copy.m_Sections[i] = Allocate();
*copy.m_Sections[i] = *m_Sections[i];
}
}
return copy;
}
void cChunkBuffer::CopyBlocks (BLOCKTYPE * a_dest, size_t a_Idx, size_t length) const
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16;
if (a_Idx > 0) a_Idx = a_Idx > length ? a_Idx - length : 0;
if (a_Idx == 0)
{
size_t tocopy = length > segment_length ? segment_length : length;
length -= tocopy;
memcpy(&a_dest[i * segment_length], &m_Sections[i]->m_BlockTypes, sizeof(BLOCKTYPE) * length);
}
}
}
void cChunkBuffer::CopyMeta(NIBBLETYPE * a_dest) const
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
memcpy(&a_dest[i * segment_length], &m_Sections[i]->m_BlockMeta, sizeof(NIBBLETYPE) * segment_length);
}
}
void cChunkBuffer::CopyLight(NIBBLETYPE * a_dest) const
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
memcpy(&a_dest[i * segment_length], &m_Sections[i]->m_BlockLight, sizeof(NIBBLETYPE) * segment_length);
}
}
void cChunkBuffer::CopySkyLight(NIBBLETYPE * a_dest) const
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
memcpy(&a_dest[i * segment_length], &m_Sections[i]->m_BlockSkyLight, sizeof(NIBBLETYPE) * segment_length);
}
}
void cChunkBuffer::SetBlocks(const BLOCKTYPE * a_src)
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
if (m_Sections[i])
{
memcpy(&m_Sections[i]->m_BlockTypes, &a_src[i * segment_length], sizeof(BLOCKTYPE) * segment_length);
}
}
}
void cChunkBuffer::SetMeta(const NIBBLETYPE * a_src)
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
if (m_Sections[i])
{
memcpy(&m_Sections[i]->m_BlockMeta, &a_src[i * segment_length], sizeof(NIBBLETYPE) * segment_length);
}
}
}
void cChunkBuffer::SetLight(const NIBBLETYPE * a_src)
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
if (m_Sections[i])
{
memcpy(&m_Sections[i]->m_BlockLight, &a_src[i * segment_length], sizeof(NIBBLETYPE) * segment_length);
}
}
}
void cChunkBuffer::SetSkyLight (const NIBBLETYPE * a_src)
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
if (m_Sections[i])
{
memcpy(&m_Sections[i]->m_BlockSkyLight, &a_src[i * segment_length], sizeof(NIBBLETYPE) * segment_length);
}
}
}
cChunkBuffer::sChunkSection * cChunkBuffer::Allocate() const
{
// TODO: use a allocation pool
return new cChunkBuffer::sChunkSection;
}

310
src/ChunkBuffer.h Normal file
View File

@ -0,0 +1,310 @@
#pragma once
#define CHUNK_SECTION_HEIGHT 16
#define CHUNK_SECTION_NUM (256 / CHUNK_SECTION_HEIGHT)
#if __cplusplus < 201103L
// auto_ptr style interface for memory management
#else
// unique_ptr style interface for memory management
#endif
class cChunkBuffer
{
public:
cChunkBuffer()
#if __cplusplus < 201103L
// auto_ptr style interface for memory management
: IsOwner(true)
#endif
{
memset(m_Sections, 0, sizeof(m_Sections));
}
~cChunkBuffer()
{
#if __cplusplus < 201103L
// auto_ptr style interface for memory management
if(!IsOwner) return;
#endif
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
if(m_Sections[i]) delete m_Sections[i];
}
}
#if __cplusplus < 201103L
// auto_ptr style interface for memory management
cChunkBuffer(cChunkBuffer& other) :
IsOwner(true);
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
m_Sections[i] = other.m_Sections[i];
}
other.IsOwner = false;
}
void operator=(cChunkBuffer& other)
{
if(IsOwner)
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
if(m_Sections[i]) delete m_Sections[i];
}
}
IsOwner = true;
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
m_Sections[i] = other.m_Sections[i];
}
other.IsOwner = false;
}
#else
// unique_ptr style interface for memory management
cChunkBuffer(cChunkBuffer&& other)
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
m_Sections[i] = other.m_Sections[i];
}
}
void operator=(cChunkBuffer&& other)
{
for (int i = 0; i < CHUNK_SECTION_NUM; i++)
{
if(m_Sections[i]) delete m_Sections[i];
m_Sections[i] = other.m_Sections[i];
}
}
#endif
BLOCKTYPE GetBlock(int a_X, int a_Y, int a_Z) const
{
ASSERT((a_X >= 0) && (a_X < cChunkDef::Width));
ASSERT((a_Y >= 0) && (a_Y < cChunkDef::Height));
ASSERT((a_Z >= 0) && (a_Z < cChunkDef::Width));
int Section = a_Y / CHUNK_SECTION_HEIGHT;
if(m_Sections[Section])
{
int Index = cChunkDef::MakeIndexNoCheck(a_X, a_Y - (Section * CHUNK_SECTION_HEIGHT), a_Z);
return m_Sections[Section]->m_BlockTypes[Index];
}
else
{
return 0;
}
}
void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block)
{
if (
(a_RelX >= cChunkDef::Width) || (a_RelX < 0) ||
(a_RelY >= cChunkDef::Height) || (a_RelY < 0) ||
(a_RelZ >= cChunkDef::Width) || (a_RelZ < 0)
)
{
ASSERT(!"cChunkBuffer::SetMeta(): index out of range!");
return;
}
int Section = a_RelY / CHUNK_SECTION_HEIGHT;
if(!m_Sections[Section])
{
m_Sections[Section] = Allocate();
if(!m_Sections[Section])
{
ASSERT("Failed to allocate a new section in Chunkbuffer");
return;
}
}
int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
m_Sections[Section]->m_BlockTypes[Index] = a_Block;
}
NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
{
if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1))
{
int Section = a_RelY / CHUNK_SECTION_HEIGHT;
if(m_Sections[Section])
{
int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
return (m_Sections[Section]->m_BlockMeta[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
}
else
{
return 0;
}
}
ASSERT(!"cChunkBuffer::GetMeta(): coords out of chunk range!");
return 0;
}
void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Nibble)
{
if (
(a_RelX >= cChunkDef::Width) || (a_RelX < 0) ||
(a_RelY >= cChunkDef::Height) || (a_RelY < 0) ||
(a_RelZ >= cChunkDef::Width) || (a_RelZ < 0)
)
{
ASSERT(!"cChunkBuffer::SetMeta(): index out of range!");
return;
}
int Section = a_RelY / CHUNK_SECTION_HEIGHT;
if(!m_Sections[Section])
{
m_Sections[Section] = Allocate();
if(!m_Sections[Section])
{
ASSERT("Failed to allocate a new section in Chunkbuffer");
return;
}
}
int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
m_Sections[Section]->m_BlockMeta[Index / 2] = static_cast<NIBBLETYPE>(
(m_Sections[Section]->m_BlockMeta[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble
((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set
);
}
NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const
{
if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1))
{
int Section = a_RelY / CHUNK_SECTION_HEIGHT;
if(m_Sections[Section])
{
int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
}
else
{
return 0;
}
}
ASSERT(!"cChunkBuffer::GetMeta(): coords out of chunk range!");
return 0;
}
NIBBLETYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const
{
if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1))
{
int Section = a_RelY / CHUNK_SECTION_HEIGHT;
if(m_Sections[Section])
{
int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
}
else
{
return 0xFF;
}
}
ASSERT(!"cChunkBuffer::GetMeta(): coords out of chunk range!");
return 0;
}
cChunkBuffer Copy() const;
void CopyBlocks (BLOCKTYPE * a_dest, size_t a_Idx = 0, size_t length = cChunkDef::NumBlocks) const;
void CopyMeta (NIBBLETYPE * a_dest) const;
void CopyLight (NIBBLETYPE * a_dest) const;
void CopySkyLight (NIBBLETYPE * a_dest) const;
void SetBlocks (const BLOCKTYPE * a_src);
void SetMeta (const NIBBLETYPE * a_src);
void SetLight (const NIBBLETYPE * a_src);
void SetSkyLight (const NIBBLETYPE * a_src);
private:
#if __cplusplus < 201103L
// auto_ptr style interface for memory management
bool IsOwner;
#endif
struct sChunkSection {
BLOCKTYPE m_BlockTypes [CHUNK_SECTION_HEIGHT * 16 * 16] ;
NIBBLETYPE m_BlockMeta [CHUNK_SECTION_HEIGHT * 16 * 16 / 2];
NIBBLETYPE m_BlockLight [CHUNK_SECTION_HEIGHT * 16 * 16 / 2];
NIBBLETYPE m_BlockSkyLight[CHUNK_SECTION_HEIGHT * 16 * 16 / 2];
};
sChunkSection *m_Sections[CHUNK_SECTION_NUM];
sChunkSection * Allocate() const;
};
/** A simple implementation of the cChunkDataCallback interface that collects all block data into a buffer
*/
class cChunkBufferCollector :
public cChunkDataCallback
{
public:
cChunkBuffer m_BlockData;
protected:
virtual void ChunkBuffer(const cChunkBuffer & a_BlockData) override
{
m_BlockData = a_BlockData.Copy();
}
};
/** A simple implementation of the cChunkDataCallback interface that collects all block data into a single buffer
*/
class cChunkDataCollector :
public cChunkDataCallback
{
public:
// Must be unsigned char instead of BLOCKTYPE or NIBBLETYPE, because it houses both.
unsigned char m_BlockData[cChunkDef::BlockDataSize];
protected:
virtual void ChunkBuffer(const cChunkBuffer & a_ChunkBuffer) override
{
a_ChunkBuffer.CopyBlocks(m_BlockData);
a_ChunkBuffer.CopyMeta(m_BlockData + cChunkDef::NumBlocks);
a_ChunkBuffer.CopyLight(m_BlockData + 3 * cChunkDef::NumBlocks / 2);
a_ChunkBuffer.CopySkyLight(m_BlockData + 2 * cChunkDef::NumBlocks);
}
};
/** A simple implementation of the cChunkDataCallback interface that collects all block data into a separate buffers
*/
class cChunkDataSeparateCollector :
public cChunkDataCallback
{
public:
cChunkDef::BlockTypes m_BlockTypes;
cChunkDef::BlockNibbles m_BlockMetas;
cChunkDef::BlockNibbles m_BlockLight;
cChunkDef::BlockNibbles m_BlockSkyLight;
protected:
virtual void ChunkBuffer(const cChunkBuffer & a_ChunkBuffer) override
{
a_ChunkBuffer.CopyBlocks(m_BlockTypes);
a_ChunkBuffer.CopyMeta(m_BlockMetas);
a_ChunkBuffer.CopyLight(m_BlockLight);
a_ChunkBuffer.CopySkyLight(m_BlockSkyLight);
}
} ;

View File

@ -366,6 +366,7 @@ public:
class cChunkBuffer;
/** Interface class used for getting data out of a chunk using the GetAllData() function. /** Interface class used for getting data out of a chunk using the GetAllData() function.
@ -390,20 +391,11 @@ public:
/// Called once to provide biome data /// Called once to provide biome data
virtual void BiomeData (const cChunkDef::BiomeMap * a_BiomeMap) {UNUSED(a_BiomeMap); }; virtual void BiomeData (const cChunkDef::BiomeMap * a_BiomeMap) {UNUSED(a_BiomeMap); };
/// Called once to export block types /// Called once to let know if the chunk lighting is valid. Return value is ignored
virtual void BlockTypes (const BLOCKTYPE * a_Type) {UNUSED(a_Type); }; virtual void LightIsValid(bool a_IsLightValid) {UNUSED(a_IsLightValid); };
/// Called once to export block meta /// Called once to export block info
virtual void BlockMeta (const NIBBLETYPE * a_Meta) {UNUSED(a_Meta); }; virtual void ChunkBuffer (const cChunkBuffer & a_Buffer) {UNUSED(a_Buffer); };
/// Called once to let know if the chunk lighting is valid. Return value is used to control if BlockLight() and BlockSkyLight() are called next (if true)
virtual bool LightIsValid(bool a_IsLightValid) {UNUSED(a_IsLightValid); return true; };
/// Called once to export block light
virtual void BlockLight (const NIBBLETYPE * a_BlockLight) {UNUSED(a_BlockLight); };
/// Called once to export sky light
virtual void BlockSkyLight(const NIBBLETYPE * a_SkyLight) {UNUSED(a_SkyLight); };
/// Called for each entity in the chunk /// Called for each entity in the chunk
virtual void Entity(cEntity * a_Entity) {UNUSED(a_Entity); }; virtual void Entity(cEntity * a_Entity) {UNUSED(a_Entity); };
@ -416,88 +408,6 @@ public:
/** A simple implementation of the cChunkDataCallback interface that collects all block data into a single buffer
*/
class cChunkDataCollector :
public cChunkDataCallback
{
public:
// Must be unsigned char instead of BLOCKTYPE or NIBBLETYPE, because it houses both.
unsigned char m_BlockData[cChunkDef::BlockDataSize];
protected:
virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override
{
memcpy(m_BlockData, a_BlockTypes, sizeof(cChunkDef::BlockTypes));
}
virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override
{
memcpy(m_BlockData + cChunkDef::NumBlocks, a_BlockMeta, cChunkDef::NumBlocks / 2);
}
virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override
{
memcpy(m_BlockData + 3 * cChunkDef::NumBlocks / 2, a_BlockLight, cChunkDef::NumBlocks / 2);
}
virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override
{
memcpy(m_BlockData + 2 * cChunkDef::NumBlocks, a_BlockSkyLight, cChunkDef::NumBlocks / 2);
}
} ;
/** A simple implementation of the cChunkDataCallback interface that collects all block data into a separate buffers
*/
class cChunkDataSeparateCollector :
public cChunkDataCallback
{
public:
cChunkDef::BlockTypes m_BlockTypes;
cChunkDef::BlockNibbles m_BlockMetas;
cChunkDef::BlockNibbles m_BlockLight;
cChunkDef::BlockNibbles m_BlockSkyLight;
protected:
virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override
{
memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes));
}
virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override
{
memcpy(m_BlockMetas, a_BlockMeta, sizeof(m_BlockMetas));
}
virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override
{
memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
}
virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override
{
memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight));
}
} ;
/** Interface class used for comparing clients of two chunks. /** Interface class used for comparing clients of two chunks.
Used primarily for entity moving while both chunks are locked. Used primarily for entity moving while both chunks are locked.
*/ */

View File

@ -219,9 +219,8 @@ bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY
return false; return false;
} }
int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ); a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
a_BlockType = Chunk->GetBlock(Index); a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ);
a_BlockMeta = Chunk->GetMeta(Index);
return true; return true;
} }
@ -242,8 +241,7 @@ bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLO
return false; return false;
} }
int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ); a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
a_BlockType = Chunk->GetBlock(Index);
return true; return true;
} }
@ -264,8 +262,7 @@ bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB
return false; return false;
} }
int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ); a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ);
a_BlockMeta = Chunk->GetMeta(Index);
return true; return true;
} }
@ -1486,9 +1483,8 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
res = false; res = false;
continue; continue;
} }
int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z); itr->BlockType = Chunk->GetBlock(itr->x, itr->y, itr->z);
itr->BlockType = Chunk->GetBlock(idx); itr->BlockMeta = Chunk->GetMeta(itr->x, itr->y, itr->z);
itr->BlockMeta = Chunk->GetMeta(idx);
} }
return res; return res;
} }

View File

@ -27,6 +27,7 @@ Note that it may be called by world's BroadcastToChunk() if the client is still
#include "OSSupport/IsThread.h" #include "OSSupport/IsThread.h"
#include "ChunkDef.h" #include "ChunkDef.h"
#include "ChunkBuffer.h"

View File

@ -55,9 +55,8 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
return; return;
} }
int idx = a_Chunk.MakeIndexNoCheck(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width); BLOCKTYPE BlockBelow = a_Chunk.GetBlock(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
BLOCKTYPE BlockBelow = a_Chunk.GetBlock(idx); NIBBLETYPE BelowMeta = a_Chunk.GetMeta(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
NIBBLETYPE BelowMeta = a_Chunk.GetMeta(idx);
if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta)) if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta))
{ {
// Fallen onto a block that breaks this into pickups (e. g. half-slab) // Fallen onto a block that breaks this into pickups (e. g. half-slab)

View File

@ -18,20 +18,17 @@
class cReader : class cReader :
public cChunkDataCallback public cChunkDataCallback
{ {
virtual void BlockTypes(const BLOCKTYPE * a_Type) override virtual void ChunkBuffer(const cChunkBuffer & a_ChunkBuffer) override
{ {
// ROW is a block of 16 Blocks, one whole row is copied at a time (hopefully the compiler will optimize that) BLOCKTYPE * OutputRows = m_BlockTypes;
// C++ doesn't permit copying arrays, but arrays as a part of a struct is ok :)
typedef struct {BLOCKTYPE m_Row[16]; } ROW;
ROW * InputRows = (ROW *)a_Type;
ROW * OutputRows = (ROW *)m_BlockTypes;
int InputIdx = 0; int InputIdx = 0;
int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3; int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
for (int y = 0; y < cChunkDef::Height; y++) for (int y = 0; y < cChunkDef::Height; y++)
{ {
for (int z = 0; z < cChunkDef::Width; z++) for (int z = 0; z < cChunkDef::Width; z++)
{ {
OutputRows[OutputIdx] = InputRows[InputIdx++]; a_ChunkBuffer.CopyBlocks(OutputRows + OutputIdx * 16, InputIdx * 16, 16);
InputIdx++;
OutputIdx += 3; OutputIdx += 3;
} // for z } // for z
// Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows // Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows

View File

@ -24,7 +24,8 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl
if (a_Distance < it->second.m_Distance) if (a_Distance < it->second.m_Distance)
{ {
it->second.m_Distance = a_Distance; it->second.m_Distance = a_Distance;
it->second.m_Chunk = a_Chunk; ASSERT(false);
//it->second.m_Chunk = a_Chunk;
} }
} }

View File

@ -95,8 +95,10 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
int NumMSecs = (int)a_Dt; int NumMSecs = (int)a_Dt;
for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();) for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();)
{ {
int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z); int x = itr->x;
BLOCKTYPE BlockType = a_Chunk->GetBlock(idx); int y = itr->y;
int z = itr->z;
BLOCKTYPE BlockType = a_Chunk->GetBlock(x,y,z);
if (!IsAllowedBlock(BlockType)) if (!IsAllowedBlock(BlockType))
{ {
@ -125,7 +127,7 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width
); );
*/ */
NIBBLETYPE BlockMeta = a_Chunk->GetMeta(idx); NIBBLETYPE BlockMeta = a_Chunk->GetMeta(x, y, z);
if (BlockMeta == 0x0f) if (BlockMeta == 0x0f)
{ {
// The fire burnt out completely // The fire burnt out completely
@ -140,7 +142,7 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
if((itr->y > 0) && (!DoesBurnForever(a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z)))) if((itr->y > 0) && (!DoesBurnForever(a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z))))
{ {
a_Chunk->SetMeta(idx, BlockMeta + 1); a_Chunk->SetMeta(x, y, z, BlockMeta + 1);
} }
itr->Data = GetBurnStepTime(a_Chunk, itr->x, itr->y, itr->z); // TODO: Add some randomness into this itr->Data = GetBurnStepTime(a_Chunk, itr->x, itr->y, itr->z); // TODO: Add some randomness into this
} // for itr - Data[] } // for itr - Data[]

View File

@ -692,10 +692,9 @@ void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Mineca
bool cNBTChunkSerializer::LightIsValid(bool a_IsLightValid) void cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
{ {
m_IsLightValid = a_IsLightValid; m_IsLightValid = a_IsLightValid;
return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother
} }

View File

@ -9,7 +9,7 @@
#pragma once #pragma once
#include "../ChunkDef.h" #include "../ChunkBuffer.h"
@ -121,7 +121,7 @@ protected:
void AddMinecartChestContents(cMinecartWithChest * a_Minecart); void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
// cChunkDataSeparateCollector overrides: // cChunkDataSeparateCollector overrides:
virtual bool LightIsValid(bool a_IsLightValid) override; virtual void LightIsValid(bool a_IsLightValid) override;
virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override; virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override;
virtual void Entity(cEntity * a_Entity) override; virtual void Entity(cEntity * a_Entity) override;
virtual void BlockEntity(cBlockEntity * a_Entity) override; virtual void BlockEntity(cBlockEntity * a_Entity) override;

View File

@ -107,15 +107,13 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity)
bool cJsonChunkSerializer::LightIsValid(bool a_IsLightValid) void cJsonChunkSerializer::LightIsValid(bool a_IsLightValid)
{ {
if (!a_IsLightValid) if (a_IsLightValid)
{ {
return false;
}
m_Root["IsLightValid"] = true; m_Root["IsLightValid"] = true;
m_HasJsonData = true; m_HasJsonData = true;
return true; }
} }

View File

@ -14,6 +14,7 @@
#include "WorldStorage.h" #include "WorldStorage.h"
#include "../Vector3.h" #include "../Vector3.h"
#include "json/json.h" #include "json/json.h"
#include "ChunkBuffer.h"
@ -42,7 +43,7 @@ protected:
// cChunkDataCollector overrides: // cChunkDataCollector overrides:
virtual void Entity (cEntity * a_Entity) override; virtual void Entity (cEntity * a_Entity) override;
virtual void BlockEntity (cBlockEntity * a_Entity) override; virtual void BlockEntity (cBlockEntity * a_Entity) override;
virtual bool LightIsValid (bool a_IsLightValid) override; virtual void LightIsValid (bool a_IsLightValid) override;
} ; } ;