2017-07-13 10:44:49 +01:00

1079 lines
27 KiB
PHP

<?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);
/**
* All the Item classes
*/
namespace pocketmine\item;
use pocketmine\block\Block;
use pocketmine\entity\Entity;
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;
use pocketmine\nbt\tag\StringTag;
use pocketmine\nbt\tag\Tag;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\utils\Binary;
use pocketmine\utils\Config;
class Item implements ItemIds, \JsonSerializable{
/** @var NBT */
private static $cachedParser = null;
private static function parseCompoundTag(string $tag) : CompoundTag{
if(strlen($tag) === 0){
throw new \InvalidArgumentException("No NBT data found in supplied string");
}
if(self::$cachedParser === null){
self::$cachedParser = new NBT(NBT::LITTLE_ENDIAN);
}
self::$cachedParser->read($tag);
$data = self::$cachedParser->getData();
if(!($data instanceof CompoundTag)){
throw new \InvalidArgumentException("Invalid item NBT string given, it could not be deserialized");
}
return $data;
}
private static function writeCompoundTag(CompoundTag $tag) : string{
if(self::$cachedParser === null){
self::$cachedParser = new NBT(NBT::LITTLE_ENDIAN);
}
self::$cachedParser->setData($tag);
return self::$cachedParser->write();
}
/** @var \SplFixedArray */
public static $list = null;
/** @var Block|null */
protected $block;
/** @var int */
protected $id;
/** @var int */
protected $meta;
/** @var string */
private $tags = "";
/** @var CompoundTag|null */
private $cachedNBT = null;
/** @var int */
public $count;
/** @var string */
protected $name;
public function canBeActivated(){
return false;
}
public static function init(){
if(self::$list === null){
self::$list = new \SplFixedArray(65536);
self::$list[self::IRON_SHOVEL] = IronShovel::class;
self::$list[self::IRON_PICKAXE] = IronPickaxe::class;
self::$list[self::IRON_AXE] = IronAxe::class;
self::$list[self::FLINT_STEEL] = FlintSteel::class;
self::$list[self::APPLE] = Apple::class;
self::$list[self::BOW] = Bow::class;
self::$list[self::ARROW] = Arrow::class;
self::$list[self::COAL] = Coal::class;
self::$list[self::DIAMOND] = Diamond::class;
self::$list[self::IRON_INGOT] = IronIngot::class;
self::$list[self::GOLD_INGOT] = GoldIngot::class;
self::$list[self::IRON_SWORD] = IronSword::class;
self::$list[self::WOODEN_SWORD] = WoodenSword::class;
self::$list[self::WOODEN_SHOVEL] = WoodenShovel::class;
self::$list[self::WOODEN_PICKAXE] = WoodenPickaxe::class;
self::$list[self::WOODEN_AXE] = WoodenAxe::class;
self::$list[self::STONE_SWORD] = StoneSword::class;
self::$list[self::STONE_SHOVEL] = StoneShovel::class;
self::$list[self::STONE_PICKAXE] = StonePickaxe::class;
self::$list[self::STONE_AXE] = StoneAxe::class;
self::$list[self::DIAMOND_SWORD] = DiamondSword::class;
self::$list[self::DIAMOND_SHOVEL] = DiamondShovel::class;
self::$list[self::DIAMOND_PICKAXE] = DiamondPickaxe::class;
self::$list[self::DIAMOND_AXE] = DiamondAxe::class;
self::$list[self::STICK] = Stick::class;
self::$list[self::BOWL] = Bowl::class;
self::$list[self::MUSHROOM_STEW] = MushroomStew::class;
self::$list[self::GOLD_SWORD] = GoldSword::class;
self::$list[self::GOLD_SHOVEL] = GoldShovel::class;
self::$list[self::GOLD_PICKAXE] = GoldPickaxe::class;
self::$list[self::GOLD_AXE] = GoldAxe::class;
self::$list[self::STRING] = StringItem::class;
self::$list[self::FEATHER] = Feather::class;
self::$list[self::GUNPOWDER] = Gunpowder::class;
self::$list[self::WOODEN_HOE] = WoodenHoe::class;
self::$list[self::STONE_HOE] = StoneHoe::class;
self::$list[self::IRON_HOE] = IronHoe::class;
self::$list[self::DIAMOND_HOE] = DiamondHoe::class;
self::$list[self::GOLD_HOE] = GoldHoe::class;
self::$list[self::WHEAT_SEEDS] = WheatSeeds::class;
self::$list[self::WHEAT] = Wheat::class;
self::$list[self::BREAD] = Bread::class;
self::$list[self::LEATHER_CAP] = LeatherCap::class;
self::$list[self::LEATHER_TUNIC] = LeatherTunic::class;
self::$list[self::LEATHER_PANTS] = LeatherPants::class;
self::$list[self::LEATHER_BOOTS] = LeatherBoots::class;
self::$list[self::CHAIN_HELMET] = ChainHelmet::class;
self::$list[self::CHAIN_CHESTPLATE] = ChainChestplate::class;
self::$list[self::CHAIN_LEGGINGS] = ChainLeggings::class;
self::$list[self::CHAIN_BOOTS] = ChainBoots::class;
self::$list[self::IRON_HELMET] = IronHelmet::class;
self::$list[self::IRON_CHESTPLATE] = IronChestplate::class;
self::$list[self::IRON_LEGGINGS] = IronLeggings::class;
self::$list[self::IRON_BOOTS] = IronBoots::class;
self::$list[self::DIAMOND_HELMET] = DiamondHelmet::class;
self::$list[self::DIAMOND_CHESTPLATE] = DiamondChestplate::class;
self::$list[self::DIAMOND_LEGGINGS] = DiamondLeggings::class;
self::$list[self::DIAMOND_BOOTS] = DiamondBoots::class;
self::$list[self::GOLD_HELMET] = GoldHelmet::class;
self::$list[self::GOLD_CHESTPLATE] = GoldChestplate::class;
self::$list[self::GOLD_LEGGINGS] = GoldLeggings::class;
self::$list[self::GOLD_BOOTS] = GoldBoots::class;
self::$list[self::FLINT] = Flint::class;
self::$list[self::RAW_PORKCHOP] = RawPorkchop::class;
self::$list[self::COOKED_PORKCHOP] = CookedPorkchop::class;
self::$list[self::PAINTING] = Painting::class;
self::$list[self::GOLDEN_APPLE] = GoldenApple::class;
self::$list[self::SIGN] = Sign::class;
self::$list[self::WOODEN_DOOR] = WoodenDoor::class;
self::$list[self::BUCKET] = Bucket::class;
self::$list[self::MINECART] = Minecart::class;
self::$list[self::IRON_DOOR] = IronDoor::class;
self::$list[self::REDSTONE] = Redstone::class;
self::$list[self::SNOWBALL] = Snowball::class;
self::$list[self::BOAT] = Boat::class;
self::$list[self::LEATHER] = Leather::class;
self::$list[self::BRICK] = Brick::class;
self::$list[self::CLAY] = Clay::class;
self::$list[self::SUGARCANE] = Sugarcane::class;
self::$list[self::PAPER] = Paper::class;
self::$list[self::BOOK] = Book::class;
self::$list[self::SLIMEBALL] = Slimeball::class;
self::$list[self::EGG] = Egg::class;
self::$list[self::COMPASS] = Compass::class;
self::$list[self::FISHING_ROD] = FishingRod::class;
self::$list[self::CLOCK] = Clock::class;
self::$list[self::GLOWSTONE_DUST] = GlowstoneDust::class;
self::$list[self::RAW_FISH] = Fish::class;
self::$list[self::COOKED_FISH] = CookedFish::class;
self::$list[self::DYE] = Dye::class;
self::$list[self::BONE] = Bone::class;
self::$list[self::SUGAR] = Sugar::class;
self::$list[self::CAKE] = Cake::class;
self::$list[self::BED] = Bed::class;
self::$list[self::COOKIE] = Cookie::class;
self::$list[self::SHEARS] = Shears::class;
self::$list[self::MELON] = Melon::class;
self::$list[self::PUMPKIN_SEEDS] = PumpkinSeeds::class;
self::$list[self::MELON_SEEDS] = MelonSeeds::class;
self::$list[self::RAW_BEEF] = RawBeef::class;
self::$list[self::STEAK] = Steak::class;
self::$list[self::RAW_CHICKEN] = RawChicken::class;
self::$list[self::COOKED_CHICKEN] = CookedChicken::class;
self::$list[self::GOLD_NUGGET] = GoldNugget::class;
self::$list[self::NETHER_WART] = NetherWart::class;
self::$list[self::POTION] = Potion::class;
self::$list[self::GLASS_BOTTLE] = GlassBottle::class;
self::$list[self::SPIDER_EYE] = SpiderEye::class;
self::$list[self::FERMENTED_SPIDER_EYE] = FermentedSpiderEye::class;
self::$list[self::BLAZE_POWDER] = BlazePowder::class;
self::$list[self::MAGMA_CREAM] = MagmaCream::class;
self::$list[self::BREWING_STAND] = BrewingStand::class;
self::$list[self::GLISTERING_MELON] = GlisteringMelon::class;
self::$list[self::SPAWN_EGG] = SpawnEgg::class;
self::$list[self::EMERALD] = Emerald::class;
self::$list[self::ITEM_FRAME] = ItemFrame::class;
self::$list[self::FLOWER_POT] = FlowerPot::class;
self::$list[self::CARROT] = Carrot::class;
self::$list[self::POTATO] = Potato::class;
self::$list[self::BAKED_POTATO] = BakedPotato::class;
self::$list[self::GOLDEN_CARROT] = GoldenCarrot::class;
self::$list[self::MOB_HEAD] = MobHead::class;
self::$list[self::PUMPKIN_PIE] = PumpkinPie::class;
self::$list[self::NETHER_BRICK] = NetherBrick::class;
self::$list[self::QUARTZ] = Quartz::class;
self::$list[self::QUARTZ] = NetherQuartz::class;
self::$list[self::COOKED_RABBIT] = CookedRabbit::class;
// self::$list[self::CAMERA] = Camera::class;
self::$list[self::BEETROOT] = Beetroot::class;
self::$list[self::BEETROOT_SEEDS] = BeetrootSeeds::class;
self::$list[self::BEETROOT_SOUP] = BeetrootSoup::class;
self::$list[self::PRISMARINE_CRYSTALS] = PrismarineCrystals::class;
self::$list[self::PRISMARINE_SHARD] = PrismarineShard::class;
self::$list[self::NETHER_STAR] = NetherStar::class;
self::$list[self::ENCHANTED_GOLDEN_APPLE] = GoldenAppleEnchanted::class;
for($i = 0; $i < 256; ++$i){
if(Block::$list[$i] !== null){
self::$list[$i] = Block::$list[$i];
}
}
}
self::initCreativeItems();
}
private static $creative = [];
private static function initCreativeItems(){
self::clearCreativeItems();
$creativeItems = new Config(Server::getInstance()->getFilePath() . "src/pocketmine/resources/creativeitems.json", Config::JSON, []);
foreach($creativeItems->getAll() as $data){
$item = Item::get($data["id"], $data["damage"], $data["count"], $data["nbt"]);
if($item->getName() === "Unknown"){
continue;
}
self::addCreativeItem($item);
}
}
public static function clearCreativeItems(){
Item::$creative = [];
}
public static function getCreativeItems() : array{
return Item::$creative;
}
public static function addCreativeItem(Item $item){
Item::$creative[] = clone $item;
}
public static function removeCreativeItem(Item $item){
$index = self::getCreativeItemIndex($item);
if($index !== -1){
unset(Item::$creative[$index]);
}
}
public static function isCreativeItem(Item $item) : bool{
foreach(Item::$creative as $i => $d){
if($item->equals($d, !$item->isTool())){
return true;
}
}
return false;
}
/**
* @param $index
*
* @return Item|null
*/
public static function getCreativeItem(int $index){
return Item::$creative[$index] ?? null;
}
public static function getCreativeItemIndex(Item $item) : int{
foreach(Item::$creative as $i => $d){
if($item->equals($d, !$item->isTool())){
return $i;
}
}
return -1;
}
/**
* Returns an instance of the Item with the specified id, meta, count and NBT.
*
* @param int $id
* @param int $meta
* @param int $count
* @param CompoundTag|string $tags
*
* @return Item
*/
public static function get(int $id, int $meta = 0, int $count = 1, $tags = "") : Item{
try{
$class = self::$list[$id];
if($class === null){
return (new Item($id, $meta, $count))->setCompoundTag($tags);
}elseif($id < 256){
return (new ItemBlock(new $class($meta), $meta, $count))->setCompoundTag($tags);
}else{
return (new $class($meta, $count))->setCompoundTag($tags);
}
}catch(\RuntimeException $e){
return (new Item($id, $meta, $count))->setCompoundTag($tags);
}
}
/**
* @param string $str
* @param bool $multiple
*
* @return Item[]|Item
*/
public static function fromString(string $str, bool $multiple = false){
if($multiple === true){
$blocks = [];
foreach(explode(",", $str) as $b){
$blocks[] = self::fromString($b, false);
}
return $blocks;
}else{
$b = explode(":", str_replace([" ", "minecraft:"], ["_", ""], trim($str)));
if(!isset($b[1])){
$meta = 0;
}else{
$meta = $b[1] & 0xFFFF;
}
if(defined(Item::class . "::" . strtoupper($b[0]))){
$item = self::get(constant(Item::class . "::" . strtoupper($b[0])), $meta);
if($item->getId() === self::AIR and strtoupper($b[0]) !== "AIR"){
$item = self::get($b[0] & 0xFFFF, $meta);
}
}else{
$item = self::get($b[0] & 0xFFFF, $meta);
}
return $item;
}
}
/**
* @param int $id
* @param int $meta
* @param int $count
* @param string $name
*/
public function __construct(int $id, int $meta = 0, int $count = 1, string $name = "Unknown"){
$this->id = $id & 0xffff;
$this->meta = $meta !== -1 ? $meta & 0xffff : -1;
$this->count = $count;
$this->name = $name;
if(!isset($this->block) and $this->id <= 0xff and isset(Block::$list[$this->id])){
$this->block = Block::get($this->id, $this->meta);
$this->name = $this->block->getName();
}
}
/**
* Sets the Item's NBT
*
* @param CompoundTag|string $tags
*
* @return $this
*/
public function setCompoundTag($tags){
if($tags instanceof CompoundTag){
$this->setNamedTag($tags);
}else{
$this->tags = (string) $tags;
$this->cachedNBT = null;
}
return $this;
}
/**
* Returns the serialized NBT of the Item
* @return string
*/
public function getCompoundTag() : string{
return $this->tags;
}
/**
* Returns whether this Item has a non-empty NBT.
* @return bool
*/
public function hasCompoundTag() : bool{
return $this->tags !== "";
}
/**
* @return bool
*/
public function hasCustomBlockData() : bool{
if(!$this->hasCompoundTag()){
return false;
}
$tag = $this->getNamedTag();
if(isset($tag->BlockEntityTag) and $tag->BlockEntityTag instanceof CompoundTag){
return true;
}
return false;
}
public function clearCustomBlockData(){
if(!$this->hasCompoundTag()){
return $this;
}
$tag = $this->getNamedTag();
if(isset($tag->BlockEntityTag) and $tag->BlockEntityTag instanceof CompoundTag){
unset($tag->BlockEntityTag);
$this->setNamedTag($tag);
}
return $this;
}
/**
* @param CompoundTag $compound
*
* @return $this
*/
public function setCustomBlockData(CompoundTag $compound){
$tags = clone $compound;
$tags->setName("BlockEntityTag");
if(!$this->hasCompoundTag()){
$tag = new CompoundTag("", []);
}else{
$tag = $this->getNamedTag();
}
$tag->BlockEntityTag = $tags;
$this->setNamedTag($tag);
return $this;
}
/**
* @return CompoundTag|null
*/
public function getCustomBlockData(){
if(!$this->hasCompoundTag()){
return null;
}
$tag = $this->getNamedTag();
if(isset($tag->BlockEntityTag) and $tag->BlockEntityTag instanceof CompoundTag){
return $tag->BlockEntityTag;
}
return null;
}
/**
* @return bool
*/
public function hasEnchantments() : bool{
if(!$this->hasCompoundTag()){
return false;
}
$tag = $this->getNamedTag();
if(isset($tag->ench)){
$tag = $tag->ench;
if($tag instanceof ListTag){
return true;
}
}
return false;
}
/**
* @param int $id
*
* @return Enchantment|null
*/
public function getEnchantment(int $id){
if(!$this->hasEnchantments()){
return null;
}
foreach($this->getNamedTag()->ench as $entry){
if($entry["id"] === $id){
$e = Enchantment::getEnchantment($entry["id"]);
$e->setLevel($entry["lvl"]);
return $e;
}
}
return null;
}
/**
* @param Enchantment $ench
*/
public function addEnchantment(Enchantment $ench){
if(!$this->hasCompoundTag()){
$tag = new CompoundTag("", []);
}else{
$tag = $this->getNamedTag();
}
if(!isset($tag->ench)){
$tag->ench = new ListTag("ench", []);
$tag->ench->setTagType(NBT::TAG_Compound);
}
$found = false;
foreach($tag->ench as $k => $entry){
if($entry["id"] === $ench->getId()){
$tag->ench->{$k} = new CompoundTag("", [
new ShortTag("id", $ench->getId()),
new ShortTag("lvl", $ench->getLevel())
]);
$found = true;
break;
}
}
if(!$found){
$tag->ench->{count($tag->ench) + 1} = new CompoundTag("", [
new ShortTag("id", $ench->getId()),
new ShortTag("lvl", $ench->getLevel())
]);
}
$this->setNamedTag($tag);
}
/**
* @return Enchantment[]
*/
public function getEnchantments() : array{
if(!$this->hasEnchantments()){
return [];
}
$enchantments = [];
foreach($this->getNamedTag()->ench as $entry){
$e = Enchantment::getEnchantment($entry["id"]);
$e->setLevel($entry["lvl"]);
$enchantments[] = $e;
}
return $enchantments;
}
/**
* @return bool
*/
public function hasCustomName() : bool{
if(!$this->hasCompoundTag()){
return false;
}
$tag = $this->getNamedTag();
if(isset($tag->display)){
$tag = $tag->display;
if($tag instanceof CompoundTag and isset($tag->Name) and $tag->Name instanceof StringTag){
return true;
}
}
return false;
}
/**
* @return string
*/
public function getCustomName() : string{
if(!$this->hasCompoundTag()){
return "";
}
$tag = $this->getNamedTag();
if(isset($tag->display)){
$tag = $tag->display;
if($tag instanceof CompoundTag and isset($tag->Name) and $tag->Name instanceof StringTag){
return $tag->Name->getValue();
}
}
return "";
}
/**
* @param string $name
*
* @return $this
*/
public function setCustomName(string $name){
if($name === ""){
$this->clearCustomName();
}
if(!$this->hasCompoundTag()){
$tag = new CompoundTag("", []);
}else{
$tag = $this->getNamedTag();
}
if(isset($tag->display) and $tag->display instanceof CompoundTag){
$tag->display->Name = new StringTag("Name", $name);
}else{
$tag->display = new CompoundTag("display", [
new StringTag("Name", $name)
]);
}
$this->setCompoundTag($tag);
return $this;
}
/**
* @return $this
*/
public function clearCustomName(){
if(!$this->hasCompoundTag()){
return $this;
}
$tag = $this->getNamedTag();
if(isset($tag->display) and $tag->display instanceof CompoundTag){
unset($tag->display->Name);
if($tag->display->getCount() === 0){
unset($tag->display);
}
$this->setNamedTag($tag);
}
return $this;
}
public function getLore() : array{
$tag = $this->getNamedTagEntry("display");
if($tag instanceof CompoundTag and isset($tag->Lore) and $tag->Lore instanceof ListTag){
$lines = [];
foreach($tag->Lore->getValue() as $line){
$lines[] = $line->getValue();
}
return $lines;
}
return [];
}
/**
* @param string[] $lines
*
* @return $this
*/
public function setLore(array $lines){
$tag = $this->getNamedTag() ?? new CompoundTag("", []);
if(!isset($tag->display)){
$tag->display = new CompoundTag("display", []);
}
$tag->display->Lore = new ListTag("Lore");
$tag->display->Lore->setTagType(NBT::TAG_String);
$count = 0;
foreach($lines as $line){
$tag->display->Lore[$count++] = new StringTag("", $line);
}
$this->setNamedTag($tag);
return $this;
}
/**
* @param $name
* @return Tag|null
*/
public function getNamedTagEntry($name){
$tag = $this->getNamedTag();
if($tag !== null){
return $tag->{$name} ?? null;
}
return null;
}
/**
* Returns a tree of Tag objects representing the Item's NBT
* @return null|CompoundTag
*/
public function getNamedTag(){
if(!$this->hasCompoundTag()){
return null;
}elseif($this->cachedNBT !== null){
return $this->cachedNBT;
}
return $this->cachedNBT = self::parseCompoundTag($this->tags);
}
/**
* Sets the Item's NBT from the supplied CompoundTag object.
* @param CompoundTag $tag
*
* @return $this
*/
public function setNamedTag(CompoundTag $tag){
if($tag->getCount() === 0){
return $this->clearNamedTag();
}
$this->cachedNBT = $tag;
$this->tags = self::writeCompoundTag($tag);
return $this;
}
/**
* Removes the Item's NBT.
* @return Item
*/
public function clearNamedTag(){
return $this->setCompoundTag("");
}
/**
* @return int
*/
public function getCount() : int{
return $this->count;
}
/**
* @param int $count
*/
public function setCount(int $count){
$this->count = $count;
}
/**
* Returns the name of the item, or the custom name if it is set.
* @return string
*/
final public function getName() : string{
return $this->hasCustomName() ? $this->getCustomName() : $this->name;
}
/**
* @return bool
*/
final public function canBePlaced() : bool{
return $this->block !== null and $this->block->canBePlaced();
}
/**
* Returns whether an entity can eat or drink this item.
* @return bool
*/
public function canBeConsumed() : bool{
return false;
}
/**
* Returns whether this item can be consumed by the supplied Entity.
* @param Entity $entity
*
* @return bool
*/
public function canBeConsumedBy(Entity $entity) : bool{
return $this->canBeConsumed();
}
/**
* Called when the item is consumed by an Entity.
* @param Entity $entity
*/
public function onConsume(Entity $entity){
}
/**
* Returns the block corresponding to this Item.
* @return Block
*/
public function getBlock() : Block{
if($this->block instanceof Block){
return clone $this->block;
}else{
return Block::get(self::AIR);
}
}
/**
* @return int
*/
final public function getId() : int{
return $this->id;
}
/**
* @return int
*/
final public function getDamage() : int{
return $this->meta;
}
/**
* @param int $meta
*/
public function setDamage(int $meta){
$this->meta = $meta !== -1 ? $meta & 0xFFFF : -1;
}
/**
* Returns whether this item can match any item with an equivalent ID with any meta value.
* Used in crafting recipes which accept multiple variants of the same item, for example crafting tables recipes.
*
* @return bool
*/
public function hasAnyDamageValue() : bool{
return $this->meta === -1;
}
/**
* Returns the highest amount of this item which will fit into one inventory slot.
* @return int
*/
public function getMaxStackSize(){
return 64;
}
final public function getFuelTime(){
if(!isset(Fuel::$duration[$this->id])){
return null;
}
if($this->id !== self::BUCKET or $this->meta === 10){
return Fuel::$duration[$this->id];
}
return null;
}
/**
* @param Entity|Block $object
*
* @return bool
*/
public function useOn($object){
return false;
}
/**
* @return bool
*/
public function isTool(){
return false;
}
/**
* @return int|bool
*/
public function getMaxDurability(){
return false;
}
public function isPickaxe(){
return false;
}
public function isAxe(){
return false;
}
public function isSword(){
return false;
}
public function isShovel(){
return false;
}
public function isHoe(){
return false;
}
public function isShears(){
return false;
}
public function getDestroySpeed(Block $block, Player $player){
return 1;
}
/**
* Called when a player uses this item on a block.
*
* @param Level $level
* @param Player $player
* @param Block $block
* @param Block $target
* @param int $face
* @param float $fx
* @param float $fy
* @param float $fz
*
* @return bool
*/
public function onActivate(Level $level, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
return false;
}
/**
* Compares an Item to this Item and check if they match.
*
* @param Item $item
* @param bool $checkDamage Whether to verify that the damage values match.
* @param bool $checkCompound Whether to verify that the items' NBT match.
*
* @return bool
*/
final public function equals(Item $item, bool $checkDamage = true, bool $checkCompound = true) : bool{
if($this->id === $item->getId() and ($checkDamage === false or $this->getDamage() === $item->getDamage())){
if($checkCompound){
if($item->getCompoundTag() === $this->getCompoundTag()){
return true;
}elseif($this->hasCompoundTag() and $item->hasCompoundTag()){
//Serialized NBT didn't match, check the cached object tree.
return NBT::matchTree($this->getNamedTag(), $item->getNamedTag());
}
}else{
return true;
}
}
return false;
}
/**
* @deprecated Use {@link Item#equals} instead, this method will be removed in the future.
*
* @param Item $item
* @param bool $checkDamage
* @param bool $checkCompound
*
* @return bool
*/
final public function deepEquals(Item $item, bool $checkDamage = true, bool $checkCompound = true) : bool{
return $this->equals($item, $checkDamage, $checkCompound);
}
/**
* @return string
*/
final public function __toString() : string{
return "Item " . $this->name . " (" . $this->id . ":" . ($this->hasAnyDamageValue() ? "?" : $this->meta) . ")x" . $this->count . ($this->hasCompoundTag() ? " tags:0x" . bin2hex($this->getCompoundTag()) : "");
}
/**
* Returns an array of item stack properties that can be serialized to json.
*
* @return array
*/
final public function jsonSerialize(){
return [
"id" => $this->id,
"damage" => $this->meta,
"count" => $this->count, //TODO: separate items and stacks
"nbt" => $this->tags
];
}
/**
* Serializes the item to an NBT CompoundTag
*
* @param int $slot optional, the inventory slot of the item
* @param string $tagName the name to assign to the CompoundTag object
*
* @return CompoundTag
*/
public function nbtSerialize(int $slot = -1, string $tagName = "") : CompoundTag{
$tag = new CompoundTag($tagName, [
new ShortTag("id", $this->id),
new ByteTag("Count", Binary::signByte($this->count)),
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);
}
$count = Binary::unsignByte($tag->Count->getValue());
$meta = isset($tag->Damage) ? $tag->Damage->getValue() : 0;
if($tag->id instanceof ShortTag){
$item = Item::get($tag->id->getValue(), $meta, $count);
}elseif($tag->id instanceof StringTag){ //PC item save format
$item = Item::fromString($tag->id->getValue());
$item->setDamage($meta);
$item->setCount($count);
}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){
$t = clone $tag->tag;
$t->setName("");
$item->setNamedTag($t);
}
return $item;
}
public function __clone(){
if($this->block !== null){
$this->block = clone $this->block;
}
$this->cachedNBT = null;
}
}