diff --git a/src/pocketmine/block/StandingBanner.php b/src/pocketmine/block/StandingBanner.php index 8e4ac59e2..88520deb2 100644 --- a/src/pocketmine/block/StandingBanner.php +++ b/src/pocketmine/block/StandingBanner.php @@ -92,8 +92,8 @@ class StandingBanner extends Transparent{ $tile = $this->level->getTile($this); $drop = ItemFactory::get(Item::BANNER, ($tile instanceof TileBanner ? $tile->getBaseColor() : 0)); - if($tile instanceof TileBanner and ($patterns = $tile->namedtag->getListTag(TileBanner::TAG_PATTERNS)) !== null and !$patterns->empty()){ - $drop->setNamedTagEntry($patterns); + if($tile instanceof TileBanner and !($patterns = $tile->getPatterns())->empty()){ + $drop->setNamedTagEntry(clone $patterns); } return [$drop]; diff --git a/src/pocketmine/tile/Banner.php b/src/pocketmine/tile/Banner.php index dde23c8c2..647d8fc08 100644 --- a/src/pocketmine/tile/Banner.php +++ b/src/pocketmine/tile/Banner.php @@ -99,19 +99,30 @@ class Banner extends Spawnable implements Nameable{ public const COLOR_ORANGE = 14; public const COLOR_WHITE = 15; + /** @var int */ + private $baseColor; + /** + * @var ListTag + * TODO: break this down further and remove runtime NBT from here entirely + */ + private $patterns; + public function __construct(Level $level, CompoundTag $nbt){ - if(!$nbt->hasTag(self::TAG_BASE, IntTag::class)){ - $nbt->setInt(self::TAG_BASE, 0); - } - if(!$nbt->hasTag(self::TAG_PATTERNS, ListTag::class)){ - $nbt->setTag(new ListTag(self::TAG_PATTERNS)); - } + $this->baseColor = $nbt->getInt(self::TAG_BASE, self::COLOR_BLACK, true); + $this->patterns = $nbt->getListTag(self::TAG_PATTERNS) ?? new ListTag(self::TAG_PATTERNS); + $nbt->removeTag(self::TAG_BASE, self::TAG_PATTERNS); parent::__construct($level, $nbt); } + public function saveNBT() : void{ + parent::saveNBT(); + $this->namedtag->setInt(self::TAG_BASE, $this->baseColor); + $this->namedtag->setTag($this->patterns); + } + public function addAdditionalSpawnData(CompoundTag $nbt) : void{ - $nbt->setTag($this->namedtag->getTag(self::TAG_PATTERNS)); - $nbt->setTag($this->namedtag->getTag(self::TAG_BASE)); + $nbt->setInt(self::TAG_BASE, $this->baseColor); + $nbt->setTag($this->patterns); $this->addNameSpawnData($nbt); } @@ -121,7 +132,7 @@ class Banner extends Spawnable implements Nameable{ * @return int */ public function getBaseColor() : int{ - return $this->namedtag->getInt(self::TAG_BASE, 0); + return $this->baseColor; } /** @@ -130,7 +141,7 @@ class Banner extends Spawnable implements Nameable{ * @param int $color */ public function setBaseColor(int $color) : void{ - $this->namedtag->setInt(self::TAG_BASE, $color & 0x0f); + $this->baseColor = $color; $this->onChanged(); } @@ -143,15 +154,13 @@ class Banner extends Spawnable implements Nameable{ * @return int ID of pattern. */ public function addPattern(string $pattern, int $color) : int{ - $list = $this->namedtag->getListTag(self::TAG_PATTERNS); - assert($list !== null); - $list->push(new CompoundTag("", [ + $this->patterns->push(new CompoundTag("", [ new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f), new StringTag(self::TAG_PATTERN_NAME, $pattern) ])); $this->onChanged(); - return $list->count() - 1; //Last offset in the list + return $this->patterns->count() - 1; //Last offset in the list } /** @@ -162,7 +171,7 @@ class Banner extends Spawnable implements Nameable{ * @return bool */ public function patternExists(int $patternId) : bool{ - return $this->namedtag->getListTag(self::TAG_PATTERNS)->isset($patternId); + return $this->patterns->isset($patternId); } /** @@ -177,9 +186,7 @@ class Banner extends Spawnable implements Nameable{ return []; } - $list = $this->namedtag->getListTag(self::TAG_PATTERNS); - assert($list instanceof ListTag); - $patternTag = $list->get($patternId); + $patternTag = $this->patterns->get($patternId); assert($patternTag instanceof CompoundTag); return [ @@ -202,10 +209,7 @@ class Banner extends Spawnable implements Nameable{ return false; } - $list = $this->namedtag->getListTag(self::TAG_PATTERNS); - assert($list instanceof ListTag); - - $list->set($patternId, new CompoundTag("", [ + $this->patterns->set($patternId, new CompoundTag("", [ new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f), new StringTag(self::TAG_PATTERN_NAME, $pattern) ])); @@ -226,10 +230,7 @@ class Banner extends Spawnable implements Nameable{ return false; } - $list = $this->namedtag->getListTag(self::TAG_PATTERNS); - if($list !== null){ - $list->remove($patternId); - } + $this->patterns->remove($patternId); $this->onChanged(); return true; @@ -259,7 +260,14 @@ class Banner extends Spawnable implements Nameable{ * @return int */ public function getPatternCount() : int{ - return $this->namedtag->getListTag(self::TAG_PATTERNS)->count(); + return $this->patterns->count(); + } + + /** + * @return ListTag + */ + public function getPatterns() : ListTag{ + return $this->patterns; } protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{ diff --git a/src/pocketmine/tile/Bed.php b/src/pocketmine/tile/Bed.php index 58c1d57a5..ad7694b02 100644 --- a/src/pocketmine/tile/Bed.php +++ b/src/pocketmine/tile/Bed.php @@ -27,34 +27,42 @@ namespace pocketmine\tile; use pocketmine\item\Item; use pocketmine\level\Level; use pocketmine\math\Vector3; -use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\Player; class Bed extends Spawnable{ public const TAG_COLOR = "color"; + /** @var int */ + private $color = 14; //default to old red public function __construct(Level $level, CompoundTag $nbt){ - if(!$nbt->hasTag(self::TAG_COLOR, ByteTag::class)){ //TODO: check PC format - $nbt->setByte(self::TAG_COLOR, 14, true); //default to old red - } + $this->color = $nbt->getByte(self::TAG_COLOR, 14, true); + $nbt->removeTag(self::TAG_COLOR); + parent::__construct($level, $nbt); } public function getColor() : int{ - return $this->namedtag->getByte(self::TAG_COLOR); + return $this->color; } public function setColor(int $color){ - $this->namedtag->setByte(self::TAG_COLOR, $color & 0x0f); + $this->color = $color & 0xf; $this->onChanged(); } public function addAdditionalSpawnData(CompoundTag $nbt) : void{ - $nbt->setTag($this->namedtag->getTag(self::TAG_COLOR)); + $nbt->setByte(self::TAG_COLOR, $this->color); + } + + public function saveNBT() : void{ + parent::saveNBT(); + $this->namedtag->setByte(self::TAG_COLOR, $this->color); } protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{ - $nbt->setByte(self::TAG_COLOR, $item !== null ? $item->getDamage() : 14); //default red + if($item !== null){ + $nbt->setByte(self::TAG_COLOR, $item->getDamage()); + } } } diff --git a/src/pocketmine/tile/Chest.php b/src/pocketmine/tile/Chest.php index 4f08f1ff3..7fd3f3add 100644 --- a/src/pocketmine/tile/Chest.php +++ b/src/pocketmine/tile/Chest.php @@ -28,6 +28,7 @@ use pocketmine\inventory\DoubleChestInventory; use pocketmine\inventory\InventoryHolder; use pocketmine\level\Level; use pocketmine\nbt\tag\CompoundTag; +use pocketmine\nbt\tag\IntTag; class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ use NameableTrait { @@ -44,8 +45,19 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ /** @var DoubleChestInventory */ protected $doubleInventory = null; + /** @var int|null */ + private $pairX; + /** @var int|null */ + private $pairZ; + public function __construct(Level $level, CompoundTag $nbt){ + if($nbt->hasTag(self::TAG_PAIRX, IntTag::class) and $nbt->hasTag(self::TAG_PAIRZ, IntTag::class)){ + $this->pairX = $nbt->getInt(self::TAG_PAIRX); + $this->pairZ = $nbt->getInt(self::TAG_PAIRZ); + } + $nbt->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ); parent::__construct($level, $nbt); + $this->inventory = new ChestInventory($this); $this->loadItems(); } @@ -68,6 +80,12 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ public function saveNBT() : void{ parent::saveNBT(); + if($this->isPaired()){ + $this->namedtag->setInt(self::TAG_PAIRX, $this->pairX); + $this->namedtag->setInt(self::TAG_PAIRZ, $this->pairZ); + }else{ + $this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ); + } $this->saveItems(); } @@ -89,7 +107,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ } protected function checkPairing(){ - if($this->isPaired() and !$this->getLevel()->isChunkLoaded($this->namedtag->getInt(self::TAG_PAIRX) >> 4, $this->namedtag->getInt(self::TAG_PAIRZ) >> 4)){ + if($this->isPaired() and !$this->getLevel()->isChunkLoaded($this->pairX >> 4, $this->pairZ >> 4)){ //paired to a tile in an unloaded chunk $this->doubleInventory = null; @@ -107,7 +125,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ } }else{ $this->doubleInventory = null; - $this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ); + $this->pairX = $this->pairZ = null; } } @@ -119,7 +137,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ } public function isPaired(){ - return $this->namedtag->hasTag(self::TAG_PAIRX) and $this->namedtag->hasTag(self::TAG_PAIRZ); + return $this->pairX !== null and $this->pairZ !== null; } /** @@ -127,7 +145,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ */ public function getPair() : ?Chest{ if($this->isPaired()){ - $tile = $this->getLevel()->getTileAt($this->namedtag->getInt(self::TAG_PAIRX), $this->y, $this->namedtag->getInt(self::TAG_PAIRZ)); + $tile = $this->getLevel()->getTileAt($this->pairX, $this->y, $this->pairZ); if($tile instanceof Chest){ return $tile; } @@ -151,11 +169,11 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ } private function createPair(Chest $tile){ - $this->namedtag->setInt(self::TAG_PAIRX, $tile->x); - $this->namedtag->setInt(self::TAG_PAIRZ, $tile->z); + $this->pairX = $tile->x; + $this->pairZ = $tile->z; - $tile->namedtag->setInt(self::TAG_PAIRX, $this->x); - $tile->namedtag->setInt(self::TAG_PAIRZ, $this->z); + $tile->pairX = $this->x; + $tile->pairZ = $this->z; } public function unpair(){ @@ -164,12 +182,12 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ } $tile = $this->getPair(); - $this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ); + $this->pairX = $this->pairZ = null; $this->onChanged(); if($tile instanceof Chest){ - $tile->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ); + $tile->pairX = $tile->pairZ = null; $tile->checkPairing(); $tile->onChanged(); } @@ -180,8 +198,8 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{ if($this->isPaired()){ - $nbt->setTag($this->namedtag->getTag(self::TAG_PAIRX)); - $nbt->setTag($this->namedtag->getTag(self::TAG_PAIRZ)); + $nbt->setInt(self::TAG_PAIRX, $this->pairX); + $nbt->setInt(self::TAG_PAIRZ, $this->pairZ); } $this->addNameSpawnData($nbt); diff --git a/src/pocketmine/tile/FlowerPot.php b/src/pocketmine/tile/FlowerPot.php index c2f6f0cb0..e4c7eb734 100644 --- a/src/pocketmine/tile/FlowerPot.php +++ b/src/pocketmine/tile/FlowerPot.php @@ -27,24 +27,27 @@ use pocketmine\item\Item; use pocketmine\item\ItemFactory; use pocketmine\level\Level; use pocketmine\nbt\tag\CompoundTag; -use pocketmine\nbt\tag\IntTag; -use pocketmine\nbt\tag\ShortTag; class FlowerPot extends Spawnable{ public const TAG_ITEM = "item"; public const TAG_ITEM_DATA = "mData"; + /** @var Item */ + private $item; + public function __construct(Level $level, CompoundTag $nbt){ //TODO: check PC format - if(!$nbt->hasTag(self::TAG_ITEM, ShortTag::class)){ - $nbt->setShort(self::TAG_ITEM, 0, true); - } - if(!$nbt->hasTag(self::TAG_ITEM_DATA, IntTag::class)){ - $nbt->setInt(self::TAG_ITEM_DATA, 0, true); - } + $this->item = ItemFactory::get($nbt->getShort(self::TAG_ITEM, 0, true), $nbt->getInt(self::TAG_ITEM_DATA, 0, true), 1); + $nbt->removeTag(self::TAG_ITEM, self::TAG_ITEM_DATA); + parent::__construct($level, $nbt); } + public function saveNBT() : void{ + $this->namedtag->setShort(self::TAG_ITEM, $this->item->getId()); + $this->namedtag->setInt(self::TAG_ITEM_DATA, $this->item->getDamage()); + } + public function canAddItem(Item $item) : bool{ if(!$this->isEmpty()){ return false; @@ -69,12 +72,11 @@ class FlowerPot extends Spawnable{ } public function getItem() : Item{ - return ItemFactory::get($this->namedtag->getShort(self::TAG_ITEM), $this->namedtag->getInt(self::TAG_ITEM_DATA), 1); + return clone $this->item; } public function setItem(Item $item){ - $this->namedtag->setShort(self::TAG_ITEM, $item->getId()); - $this->namedtag->setInt(self::TAG_ITEM_DATA, $item->getDamage()); + $this->item = clone $item; $this->onChanged(); } @@ -87,7 +89,7 @@ class FlowerPot extends Spawnable{ } public function addAdditionalSpawnData(CompoundTag $nbt) : void{ - $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM)); - $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_DATA)); + $nbt->setShort(self::TAG_ITEM, $this->item->getId()); + $nbt->setInt(self::TAG_ITEM_DATA, $this->item->getDamage()); } } diff --git a/src/pocketmine/tile/ItemFrame.php b/src/pocketmine/tile/ItemFrame.php index 6cae86e32..39f715121 100644 --- a/src/pocketmine/tile/ItemFrame.php +++ b/src/pocketmine/tile/ItemFrame.php @@ -26,73 +26,78 @@ namespace pocketmine\tile; use pocketmine\item\Item; use pocketmine\item\ItemFactory; use pocketmine\level\Level; -use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; -use pocketmine\nbt\tag\FloatTag; class ItemFrame extends Spawnable{ public const TAG_ITEM_ROTATION = "ItemRotation"; public const TAG_ITEM_DROP_CHANCE = "ItemDropChance"; public const TAG_ITEM = "Item"; - public function __construct(Level $level, CompoundTag $nbt){ - if(!$nbt->hasTag(self::TAG_ITEM_ROTATION, ByteTag::class)){ - $nbt->setByte(self::TAG_ITEM_ROTATION, 0, true); - } + /** @var Item */ + private $item; + /** @var int */ + private $itemRotation; + /** @var float */ + private $itemDropChance; - if(!$nbt->hasTag(self::TAG_ITEM_DROP_CHANCE, FloatTag::class)){ - $nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, 1.0, true); + public function __construct(Level $level, CompoundTag $nbt){ + if(($itemTag = $nbt->getCompoundTag(self::TAG_ITEM)) !== null){ + $this->item = Item::nbtDeserialize($itemTag); + }else{ + $this->item = ItemFactory::get(Item::AIR, 0, 0); } + $this->itemRotation = $nbt->getByte(self::TAG_ITEM_ROTATION, 0, true); + $this->itemDropChance = $nbt->getFloat(self::TAG_ITEM_DROP_CHANCE, 1.0, true); + $nbt->removeTag(self::TAG_ITEM, self::TAG_ITEM_ROTATION, self::TAG_ITEM_DROP_CHANCE); parent::__construct($level, $nbt); } + public function saveNBT() : void{ + parent::saveNBT(); + $this->namedtag->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance); + $this->namedtag->setByte(self::TAG_ITEM_ROTATION, $this->itemRotation); + $this->namedtag->setTag($this->item->nbtSerialize(-1, self::TAG_ITEM)); + } + public function hasItem() : bool{ - return !$this->getItem()->isNull(); + return !$this->item->isNull(); } public function getItem() : Item{ - $c = $this->namedtag->getCompoundTag(self::TAG_ITEM); - if($c !== null){ - return Item::nbtDeserialize($c); - } - - return ItemFactory::get(Item::AIR, 0, 0); + return clone $this->item; } public function setItem(Item $item = null){ if($item !== null and !$item->isNull()){ - $this->namedtag->setTag($item->nbtSerialize(-1, self::TAG_ITEM)); + $this->item = clone $item; }else{ - $this->namedtag->removeTag(self::TAG_ITEM); + $this->item = ItemFactory::get(Item::AIR, 0, 0); } $this->onChanged(); } public function getItemRotation() : int{ - return $this->namedtag->getByte(self::TAG_ITEM_ROTATION); + return $this->itemRotation; } public function setItemRotation(int $rotation){ - $this->namedtag->setByte(self::TAG_ITEM_ROTATION, $rotation); + $this->itemRotation = $rotation; $this->onChanged(); } public function getItemDropChance() : float{ - return $this->namedtag->getFloat(self::TAG_ITEM_DROP_CHANCE); + return $this->itemDropChance; } public function setItemDropChance(float $chance){ - $this->namedtag->setFloat(self::TAG_ITEM_DROP_CHANCE, $chance); + $this->itemDropChance = $chance; $this->onChanged(); } public function addAdditionalSpawnData(CompoundTag $nbt) : void{ - $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_DROP_CHANCE)); - $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_ROTATION)); - - if($this->hasItem()){ - $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM)); - } + $nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance); + $nbt->setByte(self::TAG_ITEM_ROTATION, $this->itemRotation); + $nbt->setTag($this->item->nbtSerialize(-1, self::TAG_ITEM)); } } diff --git a/src/pocketmine/tile/Skull.php b/src/pocketmine/tile/Skull.php index 68edd7579..1b24eb534 100644 --- a/src/pocketmine/tile/Skull.php +++ b/src/pocketmine/tile/Skull.php @@ -26,7 +26,6 @@ namespace pocketmine\tile; use pocketmine\item\Item; use pocketmine\level\Level; use pocketmine\math\Vector3; -use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\Player; @@ -43,28 +42,36 @@ class Skull extends Spawnable{ public const TAG_MOUTH_MOVING = "MouthMoving"; //TAG_Byte public const TAG_MOUTH_TICK_COUNT = "MouthTickCount"; //TAG_Int + /** @var int */ + private $skullType; + /** @var int */ + private $skullRotation; + public function __construct(Level $level, CompoundTag $nbt){ - if(!$nbt->hasTag(self::TAG_SKULL_TYPE, ByteTag::class)){ - $nbt->setByte(self::TAG_SKULL_TYPE, 0, true); - } - if(!$nbt->hasTag(self::TAG_ROT, ByteTag::class)){ - $nbt->setByte(self::TAG_ROT, 0, true); - } + $this->skullType = $nbt->getByte(self::TAG_SKULL_TYPE, self::TYPE_SKELETON, true); + $this->skullRotation = $nbt->getByte(self::TAG_ROT, 0, true); + $nbt->removeTag(self::TAG_SKULL_TYPE, self::TAG_ROT); parent::__construct($level, $nbt); } + public function saveNBT() : void{ + parent::saveNBT(); + $this->namedtag->setByte(self::TAG_SKULL_TYPE, $this->skullType); + $this->namedtag->setByte(self::TAG_ROT, $this->skullRotation); + } + public function setType(int $type){ - $this->namedtag->setByte(self::TAG_SKULL_TYPE, $type); + $this->skullType = $type; $this->onChanged(); } public function getType() : int{ - return $this->namedtag->getByte(self::TAG_SKULL_TYPE); + return $this->skullType; } public function addAdditionalSpawnData(CompoundTag $nbt) : void{ - $nbt->setTag($this->namedtag->getTag(self::TAG_SKULL_TYPE)); - $nbt->setTag($this->namedtag->getTag(self::TAG_ROT)); + $nbt->setByte(self::TAG_SKULL_TYPE, $this->skullType); + $nbt->setByte(self::TAG_ROT, $this->skullRotation); } protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{ @@ -74,6 +81,6 @@ class Skull extends Spawnable{ if($face === Vector3::SIDE_UP and $player !== null){ $rot = floor(($player->yaw * 16 / 360) + 0.5) & 0x0F; } - $nbt->setByte("Rot", $rot); + $nbt->setByte(self::TAG_ROT, $rot); } } diff --git a/src/pocketmine/tile/Spawnable.php b/src/pocketmine/tile/Spawnable.php index 4c1bced23..1937c7d00 100644 --- a/src/pocketmine/tile/Spawnable.php +++ b/src/pocketmine/tile/Spawnable.php @@ -26,6 +26,7 @@ namespace pocketmine\tile; use pocketmine\level\Level; use pocketmine\nbt\NetworkLittleEndianNBTStream; use pocketmine\nbt\tag\CompoundTag; +use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\protocol\BlockEntityDataPacket; use pocketmine\Player; @@ -105,9 +106,9 @@ abstract class Spawnable extends Tile{ final public function getSpawnCompound() : CompoundTag{ $nbt = new CompoundTag("", [ new StringTag(self::TAG_ID, static::getSaveId()), - $this->namedtag->getTag(self::TAG_X), - $this->namedtag->getTag(self::TAG_Y), - $this->namedtag->getTag(self::TAG_Z) + new IntTag(self::TAG_X, $this->x), + new IntTag(self::TAG_Y, $this->y), + new IntTag(self::TAG_Z, $this->z) ]); $this->addAdditionalSpawnData($nbt); return $nbt;