diff options
Diffstat (limited to 'src/Blocks/BlockLeaves.h')
-rw-r--r-- | src/Blocks/BlockLeaves.h | 176 |
1 files changed, 90 insertions, 86 deletions
diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index 065c5ec19..c936e0405 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -10,29 +10,88 @@ // Leaves can be this many blocks that away (inclusive) from the log not to decay #define LEAVES_CHECK_DISTANCE 6 -#define PROCESS_NEIGHBOR(x, y, z) \ - do { \ - switch (a_Area.GetBlockType(x, y, z)) \ - { \ - case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, static_cast<BLOCKTYPE>(E_BLOCK_SPONGE + i + 1)); break; \ - case E_BLOCK_LOG: return true; \ - case E_BLOCK_NEW_LEAVES: a_Area.SetBlockType(x, y, z, static_cast<BLOCKTYPE>(E_BLOCK_SPONGE + i + 1)); break; \ - case E_BLOCK_NEW_LOG: return true; \ - } \ - } while (false) -bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ); - - -class cBlockLeavesHandler : +class cBlockLeavesHandler: public cBlockHandler { + using Super = cBlockHandler; + + /** Returns true if the area contains a continous path from the specified block to a log block entirely made out of leaves blocks. */ + static bool HasNearLog(cBlockArea & a_Area, const Vector3i a_BlockPos) + { + // Filter the blocks into a {leaves, log, other (air)} set: + auto * Types = a_Area.GetBlockTypes(); + for (size_t i = a_Area.GetBlockCount() - 1; i > 0; i--) + { + switch (Types[i]) + { + case E_BLOCK_LEAVES: + case E_BLOCK_LOG: + case E_BLOCK_NEW_LEAVES: + case E_BLOCK_NEW_LOG: + { + break; + } + default: + { + Types[i] = E_BLOCK_AIR; + break; + } + } + } // for i - Types[] + + // Perform a breadth-first search to see if there's a log connected within 4 blocks of the leaves block: + // Simply replace all reachable leaves blocks with a sponge block plus iteration (in the Area) and see if we can reach a log + a_Area.SetBlockType(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_SPONGE); + for (int i = 0; i < LEAVES_CHECK_DISTANCE; i++) + { + auto ProcessNeighbor = [&a_Area, i](int cbx, int cby, int cbz) -> bool + { + switch (a_Area.GetBlockType(cbx, cby, cbz)) + { + case E_BLOCK_LEAVES: a_Area.SetBlockType(cbx, cby, cbz, static_cast<BLOCKTYPE>(E_BLOCK_SPONGE + i + 1)); break; + case E_BLOCK_LOG: return true; + case E_BLOCK_NEW_LEAVES: a_Area.SetBlockType(cbx, cby, cbz, static_cast<BLOCKTYPE>(E_BLOCK_SPONGE + i + 1)); break; + case E_BLOCK_NEW_LOG: return true; + } + return false; + }; + for (int y = std::max(a_BlockPos.y - i, 0); y <= std::min(a_BlockPos.y + i, cChunkDef::Height - 1); y++) + { + for (int z = a_BlockPos.z - i; z <= a_BlockPos.z + i; z++) + { + for (int x = a_BlockPos.x - i; x <= a_BlockPos.x + i; x++) + { + if (a_Area.GetBlockType(x, y, z) != E_BLOCK_SPONGE + i) + { + continue; + } + if ( + ProcessNeighbor(x - 1, y, z) || + ProcessNeighbor(x + 1, y, z) || + ProcessNeighbor(x, y, z - 1) || + ProcessNeighbor(x, y, z + 1) || + ProcessNeighbor(x, y + 1, z) || + ProcessNeighbor(x, y - 1, z) + ) + { + return true; + } + } // for x + } // for z + } // for y + } // for i - BFS iterations + return false; + } + + public: - cBlockLeavesHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockLeavesHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } @@ -104,30 +163,34 @@ public: - virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { - NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + auto Meta = a_Chunk.GetMeta(a_RelPos); if ((Meta & 0x04) != 0) { // Player-placed leaves, don't decay return; } - if ((Meta & 0x8) == 0) + if ((Meta & 0x08) == 0) { // These leaves have been checked for decay lately and nothing around them changed return; } // Get the data around the leaves: - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; + auto worldPos = a_Chunk.RelativeToAbsolute(a_RelPos); cBlockArea Area; if (!Area.Read( *a_Chunk.GetWorld(), - BlockX - LEAVES_CHECK_DISTANCE, BlockX + LEAVES_CHECK_DISTANCE, - a_RelY - LEAVES_CHECK_DISTANCE, a_RelY + LEAVES_CHECK_DISTANCE, - BlockZ - LEAVES_CHECK_DISTANCE, BlockZ + LEAVES_CHECK_DISTANCE, + worldPos - Vector3i(LEAVES_CHECK_DISTANCE, LEAVES_CHECK_DISTANCE, LEAVES_CHECK_DISTANCE), + worldPos + Vector3i(LEAVES_CHECK_DISTANCE, LEAVES_CHECK_DISTANCE, LEAVES_CHECK_DISTANCE), cBlockArea::baTypes) ) { @@ -135,15 +198,15 @@ public: return; } - if (HasNearLog(Area, BlockX, a_RelY, BlockZ)) + if (HasNearLog(Area, worldPos)) { // Wood found, the leaves stay; unset the check bit - a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta ^ 0x08, true, false); + a_Chunk.SetMeta(a_RelPos, Meta ^ 0x08, true, false); return; } // Decay the leaves: - a_ChunkInterface.DropBlockAsPickups({BlockX, a_RelY, BlockZ}); + a_ChunkInterface.DropBlockAsPickups(worldPos); } @@ -156,62 +219,3 @@ public: return 7; } } ; - - - - - -bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ) -{ - // Filter the blocks into a {leaves, log, other (air)} set: - BLOCKTYPE * Types = a_Area.GetBlockTypes(); - for (size_t i = a_Area.GetBlockCount() - 1; i > 0; i--) - { - switch (Types[i]) - { - case E_BLOCK_LEAVES: - case E_BLOCK_LOG: - case E_BLOCK_NEW_LEAVES: - case E_BLOCK_NEW_LOG: - { - break; - } - default: - { - Types[i] = E_BLOCK_AIR; - break; - } - } - } // for i - Types[] - - // Perform a breadth-first search to see if there's a log connected within 4 blocks of the leaves block: - // Simply replace all reachable leaves blocks with a sponge block plus iteration (in the Area) and see if we can reach a log in 4 iterations - a_Area.SetBlockType(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SPONGE); - for (int i = 0; i < LEAVES_CHECK_DISTANCE; i++) - { - for (int y = std::max(a_BlockY - i, 0); y <= std::min(a_BlockY + i, cChunkDef::Height - 1); y++) - { - for (int z = a_BlockZ - i; z <= a_BlockZ + i; z++) - { - for (int x = a_BlockX - i; x <= a_BlockX + i; x++) - { - if (a_Area.GetBlockType(x, y, z) != E_BLOCK_SPONGE + i) - { - continue; - } - PROCESS_NEIGHBOR(x - 1, y, z); - PROCESS_NEIGHBOR(x + 1, y, z); - PROCESS_NEIGHBOR(x, y, z - 1); - PROCESS_NEIGHBOR(x, y, z + 1); - PROCESS_NEIGHBOR(x, y + 1, z); - PROCESS_NEIGHBOR(x, y - 1, z); - } // for x - } // for z - } // for y - } // for i - BFS iterations - return false; -} - - - - |