summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Blocks/BlockHandler.h3
-rw-r--r--src/ClientHandle.cpp278
-rw-r--r--src/ClientHandle.h3
-rw-r--r--src/Protocol/Protocol_1_11.cpp2
-rw-r--r--src/Protocol/Protocol_1_12.cpp2
-rw-r--r--src/Protocol/Protocol_1_8.cpp12
-rw-r--r--src/Protocol/Protocol_1_9.cpp27
-rw-r--r--src/Protocol/Protocol_1_9.h4
8 files changed, 173 insertions, 158 deletions
diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h
index d027d3cdc..7fbc15ff5 100644
--- a/src/Blocks/BlockHandler.h
+++ b/src/Blocks/BlockHandler.h
@@ -81,7 +81,8 @@ public:
returns true if the use was successful, return false to use the block as a "normal" block */
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { return false; }
- /** Called when a right click to this block is cancelled */
+ /** Called when a right click to this block is cancelled.
+ It forces the server to send the real state of a block to the client to prevent client assuming the operation is successfull */
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) {}
/** Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents */
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 8470e7de6..3a07de7f1 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1395,186 +1395,113 @@ void cClientHandle::FinishDigAnimation()
-void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem)
-{
- // TODO: Rewrite this function
-
+void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, eHand a_Hand)
+{
+ // This function handles three actions:
+ // (1) Place a block;
+ // (2) "Use" a block: Interactive with the block, like opening a chest/crafting table/furnace;
+ // (3) Use the held item targeting a block. E.g. farming.
+ //
+ // Sneaking player will not use the block if hand is not empty.
+ // Frozen player can do nothing.
+ // In Game Mode Spectator, player cannot use item or place block, but can interactive with some block depending on cBlockInfo::IsUseableBySpectator(BlockType)
+ //
+ // If the action failed, we need to send an update of the placed block or inventory to the client.
+ //
+ // Actions rejected by plugin will not lead to other attempts.
+ // E.g., when opening a chest with a dirt in hand, if the plugin rejects opening the chest, the dirt will not be placed.
+
+ // TODO: We are still consuming the items in main hand. Remove this override when the off-hand consumption is handled correctly.
+ a_Hand = eHand::hMain;
+ const cItem & HeldItem = (a_Hand == eHand::hOff) ? m_Player->GetInventory().GetShieldSlot() : m_Player->GetEquippedItem();
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(HeldItem.m_ItemType);
+
+ // TODO: This distance should be calculated from the point that the cursor pointing at, instead of the center of the block
// Distance from the block's center to the player's eye height
- double dist = (Vector3d(a_BlockX, a_BlockY, a_BlockZ) + Vector3d(0.5, 0.5, 0.5) - m_Player->GetEyePosition()).Length();
- LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s; dist: %.02f",
- a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str(), dist
+ double Dist = (Vector3d(a_BlockX, a_BlockY, a_BlockZ) + Vector3d(0.5, 0.5, 0.5) - m_Player->GetEyePosition()).Length();
+ LOGD("HandleRightClick: {%d, %d, %d}, face %d, Hand: %d, HeldItem: %s; Dist: %.02f",
+ a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Hand, ItemToFullString(HeldItem).c_str(), Dist
);
// Check the reach distance:
// _X 2014-11-25: I've maxed at 5.26 with a Survival client and 5.78 with a Creative client in my tests
- double maxDist = m_Player->IsGameModeCreative() ? 5.78 : 5.26;
- bool AreRealCoords = (dist <= maxDist);
-
+ double MaxDist = m_Player->IsGameModeCreative() ? 5.78 : 5.26;
+ bool IsWithinReach = (Dist <= MaxDist);
cWorld * World = m_Player->GetWorld();
-
- if (
- (a_BlockFace != BLOCK_FACE_NONE) && // The client is interacting with a specific block
- IsValidBlock(a_HeldItem.m_ItemType) &&
- !AreRealCoords
- )
- {
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- if ((a_BlockX != -1) && (a_BlockY >= 0) && (a_BlockZ != -1))
- {
- if (cChunkDef::IsValidHeight(a_BlockY))
- {
- World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, *m_Player);
- }
- if (cChunkDef::IsValidHeight(a_BlockY + 1))
- {
- World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, *m_Player); // 2 block high things
- }
- if (cChunkDef::IsValidHeight(a_BlockY - 1))
- {
- World->SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, *m_Player); // 2 block high things
- }
- }
- m_Player->GetInventory().SendEquippedSlot();
- return;
- }
-
- if (!AreRealCoords)
- {
- a_BlockFace = BLOCK_FACE_NONE;
- }
-
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
- if (m_Player->IsFrozen() || PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
- {
- // A plugin doesn't agree with the action, replace the block on the client and quit:
- if (AreRealCoords)
- {
- cChunkInterface ChunkInterface(World->GetChunkMap());
- BLOCKTYPE BlockType = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
- BlockHandler->OnCancelRightClick(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-
- if (a_BlockFace != BLOCK_FACE_NONE)
- {
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- if (cChunkDef::IsValidHeight(a_BlockY))
- {
- World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, *m_Player);
- }
- if (cChunkDef::IsValidHeight(a_BlockY + 1))
- {
- World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, *m_Player); // 2 block high things
- }
- if (cChunkDef::IsValidHeight(a_BlockY - 1))
- {
- World->SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, *m_Player); // 2 block high things
- }
- m_Player->GetInventory().SendEquippedSlot();
- }
- }
- return;
- }
-
- m_NumBlockChangeInteractionsThisTick++;
-
- if (!CheckBlockInteractionsRate())
- {
- Kick("Too many blocks were placed / interacted with per unit time - hacked client?");
- return;
- }
-
- const cItem & Equipped = m_Player->GetInventory().GetEquippedItem();
-
- if ((Equipped.m_ItemType != a_HeldItem.m_ItemType) && (a_HeldItem.m_ItemType != -1))
- {
- // Only compare ItemType, not meta (torches have different metas)
- // The -1 check is there because sometimes the client sends -1 instead of the held item
- // Ref.: https://forum.cuberite.org/thread-549-post-4502.html#pid4502
- LOGWARN("Player %s tried to place a block that was not equipped (exp %d, got %d)",
- m_Username.c_str(), Equipped.m_ItemType, a_HeldItem.m_ItemType
- );
-
- // Let's send the current world block to the client, so that it can immediately "let the user know" that they haven't placed the block
- if (a_BlockFace != BLOCK_FACE_NONE)
- {
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, *m_Player);
- }
- return;
- }
- if (AreRealCoords)
+ bool Success = false;
+ if (IsWithinReach && !m_Player->IsFrozen())
{
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
- if (BlockHandler->IsUseable() && !m_Player->IsCrouched() && (!m_Player->IsGameModeSpectator() || cBlockInfo::IsUseableBySpectator(BlockType)))
+ bool Placeable = ItemHandler->IsPlaceable() && !m_Player->IsGameModeSpectator();
+ bool BlockUsable = BlockHandler->IsUseable() && (!m_Player->IsGameModeSpectator() || cBlockInfo::IsUseableBySpectator(BlockType));
+
+ if (BlockUsable && !(m_Player->IsCrouched() && !HeldItem.IsEmpty()))
{
+ // use a block
+ cChunkInterface ChunkInterface(World->GetChunkMap());
if (!PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
{
- cChunkInterface ChunkInterface(World->GetChunkMap());
if (BlockHandler->OnUse(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
{
// block use was successful, we're done
PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
- return;
+ Success = true;
}
}
+ else
+ {
+ // TODO: OnCancelRightClick seems to do the same thing with updating blocks at the end of this function. Need to double check
+ // A plugin doesn't agree with the action, replace the block on the client and quit:
+ BlockHandler->OnCancelRightClick(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ }
}
- }
-
- // Players, who spectate cannot use their items
- if (m_Player->IsGameModeSpectator())
- {
- return;
- }
-
- short EquippedDamage = Equipped.m_ItemDamage;
- cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType);
-
- if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE))
- {
- if (!ItemHandler->OnPlayerPlace(*World, *m_Player, Equipped, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
- {
- // Placement failed, bail out
- return;
- }
- }
- else if ((ItemHandler->IsFood() || ItemHandler->IsDrinkable(EquippedDamage)))
- {
- if (
- (m_Player->IsSatiated() || m_Player->IsGameModeCreative()) && // Only creative or hungry players can eat
- ItemHandler->IsFood() &&
- (Equipped.m_ItemType != E_ITEM_GOLDEN_APPLE) // Golden apple is a special case, it is used instead of eaten
- )
+ else if (Placeable)
{
- // The player is satiated or in creative, and trying to eat
- return;
+ // TODO: Double check that we don't need this for using item and for packet out of range
+ m_NumBlockChangeInteractionsThisTick++;
+ if (!CheckBlockInteractionsRate())
+ {
+ Kick("Too many blocks were placed / interacted with per unit time - hacked client?");
+ return;
+ }
+ if (!PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
+ {
+ // place a block
+ Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
+ }
}
- m_Player->StartEating();
- if (m_Player->IsFrozen() || PlgMgr->CallHookPlayerEating(*m_Player))
+ else
{
- // A plugin won't let us eat, abort (send the proper packets to the client, too):
- m_Player->AbortEating();
+ // Use an item in hand with a target block
+ if (!PlgMgr->CallHookPlayerUsingItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
+ {
+ // All plugins agree with using the item
+ cBlockInServerPluginInterface PluginInterface(*World);
+ ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ PlgMgr->CallHookPlayerUsedItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
+ Success = true;
+ }
}
}
- else
+ if (!Success)
{
- if (m_Player->IsFrozen() || PlgMgr->CallHookPlayerUsingItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
+ // Update the target block including the block above and below for 2 block high things
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ for (int y = a_BlockY - 1; y <= a_BlockY + 1; y++)
{
- // A plugin doesn't agree with using the item, abort
- return;
+ if (cChunkDef::IsValidHeight(y))
+ {
+ World->SendBlockTo(a_BlockX, y, a_BlockZ, *m_Player);
+ }
}
- cBlockInServerPluginInterface PluginInterface(*World);
- ItemHandler->OnItemUse(World, m_Player, PluginInterface, Equipped, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- PlgMgr->CallHookPlayerUsedItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
- }
- // Charge bow when it's in slot off-hand / shield
- if ((a_BlockFace == BLOCK_FACE_NONE) && (m_Player->GetInventory().GetShieldSlot().m_ItemType == E_ITEM_BOW))
- {
- m_Player->StartChargingBow();
+ // TODO: Send corresponding slot based on hand
+ m_Player->GetInventory().SendEquippedSlot();
}
}
@@ -1810,6 +1737,61 @@ void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
+void cClientHandle::HandleUseItem(eHand a_Hand)
+{
+ // Use the held item without targeting a block: eating, drinking, charging a bow, using buckets
+ // In version 1.8.x, this function shares the same packet id with HandleRightClick.
+ // In version >= 1.9, there is a new packet id for "Use Item".
+
+ // TODO: We are still consuming the items in main hand. Remove this override when the off-hand consumption is handled correctly.
+ a_Hand = eHand::hMain;
+ const cItem & HeldItem = (a_Hand == eHand::hOff) ? m_Player->GetInventory().GetShieldSlot() : m_Player->GetEquippedItem();
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(HeldItem.m_ItemType);
+ cWorld * World = m_Player->GetWorld();
+ cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
+
+ LOGD("HandleUseItem: Hand: %d; HeldItem: %s", a_Hand, ItemToFullString(HeldItem).c_str());
+
+ // Use item in main / off hand
+ // TODO: do we need to sync the current inventory with client if it fails?
+ if (m_Player->IsFrozen() || m_Player->IsGameModeSpectator())
+ {
+ return;
+ }
+
+ if (ItemHandler->IsFood() || ItemHandler->IsDrinkable(HeldItem.m_ItemDamage))
+ {
+ if (
+ ItemHandler->IsFood() &&
+ (m_Player->IsSatiated() || m_Player->IsGameModeCreative()) && // Only non-creative or hungry players can eat
+ (HeldItem.m_ItemType != E_ITEM_GOLDEN_APPLE) // Golden apple is a special case, it is used instead of eaten
+ )
+ {
+ // The player is satiated or in creative, and trying to eat
+ return;
+ }
+ if (!PlgMgr->CallHookPlayerEating(*m_Player))
+ {
+ m_Player->StartEating();
+ }
+ }
+ else
+ {
+ // Use an item in hand without a target block
+ if (!PlgMgr->CallHookPlayerUsingItem(*m_Player, -1, 255, -1, BLOCK_FACE_NONE, 0, 0, 0))
+ {
+ // All plugins agree with using the item
+ cBlockInServerPluginInterface PluginInterface(*World);
+ ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, -1, 255, -1, BLOCK_FACE_NONE);
+ PlgMgr->CallHookPlayerUsedItem(*m_Player, -1, 255, -1, BLOCK_FACE_NONE, 0, 0, 0);
+ }
+ }
+}
+
+
+
+
+
void cClientHandle::HandleRespawn(void)
{
if (m_Player == nullptr)
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 42e2ee10a..78da199a7 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -356,7 +356,7 @@ public: // tolua_export
void HandlePluginMessage (const AString & a_Channel, const AString & a_Message);
void HandleRespawn (void);
- void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem);
+ void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, eHand a_Hand);
void HandleSlotSelected (Int16 a_SlotNum);
void HandleSpectate (const cUUID & a_PlayerUUID);
void HandleSteerVehicle (float Forward, float Sideways);
@@ -368,6 +368,7 @@ public: // tolua_export
);
void HandleUnmount (void);
void HandleUseEntity (UInt32 a_TargetEntityID, bool a_IsLeftClick);
+ void HandleUseItem (eHand a_Hand);
void HandleWindowClick (UInt8 a_WindowID, Int16 a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem);
void HandleWindowClose (UInt8 a_WindowID);
diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp
index c0c8815e8..f5df4e646 100644
--- a/src/Protocol/Protocol_1_11.cpp
+++ b/src/Protocol/Protocol_1_11.cpp
@@ -550,7 +550,7 @@ void cProtocol_1_11_0::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorX);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorY);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorZ);
- m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), FloorC(CursorX * 16), FloorC(CursorY * 16), FloorC(CursorZ * 16), m_Client->GetPlayer()->GetEquippedItem());
+ m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), FloorC(CursorX * 16), FloorC(CursorY * 16), FloorC(CursorZ * 16), HandIntToEnum(Hand));
}
diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp
index b804dd351..a3d1952ed 100644
--- a/src/Protocol/Protocol_1_12.cpp
+++ b/src/Protocol/Protocol_1_12.cpp
@@ -363,7 +363,7 @@ void cProtocol_1_12::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorX);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorY);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorZ);
- m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), FloorC(CursorX * 16), FloorC(CursorY * 16), FloorC(CursorZ * 16), m_Client->GetPlayer()->GetEquippedItem());
+ m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), FloorC(CursorX * 16), FloorC(CursorY * 16), FloorC(CursorZ * 16), HandIntToEnum(Hand));
}
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index 4568ad8cb..41e168c95 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -2329,13 +2329,21 @@ void cProtocol_1_8_0::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face);
- cItem Item;
+ cItem Item; // Ignored
ReadItem(a_ByteBuffer, Item, 3);
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorX);
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorY);
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorZ);
- m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem());
+ eBlockFace blockFace = FaceIntToBlockFace(Face);
+ if (blockFace == eBlockFace::BLOCK_FACE_NONE)
+ {
+ m_Client->HandleUseItem(eHand::hMain);
+ }
+ else
+ {
+ m_Client->HandleRightClick(BlockX, BlockY, BlockZ, blockFace, CursorX, CursorY, CursorZ, eHand::hMain);
+ }
}
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index 2b66cc7fa..3e600cefd 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -66,6 +66,7 @@ static const Int16 SLOT_NUM_OUTSIDE = -999;
/** Value for main hand in Hand parameter for Protocol 1.9. */
static const UInt32 MAIN_HAND = 0;
+static const UInt32 OFF_HAND = 1;
@@ -2384,7 +2385,7 @@ void cProtocol_1_9_0::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorX);
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorY);
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorZ);
- m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem());
+ m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, HandIntToEnum(Hand));
}
@@ -2784,10 +2785,9 @@ void cProtocol_1_9_0::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer)
void cProtocol_1_9_0::HandlePacketUseItem(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt64, Hand);
+ HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Hand);
- // Didn't click a block - emulate old values used with place block of -1, -1, -1 (and BLOCK_FACE_NONE).
- m_Client->HandleRightClick(-1, 255, -1, BLOCK_FACE_NONE, 0, 0, 0, m_Client->GetPlayer()->GetEquippedItem());
+ m_Client->HandleUseItem(HandIntToEnum(Hand));
}
@@ -3267,6 +3267,25 @@ eBlockFace cProtocol_1_9_0::FaceIntToBlockFace(Int32 a_BlockFace)
+eHand cProtocol_1_9_0::HandIntToEnum(Int32 a_Hand)
+{
+ // Convert hand parameter into eHand enum
+ switch (a_Hand)
+ {
+ case MAIN_HAND: return eHand::hMain;
+ case OFF_HAND: return eHand::hOff;
+ default:
+ {
+ ASSERT(!"Unknown hand value");
+ return eHand::hMain;
+ }
+ }
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// cProtocol_1_9_0::cPacketizer:
diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h
index d08b76755..a7fd137a9 100644
--- a/src/Protocol/Protocol_1_9.h
+++ b/src/Protocol/Protocol_1_9.h
@@ -255,6 +255,10 @@ protected:
If the received value doesn't match any of our eBlockFace constants, BLOCK_FACE_NONE is returned. */
eBlockFace FaceIntToBlockFace(Int32 a_FaceInt);
+ /** Converts the hand parameter received by the protocol into eHand constants.
+ If the received value doesn't match any of the know value, raise an assertion fail or return hMain. */
+ eHand HandIntToEnum(Int32 a_Hand);
+
/** Writes the item data into a packet. */
void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item);