mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-11 16:29:40 +00:00
the great airgapping of recipes and itemstacks
This commit is contained in:
parent
843993f02b
commit
18d48869a0
@ -26,13 +26,22 @@ namespace pocketmine\crafting;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
||||
use pocketmine\network\mcpe\compression\Zlib;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\PacketBatch;
|
||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe as ProtocolFurnaceRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\ShapedRecipe as ProtocolShapedRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\ShapelessRecipe as ProtocolShapelessRecipe;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\UUID;
|
||||
use function array_map;
|
||||
use function file_get_contents;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function str_repeat;
|
||||
use function usort;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
@ -101,19 +110,58 @@ class CraftingManager{
|
||||
$pk = new CraftingDataPacket();
|
||||
$pk->cleanRecipes = true;
|
||||
|
||||
$counter = 0;
|
||||
$nullUUID = UUID::fromData(str_repeat("\x00", 16));
|
||||
$converter = TypeConverter::getInstance();
|
||||
foreach($this->shapelessRecipes as $list){
|
||||
foreach($list as $recipe){
|
||||
$pk->addShapelessRecipe($recipe);
|
||||
$pk->entries[] = new ProtocolShapelessRecipe(
|
||||
CraftingDataPacket::ENTRY_SHAPELESS,
|
||||
Binary::writeInt($counter++),
|
||||
array_map(function(Item $item) use ($converter) : RecipeIngredient{
|
||||
return $converter->coreItemStackToRecipeIngredient($item);
|
||||
}, $recipe->getIngredientList()),
|
||||
array_map(function(Item $item) use ($converter) : ItemStack{
|
||||
return $converter->coreItemStackToNet($item);
|
||||
}, $recipe->getResults()),
|
||||
$nullUUID,
|
||||
"crafting_table",
|
||||
50
|
||||
);
|
||||
}
|
||||
}
|
||||
foreach($this->shapedRecipes as $list){
|
||||
foreach($list as $recipe){
|
||||
$pk->addShapedRecipe($recipe);
|
||||
$inputs = [];
|
||||
|
||||
for($row = 0, $height = $recipe->getHeight(); $row < $height; ++$row){
|
||||
for($column = 0, $width = $recipe->getWidth(); $column < $width; ++$column){
|
||||
$inputs[$row][$column] = $converter->coreItemStackToRecipeIngredient($recipe->getIngredient($column, $row));
|
||||
}
|
||||
}
|
||||
$pk->entries[] = $r = new ProtocolShapedRecipe(
|
||||
CraftingDataPacket::ENTRY_SHAPED,
|
||||
Binary::writeInt($counter++),
|
||||
$inputs,
|
||||
array_map(function(Item $item) use ($converter) : ItemStack{
|
||||
return $converter->coreItemStackToNet($item);
|
||||
}, $recipe->getResults()),
|
||||
$nullUUID,
|
||||
"crafting_table",
|
||||
50
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->furnaceRecipes as $recipe){
|
||||
$pk->addFurnaceRecipe($recipe);
|
||||
$input = $converter->coreItemStackToNet($recipe->getInput());
|
||||
$pk->entries[] = new ProtocolFurnaceRecipe(
|
||||
CraftingDataPacket::ENTRY_FURNACE_DATA,
|
||||
$input->getId(),
|
||||
$input->getMeta(),
|
||||
$converter->coreItemStackToNet($recipe->getResult()),
|
||||
"furnace"
|
||||
);
|
||||
}
|
||||
|
||||
$this->craftingDataCache = new CompressBatchPromise();
|
||||
|
@ -41,6 +41,7 @@ use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\ActorEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
|
||||
@ -403,7 +404,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
$pk->motion = $this->getMotion();
|
||||
$pk->yaw = $this->location->yaw;
|
||||
$pk->pitch = $this->location->pitch;
|
||||
$pk->item = $this->getInventory()->getItemInHand();
|
||||
$pk->item = TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand());
|
||||
$pk->metadata = $this->getSyncedNetworkData(false);
|
||||
$player->getNetworkSession()->sendDataPacket($pk);
|
||||
|
||||
|
@ -29,6 +29,7 @@ use pocketmine\event\entity\ItemSpawnEvent;
|
||||
use pocketmine\event\inventory\InventoryPickupItemEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityLegacyIds;
|
||||
@ -210,7 +211,7 @@ class ItemEntity extends Entity{
|
||||
$pk->entityRuntimeId = $this->getId();
|
||||
$pk->position = $this->location->asVector3();
|
||||
$pk->motion = $this->getMotion();
|
||||
$pk->item = $this->getItem();
|
||||
$pk->item = TypeConverter::getInstance()->coreItemStackToNet($this->getItem());
|
||||
$pk->metadata = $this->getSyncedNetworkData(false);
|
||||
|
||||
$player->getNetworkSession()->sendDataPacket($pk);
|
||||
|
@ -34,6 +34,7 @@ use pocketmine\inventory\Inventory;
|
||||
use pocketmine\inventory\transaction\action\SlotChangeAction;
|
||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
|
||||
@ -41,6 +42,7 @@ use pocketmine\network\mcpe\protocol\InventoryContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\WindowTypes;
|
||||
use pocketmine\player\Player;
|
||||
use function array_search;
|
||||
@ -159,7 +161,7 @@ class InventoryManager{
|
||||
$currentItem = $inventory->getItem($slot);
|
||||
$clientSideItem = $this->initiatedSlotChanges[$windowId][$slot] ?? null;
|
||||
if($clientSideItem === null or !$clientSideItem->equalsExact($currentItem)){
|
||||
$this->session->sendDataPacket(InventorySlotPacket::create($windowId, $slot, $currentItem));
|
||||
$this->session->sendDataPacket(InventorySlotPacket::create($windowId, $slot, TypeConverter::getInstance()->coreItemStackToNet($currentItem)));
|
||||
}
|
||||
unset($this->initiatedSlotChanges[$windowId][$slot]);
|
||||
}
|
||||
@ -169,7 +171,10 @@ class InventoryManager{
|
||||
$windowId = $this->getWindowId($inventory);
|
||||
if($windowId !== null){
|
||||
unset($this->initiatedSlotChanges[$windowId]);
|
||||
$this->session->sendDataPacket(InventoryContentPacket::create($windowId, $inventory->getContents(true)));
|
||||
$typeConverter = TypeConverter::getInstance();
|
||||
$this->session->sendDataPacket(InventoryContentPacket::create($windowId, array_map(function(Item $itemStack) use ($typeConverter) : ItemStack{
|
||||
return $typeConverter->coreItemStackToNet($itemStack);
|
||||
}, $inventory->getContents(true))));
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,7 +194,7 @@ class InventoryManager{
|
||||
public function syncSelectedHotbarSlot() : void{
|
||||
$this->session->sendDataPacket(MobEquipmentPacket::create(
|
||||
$this->player->getId(),
|
||||
$this->player->getInventory()->getItemInHand(),
|
||||
TypeConverter::getInstance()->coreItemStackToNet($this->player->getInventory()->getItemInHand()),
|
||||
$this->player->getInventory()->getHeldItemIndex(),
|
||||
ContainerIds::INVENTORY
|
||||
));
|
||||
@ -197,9 +202,10 @@ class InventoryManager{
|
||||
|
||||
public function syncCreative() : void{
|
||||
$items = [];
|
||||
$typeConverter = TypeConverter::getInstance();
|
||||
if(!$this->player->isSpectator()){ //fill it for all gamemodes except spectator
|
||||
foreach(CreativeInventory::getAll() as $i => $item){
|
||||
$items[$i] = clone $item;
|
||||
$items[$i] = $typeConverter->coreItemStackToNet($item);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@ use pocketmine\network\BadPacketException;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
||||
use pocketmine\network\mcpe\compression\DecompressionException;
|
||||
use pocketmine\network\mcpe\compression\Zlib;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\encryption\DecryptionException;
|
||||
use pocketmine\network\mcpe\encryption\NetworkCipher;
|
||||
use pocketmine\network\mcpe\encryption\PrepareEncryptionTask;
|
||||
@ -790,12 +791,19 @@ class NetworkSession{
|
||||
public function onMobEquipmentChange(Human $mob) : void{
|
||||
//TODO: we could send zero for slot here because remote players don't need to know which slot was selected
|
||||
$inv = $mob->getInventory();
|
||||
$this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), $inv->getItemInHand(), $inv->getHeldItemIndex(), ContainerIds::INVENTORY));
|
||||
$this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), TypeConverter::getInstance()->coreItemStackToNet($inv->getItemInHand()), $inv->getHeldItemIndex(), ContainerIds::INVENTORY));
|
||||
}
|
||||
|
||||
public function onMobArmorChange(Living $mob) : void{
|
||||
$inv = $mob->getArmorInventory();
|
||||
$this->sendDataPacket(MobArmorEquipmentPacket::create($mob->getId(), $inv->getHelmet(), $inv->getChestplate(), $inv->getLeggings(), $inv->getBoots()));
|
||||
$converter = TypeConverter::getInstance();
|
||||
$this->sendDataPacket(MobArmorEquipmentPacket::create(
|
||||
$mob->getId(),
|
||||
$converter->coreItemStackToNet($inv->getHelmet()),
|
||||
$converter->coreItemStackToNet($inv->getChestplate()),
|
||||
$converter->coreItemStackToNet($inv->getLeggings()),
|
||||
$converter->coreItemStackToNet($inv->getBoots())
|
||||
));
|
||||
}
|
||||
|
||||
public function syncPlayerList() : void{
|
||||
|
124
src/network/mcpe/convert/TypeConverter.php
Normal file
124
src/network/mcpe/convert/TypeConverter.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?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\convert;
|
||||
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\ItemIds;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient;
|
||||
|
||||
class TypeConverter{
|
||||
private const DAMAGE_TAG = "Damage"; //TAG_Int
|
||||
private const DAMAGE_TAG_CONFLICT_RESOLUTION = "___Damage_ProtocolCollisionResolution___";
|
||||
|
||||
/** @var self|null */
|
||||
private static $instance;
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public static function getInstance() : self{
|
||||
if(self::$instance === null){
|
||||
self::$instance = new self;
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public static function setInstance(self $instance) : void{
|
||||
self::$instance = $instance;
|
||||
}
|
||||
|
||||
public function coreItemStackToRecipeIngredient(Item $itemStack) : RecipeIngredient{
|
||||
$meta = $itemStack->getMeta();
|
||||
return new RecipeIngredient($itemStack->getId(), $meta === -1 ? 0x7fff : $meta, $itemStack->getCount());
|
||||
}
|
||||
|
||||
public function recipeIngredientToCoreItemStack(RecipeIngredient $ingredient) : Item{
|
||||
$meta = $ingredient->getMeta();
|
||||
return ItemFactory::get($ingredient->getId(), $meta === 0x7fff ? -1 : $meta, $ingredient->getCount());
|
||||
}
|
||||
|
||||
public function coreItemStackToNet(Item $itemStack) : ItemStack{
|
||||
$nbt = null;
|
||||
if($itemStack->hasNamedTag()){
|
||||
$nbt = clone $itemStack->getNamedTag();
|
||||
}
|
||||
if($itemStack instanceof Durable and $itemStack->getDamage() > 0){
|
||||
if($nbt !== null){
|
||||
if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){
|
||||
$nbt->removeTag(self::DAMAGE_TAG);
|
||||
$nbt->setTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION, $existing);
|
||||
}
|
||||
}else{
|
||||
$nbt = new CompoundTag();
|
||||
}
|
||||
$nbt->setInt(self::DAMAGE_TAG, $itemStack->getDamage());
|
||||
}
|
||||
$id = $itemStack->getId();
|
||||
$meta = $itemStack->getMeta();
|
||||
|
||||
return new ItemStack(
|
||||
$id,
|
||||
$meta === -1 ? 0x7fff : $meta,
|
||||
$itemStack->getCount(),
|
||||
$nbt,
|
||||
[],
|
||||
[],
|
||||
$id === ItemIds::SHIELD ? 0 : null
|
||||
);
|
||||
}
|
||||
|
||||
public function netItemStackToCore(ItemStack $itemStack) : Item{
|
||||
$compound = $itemStack->getNbt();
|
||||
$meta = $itemStack->getMeta();
|
||||
|
||||
if($compound !== null){
|
||||
$compound = clone $compound;
|
||||
if($compound->hasTag(self::DAMAGE_TAG, IntTag::class)){
|
||||
$meta = $compound->getInt(self::DAMAGE_TAG);
|
||||
$compound->removeTag(self::DAMAGE_TAG);
|
||||
if($compound->count() === 0){
|
||||
$compound = null;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if(($conflicted = $compound->getTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION)) !== null){
|
||||
$compound->removeTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
|
||||
$compound->setTag(self::DAMAGE_TAG, $conflicted);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return ItemFactory::get(
|
||||
$itemStack->getId(),
|
||||
$meta !== 0x7fff ? $meta : -1,
|
||||
$itemStack->getCount(),
|
||||
$compound
|
||||
);
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NbtDataException;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\BadPacketException;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\ActorEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\ActorFallPacket;
|
||||
@ -205,14 +206,16 @@ class InGamePacketHandler extends PacketHandler{
|
||||
$isCrafting = false;
|
||||
$isFinalCraftingPart = false;
|
||||
foreach($data->getActions() as $networkInventoryAction){
|
||||
$old = TypeConverter::getInstance()->netItemStackToCore($networkInventoryAction->oldItem);
|
||||
$new = TypeConverter::getInstance()->netItemStackToCore($networkInventoryAction->newItem);
|
||||
if(
|
||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER and
|
||||
$networkInventoryAction->windowId === ContainerIds::UI and
|
||||
$networkInventoryAction->inventorySlot === 50 and
|
||||
!$networkInventoryAction->oldItem->equalsExact($networkInventoryAction->newItem)
|
||||
!$old->equalsExact($new)
|
||||
){
|
||||
$isCrafting = true;
|
||||
if(!$networkInventoryAction->oldItem->isNull() and $networkInventoryAction->newItem->isNull()){
|
||||
if(!$old->isNull() and $new->isNull()){
|
||||
$isFinalCraftingPart = true;
|
||||
}
|
||||
}elseif(
|
||||
|
@ -43,6 +43,7 @@ use pocketmine\player\Player;
|
||||
use pocketmine\player\PlayerInfo;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\UUID;
|
||||
use function array_map;
|
||||
use function base64_decode;
|
||||
|
||||
/**
|
||||
|
@ -25,10 +25,10 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\handler\PacketHandler;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
|
||||
class AddItemActorPacket extends DataPacket implements ClientboundPacket{
|
||||
@ -38,7 +38,7 @@ class AddItemActorPacket extends DataPacket implements ClientboundPacket{
|
||||
public $entityUniqueId = null; //TODO
|
||||
/** @var int */
|
||||
public $entityRuntimeId;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $item;
|
||||
/** @var Vector3 */
|
||||
public $position;
|
||||
|
@ -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\handler\PacketHandler;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityLink;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
use pocketmine\utils\UUID;
|
||||
use function count;
|
||||
@ -57,7 +57,7 @@ class AddPlayerPacket extends DataPacket implements ClientboundPacket{
|
||||
public $yaw = 0.0;
|
||||
/** @var float|null */
|
||||
public $headYaw = null; //TODO
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $item;
|
||||
/**
|
||||
* @var MetadataProperty[]
|
||||
|
@ -25,21 +25,17 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\crafting\FurnaceRecipe;
|
||||
use pocketmine\crafting\ShapedRecipe;
|
||||
use pocketmine\crafting\ShapelessRecipe;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\network\BadPacketException;
|
||||
use pocketmine\network\mcpe\handler\PacketHandler;
|
||||
use pocketmine\network\mcpe\protocol\types\PotionContainerChangeRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\PotionTypeRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\MultiRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\RecipeWithTypeId;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\ShapedRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\ShapelessRecipe;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
#ifndef COMPILE
|
||||
use pocketmine\utils\Binary;
|
||||
#endif
|
||||
use function count;
|
||||
use function str_repeat;
|
||||
|
||||
class CraftingDataPacket extends DataPacket implements ClientboundPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::CRAFTING_DATA_PACKET;
|
||||
@ -48,12 +44,12 @@ class CraftingDataPacket extends DataPacket implements ClientboundPacket{
|
||||
public const ENTRY_SHAPED = 1;
|
||||
public const ENTRY_FURNACE = 2;
|
||||
public const ENTRY_FURNACE_DATA = 3;
|
||||
public const ENTRY_MULTI = 4; //TODO
|
||||
public const ENTRY_SHULKER_BOX = 5; //TODO
|
||||
public const ENTRY_SHAPELESS_CHEMISTRY = 6; //TODO
|
||||
public const ENTRY_SHAPED_CHEMISTRY = 7; //TODO
|
||||
public const ENTRY_MULTI = 4;
|
||||
public const ENTRY_SHULKER_BOX = 5;
|
||||
public const ENTRY_SHAPELESS_CHEMISTRY = 6;
|
||||
public const ENTRY_SHAPED_CHEMISTRY = 7;
|
||||
|
||||
/** @var object[] */
|
||||
/** @var RecipeWithTypeId[] */
|
||||
public $entries = [];
|
||||
/** @var PotionTypeRecipe[] */
|
||||
public $potionTypeRecipes = [];
|
||||
@ -62,88 +58,31 @@ class CraftingDataPacket extends DataPacket implements ClientboundPacket{
|
||||
/** @var bool */
|
||||
public $cleanRecipes = false;
|
||||
|
||||
/** @var mixed[][] */
|
||||
public $decodedEntries = [];
|
||||
|
||||
protected function decodePayload(NetworkBinaryStream $in) : void{
|
||||
$this->decodedEntries = [];
|
||||
$recipeCount = $in->getUnsignedVarInt();
|
||||
for($i = 0; $i < $recipeCount; ++$i){
|
||||
$entry = [];
|
||||
$entry["type"] = $recipeType = $in->getVarInt();
|
||||
$recipeType = $in->getVarInt();
|
||||
|
||||
switch($recipeType){
|
||||
case self::ENTRY_SHAPELESS:
|
||||
case self::ENTRY_SHULKER_BOX:
|
||||
case self::ENTRY_SHAPELESS_CHEMISTRY:
|
||||
$entry["recipe_id"] = $in->getString();
|
||||
$ingredientCount = $in->getUnsignedVarInt();
|
||||
/** @var Item */
|
||||
$entry["input"] = [];
|
||||
for($j = 0; $j < $ingredientCount; ++$j){
|
||||
$entry["input"][] = $input = $in->getRecipeIngredient();
|
||||
$input->setCount(1); //TODO HACK: they send a useless count field which breaks the PM crafting system because it isn't always 1
|
||||
}
|
||||
$resultCount = $in->getUnsignedVarInt();
|
||||
$entry["output"] = [];
|
||||
for($k = 0; $k < $resultCount; ++$k){
|
||||
$entry["output"][] = $in->getSlot();
|
||||
}
|
||||
$entry["uuid"] = $in->getUUID()->toString();
|
||||
$entry["block"] = $in->getString();
|
||||
$entry["priority"] = $in->getVarInt();
|
||||
|
||||
$this->entries[] = ShapelessRecipe::decode($recipeType, $in);
|
||||
break;
|
||||
case self::ENTRY_SHAPED:
|
||||
case self::ENTRY_SHAPED_CHEMISTRY:
|
||||
$entry["recipe_id"] = $in->getString();
|
||||
$entry["width"] = $in->getVarInt();
|
||||
$entry["height"] = $in->getVarInt();
|
||||
$count = $entry["width"] * $entry["height"];
|
||||
$entry["input"] = [];
|
||||
for($j = 0; $j < $count; ++$j){
|
||||
$entry["input"][] = $input = $in->getRecipeIngredient();
|
||||
$input->setCount(1); //TODO HACK: they send a useless count field which breaks the PM crafting system
|
||||
}
|
||||
$resultCount = $in->getUnsignedVarInt();
|
||||
$entry["output"] = [];
|
||||
for($k = 0; $k < $resultCount; ++$k){
|
||||
$entry["output"][] = $in->getSlot();
|
||||
}
|
||||
$entry["uuid"] = $in->getUUID()->toString();
|
||||
$entry["block"] = $in->getString();
|
||||
$entry["priority"] = $in->getVarInt();
|
||||
|
||||
$this->entries[] = ShapedRecipe::decode($recipeType, $in);
|
||||
break;
|
||||
case self::ENTRY_FURNACE:
|
||||
case self::ENTRY_FURNACE_DATA:
|
||||
$inputId = $in->getVarInt();
|
||||
$inputData = -1;
|
||||
if($recipeType === self::ENTRY_FURNACE_DATA){
|
||||
$inputData = $in->getVarInt();
|
||||
if($inputData === 0x7fff){
|
||||
$inputData = -1;
|
||||
}
|
||||
}
|
||||
try{
|
||||
$entry["input"] = ItemFactory::get($inputId, $inputData);
|
||||
}catch(\InvalidArgumentException $e){
|
||||
throw BadPacketException::wrap($e);
|
||||
}
|
||||
$entry["output"] = $out = $in->getSlot();
|
||||
if($out->getMeta() === 0x7fff){
|
||||
$entry["output"] = ItemFactory::get($out->getId(), 0); //TODO HACK: some 1.12 furnace recipe outputs have wildcard damage values
|
||||
}
|
||||
$entry["block"] = $in->getString();
|
||||
|
||||
$this->entries[] = FurnaceRecipe::decode($recipeType, $in);
|
||||
break;
|
||||
case self::ENTRY_MULTI:
|
||||
$entry["uuid"] = $in->getUUID()->toString();
|
||||
$this->entries[] = MultiRecipe::decode($recipeType, $in);
|
||||
break;
|
||||
default:
|
||||
throw new BadPacketException("Unhandled recipe type $recipeType!"); //do not continue attempting to decode
|
||||
}
|
||||
$this->decodedEntries[] = $entry;
|
||||
}
|
||||
for($i = 0, $count = $in->getUnsignedVarInt(); $i < $count; ++$i){
|
||||
$input = $in->getVarInt();
|
||||
@ -160,105 +99,11 @@ class CraftingDataPacket extends DataPacket implements ClientboundPacket{
|
||||
$this->cleanRecipes = $in->getBool();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $entry
|
||||
*/
|
||||
private static function writeEntry($entry, NetworkBinaryStream $stream, int $pos) : int{
|
||||
if($entry instanceof ShapelessRecipe){
|
||||
return self::writeShapelessRecipe($entry, $stream, $pos);
|
||||
}elseif($entry instanceof ShapedRecipe){
|
||||
return self::writeShapedRecipe($entry, $stream, $pos);
|
||||
}elseif($entry instanceof FurnaceRecipe){
|
||||
return self::writeFurnaceRecipe($entry, $stream);
|
||||
}
|
||||
//TODO: add MultiRecipe
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static function writeShapelessRecipe(ShapelessRecipe $recipe, NetworkBinaryStream $stream, int $pos) : int{
|
||||
$stream->putString(Binary::writeInt($pos)); //some kind of recipe ID, doesn't matter what it is as long as it's unique
|
||||
$stream->putUnsignedVarInt($recipe->getIngredientCount());
|
||||
foreach($recipe->getIngredientList() as $item){
|
||||
$stream->putRecipeIngredient($item);
|
||||
}
|
||||
|
||||
$results = $recipe->getResults();
|
||||
$stream->putUnsignedVarInt(count($results));
|
||||
foreach($results as $item){
|
||||
$stream->putSlot($item);
|
||||
}
|
||||
|
||||
$stream->put(str_repeat("\x00", 16)); //Null UUID
|
||||
$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
|
||||
$stream->putVarInt(50); //TODO: priority
|
||||
|
||||
return CraftingDataPacket::ENTRY_SHAPELESS;
|
||||
}
|
||||
|
||||
private static function writeShapedRecipe(ShapedRecipe $recipe, NetworkBinaryStream $stream, int $pos) : int{
|
||||
$stream->putString(Binary::writeInt($pos)); //some kind of recipe ID, doesn't matter what it is as long as it's unique
|
||||
$stream->putVarInt($recipe->getWidth());
|
||||
$stream->putVarInt($recipe->getHeight());
|
||||
|
||||
for($z = 0; $z < $recipe->getHeight(); ++$z){
|
||||
for($x = 0; $x < $recipe->getWidth(); ++$x){
|
||||
$stream->putRecipeIngredient($recipe->getIngredient($x, $z));
|
||||
}
|
||||
}
|
||||
|
||||
$results = $recipe->getResults();
|
||||
$stream->putUnsignedVarInt(count($results));
|
||||
foreach($results as $item){
|
||||
$stream->putSlot($item);
|
||||
}
|
||||
|
||||
$stream->put(str_repeat("\x00", 16)); //Null UUID
|
||||
$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
|
||||
$stream->putVarInt(50); //TODO: priority
|
||||
|
||||
return CraftingDataPacket::ENTRY_SHAPED;
|
||||
}
|
||||
|
||||
private static function writeFurnaceRecipe(FurnaceRecipe $recipe, NetworkBinaryStream $stream) : int{
|
||||
$stream->putVarInt($recipe->getInput()->getId());
|
||||
$result = CraftingDataPacket::ENTRY_FURNACE;
|
||||
if(!$recipe->getInput()->hasAnyDamageValue()){ //Data recipe
|
||||
$stream->putVarInt($recipe->getInput()->getMeta());
|
||||
$result = CraftingDataPacket::ENTRY_FURNACE_DATA;
|
||||
}
|
||||
$stream->putSlot($recipe->getResult());
|
||||
$stream->putString("furnace"); //TODO: blocktype (no prefix) (this might require internal API breaks)
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function addShapelessRecipe(ShapelessRecipe $recipe) : void{
|
||||
$this->entries[] = $recipe;
|
||||
}
|
||||
|
||||
public function addShapedRecipe(ShapedRecipe $recipe) : void{
|
||||
$this->entries[] = $recipe;
|
||||
}
|
||||
|
||||
public function addFurnaceRecipe(FurnaceRecipe $recipe) : void{
|
||||
$this->entries[] = $recipe;
|
||||
}
|
||||
|
||||
protected function encodePayload(NetworkBinaryStream $out) : void{
|
||||
$out->putUnsignedVarInt(count($this->entries));
|
||||
|
||||
$writer = new NetworkBinaryStream();
|
||||
$counter = 0;
|
||||
foreach($this->entries as $d){
|
||||
$entryType = self::writeEntry($d, $writer, $counter++);
|
||||
if($entryType >= 0){
|
||||
$out->putVarInt($entryType);
|
||||
$out->put($writer->getBuffer());
|
||||
}else{
|
||||
$out->putVarInt(-1);
|
||||
}
|
||||
|
||||
$writer->reset();
|
||||
$out->putVarInt($d->getTypeId());
|
||||
$d->encode($out);
|
||||
}
|
||||
$out->putUnsignedVarInt(count($this->potionTypeRecipes));
|
||||
foreach($this->potionTypeRecipes as $recipe){
|
||||
|
@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\handler\PacketHandler;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
use pocketmine\utils\UUID;
|
||||
use function count;
|
||||
@ -40,9 +40,9 @@ class CraftingEventPacket extends DataPacket implements ServerboundPacket{
|
||||
public $type;
|
||||
/** @var UUID */
|
||||
public $id;
|
||||
/** @var Item[] */
|
||||
/** @var ItemStack[] */
|
||||
public $input = [];
|
||||
/** @var Item[] */
|
||||
/** @var ItemStack[] */
|
||||
public $output = [];
|
||||
|
||||
protected function decodePayload(NetworkBinaryStream $in) : void{
|
||||
|
@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\handler\PacketHandler;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
use function count;
|
||||
|
||||
@ -35,11 +35,11 @@ class InventoryContentPacket extends DataPacket implements ClientboundPacket{
|
||||
|
||||
/** @var int */
|
||||
public $windowId;
|
||||
/** @var Item[] */
|
||||
/** @var ItemStack[] */
|
||||
public $items = [];
|
||||
|
||||
/**
|
||||
* @param Item[] $items
|
||||
* @param ItemStack[] $items
|
||||
*
|
||||
* @return InventoryContentPacket
|
||||
*/
|
||||
|
@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\handler\PacketHandler;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
|
||||
class InventorySlotPacket extends DataPacket implements ClientboundPacket{
|
||||
@ -36,14 +36,15 @@ class InventorySlotPacket extends DataPacket implements ClientboundPacket{
|
||||
public $windowId;
|
||||
/** @var int */
|
||||
public $inventorySlot;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $item;
|
||||
|
||||
public static function create(int $windowId, int $slot, Item $item) : self{
|
||||
public static function create(int $windowId, int $slot, ItemStack $item) : self{
|
||||
$result = new self;
|
||||
$result->inventorySlot = $slot;
|
||||
$result->item = $item;
|
||||
$result->windowId = $windowId;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\handler\PacketHandler;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
|
||||
class MobArmorEquipmentPacket extends DataPacket implements ClientboundPacket, ServerboundPacket{
|
||||
@ -37,22 +37,23 @@ class MobArmorEquipmentPacket extends DataPacket implements ClientboundPacket, S
|
||||
|
||||
//this intentionally doesn't use an array because we don't want any implicit dependencies on internal order
|
||||
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $head;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $chest;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $legs;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $feet;
|
||||
|
||||
public static function create(int $entityRuntimeId, Item $head, Item $chest, Item $legs, Item $feet) : self{
|
||||
public static function create(int $entityRuntimeId, ItemStack $head, ItemStack $chest, ItemStack $legs, ItemStack $feet) : self{
|
||||
$result = new self;
|
||||
$result->entityRuntimeId = $entityRuntimeId;
|
||||
$result->head = $head;
|
||||
$result->chest = $chest;
|
||||
$result->legs = $legs;
|
||||
$result->feet = $feet;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\handler\PacketHandler;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
|
||||
class MobEquipmentPacket extends DataPacket implements ClientboundPacket, ServerboundPacket{
|
||||
@ -34,7 +34,7 @@ class MobEquipmentPacket extends DataPacket implements ClientboundPacket, Server
|
||||
|
||||
/** @var int */
|
||||
public $entityRuntimeId;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $item;
|
||||
/** @var int */
|
||||
public $inventorySlot;
|
||||
@ -43,7 +43,7 @@ class MobEquipmentPacket extends DataPacket implements ClientboundPacket, Server
|
||||
/** @var int */
|
||||
public $windowId = 0;
|
||||
|
||||
public static function create(int $entityRuntimeId, Item $item, int $inventorySlot, int $windowId) : self{
|
||||
public static function create(int $entityRuntimeId, ItemStack $item, int $inventorySlot, int $windowId) : self{
|
||||
$result = new self;
|
||||
$result->entityRuntimeId = $entityRuntimeId;
|
||||
$result->item = $item;
|
||||
|
100
src/network/mcpe/protocol/types/inventory/ItemStack.php
Normal file
100
src/network/mcpe/protocol/types/inventory/ItemStack.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?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\inventory;
|
||||
|
||||
use pocketmine\item\ItemIds;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
|
||||
final class ItemStack{
|
||||
|
||||
/** @var int */
|
||||
private $id;
|
||||
/** @var int */
|
||||
private $meta;
|
||||
/** @var int */
|
||||
private $count;
|
||||
/** @var string[] */
|
||||
private $canPlaceOn;
|
||||
/** @var string[] */
|
||||
private $canDestroy;
|
||||
/** @var CompoundTag|null */
|
||||
private $nbt;
|
||||
/** @var int|null */
|
||||
private $shieldBlockingTick;
|
||||
|
||||
/**
|
||||
* @param string[] $canPlaceOn
|
||||
* @param string[] $canDestroy
|
||||
*/
|
||||
public function __construct(int $id, int $meta, int $count, ?CompoundTag $nbt, array $canPlaceOn, array $canDestroy, ?int $shieldBlockingTick = null){
|
||||
if(($shieldBlockingTick !== null) !== ($id === ItemIds::SHIELD)){
|
||||
throw new \InvalidArgumentException("Blocking tick must only be provided for shield items");
|
||||
}
|
||||
$this->id = $id;
|
||||
$this->meta = $meta;
|
||||
$this->count = $count;
|
||||
$this->canPlaceOn = $canPlaceOn;
|
||||
$this->canDestroy = $canDestroy;
|
||||
$this->nbt = $nbt;
|
||||
$this->shieldBlockingTick = $shieldBlockingTick;
|
||||
}
|
||||
|
||||
public static function null() : self{
|
||||
return new self(0, 0, 0, null, [], [], null);
|
||||
}
|
||||
|
||||
public function getId() : int{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getMeta() : int{
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
public function getCount() : int{
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getCanPlaceOn() : array{
|
||||
return $this->canPlaceOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getCanDestroy() : array{
|
||||
return $this->canDestroy;
|
||||
}
|
||||
|
||||
public function getNbt() : ?CompoundTag{
|
||||
return $this->nbt;
|
||||
}
|
||||
|
||||
public function getShieldBlockingTick() : ?int{
|
||||
return $this->shieldBlockingTick;
|
||||
}
|
||||
}
|
@ -31,8 +31,8 @@ use pocketmine\inventory\transaction\action\DestroyItemAction;
|
||||
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\BadPacketException;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\BinaryDataException;
|
||||
@ -82,9 +82,9 @@ class NetworkInventoryAction{
|
||||
public $sourceFlags = 0;
|
||||
/** @var int */
|
||||
public $inventorySlot;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $oldItem;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
public $newItem;
|
||||
|
||||
/**
|
||||
@ -150,7 +150,9 @@ class NetworkInventoryAction{
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
public function createInventoryAction(Player $player) : ?InventoryAction{
|
||||
if($this->oldItem->equalsExact($this->newItem)){
|
||||
$old = TypeConverter::getInstance()->netItemStackToCore($this->oldItem);
|
||||
$new = TypeConverter::getInstance()->netItemStackToCore($this->newItem);
|
||||
if($old->equalsExact($new)){
|
||||
//filter out useless noise in 1.13
|
||||
return null;
|
||||
}
|
||||
@ -180,7 +182,7 @@ class NetworkInventoryAction{
|
||||
$slot = $this->inventorySlot;
|
||||
}
|
||||
if($window !== null){
|
||||
return new SlotChangeAction($window, $slot, $this->oldItem, $this->newItem);
|
||||
return new SlotChangeAction($window, $slot, $old, $new);
|
||||
}
|
||||
|
||||
throw new \UnexpectedValueException("No open container with window ID $this->windowId");
|
||||
@ -189,13 +191,13 @@ class NetworkInventoryAction{
|
||||
throw new \UnexpectedValueException("Only expecting drop-item world actions from the client!");
|
||||
}
|
||||
|
||||
return new DropItemAction($this->newItem);
|
||||
return new DropItemAction($new);
|
||||
case self::SOURCE_CREATIVE:
|
||||
switch($this->inventorySlot){
|
||||
case self::ACTION_MAGIC_SLOT_CREATIVE_DELETE_ITEM:
|
||||
return new DestroyItemAction($this->newItem);
|
||||
return new DestroyItemAction($new);
|
||||
case self::ACTION_MAGIC_SLOT_CREATIVE_CREATE_ITEM:
|
||||
return new CreateItemAction($this->oldItem);
|
||||
return new CreateItemAction($new);
|
||||
default:
|
||||
throw new \UnexpectedValueException("Unexpected creative action type $this->inventorySlot");
|
||||
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
@ -36,7 +35,7 @@ class ReleaseItemTransactionData extends TransactionData{
|
||||
private $actionType;
|
||||
/** @var int */
|
||||
private $hotbarSlot;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
private $itemInHand;
|
||||
/** @var Vector3 */
|
||||
private $headPos;
|
||||
@ -49,7 +48,7 @@ class ReleaseItemTransactionData extends TransactionData{
|
||||
return $this->hotbarSlot;
|
||||
}
|
||||
|
||||
public function getItemInHand() : Item{
|
||||
public function getItemInHand() : ItemStack{
|
||||
return $this->itemInHand;
|
||||
}
|
||||
|
||||
@ -78,13 +77,14 @@ class ReleaseItemTransactionData extends TransactionData{
|
||||
/**
|
||||
* @param NetworkInventoryAction[] $actions
|
||||
*/
|
||||
public static function new(array $actions, int $actionType, int $hotbarSlot, Item $itemInHand, Vector3 $headPos) : self{
|
||||
public static function new(array $actions, int $actionType, int $hotbarSlot, ItemStack $itemInHand, Vector3 $headPos) : self{
|
||||
$result = new self;
|
||||
$result->actions = $actions;
|
||||
$result->actionType = $actionType;
|
||||
$result->hotbarSlot = $hotbarSlot;
|
||||
$result->itemInHand = $itemInHand;
|
||||
$result->headPos = $headPos;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
@ -38,7 +37,7 @@ class UseItemOnEntityTransactionData extends TransactionData{
|
||||
private $actionType;
|
||||
/** @var int */
|
||||
private $hotbarSlot;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
private $itemInHand;
|
||||
/** @var Vector3 */
|
||||
private $playerPos;
|
||||
@ -57,7 +56,7 @@ class UseItemOnEntityTransactionData extends TransactionData{
|
||||
return $this->hotbarSlot;
|
||||
}
|
||||
|
||||
public function getItemInHand() : Item{
|
||||
public function getItemInHand() : ItemStack{
|
||||
return $this->itemInHand;
|
||||
}
|
||||
|
||||
@ -94,7 +93,7 @@ class UseItemOnEntityTransactionData extends TransactionData{
|
||||
/**
|
||||
* @param NetworkInventoryAction[] $actions
|
||||
*/
|
||||
public static function new(array $actions, int $entityRuntimeId, int $actionType, int $hotbarSlot, Item $itemInHand, Vector3 $playerPos, Vector3 $clickPos) : self{
|
||||
public static function new(array $actions, int $entityRuntimeId, int $actionType, int $hotbarSlot, ItemStack $itemInHand, Vector3 $playerPos, Vector3 $clickPos) : self{
|
||||
$result = new self;
|
||||
$result->actions = $actions;
|
||||
$result->entityRuntimeId = $entityRuntimeId;
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
@ -41,7 +40,7 @@ class UseItemTransactionData extends TransactionData{
|
||||
private $face;
|
||||
/** @var int */
|
||||
private $hotbarSlot;
|
||||
/** @var Item */
|
||||
/** @var ItemStack */
|
||||
private $itemInHand;
|
||||
/** @var Vector3 */
|
||||
private $playerPos;
|
||||
@ -66,7 +65,7 @@ class UseItemTransactionData extends TransactionData{
|
||||
return $this->hotbarSlot;
|
||||
}
|
||||
|
||||
public function getItemInHand() : Item{
|
||||
public function getItemInHand() : ItemStack{
|
||||
return $this->itemInHand;
|
||||
}
|
||||
|
||||
@ -112,7 +111,7 @@ class UseItemTransactionData extends TransactionData{
|
||||
/**
|
||||
* @param NetworkInventoryAction[] $actions
|
||||
*/
|
||||
public static function new(array $actions, int $actionType, Vector3 $blockPos, int $face, int $hotbarSlot, Item $itemInHand, Vector3 $playerPos, Vector3 $clickPos, int $blockRuntimeId) : self{
|
||||
public static function new(array $actions, int $actionType, Vector3 $blockPos, int $face, int $hotbarSlot, ItemStack $itemInHand, Vector3 $playerPos, Vector3 $clickPos, int $blockRuntimeId) : self{
|
||||
$result = new self;
|
||||
$result->actions = $actions;
|
||||
$result->actionType = $actionType;
|
||||
|
85
src/network/mcpe/protocol/types/recipe/FurnaceRecipe.php
Normal file
85
src/network/mcpe/protocol/types/recipe/FurnaceRecipe.php
Normal 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\network\mcpe\protocol\types\recipe;
|
||||
|
||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
|
||||
final class FurnaceRecipe extends RecipeWithTypeId{
|
||||
|
||||
/** @var int */
|
||||
private $inputId;
|
||||
/** @var int|null */
|
||||
private $inputMeta;
|
||||
/** @var ItemStack */
|
||||
private $result;
|
||||
/** @var string */
|
||||
private $blockName;
|
||||
|
||||
public function __construct(int $typeId, int $inputId, ?int $inputMeta, ItemStack $result, string $blockName){
|
||||
parent::__construct($typeId);
|
||||
$this->inputId = $inputId;
|
||||
$this->inputMeta = $inputMeta;
|
||||
$this->result = $result;
|
||||
$this->blockName = $blockName;
|
||||
}
|
||||
|
||||
public function getInputId() : int{
|
||||
return $this->inputId;
|
||||
}
|
||||
|
||||
public function getInputMeta() : ?int{
|
||||
return $this->inputMeta;
|
||||
}
|
||||
|
||||
public function getResult() : ItemStack{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
public function getBlockName() : string{
|
||||
return $this->blockName;
|
||||
}
|
||||
|
||||
public static function decode(int $typeId, NetworkBinaryStream $in) : self{
|
||||
$inputId = $in->getVarInt();
|
||||
$inputData = null;
|
||||
if($typeId === CraftingDataPacket::ENTRY_FURNACE_DATA){
|
||||
$inputData = $in->getVarInt();
|
||||
}
|
||||
$output = $in->getSlot();
|
||||
$block = $in->getString();
|
||||
|
||||
return new self($typeId, $inputId, $inputData, $output, $block);
|
||||
}
|
||||
|
||||
public function encode(NetworkBinaryStream $out) : void{
|
||||
$out->putVarInt($this->inputId);
|
||||
if($this->getTypeId() === CraftingDataPacket::ENTRY_FURNACE_DATA){
|
||||
$out->putVarInt($this->inputMeta);
|
||||
}
|
||||
$out->putSlot($this->result);
|
||||
$out->putString($this->blockName);
|
||||
}
|
||||
}
|
50
src/network/mcpe/protocol/types/recipe/MultiRecipe.php
Normal file
50
src/network/mcpe/protocol/types/recipe/MultiRecipe.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?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\recipe;
|
||||
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
final class MultiRecipe extends RecipeWithTypeId{
|
||||
|
||||
/** @var UUID */
|
||||
private $recipeId;
|
||||
|
||||
public function __construct(int $typeId, UUID $recipeId){
|
||||
parent::__construct($typeId);
|
||||
$this->recipeId = $recipeId;
|
||||
}
|
||||
|
||||
public function getRecipeId() : UUID{
|
||||
return $this->recipeId;
|
||||
}
|
||||
|
||||
public static function decode(int $typeId, NetworkBinaryStream $in) : self{
|
||||
return new self($typeId, $in->getUUID());
|
||||
}
|
||||
|
||||
public function encode(NetworkBinaryStream $out) : void{
|
||||
$out->putUUID($this->recipeId);
|
||||
}
|
||||
}
|
52
src/network/mcpe/protocol/types/recipe/RecipeIngredient.php
Normal file
52
src/network/mcpe/protocol/types/recipe/RecipeIngredient.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?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\recipe;
|
||||
|
||||
final class RecipeIngredient{
|
||||
|
||||
/** @var int */
|
||||
private $id;
|
||||
/** @var int */
|
||||
private $meta;
|
||||
/** @var int */
|
||||
private $count;
|
||||
|
||||
public function __construct(int $id, int $meta, int $count){
|
||||
$this->id = $id;
|
||||
$this->meta = $meta;
|
||||
$this->count = $count;
|
||||
}
|
||||
|
||||
public function getId() : int{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getMeta() : int{
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
public function getCount() : int{
|
||||
return $this->count;
|
||||
}
|
||||
}
|
41
src/network/mcpe/protocol/types/recipe/RecipeWithTypeId.php
Normal file
41
src/network/mcpe/protocol/types/recipe/RecipeWithTypeId.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?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\recipe;
|
||||
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
|
||||
abstract class RecipeWithTypeId{
|
||||
/** @var int */
|
||||
private $typeId;
|
||||
|
||||
protected function __construct(int $typeId){
|
||||
$this->typeId = $typeId;
|
||||
}
|
||||
|
||||
final public function getTypeId() : int{
|
||||
return $this->typeId;
|
||||
}
|
||||
|
||||
abstract public function encode(NetworkBinaryStream $out) : void;
|
||||
}
|
151
src/network/mcpe/protocol/types/recipe/ShapedRecipe.php
Normal file
151
src/network/mcpe/protocol/types/recipe/ShapedRecipe.php
Normal file
@ -0,0 +1,151 @@
|
||||
<?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\recipe;
|
||||
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
use pocketmine\utils\UUID;
|
||||
use function count;
|
||||
|
||||
final class ShapedRecipe extends RecipeWithTypeId{
|
||||
|
||||
/** @var string */
|
||||
private $recipeId;
|
||||
/** @var RecipeIngredient[][] */
|
||||
private $input;
|
||||
/** @var ItemStack[] */
|
||||
private $output;
|
||||
/** @var UUID */
|
||||
private $uuid;
|
||||
/** @var string */
|
||||
private $blockName;
|
||||
/** @var int */
|
||||
private $priority;
|
||||
|
||||
/**
|
||||
* @param RecipeIngredient[][] $input
|
||||
* @param ItemStack[] $output
|
||||
*/
|
||||
public function __construct(int $typeId, string $recipeId, array $input, array $output, UUID $uuid, string $blockType, int $priority){
|
||||
parent::__construct($typeId);
|
||||
$rows = count($input);
|
||||
if($rows < 1 or $rows > 3){
|
||||
throw new \InvalidArgumentException("Expected 1, 2 or 3 input rows");
|
||||
}
|
||||
$columns = null;
|
||||
foreach($input as $rowNumber => $row){
|
||||
if($columns === null){
|
||||
$columns = count($row);
|
||||
}elseif(count($row) !== $columns){
|
||||
throw new \InvalidArgumentException("Expected each row to be $columns columns, but have " . count($row) . " in row $rowNumber");
|
||||
}
|
||||
}
|
||||
$this->recipeId = $recipeId;
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
$this->blockName = $blockType;
|
||||
$this->priority = $priority;
|
||||
$this->uuid = $uuid;
|
||||
}
|
||||
|
||||
public function getRecipeId() : string{
|
||||
return $this->recipeId;
|
||||
}
|
||||
|
||||
public function getWidth() : int{
|
||||
return count($this->input[0]);
|
||||
}
|
||||
|
||||
public function getHeight() : int{
|
||||
return count($this->input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RecipeIngredient[][]
|
||||
*/
|
||||
public function getInput() : array{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ItemStack[]
|
||||
*/
|
||||
public function getOutput() : array{
|
||||
return $this->output;
|
||||
}
|
||||
|
||||
public function getUuid() : UUID{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
public function getBlockName() : string{
|
||||
return $this->blockName;
|
||||
}
|
||||
|
||||
public function getPriority() : int{
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
public static function decode(int $recipeType, NetworkBinaryStream $in) : self{
|
||||
$recipeId = $in->getString();
|
||||
$width = $in->getVarInt();
|
||||
$height = $in->getVarInt();
|
||||
$input = [];
|
||||
for($row = 0; $row < $height; ++$row){
|
||||
for($column = 0; $column < $width; ++$column){
|
||||
$input[$row][$column] = $in->getRecipeIngredient();
|
||||
}
|
||||
}
|
||||
|
||||
$output = [];
|
||||
for($k = 0, $resultCount = $in->getUnsignedVarInt(); $k < $resultCount; ++$k){
|
||||
$output[] = $in->getSlot();
|
||||
}
|
||||
$uuid = $in->getUUID();
|
||||
$block = $in->getString();
|
||||
$priority = $in->getVarInt();
|
||||
|
||||
return new self($recipeType, $recipeId, $input, $output, $uuid, $block, $priority);
|
||||
}
|
||||
|
||||
public function encode(NetworkBinaryStream $out) : void{
|
||||
$out->putString($this->recipeId);
|
||||
$out->putVarInt($this->getWidth());
|
||||
$out->putVarInt($this->getHeight());
|
||||
foreach($this->input as $row){
|
||||
foreach($row as $ingredient){
|
||||
$out->putRecipeIngredient($ingredient);
|
||||
}
|
||||
}
|
||||
|
||||
$out->putUnsignedVarInt(count($this->output));
|
||||
foreach($this->output as $item){
|
||||
$out->putSlot($item);
|
||||
}
|
||||
|
||||
$out->putUUID($this->uuid);
|
||||
$out->putString($this->blockName);
|
||||
$out->putVarInt($this->priority);
|
||||
}
|
||||
}
|
123
src/network/mcpe/protocol/types/recipe/ShapelessRecipe.php
Normal file
123
src/network/mcpe/protocol/types/recipe/ShapelessRecipe.php
Normal file
@ -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\recipe;
|
||||
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\serializer\NetworkBinaryStream;
|
||||
use pocketmine\utils\UUID;
|
||||
use function count;
|
||||
|
||||
final class ShapelessRecipe extends RecipeWithTypeId{
|
||||
|
||||
/** @var string */
|
||||
private $recipeId;
|
||||
/** @var RecipeIngredient[] */
|
||||
private $inputs;
|
||||
/** @var ItemStack[] */
|
||||
private $outputs;
|
||||
/** @var UUID */
|
||||
private $uuid;
|
||||
/** @var string */
|
||||
private $blockName;
|
||||
/** @var int */
|
||||
private $priority;
|
||||
|
||||
/**
|
||||
* @param RecipeIngredient[] $inputs
|
||||
* @param ItemStack[] $outputs
|
||||
*/
|
||||
public function __construct(int $typeId, string $recipeId, array $inputs, array $outputs, UUID $uuid, string $blockName, int $priority){
|
||||
parent::__construct($typeId);
|
||||
$this->recipeId = $recipeId;
|
||||
$this->inputs = $inputs;
|
||||
$this->outputs = $outputs;
|
||||
$this->uuid = $uuid;
|
||||
$this->blockName = $blockName;
|
||||
$this->priority = $priority;
|
||||
}
|
||||
|
||||
public function getRecipeId() : string{
|
||||
return $this->recipeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RecipeIngredient[]
|
||||
*/
|
||||
public function getInputs() : array{
|
||||
return $this->inputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ItemStack[]
|
||||
*/
|
||||
public function getOutputs() : array{
|
||||
return $this->outputs;
|
||||
}
|
||||
|
||||
public function getUuid() : UUID{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
public function getBlockName() : string{
|
||||
return $this->blockName;
|
||||
}
|
||||
|
||||
public function getPriority() : int{
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
public static function decode(int $recipeType, NetworkBinaryStream $in) : self{
|
||||
$recipeId = $in->getString();
|
||||
$input = [];
|
||||
for($j = 0, $ingredientCount = $in->getUnsignedVarInt(); $j < $ingredientCount; ++$j){
|
||||
$input[] = $in->getRecipeIngredient();
|
||||
}
|
||||
$output = [];
|
||||
for($k = 0, $resultCount = $in->getUnsignedVarInt(); $k < $resultCount; ++$k){
|
||||
$output[] = $in->getSlot();
|
||||
}
|
||||
$uuid = $in->getUUID();
|
||||
$block = $in->getString();
|
||||
$priority = $in->getVarInt();
|
||||
|
||||
return new self($recipeType, $recipeId, $input, $output, $uuid, $block, $priority);
|
||||
}
|
||||
|
||||
public function encode(NetworkBinaryStream $out) : void{
|
||||
$out->putString($this->recipeId);
|
||||
$out->putUnsignedVarInt(count($this->inputs));
|
||||
foreach($this->inputs as $item){
|
||||
$out->putRecipeIngredient($item);
|
||||
}
|
||||
|
||||
$out->putUnsignedVarInt(count($this->outputs));
|
||||
foreach($this->outputs as $item){
|
||||
$out->putSlot($item);
|
||||
}
|
||||
|
||||
$out->putUUID($this->uuid);
|
||||
$out->putString($this->blockName);
|
||||
$out->putVarInt($this->priority);
|
||||
}
|
||||
}
|
@ -25,14 +25,10 @@ namespace pocketmine\network\mcpe\serializer;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\ItemIds;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NbtDataException;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\TreeRoot;
|
||||
use pocketmine\network\BadPacketException;
|
||||
use pocketmine\network\mcpe\protocol\types\command\CommandOriginData;
|
||||
@ -48,8 +44,10 @@ use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\ShortMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\Vec3MetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\PersonaPieceTintColor;
|
||||
use pocketmine\network\mcpe\protocol\types\PersonaSkinPiece;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinData;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinImage;
|
||||
@ -63,9 +61,6 @@ use function strlen;
|
||||
|
||||
class NetworkBinaryStream extends BinaryStream{
|
||||
|
||||
private const DAMAGE_TAG = "Damage"; //TAG_Int
|
||||
private const DAMAGE_TAG_CONFLICT_RESOLUTION = "___Damage_ProtocolCollisionResolution___";
|
||||
|
||||
/**
|
||||
* @throws BinaryDataException
|
||||
*/
|
||||
@ -209,15 +204,15 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
* @throws BadPacketException
|
||||
* @throws BinaryDataException
|
||||
*/
|
||||
public function getSlot() : Item{
|
||||
public function getSlot() : ItemStack{
|
||||
$id = $this->getVarInt();
|
||||
if($id === 0){
|
||||
return ItemFactory::get(0, 0, 0);
|
||||
return ItemStack::null();
|
||||
}
|
||||
|
||||
$auxValue = $this->getVarInt();
|
||||
$data = $auxValue >> 8;
|
||||
$cnt = $auxValue & 0xff;
|
||||
$meta = $auxValue >> 8;
|
||||
$count = $auxValue & 0xff;
|
||||
|
||||
$nbtLen = $this->getLShort();
|
||||
|
||||
@ -237,43 +232,25 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
throw new BadPacketException("Unexpected fake NBT length $nbtLen");
|
||||
}
|
||||
|
||||
//TODO
|
||||
for($i = 0, $canPlaceOn = $this->getVarInt(); $i < $canPlaceOn; ++$i){
|
||||
$this->getString();
|
||||
$canPlaceOn = [];
|
||||
for($i = 0, $canPlaceOnCount = $this->getVarInt(); $i < $canPlaceOnCount; ++$i){
|
||||
$canPlaceOn[] = $this->getString();
|
||||
}
|
||||
|
||||
//TODO
|
||||
for($i = 0, $canDestroy = $this->getVarInt(); $i < $canDestroy; ++$i){
|
||||
$this->getString();
|
||||
$canDestroy = [];
|
||||
for($i = 0, $canDestroyCount = $this->getVarInt(); $i < $canDestroyCount; ++$i){
|
||||
$canDestroy[] = $this->getString();
|
||||
}
|
||||
|
||||
$shieldBlockingTick = null;
|
||||
if($id === ItemIds::SHIELD){
|
||||
$this->getVarLong(); //"blocking tick" (ffs mojang)
|
||||
$shieldBlockingTick = $this->getVarLong();
|
||||
}
|
||||
|
||||
if($compound !== null){
|
||||
if($compound->hasTag(self::DAMAGE_TAG, IntTag::class)){
|
||||
$data = $compound->getInt(self::DAMAGE_TAG);
|
||||
$compound->removeTag(self::DAMAGE_TAG);
|
||||
if($compound->count() === 0){
|
||||
$compound = null;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if(($conflicted = $compound->getTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION)) !== null){
|
||||
$compound->removeTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
|
||||
$compound->setTag(self::DAMAGE_TAG, $conflicted);
|
||||
}
|
||||
}
|
||||
end:
|
||||
try{
|
||||
return ItemFactory::get($id, $data, $cnt, $compound);
|
||||
}catch(\InvalidArgumentException $e){
|
||||
throw new BadPacketException($e->getMessage(), 0, $e);
|
||||
}
|
||||
return new ItemStack($id, $meta, $count, $compound, $canPlaceOn, $canDestroy, $shieldBlockingTick);
|
||||
}
|
||||
|
||||
public function putSlot(Item $item) : void{
|
||||
public function putSlot(ItemStack $item) : void{
|
||||
if($item->getId() === 0){
|
||||
$this->putVarInt(0);
|
||||
|
||||
@ -284,22 +261,7 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
$auxValue = (($item->getMeta() & 0x7fff) << 8) | $item->getCount();
|
||||
$this->putVarInt($auxValue);
|
||||
|
||||
$nbt = null;
|
||||
if($item->hasNamedTag()){
|
||||
$nbt = clone $item->getNamedTag();
|
||||
}
|
||||
if($item instanceof Durable and $item->getDamage() > 0){
|
||||
if($nbt !== null){
|
||||
if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){
|
||||
$nbt->removeTag(self::DAMAGE_TAG);
|
||||
$nbt->setTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION, $existing);
|
||||
}
|
||||
}else{
|
||||
$nbt = new CompoundTag();
|
||||
}
|
||||
$nbt->setInt(self::DAMAGE_TAG, $item->getDamage());
|
||||
}
|
||||
|
||||
$nbt = $item->getNbt();
|
||||
if($nbt !== null){
|
||||
$this->putLShort(0xffff);
|
||||
$this->putByte(1); //TODO: some kind of count field? always 1 as of 1.9.0
|
||||
@ -308,34 +270,39 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
$this->putLShort(0);
|
||||
}
|
||||
|
||||
$this->putVarInt(0); //CanPlaceOn entry count (TODO)
|
||||
$this->putVarInt(0); //CanDestroy entry count (TODO)
|
||||
$this->putVarInt(count($item->getCanPlaceOn()));
|
||||
foreach($item->getCanPlaceOn() as $entry){
|
||||
$this->putString($entry);
|
||||
}
|
||||
$this->putVarInt(count($item->getCanDestroy()));
|
||||
foreach($item->getCanDestroy() as $entry){
|
||||
$this->putString($entry);
|
||||
}
|
||||
|
||||
if($item->getId() === ItemIds::SHIELD){
|
||||
$this->putVarLong(0); //"blocking tick" (ffs mojang)
|
||||
$blockingTick = $item->getShieldBlockingTick();
|
||||
if($blockingTick !== null){
|
||||
$this->putVarLong($blockingTick);
|
||||
}
|
||||
}
|
||||
|
||||
public function getRecipeIngredient() : Item{
|
||||
public function getRecipeIngredient() : RecipeIngredient{
|
||||
$id = $this->getVarInt();
|
||||
if($id === 0){
|
||||
return ItemFactory::get(ItemIds::AIR, 0, 0);
|
||||
return new RecipeIngredient(0, 0, 0);
|
||||
}
|
||||
$meta = $this->getVarInt();
|
||||
if($meta === 0x7fff){
|
||||
$meta = -1;
|
||||
}
|
||||
$count = $this->getVarInt();
|
||||
return ItemFactory::get($id, $meta, $count);
|
||||
|
||||
return new RecipeIngredient($id, $meta, $count);
|
||||
}
|
||||
|
||||
public function putRecipeIngredient(Item $item) : void{
|
||||
if($item->isNull()){
|
||||
public function putRecipeIngredient(RecipeIngredient $ingredient) : void{
|
||||
if($ingredient->getId() === 0){
|
||||
$this->putVarInt(0);
|
||||
}else{
|
||||
$this->putVarInt($item->getId());
|
||||
$this->putVarInt($item->getMeta() & 0x7fff);
|
||||
$this->putVarInt($item->getCount());
|
||||
$this->putVarInt($ingredient->getId());
|
||||
$this->putVarInt($ingredient->getMeta());
|
||||
$this->putVarInt($ingredient->getCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ namespace pocketmine\world\particle;
|
||||
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Skin;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||
@ -34,6 +33,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\LongMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
|
||||
use pocketmine\utils\UUID;
|
||||
@ -100,7 +100,7 @@ class FloatingTextParticle implements Particle{
|
||||
$pk->username = $name;
|
||||
$pk->entityRuntimeId = $this->entityId;
|
||||
$pk->position = $pos; //TODO: check offset
|
||||
$pk->item = ItemFactory::air();
|
||||
$pk->item = ItemStack::null();
|
||||
|
||||
$flags = (
|
||||
1 << EntityMetadataFlags::IMMOBILE
|
||||
|
Loading…
x
Reference in New Issue
Block a user