summaryrefslogtreecommitdiffstats
path: root/src/Blocks/BlockLeaves.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/Blocks/BlockLeaves.h')
-rw-r--r--src/Blocks/BlockLeaves.h176
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;
-}
-
-
-
-