diff options
Diffstat (limited to '')
-rw-r--r-- | src/Blocks/BlockHandler.h | 3 | ||||
-rw-r--r-- | src/ClientHandle.cpp | 278 | ||||
-rw-r--r-- | src/ClientHandle.h | 3 | ||||
-rw-r--r-- | src/Protocol/Protocol_1_11.cpp | 2 | ||||
-rw-r--r-- | src/Protocol/Protocol_1_12.cpp | 2 | ||||
-rw-r--r-- | src/Protocol/Protocol_1_8.cpp | 12 | ||||
-rw-r--r-- | src/Protocol/Protocol_1_9.cpp | 27 | ||||
-rw-r--r-- | src/Protocol/Protocol_1_9.h | 4 |
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); |