diff options
Diffstat (limited to 'src/Chunk.cpp')
-rw-r--r-- | src/Chunk.cpp | 158 |
1 files changed, 121 insertions, 37 deletions
diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 22b33c595..ca536e89a 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() / 2]); + } + + { // Compress skylight + m_BlockSkyLight.clear(); + m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size() / 2]); + } + 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); } @@ -452,7 +507,7 @@ void cChunk::CollectMobCensus(cMobCensus& toFill) { cMonster& Monster = (cMonster&)(**itr); currentPosition = Monster.GetPosition(); - for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); itr2 ++) + for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); ++itr2) { toFill.CollectMob(Monster,*this,(currentPosition-**itr2).SqrLength()); } @@ -600,7 +655,7 @@ void cChunk::Tick(float a_Dt) delete ToDelete; continue; } - itr++; + ++itr; } // for itr - m_Entitites[] // If any entity moved out of the chunk, move it to the neighbor: @@ -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()); @@ -694,7 +749,7 @@ void cChunk::ProcessQueuedSetBlocks(void) { if (itr->m_Tick <= CurrTick) { - if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to -1 if not specified + if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to 0 if not specified { if (GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ) == itr->m_PreviousType) { @@ -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,9 +1351,10 @@ 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: case E_BLOCK_CHEST: case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: @@ -1348,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)) @@ -1383,7 +1439,7 @@ void cChunk::WakeUpSimulators(void) -void cChunk::CalculateHeightmap() +void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes) { for (int x = 0; x < Width; x++) { @@ -1392,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; @@ -1429,6 +1485,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, // If the new block is a block entity, create the entity object: switch (a_BlockType) { + case E_BLOCK_BEACON: case E_BLOCK_CHEST: case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: @@ -1515,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)) { @@ -1523,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: @@ -1563,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; @@ -1577,6 +1638,24 @@ 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. @@ -2450,7 +2529,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)); } @@ -2464,8 +2543,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]; } @@ -2475,7 +2559,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); } @@ -2486,7 +2570,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); @@ -2511,7 +2595,7 @@ cChunk * cChunk::GetNeighborChunk(int a_BlockX, int a_BlockZ) cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) { // If the relative coords are too far away, use the parent's chunk lookup instead: - if ((a_RelX < 128) || (a_RelX > 128) || (a_RelZ < -128) || (a_RelZ > 128)) + if ((a_RelX < -128) || (a_RelX > 128) || (a_RelZ < -128) || (a_RelZ > 128)) { int BlockX = m_PosX * cChunkDef::Width + a_RelX; int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ; |