diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 0b330117a..f136b97df 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -277,9 +277,9 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ if($item["Slot"] >= 0 and $item["Slot"] < 9){ //Hotbar $this->inventory->setHotbarSlotIndex($item["Slot"], isset($item["TrueSlot"]) ? $item["TrueSlot"] : -1); }elseif($item["Slot"] >= 100 and $item["Slot"] < 104){ //Armor - $this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, NBT::getItemHelper($item)); + $this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, ItemItem::nbtDeserialize($item)); }else{ - $this->inventory->setItem($item["Slot"] - 9, NBT::getItemHelper($item)); + $this->inventory->setItem($item["Slot"] - 9, ItemItem::nbtDeserialize($item)); } } } @@ -407,7 +407,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ if($hotbarSlot !== -1){ $item = $this->inventory->getItem($hotbarSlot); if($item->getId() !== 0 and $item->getCount() > 0){ - $tag = NBT::putItemHelper($item, $slot); + $tag = $item->nbtSerialize($slot); $tag->TrueSlot = new ByteTag("TrueSlot", $hotbarSlot); $this->namedtag->Inventory[$slot] = $tag; @@ -429,14 +429,14 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ //$slotCount = (($this instanceof Player and ($this->gamemode & 0x01) === 1) ? Player::CREATIVE_SLOTS : Player::SURVIVAL_SLOTS) + 9; for($slot = 9; $slot < $slotCount; ++$slot){ $item = $this->inventory->getItem($slot - 9); - $this->namedtag->Inventory[$slot] = NBT::putItemHelper($item, $slot); + $this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot); } //Armor for($slot = 100; $slot < 104; ++$slot){ $item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100); if($item instanceof ItemItem and $item->getId() !== ItemItem::AIR){ - $this->namedtag->Inventory[$slot] = NBT::putItemHelper($item, $slot); + $this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot); } } } diff --git a/src/pocketmine/entity/Item.php b/src/pocketmine/entity/Item.php index 3f1f1b7b3..b2ccc6c4e 100644 --- a/src/pocketmine/entity/Item.php +++ b/src/pocketmine/entity/Item.php @@ -75,7 +75,7 @@ class Item extends Entity{ assert($this->namedtag->Item instanceof CompoundTag); - $this->item = NBT::getItemHelper($this->namedtag->Item); + $this->item = ItemItem::nbtDeserialize($this->namedtag->Item); $this->server->getPluginManager()->callEvent(new ItemSpawnEvent($this)); @@ -160,7 +160,7 @@ class Item extends Entity{ public function saveNBT(){ parent::saveNBT(); - $this->namedtag->Item = NBT::putItemHelper($this->item); + $this->namedtag->Item = $this->item->nbtSerialize(); $this->namedtag->Health = new ShortTag("Health", $this->getHealth()); $this->namedtag->Age = new ShortTag("Age", $this->age); $this->namedtag->PickupDelay = new ShortTag("PickupDelay", $this->pickupDelay); diff --git a/src/pocketmine/item/Item.php b/src/pocketmine/item/Item.php index 04906475a..c04ffad4d 100644 --- a/src/pocketmine/item/Item.php +++ b/src/pocketmine/item/Item.php @@ -30,6 +30,7 @@ use pocketmine\inventory\Fuel; use pocketmine\item\enchantment\Enchantment; use pocketmine\level\Level; use pocketmine\nbt\NBT; +use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ShortTag; @@ -770,4 +771,59 @@ class Item implements ItemIds, \JsonSerializable{ ]; } + /** + * Serializes the item to an NBT CompoundTag + * + * @param int $slot optional, the inventory slot of the item + * + * @return CompoundTag + */ + public function nbtSerialize(int $slot = -1) : CompoundTag{ + $tag = new CompoundTag(null, [ + "id" => new ShortTag("id", $this->id), + "Count" => new ByteTag("Count", $this->count ?? -1), + "Damage" => new ShortTag("Damage", $this->meta), + ]); + + if($this->hasCompoundTag()){ + $tag->tag = clone $this->getNamedTag(); + $tag->tag->setName("tag"); + } + + if($slot !== -1){ + $tag->Slot = new ByteTag("Slot", $slot); + } + + return $tag; + } + + /** + * Deserializes an Item from an NBT CompoundTag + * + * @param CompoundTag $tag + * + * @return Item + */ + public static function nbtDeserialize(CompoundTag $tag) : Item{ + if(!isset($tag->id) or !isset($tag->Count)){ + return Item::get(0); + } + + if($tag->id instanceof ShortTag){ + $item = Item::get($tag->id->getValue(), !isset($tag->Damage) ? 0 : $tag->Damage->getValue(), $tag->Count->getValue()); + }elseif($tag->id instanceof StringTag){ //PC item save format + $item = Item::fromString($tag->id->getValue()); + $item->setDamage(!isset($tag->Damage) ? 0 : $tag->Damage->getValue()); + $item->setCount($tag->Count->getValue()); + }else{ + throw new \InvalidArgumentException("Item CompoundTag ID must be an instance of StringTag or ShortTag, " . get_class($tag->id) . " given"); + } + + if(isset($tag->tag) and $tag->tag instanceof CompoundTag){ + $item->setNamedTag($tag->tag); + } + + return $item; + } + } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index be46f930c..d831fb491 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -1454,7 +1454,7 @@ class Level implements ChunkManager, Metadatable{ */ public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, int $delay = 10){ $motion = $motion === null ? new Vector3(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1) : $motion; - $itemTag = NBT::putItemHelper($item); + $itemTag = $item->nbtSerialize(); $itemTag->setName("Item"); if($item->getId() > 0 and $item->getCount() > 0){ diff --git a/src/pocketmine/nbt/NBT.php b/src/pocketmine/nbt/NBT.php index 510a04767..38e911455 100644 --- a/src/pocketmine/nbt/NBT.php +++ b/src/pocketmine/nbt/NBT.php @@ -24,7 +24,6 @@ */ namespace pocketmine\nbt; -use pocketmine\item\Item; use pocketmine\nbt\tag\ByteArrayTag; use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; @@ -73,57 +72,6 @@ class NBT{ public $endianness; private $data; - - /** - * @param Item $item - * @param int $slot - * @return CompoundTag - */ - public static function putItemHelper(Item $item, $slot = null){ - $tag = new CompoundTag(null, [ - "id" => new ShortTag("id", $item->getId()), - "Count" => new ByteTag("Count", $item->getCount()), - "Damage" => new ShortTag("Damage", $item->getDamage()) - ]); - - if($slot !== null){ - $tag->Slot = new ByteTag("Slot", (int) $slot); - } - - if($item->hasCompoundTag()){ - $tag->tag = clone $item->getNamedTag(); - $tag->tag->setName("tag"); - } - - return $tag; - } - - /** - * @param CompoundTag $tag - * @return Item - */ - public static function getItemHelper(CompoundTag $tag){ - if(!isset($tag->id) or !isset($tag->Count)){ - return Item::get(0); - } - - if($tag->id instanceof ShortTag){ - $item = Item::get($tag->id->getValue(), !isset($tag->Damage) ? 0 : $tag->Damage->getValue(), $tag->Count->getValue()); - }elseif($tag->id instanceof StringTag){ //PC item save format - $item = Item::fromString($tag->id->getValue()); - $item->setDamage(!isset($tag->Damage) ? 0 : $tag->Damage->getValue()); - $item->setCount($tag->Count->getValue()); - }else{ - throw new \InvalidArgumentException("Item CompoundTag ID must be an instance of StringTag or ShortTag, " . get_class($tag->id) . " given"); - } - - if(isset($tag->tag) and $tag->tag instanceof CompoundTag){ - $item->setNamedTag($tag->tag); - } - - return $item; - } - public static function matchList(ListTag $tag1, ListTag $tag2){ if($tag1->getName() !== $tag2->getName() or $tag1->getCount() !== $tag2->getCount()){ return false; diff --git a/src/pocketmine/tile/Chest.php b/src/pocketmine/tile/Chest.php index 5d55d0772..c924482e6 100644 --- a/src/pocketmine/tile/Chest.php +++ b/src/pocketmine/tile/Chest.php @@ -109,7 +109,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ if($i < 0){ return Item::get(Item::AIR, 0, 0); }else{ - return NBT::getItemHelper($this->namedtag->Items[$i]); + return Item::nbtDeserialize($this->namedtag->Items[$i]); } } @@ -124,7 +124,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ public function setItem($index, Item $item){ $i = $this->getSlotIndex($index); - $d = NBT::putItemHelper($item, $index); + $d = $item->nbtSerialize($index); if($item->getId() === Item::AIR or $item->getCount() <= 0){ if($i >= 0){ diff --git a/src/pocketmine/tile/Furnace.php b/src/pocketmine/tile/Furnace.php index ab13208e9..ba7e747e9 100644 --- a/src/pocketmine/tile/Furnace.php +++ b/src/pocketmine/tile/Furnace.php @@ -138,7 +138,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{ if($i < 0){ return Item::get(Item::AIR, 0, 0); }else{ - return NBT::getItemHelper($this->namedtag->Items[$i]); + return Item::nbtDeserialize($this->namedtag->Items[$i]); } } @@ -153,7 +153,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{ public function setItem($index, Item $item){ $i = $this->getSlotIndex($index); - $d = NBT::putItemHelper($item, $index); + $d = $item->nbtSerialize($index); if($item->getId() === Item::AIR or $item->getCount() <= 0){ if($i >= 0){