From fe4253834919d6c742c59c701d3d5ce8285f4504 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sat, 24 Jun 2017 11:58:06 +0200 Subject: cBlockArea supports block entities. (#3795) --- src/Chunk.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 7 deletions(-) (limited to 'src/Chunk.cpp') diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 849b0e2f5..99f643437 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -408,7 +408,7 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock { if ((a_DataTypes & (cBlockArea::baTypes | cBlockArea::baMetas)) != (cBlockArea::baTypes | cBlockArea::baMetas)) { - LOGWARNING("cChunk::WriteBlockArea(): unsupported datatype request, can write only types + metas (0x%x), requested 0x%x. Ignoring.", + LOGWARNING("cChunk::WriteBlockArea(): unsupported datatype request, can write only types + metas together (0x%x), requested 0x%x. Ignoring.", (cBlockArea::baTypes | cBlockArea::baMetas), a_DataTypes & (cBlockArea::baTypes | cBlockArea::baMetas) ); return; @@ -420,16 +420,16 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock int BlockEndX = std::min(a_MinBlockX + a_Area.GetSizeX(), (m_PosX + 1) * cChunkDef::Width); int BlockStartZ = std::max(a_MinBlockZ, m_PosZ * cChunkDef::Width); int BlockEndZ = std::min(a_MinBlockZ + a_Area.GetSizeZ(), (m_PosZ + 1) * cChunkDef::Width); - int SizeX = BlockEndX - BlockStartX; + int SizeX = BlockEndX - BlockStartX; // Size of the union int SizeZ = BlockEndZ - BlockStartZ; - int OffX = BlockStartX - m_PosX * cChunkDef::Width; + int SizeY = std::min(a_Area.GetSizeY(), cChunkDef::Height - a_MinBlockY); + int OffX = BlockStartX - m_PosX * cChunkDef::Width; // Offset within the chunk where the union starts int OffZ = BlockStartZ - m_PosZ * cChunkDef::Width; - int BaseX = BlockStartX - a_MinBlockX; + int BaseX = BlockStartX - a_MinBlockX; // Offset within the area where the union starts int BaseZ = BlockStartZ - a_MinBlockZ; - int SizeY = std::min(a_Area.GetSizeY(), cChunkDef::Height - a_MinBlockY); - // TODO: Improve this by not calling FastSetBlock() and doing the processing here - // so that the heightmap is touched only once for each column. + // Copy blocktype and blockmeta: + // TODO: Right now each changed block is transmitted to all clients as a separate packet. Optimize this for larger areas. BLOCKTYPE * AreaBlockTypes = a_Area.GetBlockTypes(); NIBBLETYPE * AreaBlockMetas = a_Area.GetBlockMetas(); for (int y = 0; y < SizeY; y++) @@ -451,6 +451,50 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock } // for x } // for z } // for y + + // Erase all affected block entities: + cCuboid affectedArea(OffX, a_MinBlockY, OffZ, OffX + SizeX - 1, a_MinBlockY + SizeY - 1, OffZ + SizeZ - 1); + for (auto itr = m_BlockEntities.begin(); itr != m_BlockEntities.end();) + { + if (affectedArea.IsInside(itr->second->GetPos())) + { + itr = m_BlockEntities.erase(itr); + } + else + { + ++itr; + } + } + + // Clone block entities from a_Area into this chunk: + if ((a_DataTypes & cBlockArea::baBlockEntities) != 0) + { + for (const auto & keyPair: a_Area.GetBlockEntities()) + { + auto & be = keyPair.second; + auto posX = be->GetPosX() + a_MinBlockX; + auto posY = be->GetPosY() + a_MinBlockY; + auto posZ = be->GetPosZ() + a_MinBlockZ; + if ( + (posX < m_PosX * cChunkDef::Width) || (posX >= m_PosX * cChunkDef::Width + cChunkDef::Width) || + (posZ < m_PosZ * cChunkDef::Width) || (posZ >= m_PosZ * cChunkDef::Width + cChunkDef::Width) + ) + { + continue; + } + // This block entity is inside the chunk, clone it (and remove any that is there currently): + auto idx = MakeIndex(posX - m_PosX * cChunkDef::Width, posY, posZ - m_PosZ * cChunkDef::Width); + auto itr = m_BlockEntities.find(idx); + if (itr != m_BlockEntities.end()) + { + m_BlockEntities.erase(itr); + } + auto clone = be->Clone(posX, posY, posZ); + clone->SetWorld(m_World); + AddBlockEntityClean(clone); + BroadcastBlockEntity(posX, posY, posZ); + } + } } -- cgit v1.2.3