summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/ManualBindings.cpp4
-rw-r--r--src/BiomeDef.h2
-rw-r--r--src/BlockArea.cpp164
-rw-r--r--src/BlockArea.h8
-rw-r--r--src/Chunk.cpp185
-rw-r--r--src/Chunk.h37
-rw-r--r--src/ChunkData.cpp592
-rw-r--r--src/ChunkData.h125
-rw-r--r--src/ChunkDataCallback.h127
-rw-r--r--src/ChunkDef.h130
-rw-r--r--src/ChunkMap.cpp16
-rw-r--r--src/ChunkMap.h3
-rw-r--r--src/ChunkSender.h1
-rw-r--r--src/Entities/FallingBlock.cpp5
-rw-r--r--src/Globals.h70
-rw-r--r--src/LightingThread.cpp11
-rw-r--r--src/MobProximityCounter.cpp4
-rw-r--r--src/MobProximityCounter.h4
-rw-r--r--src/Simulator/FireSimulator.cpp10
-rw-r--r--src/StringUtils.h3
-rw-r--r--src/Vector3.h2
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp3
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h4
-rw-r--r--src/WorldStorage/WSSCompact.cpp10
-rw-r--r--src/WorldStorage/WSSCompact.h5
25 files changed, 1074 insertions, 451 deletions
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 10e560ac0..14d9d16fc 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -2864,8 +2864,8 @@ static int tolua_cCompositeChat_SetMessageType(lua_State * tolua_S)
}
// Set the type:
- int MessageType;
- L.GetStackValue(1, MessageType);
+ int MessageType = mtCustom;
+ L.GetStackValue(2, MessageType);
self->SetMessageType((eMessageType)MessageType);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
diff --git a/src/BiomeDef.h b/src/BiomeDef.h
index 67916890d..f929596e9 100644
--- a/src/BiomeDef.h
+++ b/src/BiomeDef.h
@@ -10,7 +10,7 @@
#pragma once
-
+#include "StringUtils.h"
// tolua_begin
diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp
index aff0bf9c6..40fdd68c0 100644
--- a/src/BlockArea.cpp
+++ b/src/BlockArea.cpp
@@ -9,7 +9,7 @@
#include "OSSupport/GZipFile.h"
#include "Blocks/BlockHandler.h"
#include "Cuboid.h"
-
+#include "ChunkData.h"
@@ -1835,116 +1835,88 @@ bool cBlockArea::cChunkReader::Coords(int a_ChunkX, int a_ChunkZ)
-void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
+void cBlockArea::cChunkReader::ChunkData(const cChunkData & a_BlockBuffer)
{
- if (m_Area.m_BlockTypes == NULL)
{
- // Don't want BlockTypes
- return;
- }
-
- int SizeY = m_Area.m_Size.y;
- int MinY = m_Origin.y;
-
- // SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
- // OffX, OffZ are the offsets of the current chunk data from the area origin
- // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders
- int SizeX = cChunkDef::Width;
- int SizeZ = cChunkDef::Width;
- int OffX, OffZ;
- int BaseX, BaseZ;
- OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
- if (OffX < 0)
- {
- BaseX = -OffX;
- SizeX += OffX; // SizeX is decreased, OffX is negative
- OffX = 0;
- }
- else
- {
- BaseX = 0;
- }
- OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
- if (OffZ < 0)
- {
- BaseZ = -OffZ;
- SizeZ += OffZ; // SizeZ is decreased, OffZ is negative
- OffZ = 0;
- }
- else
- {
- BaseZ = 0;
- }
- // If the chunk extends beyond the area in the X or Z axis, cut off the Size:
- if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
- {
- SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
- }
- if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
- {
- SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
- }
-
- for (int y = 0; y < SizeY; y++)
- {
- int ChunkY = MinY + y;
- int AreaY = y;
- for (int z = 0; z < SizeZ; z++)
+ if (m_Area.m_BlockTypes != NULL)
{
- int ChunkZ = BaseZ + z;
- int AreaZ = OffZ + z;
- for (int x = 0; x < SizeX; x++)
+ int SizeY = m_Area.m_Size.y;
+ int MinY = m_Origin.y;
+
+ // SizeX, SizeZ are the dimensions of the block data to copy from the current chunk (size of the geometric union)
+ // OffX, OffZ are the offsets of the current chunk data from the area origin
+ // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders
+ int SizeX = cChunkDef::Width;
+ int SizeZ = cChunkDef::Width;
+ int OffX, OffZ;
+ int BaseX, BaseZ;
+ OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
+ if (OffX < 0)
{
- int ChunkX = BaseX + x;
- int AreaX = OffX + x;
- m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetBlock(a_BlockTypes, ChunkX, ChunkY, ChunkZ);
- } // for x
- } // for z
- } // for y
-}
-
-
-
+ BaseX = -OffX;
+ SizeX += OffX; // SizeX is decreased, OffX is negative
+ OffX = 0;
+ }
+ else
+ {
+ BaseX = 0;
+ }
+ OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
+ if (OffZ < 0)
+ {
+ BaseZ = -OffZ;
+ SizeZ += OffZ; // SizeZ is decreased, OffZ is negative
+ OffZ = 0;
+ }
+ else
+ {
+ BaseZ = 0;
+ }
+ // If the chunk extends beyond the area in the X or Z axis, cut off the Size:
+ if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
+ {
+ SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
+ }
+ if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
+ {
+ SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
+ }
+ for (int y = 0; y < SizeY; y++)
+ {
+ int ChunkY = MinY + y;
+ int AreaY = y;
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int ChunkZ = BaseZ + z;
+ int AreaZ = OffZ + z;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int ChunkX = BaseX + x;
+ int AreaX = OffX + x;
+ m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = a_BlockBuffer.GetBlock(ChunkX, ChunkY, ChunkZ);
+ } // for x
+ } // for z
+ } // for y
+ }
+ }
-void cBlockArea::cChunkReader::BlockMeta(const NIBBLETYPE * a_BlockMetas)
-{
- if (m_Area.m_BlockMetas == NULL)
+ if (m_Area.m_BlockMetas != NULL)
{
- // Don't want metas
- return;
+ a_BlockBuffer.CopyMetas(m_Area.m_BlockMetas);
}
- CopyNibbles(m_Area.m_BlockMetas, a_BlockMetas);
-}
-
-
-
-
-void cBlockArea::cChunkReader::BlockLight(const NIBBLETYPE * a_BlockLight)
-{
- if (m_Area.m_BlockLight == NULL)
+ if (m_Area.m_BlockLight != NULL)
{
- // Don't want light
- return;
+ a_BlockBuffer.CopyBlockLight(m_Area.m_BlockLight);
}
- CopyNibbles(m_Area.m_BlockLight, a_BlockLight);
-}
-
-
-
-
-void cBlockArea::cChunkReader::BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight)
-{
- if (m_Area.m_BlockSkyLight == NULL)
+ if (m_Area.m_BlockSkyLight != NULL)
{
- // Don't want skylight
- return;
+ a_BlockBuffer.CopySkyLight(m_Area.m_BlockSkyLight);
}
- CopyNibbles(m_Area.m_BlockSkyLight, a_BlockSkyLight);
-}
+}
diff --git a/src/BlockArea.h b/src/BlockArea.h
index 6dba0f12e..2bd26facd 100644
--- a/src/BlockArea.h
+++ b/src/BlockArea.h
@@ -14,6 +14,7 @@
#include "ForEachChunkProvider.h"
#include "Vector3.h"
+#include "ChunkDataCallback.h"
@@ -316,11 +317,8 @@ protected:
void CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLETYPE * a_ChunkSrc);
// cChunkDataCallback overrides:
- virtual bool Coords (int a_ChunkX, int a_ChunkZ) override;
- virtual void BlockTypes (const BLOCKTYPE * 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;
+ virtual bool Coords(int a_ChunkX, int a_ChunkZ) override;
+ virtual void ChunkData(const cChunkData & a_BlockTypes) override;
} ;
typedef NIBBLETYPE * NIBBLEARRAY;
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index ca536e89a..23412a4c3 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -238,26 +238,12 @@ void cChunk::MarkLoadFailed(void)
void cChunk::GetAllData(cChunkDataCallback & a_Callback)
{
- a_Callback.HeightMap (&m_HeightMap);
- a_Callback.BiomeData (&m_BiomeMap);
+ a_Callback.HeightMap(&m_HeightMap);
+ a_Callback.BiomeData(&m_BiomeMap);
- COMPRESSED_BLOCKTYPE Blocks = m_BlockTypes;
- Blocks.resize(NumBlocks);
- a_Callback.BlockTypes (&Blocks[0]);
+ a_Callback.LightIsValid(m_IsLightValid);
- COMPRESSED_NIBBLETYPE Metas = m_BlockMeta;
- Metas.resize(NumBlocks / 2);
- a_Callback.BlockMeta (&Metas[0]);
-
- a_Callback.LightIsValid (m_IsLightValid);
-
- COMPRESSED_NIBBLETYPE BlockLights = m_BlockLight;
- BlockLights.resize(NumBlocks / 2);
- a_Callback.BlockLight (&BlockLights[0]);
-
- COMPRESSED_NIBBLETYPE BlockSkyLights = m_BlockSkyLight;
- BlockSkyLights.resize(NumBlocks / 2, 0xff);
- a_Callback.BlockSkyLight(&BlockSkyLights[0]);
+ a_Callback.ChunkData(m_ChunkData);
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
{
@@ -296,48 +282,10 @@ void cChunk::SetAllData(
CalculateHeightmap(a_BlockTypes);
}
- int IdxWhereNonEmptyStarts = 0;
- { // Blocktype compression
- unsigned char Highest = 0;
- int X = 0, Z = 0;
- 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_ChunkData.SetBlockTypes(a_BlockTypes);
+ m_ChunkData.SetMetas(a_BlockMeta);
+ m_ChunkData.SetBlockLight(a_BlockLight);
+ m_ChunkData.SetSkyLight(a_BlockSkyLight);
m_IsLightValid = (a_BlockLight != NULL) && (a_BlockSkyLight != NULL);
@@ -378,15 +326,9 @@ void cChunk::SetLight(
// 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 :)
- { // Compress blocklight
- m_BlockLight.clear();
- m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[m_BlockTypes.size() / 2]);
- }
+ m_ChunkData.SetBlockLight(a_BlockLight);
- { // Compress skylight
- m_BlockSkyLight.clear();
- m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size() / 2]);
- }
+ m_ChunkData.SetSkyLight(a_SkyLight);
m_IsLightValid = true;
}
@@ -397,8 +339,7 @@ void cChunk::SetLight(
void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes)
{
- std::copy(m_BlockTypes.begin(), m_BlockTypes.end(), a_BlockTypes);
- std::fill_n(&a_BlockTypes[m_BlockTypes.size()], NumBlocks - m_BlockTypes.size(), E_BLOCK_AIR);
+ m_ChunkData.CopyBlockTypes(a_BlockTypes);
}
@@ -684,8 +625,7 @@ void cChunk::Tick(float a_Dt)
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(Index));
+ cBlockHandler * Handler = BlockHandler(GetBlock(a_RelX, a_RelY, a_RelZ));
ASSERT(Handler != NULL); // Happenned on server restart, FS #243
cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*this->GetWorld());
@@ -810,19 +750,18 @@ void cChunk::CheckBlocks()
{
return;
}
- std::vector<unsigned int> ToTickBlocks;
+ std::vector<Vector3i> ToTickBlocks;
std::swap(m_ToTickBlocks, ToTickBlocks);
cChunkInterface ChunkInterface(m_World->GetChunkMap());
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 BlockPos = IndexToCoordinate(index);
+ Vector3i Pos = (*itr);
- cBlockHandler * Handler = BlockHandler(GetBlock(index));
- Handler->Check(ChunkInterface, PluginInterface, BlockPos.x, BlockPos.y, BlockPos.z, *this);
+ cBlockHandler * Handler = BlockHandler(GetBlock(Pos));
+ Handler->Check(ChunkInterface, PluginInterface, Pos.x, Pos.y, Pos.z, *this);
} // for itr - ToTickBlocks[]
}
@@ -865,8 +804,7 @@ void cChunk::TickBlocks(void)
continue; // It's all air up here
}
- unsigned int Index = MakeIndexNoCheck(m_BlockTickX, m_BlockTickY, m_BlockTickZ);
- cBlockHandler * Handler = BlockHandler(GetBlock(Index));
+ cBlockHandler * Handler = BlockHandler(GetBlock(m_BlockTickX, m_BlockTickY, m_BlockTickZ));
ASSERT(Handler != NULL); // Happenned on server restart, FS #243
Handler->OnUpdate(ChunkInterface, *this->GetWorld(), PluginInterface, *this, m_BlockTickX, m_BlockTickY, m_BlockTickZ);
} // for i - tickblocks
@@ -1258,9 +1196,8 @@ bool cChunk::UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBB
// The chunk is not available, bail out
return false;
}
- int idx = Chunk->MakeIndex(a_RelX, a_RelY, a_RelZ);
- a_BlockLight = Chunk->GetBlockLight(idx);
- a_SkyLight = Chunk->GetSkyLight(idx);
+ a_BlockLight = Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ);
+ a_SkyLight = Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ);
return true;
}
@@ -1465,11 +1402,9 @@ void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes)
void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE 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:
- m_ToTickBlocks.push_back(index);
+ m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ);
// If there was a block entity, remove it:
@@ -1533,7 +1468,7 @@ void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
return;
}
- m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ));
+ m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
}
@@ -1571,9 +1506,8 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
ASSERT(IsValid());
- const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
- const BLOCKTYPE OldBlockType = GetBlock(index);
- const BLOCKTYPE OldBlockMeta = GetNibble(m_BlockMeta, index);
+ const BLOCKTYPE OldBlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
+ const BLOCKTYPE OldBlockMeta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta))
{
return;
@@ -1581,11 +1515,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
MarkDirty();
- if ((size_t)index >= m_BlockTypes.size())
- {
- m_BlockTypes.resize(index + 1);
- }
- m_BlockTypes[index] = a_BlockType;
+ m_ChunkData.SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType);
// The client doesn't need to distinguish between stationary and nonstationary fluids:
if (
@@ -1601,7 +1531,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));
}
- SetNibble(m_BlockMeta, index, a_BlockMeta);
+ m_ChunkData.SetMeta(a_RelX, a_RelY, a_RelZ, a_BlockMeta);
// ONLY recalculate lighting if it's necessary!
if (
@@ -1624,7 +1554,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)
{
- 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;
break;
@@ -1638,39 +1568,18 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
-void cChunk::SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta)
-{
- if (GetNibble(m_BlockMeta, a_BlockIdx) == a_Meta)
- {
- return;
- }
-
- MarkDirty();
- SetNibble(m_BlockMeta, a_BlockIdx, a_Meta);
- Vector3i Coords(IndexToCoordinate(a_BlockIdx));
-
- m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, Coords.x, Coords.y, Coords.z, GetBlock(a_BlockIdx), a_Meta));
-}
-
-
-
-
-
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.
- // There's an debug-time assert in MakeIndexNoCheck anyway
- unsigned int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
if (a_Client == NULL)
{
// 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;
}
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:
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), end = m_BlockEntities.end(); itr != end; ++itr)
@@ -2529,27 +2438,7 @@ BLOCKTYPE cChunk::GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
return 0; // Clip
}
- return GetBlock(MakeIndexNoCheck(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 ((size_t)a_BlockIdx >= m_BlockTypes.size())
- {
- return E_BLOCK_AIR;
- }
-
- return m_BlockTypes[a_BlockIdx];
+ return m_ChunkData.GetBlock(a_RelX, a_RelY, a_RelZ);
}
@@ -2558,9 +2447,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)
{
- int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
- a_BlockType = GetBlock(Idx);
- a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Idx);
+ a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
+ a_BlockMeta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
}
@@ -2569,11 +2457,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)
{
- int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
- a_BlockType = GetBlock(Idx);
- a_Meta = cChunkDef::GetNibble(m_BlockMeta, Idx);
- a_SkyLight = cChunkDef::GetNibble(m_BlockSkyLight, Idx);
- a_BlockLight = cChunkDef::GetNibble(m_BlockLight, Idx);
+ a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
+ a_Meta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
+ a_SkyLight = m_ChunkData.GetSkyLight(a_RelX, a_RelY, a_RelZ);
+ a_BlockLight = m_ChunkData.GetBlockLight(a_RelX, a_RelY, a_RelZ);
}
diff --git a/src/Chunk.h b/src/Chunk.h
index 84ec35496..d95537acf 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -3,6 +3,7 @@
#include "Entities/Entity.h"
#include "ChunkDef.h"
+#include "ChunkData.h"
#include "Simulator/FireSimulator.h"
#include "Simulator/SandSimulator.h"
@@ -66,6 +67,7 @@ public:
cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects
cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP // Neighbor chunks
);
+ cChunk(cChunk & other);
~cChunk();
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.
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 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,23 @@ public:
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_BlockIdx) const { return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
- inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { SetMeta(MakeIndex(a_RelX, a_RelY, a_RelZ), a_Meta); }
- void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta);
+ inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
+ {
+ return m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
+ }
+ inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
+ {
+ bool hasChanged = m_ChunkData.SetMeta(a_RelX, a_RelY, a_RelZ, a_Meta);
+ if (hasChanged)
+ {
+ MarkDirty();
+
+ m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(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 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 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); }
+ inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetBlockLight(a_RelX, a_RelY, a_RelZ); }
+ inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetSkyLight(a_RelX, a_RelY, a_RelZ); }
/** 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;
@@ -403,8 +413,8 @@ private:
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
- std::vector<unsigned int> m_ToTickBlocks;
- sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients
+ std::vector<Vector3i> m_ToTickBlocks;
+ 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
@@ -420,10 +430,7 @@ private:
cWorld * m_World;
cChunkMap * m_ChunkMap;
- COMPRESSED_BLOCKTYPE m_BlockTypes;
- COMPRESSED_NIBBLETYPE m_BlockMeta;
- COMPRESSED_NIBBLETYPE m_BlockLight;
- COMPRESSED_NIBBLETYPE m_BlockSkyLight;
+ cChunkData m_ChunkData;
cChunkDef::HeightMap m_HeightMap;
cChunkDef::BiomeMap m_BiomeMap;
diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp
new file mode 100644
index 000000000..142c141c4
--- /dev/null
+++ b/src/ChunkData.cpp
@@ -0,0 +1,592 @@
+
+// ChunkData.cpp
+
+// Implements the cChunkData class that represents the block's type, meta, blocklight and skylight storage for a chunk
+
+#include "Globals.h"
+#include "ChunkData.h"
+
+
+
+
+
+/** Returns true if all a_Array's elements between [0] and [a_NumElements - 1] are equal to a_Value. */
+template <typename T> inline bool IsAllValue(const T * a_Array, size_t a_NumElements, T a_Value)
+{
+ for (size_t i = 0; i < a_NumElements; i++)
+ {
+ if (a_Array[i] != a_Value)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+
+cChunkData::cChunkData(void)
+#if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ : m_IsOwner(true)
+#endif
+{
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ m_Sections[i] = NULL;
+ }
+}
+
+
+
+
+
+cChunkData::~cChunkData()
+{
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ if (!m_IsOwner)
+ {
+ return;
+ }
+ #endif
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = NULL;
+ }
+}
+
+
+
+
+
+#if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ cChunkData::cChunkData(const cChunkData & a_Other) :
+ m_IsOwner(true)
+ {
+ // Move contents and ownership from a_Other to this, pointer-wise:
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ m_Sections[i] = a_Other.m_Sections[i];
+ }
+ a_Other.m_IsOwner = false;
+ }
+
+
+
+
+
+ cChunkData & cChunkData::operator =(const cChunkData & a_Other)
+ {
+ // If assigning to self, no-op
+ if (&a_Other == this)
+ {
+ return *this;
+ }
+
+ // Free any currently held contents:
+ if (m_IsOwner)
+ {
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = NULL;
+ }
+ }
+
+ // Move contents and ownership from a_Other to this, pointer-wise:
+ m_IsOwner = true;
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ m_Sections[i] = a_Other.m_Sections[i];
+ }
+ a_Other.m_IsOwner = false;
+ return *this;
+ }
+
+#else
+
+ // unique_ptr style interface for memory management
+ cChunkData::cChunkData(cChunkData && other)
+ {
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ m_Sections[i] = other.m_Sections[i];
+ other.m_Sections[i] = NULL;
+ }
+ }
+
+
+
+
+
+ cChunkData & cChunkData::operator =(cChunkData && other)
+ {
+ if (&other != this)
+ {
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = other.m_Sections[i];
+ other.m_Sections[i] = NULL;
+ }
+ }
+ return *this;
+ }
+#endif
+
+
+
+
+
+BLOCKTYPE cChunkData::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 / SectionHeight;
+ if (m_Sections[Section] != NULL)
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_X, a_Y - (Section * SectionHeight), a_Z);
+ return m_Sections[Section]->m_BlockTypes[Index];
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+
+
+
+void cChunkData::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(!"cChunkData::SetMeta(): index out of range!");
+ return;
+ }
+
+ int Section = a_RelY / SectionHeight;
+ if (m_Sections[Section] == NULL)
+ {
+ if (a_Block == 0x00)
+ {
+ return;
+ }
+ m_Sections[Section] = Allocate();
+ if (m_Sections[Section] == NULL)
+ {
+ ASSERT(!"Failed to allocate a new section in Chunkbuffer");
+ return;
+ }
+ ZeroSection(m_Sections[Section]);
+ }
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ m_Sections[Section]->m_BlockTypes[Index] = a_Block;
+}
+
+
+
+
+
+NIBBLETYPE cChunkData::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 / SectionHeight;
+ if (m_Sections[Section] != NULL)
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ return (m_Sections[Section]->m_BlockMetas[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ ASSERT(!"cChunkData::GetMeta(): coords out of chunk range!");
+ return 0;
+}
+
+
+
+
+
+bool cChunkData::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(!"cChunkData::SetMeta(): index out of range!");
+ return false;
+ }
+
+ int Section = a_RelY / SectionHeight;
+ if (m_Sections[Section] == NULL)
+ {
+ if ((a_Nibble & 0xf) == 0x00)
+ {
+ return false;
+ }
+ m_Sections[Section] = Allocate();
+ if (m_Sections[Section] == NULL)
+ {
+ ASSERT(!"Failed to allocate a new section in Chunkbuffer");
+ return false;
+ }
+ ZeroSection(m_Sections[Section]);
+ }
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ NIBBLETYPE oldval = m_Sections[Section]->m_BlockMetas[Index / 2] >> ((Index & 1) * 4) & 0xf;
+ m_Sections[Section]->m_BlockMetas[Index / 2] = static_cast<NIBBLETYPE>(
+ (m_Sections[Section]->m_BlockMetas[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble
+ ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set
+ );
+ return oldval == a_Nibble;
+}
+
+
+
+
+
+NIBBLETYPE cChunkData::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 / SectionHeight;
+ if (m_Sections[Section] != NULL)
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ ASSERT(!"cChunkData::GetMeta(): coords out of chunk range!");
+ return 0;
+}
+
+
+
+
+
+NIBBLETYPE cChunkData::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 / SectionHeight;
+ if (m_Sections[Section] != NULL)
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ }
+ else
+ {
+ return 0xF;
+ }
+ }
+ ASSERT(!"cChunkData::GetMeta(): coords out of chunk range!");
+ return 0;
+}
+
+
+
+
+
+cChunkData cChunkData::Copy(void) const
+{
+ cChunkData copy;
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ if (m_Sections[i] != NULL)
+ {
+ copy.m_Sections[i] = Allocate();
+ *copy.m_Sections[i] = *m_Sections[i];
+ }
+ }
+ return copy;
+}
+
+
+
+
+
+void cChunkData::CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx, size_t a_Length) const
+{
+ size_t ToSkip = a_Idx;
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ size_t StartPos = 0;
+ if (ToSkip > 0)
+ {
+ StartPos = std::min(ToSkip, +SectionBlockCount);
+ ToSkip -= StartPos;
+ }
+ if (StartPos < SectionBlockCount)
+ {
+ size_t ToCopy = std::min(+SectionBlockCount - StartPos, a_Length);
+ a_Length -= ToCopy;
+ if (m_Sections[i] != NULL)
+ {
+ BLOCKTYPE * blockbuffer = m_Sections[i]->m_BlockTypes;
+ memcpy(&a_Dest[(i * SectionBlockCount) + StartPos - a_Idx], blockbuffer + StartPos, sizeof(BLOCKTYPE) * ToCopy);
+ }
+ else
+ {
+ memset(&a_Dest[(i * SectionBlockCount) - a_Idx], 0, sizeof(BLOCKTYPE) * ToCopy);
+ }
+ }
+ }
+}
+
+
+
+
+
+void cChunkData::CopyMetas(NIBBLETYPE * a_Dest) const
+{
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockMetas, sizeof(m_Sections[i]->m_BlockMetas));
+ }
+ else
+ {
+ memset(&a_Dest[i * SectionBlockCount / 2], 0, sizeof(m_Sections[i]->m_BlockMetas));
+ }
+ }
+}
+
+
+
+
+
+void cChunkData::CopyBlockLight(NIBBLETYPE * a_Dest) const
+{
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockLight, sizeof(m_Sections[i]->m_BlockLight));
+ }
+ else
+ {
+ memset(&a_Dest[i * SectionBlockCount / 2], 0, sizeof(m_Sections[i]->m_BlockLight));
+ }
+ }
+}
+
+
+
+
+
+void cChunkData::CopySkyLight(NIBBLETYPE * a_Dest) const
+{
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockSkyLight, sizeof(m_Sections[i]->m_BlockSkyLight));
+ }
+ else
+ {
+ memset(&a_Dest[i * SectionBlockCount / 2], 0xff, sizeof(m_Sections[i]->m_BlockSkyLight));
+ }
+ }
+}
+
+
+
+
+
+void cChunkData::SetBlockTypes(const BLOCKTYPE * a_Src)
+{
+ ASSERT(a_Src != NULL);
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ // If the section is already allocated, copy the data into it:
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(m_Sections[i]->m_BlockTypes, &a_Src[i * SectionBlockCount], sizeof(m_Sections[i]->m_BlockTypes));
+ continue;
+ }
+
+ // The section doesn't exist, find out if it is needed:
+ if (IsAllValue(a_Src + i * SectionBlockCount, SectionBlockCount, (const BLOCKTYPE)0))
+ {
+ // No need for the section, the data is all-air
+ continue;
+ }
+
+ // Allocate the section and copy the data into it:
+ m_Sections[i] = Allocate();
+ memcpy(m_Sections[i]->m_BlockTypes, &a_Src[i * SectionBlockCount], sizeof(m_Sections[i]->m_BlockTypes));
+ memset(m_Sections[i]->m_BlockMetas, 0x00, sizeof(m_Sections[i]->m_BlockMetas));
+ memset(m_Sections[i]->m_BlockLight, 0x00, sizeof(m_Sections[i]->m_BlockLight));
+ memset(m_Sections[i]->m_BlockSkyLight, 0xff, sizeof(m_Sections[i]->m_BlockSkyLight));
+ } // for i - m_Sections[]
+}
+
+
+
+
+void cChunkData::SetMetas(const NIBBLETYPE * a_Src)
+{
+ ASSERT(a_Src != NULL);
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ // If the section is already allocated, copy the data into it:
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(m_Sections[i]->m_BlockMetas, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockMetas));
+ continue;
+ }
+
+ // The section doesn't exist, find out if it is needed:
+ if (IsAllValue(a_Src + i * SectionBlockCount / 2, SectionBlockCount / 2, (NIBBLETYPE)0))
+ {
+ // No need for the section, the data is all zeroes
+ continue;
+ }
+
+ // Allocate the section and copy the data into it:
+ m_Sections[i] = Allocate();
+ memcpy(m_Sections[i]->m_BlockMetas, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockMetas));
+ memset(m_Sections[i]->m_BlockTypes, 0x00, sizeof(m_Sections[i]->m_BlockTypes));
+ memset(m_Sections[i]->m_BlockLight, 0x00, sizeof(m_Sections[i]->m_BlockLight));
+ memset(m_Sections[i]->m_BlockSkyLight, 0xff, sizeof(m_Sections[i]->m_BlockSkyLight));
+ } // for i - m_Sections[]
+}
+
+
+
+
+
+void cChunkData::SetBlockLight(const NIBBLETYPE * a_Src)
+{
+ if (a_Src == NULL)
+ {
+ return;
+ }
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ // If the section is already allocated, copy the data into it:
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(m_Sections[i]->m_BlockLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockLight));
+ continue;
+ }
+
+ // The section doesn't exist, find out if it is needed:
+ if (IsAllValue(a_Src + i * SectionBlockCount / 2, SectionBlockCount / 2, (NIBBLETYPE)0))
+ {
+ // No need for the section, the data is all zeroes
+ continue;
+ }
+
+ // Allocate the section and copy the data into it:
+ m_Sections[i] = Allocate();
+ memcpy(m_Sections[i]->m_BlockLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockLight));
+ memset(m_Sections[i]->m_BlockTypes, 0x00, sizeof(m_Sections[i]->m_BlockTypes));
+ memset(m_Sections[i]->m_BlockMetas, 0x00, sizeof(m_Sections[i]->m_BlockMetas));
+ memset(m_Sections[i]->m_BlockSkyLight, 0xff, sizeof(m_Sections[i]->m_BlockSkyLight));
+ } // for i - m_Sections[]
+}
+
+
+
+
+void cChunkData::SetSkyLight(const NIBBLETYPE * a_Src)
+{
+ if (a_Src == NULL)
+ {
+ return;
+ }
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ // If the section is already allocated, copy the data into it:
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(m_Sections[i]->m_BlockSkyLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockSkyLight));
+ continue;
+ }
+
+ // The section doesn't exist, find out if it is needed:
+ if (IsAllValue(a_Src + i * SectionBlockCount / 2, SectionBlockCount / 2, (NIBBLETYPE)0xff))
+ {
+ // No need for the section, the data is all zeroes
+ continue;
+ }
+
+ // Allocate the section and copy the data into it:
+ m_Sections[i] = Allocate();
+ memcpy(m_Sections[i]->m_BlockSkyLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockSkyLight));
+ memset(m_Sections[i]->m_BlockTypes, 0x00, sizeof(m_Sections[i]->m_BlockTypes));
+ memset(m_Sections[i]->m_BlockMetas, 0x00, sizeof(m_Sections[i]->m_BlockMetas));
+ memset(m_Sections[i]->m_BlockLight, 0x00, sizeof(m_Sections[i]->m_BlockLight));
+ } // for i - m_Sections[]
+}
+
+
+
+
+
+cChunkData::sChunkSection * cChunkData::Allocate(void)
+{
+ // TODO: Use an allocation pool
+ return new cChunkData::sChunkSection;
+}
+
+
+
+
+
+void cChunkData::Free(cChunkData::sChunkSection * a_Section)
+{
+ // TODO: Use an allocation pool
+ delete a_Section;
+}
+
+
+
+
+
+void cChunkData::ZeroSection(cChunkData::sChunkSection * a_Section) const
+{
+ memset(a_Section->m_BlockTypes, 0x00, sizeof(a_Section->m_BlockTypes));
+ memset(a_Section->m_BlockMetas, 0x00, sizeof(a_Section->m_BlockMetas));
+ memset(a_Section->m_BlockLight, 0x00, sizeof(a_Section->m_BlockLight));
+ memset(a_Section->m_BlockSkyLight, 0xff, sizeof(a_Section->m_BlockSkyLight));
+}
+
+
+
+
diff --git a/src/ChunkData.h b/src/ChunkData.h
new file mode 100644
index 000000000..fef31b5ad
--- /dev/null
+++ b/src/ChunkData.h
@@ -0,0 +1,125 @@
+
+// ChunkData.h
+
+// Declares the cChunkData class that represents the block's type, meta, blocklight and skylight storage for a chunk
+
+
+
+
+
+#pragma once
+
+
+#include <cstring>
+
+
+#include "ChunkDef.h"
+
+
+
+
+#if __cplusplus < 201103L
+// auto_ptr style interface for memory management
+#else
+// unique_ptr style interface for memory management
+#endif
+
+class cChunkData
+{
+public:
+
+ cChunkData(void);
+ ~cChunkData();
+
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ cChunkData(const cChunkData & a_Other);
+ cChunkData & operator =(const cChunkData & a_Other);
+ #else
+ // unique_ptr style interface for memory management
+ cChunkData(cChunkData && a_Other);
+ cChunkData & operator =(cChunkData && a_ther);
+ #endif
+
+ BLOCKTYPE GetBlock(int a_X, int a_Y, int a_Z) const;
+ void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block);
+
+ NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const;
+ bool SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Nibble);
+
+ NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const;
+
+ NIBBLETYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const;
+
+ /** Creates a (deep) copy of self. */
+ cChunkData Copy(void) const;
+
+ /** Copies the blocktype data into the specified flat array.
+ Optionally, only a part of the data is copied, as specified by the a_Idx and a_Length parameters. */
+ void CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx = 0, size_t a_Length = cChunkDef::NumBlocks) const;
+
+ /** Copies the metadata into the specified flat array. */
+ void CopyMetas(NIBBLETYPE * a_Dest) const;
+
+ /** Copies the block light data into the specified flat array. */
+ void CopyBlockLight(NIBBLETYPE * a_Dest) const;
+
+ /** Copies the skylight data into the specified flat array. */
+ void CopySkyLight (NIBBLETYPE * a_Dest) const;
+
+ /** Copies the blocktype data from the specified flat array into the internal representation.
+ Allocates sections that are needed for the operation.
+ Requires that a_Src is a valid pointer. */
+ void SetBlockTypes(const BLOCKTYPE * a_Src);
+
+ /** Copies the metadata from the specified flat array into the internal representation.
+ Allocates sectios that are needed for the operation.
+ Requires that a_Src is a valid pointer. */
+ void SetMetas(const NIBBLETYPE * a_Src);
+
+ /** Copies the blocklight data from the specified flat array into the internal representation.
+ Allocates sectios that are needed for the operation.
+ Allows a_Src to be NULL, in which case it doesn't do anything. */
+ void SetBlockLight(const NIBBLETYPE * a_Src);
+
+ /** Copies the skylight data from the specified flat array into the internal representation.
+ Allocates sectios that are needed for the operation.
+ Allows a_Src to be NULL, in which case it doesn't do anything. */
+ void SetSkyLight(const NIBBLETYPE * a_Src);
+
+private:
+
+ static const size_t SectionHeight = 16;
+ static const size_t NumSections = (cChunkDef::Height / SectionHeight);
+ static const size_t SectionBlockCount = SectionHeight * cChunkDef::Width * cChunkDef::Width;
+
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ mutable bool m_IsOwner;
+ #endif
+
+ struct sChunkSection {
+ BLOCKTYPE m_BlockTypes [SectionBlockCount];
+ NIBBLETYPE m_BlockMetas [SectionBlockCount / 2];
+ NIBBLETYPE m_BlockLight [SectionBlockCount / 2];
+ NIBBLETYPE m_BlockSkyLight[SectionBlockCount / 2];
+ };
+
+ sChunkSection * m_Sections[NumSections];
+
+ /** Allocates a new section. Entry-point to custom allocators. */
+ static sChunkSection * Allocate(void);
+
+ /** Frees the specified section, previously allocated using Allocate().
+ Note that a_Section may be NULL. */
+ static void Free(sChunkSection * a_Section);
+
+ /** Sets the data in the specified section to their default values. */
+ void ZeroSection(sChunkSection * a_Section) const;
+};
+
+
+
+
+
+
diff --git a/src/ChunkDataCallback.h b/src/ChunkDataCallback.h
new file mode 100644
index 000000000..0c8b1098f
--- /dev/null
+++ b/src/ChunkDataCallback.h
@@ -0,0 +1,127 @@
+
+// ChunkDataCallback.h
+
+// Declares the cChunkDataCallback interface and several trivial descendants, for reading chunk data
+
+
+
+
+
+#pragma once
+
+#include "ChunkData.h"
+
+
+
+
+
+/** Interface class used for getting data out of a chunk using the GetAllData() function.
+Implementation must use the pointers immediately and NOT store any of them for later use
+The virtual methods are called in the same order as they're declared here.
+*/
+class cChunkDataCallback abstract
+{
+public:
+
+ virtual ~cChunkDataCallback() {}
+
+ /** Called before any other callbacks to inform of the current coords
+ (only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()).
+ If false is returned, the chunk is skipped.
+ */
+ virtual bool Coords(int a_ChunkX, int a_ChunkZ) { UNUSED(a_ChunkX); UNUSED(a_ChunkZ); return true; };
+
+ /// Called once to provide heightmap data
+ virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) {UNUSED(a_HeightMap); };
+
+ /// Called once to provide biome data
+ virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) {UNUSED(a_BiomeMap); };
+
+ /// Called once to let know if the chunk lighting is valid. Return value is ignored
+ virtual void LightIsValid(bool a_IsLightValid) {UNUSED(a_IsLightValid); };
+
+ /// Called once to export block info
+ virtual void ChunkData(const cChunkData & a_Buffer) {UNUSED(a_Buffer); };
+
+ /// Called for each entity in the chunk
+ virtual void Entity(cEntity * a_Entity) {UNUSED(a_Entity); };
+
+ /// Called for each blockentity in the chunk
+ virtual void BlockEntity(cBlockEntity * a_Entity) {UNUSED(a_Entity); };
+} ;
+
+
+
+
+
+/** A simple implementation of the cChunkDataCallback interface that collects all block data into a buffer
+*/
+class cChunkDataCollector :
+ public cChunkDataCallback
+{
+public:
+
+ cChunkData m_BlockData;
+
+protected:
+
+ virtual void ChunkData(const cChunkData & 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 cChunkDataArrayCollector :
+ 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 ChunkData(const cChunkData & a_ChunkBuffer) override
+ {
+ a_ChunkBuffer.CopyBlockTypes(m_BlockData);
+ a_ChunkBuffer.CopyMetas(m_BlockData + cChunkDef::NumBlocks);
+ a_ChunkBuffer.CopyBlockLight(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 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 ChunkData(const cChunkData & a_ChunkBuffer) override
+ {
+ a_ChunkBuffer.CopyBlockTypes(m_BlockTypes);
+ a_ChunkBuffer.CopyMetas(m_BlockMetas);
+ a_ChunkBuffer.CopyBlockLight(m_BlockLight);
+ a_ChunkBuffer.CopySkyLight(m_BlockSkyLight);
+ }
+} ;
+
+
+
+
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index 83f3c8f5f..f89e16ed1 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -330,136 +330,6 @@ private:
-/** Interface class used for getting data out of a chunk using the GetAllData() function.
-Implementation must use the pointers immediately and NOT store any of them for later use
-The virtual methods are called in the same order as they're declared here.
-*/
-class cChunkDataCallback abstract
-{
-public:
-
- virtual ~cChunkDataCallback() {}
-
- /** Called before any other callbacks to inform of the current coords
- (only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()).
- If false is returned, the chunk is skipped.
- */
- virtual bool Coords(int a_ChunkX, int a_ChunkZ) { UNUSED(a_ChunkX); UNUSED(a_ChunkZ); return true; };
-
- /// Called once to provide heightmap data
- virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) {UNUSED(a_HeightMap); };
-
- /// Called once to provide biome data
- virtual void BiomeData (const cChunkDef::BiomeMap * a_BiomeMap) {UNUSED(a_BiomeMap); };
-
- /// Called once to export block types
- virtual void BlockTypes (const BLOCKTYPE * a_Type) {UNUSED(a_Type); };
-
- /// Called once to export block meta
- virtual void BlockMeta (const NIBBLETYPE * a_Meta) {UNUSED(a_Meta); };
-
- /// 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
- virtual void Entity(cEntity * a_Entity) {UNUSED(a_Entity); };
-
- /// Called for each blockentity in the chunk
- virtual void BlockEntity(cBlockEntity * a_Entity) {UNUSED(a_Entity); };
-} ;
-
-
-
-
-
-/** 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.
Used primarily for entity moving while both chunks are locked.
*/
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index d7164a6a5..d3f44bef8 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -219,9 +219,8 @@ bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY
return false;
}
- int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
- a_BlockType = Chunk->GetBlock(Index);
- a_BlockMeta = Chunk->GetMeta(Index);
+ a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ);
return true;
}
@@ -242,8 +241,7 @@ bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLO
return false;
}
- int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
- a_BlockType = Chunk->GetBlock(Index);
+ a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
return true;
}
@@ -264,8 +262,7 @@ bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB
return false;
}
- int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
- a_BlockMeta = Chunk->GetMeta(Index);
+ a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ);
return true;
}
@@ -1484,9 +1481,8 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
res = false;
continue;
}
- int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z);
- itr->BlockType = Chunk->GetBlock(idx);
- itr->BlockMeta = Chunk->GetMeta(idx);
+ itr->BlockType = Chunk->GetBlock(itr->x, itr->y, itr->z);
+ itr->BlockMeta = Chunk->GetMeta(itr->x, itr->y, itr->z);
}
return res;
}
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 9d973f2a9..c3deda088 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -5,7 +5,8 @@
#pragma once
-#include "ChunkDef.h"
+
+#include "ChunkDataCallback.h"
diff --git a/src/ChunkSender.h b/src/ChunkSender.h
index a26f764a7..00565d7c3 100644
--- a/src/ChunkSender.h
+++ b/src/ChunkSender.h
@@ -27,6 +27,7 @@ Note that it may be called by world's BroadcastToChunk() if the client is still
#include "OSSupport/IsThread.h"
#include "ChunkDef.h"
+#include "ChunkDataCallback.h"
diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp
index beb58f207..111c5fa84 100644
--- a/src/Entities/FallingBlock.cpp
+++ b/src/Entities/FallingBlock.cpp
@@ -55,9 +55,8 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
return;
}
- int idx = a_Chunk.MakeIndexNoCheck(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
- BLOCKTYPE BlockBelow = a_Chunk.GetBlock(idx);
- NIBBLETYPE BelowMeta = a_Chunk.GetMeta(idx);
+ BLOCKTYPE BlockBelow = a_Chunk.GetBlock(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
+ NIBBLETYPE BelowMeta = a_Chunk.GetMeta(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta))
{
// Fallen onto a block that breaks this into pickups (e. g. half-slab)
diff --git a/src/Globals.h b/src/Globals.h
index 71e9191e4..c5768facf 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -225,16 +225,28 @@ template class SizeChecker<UInt16, 2>;
+#ifndef TEST_GLOBALS
+ // Common headers (part 1, without macros):
+ #include "StringUtils.h"
+ #include "OSSupport/Sleep.h"
+ #include "OSSupport/CriticalSection.h"
+ #include "OSSupport/Semaphore.h"
+ #include "OSSupport/Event.h"
+ #include "OSSupport/Thread.h"
+ #include "OSSupport/File.h"
+ #include "MCLogger.h"
+#else
+ // Logging functions
+void inline LOGERROR(const char* a_Format, ...) FORMATSTRING(1,2);
-// Common headers (part 1, without macros):
-#include "StringUtils.h"
-#include "OSSupport/Sleep.h"
-#include "OSSupport/CriticalSection.h"
-#include "OSSupport/Semaphore.h"
-#include "OSSupport/Event.h"
-#include "OSSupport/Thread.h"
-#include "OSSupport/File.h"
-#include "MCLogger.h"
+void inline LOGERROR(const char* a_Format, ...)
+{
+ va_list argList;
+ va_start(argList, a_Format);
+ vprintf(a_Format, argList);
+ va_end(argList);
+}
+#endif
@@ -253,10 +265,44 @@ template class SizeChecker<UInt16, 2>;
#define FAST_FLOOR_DIV( x, div ) (((x) - (((x) < 0) ? ((div) - 1) : 0)) / (div))
// Own version of assert() that writes failed assertions to the log for review
-#ifdef _DEBUG
- #define ASSERT( x ) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), assert(0), 0 ) )
+#ifdef TEST_GLOBALS
+
+ class cAssertFailure
+ {
+ };
+
+ #ifdef _WIN32
+ #if (defined(_MSC_VER) && defined(_DEBUG))
+ #define DBG_BREAK _CrtDbgBreak()
+ #else
+ #define DBG_BREAK
+ #endif
+ #define REPORT_ERROR(FMT, ...) \
+ { \
+ AString msg = Printf(FMT, __VA_ARGS__); \
+ puts(msg.c_str()); \
+ fflush(stdout); \
+ OutputDebugStringA(msg.c_str()); \
+ DBG_BREAK; \
+ }
+ #else
+ #define REPORT_ERROR(FMT, ...) \
+ { \
+ AString msg = Printf(FMT, __VA_ARGS__); \
+ puts(msg.c_str()); \
+ fflush(stdout); \
+ }
+ #endif
+ #define ASSERT(x) do { if (!(x)) { throw cAssertFailure();} } while (0)
+ #define testassert(x) do { if(!(x)) { REPORT_ERROR("Test failure: %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } } while (0)
+ #define CheckAsserts(x) do { try {x} catch (cAssertFailure) { break; } REPORT_ERROR("Test failure: assert didn't fire for %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } while (0)
+
#else
- #define ASSERT(x) ((void)(x))
+ #ifdef _DEBUG
+ #define ASSERT( x ) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), assert(0), 0 ) )
+ #else
+ #define ASSERT(x) ((void)(x))
+ #endif
#endif
// Pretty much the same as ASSERT() but stays in Release builds
diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp
index 5459644af..dc19bf500 100644
--- a/src/LightingThread.cpp
+++ b/src/LightingThread.cpp
@@ -18,20 +18,17 @@
class cReader :
public cChunkDataCallback
{
- virtual void BlockTypes(const BLOCKTYPE * a_Type) override
+ virtual void ChunkData(const cChunkData & a_ChunkBuffer) override
{
- // ROW is a block of 16 Blocks, one whole row is copied at a time (hopefully the compiler will optimize that)
- // 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;
+ BLOCKTYPE * OutputRows = m_BlockTypes;
int InputIdx = 0;
int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
for (int y = 0; y < cChunkDef::Height; y++)
{
for (int z = 0; z < cChunkDef::Width; z++)
{
- OutputRows[OutputIdx] = InputRows[InputIdx++];
+ a_ChunkBuffer.CopyBlockTypes(OutputRows + OutputIdx * 16, InputIdx * 16, 16);
+ InputIdx++;
OutputIdx += 3;
} // for z
// Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows
diff --git a/src/MobProximityCounter.cpp b/src/MobProximityCounter.cpp
index 519757c2c..ce20bf56b 100644
--- a/src/MobProximityCounter.cpp
+++ b/src/MobProximityCounter.cpp
@@ -24,7 +24,7 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl
if (a_Distance < it->second.m_Distance)
{
it->second.m_Distance = a_Distance;
- it->second.m_Chunk = a_Chunk;
+ it->second.m_Chunk = &a_Chunk;
}
}
@@ -36,7 +36,7 @@ void cMobProximityCounter::convertMaps()
{
for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); ++itr)
{
- m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,itr->second.m_Chunk)));
+ m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,*itr->second.m_Chunk)));
}
}
diff --git a/src/MobProximityCounter.h b/src/MobProximityCounter.h
index 8a67139aa..79429eb60 100644
--- a/src/MobProximityCounter.h
+++ b/src/MobProximityCounter.h
@@ -16,9 +16,9 @@ protected :
// structs used for later maps (see m_MonsterToDistance and m_DistanceToMonster)
struct sDistanceAndChunk
{
- sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(a_Chunk) {}
+ sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(&a_Chunk) {}
double m_Distance;
- cChunk& m_Chunk;
+ cChunk* m_Chunk;
};
struct sMonsterAndChunk
{
diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp
index 4fbfffd43..311f8b4c4 100644
--- a/src/Simulator/FireSimulator.cpp
+++ b/src/Simulator/FireSimulator.cpp
@@ -95,8 +95,10 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
int NumMSecs = (int)a_Dt;
for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();)
{
- int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z);
- BLOCKTYPE BlockType = a_Chunk->GetBlock(idx);
+ int x = itr->x;
+ int y = itr->y;
+ int z = itr->z;
+ BLOCKTYPE BlockType = a_Chunk->GetBlock(x,y,z);
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
);
*/
- NIBBLETYPE BlockMeta = a_Chunk->GetMeta(idx);
+ NIBBLETYPE BlockMeta = a_Chunk->GetMeta(x, y, z);
if (BlockMeta == 0x0f)
{
// 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))))
{
- 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
} // for itr - Data[]
diff --git a/src/StringUtils.h b/src/StringUtils.h
index caad85aef..87b574a34 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -11,6 +11,9 @@
+#include <string>
+
+
typedef std::string AString;
diff --git a/src/Vector3.h b/src/Vector3.h
index fed776018..5faac1457 100644
--- a/src/Vector3.h
+++ b/src/Vector3.h
@@ -5,6 +5,8 @@
#define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC)
#include <math.h>
+#include <list>
+#include <vector>
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 7b7cd3c7e..a3b0d57be 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -727,10 +727,9 @@ void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Mineca
-bool cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
+void cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
{
m_IsLightValid = a_IsLightValid;
- return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother
}
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 51d104970..112afc27e 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -9,7 +9,7 @@
#pragma once
-#include "../ChunkDef.h"
+#include "ChunkDataCallback.h"
@@ -121,7 +121,7 @@ protected:
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
// 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 Entity(cEntity * a_Entity) override;
virtual void BlockEntity(cBlockEntity * a_Entity) override;
diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp
index 6d06b8fe3..7a113849a 100644
--- a/src/WorldStorage/WSSCompact.cpp
+++ b/src/WorldStorage/WSSCompact.cpp
@@ -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_HasJsonData = true;
}
- m_Root["IsLightValid"] = true;
- m_HasJsonData = true;
- return true;
}
diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h
index 97e3b82f9..b148005f6 100644
--- a/src/WorldStorage/WSSCompact.h
+++ b/src/WorldStorage/WSSCompact.h
@@ -14,6 +14,7 @@
#include "WorldStorage.h"
#include "../Vector3.h"
#include "json/json.h"
+#include "ChunkDataCallback.h"
@@ -21,7 +22,7 @@
/// Helper class for serializing a chunk into Json
class cJsonChunkSerializer :
- public cChunkDataCollector
+ public cChunkDataArrayCollector
{
public:
@@ -42,7 +43,7 @@ protected:
// cChunkDataCollector overrides:
virtual void Entity (cEntity * a_Entity) override;
virtual void BlockEntity (cBlockEntity * a_Entity) override;
- virtual bool LightIsValid (bool a_IsLightValid) override;
+ virtual void LightIsValid (bool a_IsLightValid) override;
} ;