mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-11 08:19:45 +00:00
Cleaned up the InventoryTransactionPacket decoding clusterfuck
@shoghicp, y u do dis... I almost created a sub-packet architecture to deal with this shit :( This mess really ought to be split into multiple packets. Perhaps the PacketPool can be extended to do that in the future.
This commit is contained in:
parent
134956ac58
commit
4d15eb3327
@ -63,6 +63,11 @@ use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
|
||||
use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket;
|
||||
use pocketmine\network\mcpe\protocol\SubClientLoginPacket;
|
||||
use pocketmine\network\mcpe\protocol\TextPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\MismatchTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\NormalTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\ReleaseItemTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\UseItemOnEntityTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\UseItemTransactionData;
|
||||
use pocketmine\Player;
|
||||
|
||||
/**
|
||||
@ -112,22 +117,52 @@ class SimpleSessionHandler extends SessionHandler{
|
||||
return true;
|
||||
}
|
||||
|
||||
$result = true;
|
||||
|
||||
if($packet->trData instanceof NormalTransactionData){
|
||||
$result = $this->handleNormalTransaction($packet->trData);
|
||||
}elseif($packet->trData instanceof MismatchTransactionData){
|
||||
$this->player->sendAllInventories();
|
||||
$result = true;
|
||||
}elseif($packet->trData instanceof UseItemTransactionData){
|
||||
$result = $this->handleUseItemTransaction($packet->trData);
|
||||
}elseif($packet->trData instanceof UseItemOnEntityTransactionData){
|
||||
$result = $this->handleUseItemOnEntityTransaction($packet->trData);
|
||||
}elseif($packet->trData instanceof ReleaseItemTransactionData){
|
||||
$result = $this->handleReleaseItemTransaction($packet->trData);
|
||||
}
|
||||
|
||||
if(!$result){
|
||||
$this->player->sendAllInventories();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function handleNormalTransaction(NormalTransactionData $data) : bool{
|
||||
/** @var InventoryAction[] $actions */
|
||||
$actions = [];
|
||||
foreach($packet->actions as $networkInventoryAction){
|
||||
|
||||
$isCrafting = false;
|
||||
$isFinalCraftingPart = false;
|
||||
foreach($data->getActions() as $networkInventoryAction){
|
||||
$isCrafting = $isCrafting || $networkInventoryAction->isCraftingPart();
|
||||
$isFinalCraftingPart = $isFinalCraftingPart || $networkInventoryAction->isFinalCraftingPart();
|
||||
|
||||
try{
|
||||
$action = $networkInventoryAction->createInventoryAction($this->player);
|
||||
if($action !== null){
|
||||
$actions[] = $action;
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
}catch(\UnexpectedValueException $e){
|
||||
$this->player->getServer()->getLogger()->debug("Unhandled inventory action from " . $this->player->getName() . ": " . $e->getMessage());
|
||||
$this->player->sendAllInventories();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if($packet->isCraftingPart){
|
||||
if($isCrafting){
|
||||
//we get the actions for this in several packets, so we need to wait until we have all the pieces before
|
||||
//trying to execute it
|
||||
|
||||
if($this->craftingTransaction === null){
|
||||
$this->craftingTransaction = new CraftingTransaction($this->player, $actions);
|
||||
}else{
|
||||
@ -136,113 +171,98 @@ class SimpleSessionHandler extends SessionHandler{
|
||||
}
|
||||
}
|
||||
|
||||
if($packet->isFinalCraftingPart){
|
||||
//we get the actions for this in several packets, so we need to wait until we have all the pieces before
|
||||
//trying to execute it
|
||||
|
||||
$ret = true;
|
||||
if($isFinalCraftingPart){
|
||||
try{
|
||||
$this->craftingTransaction->execute();
|
||||
}catch(TransactionValidationException $e){
|
||||
$this->player->getServer()->getLogger()->debug("Failed to execute crafting transaction for " . $this->player->getName() . ": " . $e->getMessage());
|
||||
$ret = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}finally{
|
||||
$this->craftingTransaction = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
//normal transaction fallthru
|
||||
if($this->craftingTransaction !== null){
|
||||
$this->player->getServer()->getLogger()->debug("Got unexpected normal inventory action with incomplete crafting transaction from " . $this->player->getName() . ", refusing to execute crafting");
|
||||
$this->craftingTransaction = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($packet->transactionType){
|
||||
case InventoryTransactionPacket::TYPE_NORMAL:
|
||||
$transaction = new InventoryTransaction($this->player, $actions);
|
||||
|
||||
try{
|
||||
$transaction->execute();
|
||||
}catch(TransactionValidationException $e){
|
||||
$this->player->getServer()->getLogger()->debug("Failed to execute inventory transaction from " . $this->player->getName() . ": " . $e->getMessage());
|
||||
$this->player->getServer()->getLogger()->debug("Actions: " . json_encode($packet->actions));
|
||||
$logger = $this->player->getServer()->getLogger();
|
||||
$logger->debug("Failed to execute inventory transaction from " . $this->player->getName() . ": " . $e->getMessage());
|
||||
$logger->debug("Actions: " . json_encode($data->getActions()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//TODO: fix achievement for getting iron from furnace
|
||||
|
||||
return true;
|
||||
case InventoryTransactionPacket::TYPE_MISMATCH:
|
||||
if(count($packet->actions) > 0){
|
||||
$this->player->getServer()->getLogger()->debug("Expected 0 actions for mismatch, got " . count($packet->actions) . ", " . json_encode($packet->actions));
|
||||
}
|
||||
$this->player->sendAllInventories();
|
||||
|
||||
return true;
|
||||
case InventoryTransactionPacket::TYPE_USE_ITEM:
|
||||
$blockVector = new Vector3($packet->trData->x, $packet->trData->y, $packet->trData->z);
|
||||
$face = $packet->trData->face;
|
||||
}
|
||||
|
||||
$type = $packet->trData->actionType;
|
||||
switch($type){
|
||||
case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_BLOCK:
|
||||
private function handleUseItemTransaction(UseItemTransactionData $data) : bool{
|
||||
switch($data->getActionType()){
|
||||
case UseItemTransactionData::ACTION_CLICK_BLOCK:
|
||||
//TODO: start hack for client spam bug
|
||||
$clickPos = $data->getClickPos();
|
||||
$spamBug = ($this->lastRightClickPos !== null and
|
||||
microtime(true) - $this->lastRightClickTime < 0.1 and //100ms
|
||||
$this->lastRightClickPos->distanceSquared($packet->trData->clickPos) < 0.00001 //signature spam bug has 0 distance, but allow some error
|
||||
$this->lastRightClickPos->distanceSquared($clickPos) < 0.00001 //signature spam bug has 0 distance, but allow some error
|
||||
);
|
||||
//get rid of continued spam if the player clicks and holds right-click
|
||||
$this->lastRightClickPos = clone $packet->trData->clickPos;
|
||||
$this->lastRightClickPos = clone $clickPos;
|
||||
$this->lastRightClickTime = microtime(true);
|
||||
if($spamBug){
|
||||
return true;
|
||||
}
|
||||
//TODO: end hack for client spam bug
|
||||
$this->player->interactBlock($blockVector, $face, $packet->trData->clickPos);
|
||||
$this->player->interactBlock($data->getBlockPos(), $data->getFace(), $clickPos);
|
||||
return true;
|
||||
case InventoryTransactionPacket::USE_ITEM_ACTION_BREAK_BLOCK:
|
||||
$this->player->breakBlock($blockVector);
|
||||
case UseItemTransactionData::ACTION_BREAK_BLOCK:
|
||||
$this->player->breakBlock($data->getBlockPos());
|
||||
return true;
|
||||
case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_AIR:
|
||||
case UseItemTransactionData::ACTION_CLICK_AIR:
|
||||
$this->player->useHeldItem();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case InventoryTransactionPacket::TYPE_USE_ITEM_ON_ENTITY:
|
||||
$target = $this->player->getLevel()->getEntity($packet->trData->entityRuntimeId);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function handleUseItemOnEntityTransaction(UseItemOnEntityTransactionData $data) : bool{
|
||||
$target = $this->player->getLevel()->getEntity($data->getEntityRuntimeId());
|
||||
if($target === null){
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($packet->trData->actionType){
|
||||
case InventoryTransactionPacket::USE_ITEM_ON_ENTITY_ACTION_INTERACT:
|
||||
$this->player->interactEntity($target, $packet->trData->clickPos);
|
||||
switch($data->getActionType()){
|
||||
case UseItemOnEntityTransactionData::ACTION_INTERACT:
|
||||
$this->player->interactEntity($target, $data->getClickPos());
|
||||
return true;
|
||||
case InventoryTransactionPacket::USE_ITEM_ON_ENTITY_ACTION_ATTACK:
|
||||
case UseItemOnEntityTransactionData::ACTION_ATTACK:
|
||||
$this->player->attackEntity($target);
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
case InventoryTransactionPacket::TYPE_RELEASE_ITEM:
|
||||
switch($packet->trData->actionType){
|
||||
case InventoryTransactionPacket::RELEASE_ITEM_ACTION_RELEASE:
|
||||
return false;
|
||||
}
|
||||
|
||||
private function handleReleaseItemTransaction(ReleaseItemTransactionData $data) : bool{
|
||||
switch($data->getActionType()){
|
||||
case ReleaseItemTransactionData::ACTION_RELEASE:
|
||||
$this->player->releaseHeldItem();
|
||||
return true;
|
||||
case InventoryTransactionPacket::RELEASE_ITEM_ACTION_CONSUME:
|
||||
case ReleaseItemTransactionData::ACTION_CONSUME:
|
||||
$this->player->consumeHeldItem();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$this->player->sendAllInventories();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,16 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\handler\SessionHandler;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
use pocketmine\network\mcpe\protocol\types\MismatchTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\NormalTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\ReleaseItemTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\TransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\UseItemOnEntityTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\UseItemTransactionData;
|
||||
|
||||
/**
|
||||
* This packet effectively crams multiple packets into one.
|
||||
*/
|
||||
class InventoryTransactionPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::INVENTORY_TRANSACTION_PACKET;
|
||||
|
||||
@ -37,118 +45,38 @@ class InventoryTransactionPacket extends DataPacket{
|
||||
public const TYPE_USE_ITEM_ON_ENTITY = 3;
|
||||
public const TYPE_RELEASE_ITEM = 4;
|
||||
|
||||
public const USE_ITEM_ACTION_CLICK_BLOCK = 0;
|
||||
public const USE_ITEM_ACTION_CLICK_AIR = 1;
|
||||
public const USE_ITEM_ACTION_BREAK_BLOCK = 2;
|
||||
|
||||
public const RELEASE_ITEM_ACTION_RELEASE = 0; //bow shoot
|
||||
public const RELEASE_ITEM_ACTION_CONSUME = 1; //eat food, drink potion
|
||||
|
||||
public const USE_ITEM_ON_ENTITY_ACTION_INTERACT = 0;
|
||||
public const USE_ITEM_ON_ENTITY_ACTION_ATTACK = 1;
|
||||
|
||||
/** @var int */
|
||||
public $transactionType;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* NOTE: THIS FIELD DOES NOT EXIST IN THE PROTOCOL, it's merely used for convenience for PocketMine-MP to easily
|
||||
* determine whether we're doing a crafting transaction.
|
||||
*/
|
||||
public $isCraftingPart = false;
|
||||
/**
|
||||
* @var bool
|
||||
* NOTE: THIS FIELD DOES NOT EXIST IN THE PROTOCOL, it's merely used for convenience for PocketMine-MP to easily
|
||||
* determine whether we're doing a crafting transaction.
|
||||
*/
|
||||
public $isFinalCraftingPart = false;
|
||||
|
||||
/** @var NetworkInventoryAction[] */
|
||||
public $actions = [];
|
||||
|
||||
/** @var \stdClass */
|
||||
/** @var TransactionData */
|
||||
public $trData;
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->transactionType = $this->getUnsignedVarInt();
|
||||
$transactionType = $this->getUnsignedVarInt();
|
||||
|
||||
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
|
||||
$this->actions[] = (new NetworkInventoryAction())->read($this);
|
||||
}
|
||||
|
||||
$this->trData = new \stdClass();
|
||||
|
||||
switch($this->transactionType){
|
||||
switch($transactionType){
|
||||
case self::TYPE_NORMAL:
|
||||
$this->trData = new NormalTransactionData();
|
||||
break;
|
||||
case self::TYPE_MISMATCH:
|
||||
//Regular ComplexInventoryTransaction doesn't read any extra data
|
||||
$this->trData = new MismatchTransactionData();
|
||||
break;
|
||||
case self::TYPE_USE_ITEM:
|
||||
$this->trData->actionType = $this->getUnsignedVarInt();
|
||||
$this->getBlockPosition($this->trData->x, $this->trData->y, $this->trData->z);
|
||||
$this->trData->face = $this->getVarInt();
|
||||
$this->trData->hotbarSlot = $this->getVarInt();
|
||||
$this->trData->itemInHand = $this->getSlot();
|
||||
$this->trData->playerPos = $this->getVector3();
|
||||
$this->trData->clickPos = $this->getVector3();
|
||||
$this->trData = new UseItemTransactionData();
|
||||
break;
|
||||
case self::TYPE_USE_ITEM_ON_ENTITY:
|
||||
$this->trData->entityRuntimeId = $this->getEntityRuntimeId();
|
||||
$this->trData->actionType = $this->getUnsignedVarInt();
|
||||
$this->trData->hotbarSlot = $this->getVarInt();
|
||||
$this->trData->itemInHand = $this->getSlot();
|
||||
$this->trData->playerPos = $this->getVector3();
|
||||
$this->trData->clickPos = $this->getVector3();
|
||||
$this->trData = new UseItemOnEntityTransactionData();
|
||||
break;
|
||||
case self::TYPE_RELEASE_ITEM:
|
||||
$this->trData->actionType = $this->getUnsignedVarInt();
|
||||
$this->trData->hotbarSlot = $this->getVarInt();
|
||||
$this->trData->itemInHand = $this->getSlot();
|
||||
$this->trData->headPos = $this->getVector3();
|
||||
$this->trData = new ReleaseItemTransactionData();
|
||||
break;
|
||||
default:
|
||||
throw new \UnexpectedValueException("Unknown transaction type $this->transactionType");
|
||||
throw new \UnexpectedValueException("Unknown transaction type $transactionType");
|
||||
}
|
||||
|
||||
$this->trData->decode($this);
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putUnsignedVarInt($this->transactionType);
|
||||
|
||||
$this->putUnsignedVarInt(count($this->actions));
|
||||
foreach($this->actions as $action){
|
||||
$action->write($this);
|
||||
}
|
||||
|
||||
switch($this->transactionType){
|
||||
case self::TYPE_NORMAL:
|
||||
case self::TYPE_MISMATCH:
|
||||
break;
|
||||
case self::TYPE_USE_ITEM:
|
||||
$this->putUnsignedVarInt($this->trData->actionType);
|
||||
$this->putBlockPosition($this->trData->x, $this->trData->y, $this->trData->z);
|
||||
$this->putVarInt($this->trData->face);
|
||||
$this->putVarInt($this->trData->hotbarSlot);
|
||||
$this->putSlot($this->trData->itemInHand);
|
||||
$this->putVector3($this->trData->playerPos);
|
||||
$this->putVector3($this->trData->clickPos);
|
||||
break;
|
||||
case self::TYPE_USE_ITEM_ON_ENTITY:
|
||||
$this->putEntityRuntimeId($this->trData->entityRuntimeId);
|
||||
$this->putUnsignedVarInt($this->trData->actionType);
|
||||
$this->putVarInt($this->trData->hotbarSlot);
|
||||
$this->putSlot($this->trData->itemInHand);
|
||||
$this->putVector3($this->trData->playerPos);
|
||||
$this->putVector3($this->trData->clickPos);
|
||||
break;
|
||||
case self::TYPE_RELEASE_ITEM:
|
||||
$this->putUnsignedVarInt($this->trData->actionType);
|
||||
$this->putVarInt($this->trData->hotbarSlot);
|
||||
$this->putSlot($this->trData->itemInHand);
|
||||
$this->putVector3($this->trData->headPos);
|
||||
break;
|
||||
default:
|
||||
throw new \UnexpectedValueException("Unknown transaction type $this->transactionType");
|
||||
}
|
||||
$this->putUnsignedVarInt($this->trData->getTypeId());
|
||||
$this->trData->encode($this);
|
||||
}
|
||||
|
||||
public function handle(SessionHandler $handler) : bool{
|
||||
|
@ -0,0 +1,48 @@
|
||||
<?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\types;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
|
||||
class MismatchTransactionData extends TransactionData{
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
protected function decodeData(NetworkBinaryStream $stream) : void{
|
||||
if(!empty($this->actions)){
|
||||
throw new \UnexpectedValueException("Mismatch transaction type should not have any actions associated with it, but got " . count($this->actions));
|
||||
}
|
||||
}
|
||||
|
||||
protected function encodeData(NetworkBinaryStream $stream) : void{
|
||||
|
||||
}
|
||||
|
||||
public static function new() : self{
|
||||
return new self; //no arguments
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ use pocketmine\inventory\transaction\action\DropItemAction;
|
||||
use pocketmine\inventory\transaction\action\InventoryAction;
|
||||
use pocketmine\inventory\transaction\action\SlotChangeAction;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\Player;
|
||||
|
||||
class NetworkInventoryAction{
|
||||
@ -92,11 +92,13 @@ class NetworkInventoryAction{
|
||||
public $newItem;
|
||||
|
||||
/**
|
||||
* @param InventoryTransactionPacket $packet
|
||||
* @param NetworkBinaryStream $packet
|
||||
*
|
||||
* @return $this
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \OutOfBoundsException
|
||||
*/
|
||||
public function read(InventoryTransactionPacket $packet) : NetworkInventoryAction{
|
||||
public function read(NetworkBinaryStream $packet) : NetworkInventoryAction{
|
||||
$this->sourceType = $packet->getUnsignedVarInt();
|
||||
|
||||
switch($this->sourceType){
|
||||
@ -111,14 +113,6 @@ class NetworkInventoryAction{
|
||||
case self::SOURCE_CRAFTING_GRID:
|
||||
case self::SOURCE_TODO:
|
||||
$this->windowId = $packet->getVarInt();
|
||||
switch($this->windowId){
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case self::SOURCE_TYPE_CRAFTING_RESULT:
|
||||
$packet->isFinalCraftingPart = true;
|
||||
case self::SOURCE_TYPE_CRAFTING_USE_INGREDIENT:
|
||||
$packet->isCraftingPart = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \UnexpectedValueException("Unknown inventory action source type $this->sourceType");
|
||||
@ -132,9 +126,11 @@ class NetworkInventoryAction{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InventoryTransactionPacket $packet
|
||||
* @param NetworkBinaryStream $packet
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function write(InventoryTransactionPacket $packet) : void{
|
||||
public function write(NetworkBinaryStream $packet) : void{
|
||||
$packet->putUnsignedVarInt($this->sourceType);
|
||||
|
||||
switch($this->sourceType){
|
||||
@ -151,7 +147,7 @@ class NetworkInventoryAction{
|
||||
$packet->putVarInt($this->windowId);
|
||||
break;
|
||||
default:
|
||||
throw new \UnexpectedValueException("Unknown inventory action source type $this->sourceType");
|
||||
throw new \InvalidArgumentException("Unknown inventory action source type $this->sourceType");
|
||||
}
|
||||
|
||||
$packet->putUnsignedVarInt($this->inventorySlot);
|
||||
@ -163,6 +159,7 @@ class NetworkInventoryAction{
|
||||
* @param Player $player
|
||||
*
|
||||
* @return InventoryAction|null
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
public function createInventoryAction(Player $player) : ?InventoryAction{
|
||||
switch($this->sourceType){
|
||||
@ -172,7 +169,7 @@ class NetworkInventoryAction{
|
||||
return new SlotChangeAction($window, $this->inventorySlot, $this->oldItem, $this->newItem);
|
||||
}
|
||||
|
||||
throw new \InvalidStateException("Player " . $player->getName() . " has no open container with window ID $this->windowId");
|
||||
throw new \UnexpectedValueException("Player " . $player->getName() . " has no open container with window ID $this->windowId");
|
||||
case self::SOURCE_WORLD:
|
||||
if($this->inventorySlot !== self::ACTION_MAGIC_SLOT_DROP_ITEM){
|
||||
throw new \UnexpectedValueException("Only expecting drop-item world actions from the client!");
|
||||
@ -212,4 +209,18 @@ class NetworkInventoryAction{
|
||||
throw new \UnexpectedValueException("Unknown inventory source type $this->sourceType");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hack to allow identifying crafting transaction parts.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isCraftingPart() : bool{
|
||||
return ($this->sourceType === self::SOURCE_TODO or $this->sourceType === self::SOURCE_CRAFTING_GRID) and
|
||||
($this->windowId === self::SOURCE_TYPE_CRAFTING_RESULT or $this->windowId === self::SOURCE_TYPE_CRAFTING_USE_INGREDIENT);
|
||||
}
|
||||
|
||||
public function isFinalCraftingPart() : bool{
|
||||
return $this->isCraftingPart() and $this->windowId === self::SOURCE_TYPE_CRAFTING_RESULT;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
<?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\types;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
|
||||
class NormalTransactionData extends TransactionData{
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_NORMAL;
|
||||
}
|
||||
|
||||
protected function decodeData(NetworkBinaryStream $stream) : void{
|
||||
|
||||
}
|
||||
|
||||
protected function encodeData(NetworkBinaryStream $stream) : void{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NetworkInventoryAction[] $actions
|
||||
*
|
||||
* @return NormalTransactionData
|
||||
*/
|
||||
public static function new(array $actions) : self{
|
||||
$result = new self();
|
||||
$result->actions = $actions;
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
<?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\types;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
|
||||
class ReleaseItemTransactionData extends TransactionData{
|
||||
public const ACTION_RELEASE = 0; //bow shoot
|
||||
public const ACTION_CONSUME = 1; //eat food, drink potion
|
||||
|
||||
/** @var int */
|
||||
private $actionType;
|
||||
/** @var int */
|
||||
private $hotbarSlot;
|
||||
/** @var Item */
|
||||
private $itemInHand;
|
||||
/** @var Vector3 */
|
||||
private $headPos;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getActionType() : int{
|
||||
return $this->actionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getHotbarSlot() : int{
|
||||
return $this->hotbarSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getItemInHand() : Item{
|
||||
return $this->itemInHand;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getHeadPos() : Vector3{
|
||||
return $this->headPos;
|
||||
}
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_RELEASE_ITEM;
|
||||
}
|
||||
|
||||
protected function decodeData(NetworkBinaryStream $stream) : void{
|
||||
$this->actionType = $stream->getUnsignedVarInt();
|
||||
$this->hotbarSlot = $stream->getVarInt();
|
||||
$this->itemInHand = $stream->getSlot();
|
||||
$this->headPos = $stream->getVector3();
|
||||
}
|
||||
|
||||
protected function encodeData(NetworkBinaryStream $stream) : void{
|
||||
$stream->putUnsignedVarInt($this->actionType);
|
||||
$stream->putVarInt($this->hotbarSlot);
|
||||
$stream->putSlot($this->itemInHand);
|
||||
$stream->putVector3($this->headPos);
|
||||
}
|
||||
|
||||
public static function new(array $actions, int $actionType, int $hotbarSlot, Item $itemInHand, Vector3 $headPos) : self{
|
||||
$result = new self;
|
||||
$result->actions = $actions;
|
||||
$result->actionType = $actionType;
|
||||
$result->hotbarSlot = $hotbarSlot;
|
||||
$result->itemInHand = $itemInHand;
|
||||
$result->headPos = $headPos;
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
<?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\types;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
|
||||
abstract class TransactionData{
|
||||
/** @var NetworkInventoryAction[] */
|
||||
protected $actions;
|
||||
|
||||
/**
|
||||
* @return NetworkInventoryAction[]
|
||||
*/
|
||||
final public function getActions() : array{
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getTypeId() : int;
|
||||
|
||||
/**
|
||||
* @param NetworkBinaryStream $stream
|
||||
*
|
||||
* @throws \OutOfBoundsException
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
final public function decode(NetworkBinaryStream $stream) : void{
|
||||
$actionCount = $stream->getUnsignedVarInt();
|
||||
for($i = 0; $i < $actionCount; ++$i){
|
||||
$this->actions[] = (new NetworkInventoryAction())->read($stream);
|
||||
}
|
||||
$this->decodeData($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NetworkBinaryStream $stream
|
||||
*
|
||||
* @throws \OutOfBoundsException
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
abstract protected function decodeData(NetworkBinaryStream $stream) : void;
|
||||
|
||||
final public function encode(NetworkBinaryStream $stream) : void{
|
||||
$stream->putUnsignedVarInt(count($this->actions));
|
||||
foreach($this->actions as $action){
|
||||
$action->write($stream);
|
||||
}
|
||||
$this->encodeData($stream);
|
||||
}
|
||||
|
||||
abstract protected function encodeData(NetworkBinaryStream $stream) : void;
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
<?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\types;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
|
||||
class UseItemOnEntityTransactionData extends TransactionData{
|
||||
public const ACTION_INTERACT = 0;
|
||||
public const ACTION_ATTACK = 1;
|
||||
|
||||
/** @var int */
|
||||
private $entityRuntimeId;
|
||||
/** @var int */
|
||||
private $actionType;
|
||||
/** @var int */
|
||||
private $hotbarSlot;
|
||||
/** @var Item */
|
||||
private $itemInHand;
|
||||
/** @var Vector3 */
|
||||
private $playerPos;
|
||||
/** @var Vector3 */
|
||||
private $clickPos;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getEntityRuntimeId() : int{
|
||||
return $this->entityRuntimeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getActionType() : int{
|
||||
return $this->actionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getHotbarSlot() : int{
|
||||
return $this->hotbarSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getItemInHand() : Item{
|
||||
return $this->itemInHand;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getPlayerPos() : Vector3{
|
||||
return $this->playerPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getClickPos() : Vector3{
|
||||
return $this->clickPos;
|
||||
}
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_USE_ITEM_ON_ENTITY;
|
||||
}
|
||||
|
||||
protected function decodeData(NetworkBinaryStream $stream) : void{
|
||||
$this->entityRuntimeId = $stream->getEntityRuntimeId();
|
||||
$this->actionType = $stream->getUnsignedVarInt();
|
||||
$this->hotbarSlot = $stream->getVarInt();
|
||||
$this->itemInHand = $stream->getSlot();
|
||||
$this->playerPos = $stream->getVector3();
|
||||
$this->clickPos = $stream->getVector3();
|
||||
}
|
||||
|
||||
protected function encodeData(NetworkBinaryStream $stream) : void{
|
||||
$stream->putEntityRuntimeId($this->entityRuntimeId);
|
||||
$stream->putUnsignedVarInt($this->actionType);
|
||||
$stream->putVarInt($this->hotbarSlot);
|
||||
$stream->putSlot($this->itemInHand);
|
||||
$stream->putVector3($this->playerPos);
|
||||
$stream->putVector3($this->clickPos);
|
||||
}
|
||||
|
||||
public static function new(array $actions, int $entityRuntimeId, int $actionType, int $hotbarSlot, Item $itemInHand, Vector3 $playerPos, Vector3 $clickPos) : self{
|
||||
$result = new self;
|
||||
$result->actions = $actions;
|
||||
$result->entityRuntimeId = $entityRuntimeId;
|
||||
$result->actionType = $actionType;
|
||||
$result->hotbarSlot = $hotbarSlot;
|
||||
$result->itemInHand = $itemInHand;
|
||||
$result->playerPos = $playerPos;
|
||||
$result->clickPos = $clickPos;
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
<?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\types;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
|
||||
class UseItemTransactionData extends TransactionData{
|
||||
public const ACTION_CLICK_BLOCK = 0;
|
||||
public const ACTION_CLICK_AIR = 1;
|
||||
public const ACTION_BREAK_BLOCK = 2;
|
||||
|
||||
/** @var int */
|
||||
private $actionType;
|
||||
/** @var Vector3 */
|
||||
private $blockPos;
|
||||
/** @var int */
|
||||
private $face;
|
||||
/** @var int */
|
||||
private $hotbarSlot;
|
||||
/** @var Item */
|
||||
private $itemInHand;
|
||||
/** @var Vector3 */
|
||||
private $playerPos;
|
||||
/** @var Vector3 */
|
||||
private $clickPos;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getActionType() : int{
|
||||
return $this->actionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getBlockPos() : Vector3{
|
||||
return $this->blockPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getFace() : int{
|
||||
return $this->face;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getHotbarSlot() : int{
|
||||
return $this->hotbarSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getItemInHand() : Item{
|
||||
return $this->itemInHand;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getPlayerPos() : Vector3{
|
||||
return $this->playerPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getClickPos() : Vector3{
|
||||
return $this->clickPos;
|
||||
}
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_USE_ITEM;
|
||||
}
|
||||
|
||||
protected function decodeData(NetworkBinaryStream $stream) : void{
|
||||
$this->actionType = $stream->getUnsignedVarInt();
|
||||
$this->blockPos = new Vector3();
|
||||
$stream->getBlockPosition($this->blockPos->x, $this->blockPos->y, $this->blockPos->z);
|
||||
$this->face = $stream->getVarInt();
|
||||
$this->hotbarSlot = $stream->getVarInt();
|
||||
$this->itemInHand = $stream->getSlot();
|
||||
$this->playerPos = $stream->getVector3();
|
||||
$this->clickPos = $stream->getVector3();
|
||||
}
|
||||
|
||||
protected function encodeData(NetworkBinaryStream $stream) : void{
|
||||
$stream->putUnsignedVarInt($this->actionType);
|
||||
$stream->putBlockPosition($this->blockPos->x, $this->blockPos->y, $this->blockPos->z);
|
||||
$stream->putVarInt($this->face);
|
||||
$stream->putVarInt($this->hotbarSlot);
|
||||
$stream->putSlot($this->itemInHand);
|
||||
$stream->putVector3($this->playerPos);
|
||||
$stream->putVector3($this->clickPos);
|
||||
}
|
||||
|
||||
public static function new(array $actions, int $actionType, Vector3 $blockPos, int $face, int $hotbarSlot, Item $itemInHand, Vector3 $playerPos, Vector3 $clickPos) : self{
|
||||
$result = new self;
|
||||
$result->actions = $actions;
|
||||
$result->actionType = $actionType;
|
||||
$result->blockPos = $blockPos;
|
||||
$result->face = $face;
|
||||
$result->hotbarSlot = $hotbarSlot;
|
||||
$result->itemInHand = $itemInHand;
|
||||
$result->playerPos = $playerPos;
|
||||
$result->clickPos = $clickPos;
|
||||
return $result;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user