From a4f2b99ed55c97180531a4086bbbfb5df3c56177 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 24 Apr 2023 14:06:29 +0100 Subject: [PATCH] InGamePacketHandler: queue slots for syncing if they appear in requestChangedSlots this is essentially a prediction without the actual predicted item. We have to sync these regardless of what happens. fixes #5708 --- .../mcpe/handler/InGamePacketHandler.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 37f23e158..12859be46 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -328,6 +328,9 @@ class InGamePacketHandler extends PacketHandler{ if(count($packet->trData->getActions()) > 50){ throw new PacketHandlingException("Too many actions in inventory transaction"); } + if(count($packet->requestChangedSlots) > 10){ + throw new PacketHandlingException("Too many slot sync requests in inventory transaction"); + } $this->inventoryManager->setCurrentItemStackRequestId($packet->requestId); $this->inventoryManager->addRawPredictedSlotChanges($packet->trData->getActions()); @@ -347,6 +350,21 @@ class InGamePacketHandler extends PacketHandler{ } $this->inventoryManager->syncMismatchedPredictedSlotChanges(); + + //requestChangedSlots asks the server to always send out the contents of the specified slots, even if they + //haven't changed. Handling these is necessary to ensure the client inventory stays in sync if the server + //rejects the transaction. The most common example of this is equipping armor by right-click, which doesn't send + //a legacy prediction action for the destination armor slot. + foreach($packet->requestChangedSlots as $containerInfo){ + $windowId = ItemStackContainerIdTranslator::translate($containerInfo->getContainerId(), $this->inventoryManager->getCurrentWindowId()); + foreach($containerInfo->getChangedSlotIndexes() as $slot){ + $inventoryAndSlot = $this->inventoryManager->locateWindowAndSlot($windowId, $slot); + if($inventoryAndSlot !== null){ //trigger the normal slot sync logic + $this->inventoryManager->onSlotChange($inventoryAndSlot[0], $inventoryAndSlot[1]); + } + } + } + $this->inventoryManager->setCurrentItemStackRequestId(null); return $result; }