Properly handle transaction building errors instead of kicking the player

This commit is contained in:
Dylan K. Taylor
2023-03-20 00:52:26 +00:00
parent 4864444440
commit 7b0816e42f
5 changed files with 104 additions and 63 deletions

View File

@ -29,7 +29,7 @@ use pocketmine\network\mcpe\protocol\types\inventory\ContainerUIIds;
use pocketmine\network\mcpe\protocol\types\inventory\stackresponse\ItemStackResponse;
use pocketmine\network\mcpe\protocol\types\inventory\stackresponse\ItemStackResponseContainerInfo;
use pocketmine\network\mcpe\protocol\types\inventory\stackresponse\ItemStackResponseSlotInfo;
use pocketmine\network\PacketHandlingException;
use pocketmine\utils\AssumptionFailedError;
final class ItemStackResponseBuilder{
@ -51,15 +51,15 @@ final class ItemStackResponseBuilder{
/**
* @phpstan-return array{Inventory, int}
*/
private function getInventoryAndSlot(int $containerInterfaceId, int $slotId) : array{
private function getInventoryAndSlot(int $containerInterfaceId, int $slotId) : ?array{
$windowId = ItemStackContainerIdTranslator::translate($containerInterfaceId, $this->inventoryManager->getCurrentWindowId());
$windowAndSlot = $this->inventoryManager->locateWindowAndSlot($windowId, $slotId);
if($windowAndSlot === null){
throw new PacketHandlingException("Stack request action cannot target an inventory that is not open");
return null;
}
[$inventory, $slot] = $windowAndSlot;
if(!$inventory->slotExists($slot)){
throw new PacketHandlingException("Stack request action cannot target an inventory slot that does not exist");
return null;
}
return [$inventory, $slot];
@ -72,16 +72,21 @@ final class ItemStackResponseBuilder{
continue;
}
foreach($slotIds as $slotId){
[$inventory, $slot] = $this->getInventoryAndSlot($containerInterfaceId, $slotId);
$inventoryAndSlot = $this->getInventoryAndSlot($containerInterfaceId, $slotId);
if($inventoryAndSlot === null){
//a plugin may have closed the inventory during an event, or the slot may have been invalid
continue;
}
[$inventory, $slot] = $inventoryAndSlot;
$itemStackInfo = $this->inventoryManager->getItemStackInfo($inventory, $slot);
if($itemStackInfo === null){
//TODO: what if a plugin closes the inventory while the transaction is ongoing?
throw new \LogicException("ItemStackInfo should never be null for an open inventory");
throw new AssumptionFailedError("ItemStackInfo should never be null for an open inventory");
}
if($itemStackInfo->getRequestId() !== $this->requestId){
//the itemstack may have been synced due to transaction producing results that the client did not
//predict correctly, which will wipe out the tracked request ID (intentionally)
//TODO: is this the correct behaviour?
continue;
}
$item = $inventory->getItem($slot);