From ee929793f09c431693e1bef7edd77213ba412f60 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 25 May 2014 13:46:34 +0100 Subject: Hopefully fixed piston duplication issues * Fixes #879 * Fixes #714 --- src/Blocks/BlockPiston.cpp | 166 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 161 insertions(+), 5 deletions(-) (limited to 'src/Blocks/BlockPiston.cpp') diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index 542eb33b5..f758013dc 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -4,14 +4,14 @@ #include "../Item.h" #include "../World.h" #include "../Entities/Player.h" -#include "../Piston.h" +#include "BlockInServerPluginInterface.h" #define AddPistonDir(x, y, z, dir, amount) \ - switch (dir) \ + switch (dir & 0x07) \ { \ case 0: (y) -= (amount); break; \ case 1: (y) += (amount); break; \ @@ -19,8 +19,15 @@ case 3: (z) += (amount); break; \ case 4: (x) -= (amount); break; \ case 5: (x) += (amount); break; \ + default: \ + { \ + LOGWARNING("%s: invalid direction %d, ignoring", __FUNCTION__, dir & 0x07); \ + break; \ + } \ } +#define PISTON_TICK_DELAY 1 + @@ -40,7 +47,7 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld int newX = a_BlockX; int newY = a_BlockY; int newZ = a_BlockZ; - AddPistonDir(newX, newY, newZ, OldMeta & ~(8), 1); + AddPistonDir(newX, newY, newZ, OldMeta, 1); if (a_ChunkInterface.GetBlock(newX, newY, newZ) == E_BLOCK_PISTON_EXTENSION) { @@ -60,7 +67,7 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta( ) { a_BlockType = m_BlockType; - a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch()); + a_BlockMeta = RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch()); return true; } @@ -68,6 +75,155 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta( +int cBlockPistonHandler::FirstPassthroughBlock(int pistonX, int pistonY, int pistonZ, NIBBLETYPE pistonmeta, cWorld * a_World) +{ + // Examine each of the 12 blocks ahead of the piston: + for (int ret = 0; ret < 12; ret++) + { + BLOCKTYPE currBlock; + NIBBLETYPE currMeta; + AddPistonDir(pistonX, pistonY, pistonZ, pistonmeta, 1); + a_World->GetBlockTypeMeta(pistonX, pistonY, pistonZ, currBlock, currMeta); + if (CanBreakPush(currBlock)) + { + // This block breaks when pushed, extend up to here + return ret; + } + if (!CanPush(currBlock, currMeta)) + { + // This block cannot be pushed at all, the piston can't extend + return -1; + } + } + // There is no space for the blocks to move, piston can't extend + return -1; +} + + + + + +void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) +{ + BLOCKTYPE pistonBlock; + NIBBLETYPE pistonMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta); + + if (IsExtended(pistonMeta)) + { + // Already extended, bail out + return; + } + + int dist = FirstPassthroughBlock(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, a_World); + if (dist < 0) + { + // FirstPassthroughBlock says piston can't push anything, bail out + return; + } + + a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 0, pistonMeta, pistonBlock); + a_World->BroadcastSoundEffect("tile.piston.out", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f); + + // Drop the breakable block in the line, if appropriate: + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, dist + 1); // "a_Block" now at the breakable / empty block + BLOCKTYPE currBlock; + NIBBLETYPE currMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, currBlock, currMeta); + if (currBlock != E_BLOCK_AIR) + { + cBlockHandler * Handler = BlockHandler(currBlock); + if (Handler->DoesDropOnUnsuitable()) + { + cChunkInterface ChunkInterface(a_World->GetChunkMap()); + cBlockInServerPluginInterface PluginInterface(*a_World); + Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, NULL, a_BlockX, a_BlockY, a_BlockZ); + } + } + + // Push blocks, from the furthest to the nearest: + int oldx = a_BlockX, oldy = a_BlockY, oldz = a_BlockZ; + NIBBLETYPE currBlockMeta; + for (int i = dist + 1; i > 1; i--) + { + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, currBlock, currBlockMeta); + a_World->SetBlock(oldx, oldy, oldz, currBlock, currBlockMeta, false); + a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(oldx, oldy, oldz)); + oldx = a_BlockX; + oldy = a_BlockY; + oldz = a_BlockZ; + } + + int extx = a_BlockX; + int exty = a_BlockY; + int extz = a_BlockZ; + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); + // "a_Block" now at piston body, "ext" at future extension + + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta | 0x8); + a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), false); + a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(extx, exty, extz)); +} + + + + + +void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) +{ + BLOCKTYPE pistonBlock; + NIBBLETYPE pistonMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta); + + if (!IsExtended(pistonMeta)) + { + // Already retracted, bail out + return; + } + + // Check the extension: + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, 1); + if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_PISTON_EXTENSION) + { + LOGD("%s: Piston without an extension - still extending, or just in an invalid state?", __FUNCTION__); + return; + } + + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta & ~(8)); + a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 1, pistonMeta & ~(8), pistonBlock); + a_World->BroadcastSoundEffect("tile.piston.in", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f); + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, 1); + + // Retract the extension, pull block if appropriate + if (IsSticky(pistonBlock)) + { + int tempx = a_BlockX, tempy = a_BlockY, tempz = a_BlockZ; + AddPistonDir(tempx, tempy, tempz, pistonMeta, 1); + BLOCKTYPE tempBlock; + NIBBLETYPE tempMeta; + a_World->GetBlockTypeMeta(tempx, tempy, tempz, tempBlock, tempMeta); + if (CanPull(tempBlock, tempMeta)) + { + // Pull the block + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, tempBlock, tempMeta, false); + a_World->SetBlock(tempx, tempy, tempz, E_BLOCK_AIR, 0, false); + a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(a_BlockX, a_BlockY, a_BlockZ)); + a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(tempx, tempy, tempz)); + return; + } + } + + // Retract without pulling + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0, false); + a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(a_BlockX, a_BlockY, a_BlockZ)); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cBlockPistonHeadHandler: @@ -87,7 +243,7 @@ void cBlockPistonHeadHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInter int newX = a_BlockX; int newY = a_BlockY; int newZ = a_BlockZ; - AddPistonDir(newX, newY, newZ, OldMeta & ~(8), -1); + AddPistonDir(newX, newY, newZ, OldMeta, -1); BLOCKTYPE Block = a_ChunkInterface.GetBlock(newX, newY, newZ); if ((Block == E_BLOCK_STICKY_PISTON) || (Block == E_BLOCK_PISTON)) -- cgit v1.2.3 From 365c6f50bd057eb62c66b9b222a07ca6efcb2c47 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 29 May 2014 11:57:06 +0100 Subject: Changed block send queue to use vectors As suggested by @worktycho. --- src/Blocks/BlockPiston.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'src/Blocks/BlockPiston.cpp') diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index f758013dc..1f8e0d9e0 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -27,6 +27,7 @@ } #define PISTON_TICK_DELAY 1 +#define PISTON_MAX_PUSH_DISTANCE 12 @@ -78,7 +79,7 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta( int cBlockPistonHandler::FirstPassthroughBlock(int pistonX, int pistonY, int pistonZ, NIBBLETYPE pistonmeta, cWorld * a_World) { // Examine each of the 12 blocks ahead of the piston: - for (int ret = 0; ret < 12; ret++) + for (int ret = 0; ret < PISTON_MAX_PUSH_DISTANCE; ret++) { BLOCKTYPE currBlock; NIBBLETYPE currMeta; @@ -144,12 +145,15 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, // Push blocks, from the furthest to the nearest: int oldx = a_BlockX, oldy = a_BlockY, oldz = a_BlockZ; NIBBLETYPE currBlockMeta; + std::vector ScheduledBlocks; + ScheduledBlocks.reserve(PISTON_MAX_PUSH_DISTANCE); + for (int i = dist + 1; i > 1; i--) { AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, currBlock, currBlockMeta); a_World->SetBlock(oldx, oldy, oldz, currBlock, currBlockMeta, false); - a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(oldx, oldy, oldz)); + ScheduledBlocks.push_back(Vector3i(oldx, oldy, oldz)); oldx = a_BlockX; oldy = a_BlockY; oldz = a_BlockZ; @@ -158,12 +162,13 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, int extx = a_BlockX; int exty = a_BlockY; int extz = a_BlockZ; + ScheduledBlocks.push_back(Vector3i(extx, exty, extz)); AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); // "a_Block" now at piston body, "ext" at future extension a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta | 0x8); a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), false); - a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(extx, exty, extz)); + a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks)); } @@ -209,15 +214,21 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ // Pull the block a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, tempBlock, tempMeta, false); a_World->SetBlock(tempx, tempy, tempz, E_BLOCK_AIR, 0, false); - a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(a_BlockX, a_BlockY, a_BlockZ)); - a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(tempx, tempy, tempz)); + + std::vector ScheduledBlocks; + ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); + ScheduledBlocks.push_back(Vector3i(tempx, tempy, tempz)); + a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks)); return; } } // Retract without pulling a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0, false); - a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(a_BlockX, a_BlockY, a_BlockZ)); + + std::vector ScheduledBlocks; + ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); + a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks)); } -- cgit v1.2.3 From a84f107400a326b0be27c290359220b8bf0e6635 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 1 Jun 2014 20:00:11 +0100 Subject: Suggestions two --- src/Blocks/BlockPiston.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Blocks/BlockPiston.cpp') diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index 1f8e0d9e0..faf639312 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -76,15 +76,15 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta( -int cBlockPistonHandler::FirstPassthroughBlock(int pistonX, int pistonY, int pistonZ, NIBBLETYPE pistonmeta, cWorld * a_World) +int cBlockPistonHandler::FirstPassthroughBlock(int a_PistonX, int a_PistonY, int a_PistonZ, NIBBLETYPE pistonmeta, cWorld * a_World) { // Examine each of the 12 blocks ahead of the piston: for (int ret = 0; ret < PISTON_MAX_PUSH_DISTANCE; ret++) { BLOCKTYPE currBlock; NIBBLETYPE currMeta; - AddPistonDir(pistonX, pistonY, pistonZ, pistonmeta, 1); - a_World->GetBlockTypeMeta(pistonX, pistonY, pistonZ, currBlock, currMeta); + AddPistonDir(a_PistonX, a_PistonY, a_PistonZ, pistonmeta, 1); + a_World->GetBlockTypeMeta(a_PistonX, a_PistonY, a_PistonZ, currBlock, currMeta); if (CanBreakPush(currBlock)) { // This block breaks when pushed, extend up to here -- cgit v1.2.3