Protocol changes for 1.16.220

This commit is contained in:
Dylan K. Taylor 2021-04-07 18:59:01 +01:00
parent e22b6ff566
commit c9b83d7276
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
23 changed files with 232 additions and 179 deletions

View File

@ -2447,7 +2447,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_USE_INGREDIENT
) or (
$this->craftingTransaction !== null &&
!$networkInventoryAction->oldItem->equalsExact($networkInventoryAction->newItem) &&
!$networkInventoryAction->oldItem->getItemStack()->equalsExact($networkInventoryAction->newItem->getItemStack()) &&
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER &&
$networkInventoryAction->windowId === ContainerIds::UI &&
$networkInventoryAction->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT
@ -2552,7 +2552,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->getClickPos(), $this, true)){
return true;
}
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->getItemInHand())){
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->getItemInHand()->getItemStack())){
$this->inventory->sendHeldItem($this);
}else{
$item = $this->inventory->getItemInHand();
@ -2644,7 +2644,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if($this->isCreative()){
$item = $this->inventory->getItemInHand();
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->getItemInHand())){
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->getItemInHand()->getItemStack())){
$this->inventory->sendHeldItem($this);
return true;
}else{
@ -2814,8 +2814,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$item = $this->inventory->getItem($packet->hotbarSlot);
if(!$item->equals($packet->item)){
$this->server->getLogger()->debug("Tried to equip " . $packet->item . " but have " . $item . " in target slot");
if(!$item->equals($packet->item->getItemStack())){
$this->server->getLogger()->debug("Tried to equip " . $packet->item->getItemStack() . " but have " . $item . " in target slot");
$this->inventory->sendContents($this);
return false;
}

View File

@ -54,6 +54,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\Player;
@ -813,7 +814,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
$pk->motion = $this->getMotion();
$pk->yaw = $this->yaw;
$pk->pitch = $this->pitch;
$pk->item = $this->getInventory()->getItemInHand();
$pk->item = ItemStackWrapper::legacy($this->getInventory()->getItemInHand());
$pk->metadata = $this->propertyManager->getAll();
$player->dataPacket($pk);

View File

@ -30,6 +30,7 @@ use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\Player;
use function get_class;
@ -173,7 +174,7 @@ class ItemEntity extends Entity{
$pk->entityRuntimeId = $this->getId();
$pk->position = $this->asVector3();
$pk->motion = $this->getMotion();
$pk->item = $this->getItem();
$pk->item = ItemStackWrapper::legacy($this->getItem());
$pk->metadata = $this->propertyManager->getAll();
$player->dataPacket($pk);

View File

@ -98,10 +98,10 @@ class ArmorInventory extends BaseInventory{
$pk = new MobArmorEquipmentPacket();
$pk->entityRuntimeId = $this->getHolder()->getId();
$pk->head = $this->getHelmet();
$pk->chest = $this->getChestplate();
$pk->legs = $this->getLeggings();
$pk->feet = $this->getBoots();
$pk->head = ItemStackWrapper::legacy($this->getHelmet());
$pk->chest = ItemStackWrapper::legacy($this->getChestplate());
$pk->legs = ItemStackWrapper::legacy($this->getLeggings());
$pk->feet = ItemStackWrapper::legacy($this->getBoots());
$pk->encode();
foreach($target as $player){
@ -126,10 +126,10 @@ class ArmorInventory extends BaseInventory{
$pk = new MobArmorEquipmentPacket();
$pk->entityRuntimeId = $this->getHolder()->getId();
$pk->head = $this->getHelmet();
$pk->chest = $this->getChestplate();
$pk->legs = $this->getLeggings();
$pk->feet = $this->getBoots();
$pk->head = ItemStackWrapper::legacy($this->getHelmet());
$pk->chest = ItemStackWrapper::legacy($this->getChestplate());
$pk->legs = ItemStackWrapper::legacy($this->getLeggings());
$pk->feet = ItemStackWrapper::legacy($this->getBoots());
$pk->encode();
foreach($target as $player){

View File

@ -30,6 +30,7 @@ use pocketmine\network\mcpe\protocol\CreativeContentPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\Player;
use function array_map;
use function in_array;
@ -165,7 +166,7 @@ class PlayerInventory extends BaseInventory{
$pk = new MobEquipmentPacket();
$pk->entityRuntimeId = $this->getHolder()->getId();
$pk->item = $item;
$pk->item = ItemStackWrapper::legacy($item);
$pk->inventorySlot = $pk->hotbarSlot = $this->getHeldItemIndex();
$pk->windowId = ContainerIds::INVENTORY;

View File

@ -31,6 +31,7 @@ use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\utils\UUID;
@ -104,7 +105,7 @@ class FloatingTextParticle extends Particle{
$pk->username = $name;
$pk->entityRuntimeId = $this->entityId;
$pk->position = $this->asVector3(); //TODO: check offset
$pk->item = ItemFactory::get(Item::AIR, 0, 0);
$pk->item = ItemStackWrapper::legacy(ItemFactory::get(Item::AIR, 0, 0));
$flags = (
1 << Entity::DATA_FLAG_IMMOBILE

View File

@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe;
#include <rules/DataPacket.h>
use pocketmine\block\BlockIds;
use pocketmine\entity\Attribute;
use pocketmine\entity\Entity;
use pocketmine\item\Durable;
@ -32,12 +33,14 @@ use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\ItemIds;
use pocketmine\math\Vector3;
use pocketmine\nbt\LittleEndianNBTStream;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\NamedTag;
use pocketmine\network\mcpe\convert\ItemTranslator;
use pocketmine\network\mcpe\convert\ItemTypeDictionary;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\network\mcpe\protocol\types\GameRuleType;
@ -58,6 +61,7 @@ class NetworkBinaryStream extends BinaryStream{
private const DAMAGE_TAG = "Damage"; //TAG_Int
private const DAMAGE_TAG_CONFLICT_RESOLUTION = "___Damage_ProtocolCollisionResolution___";
private const PM_META_TAG = "___Meta___";
public function getString() : string{
return $this->get($this->getUnsignedVarInt());
@ -193,28 +197,48 @@ class NetworkBinaryStream extends BinaryStream{
$this->putString($image->getData());
}
public function getSlot() : Item{
public function getItemStackWithoutStackId() : Item{
return $this->getItemStack(function() : void{
//NOOP
});
}
public function putItemStackWithoutStackId(Item $item) : void{
$this->putItemStack($item, function() : void{
//NOOP
});
}
/**
* @phpstan-param \Closure(NetworkBinaryStream) : void $readExtraCrapInTheMiddle
*/
public function getItemStack(\Closure $readExtraCrapInTheMiddle) : Item{
$netId = $this->getVarInt();
if($netId === 0){
return ItemFactory::get(0, 0, 0);
}
$auxValue = $this->getVarInt();
$netData = $auxValue >> 8;
$cnt = $auxValue & 0xff;
$cnt = $this->getLShort();
$netData = $this->getUnsignedVarInt();
[$id, $meta] = ItemTranslator::getInstance()->fromNetworkId($netId, $netData);
$nbtLen = $this->getLShort();
$readExtraCrapInTheMiddle($this);
$this->getVarInt();
$extraData = new NetworkBinaryStream($this->getString());
return (static function() use ($extraData, $netId, $id, $meta, $cnt) : Item{
$nbtLen = $extraData->getLShort();
/** @var CompoundTag|null $nbt */
$nbt = null;
if($nbtLen === 0xffff){
$nbtDataVersion = $this->getByte();
$nbtDataVersion = $extraData->getByte();
if($nbtDataVersion !== 1){
throw new \UnexpectedValueException("Unexpected NBT data version $nbtDataVersion");
}
$decodedNBT = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
$decodedNBT = (new LittleEndianNBTStream())->read($extraData->buffer, false, $extraData->offset, 512);
if(!($decodedNBT instanceof CompoundTag)){
throw new \UnexpectedValueException("Unexpected root tag type for itemstack");
}
@ -224,17 +248,17 @@ class NetworkBinaryStream extends BinaryStream{
}
//TODO
for($i = 0, $canPlaceOn = $this->getVarInt(); $i < $canPlaceOn; ++$i){
$this->getString();
for($i = 0, $canPlaceOn = $extraData->getLInt(); $i < $canPlaceOn; ++$i){
$extraData->get($extraData->getLShort());
}
//TODO
for($i = 0, $canDestroy = $this->getVarInt(); $i < $canDestroy; ++$i){
$this->getString();
for($i = 0, $canDestroy = $extraData->getLInt(); $i < $canDestroy; ++$i){
$extraData->get($extraData->getLShort());
}
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
$this->getVarLong(); //"blocking tick" (ffs mojang)
$extraData->getLLong(); //"blocking tick" (ffs mojang)
}
if($nbt !== null){
if($nbt->hasTag(self::DAMAGE_TAG, IntTag::class)){
@ -247,29 +271,48 @@ class NetworkBinaryStream extends BinaryStream{
}elseif($nbt->count() === 0){
$nbt = null;
}
}elseif(($metaTag = $nbt->getTag(self::PM_META_TAG)) instanceof IntTag){
//TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the
//client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata
//client-side. Aside from being very annoying, this also breaks various server-side behaviours.
$meta = $metaTag->getValue();
$nbt->removeTag(self::PM_META_TAG);
if($nbt->count() === 0){
$nbt = null;
}
}
}
return ItemFactory::get($id, $meta, $cnt, $nbt);
})();
}
public function putSlot(Item $item) : void{
/**
* @phpstan-param \Closure(NetworkBinaryStream) : void $writeExtraCrapInTheMiddle
*/
public function putItemStack(Item $item, \Closure $writeExtraCrapInTheMiddle) : void{
if($item->getId() === 0){
$this->putVarInt(0);
return;
}
[$netId, $netData] = ItemTranslator::getInstance()->toNetworkId($item->getId(), $item->getDamage());
$coreData = $item->getDamage();
[$netId, $netData] = ItemTranslator::getInstance()->toNetworkId($item->getId(), $coreData);
$this->putVarInt($netId);
$auxValue = (($netData & 0x7fff) << 8) | $item->getCount();
$this->putVarInt($auxValue);
$this->putLShort($item->getCount());
$this->putUnsignedVarInt($netData);
$writeExtraCrapInTheMiddle($this);
$block = $item->getBlock();
$this->putVarInt($block->getId() === BlockIds::AIR ? 0 : RuntimeBlockMapping::toStaticRuntimeId($block->getId(), $block->getDamage()));
$nbt = null;
if($item->hasCompoundTag()){
$nbt = clone $item->getNamedTag();
}
if($item instanceof Durable and $item->getDamage() > 0){
if($item instanceof Durable and $coreData > 0){
if($nbt !== null){
if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){
$nbt->removeTag(self::DAMAGE_TAG);
@ -279,23 +322,37 @@ class NetworkBinaryStream extends BinaryStream{
}else{
$nbt = new CompoundTag();
}
$nbt->setInt(self::DAMAGE_TAG, $item->getDamage());
$nbt->setInt(self::DAMAGE_TAG, $coreData);
}elseif($block->getId() !== BlockIds::AIR && $coreData !== 0){
//TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the
//client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata
//client-side. Aside from being very annoying, this also breaks various server-side behaviours.
if($nbt === null){
$nbt = new CompoundTag();
}
$nbt->setInt(self::PM_META_TAG, $coreData);
}
$this->putString(
(static function() use ($nbt, $netId) : string{
$extraData = new NetworkBinaryStream();
if($nbt !== null){
$this->putLShort(0xffff);
$this->putByte(1); //TODO: NBT data version (?)
$this->put((new NetworkLittleEndianNBTStream())->write($nbt));
$extraData->putLShort(0xffff);
$extraData->putByte(1); //TODO: NBT data version (?)
$extraData->put((new LittleEndianNBTStream())->write($nbt));
}else{
$this->putLShort(0);
$extraData->putLShort(0);
}
$this->putVarInt(0); //CanPlaceOn entry count (TODO)
$this->putVarInt(0); //CanDestroy entry count (TODO)
$extraData->putLInt(0); //CanPlaceOn entry count (TODO)
$extraData->putLInt(0); //CanDestroy entry count (TODO)
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
$this->putVarLong(0); //"blocking tick" (ffs mojang)
$extraData->putLLong(0); //"blocking tick" (ffs mojang)
}
return $extraData->getBuffer();
})());
}
public function getRecipeIngredient() : Item{

View File

@ -25,9 +25,9 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
class AddItemActorPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ADD_ITEM_ACTOR_PACKET;
@ -36,7 +36,7 @@ class AddItemActorPacket extends DataPacket{
public $entityUniqueId = null; //TODO
/** @var int */
public $entityRuntimeId;
/** @var Item */
/** @var ItemStackWrapper */
public $item;
/** @var Vector3 */
public $position;
@ -53,7 +53,7 @@ class AddItemActorPacket extends DataPacket{
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->item = $this->getSlot();
$this->item = ItemStackWrapper::read($this);
$this->position = $this->getVector3();
$this->motion = $this->getVector3();
$this->metadata = $this->getEntityMetadata();
@ -63,7 +63,7 @@ class AddItemActorPacket extends DataPacket{
protected function encodePayload(){
$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
$this->putEntityRuntimeId($this->entityRuntimeId);
$this->putSlot($this->item);
$this->item->write($this);
$this->putVector3($this->position);
$this->putVector3Nullable($this->motion);
$this->putEntityMetadata($this->metadata);

View File

@ -25,11 +25,11 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\DeviceOS;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\utils\UUID;
use function count;
@ -56,7 +56,7 @@ class AddPlayerPacket extends DataPacket{
public $yaw = 0.0;
/** @var float|null */
public $headYaw = null; //TODO
/** @var Item */
/** @var ItemStackWrapper */
public $item;
/**
* @var mixed[][]
@ -98,7 +98,7 @@ class AddPlayerPacket extends DataPacket{
$this->pitch = $this->getLFloat();
$this->yaw = $this->getLFloat();
$this->headYaw = $this->getLFloat();
$this->item = $this->getSlot();
$this->item = ItemStackWrapper::read($this);
$this->metadata = $this->getEntityMetadata();
$this->uvarint1 = $this->getUnsignedVarInt();
@ -129,7 +129,7 @@ class AddPlayerPacket extends DataPacket{
$this->putLFloat($this->pitch);
$this->putLFloat($this->yaw);
$this->putLFloat($this->headYaw ?? $this->yaw);
$this->putSlot($this->item);
$this->item->write($this);
$this->putEntityMetadata($this->metadata);
$this->putUnsignedVarInt($this->uvarint1);

View File

@ -91,7 +91,7 @@ class CraftingDataPacket extends DataPacket{
$resultCount = $this->getUnsignedVarInt();
$entry["output"] = [];
for($k = 0; $k < $resultCount; ++$k){
$entry["output"][] = $this->getSlot();
$entry["output"][] = $this->getItemStackWithoutStackId();
}
$entry["uuid"] = $this->getUUID()->toString();
$entry["block"] = $this->getString();
@ -113,7 +113,7 @@ class CraftingDataPacket extends DataPacket{
$resultCount = $this->getUnsignedVarInt();
$entry["output"] = [];
for($k = 0; $k < $resultCount; ++$k){
$entry["output"][] = $this->getSlot();
$entry["output"][] = $this->getItemStackWithoutStackId();
}
$entry["uuid"] = $this->getUUID()->toString();
$entry["block"] = $this->getString();
@ -131,7 +131,7 @@ class CraftingDataPacket extends DataPacket{
[$inputId, $inputData] = ItemTranslator::getInstance()->fromNetworkIdWithWildcardHandling($inputIdNet, $inputMetaNet);
}
$entry["input"] = ItemFactory::get($inputId, $inputData);
$entry["output"] = $out = $this->getSlot();
$entry["output"] = $out = $this->getItemStackWithoutStackId();
if($out->getDamage() === 0x7fff){
$out->setDamage(0); //TODO HACK: some 1.12 furnace recipe outputs have wildcard damage values
}
@ -198,7 +198,7 @@ class CraftingDataPacket extends DataPacket{
$results = $recipe->getResults();
$stream->putUnsignedVarInt(count($results));
foreach($results as $item){
$stream->putSlot($item);
$stream->putItemStackWithoutStackId($item);
}
$stream->put(str_repeat("\x00", 16)); //Null UUID
@ -223,7 +223,7 @@ class CraftingDataPacket extends DataPacket{
$results = $recipe->getResults();
$stream->putUnsignedVarInt(count($results));
foreach($results as $item){
$stream->putSlot($item);
$stream->putItemStackWithoutStackId($item);
}
$stream->put(str_repeat("\x00", 16)); //Null UUID
@ -244,7 +244,7 @@ class CraftingDataPacket extends DataPacket{
}
$stream->putVarInt($netId);
$stream->putVarInt($netData);
$stream->putSlot($recipe->getResult());
$stream->putItemStackWithoutStackId($recipe->getResult());
$stream->putString("furnace"); //TODO: blocktype (no prefix) (this might require internal API breaks)
return CraftingDataPacket::ENTRY_FURNACE_DATA;
}

View File

@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\utils\UUID;
use function count;
@ -39,9 +39,9 @@ class CraftingEventPacket extends DataPacket{
public $type;
/** @var UUID */
public $id;
/** @var Item[] */
/** @var ItemStackWrapper[] */
public $input = [];
/** @var Item[] */
/** @var ItemStackWrapper[] */
public $output = [];
public function clean(){
@ -57,12 +57,12 @@ class CraftingEventPacket extends DataPacket{
$size = $this->getUnsignedVarInt();
for($i = 0; $i < $size and $i < 128; ++$i){
$this->input[] = $this->getSlot();
$this->input[] = ItemStackWrapper::read($this);
}
$size = $this->getUnsignedVarInt();
for($i = 0; $i < $size and $i < 128; ++$i){
$this->output[] = $this->getSlot();
$this->output[] = ItemStackWrapper::read($this);
}
}
@ -73,12 +73,12 @@ class CraftingEventPacket extends DataPacket{
$this->putUnsignedVarInt(count($this->input));
foreach($this->input as $item){
$this->putSlot($item);
$item->write($this);
}
$this->putUnsignedVarInt(count($this->output));
foreach($this->output as $item){
$this->putSlot($item);
$item->write($this);
}
}

View File

@ -49,8 +49,6 @@ class InventoryTransactionPacket extends DataPacket{
public $requestId;
/** @var InventoryTransactionChangedSlotsHack[] */
public $requestChangedSlots;
/** @var bool */
public $hasItemStackIds;
/** @var TransactionData */
public $trData;
@ -66,8 +64,6 @@ class InventoryTransactionPacket extends DataPacket{
$transactionType = $in->getUnsignedVarInt();
$this->hasItemStackIds = $in->getBool();
switch($transactionType){
case self::TYPE_NORMAL:
$this->trData = new NormalTransactionData();
@ -88,7 +84,7 @@ class InventoryTransactionPacket extends DataPacket{
throw new PacketDecodeException("Unknown transaction type $transactionType");
}
$this->trData->decode($in, $this->hasItemStackIds);
$this->trData->decode($in);
}
protected function encodePayload() : void{
@ -103,9 +99,7 @@ class InventoryTransactionPacket extends DataPacket{
$out->putUnsignedVarInt($this->trData->getTypeId());
$out->putBool($this->hasItemStackIds);
$this->trData->encode($out, $this->hasItemStackIds);
$this->trData->encode($out);
}
public function handle(PacketHandlerInterface $handler) : bool{

View File

@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
class MobArmorEquipmentPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET;
@ -36,29 +36,29 @@ class MobArmorEquipmentPacket extends DataPacket{
//this intentionally doesn't use an array because we don't want any implicit dependencies on internal order
/** @var Item */
/** @var ItemStackWrapper */
public $head;
/** @var Item */
/** @var ItemStackWrapper */
public $chest;
/** @var Item */
/** @var ItemStackWrapper */
public $legs;
/** @var Item */
/** @var ItemStackWrapper */
public $feet;
protected function decodePayload(){
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->head = $this->getSlot();
$this->chest = $this->getSlot();
$this->legs = $this->getSlot();
$this->feet = $this->getSlot();
$this->head = ItemStackWrapper::read($this);
$this->chest = ItemStackWrapper::read($this);
$this->legs = ItemStackWrapper::read($this);
$this->feet = ItemStackWrapper::read($this);
}
protected function encodePayload(){
$this->putEntityRuntimeId($this->entityRuntimeId);
$this->putSlot($this->head);
$this->putSlot($this->chest);
$this->putSlot($this->legs);
$this->putSlot($this->feet);
$this->head->write($this);
$this->chest->write($this);
$this->legs->write($this);
$this->feet->write($this);
}
public function handle(NetworkSession $session) : bool{

View File

@ -25,15 +25,15 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
class MobEquipmentPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::MOB_EQUIPMENT_PACKET;
/** @var int */
public $entityRuntimeId;
/** @var Item */
/** @var ItemStackWrapper */
public $item;
/** @var int */
public $inventorySlot;
@ -44,7 +44,7 @@ class MobEquipmentPacket extends DataPacket{
protected function decodePayload(){
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->item = $this->getSlot();
$this->item = ItemStackWrapper::read($this);
$this->inventorySlot = $this->getByte();
$this->hotbarSlot = $this->getByte();
$this->windowId = $this->getByte();
@ -52,7 +52,7 @@ class MobEquipmentPacket extends DataPacket{
protected function encodePayload(){
$this->putEntityRuntimeId($this->entityRuntimeId);
$this->putSlot($this->item);
$this->item->write($this);
$this->putByte($this->inventorySlot);
$this->putByte($this->hotbarSlot);
$this->putByte($this->windowId);

View File

@ -37,11 +37,11 @@ interface ProtocolInfo{
*/
/** Actual Minecraft: PE protocol version */
public const CURRENT_PROTOCOL = 428;
public const CURRENT_PROTOCOL = 431;
/** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */
public const MINECRAFT_VERSION = 'v1.16.210';
public const MINECRAFT_VERSION = 'v1.16.220';
/** Version number sent to clients in ping responses. */
public const MINECRAFT_VERSION_NETWORK = '1.16.210';
public const MINECRAFT_VERSION_NETWORK = '1.16.220';
public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02;

View File

@ -30,6 +30,7 @@ use pocketmine\inventory\transaction\action\InventoryAction;
use pocketmine\inventory\transaction\action\SlotChangeAction;
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
use pocketmine\Player;
use function array_key_exists;
@ -79,17 +80,15 @@ class NetworkInventoryAction{
public $sourceFlags = 0;
/** @var int */
public $inventorySlot;
/** @var Item */
/** @var ItemStackWrapper */
public $oldItem;
/** @var Item */
/** @var ItemStackWrapper */
public $newItem;
/** @var int|null */
public $newItemStackId = null;
/**
* @return $this
*/
public function read(NetworkBinaryStream $packet, bool $hasItemStackIds){
public function read(NetworkBinaryStream $packet){
$this->sourceType = $packet->getUnsignedVarInt();
switch($this->sourceType){
@ -109,11 +108,8 @@ class NetworkInventoryAction{
}
$this->inventorySlot = $packet->getUnsignedVarInt();
$this->oldItem = $packet->getSlot();
$this->newItem = $packet->getSlot();
if($hasItemStackIds){
$this->newItemStackId = $packet->readGenericTypeNetworkId();
}
$this->oldItem = ItemStackWrapper::read($packet);
$this->newItem = ItemStackWrapper::read($packet);
return $this;
}
@ -121,7 +117,7 @@ class NetworkInventoryAction{
/**
* @return void
*/
public function write(NetworkBinaryStream $packet, bool $hasItemStackIds){
public function write(NetworkBinaryStream $packet){
$packet->putUnsignedVarInt($this->sourceType);
switch($this->sourceType){
@ -141,14 +137,8 @@ class NetworkInventoryAction{
}
$packet->putUnsignedVarInt($this->inventorySlot);
$packet->putSlot($this->oldItem);
$packet->putSlot($this->newItem);
if($hasItemStackIds){
if($this->newItemStackId === null){
throw new \InvalidStateException("Item stack ID for newItem must be provided");
}
$packet->writeGenericTypeNetworkId($this->newItemStackId);
}
$this->oldItem->write($packet);
$this->newItem->write($packet);
}
/**
@ -157,7 +147,9 @@ class NetworkInventoryAction{
* @throws \UnexpectedValueException
*/
public function createInventoryAction(Player $player){
if($this->oldItem->equalsExact($this->newItem)){
$oldItem = $this->oldItem->getItemStack();
$newItem = $this->newItem->getItemStack();
if($oldItem->equalsExact($newItem)){
//filter out useless noise in 1.13
return null;
}
@ -187,7 +179,7 @@ class NetworkInventoryAction{
$slot = $this->inventorySlot;
}
if($window !== null){
return new SlotChangeAction($window, $slot, $this->oldItem, $this->newItem);
return new SlotChangeAction($window, $slot, $oldItem, $newItem);
}
throw new \UnexpectedValueException("Player " . $player->getName() . " has no open container with window ID $this->windowId");
@ -196,7 +188,7 @@ class NetworkInventoryAction{
throw new \UnexpectedValueException("Only expecting drop-item world actions from the client!");
}
return new DropItemAction($this->newItem);
return new DropItemAction($newItem);
case self::SOURCE_CREATIVE:
switch($this->inventorySlot){
case self::ACTION_MAGIC_SLOT_CREATIVE_DELETE_ITEM:
@ -210,7 +202,7 @@ class NetworkInventoryAction{
}
return new CreativeInventoryAction($this->oldItem, $this->newItem, $type);
return new CreativeInventoryAction($oldItem, $newItem, $type);
case self::SOURCE_TODO:
//These types need special handling.
switch($this->windowId){

View File

@ -44,12 +44,12 @@ final class CreativeContentEntry{
public static function read(NetworkBinaryStream $in) : self{
$entryId = $in->readGenericTypeNetworkId();
$item = $in->getSlot();
$item = $in->getItemStackWithoutStackId();
return new self($entryId, $item);
}
public function write(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->entryId);
$out->putSlot($this->item);
$out->putItemStackWithoutStackId($this->item);
}
}

View File

@ -47,13 +47,22 @@ final class ItemStackWrapper{
public function getItemStack() : Item{ return $this->itemStack; }
public static function read(NetworkBinaryStream $in) : self{
$stackId = 0;
$stack = $in->getItemStack(function(NetworkBinaryStream $in) use (&$stackId) : void{
$hasNetId = $in->getBool();
if($hasNetId){
$stackId = $in->readGenericTypeNetworkId();
$stack = $in->getSlot();
}
});
return new self($stackId, $stack);
}
public function write(NetworkBinaryStream $out) : void{
$out->putItemStack($this->itemStack, function(NetworkBinaryStream $out) : void{
$out->putBool($this->stackId !== 0);
if($this->stackId !== 0){
$out->writeGenericTypeNetworkId($this->stackId);
$out->putSlot($this->itemStack);
}
});
}
}

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\item\Item as ItemStack;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
@ -37,7 +36,7 @@ class ReleaseItemTransactionData extends TransactionData{
private $actionType;
/** @var int */
private $hotbarSlot;
/** @var ItemStack */
/** @var ItemStackWrapper */
private $itemInHand;
/** @var Vector3 */
private $headPos;
@ -50,7 +49,7 @@ class ReleaseItemTransactionData extends TransactionData{
return $this->hotbarSlot;
}
public function getItemInHand() : ItemStack{
public function getItemInHand() : ItemStackWrapper{
return $this->itemInHand;
}
@ -65,21 +64,21 @@ class ReleaseItemTransactionData extends TransactionData{
protected function decodeData(PacketSerializer $stream) : void{
$this->actionType = $stream->getUnsignedVarInt();
$this->hotbarSlot = $stream->getVarInt();
$this->itemInHand = $stream->getSlot();
$this->itemInHand = ItemStackWrapper::read($stream);
$this->headPos = $stream->getVector3();
}
protected function encodeData(PacketSerializer $stream) : void{
$stream->putUnsignedVarInt($this->actionType);
$stream->putVarInt($this->hotbarSlot);
$stream->putSlot($this->itemInHand);
$this->itemInHand->write($stream);
$stream->putVector3($this->headPos);
}
/**
* @param NetworkInventoryAction[] $actions
*/
public static function new(array $actions, int $actionType, int $hotbarSlot, ItemStack $itemInHand, Vector3 $headPos) : self{
public static function new(array $actions, int $actionType, int $hotbarSlot, ItemStackWrapper $itemInHand, Vector3 $headPos) : self{
$result = new self;
$result->actions = $actions;
$result->actionType = $actionType;

View File

@ -46,10 +46,10 @@ abstract class TransactionData{
* @throws BinaryDataException
* @throws PacketDecodeException
*/
final public function decode(PacketSerializer $stream, bool $hasItemStackIds) : void{
final public function decode(PacketSerializer $stream) : void{
$actionCount = $stream->getUnsignedVarInt();
for($i = 0; $i < $actionCount; ++$i){
$this->actions[] = (new NetworkInventoryAction())->read($stream, $hasItemStackIds);
$this->actions[] = (new NetworkInventoryAction())->read($stream);
}
$this->decodeData($stream);
}
@ -60,10 +60,10 @@ abstract class TransactionData{
*/
abstract protected function decodeData(PacketSerializer $stream) : void;
final public function encode(PacketSerializer $stream, bool $hasItemStackIds) : void{
final public function encode(PacketSerializer $stream) : void{
$stream->putUnsignedVarInt(count($this->actions));
foreach($this->actions as $action){
$action->write($stream, $hasItemStackIds);
$action->write($stream);
}
$this->encodeData($stream);
}

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\item\Item as ItemStack;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
@ -39,7 +38,7 @@ class UseItemOnEntityTransactionData extends TransactionData{
private $actionType;
/** @var int */
private $hotbarSlot;
/** @var ItemStack */
/** @var ItemStackWrapper */
private $itemInHand;
/** @var Vector3 */
private $playerPos;
@ -58,7 +57,7 @@ class UseItemOnEntityTransactionData extends TransactionData{
return $this->hotbarSlot;
}
public function getItemInHand() : ItemStack{
public function getItemInHand() : ItemStackWrapper{
return $this->itemInHand;
}
@ -78,7 +77,7 @@ class UseItemOnEntityTransactionData extends TransactionData{
$this->entityRuntimeId = $stream->getEntityRuntimeId();
$this->actionType = $stream->getUnsignedVarInt();
$this->hotbarSlot = $stream->getVarInt();
$this->itemInHand = $stream->getSlot();
$this->itemInHand = ItemStackWrapper::read($stream);
$this->playerPos = $stream->getVector3();
$this->clickPos = $stream->getVector3();
}
@ -87,7 +86,7 @@ class UseItemOnEntityTransactionData extends TransactionData{
$stream->putEntityRuntimeId($this->entityRuntimeId);
$stream->putUnsignedVarInt($this->actionType);
$stream->putVarInt($this->hotbarSlot);
$stream->putSlot($this->itemInHand);
$this->itemInHand->write($stream);
$stream->putVector3($this->playerPos);
$stream->putVector3($this->clickPos);
}
@ -95,7 +94,7 @@ class UseItemOnEntityTransactionData extends TransactionData{
/**
* @param NetworkInventoryAction[] $actions
*/
public static function new(array $actions, int $entityRuntimeId, int $actionType, int $hotbarSlot, ItemStack $itemInHand, Vector3 $playerPos, Vector3 $clickPos) : self{
public static function new(array $actions, int $entityRuntimeId, int $actionType, int $hotbarSlot, ItemStackWrapper $itemInHand, Vector3 $playerPos, Vector3 $clickPos) : self{
$result = new self;
$result->actions = $actions;
$result->entityRuntimeId = $entityRuntimeId;

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\item\Item as ItemStack;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
@ -42,7 +41,7 @@ class UseItemTransactionData extends TransactionData{
private $face;
/** @var int */
private $hotbarSlot;
/** @var ItemStack */
/** @var ItemStackWrapper */
private $itemInHand;
/** @var Vector3 */
private $playerPos;
@ -67,7 +66,7 @@ class UseItemTransactionData extends TransactionData{
return $this->hotbarSlot;
}
public function getItemInHand() : ItemStack{
public function getItemInHand() : ItemStackWrapper{
return $this->itemInHand;
}
@ -94,7 +93,7 @@ class UseItemTransactionData extends TransactionData{
$this->blockPos = new Vector3($x, $y, $z);
$this->face = $stream->getVarInt();
$this->hotbarSlot = $stream->getVarInt();
$this->itemInHand = $stream->getSlot();
$this->itemInHand = ItemStackWrapper::read($stream);
$this->playerPos = $stream->getVector3();
$this->clickPos = $stream->getVector3();
$this->blockRuntimeId = $stream->getUnsignedVarInt();
@ -105,7 +104,7 @@ class UseItemTransactionData extends TransactionData{
$stream->putBlockPosition($this->blockPos->x, $this->blockPos->y, $this->blockPos->z);
$stream->putVarInt($this->face);
$stream->putVarInt($this->hotbarSlot);
$stream->putSlot($this->itemInHand);
$this->itemInHand->write($stream);
$stream->putVector3($this->playerPos);
$stream->putVector3($this->clickPos);
$stream->putUnsignedVarInt($this->blockRuntimeId);
@ -114,7 +113,7 @@ class UseItemTransactionData extends TransactionData{
/**
* @param NetworkInventoryAction[] $actions
*/
public static function new(array $actions, int $actionType, Vector3 $blockPos, int $face, int $hotbarSlot, ItemStack $itemInHand, Vector3 $playerPos, Vector3 $clickPos, int $blockRuntimeId) : self{
public static function new(array $actions, int $actionType, Vector3 $blockPos, int $face, int $hotbarSlot, ItemStackWrapper $itemInHand, Vector3 $playerPos, Vector3 $clickPos, int $blockRuntimeId) : self{
$result = new self;
$result->actions = $actions;
$result->actionType = $actionType;

View File

@ -58,7 +58,7 @@ final class DeprecatedCraftingResultsStackRequestAction extends ItemStackRequest
public static function read(NetworkBinaryStream $in) : self{
$results = [];
for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){
$results[] = $in->getSlot();
$results[] = $in->getItemStackWithoutStackId();
}
$iterations = $in->getByte();
return new self($results, $iterations);
@ -67,7 +67,7 @@ final class DeprecatedCraftingResultsStackRequestAction extends ItemStackRequest
public function write(NetworkBinaryStream $out) : void{
$out->putUnsignedVarInt(count($this->results));
foreach($this->results as $result){
$out->putSlot($result);
$out->putItemStackWithoutStackId($result);
}
$out->putByte($this->iterations);
}