Many many changes related to inventory transactions, fixed item dropping, fixed creative menu

This commit is contained in:
Dylan K. Taylor 2017-08-11 19:57:30 +01:00
parent c1ff7bbef4
commit 8958b3c51c
14 changed files with 497 additions and 282 deletions

View File

@ -73,7 +73,6 @@ use pocketmine\event\server\DataPacketSendEvent;
use pocketmine\event\TextContainer;
use pocketmine\event\Timings;
use pocketmine\event\TranslationContainer;
use pocketmine\inventory\BaseTransaction;
use pocketmine\inventory\BigShapedRecipe;
use pocketmine\inventory\BigShapelessRecipe;
use pocketmine\inventory\FurnaceInventory;
@ -82,7 +81,7 @@ use pocketmine\inventory\PlayerCursorInventory;
use pocketmine\inventory\PlayerInventory;
use pocketmine\inventory\ShapedRecipe;
use pocketmine\inventory\ShapelessRecipe;
use pocketmine\inventory\SimpleTransactionGroup;
use pocketmine\inventory\transaction\SimpleInventoryTransaction;
use pocketmine\item\Item;
use pocketmine\level\ChunkLoader;
use pocketmine\level\format\Chunk;
@ -120,7 +119,6 @@ use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\DropItemPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\InteractPacket;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
@ -235,8 +233,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public $speed = null;
public $achievements = [];
/** @var SimpleTransactionGroup */
protected $currentTransaction = null;
public $craftingType = 0; //0 = 2x2 crafting, 1 = 3x3 crafting, 2 = stonecutter
/** @var PlayerCursorInventory */
@ -2161,28 +2158,38 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
switch($packet->transactionData->transactionType){
case InventoryTransactionPacket::TYPE_NORMAL:
$transaction = new SimpleTransactionGroup($this);
$transaction = new SimpleInventoryTransaction($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));
$transaction->addAction($action);
}
if(!$transaction->execute()){
//need to resend/revert/whatever (TODO)
foreach($transaction->getInventories() as $inventory){
$inventory->sendContents($this);
if($inventory instanceof PlayerInventory){
$inventory->sendArmorContents($this);
}
}
//TODO: check more stuff that might need reversion
return false; //oops!
}
//TODO: fix achievement for getting iron from furnace
return true;
case InventoryTransactionPacket::TYPE_MISMATCH:
if(count($packet->actions) > 0){
$this->server->getLogger()->debug("Expected 0 actions for mismatch, got " . count($packet->actions) . ", " . json_encode($packet->actions));
}
foreach($this->windowIndex as $id => $inventory){
$inventory->sendContents($this);
if($inventory instanceof PlayerInventory){
$inventory->sendArmorContents($this);
}
}
$this->inventory->sendHotbar();
return true;
case InventoryTransactionPacket::TYPE_USE_ITEM:
$blockVector = new Vector3($packet->transactionData->x, $packet->transactionData->y, $packet->transactionData->z);
@ -2463,6 +2470,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
case InventoryTransactionPacket::TYPE_RELEASE_ITEM:
//TODO
break;
default:
$this->inventory->sendContents($this);
break;
}
return false; //TODO
@ -2805,25 +2815,27 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true;
}
public function handleDropItem(DropItemPacket $packet) : bool{
if($this->spawned === false or !$this->isAlive()){
/**
* Drops an item on the ground in front of the player. Returns if the item drop was successful.
*
* @param Item $item
* @return bool if the item was dropped or if the item was null
*/
public function dropItem(Item $item){
if(!$this->spawned or !$this->isAlive()){
return false;
}
if($item->isNull()){
$this->server->getLogger()->debug($this->getName() . " attempted to drop a null item (" . $item . ")");
return true;
}
if($packet->item->getId() === Item::AIR){
// Windows 10 Edition drops the contents of the crafting grid on container close - including air.
return true;
}
$item = $this->inventory->getItemInHand();
$ev = new PlayerDropItemEvent($this, $item);
$this->server->getPluginManager()->callEvent($ev);
$this->server->getPluginManager()->callEvent($ev = new PlayerDropItemEvent($this, $item));
if($ev->isCancelled()){
$this->inventory->sendContents($this);
return true;
return false;
}
$this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1));
$motion = $this->getDirectionVector()->multiply(0.4);
$this->level->dropItem($this->add(0, 1.3, 0), $item, $motion, 40);
@ -2839,7 +2851,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
$this->craftingType = 0;
$this->currentTransaction = null;
if(isset($this->windowIndex[$packet->windowId])){
$this->server->getPluginManager()->callEvent(new InventoryCloseEvent($this->windowIndex[$packet->windowId], $this));
$this->removeWindow($this->windowIndex[$packet->windowId]);
@ -3477,12 +3489,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->perm->clearPermissions();
$this->perm = null;
}
if($this->inventory !== null){
$this->inventory = null;
$this->currentTransaction = null;
}
}catch(\Throwable $e){
$this->server->getLogger()->logException($e);
}finally{
@ -3809,6 +3815,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return ContainerIds::NONE;
}
/**
* @param int $windowId
*
* @return Inventory|null
*/
public function getWindow(int $windowId){
return $this->windowIndex[$windowId] ?? null;
}
/**
* Returns the created/existing window id
*

View File

@ -25,7 +25,7 @@ namespace pocketmine\event\inventory;
use pocketmine\event\Cancellable;
use pocketmine\event\Event;
use pocketmine\inventory\TransactionGroup;
use pocketmine\inventory\transaction\InventoryTransaction;
/**
* Called when there is a transaction between two Inventory objects.
@ -34,21 +34,21 @@ use pocketmine\inventory\TransactionGroup;
class InventoryTransactionEvent extends Event implements Cancellable{
public static $handlerList = null;
/** @var TransactionGroup */
private $ts;
/** @var InventoryTransaction */
private $transaction;
/**
* @param TransactionGroup $ts
* @param InventoryTransaction $transaction
*/
public function __construct(TransactionGroup $ts){
$this->ts = $ts;
public function __construct(InventoryTransaction $transaction){
$this->transaction = $transaction;
}
/**
* @return TransactionGroup
* @return InventoryTransaction
*/
public function getTransaction() : TransactionGroup{
return $this->ts;
public function getTransaction() : InventoryTransaction{
return $this->transaction;
}
}

View File

@ -140,7 +140,6 @@ abstract class BaseInventory implements Inventory{
if($holder instanceof Entity){
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityInventoryChangeEvent($holder, $this->getItem($index), $item, $index));
if($ev->isCancelled()){
$this->sendSlot($index, $this->getViewers());
return false;
}
$item = $ev->getNewItem();

View File

@ -1,73 +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\inventory;
use pocketmine\item\Item;
class BaseTransaction implements Transaction{
/** @var Inventory */
protected $inventory;
/** @var int */
protected $slot;
/** @var Item */
protected $sourceItem;
/** @var Item */
protected $targetItem;
/** @var float */
protected $creationTime;
/**
* @param Inventory $inventory
* @param int $slot
* @param Item $sourceItem
* @param Item $targetItem
*/
public function __construct(Inventory $inventory, int $slot, Item $sourceItem, Item $targetItem){
$this->inventory = $inventory;
$this->slot = $slot;
$this->sourceItem = clone $sourceItem;
$this->targetItem = clone $targetItem;
$this->creationTime = microtime(true);
}
public function getCreationTime() : float{
return $this->creationTime;
}
public function getInventory() : Inventory{
return $this->inventory;
}
public function getSlot() : int{
return $this->slot;
}
public function getSourceItem() : Item{
return clone $this->sourceItem;
}
public function getTargetItem() : Item{
return clone $this->targetItem;
}
}

View File

@ -351,6 +351,12 @@ class PlayerInventory extends BaseInventory{
}
public function setItem(int $index, Item $item, bool $send = true) : bool{
if($item->isNull()){
$item = Item::get(Item::AIR, 0, 0);
}else{
$item = clone $item;
}
if($index >= $this->getSize()){ //Armor change
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityArmorChangeEvent($this->getHolder(), $this->getItem($index), $item, $index));
if($ev->isCancelled() and $this->getHolder() instanceof Human){
@ -367,9 +373,8 @@ class PlayerInventory extends BaseInventory{
$item = $ev->getNewItem();
}
$old = $this->getItem($index);
$this->slots[$index] = clone $item;
$this->slots[$index] = $item;
$this->onSlotChange($index, $old, $send);
return true;

View File

@ -21,9 +21,12 @@
declare(strict_types=1);
namespace pocketmine\inventory;
namespace pocketmine\inventory\transaction;
interface TransactionGroup{
use pocketmine\inventory\Inventory;
use pocketmine\inventory\transaction\action\InventoryAction;
interface InventoryTransaction{
/**
* @return float
@ -31,9 +34,9 @@ interface TransactionGroup{
public function getCreationTime() : float;
/**
* @return Transaction[]
* @return InventoryAction[]
*/
public function getTransactions() : array;
public function getActions() : array;
/**
* @return Inventory[]
@ -41,9 +44,9 @@ interface TransactionGroup{
public function getInventories() : array;
/**
* @param Transaction $transaction
* @param InventoryAction $action
*/
public function addTransaction(Transaction $transaction);
public function addAction(InventoryAction $action);
/**
* @return bool

View File

@ -21,17 +21,21 @@
declare(strict_types=1);
namespace pocketmine\inventory;
namespace pocketmine\inventory\transaction;
use pocketmine\event\inventory\InventoryTransactionEvent;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\inventory\transaction\action\InventoryAction;
use pocketmine\inventory\transaction\action\SlotChangeAction;
use pocketmine\item\Item;
use pocketmine\Player;
use pocketmine\Server;
/**
* This TransactionGroup only allows doing Transaction between one / two inventories
* This InventoryTransaction only allows doing Transaction between one / two inventories
*/
class SimpleTransactionGroup implements TransactionGroup{
class SimpleInventoryTransaction implements InventoryTransaction{
/** @var float */
private $creationTime;
protected $hasExecuted = false;
@ -41,8 +45,8 @@ class SimpleTransactionGroup implements TransactionGroup{
/** @var Inventory[] */
protected $inventories = [];
/** @var Transaction[] */
protected $transactions = [];
/** @var InventoryAction[] */
protected $actions = [];
/**
* @param Player $source
@ -71,27 +75,22 @@ class SimpleTransactionGroup implements TransactionGroup{
}
/**
* @return Transaction[]
* @return InventoryAction[]
*/
public function getTransactions() : array{
return $this->transactions;
public function getActions() : array{
return $this->actions;
}
public function addTransaction(Transaction $transaction){
if(isset($this->transactions[spl_object_hash($transaction)])){
public function addAction(InventoryAction $action){
if(isset($this->actions[spl_object_hash($action)])){
return;
}
foreach($this->transactions as $hash => $tx){
if($tx->getInventory() === $transaction->getInventory() and $tx->getSlot() === $transaction->getSlot()){
if($transaction->getCreationTime() >= $tx->getCreationTime()){
unset($this->transactions[$hash]);
}else{
return;
}
}
$this->actions[spl_object_hash($action)] = $action;
if($action instanceof SlotChangeAction){
$action->setInventoryFrom($this->source);
$this->inventories[spl_object_hash($action->getInventory())] = $action->getInventory();
}
$this->transactions[spl_object_hash($transaction)] = $transaction;
$this->inventories[spl_object_hash($transaction->getInventory())] = $transaction->getInventory();
}
/**
@ -101,17 +100,17 @@ class SimpleTransactionGroup implements TransactionGroup{
* @return bool
*/
protected function matchItems(array &$needItems, array &$haveItems) : bool{
foreach($this->transactions as $key => $ts){
if($ts->getTargetItem()->getId() !== Item::AIR){
$needItems[] = $ts->getTargetItem();
foreach($this->actions as $key => $action){
if($action->getTargetItem()->getId() !== Item::AIR){
$needItems[] = $action->getTargetItem();
}
$checkSourceItem = $ts->getInventory()->getItem($ts->getSlot());
$sourceItem = $ts->getSourceItem();
if(!$checkSourceItem->equals($sourceItem) or $sourceItem->getCount() !== $checkSourceItem->getCount()){
if(!$action->isValid($this->source)){
return false;
}
if($sourceItem->getId() !== Item::AIR){
$haveItems[] = $sourceItem;
if($action->getSourceItem()->getId() !== Item::AIR){
$haveItems[] = $action->getSourceItem();
}
}
@ -139,7 +138,7 @@ class SimpleTransactionGroup implements TransactionGroup{
$haveItems = [];
$needItems = [];
return $this->matchItems($needItems, $haveItems) and count($this->transactions) > 0 and ((count($haveItems) === 0 and count($needItems) === 0) or $this->source->isCreative(true));
return $this->matchItems($needItems, $haveItems) and count($this->actions) > 0 and count($haveItems) === 0 and count($needItems) === 0;
}
/**
@ -152,18 +151,15 @@ class SimpleTransactionGroup implements TransactionGroup{
Server::getInstance()->getPluginManager()->callEvent($ev = new InventoryTransactionEvent($this));
if($ev->isCancelled()){
foreach($this->inventories as $inventory){
if($inventory instanceof PlayerInventory){
$inventory->sendArmorContents($this->getSource());
}
$inventory->sendContents($this->getSource());
}
return false;
}
foreach($this->transactions as $transaction){
$transaction->getInventory()->setItem($transaction->getSlot(), $transaction->getTargetItem());
foreach($this->actions as $action){
if($action->execute($this->source)){
$action->onExecuteSuccess($this->source);
}else{
$action->onExecuteFail($this->source);
}
}
$this->hasExecuted = true;

View File

@ -0,0 +1,85 @@
<?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\transaction\action;
use pocketmine\item\Item;
use pocketmine\Player;
class CreativeInventoryAction extends InventoryAction{
/**
* Player put an item into the creative window to destroy it.
*/
const TYPE_DELETE_ITEM = 0;
/**
* Player took an item from the creative window.
*/
const TYPE_CREATE_ITEM = 1;
protected $actionType;
public function __construct(Item $sourceItem, Item $targetItem, int $actionType){
parent::__construct($sourceItem, $targetItem);
$this->actionType = $actionType;
}
/**
* Checks that the player is in creative, and (if creating an item) that the item exists in the creative inventory.
*
* @param Player $source
*
* @return bool
*/
public function isValid(Player $source) : bool{
return $source->isCreative(true) and
($this->actionType === self::TYPE_DELETE_ITEM or Item::getCreativeItemIndex($this->sourceItem) !== -1);
}
/**
* Returns the type of the action.
*/
public function getActionType() : int{
return $this->actionType;
}
/**
* No need to do anything extra here: this type just provides a place for items to disappear or appear from.
*
* @param Player $source
*
* @return bool
*/
public function execute(Player $source) : bool{
return true;
}
public function onExecuteSuccess(Player $source){
}
public function onExecuteFail(Player $source){
}
}

View File

@ -21,34 +21,41 @@
declare(strict_types=1);
namespace pocketmine\inventory;
namespace pocketmine\inventory\transaction\action;
use pocketmine\item\Item;
use pocketmine\Player;
interface Transaction{
/**
* Represents an action involving dropping an item into the world.
*/
class DropItemAction extends InventoryAction{
/**
* @return Inventory
* Verifies that the source item of a drop-item action must be air. This is not strictly necessary, just a sanity
* check.
*
* @param Player $source
* @return bool
*/
public function getInventory() : Inventory;
public function isValid(Player $source) : bool{
return $this->sourceItem->isNull();
}
/**
* @return int
* Drops the target item in front of the player.
*
* @param Player $source
* @return bool
*/
public function getSlot() : int;
public function execute(Player $source) : bool{
return $source->dropItem($this->targetItem);
}
/**
* @return Item
*/
public function getSourceItem() : Item;
public function onExecuteSuccess(Player $source){
/**
* @return Item
*/
public function getTargetItem() : Item;
}
/**
* @return float
*/
public function getCreationTime() : float;
public function onExecuteFail(Player $source){
}
}

View File

@ -0,0 +1,102 @@
<?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\transaction\action;
use pocketmine\item\Item;
use pocketmine\Player;
/**
* Represents an action involving a change that applies in some way to an inventory or other item-source.
*/
abstract class InventoryAction{
/** @var float */
private $creationTime;
/** @var Item */
protected $sourceItem;
/** @var Item */
protected $targetItem;
public function __construct(Item $sourceItem, Item $targetItem){
$this->sourceItem = $sourceItem;
$this->targetItem = $targetItem;
$this->creationTime = microtime(true);
}
public function getCreationTime() : float{
return $this->creationTime;
}
/**
* Returns the item that was present before the action took place.
* @return Item
*/
public function getSourceItem() : Item{
return clone $this->sourceItem;
}
/**
* Returns the item that the action attempted to replace the source item with.
* @return Item
*/
public function getTargetItem() : Item{
return clone $this->targetItem;
}
/**
* Returns whether this action is currently valid. This should perform any necessary sanity checks.
*
* @param Player $source
*
* @return bool
*/
abstract public function isValid(Player $source) : bool;
/**
* Performs actions needed to complete the inventory-action server-side. Returns if it was successful. Will return
* false if plugins cancelled events. This will only be called if the transaction which it is part of is considered
* valid.
*
* @param Player $source
*
* @return bool
*/
abstract public function execute(Player $source) : bool;
/**
* Performs additional actions when this inventory-action completed successfully.
*
* @param Player $source
*/
abstract public function onExecuteSuccess(Player $source);
/**
* Performs additional actions when this inventory-action did not complete successfully.
*
* @param Player $source
*/
abstract public function onExecuteFail(Player $source);
}

View File

@ -0,0 +1,126 @@
<?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\transaction\action;
use pocketmine\inventory\Inventory;
use pocketmine\item\Item;
use pocketmine\Player;
/**
* Represents an action causing a change in an inventory slot.
*/
class SlotChangeAction extends InventoryAction{
/** @var Inventory|null */
protected $inventory;
/** @var int */
private $inventorySlot;
/** @var int */
private $containerId;
/**
* @param Item $sourceItem
* @param Item $targetItem
* @param int $containerId
* @param int $inventorySlot
*/
public function __construct(Item $sourceItem, Item $targetItem, int $containerId, int $inventorySlot){
parent::__construct($sourceItem, $targetItem);
$this->inventorySlot = $inventorySlot;
$this->containerId = $containerId;
}
public function getContainerId() : int{
return $this->containerId;
}
/**
* Returns the inventory involved in this action. Will return null if the action has not yet been fully initialized.
*
* @return Inventory|null
*/
public function getInventory(){
return $this->inventory;
}
public function setInventoryFrom(Player $player){
$inventory = $player->getWindow($this->containerId);
if($inventory === null){
throw new \InvalidStateException("Player " . $player->getName() . " has no open container with ID " . $this->containerId);
}
$this->inventory = $inventory;
}
/**
* Returns the slot in the inventory which this action modified.
* @return int
*/
public function getSlot() : int{
return $this->inventorySlot;
}
/**
* Checks if the item in the inventory at the specified slot is the same as this action's source item.
*
* @param Player $source
*
* @return bool
*/
public function isValid(Player $source) : bool{
$check = $this->inventory->getItem($this->inventorySlot);
return $check->equals($this->sourceItem) and $check->getCount() === $this->sourceItem->getCount();
}
/**
* Sets the item into the target inventory.
*
* @param Player $source
*
* @return bool
*/
public function execute(Player $source) : bool{
return $this->inventory->setItem($this->inventorySlot, $this->targetItem, false);
}
/**
* Sends slot changes to other viewers of the inventory. This will not send any change back to the source Player.
*
* @param Player $source
*/
public function onExecuteSuccess(Player $source){
$viewers = $this->inventory->getViewers();
unset($viewers[spl_object_hash($source)]);
$this->inventory->sendSlot($this->inventorySlot, $viewers);
}
/**
* Sends the original slot contents to the source player to revert the action.
*
* @param Player $source
*/
public function onExecuteFail(Player $source){
$this->inventory->sendSlot($this->inventorySlot, $source);
}
}

View File

@ -37,7 +37,6 @@ use pocketmine\network\mcpe\protocol\CommandRequestPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DropItemPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\EntityFallPacket;
use pocketmine\network\mcpe\protocol\EntityPickRequestPacket;
@ -164,16 +163,6 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
return $this->player->handleAnimate($packet);
}
/**
* TODO: REMOVE
* @param DropItemPacket $packet
*
* @return bool
*/
public function handleDropItem(DropItemPacket $packet) : bool{
return $this->player->handleDropItem($packet);
}
public function handleContainerClose(ContainerClosePacket $packet) : bool{
return $this->player->handleContainerClose($packet);
}

View File

@ -1,56 +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 DropItemPacket extends DataPacket{
const NETWORK_ID = ProtocolInfo::DROP_ITEM_PACKET;
public $type;
/** @var Item */
public $item;
protected function decodePayload(){
$this->type = $this->getByte();
$this->item = $this->getSlot();
}
protected function encodePayload(){
$this->putByte($this->type);
$this->putSlot($this->item);
}
public function handle(NetworkSession $session) : bool{
return $session->handleDropItem($this);
}
}

View File

@ -25,13 +25,18 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\inventory\transaction\action\CreativeInventoryAction;
use pocketmine\inventory\transaction\action\DropItemAction;
use pocketmine\inventory\transaction\action\InventoryAction;
use pocketmine\inventory\transaction\action\SlotChangeAction;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
class InventoryTransactionPacket extends DataPacket{
const NETWORK_ID = ProtocolInfo::INVENTORY_TRANSACTION_PACKET;
const TYPE_NORMAL = 0;
const TYPE_MISMATCH = 1;
const TYPE_USE_ITEM = 2;
const TYPE_USE_ITEM_ON_ENTITY = 3;
const TYPE_RELEASE_ITEM = 4;
@ -87,6 +92,7 @@ class InventoryTransactionPacket extends DataPacket{
const ACTION_MAGIC_SLOT_CREATIVE_DELETE_ITEM = 0;
const ACTION_MAGIC_SLOT_CREATIVE_CREATE_ITEM = 1;
/** @var InventoryAction[] */
public $actions = [];
public $transactionData;
@ -104,7 +110,7 @@ class InventoryTransactionPacket extends DataPacket{
switch($type){
case self::TYPE_NORMAL:
case 1:
case self::TYPE_MISMATCH:
//Regular ComplexInventoryTransaction doesn't read any extra data
break;
case self::TYPE_USE_ITEM:
@ -133,8 +139,6 @@ class InventoryTransactionPacket extends DataPacket{
default:
throw new \UnexpectedValueException("Unknown transaction type $type");
}
//TODO
}
protected function encodePayload(){
@ -142,45 +146,58 @@ class InventoryTransactionPacket extends DataPacket{
}
protected function decodeInventoryAction(){
$actionBucket = new \stdClass();
$actionBucket->inventorySource = $this->decodeInventorySource();
$sourceType = $this->getUnsignedVarInt();
$containerId = ContainerIds::NONE;
$unknown = 0;
$actionBucket->inventorySlot = $this->getUnsignedVarInt();
$actionBucket->oldItem = $this->getSlot();
$actionBucket->newItem = $this->getSlot();
return $actionBucket;
}
protected function decodeInventorySource(){
$bucket = new \stdClass();
$bucket->sourceType = $this->getUnsignedVarInt();
switch($bucket->sourceType){
switch($sourceType){
case self::SOURCE_CONTAINER:
$bucket->containerId = $this->getVarInt();
$bucket->field_2 = 0;
$containerId = $this->getVarInt();
break;
case 1:
break; //unused
case self::SOURCE_WORLD:
$bucket->containerId = -1;
$bucket->field_2 = $this->getUnsignedVarInt();
$unknown = $this->getUnsignedVarInt();
break;
case self::SOURCE_CREATIVE:
$bucket->containerId = -1;
$bucket->field_2 = 0;
break;
case self::SOURCE_TODO:
$bucket->containerId = $this->getVarInt();
$bucket->field_2 = 0;
$containerId = $this->getVarInt();
break;
default:
throw new \UnexpectedValueException("Unexpected inventory source type $bucket->sourceType");
throw new \UnexpectedValueException("Unexpected inventory source type $sourceType");
}
return $bucket;
$inventorySlot = $this->getUnsignedVarInt();
$sourceItem = $this->getSlot();
$targetItem = $this->getSlot();
switch($sourceType){
case self::SOURCE_CONTAINER:
if($containerId === ContainerIds::ARMOR){
//TODO: HACK!
$inventorySlot += 36;
$containerId = ContainerIds::INVENTORY;
}
return new SlotChangeAction($sourceItem, $targetItem, $containerId, $inventorySlot);
case self::SOURCE_WORLD:
if($inventorySlot !== self::ACTION_MAGIC_SLOT_DROP_ITEM){
throw new \UnexpectedValueException("Only expect drop item world action types from client");
}
return new DropItemAction($sourceItem, $targetItem);
case self::SOURCE_CREATIVE:
if($inventorySlot === self::ACTION_MAGIC_SLOT_CREATIVE_DELETE_ITEM){
return new CreativeInventoryAction($sourceItem, $targetItem, CreativeInventoryAction::TYPE_DELETE_ITEM);
}elseif($inventorySlot === self::ACTION_MAGIC_SLOT_CREATIVE_CREATE_ITEM){
return new CreativeInventoryAction($sourceItem, $targetItem, CreativeInventoryAction::TYPE_CREATE_ITEM);
}else{
throw new \UnexpectedValueException("Unknown creative inventory action type $inventorySlot");
}
case self::SOURCE_TODO:
return new SlotChangeAction($sourceItem, $targetItem, $containerId, $inventorySlot);
default:
throw new \UnexpectedValueException("Unknown source type $sourceType");
}
}
public function handle(NetworkSession $session) : bool{