From 66a164a9a75a2d48763520aab3aeb8eeda85c92d Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 1 Jul 2015 10:40:16 +0200 Subject: Added neighbor specification in the OnNeighborChanged() block callback. Fixes the OnNeighborChanged endless recursion with large melon / pumpkin fields. Fixes #2213. --- src/Blocks/BlockFarmland.h | 13 ++++++++++++- src/Blocks/BlockHandler.cpp | 30 +++++++++++++++--------------- src/Blocks/BlockHandler.h | 20 +++++++++++++------- src/Blocks/BlockLeaves.h | 8 ++++++-- src/Blocks/BlockRail.h | 36 +++++++++++++++++------------------- src/Chunk.cpp | 2 +- tests/LoadablePieces/Stubs.cpp | 2 +- 7 files changed, 65 insertions(+), 46 deletions(-) diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index 23a7392da..8d43632ff 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -65,13 +65,22 @@ public: } } - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override { + // Don't care about any neighbor but the one above us (fix recursion loop in #2213): + if (a_WhichNeighbor != BLOCK_FACE_YP) + { + return; + } + + // Don't care about anything if we're at the top of the world: if (a_BlockY >= cChunkDef::Height) { return; } + // Check whether we should revert to dirt: BLOCKTYPE UpperBlock = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); if (cBlockInfo::FullyOccupiesVoxel(UpperBlock)) { @@ -79,11 +88,13 @@ public: } } + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { a_Pickups.Add(E_BLOCK_DIRT, 1, 0); // Reset meta } + bool IsWaterInNear(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) { if (a_Chunk.GetWorld()->IsWeatherWetAt(a_RelX, a_RelZ)) diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 520d0d328..412fc3aeb 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -389,12 +389,12 @@ void cBlockHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWor void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { // Notify the neighbors - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1); + NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ, BLOCK_FACE_XP); + NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ, BLOCK_FACE_XM); + NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_YP); + NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_YM); + NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1, BLOCK_FACE_ZP); + NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1, BLOCK_FACE_ZM); } @@ -404,23 +404,23 @@ void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface void cBlockHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) { // Notify the neighbors - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1); + NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ, BLOCK_FACE_XP); + NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ, BLOCK_FACE_XM); + NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_YP); + NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_YM); + NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1, BLOCK_FACE_ZP); + NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1, BLOCK_FACE_ZM); } -void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_NeighborX, int a_NeighborY, int a_NeighborZ, eBlockFace a_WhichNeighbor) { - if ((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height)) + if ((a_NeighborY >= 0) && (a_NeighborY < cChunkDef::Height)) { - cBlockInfo::GetHandler(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); + cBlockInfo::GetHandler(a_ChunkInterface.GetBlock(a_NeighborX, a_NeighborY, a_NeighborZ))->OnNeighborChanged(a_ChunkInterface, a_NeighborX, a_NeighborY, a_NeighborZ, a_WhichNeighbor); } } diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index a71c70e8b..1b357c3f1 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -56,13 +56,19 @@ public: /// Called before a block gets destroyed / replaced with air virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ); - /// Called when a direct neighbor of this block has been changed (The position is the own position, not the neighbor position) - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) {} - - /// Notifies all neighbors of the given block about a change - static void NeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ); - - /// Called while the player diggs the block. + /** Called when a direct neighbor of this block has been changed (The position is the block's own position, not the changing neighbor's position) + a_WhichNeighbor indicates which neighbor has changed. For example, BLOCK_FACE_YP meant the neighbor above has changed. + BLOCK_FACE_NONE means that it is a neighbor not directly adjacent (diagonal, etc.) */ + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) {} + + /** Notifies the specified neighbor that the current block has changed. + a_NeighborXYZ coords are the coords of the neighbor + a_WhichNeighbor specifies which neighbor (relative to a_NeighborXYZ) has changed. + For example BLOCK_FACE_YP means that the block at {a_NeighborX, a_NeighborY + 1, a_NeighborZ} has changed. + BLOCK_FACE_NONE means that it is a neighbor not directly adjacent (diagonal, etc.) */ + static void NeighborChanged(cChunkInterface & a_ChunkInterface, int a_NeighborX, int a_NeighborY, int a_NeighborZ, eBlockFace a_WhichNeighbor); + + /** Called when the player starts digging the block. */ virtual void OnDigging(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {} /// Called if the user right clicks the block and the block is useable diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index 5c9283979..2368eab7b 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -75,10 +75,14 @@ public: } - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override { + // Unset 0x8 bit so this block gets checked for decay: NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0x7); // Unset 0x8 bit so it gets checked for decay + if ((Meta & 0x08) != 0) + { + a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0x7); + } } diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index eecd07006..7fb910e8c 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -47,15 +47,14 @@ public: super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); // Alert diagonal rails - OnNeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ); - OnNeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ); - OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1); - OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1); - - OnNeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ); - OnNeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ); - OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1); - OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1); + OnNeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1, BLOCK_FACE_NONE); } @@ -64,19 +63,18 @@ public: super::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ); // Alert diagonal rails - OnNeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ); - OnNeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ); - OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1); - OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1); - - OnNeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ); - OnNeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ); - OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1); - OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1); + OnNeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1, BLOCK_FACE_NONE); + OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1, BLOCK_FACE_NONE); } - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override { NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); if (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ) && (Meta != FindMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ))) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index d9410dc8d..9dc453079 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -1037,7 +1037,7 @@ void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl VERIFY(UnboundedRelFastSetBlock(a_RelX + x, a_RelY, a_RelZ + z, ProduceType, Meta)); auto Absolute = RelativeToAbsolute(Vector3i{a_RelX + x, a_RelY, a_RelZ + z}, m_PosX, m_PosZ); cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap()); - cBlockHandler::NeighborChanged(ChunkInterface, Absolute.x, Absolute.y, Absolute.z); + cBlockHandler::NeighborChanged(ChunkInterface, Absolute.x, Absolute.y - 1, Absolute.z, BLOCK_FACE_YP); break; } } diff --git a/tests/LoadablePieces/Stubs.cpp b/tests/LoadablePieces/Stubs.cpp index 0a8f2cb63..3f4623850 100644 --- a/tests/LoadablePieces/Stubs.cpp +++ b/tests/LoadablePieces/Stubs.cpp @@ -160,7 +160,7 @@ void cBlockHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterf -void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) { } -- cgit v1.2.3