Make tiles less dependent on runtime NBT, use properties instead

This will ultimately culminate in the complete removal of runtime NBT, so plugins should also follow these steps if they have custom data.
This commit is contained in:
Dylan K. Taylor 2018-06-03 12:50:16 +01:00
parent 1bb0337420
commit 6aaaaefd2f
8 changed files with 153 additions and 104 deletions

View File

@ -92,8 +92,8 @@ class StandingBanner extends Transparent{
$tile = $this->level->getTile($this); $tile = $this->level->getTile($this);
$drop = ItemFactory::get(Item::BANNER, ($tile instanceof TileBanner ? $tile->getBaseColor() : 0)); $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()){ if($tile instanceof TileBanner and !($patterns = $tile->getPatterns())->empty()){
$drop->setNamedTagEntry($patterns); $drop->setNamedTagEntry(clone $patterns);
} }
return [$drop]; return [$drop];

View File

@ -99,19 +99,30 @@ class Banner extends Spawnable implements Nameable{
public const COLOR_ORANGE = 14; public const COLOR_ORANGE = 14;
public const COLOR_WHITE = 15; 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){ public function __construct(Level $level, CompoundTag $nbt){
if(!$nbt->hasTag(self::TAG_BASE, IntTag::class)){ $this->baseColor = $nbt->getInt(self::TAG_BASE, self::COLOR_BLACK, true);
$nbt->setInt(self::TAG_BASE, 0); $this->patterns = $nbt->getListTag(self::TAG_PATTERNS) ?? new ListTag(self::TAG_PATTERNS);
} $nbt->removeTag(self::TAG_BASE, self::TAG_PATTERNS);
if(!$nbt->hasTag(self::TAG_PATTERNS, ListTag::class)){
$nbt->setTag(new ListTag(self::TAG_PATTERNS));
}
parent::__construct($level, $nbt); 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{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->setTag($this->namedtag->getTag(self::TAG_PATTERNS)); $nbt->setInt(self::TAG_BASE, $this->baseColor);
$nbt->setTag($this->namedtag->getTag(self::TAG_BASE)); $nbt->setTag($this->patterns);
$this->addNameSpawnData($nbt); $this->addNameSpawnData($nbt);
} }
@ -121,7 +132,7 @@ class Banner extends Spawnable implements Nameable{
* @return int * @return int
*/ */
public function getBaseColor() : 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 * @param int $color
*/ */
public function setBaseColor(int $color) : void{ public function setBaseColor(int $color) : void{
$this->namedtag->setInt(self::TAG_BASE, $color & 0x0f); $this->baseColor = $color;
$this->onChanged(); $this->onChanged();
} }
@ -143,15 +154,13 @@ class Banner extends Spawnable implements Nameable{
* @return int ID of pattern. * @return int ID of pattern.
*/ */
public function addPattern(string $pattern, int $color) : int{ public function addPattern(string $pattern, int $color) : int{
$list = $this->namedtag->getListTag(self::TAG_PATTERNS); $this->patterns->push(new CompoundTag("", [
assert($list !== null);
$list->push(new CompoundTag("", [
new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f), new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f),
new StringTag(self::TAG_PATTERN_NAME, $pattern) new StringTag(self::TAG_PATTERN_NAME, $pattern)
])); ]));
$this->onChanged(); $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 * @return bool
*/ */
public function patternExists(int $patternId) : 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 []; return [];
} }
$list = $this->namedtag->getListTag(self::TAG_PATTERNS); $patternTag = $this->patterns->get($patternId);
assert($list instanceof ListTag);
$patternTag = $list->get($patternId);
assert($patternTag instanceof CompoundTag); assert($patternTag instanceof CompoundTag);
return [ return [
@ -202,10 +209,7 @@ class Banner extends Spawnable implements Nameable{
return false; return false;
} }
$list = $this->namedtag->getListTag(self::TAG_PATTERNS); $this->patterns->set($patternId, new CompoundTag("", [
assert($list instanceof ListTag);
$list->set($patternId, new CompoundTag("", [
new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f), new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f),
new StringTag(self::TAG_PATTERN_NAME, $pattern) new StringTag(self::TAG_PATTERN_NAME, $pattern)
])); ]));
@ -226,10 +230,7 @@ class Banner extends Spawnable implements Nameable{
return false; return false;
} }
$list = $this->namedtag->getListTag(self::TAG_PATTERNS); $this->patterns->remove($patternId);
if($list !== null){
$list->remove($patternId);
}
$this->onChanged(); $this->onChanged();
return true; return true;
@ -259,7 +260,14 @@ class Banner extends Spawnable implements Nameable{
* @return int * @return int
*/ */
public function getPatternCount() : 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{ protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{

View File

@ -27,34 +27,42 @@ namespace pocketmine\tile;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player; use pocketmine\Player;
class Bed extends Spawnable{ class Bed extends Spawnable{
public const TAG_COLOR = "color"; public const TAG_COLOR = "color";
/** @var int */
private $color = 14; //default to old red
public function __construct(Level $level, CompoundTag $nbt){ public function __construct(Level $level, CompoundTag $nbt){
if(!$nbt->hasTag(self::TAG_COLOR, ByteTag::class)){ //TODO: check PC format $this->color = $nbt->getByte(self::TAG_COLOR, 14, true);
$nbt->setByte(self::TAG_COLOR, 14, true); //default to old red $nbt->removeTag(self::TAG_COLOR);
}
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
} }
public function getColor() : int{ public function getColor() : int{
return $this->namedtag->getByte(self::TAG_COLOR); return $this->color;
} }
public function setColor(int $color){ public function setColor(int $color){
$this->namedtag->setByte(self::TAG_COLOR, $color & 0x0f); $this->color = $color & 0xf;
$this->onChanged(); $this->onChanged();
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ 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{ 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());
}
} }
} }

View File

@ -28,6 +28,7 @@ use pocketmine\inventory\DoubleChestInventory;
use pocketmine\inventory\InventoryHolder; use pocketmine\inventory\InventoryHolder;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
use NameableTrait { use NameableTrait {
@ -44,8 +45,19 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
/** @var DoubleChestInventory */ /** @var DoubleChestInventory */
protected $doubleInventory = null; protected $doubleInventory = null;
/** @var int|null */
private $pairX;
/** @var int|null */
private $pairZ;
public function __construct(Level $level, CompoundTag $nbt){ 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); parent::__construct($level, $nbt);
$this->inventory = new ChestInventory($this); $this->inventory = new ChestInventory($this);
$this->loadItems(); $this->loadItems();
} }
@ -68,6 +80,12 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
public function saveNBT() : void{ public function saveNBT() : void{
parent::saveNBT(); 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(); $this->saveItems();
} }
@ -89,7 +107,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
protected function checkPairing(){ 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 //paired to a tile in an unloaded chunk
$this->doubleInventory = null; $this->doubleInventory = null;
@ -107,7 +125,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
}else{ }else{
$this->doubleInventory = null; $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(){ 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{ public function getPair() : ?Chest{
if($this->isPaired()){ 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){ if($tile instanceof Chest){
return $tile; return $tile;
} }
@ -151,11 +169,11 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
private function createPair(Chest $tile){ private function createPair(Chest $tile){
$this->namedtag->setInt(self::TAG_PAIRX, $tile->x); $this->pairX = $tile->x;
$this->namedtag->setInt(self::TAG_PAIRZ, $tile->z); $this->pairZ = $tile->z;
$tile->namedtag->setInt(self::TAG_PAIRX, $this->x); $tile->pairX = $this->x;
$tile->namedtag->setInt(self::TAG_PAIRZ, $this->z); $tile->pairZ = $this->z;
} }
public function unpair(){ public function unpair(){
@ -164,12 +182,12 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
$tile = $this->getPair(); $tile = $this->getPair();
$this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ); $this->pairX = $this->pairZ = null;
$this->onChanged(); $this->onChanged();
if($tile instanceof Chest){ if($tile instanceof Chest){
$tile->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ); $tile->pairX = $tile->pairZ = null;
$tile->checkPairing(); $tile->checkPairing();
$tile->onChanged(); $tile->onChanged();
} }
@ -180,8 +198,8 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
if($this->isPaired()){ if($this->isPaired()){
$nbt->setTag($this->namedtag->getTag(self::TAG_PAIRX)); $nbt->setInt(self::TAG_PAIRX, $this->pairX);
$nbt->setTag($this->namedtag->getTag(self::TAG_PAIRZ)); $nbt->setInt(self::TAG_PAIRZ, $this->pairZ);
} }
$this->addNameSpawnData($nbt); $this->addNameSpawnData($nbt);

View File

@ -27,24 +27,27 @@ use pocketmine\item\Item;
use pocketmine\item\ItemFactory; use pocketmine\item\ItemFactory;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ShortTag;
class FlowerPot extends Spawnable{ class FlowerPot extends Spawnable{
public const TAG_ITEM = "item"; public const TAG_ITEM = "item";
public const TAG_ITEM_DATA = "mData"; public const TAG_ITEM_DATA = "mData";
/** @var Item */
private $item;
public function __construct(Level $level, CompoundTag $nbt){ public function __construct(Level $level, CompoundTag $nbt){
//TODO: check PC format //TODO: check PC format
if(!$nbt->hasTag(self::TAG_ITEM, ShortTag::class)){ $this->item = ItemFactory::get($nbt->getShort(self::TAG_ITEM, 0, true), $nbt->getInt(self::TAG_ITEM_DATA, 0, true), 1);
$nbt->setShort(self::TAG_ITEM, 0, true); $nbt->removeTag(self::TAG_ITEM, self::TAG_ITEM_DATA);
}
if(!$nbt->hasTag(self::TAG_ITEM_DATA, IntTag::class)){
$nbt->setInt(self::TAG_ITEM_DATA, 0, true);
}
parent::__construct($level, $nbt); 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{ public function canAddItem(Item $item) : bool{
if(!$this->isEmpty()){ if(!$this->isEmpty()){
return false; return false;
@ -69,12 +72,11 @@ class FlowerPot extends Spawnable{
} }
public function getItem() : Item{ 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){ public function setItem(Item $item){
$this->namedtag->setShort(self::TAG_ITEM, $item->getId()); $this->item = clone $item;
$this->namedtag->setInt(self::TAG_ITEM_DATA, $item->getDamage());
$this->onChanged(); $this->onChanged();
} }
@ -87,7 +89,7 @@ class FlowerPot extends Spawnable{
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->setTag($this->namedtag->getTag(self::TAG_ITEM)); $nbt->setShort(self::TAG_ITEM, $this->item->getId());
$nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_DATA)); $nbt->setInt(self::TAG_ITEM_DATA, $this->item->getDamage());
} }
} }

View File

@ -26,73 +26,78 @@ namespace pocketmine\tile;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\ItemFactory; use pocketmine\item\ItemFactory;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag;
class ItemFrame extends Spawnable{ class ItemFrame extends Spawnable{
public const TAG_ITEM_ROTATION = "ItemRotation"; public const TAG_ITEM_ROTATION = "ItemRotation";
public const TAG_ITEM_DROP_CHANCE = "ItemDropChance"; public const TAG_ITEM_DROP_CHANCE = "ItemDropChance";
public const TAG_ITEM = "Item"; public const TAG_ITEM = "Item";
public function __construct(Level $level, CompoundTag $nbt){ /** @var Item */
if(!$nbt->hasTag(self::TAG_ITEM_ROTATION, ByteTag::class)){ private $item;
$nbt->setByte(self::TAG_ITEM_ROTATION, 0, true); /** @var int */
} private $itemRotation;
/** @var float */
private $itemDropChance;
if(!$nbt->hasTag(self::TAG_ITEM_DROP_CHANCE, FloatTag::class)){ public function __construct(Level $level, CompoundTag $nbt){
$nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, 1.0, true); 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); 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{ public function hasItem() : bool{
return !$this->getItem()->isNull(); return !$this->item->isNull();
} }
public function getItem() : Item{ public function getItem() : Item{
$c = $this->namedtag->getCompoundTag(self::TAG_ITEM); return clone $this->item;
if($c !== null){
return Item::nbtDeserialize($c);
}
return ItemFactory::get(Item::AIR, 0, 0);
} }
public function setItem(Item $item = null){ public function setItem(Item $item = null){
if($item !== null and !$item->isNull()){ if($item !== null and !$item->isNull()){
$this->namedtag->setTag($item->nbtSerialize(-1, self::TAG_ITEM)); $this->item = clone $item;
}else{ }else{
$this->namedtag->removeTag(self::TAG_ITEM); $this->item = ItemFactory::get(Item::AIR, 0, 0);
} }
$this->onChanged(); $this->onChanged();
} }
public function getItemRotation() : int{ public function getItemRotation() : int{
return $this->namedtag->getByte(self::TAG_ITEM_ROTATION); return $this->itemRotation;
} }
public function setItemRotation(int $rotation){ public function setItemRotation(int $rotation){
$this->namedtag->setByte(self::TAG_ITEM_ROTATION, $rotation); $this->itemRotation = $rotation;
$this->onChanged(); $this->onChanged();
} }
public function getItemDropChance() : float{ public function getItemDropChance() : float{
return $this->namedtag->getFloat(self::TAG_ITEM_DROP_CHANCE); return $this->itemDropChance;
} }
public function setItemDropChance(float $chance){ public function setItemDropChance(float $chance){
$this->namedtag->setFloat(self::TAG_ITEM_DROP_CHANCE, $chance); $this->itemDropChance = $chance;
$this->onChanged(); $this->onChanged();
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_DROP_CHANCE)); $nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance);
$nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_ROTATION)); $nbt->setByte(self::TAG_ITEM_ROTATION, $this->itemRotation);
$nbt->setTag($this->item->nbtSerialize(-1, self::TAG_ITEM));
if($this->hasItem()){
$nbt->setTag($this->namedtag->getTag(self::TAG_ITEM));
}
} }
} }

View File

@ -26,7 +26,6 @@ namespace pocketmine\tile;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player; use pocketmine\Player;
@ -43,28 +42,36 @@ class Skull extends Spawnable{
public const TAG_MOUTH_MOVING = "MouthMoving"; //TAG_Byte public const TAG_MOUTH_MOVING = "MouthMoving"; //TAG_Byte
public const TAG_MOUTH_TICK_COUNT = "MouthTickCount"; //TAG_Int public const TAG_MOUTH_TICK_COUNT = "MouthTickCount"; //TAG_Int
/** @var int */
private $skullType;
/** @var int */
private $skullRotation;
public function __construct(Level $level, CompoundTag $nbt){ public function __construct(Level $level, CompoundTag $nbt){
if(!$nbt->hasTag(self::TAG_SKULL_TYPE, ByteTag::class)){ $this->skullType = $nbt->getByte(self::TAG_SKULL_TYPE, self::TYPE_SKELETON, true);
$nbt->setByte(self::TAG_SKULL_TYPE, 0, true); $this->skullRotation = $nbt->getByte(self::TAG_ROT, 0, true);
} $nbt->removeTag(self::TAG_SKULL_TYPE, self::TAG_ROT);
if(!$nbt->hasTag(self::TAG_ROT, ByteTag::class)){
$nbt->setByte(self::TAG_ROT, 0, true);
}
parent::__construct($level, $nbt); 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){ public function setType(int $type){
$this->namedtag->setByte(self::TAG_SKULL_TYPE, $type); $this->skullType = $type;
$this->onChanged(); $this->onChanged();
} }
public function getType() : int{ public function getType() : int{
return $this->namedtag->getByte(self::TAG_SKULL_TYPE); return $this->skullType;
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->setTag($this->namedtag->getTag(self::TAG_SKULL_TYPE)); $nbt->setByte(self::TAG_SKULL_TYPE, $this->skullType);
$nbt->setTag($this->namedtag->getTag(self::TAG_ROT)); $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{ 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){ if($face === Vector3::SIDE_UP and $player !== null){
$rot = floor(($player->yaw * 16 / 360) + 0.5) & 0x0F; $rot = floor(($player->yaw * 16 / 360) + 0.5) & 0x0F;
} }
$nbt->setByte("Rot", $rot); $nbt->setByte(self::TAG_ROT, $rot);
} }
} }

View File

@ -26,6 +26,7 @@ namespace pocketmine\tile;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\NetworkLittleEndianNBTStream; use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\BlockEntityDataPacket; use pocketmine\network\mcpe\protocol\BlockEntityDataPacket;
use pocketmine\Player; use pocketmine\Player;
@ -105,9 +106,9 @@ abstract class Spawnable extends Tile{
final public function getSpawnCompound() : CompoundTag{ final public function getSpawnCompound() : CompoundTag{
$nbt = new CompoundTag("", [ $nbt = new CompoundTag("", [
new StringTag(self::TAG_ID, static::getSaveId()), new StringTag(self::TAG_ID, static::getSaveId()),
$this->namedtag->getTag(self::TAG_X), new IntTag(self::TAG_X, $this->x),
$this->namedtag->getTag(self::TAG_Y), new IntTag(self::TAG_Y, $this->y),
$this->namedtag->getTag(self::TAG_Z) new IntTag(self::TAG_Z, $this->z)
]); ]);
$this->addAdditionalSpawnData($nbt); $this->addAdditionalSpawnData($nbt);
return $nbt; return $nbt;