summaryrefslogtreecommitdiffstats
path: root/src/Blocks
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Blocks/BlockDropSpenser.h4
-rw-r--r--src/Blocks/BlockFurnace.h4
-rw-r--r--src/Blocks/BlockMobHead.h2
-rw-r--r--src/Blocks/BlockPiston.cpp177
-rw-r--r--src/Blocks/BlockPiston.h134
5 files changed, 310 insertions, 11 deletions
diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h
index 88b61a418..e2b3039fd 100644
--- a/src/Blocks/BlockDropSpenser.h
+++ b/src/Blocks/BlockDropSpenser.h
@@ -5,7 +5,7 @@
#pragma once
-#include "../Piston.h"
+#include "../Blocks/BlockPiston.h"
#include "MetaRotator.h"
@@ -32,7 +32,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for dispenser placement!
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
+ a_BlockMeta = cBlockPistonHandler::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h
index a7a807957..74582c3b3 100644
--- a/src/Blocks/BlockFurnace.h
+++ b/src/Blocks/BlockFurnace.h
@@ -3,7 +3,7 @@
#include "BlockEntity.h"
#include "../World.h"
-#include "../Piston.h"
+#include "../Blocks/BlockPiston.h"
#include "MetaRotator.h"
@@ -35,7 +35,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for furnace placement!
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), 0);
+ a_BlockMeta = cBlockPistonHandler::RotationPitchToMetaData(a_Player->GetYaw(), 0);
return true;
}
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
index b7629b07c..9855574ad 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -68,7 +68,7 @@ public:
public:
cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {}
- } PlayerCallback(Vector3f(a_BlockX, a_BlockY, a_BlockZ));
+ } PlayerCallback(Vector3f((float)a_BlockX, (float)a_BlockY, (float)a_BlockZ));
a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA);
diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp
index 542eb33b5..faf639312 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,16 @@
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
+#define PISTON_MAX_PUSH_DISTANCE 12
+
@@ -40,7 +48,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 +68,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 +76,165 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
+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(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
+ 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;
+ std::vector<Vector3i> 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);
+ ScheduledBlocks.push_back(Vector3i(oldx, oldy, oldz));
+ oldx = a_BlockX;
+ oldy = a_BlockY;
+ oldz = 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(ScheduledBlocks));
+}
+
+
+
+
+
+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);
+
+ std::vector<Vector3i> 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);
+
+ std::vector<Vector3i> ScheduledBlocks;
+ ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
+ a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBlockPistonHeadHandler:
@@ -87,7 +254,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))
diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h
index 7632b5e5a..e6fa48e54 100644
--- a/src/Blocks/BlockPiston.h
+++ b/src/Blocks/BlockPiston.h
@@ -21,6 +21,138 @@ public:
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override;
+
+ static NIBBLETYPE RotationPitchToMetaData(double a_Rotation, double a_Pitch)
+ {
+ if (a_Pitch >= 50)
+ {
+ return 0x1;
+ }
+ else if (a_Pitch <= -50)
+ {
+ return 0x0;
+ }
+ else
+ {
+ a_Rotation += 90 + 45; // So its not aligned with axis
+
+ if (a_Rotation > 360)
+ {
+ a_Rotation -= 360;
+ }
+ if ((a_Rotation >= 0) && (a_Rotation < 90))
+ {
+ return 0x4;
+ }
+ else if ((a_Rotation >= 180) && (a_Rotation < 270))
+ {
+ return 0x5;
+ }
+ else if ((a_Rotation >= 90) && (a_Rotation < 180))
+ {
+ return 0x2;
+ }
+ else
+ {
+ return 0x3;
+ }
+ }
+ }
+
+ static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData)
+ {
+ switch (a_MetaData)
+ {
+ case 0x0: return BLOCK_FACE_YM;
+ case 0x1: return BLOCK_FACE_YP;
+ case 0x2: return BLOCK_FACE_ZM;
+ case 0x3: return BLOCK_FACE_ZP;
+ case 0x4: return BLOCK_FACE_XM;
+ case 0x5: return BLOCK_FACE_XP;
+ default:
+ {
+ ASSERT(!"Invalid Metadata");
+ return BLOCK_FACE_NONE;
+ }
+ }
+ }
+
+ static void ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
+ static void RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
+
+private:
+
+ /// Returns true if the piston (specified by blocktype) is a sticky piston
+ static inline bool IsSticky(BLOCKTYPE a_BlockType) { return (a_BlockType == E_BLOCK_STICKY_PISTON); }
+
+ /// Returns true if the piston (with the specified meta) is extended
+ static inline bool IsExtended(NIBBLETYPE a_PistonMeta) { return ((a_PistonMeta & 0x8) != 0x0); }
+
+ /// Returns true if the specified block can be pushed by a piston (and left intact)
+ static inline bool CanPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+ {
+ switch (a_BlockType)
+ {
+ case E_BLOCK_ANVIL:
+ case E_BLOCK_BED:
+ case E_BLOCK_BEDROCK:
+ case E_BLOCK_BREWING_STAND:
+ case E_BLOCK_CHEST:
+ case E_BLOCK_COMMAND_BLOCK:
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ case E_BLOCK_ENCHANTMENT_TABLE:
+ case E_BLOCK_END_PORTAL:
+ case E_BLOCK_END_PORTAL_FRAME:
+ case E_BLOCK_FURNACE:
+ case E_BLOCK_LIT_FURNACE:
+ case E_BLOCK_HOPPER:
+ case E_BLOCK_JUKEBOX:
+ case E_BLOCK_MOB_SPAWNER:
+ case E_BLOCK_NETHER_PORTAL:
+ case E_BLOCK_NOTE_BLOCK:
+ case E_BLOCK_OBSIDIAN:
+ case E_BLOCK_PISTON_EXTENSION:
+ {
+ return false;
+ }
+ case E_BLOCK_STICKY_PISTON:
+ case E_BLOCK_PISTON:
+ {
+ // A piston can only be pushed if retracted:
+ return !IsExtended(a_BlockMeta);
+ }
+ }
+ return true;
+ }
+
+ /// Returns true if the specified block can be pushed by a piston and broken / replaced
+ static inline bool CanBreakPush(BLOCKTYPE a_BlockType) { return cBlockInfo::IsPistonBreakable(a_BlockType); }
+
+ /// Returns true if the specified block can be pulled by a sticky piston
+ static inline bool CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+ {
+ switch (a_BlockType)
+ {
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
+ case E_BLOCK_STATIONARY_WATER:
+ case E_BLOCK_WATER:
+ {
+ return false;
+ }
+ }
+
+ if (CanBreakPush(a_BlockType))
+ {
+ return false; // CanBreakPush returns true, but we need false to prevent pulling
+ }
+
+ return CanPush(a_BlockType, a_BlockMeta);
+ }
+
+ /// Returns how many blocks the piston has to push (where the first free space is); < 0 when unpushable
+ static int FirstPassthroughBlock(int a_PistonX, int a_PistonY, int a_PistonZ, NIBBLETYPE a_PistonMeta, cWorld * a_World);
} ;
@@ -40,7 +172,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// No pickups
- // Also with 1.7, the item forms of these tecnical blocks have been removed, so giving someone this will crash their client...
+ // Also with 1.7, the item forms of these technical blocks have been removed, so giving someone this will crash their client...
}
} ;