From 74ee94b3858af425dfb6a6c4de8350586dddf4e1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 10 Aug 2017 20:02:31 +0100 Subject: [PATCH] Duct tape for inventory transactions, removed ContainerSetSlotPacket --- src/pocketmine/Player.php | 127 +++++------------- .../inventory/PlayerCursorInventory.php | 91 +++++++++++++ .../mcpe/PlayerNetworkSessionAdapter.php | 11 -- .../mcpe/protocol/ContainerSetSlotPacket.php | 64 --------- 4 files changed, 128 insertions(+), 165 deletions(-) create mode 100644 src/pocketmine/inventory/PlayerCursorInventory.php delete mode 100644 src/pocketmine/network/mcpe/protocol/ContainerSetSlotPacket.php diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index e6f9daa09d..d916f3ea97 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -78,6 +78,7 @@ use pocketmine\inventory\BigShapedRecipe; use pocketmine\inventory\BigShapelessRecipe; use pocketmine\inventory\FurnaceInventory; use pocketmine\inventory\Inventory; +use pocketmine\inventory\PlayerCursorInventory; use pocketmine\inventory\PlayerInventory; use pocketmine\inventory\ShapedRecipe; use pocketmine\inventory\ShapelessRecipe; @@ -116,7 +117,6 @@ use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket; use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket; use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket; use pocketmine\network\mcpe\protocol\ContainerClosePacket; -use pocketmine\network\mcpe\protocol\ContainerSetSlotPacket; use pocketmine\network\mcpe\protocol\CraftingEventPacket; use pocketmine\network\mcpe\protocol\DataPacket; use pocketmine\network\mcpe\protocol\DisconnectPacket; @@ -239,6 +239,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ protected $currentTransaction = null; public $craftingType = 0; //0 = 2x2 crafting, 1 = 3x3 crafting, 2 = stonecutter + /** @var PlayerCursorInventory */ + protected $cursorInventory; + public $creationTime = 0; protected $randomClientId; @@ -2149,13 +2152,39 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ return true; } + /** + * Don't expect much from this handler. Most of it is roughly hacked and duct-taped together. + * + * @param InventoryTransactionPacket $packet + * @return bool + */ public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{ switch($packet->transactionData->transactionType){ - case 0: - //normal inventory transfer (TODO handle) - break; - case InventoryTransactionPacket::TYPE_USE_ITEM: + case InventoryTransactionPacket::TYPE_NORMAL: + $transaction = new SimpleTransactionGroup($this); + foreach($packet->actions as $action){ + if($action->inventorySource->sourceType !== InventoryTransactionPacket::SOURCE_CONTAINER){ + return false; //TODO: handle other source types + } + + if($action->inventorySource->containerId === ContainerIds::ARMOR){ + $transaction->addTransaction(new BaseTransaction($this->inventory, $action->inventorySlot + $this->inventory->getSize(), $action->oldItem, $action->newItem)); + continue; + } + + $transaction->addTransaction(new BaseTransaction($this->windowIndex[$action->inventorySource->containerId], $action->inventorySlot, $action->oldItem, $action->newItem)); + } + + if(!$transaction->execute()){ + //need to resend/revert/whatever (TODO) + return false; //oops! + } + + //TODO: fix achievement for getting iron from furnace + + return true; + case InventoryTransactionPacket::TYPE_USE_ITEM: $blockVector = new Vector3($packet->transactionData->x, $packet->transactionData->y, $packet->transactionData->z); $face = $packet->transactionData->face; @@ -2834,91 +2863,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ return true; } - public function handleContainerSetSlot(ContainerSetSlotPacket $packet) : bool{ - if($this->spawned === false or !$this->isAlive()){ - return true; - } - - if($packet->slot < 0){ - return false; - } - - switch($packet->windowid){ - case ContainerIds::INVENTORY: //Normal inventory change - if($packet->slot >= $this->inventory->getSize()){ - return false; - } - - $transaction = new BaseTransaction($this->inventory, $packet->slot, $this->inventory->getItem($packet->slot), $packet->item); - break; - case ContainerIds::ARMOR: //Armour change - if($packet->slot >= 4){ - return false; - } - - $transaction = new BaseTransaction($this->inventory, $packet->slot + $this->inventory->getSize(), $this->inventory->getArmorItem($packet->slot), $packet->item); - break; - case ContainerIds::HOTBAR: //Hotbar link update - //hotbarSlot 0-8, slot 9-44 - $this->inventory->setHotbarSlotIndex($packet->hotbarSlot, $packet->slot - 9); - return true; - default: - if(!isset($this->windowIndex[$packet->windowid])){ - return false; //unknown windowID and/or not matching any open windows - } - - $this->craftingType = 0; - $inv = $this->windowIndex[$packet->windowid]; - $transaction = new BaseTransaction($inv, $packet->slot, $inv->getItem($packet->slot), $packet->item); - break; - } - - if($transaction->getSourceItem()->equals($transaction->getTargetItem()) and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()){ //No changes! - //No changes, just a local inventory update sent by the client - return true; - } - - if($this->currentTransaction === null or $this->currentTransaction->getCreationTime() < (microtime(true) - 8)){ - if($this->currentTransaction !== null){ - foreach($this->currentTransaction->getInventories() as $inventory){ - if($inventory instanceof PlayerInventory){ - $inventory->sendArmorContents($this); - } - $inventory->sendContents($this); - } - } - $this->currentTransaction = new SimpleTransactionGroup($this); - } - - $this->currentTransaction->addTransaction($transaction); - - if($this->currentTransaction->canExecute()){ - $achievements = []; - foreach($this->currentTransaction->getTransactions() as $ts){ - $inv = $ts->getInventory(); - if($inv instanceof FurnaceInventory){ - if($ts->getSlot() === 2){ - switch($inv->getResult()->getId()){ - case Item::IRON_INGOT: - $achievements[] = "acquireIron"; - break; - } - } - } - } - - if($this->currentTransaction->execute()){ - foreach($achievements as $a){ - $this->awardAchievement($a); - } - } - - $this->currentTransaction = null; - } - - return true; - } - public function handleCraftingEvent(CraftingEventPacket $packet) : bool{ if($this->spawned === false or !$this->isAlive()){ return true; @@ -3846,6 +3790,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ protected function addDefaultWindows(){ $this->addWindow($this->getInventory(), ContainerIds::INVENTORY); + $this->cursorInventory = new PlayerCursorInventory($this); + $this->addWindow($this->cursorInventory, ContainerIds::CURSOR); + //TODO: more windows } diff --git a/src/pocketmine/inventory/PlayerCursorInventory.php b/src/pocketmine/inventory/PlayerCursorInventory.php new file mode 100644 index 0000000000..818c438834 --- /dev/null +++ b/src/pocketmine/inventory/PlayerCursorInventory.php @@ -0,0 +1,91 @@ +inventorySlot = $index; + $pk->item = clone $this->getItem($index); + + foreach($target as $player){ + if($player === $this->getHolder()){ + /** @var Player $player */ + $pk->windowId = ContainerIds::CURSOR; + $player->dataPacket(clone $pk); + }else{ + if(($id = $player->getWindowId($this)) === ContainerIds::NONE){ + $this->close($player); + continue; + } + $pk->windowId = $id; + $player->dataPacket(clone $pk); + } + } + } + + /** + * This override is here for documentation and code completion purposes only. + * @return Player + */ + public function getHolder(){ + return $this->holder; + } +} \ No newline at end of file diff --git a/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php b/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php index 3a0bcb4b44..4e2e8db2b0 100644 --- a/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php +++ b/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php @@ -35,7 +35,6 @@ use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket; use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket; use pocketmine\network\mcpe\protocol\CommandRequestPacket; use pocketmine\network\mcpe\protocol\ContainerClosePacket; -use pocketmine\network\mcpe\protocol\ContainerSetSlotPacket; use pocketmine\network\mcpe\protocol\CraftingEventPacket; use pocketmine\network\mcpe\protocol\DataPacket; use pocketmine\network\mcpe\protocol\DropItemPacket; @@ -183,16 +182,6 @@ class PlayerNetworkSessionAdapter extends NetworkSession{ return $this->player->handlePlayerHotbar($packet); } - /** - * TODO: REMOVE - * @param ContainerSetSlotPacket $packet - * - * @return bool - */ - public function handleContainerSetSlot(ContainerSetSlotPacket $packet) : bool{ - return $this->player->handleContainerSetSlot($packet); - } - public function handleCraftingEvent(CraftingEventPacket $packet) : bool{ return $this->player->handleCraftingEvent($packet); } diff --git a/src/pocketmine/network/mcpe/protocol/ContainerSetSlotPacket.php b/src/pocketmine/network/mcpe/protocol/ContainerSetSlotPacket.php deleted file mode 100644 index 879274b072..0000000000 --- a/src/pocketmine/network/mcpe/protocol/ContainerSetSlotPacket.php +++ /dev/null @@ -1,64 +0,0 @@ - - -use pocketmine\item\Item; -use pocketmine\network\mcpe\NetworkSession; - -/** - * @removed - */ -class ContainerSetSlotPacket extends DataPacket{ - const NETWORK_ID = ProtocolInfo::CONTAINER_SET_SLOT_PACKET; - - public $windowid; - public $slot; - public $hotbarSlot = 0; - /** @var Item */ - public $item; - public $selectSlot = 0; - - protected function decodePayload(){ - $this->windowid = $this->getByte(); - $this->slot = $this->getVarInt(); - $this->hotbarSlot = $this->getVarInt(); - $this->item = $this->getSlot(); - $this->selectSlot = $this->getByte(); - } - - protected function encodePayload(){ - $this->putByte($this->windowid); - $this->putVarInt($this->slot); - $this->putVarInt($this->hotbarSlot); - $this->putSlot($this->item); - $this->putByte($this->selectSlot); - } - - public function handle(NetworkSession $session) : bool{ - return $session->handleContainerSetSlot($this); - } - -}