diff options
author | Mattes D <github@xoft.cz> | 2014-04-26 15:12:10 +0200 |
---|---|---|
committer | Mattes D <github@xoft.cz> | 2014-04-26 15:12:10 +0200 |
commit | 1139b117c42d7cf9646599a74fac38536f67c616 (patch) | |
tree | c86aa4f3f4354ce54080c4bc5f4e358913d9c8a1 /src | |
parent | Merge pull request #936 from archshift/patch-1 (diff) | |
parent | Implemented comments (diff) | |
download | cuberite-1139b117c42d7cf9646599a74fac38536f67c616.tar cuberite-1139b117c42d7cf9646599a74fac38536f67c616.tar.gz cuberite-1139b117c42d7cf9646599a74fac38536f67c616.tar.bz2 cuberite-1139b117c42d7cf9646599a74fac38536f67c616.tar.lz cuberite-1139b117c42d7cf9646599a74fac38536f67c616.tar.xz cuberite-1139b117c42d7cf9646599a74fac38536f67c616.tar.zst cuberite-1139b117c42d7cf9646599a74fac38536f67c616.zip |
Diffstat (limited to '')
-rw-r--r-- | src/Chunk.cpp | 130 | ||||
-rw-r--r-- | src/Chunk.h | 14 | ||||
-rw-r--r-- | src/ChunkDef.h | 89 |
3 files changed, 166 insertions, 67 deletions
diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 8bd0985e9..cd3bceda2 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -240,11 +240,24 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) { a_Callback.HeightMap (&m_HeightMap); a_Callback.BiomeData (&m_BiomeMap); - a_Callback.BlockTypes (m_BlockTypes); - a_Callback.BlockMeta (m_BlockMeta); + + COMPRESSED_BLOCKTYPE Blocks = m_BlockTypes; + Blocks.resize(NumBlocks); + a_Callback.BlockTypes (&Blocks[0]); + + COMPRESSED_NIBBLETYPE Metas = m_BlockMeta; + Metas.resize(NumBlocks / 2); + a_Callback.BlockMeta (&Metas[0]); + a_Callback.LightIsValid (m_IsLightValid); - a_Callback.BlockLight (m_BlockLight); - a_Callback.BlockSkyLight(m_BlockSkyLight); + + 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]); for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { @@ -262,7 +275,7 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) void cChunk::SetAllData( - const BLOCKTYPE * a_BlockTypes, + const BLOCKTYPE * a_BlockTypes, const NIBBLETYPE * a_BlockMeta, const NIBBLETYPE * a_BlockLight, const NIBBLETYPE * a_BlockSkyLight, @@ -272,29 +285,61 @@ void cChunk::SetAllData( ) { memcpy(m_BiomeMap, a_BiomeMap, sizeof(m_BiomeMap)); - + if (a_HeightMap != NULL) { memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap)); } + + if (a_HeightMap == NULL) + { + 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]); + } - memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes)); - memcpy(m_BlockMeta, a_BlockMeta, sizeof(m_BlockMeta)); if (a_BlockLight != NULL) { - memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight)); + // Compress blocklight + m_BlockLight.clear(); + m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[IdxWhereNonEmptyStarts / 2]); } + if (a_BlockSkyLight != NULL) { - memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight)); + // 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); - - if (a_HeightMap == NULL) - { - CalculateHeightmap(); - } // Clear the block entities present - either the loader / saver has better, or we'll create empty ones: for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) @@ -332,8 +377,17 @@ 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 :) - memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight)); - memcpy(m_BlockSkyLight, a_SkyLight, sizeof(m_BlockSkyLight)); + + { // Compress blocklight + m_BlockLight.clear(); + m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[m_BlockTypes.size()]); + } + + { // Compress skylight + m_BlockSkyLight.clear(); + m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size()]); + } + m_IsLightValid = true; } @@ -343,7 +397,8 @@ void cChunk::SetLight( void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes) { - memcpy(a_BlockTypes, m_BlockTypes, NumBlocks); + 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); } @@ -630,7 +685,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(m_BlockTypes[Index]); + cBlockHandler * Handler = BlockHandler(GetBlock(Index)); ASSERT(Handler != NULL); // Happenned on server restart, FS #243 cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap()); cBlockInServerPluginInterface PluginInterface(*this->GetWorld()); @@ -751,7 +806,7 @@ void cChunk::BroadcastPendingBlockChanges(void) void cChunk::CheckBlocks() { - if (m_ToTickBlocks.size() == 0) + if (m_ToTickBlocks.empty()) { return; } @@ -811,7 +866,7 @@ void cChunk::TickBlocks(void) } unsigned int Index = MakeIndexNoCheck(m_BlockTickX, m_BlockTickY, m_BlockTickZ); - cBlockHandler * Handler = BlockHandler(m_BlockTypes[Index]); + cBlockHandler * Handler = BlockHandler(GetBlock(Index)); 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 @@ -1296,7 +1351,7 @@ void cChunk::CreateBlockEntities(void) { for (int y = 0; y < Height; y++) { - BLOCKTYPE BlockType = cChunkDef::GetBlock(m_BlockTypes, x, y, z); + BLOCKTYPE BlockType = GetBlock(x, y, z); switch (BlockType) { case E_BLOCK_BEACON: @@ -1349,7 +1404,7 @@ void cChunk::WakeUpSimulators(void) int BlockZ = z + BaseZ; for (int y = GetHeight(x, z); y >= 0; y--) { - BLOCKTYPE Block = cChunkDef::GetBlock(m_BlockTypes, x, y, z); + BLOCKTYPE Block = GetBlock(x, y, z); // The redstone sim takes multiple blocks, use the inbuilt checker if (RedstoneSimulator->IsAllowedBlock(Block)) @@ -1384,7 +1439,7 @@ void cChunk::WakeUpSimulators(void) -void cChunk::CalculateHeightmap() +void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes) { for (int x = 0; x < Width; x++) { @@ -1393,7 +1448,7 @@ void cChunk::CalculateHeightmap() for (int y = Height - 1; y > -1; y--) { int index = MakeIndex( x, y, z ); - if (m_BlockTypes[index] != E_BLOCK_AIR) + if (a_BlockTypes[index] != E_BLOCK_AIR) { m_HeightMap[x + z * Width] = (unsigned char)y; break; @@ -1517,7 +1572,7 @@ 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 = cChunkDef::GetBlock(m_BlockTypes, index); + const BLOCKTYPE OldBlockType = GetBlock(index); const BLOCKTYPE OldBlockMeta = GetNibble(m_BlockMeta, index); if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta)) { @@ -1525,7 +1580,11 @@ 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; // The client doesn't need to distinguish between stationary and nonstationary fluids: @@ -1565,7 +1624,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 (m_BlockTypes[MakeIndexNoCheck(a_RelX, y, a_RelZ)] != E_BLOCK_AIR) + if (GetBlock(MakeIndexNoCheck(a_RelX, y, a_RelZ)) != E_BLOCK_AIR) { m_HeightMap[a_RelX + a_RelZ * Width] = (unsigned char)y; break; @@ -2452,7 +2511,7 @@ BLOCKTYPE cChunk::GetBlock(int a_RelX, int a_RelY, int a_RelZ) const return 0; // Clip } - return m_BlockTypes[MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)]; + return GetBlock(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)); } @@ -2466,8 +2525,13 @@ BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const ASSERT(!"GetBlock(idx) out of bounds!"); return 0; } - - return m_BlockTypes[ a_BlockIdx ]; + + if ((size_t)a_BlockIdx >= m_BlockTypes.size()) + { + return E_BLOCK_AIR; + } + + return m_BlockTypes[a_BlockIdx]; } @@ -2477,7 +2541,7 @@ 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 = cChunkDef::GetBlock (m_BlockTypes, Idx); + a_BlockType = GetBlock(Idx); a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Idx); } @@ -2488,7 +2552,7 @@ 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 = cChunkDef::GetBlock (m_BlockTypes, Idx); + 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); diff --git a/src/Chunk.h b/src/Chunk.h index f20134e66..a15d43e00 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -267,7 +267,7 @@ public: void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords void CalculateLighting(); // Recalculate right now - void CalculateHeightmap(); + void CalculateHeightmap(const BLOCKTYPE * a_BlockTypes); // Broadcast various packets to all clients of this chunk: // (Please keep these alpha-sorted) @@ -326,9 +326,9 @@ public: inline void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_BlockIdx, 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); } + 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); } + 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 */ bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; @@ -421,10 +421,10 @@ private: cChunkMap * m_ChunkMap; // TODO: Make these pointers and don't allocate what isn't needed - BLOCKTYPE m_BlockTypes [cChunkDef::NumBlocks]; - NIBBLETYPE m_BlockMeta [cChunkDef::NumBlocks / 2]; - NIBBLETYPE m_BlockLight [cChunkDef::NumBlocks / 2]; - NIBBLETYPE m_BlockSkyLight[cChunkDef::NumBlocks / 2]; + COMPRESSED_BLOCKTYPE m_BlockTypes; + COMPRESSED_NIBBLETYPE m_BlockMeta; + COMPRESSED_NIBBLETYPE m_BlockLight; + COMPRESSED_NIBBLETYPE m_BlockSkyLight; cChunkDef::HeightMap m_HeightMap; cChunkDef::BiomeMap m_BiomeMap; diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 9c7753820..054168bdd 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -77,13 +77,19 @@ public: idx = x + Width * z // Need to verify this with the protocol spec, currently unknown! */ typedef EMCSBiome BiomeMap[Width * Width]; - + /// The type used for block type operations and storage, AXIS_ORDER ordering typedef BLOCKTYPE BlockTypes[NumBlocks]; - + /// The type used for block data in nibble format, AXIS_ORDER ordering typedef NIBBLETYPE BlockNibbles[NumBlocks / 2]; + /** The storage wrapper used for compressed blockdata residing in RAMz */ + typedef std::vector<BLOCKTYPE> COMPRESSED_BLOCKTYPE; + + /** The storage wrapper used for compressed nibbledata residing in RAMz */ + typedef std::vector<NIBBLETYPE> COMPRESSED_NIBBLETYPE; + /// Converts absolute block coords into relative (chunk + block) coords: inline static void AbsoluteToRelative(/* in-out */ int & a_X, int & a_Y, int & a_Z, /* out */ int & a_ChunkX, int & a_ChunkZ ) @@ -219,46 +225,67 @@ public: ASSERT((a_Z >= 0) && (a_Z <= Width)); a_BiomeMap[a_X + Width * a_Z] = a_Biome; } - - - static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, int a_BlockIdx) + + + static NIBBLETYPE GetNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_BlockIdx, bool a_IsSkyLightNibble = false) { if ((a_BlockIdx > -1) && (a_BlockIdx < NumBlocks)) { - return (a_Buffer[a_BlockIdx / 2] >> ((a_BlockIdx & 1) * 4)) & 0x0f; + if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size()) + { + return (a_IsSkyLightNibble ? 0xff : 0); + } + return (a_Buffer[(size_t)(a_BlockIdx / 2)] >> ((a_BlockIdx & 1) * 4)) & 0x0f; } ASSERT(!"cChunkDef::GetNibble(): index out of chunk range!"); return 0; } - - + + + static NIBBLETYPE GetNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int x, int y, int z, bool a_IsSkyLightNibble = false) + { + if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1)) + { + int Index = MakeIndexNoCheck(x, y, z); + if ((size_t)(Index / 2) >= a_Buffer.size()) + { + return (a_IsSkyLightNibble ? 0xff : 0); + } + return ExpandNibble(a_Buffer, Index); + } + ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!"); + return 0; + } + + static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, int x, int y, int z) { if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1)) { int Index = MakeIndexNoCheck(x, y, z); - return (a_Buffer[Index / 2] >> ((Index & 1) * 4)) & 0x0f; + return (a_Buffer[(size_t)(Index / 2)] >> ((Index & 1) * 4)) & 0x0f; } ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!"); return 0; } - static void SetNibble(NIBBLETYPE * a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble) + static void SetNibble(COMPRESSED_NIBBLETYPE & a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble) { if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks)) { ASSERT(!"cChunkDef::SetNibble(): index out of range!"); return; } - a_Buffer[a_BlockIdx / 2] = static_cast<NIBBLETYPE>( - (a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble - ((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set - ); + if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size()) + { + a_Buffer.resize((size_t)((a_BlockIdx / 2) + 1)); + } + a_Buffer[(size_t)(a_BlockIdx / 2)] = PackNibble(a_Buffer, a_BlockIdx, a_Nibble); } - - - static void SetNibble(NIBBLETYPE * a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble) + + + static void SetNibble(COMPRESSED_NIBBLETYPE & a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble) { if ( (x >= Width) || (x < 0) || @@ -271,24 +298,32 @@ public: } int Index = MakeIndexNoCheck(x, y, z); - a_Buffer[Index / 2] = static_cast<NIBBLETYPE>( - (a_Buffer[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble - ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set - ); + if ((size_t)(Index / 2) >= a_Buffer.size()) + { + a_Buffer.resize((size_t)((Index / 2) + 1)); + } + a_Buffer[(size_t)(Index / 2)] = PackNibble(a_Buffer, Index, a_Nibble); } - inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos ) +private: + + + inline static NIBBLETYPE PackNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index, NIBBLETYPE a_Nibble) { - return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z ); + return static_cast<NIBBLETYPE>( + (a_Buffer[a_Index / 2] & (0xf0 >> ((a_Index & 1) * 4))) | // The untouched nibble + ((a_Nibble & 0x0f) << ((a_Index & 1) * 4)) // The nibble being set + ); } - - - inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value ) + + + inline static NIBBLETYPE ExpandNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index) { - SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value ); + return (a_Buffer[a_Index / 2] >> ((a_Index & 1) * 4)) & 0x0f; } + } ; |