diff options
Diffstat (limited to '')
-rw-r--r-- | src/Chunk.cpp | 215 |
1 files changed, 52 insertions, 163 deletions
diff --git a/src/Chunk.cpp b/src/Chunk.cpp index ca536e89a..1aaf076df 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; } @@ -1450,7 +1387,7 @@ void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes) int index = MakeIndex( x, y, z ); if (a_BlockTypes[index] != E_BLOCK_AIR) { - m_HeightMap[x + z * Width] = (unsigned char)y; + m_HeightMap[x + z * Width] = (HEIGHTTYPE)y; break; } } // for y @@ -1462,14 +1399,12 @@ 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) +void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients) { - FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - - const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); + FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta, a_SendToClients); // 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)); } @@ -1565,15 +1500,14 @@ void cChunk::QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ) -void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta) +void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients) { ASSERT(!((a_RelX < 0) || (a_RelX >= Width) || (a_RelY < 0) || (a_RelY >= Height) || (a_RelZ < 0) || (a_RelZ >= Width))); 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,27 +1515,25 @@ 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 ( - (OldBlockMeta != a_BlockMeta) || // Different meta always gets sent to the client - !( - ((OldBlockType == E_BLOCK_STATIONARY_WATER) && (a_BlockType == E_BLOCK_WATER)) || // Replacing stationary water with water - ((OldBlockType == E_BLOCK_WATER) && (a_BlockType == E_BLOCK_STATIONARY_WATER)) || // Replacing water with stationary water - ((OldBlockType == E_BLOCK_STATIONARY_LAVA) && (a_BlockType == E_BLOCK_LAVA)) || // Replacing stationary water with water - ((OldBlockType == E_BLOCK_LAVA) && (a_BlockType == E_BLOCK_STATIONARY_LAVA)) // Replacing water with stationary water + if ( // Queue block to be sent only if ... + a_SendToClients && // ... we are told to do so AND ... + ( + (OldBlockMeta != a_BlockMeta) || // ... the meta value is different OR ... + !( // ... the old and new blocktypes AREN'T liquids (because client doesn't need to distinguish betwixt them); see below for specifics: + ((OldBlockType == E_BLOCK_STATIONARY_WATER) && (a_BlockType == E_BLOCK_WATER)) || // Replacing stationary water with water + ((OldBlockType == E_BLOCK_WATER) && (a_BlockType == E_BLOCK_STATIONARY_WATER)) || // Replacing water with stationary water + ((OldBlockType == E_BLOCK_STATIONARY_LAVA) && (a_BlockType == E_BLOCK_LAVA)) || // Replacing stationary water with water + ((OldBlockType == E_BLOCK_LAVA) && (a_BlockType == E_BLOCK_STATIONARY_LAVA)) // Replacing water with stationary water + ) ) ) { 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 ( @@ -1618,15 +1550,15 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT { if (a_BlockType != E_BLOCK_AIR) { - m_HeightMap[a_RelX + a_RelZ * Width] = (unsigned char)a_RelY; + m_HeightMap[a_RelX + a_RelZ * Width] = (HEIGHTTYPE)a_RelY; } else { 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] = (HEIGHTTYPE)y; break; } } // for y - column in m_BlockData @@ -1638,39 +1570,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 +2440,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 +2449,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 +2459,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); } |