Duct tape for inventory transactions, removed ContainerSetSlotPacket

This commit is contained in:
Dylan K. Taylor 2017-08-10 20:02:31 +01:00
parent 5208ad885c
commit 74ee94b385
4 changed files with 128 additions and 165 deletions

View File

@ -78,6 +78,7 @@ use pocketmine\inventory\BigShapedRecipe;
use pocketmine\inventory\BigShapelessRecipe; use pocketmine\inventory\BigShapelessRecipe;
use pocketmine\inventory\FurnaceInventory; use pocketmine\inventory\FurnaceInventory;
use pocketmine\inventory\Inventory; use pocketmine\inventory\Inventory;
use pocketmine\inventory\PlayerCursorInventory;
use pocketmine\inventory\PlayerInventory; use pocketmine\inventory\PlayerInventory;
use pocketmine\inventory\ShapedRecipe; use pocketmine\inventory\ShapedRecipe;
use pocketmine\inventory\ShapelessRecipe; 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\ClientToServerHandshakePacket;
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket; use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket; use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\ContainerSetSlotPacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket; use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\DataPacket; use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket; use pocketmine\network\mcpe\protocol\DisconnectPacket;
@ -239,6 +239,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
protected $currentTransaction = null; protected $currentTransaction = null;
public $craftingType = 0; //0 = 2x2 crafting, 1 = 3x3 crafting, 2 = stonecutter public $craftingType = 0; //0 = 2x2 crafting, 1 = 3x3 crafting, 2 = stonecutter
/** @var PlayerCursorInventory */
protected $cursorInventory;
public $creationTime = 0; public $creationTime = 0;
protected $randomClientId; protected $randomClientId;
@ -2149,13 +2152,39 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true; 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{ public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
switch($packet->transactionData->transactionType){ switch($packet->transactionData->transactionType){
case 0: case InventoryTransactionPacket::TYPE_NORMAL:
//normal inventory transfer (TODO handle) $transaction = new SimpleTransactionGroup($this);
break;
case InventoryTransactionPacket::TYPE_USE_ITEM:
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); $blockVector = new Vector3($packet->transactionData->x, $packet->transactionData->y, $packet->transactionData->z);
$face = $packet->transactionData->face; $face = $packet->transactionData->face;
@ -2834,91 +2863,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true; 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{ public function handleCraftingEvent(CraftingEventPacket $packet) : bool{
if($this->spawned === false or !$this->isAlive()){ if($this->spawned === false or !$this->isAlive()){
return true; return true;
@ -3846,6 +3790,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
protected function addDefaultWindows(){ protected function addDefaultWindows(){
$this->addWindow($this->getInventory(), ContainerIds::INVENTORY); $this->addWindow($this->getInventory(), ContainerIds::INVENTORY);
$this->cursorInventory = new PlayerCursorInventory($this);
$this->addWindow($this->cursorInventory, ContainerIds::CURSOR);
//TODO: more windows //TODO: more windows
} }

View File

@ -0,0 +1,91 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory;
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\WindowTypes;
use pocketmine\Player;
class PlayerCursorInventory extends BaseInventory{
/** @var Player */
protected $holder;
public function __construct(Player $holder){
parent::__construct($holder);
}
public function getName() : string{
return "Cursor";
}
public function getDefaultSize() : int{
return 1;
}
public function setSize(int $size){
throw new \BadMethodCallException("Cursor can only carry one item at a time");
}
public function getNetworkType() : int{
return WindowTypes::INVENTORY; //This should never be spawned to clients
}
/**
* @param int $index
* @param Player|Player[] $target
*/
public function sendSlot(int $index, $target){
if($target instanceof Player){
$target = [$target];
}
$pk = new InventorySlotPacket();
$pk->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;
}
}

View File

@ -35,7 +35,6 @@ use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket;
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket; use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\CommandRequestPacket; use pocketmine\network\mcpe\protocol\CommandRequestPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket; use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\ContainerSetSlotPacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket; use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\DataPacket; use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DropItemPacket; use pocketmine\network\mcpe\protocol\DropItemPacket;
@ -183,16 +182,6 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
return $this->player->handlePlayerHotbar($packet); 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{ public function handleCraftingEvent(CraftingEventPacket $packet) : bool{
return $this->player->handleCraftingEvent($packet); return $this->player->handleCraftingEvent($packet);
} }

View File

@ -1,64 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
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);
}
}