From 8480ee82eabec0ae4009d5049f7e471e5fda82df Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Jun 2020 18:34:39 +0100 Subject: [PATCH] Player: track hardcoded window state, fixes crashes opening inventory on high-latency connections --- src/pocketmine/Player.php | 18 +++++++++++++++--- src/pocketmine/block/CraftingTable.php | 22 +++++++++++++--------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 1f60f3717..4cea73907 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -176,6 +176,7 @@ use pocketmine\timings\Timings; use pocketmine\utils\TextFormat; use pocketmine\utils\UUID; use function abs; +use function array_key_exists; use function array_merge; use function array_values; use function assert; @@ -315,6 +316,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** @var CraftingTransaction|null */ protected $craftingTransaction = null; + /** + * TODO: HACK! This tracks GUIs for inventories that the server considers "always open" so that the client can't + * open them twice. (1.16 hack) + * @var true[] + * @phpstan-var array + * @internal + */ + public $openHardcodedWindows = []; + /** @var int */ protected $messageCounter = 2; /** @var bool */ @@ -2795,12 +2805,13 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ case InteractPacket::ACTION_MOUSEOVER: break; //TODO: handle these case InteractPacket::ACTION_OPEN_INVENTORY: - if($target === $this){ + if($target === $this && !array_key_exists($windowId = self::HARDCODED_INVENTORY_WINDOW_ID, $this->openHardcodedWindows)){ //TODO: HACK! this restores 1.14ish behaviour, but this should be able to be listened to and //controlled by plugins. However, the player is always a subscriber to their own inventory so it //doesn't integrate well with the regular container system right now. + $this->openHardcodedWindows[$windowId] = true; $pk = new ContainerOpenPacket(); - $pk->windowId = self::HARDCODED_INVENTORY_WINDOW_ID; + $pk->windowId = $windowId; $pk->type = WindowTypes::INVENTORY; $pk->x = $pk->y = $pk->z = 0; $pk->entityUniqueId = $this->getId(); @@ -3027,7 +3038,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->doCloseInventory(); - if($packet->windowId >= self::RESERVED_WINDOW_ID_RANGE_START and $packet->windowId <= self::RESERVED_WINDOW_ID_RANGE_END){ + if(array_key_exists($packet->windowId, $this->openHardcodedWindows)){ + unset($this->openHardcodedWindows[$packet->windowId]); $pk = new ContainerClosePacket(); $pk->windowId = $packet->windowId; $this->sendDataPacket($pk); diff --git a/src/pocketmine/block/CraftingTable.php b/src/pocketmine/block/CraftingTable.php index bb2fe5c39..0d898384c 100644 --- a/src/pocketmine/block/CraftingTable.php +++ b/src/pocketmine/block/CraftingTable.php @@ -28,6 +28,7 @@ use pocketmine\item\Item; use pocketmine\network\mcpe\protocol\ContainerOpenPacket; use pocketmine\network\mcpe\protocol\types\WindowTypes; use pocketmine\Player; +use function array_key_exists; class CraftingTable extends Solid{ @@ -53,15 +54,18 @@ class CraftingTable extends Solid{ if($player instanceof Player){ $player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG)); - //TODO: HACK! crafting grid doesn't fit very well into the current PM container system, so this hack allows - //it to carry on working approximately the same way as it did in 1.14 - $pk = new ContainerOpenPacket(); - $pk->windowId = Player::HARDCODED_CRAFTING_GRID_WINDOW_ID; - $pk->type = WindowTypes::WORKBENCH; - $pk->x = $this->getFloorX(); - $pk->y = $this->getFloorY(); - $pk->z = $this->getFloorZ(); - $player->sendDataPacket($pk); + if(!array_key_exists($windowId = Player::HARDCODED_CRAFTING_GRID_WINDOW_ID, $player->openHardcodedWindows)){ + //TODO: HACK! crafting grid doesn't fit very well into the current PM container system, so this hack allows + //it to carry on working approximately the same way as it did in 1.14 + $pk = new ContainerOpenPacket(); + $pk->windowId = $windowId; + $pk->type = WindowTypes::WORKBENCH; + $pk->x = $this->getFloorX(); + $pk->y = $this->getFloorY(); + $pk->z = $this->getFloorZ(); + $player->sendDataPacket($pk); + $player->openHardcodedWindows[$windowId] = true; + } } return true;