Cleaned up tile NBT handling, use new CompoundTag API methods

This commit is contained in:
Dylan K. Taylor 2017-10-16 16:48:24 +01:00
parent 0b1a9ba062
commit 20b86bdea8
11 changed files with 203 additions and 168 deletions

View File

@ -32,28 +32,29 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player; use pocketmine\Player;
class Bed extends Spawnable{ class Bed extends Spawnable{
const TAG_COLOR = "color";
public function __construct(Level $level, CompoundTag $nbt){ public function __construct(Level $level, CompoundTag $nbt){
if(!isset($nbt->color) or !($nbt->color instanceof ByteTag)){ if(!($nbt->getTag(self::TAG_COLOR) instanceof ByteTag)){
$nbt->color = new ByteTag("color", 14); //default to old red $nbt->setTag(new ByteTag(self::TAG_COLOR, 14)); //default to old red
} }
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
} }
public function getColor() : int{ public function getColor() : int{
return $this->namedtag->color->getValue(); return $this->namedtag->getByte(self::TAG_COLOR);
} }
public function setColor(int $color){ public function setColor(int $color){
$this->namedtag->color->setValue($color & 0x0f); $this->namedtag->setByte(self::TAG_COLOR, $color & 0x0f);
$this->onChanged(); $this->onChanged();
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->color = $this->namedtag->color; $nbt->setTag($this->namedtag->getTag(self::TAG_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->color = new ByteTag("color", $item !== null ? $item->getDamage() : 14); //default red $nbt->setByte(self::TAG_COLOR, $item !== null ? $item->getDamage() : 14); //default red
} }
} }

View File

@ -32,14 +32,16 @@ use pocketmine\level\Level;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player; use pocketmine\Player;
class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
use NameableTrait; use NameableTrait;
const TAG_PAIRX = "pairx";
const TAG_PAIRZ = "pairz";
const TAG_PAIR_LEAD = "pairlead";
/** @var ChestInventory */ /** @var ChestInventory */
protected $inventory; protected $inventory;
/** @var DoubleChestInventory */ /** @var DoubleChestInventory */
@ -49,8 +51,8 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
$this->inventory = new ChestInventory($this); $this->inventory = new ChestInventory($this);
if(!isset($this->namedtag->Items) or !($this->namedtag->Items instanceof ListTag)){ if(!($this->namedtag->getTag("Items") instanceof ListTag)){
$this->namedtag->Items = new ListTag("Items", [], NBT::TAG_Compound); $this->namedtag->setTag(new ListTag("Items", [], NBT::TAG_Compound));
} }
for($i = 0; $i < $this->getSize(); ++$i){ for($i = 0; $i < $this->getSize(); ++$i){
@ -75,7 +77,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
public function saveNBT() : void{ public function saveNBT() : void{
$this->namedtag->Items->setValue([]); $this->namedtag->setTag(new ListTag("Items", [], NBT::TAG_Compound));
for($index = 0; $index < $this->getSize(); ++$index){ for($index = 0; $index < $this->getSize(); ++$index){
$this->setItem($index, $this->inventory->getItem($index)); $this->setItem($index, $this->inventory->getItem($index));
} }
@ -94,8 +96,11 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
* @return int * @return int
*/ */
protected function getSlotIndex(int $index) : int{ protected function getSlotIndex(int $index) : int{
foreach($this->namedtag->Items as $i => $slot){ $items = $this->namedtag->getListTag("Items");
if($slot->Slot->getValue() === $index){ assert($items instanceof ListTag);
foreach($items as $i => $slot){
/** @var CompoundTag $slot */
if($slot->getByte("Slot") === $index){
return (int) $i; return (int) $i;
} }
} }
@ -115,7 +120,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
if($i < 0){ if($i < 0){
return ItemFactory::get(Item::AIR, 0, 0); return ItemFactory::get(Item::AIR, 0, 0);
}else{ }else{
return Item::nbtDeserialize($this->namedtag->Items[$i]); return Item::nbtDeserialize($this->namedtag->getListTag("Items")[$i]);
} }
} }
@ -130,20 +135,25 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
$d = $item->nbtSerialize($index); $d = $item->nbtSerialize($index);
$items = $this->namedtag->getListTag("Items");
assert($items instanceof ListTag);
if($item->isNull()){ if($item->isNull()){
if($i >= 0){ if($i >= 0){
unset($this->namedtag->Items[$i]); unset($items[$i]);
} }
}elseif($i < 0){ }elseif($i < 0){
for($i = 0; $i <= $this->getSize(); ++$i){ for($i = 0; $i <= $this->getSize(); ++$i){
if(!isset($this->namedtag->Items[$i])){ if(!isset($items[$i])){
break; break;
} }
} }
$this->namedtag->Items[$i] = $d; $items[$i] = $d;
}else{ }else{
$this->namedtag->Items[$i] = $d; $items[$i] = $d;
} }
$this->namedtag->setTag($items);
} }
/** /**
@ -164,7 +174,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
protected function checkPairing(){ protected function checkPairing(){
if($this->isPaired() and !$this->getLevel()->isChunkLoaded($this->namedtag->pairx->getValue() >> 4, $this->namedtag->pairz->getValue() >> 4)){ if($this->isPaired() and !$this->getLevel()->isChunkLoaded($this->namedtag->getInt(self::TAG_PAIRX) >> 4, $this->namedtag->getInt(self::TAG_PAIRZ) >> 4)){
//paired to a tile in an unloaded chunk //paired to a tile in an unloaded chunk
$this->doubleInventory = null; $this->doubleInventory = null;
@ -182,7 +192,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
}else{ }else{
$this->doubleInventory = null; $this->doubleInventory = null;
unset($this->namedtag->pairx, $this->namedtag->pairz); $this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
} }
} }
@ -194,7 +204,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
public function isPaired(){ public function isPaired(){
return isset($this->namedtag->pairx) and isset($this->namedtag->pairz); return $this->namedtag->hasTag(self::TAG_PAIRX) and $this->namedtag->hasTag(self::TAG_PAIRZ);
} }
/** /**
@ -202,7 +212,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()->getTile(new Vector3($this->namedtag->pairx->getValue(), $this->y, $this->namedtag->pairz->getValue())); $tile = $this->getLevel()->getTile(new Vector3($this->namedtag->getInt(self::TAG_PAIRX), $this->y, $this->namedtag->getInt(self::TAG_PAIRZ)));
if($tile instanceof Chest){ if($tile instanceof Chest){
return $tile; return $tile;
} }
@ -226,11 +236,11 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
private function createPair(Chest $tile){ private function createPair(Chest $tile){
$this->namedtag->pairx = new IntTag("pairx", $tile->x); $this->namedtag->setInt(self::TAG_PAIRX, $tile->x);
$this->namedtag->pairz = new IntTag("pairz", $tile->z); $this->namedtag->setInt(self::TAG_PAIRZ, $tile->z);
$tile->namedtag->pairx = new IntTag("pairx", $this->x); $tile->namedtag->setInt(self::TAG_PAIRX, $this->x);
$tile->namedtag->pairz = new IntTag("pairz", $this->z); $tile->namedtag->setInt(self::TAG_PAIRZ, $this->z);
} }
public function unpair(){ public function unpair(){
@ -239,12 +249,12 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
} }
$tile = $this->getPair(); $tile = $this->getPair();
unset($this->namedtag->pairx, $this->namedtag->pairz); $this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
$this->spawnToAll(); $this->spawnToAll();
if($tile instanceof Chest){ if($tile instanceof Chest){
unset($tile->namedtag->pairx, $tile->namedtag->pairz); $tile->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
$tile->checkPairing(); $tile->checkPairing();
$tile->spawnToAll(); $tile->spawnToAll();
} }
@ -255,20 +265,20 @@ 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->pairx = $this->namedtag->pairx; $nbt->setTag($this->namedtag->getTag(self::TAG_PAIRX));
$nbt->pairz = $this->namedtag->pairz; $nbt->setTag($this->namedtag->getTag(self::TAG_PAIRZ));
} }
if($this->hasName()){ if($this->hasName()){
$nbt->CustomName = $this->namedtag->CustomName; $nbt->setTag($this->namedtag->getTag("CustomName"));
} }
} }
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->Items = new ListTag("Items", [], NBT::TAG_Compound); $nbt->setTag(new ListTag("Items", [], NBT::TAG_Compound));
if($item !== null and $item->hasCustomName()){ if($item !== null and $item->hasCustomName()){
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName()); $nbt->setString("CustomName", $item->getCustomName());
} }
} }
} }

View File

@ -26,7 +26,6 @@ namespace pocketmine\tile;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player; use pocketmine\Player;
class EnchantTable extends Spawnable implements Nameable{ class EnchantTable extends Spawnable implements Nameable{
@ -41,13 +40,13 @@ class EnchantTable extends Spawnable implements Nameable{
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
if($this->hasName()){ if($this->hasName()){
$nbt->CustomName = $this->namedtag->CustomName; $nbt->setTag($this->namedtag->getTag("CustomName"));
} }
} }
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{
if($item !== null and $item->hasCustomName()){ if($item !== null and $item->hasCustomName()){
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName()); $nbt->setString("CustomName", $item->getCustomName());
} }
} }
} }

View File

@ -33,13 +33,15 @@ use pocketmine\nbt\tag\ShortTag;
use pocketmine\Player; use pocketmine\Player;
class FlowerPot extends Spawnable{ class FlowerPot extends Spawnable{
const TAG_ITEM = "item";
const TAG_ITEM_DATA = "mData";
public function __construct(Level $level, CompoundTag $nbt){ public function __construct(Level $level, CompoundTag $nbt){
if(!isset($nbt->item)){ if(!($nbt->getTag(self::TAG_ITEM) instanceof ShortTag)){
$nbt->item = new ShortTag("item", 0); $nbt->setTag(new ShortTag(self::TAG_ITEM, 0));
} }
if(!isset($nbt->mData)){ if(!($nbt->getTag(self::TAG_ITEM_DATA) instanceof IntTag)){
$nbt->mData = new IntTag("mData", 0); $nbt->setTag(new IntTag(self::TAG_ITEM_DATA, 0));
} }
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
} }
@ -68,12 +70,12 @@ class FlowerPot extends Spawnable{
} }
public function getItem() : Item{ public function getItem() : Item{
return ItemFactory::get($this->namedtag->item->getValue(), $this->namedtag->mData->getValue(), 1); return ItemFactory::get($this->namedtag->getShort(self::TAG_ITEM), $this->namedtag->getInt(self::TAG_ITEM_DATA), 1);
} }
public function setItem(Item $item){ public function setItem(Item $item){
$this->namedtag->item->setValue($item->getId()); $this->namedtag->setShort(self::TAG_ITEM, $item->getId());
$this->namedtag->mData->setValue($item->getDamage()); $this->namedtag->setInt(self::TAG_ITEM_DATA, $item->getDamage());
$this->onChanged(); $this->onChanged();
} }
@ -86,12 +88,12 @@ class FlowerPot extends Spawnable{
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->item = $this->namedtag->item; $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM));
$nbt->mData = $this->namedtag->mData; $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_DATA));
} }
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->item = new ShortTag("item", 0); $nbt->setShort(self::TAG_ITEM, 0);
$nbt->mData = new IntTag("mData", 0); $nbt->setInt(self::TAG_ITEM_DATA, 0);
} }
} }

View File

@ -38,44 +38,54 @@ use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\ShortTag; use pocketmine\nbt\tag\ShortTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket; use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
use pocketmine\Player; use pocketmine\Player;
class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
use NameableTrait; use NameableTrait;
const TAG_BURN_TIME = "BurnTime";
const TAG_COOK_TIME = "CookTime";
const TAG_MAX_TIME = "MaxTime";
const TAG_BURN_TICKS = "BurnTicks";
/** @var FurnaceInventory */ /** @var FurnaceInventory */
protected $inventory; protected $inventory;
public function __construct(Level $level, CompoundTag $nbt){ public function __construct(Level $level, CompoundTag $nbt){
if(!isset($nbt->BurnTime) or $nbt->BurnTime->getValue() < 0){ if(!($nbt->getTag(self::TAG_BURN_TIME) instanceof ShortTag) or $nbt->getShort(self::TAG_BURN_TIME) < 0){
$nbt->BurnTime = new ShortTag("BurnTime", 0); $nbt->setTag(new ShortTag(self::TAG_BURN_TIME, 0));
}
if(!isset($nbt->CookTime) or $nbt->CookTime->getValue() < 0 or ($nbt->BurnTime->getValue() === 0 and $nbt->CookTime->getValue() > 0)){
$nbt->CookTime = new ShortTag("CookTime", 0);
}
if(!isset($nbt->MaxTime)){
$nbt->MaxTime = new ShortTag("BurnTime", $nbt->BurnTime->getValue());
unset($nbt->BurnTicks);
} }
if(!isset($nbt->BurnTicks)){ if(!
$nbt->BurnTicks = new ShortTag("BurnTicks", 0); ($nbt->getTag(self::TAG_COOK_TIME) instanceof ShortTag) or
$nbt->getShort(self::TAG_COOK_TIME) < 0 or
($nbt->getShort(self::TAG_BURN_TIME) === 0 and $nbt->getShort(self::TAG_COOK_TIME) > 0)
){
$nbt->setTag(new ShortTag(self::TAG_COOK_TIME, 0));
}
if(!($nbt->getTag(self::TAG_MAX_TIME) instanceof ShortTag)){
$nbt->setTag(new ShortTag(self::TAG_MAX_TIME, $nbt->getShort(self::TAG_BURN_TIME)));
$nbt->removeTag(self::TAG_BURN_TICKS);
}
if(!($nbt->getTag(self::TAG_BURN_TICKS) instanceof ShortTag)){
$nbt->setTag(new ShortTag(self::TAG_BURN_TICKS, 0));
} }
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
$this->inventory = new FurnaceInventory($this); $this->inventory = new FurnaceInventory($this);
if(!isset($this->namedtag->Items) or !($this->namedtag->Items instanceof ListTag)){ if(!($this->namedtag->getTag("Items") instanceof ListTag)){
$this->namedtag->Items = new ListTag("Items", [], NBT::TAG_Compound); $this->namedtag->setTag(new ListTag("Items", [], NBT::TAG_Compound));
} }
for($i = 0; $i < $this->getSize(); ++$i){ for($i = 0; $i < $this->getSize(); ++$i){
$this->inventory->setItem($i, $this->getItem($i), false); $this->inventory->setItem($i, $this->getItem($i), false);
} }
if($this->namedtag->BurnTime->getValue() > 0){ if($this->namedtag->getShort(self::TAG_BURN_TIME) > 0){
$this->scheduleUpdate(); $this->scheduleUpdate();
} }
} }
@ -97,7 +107,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
} }
public function saveNBT() : void{ public function saveNBT() : void{
$this->namedtag->Items->setValue([]); $this->namedtag->setTag(new ListTag("Items", [], NBT::TAG_Compound));
for($index = 0; $index < $this->getSize(); ++$index){ for($index = 0; $index < $this->getSize(); ++$index){
$this->setItem($index, $this->inventory->getItem($index)); $this->setItem($index, $this->inventory->getItem($index));
} }
@ -116,8 +126,9 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
* @return int * @return int
*/ */
protected function getSlotIndex(int $index) : int{ protected function getSlotIndex(int $index) : int{
foreach($this->namedtag->Items as $i => $slot){ foreach($this->namedtag->getListTag("Items") as $i => $slot){
if($slot->Slot->getValue() === $index){ /** @var CompoundTag $slot */
if($slot->getByte("Slot") === $index){
return (int) $i; return (int) $i;
} }
} }
@ -137,7 +148,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
if($i < 0){ if($i < 0){
return ItemFactory::get(Item::AIR, 0, 0); return ItemFactory::get(Item::AIR, 0, 0);
}else{ }else{
return Item::nbtDeserialize($this->namedtag->Items[$i]); return Item::nbtDeserialize($this->namedtag->getListTag("Items")[$i]);
} }
} }
@ -152,20 +163,25 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
$d = $item->nbtSerialize($index); $d = $item->nbtSerialize($index);
$items = $this->namedtag->getListTag("Items");
assert($items instanceof ListTag);
if($item->isNull()){ if($item->isNull()){
if($i >= 0){ if($i >= 0){
unset($this->namedtag->Items[$i]); unset($items[$i]);
} }
}elseif($i < 0){ }elseif($i < 0){
for($i = 0; $i <= $this->getSize(); ++$i){ for($i = 0; $i <= $this->getSize(); ++$i){
if(!isset($this->namedtag->Items[$i])){ if(!isset($items[$i])){
break; break;
} }
} }
$this->namedtag->Items[$i] = $d; $items[$i] = $d;
}else{ }else{
$this->namedtag->Items[$i] = $d; $items[$i] = $d;
} }
$this->namedtag->setTag($items);
} }
/** /**
@ -182,14 +198,14 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
return; return;
} }
$this->namedtag->MaxTime->setValue($ev->getBurnTime()); $this->namedtag->setShort(self::TAG_MAX_TIME, $ev->getBurnTime());
$this->namedtag->BurnTime->setValue($ev->getBurnTime()); $this->namedtag->setShort(self::TAG_BURN_TIME, $ev->getBurnTime());
$this->namedtag->BurnTicks->setValue(0); $this->namedtag->setShort(self::TAG_BURN_TICKS, 0);
if($this->getBlock()->getId() === Block::FURNACE){ if($this->getBlock()->getId() === Block::FURNACE){
$this->getLevel()->setBlock($this, BlockFactory::get(Block::BURNING_FURNACE, $this->getBlock()->getDamage()), true); $this->getLevel()->setBlock($this, BlockFactory::get(Block::BURNING_FURNACE, $this->getBlock()->getDamage()), true);
} }
if($this->namedtag->BurnTime->getValue() > 0 and $ev->isBurning()){ if($this->namedtag->getShort(self::TAG_BURN_TIME) > 0 and $ev->isBurning()){
$fuel->pop(); $fuel->pop();
$this->inventory->setFuel($fuel); $this->inventory->setFuel($fuel);
} }
@ -210,17 +226,17 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
$smelt = $this->server->getCraftingManager()->matchFurnaceRecipe($raw); $smelt = $this->server->getCraftingManager()->matchFurnaceRecipe($raw);
$canSmelt = ($smelt instanceof FurnaceRecipe and $raw->getCount() > 0 and (($smelt->getResult()->equals($product) and $product->getCount() < $product->getMaxStackSize()) or $product->isNull())); $canSmelt = ($smelt instanceof FurnaceRecipe and $raw->getCount() > 0 and (($smelt->getResult()->equals($product) and $product->getCount() < $product->getMaxStackSize()) or $product->isNull()));
if($this->namedtag->BurnTime->getValue() <= 0 and $canSmelt and $fuel->getFuelTime() > 0 and $fuel->getCount() > 0){ if($this->namedtag->getShort(self::TAG_BURN_TIME) <= 0 and $canSmelt and $fuel->getFuelTime() > 0 and $fuel->getCount() > 0){
$this->checkFuel($fuel); $this->checkFuel($fuel);
} }
if($this->namedtag->BurnTime->getValue() > 0){ if($this->namedtag->getShort(self::TAG_BURN_TIME) > 0){
$this->namedtag->BurnTime->setValue($this->namedtag->BurnTime->getValue() - 1); $this->namedtag->setShort(self::TAG_BURN_TIME, $this->namedtag->getShort(self::TAG_BURN_TIME) - 1);
$this->namedtag->BurnTicks->setValue((int) ceil($this->namedtag->BurnTime->getValue() / $this->namedtag->MaxTime->getValue() * 200)); $this->namedtag->setShort(self::TAG_BURN_TICKS, (int) ceil($this->namedtag->getShort(self::TAG_BURN_TIME) / $this->namedtag->getShort(self::TAG_MAX_TIME) * 200));
if($smelt instanceof FurnaceRecipe and $canSmelt){ if($smelt instanceof FurnaceRecipe and $canSmelt){
$this->namedtag->CookTime->setValue($this->namedtag->CookTime->getValue() + 1); $this->namedtag->setShort(self::TAG_COOK_TIME, $this->namedtag->getShort(self::TAG_COOK_TIME) + 1);
if($this->namedtag->CookTime->getValue() >= 200){ //10 seconds if($this->namedtag->getShort(self::TAG_COOK_TIME) >= 200){ //10 seconds
$product = ItemFactory::get($smelt->getResult()->getId(), $smelt->getResult()->getDamage(), $product->getCount() + 1); $product = ItemFactory::get($smelt->getResult()->getId(), $smelt->getResult()->getDamage(), $product->getCount() + 1);
$this->server->getPluginManager()->callEvent($ev = new FurnaceSmeltEvent($this, $raw, $product)); $this->server->getPluginManager()->callEvent($ev = new FurnaceSmeltEvent($this, $raw, $product));
@ -231,23 +247,23 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
$this->inventory->setSmelting($raw); $this->inventory->setSmelting($raw);
} }
$this->namedtag->CookTime->setValue($this->namedtag->CookTime->getValue() - 200); $this->namedtag->setShort(self::TAG_COOK_TIME, $this->namedtag->getShort(self::TAG_COOK_TIME) - 200);
} }
}elseif($this->namedtag->BurnTime->getValue() <= 0){ }elseif($this->namedtag->getShort(self::TAG_BURN_TIME) <= 0){
$this->namedtag->BurnTime->setValue(0); $this->namedtag->setShort(self::TAG_BURN_TIME, 0);
$this->namedtag->CookTime->setValue(0); $this->namedtag->setShort(self::TAG_COOK_TIME, 0);
$this->namedtag->BurnTicks->setValue(0); $this->namedtag->setShort(self::TAG_BURN_TICKS, 0);
}else{ }else{
$this->namedtag->CookTime->setValue(0); $this->namedtag->setShort(self::TAG_COOK_TIME, 0);
} }
$ret = true; $ret = true;
}else{ }else{
if($this->getBlock()->getId() === Block::BURNING_FURNACE){ if($this->getBlock()->getId() === Block::BURNING_FURNACE){
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FURNACE, $this->getBlock()->getDamage()), true); $this->getLevel()->setBlock($this, BlockFactory::get(Block::FURNACE, $this->getBlock()->getDamage()), true);
} }
$this->namedtag->BurnTime->setValue(0); $this->namedtag->setShort(self::TAG_BURN_TIME, 0);
$this->namedtag->CookTime->setValue(0); $this->namedtag->setShort(self::TAG_COOK_TIME, 0);
$this->namedtag->BurnTicks->setValue(0); $this->namedtag->setShort(self::TAG_BURN_TICKS, 0);
} }
foreach($this->getInventory()->getViewers() as $player){ foreach($this->getInventory()->getViewers() as $player){
@ -256,16 +272,15 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
$pk = new ContainerSetDataPacket(); $pk = new ContainerSetDataPacket();
$pk->windowId = $windowId; $pk->windowId = $windowId;
$pk->property = ContainerSetDataPacket::PROPERTY_FURNACE_TICK_COUNT; //Smelting $pk->property = ContainerSetDataPacket::PROPERTY_FURNACE_TICK_COUNT; //Smelting
$pk->value = $this->namedtag->CookTime->getValue(); $pk->value = $this->namedtag->getShort(self::TAG_COOK_TIME);
$player->dataPacket($pk); $player->dataPacket($pk);
$pk = new ContainerSetDataPacket(); $pk = new ContainerSetDataPacket();
$pk->windowId = $windowId; $pk->windowId = $windowId;
$pk->property = ContainerSetDataPacket::PROPERTY_FURNACE_LIT_TIME; $pk->property = ContainerSetDataPacket::PROPERTY_FURNACE_LIT_TIME;
$pk->value = $this->namedtag->BurnTicks->getValue(); $pk->value = $this->namedtag->getShort(self::TAG_BURN_TICKS);
$player->dataPacket($pk); $player->dataPacket($pk);
} }
} }
$this->timings->stopTiming(); $this->timings->stopTiming();
@ -274,19 +289,19 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->BurnTime = $this->namedtag->BurnTime; $nbt->setTag($this->namedtag->getTag(self::TAG_BURN_TIME));
$nbt->CookTime = $this->namedtag->CookTime; $nbt->setTag($this->namedtag->getTag(self::TAG_COOK_TIME));
if($this->hasName()){ if($this->hasName()){
$nbt->CustomName = $this->namedtag->CustomName; $nbt->setTag($this->namedtag->getTag("CustomName"));
} }
} }
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->Items = new ListTag("Items", [], NBT::TAG_Compound); $nbt->setTag(new ListTag("Items", [], NBT::TAG_Compound));
if($item !== null and $item->hasCustomName()){ if($item !== null and $item->hasCustomName()){
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName()); $nbt->setString("CustomName", $item->getCustomName());
} }
} }
} }

View File

@ -33,14 +33,17 @@ use pocketmine\nbt\tag\FloatTag;
use pocketmine\Player; use pocketmine\Player;
class ItemFrame extends Spawnable{ class ItemFrame extends Spawnable{
const TAG_ITEM_ROTATION = "ItemRotation";
const TAG_ITEM_DROP_CHANCE = "ItemDropChance";
const TAG_ITEM = "Item";
public function __construct(Level $level, CompoundTag $nbt){ public function __construct(Level $level, CompoundTag $nbt){
if(!isset($nbt->ItemRotation)){ if(!($nbt->getTag(self::TAG_ITEM_ROTATION) instanceof ByteTag)){
$nbt->ItemRotation = new ByteTag("ItemRotation", 0); $nbt->setTag(new ByteTag(self::TAG_ITEM_ROTATION, 0));
} }
if(!isset($nbt->ItemDropChance)){ if(!($nbt->getTag(self::TAG_ITEM_DROP_CHANCE) instanceof FloatTag)){
$nbt->ItemDropChance = new FloatTag("ItemDropChance", 1.0); $nbt->setTag(new FloatTag(self::TAG_ITEM_DROP_CHANCE, 1.0));
} }
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
@ -51,52 +54,52 @@ class ItemFrame extends Spawnable{
} }
public function getItem() : Item{ public function getItem() : Item{
if(isset($this->namedtag->Item)){ $c = $this->namedtag->getCompoundTag(self::TAG_ITEM);
return Item::nbtDeserialize($this->namedtag->Item); if($c !== null){
}else{ return Item::nbtDeserialize($c);
return ItemFactory::get(Item::AIR, 0, 0);
} }
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->Item = $item->nbtSerialize(-1, "Item"); $this->namedtag->setTag($item->nbtSerialize(-1, self::TAG_ITEM));
}else{ }else{
unset($this->namedtag->Item); $this->namedtag->removeTag(self::TAG_ITEM);
} }
$this->onChanged(); $this->onChanged();
} }
public function getItemRotation() : int{ public function getItemRotation() : int{
return $this->namedtag->ItemRotation->getValue(); return $this->namedtag->getByte(self::TAG_ITEM_ROTATION);
} }
public function setItemRotation(int $rotation){ public function setItemRotation(int $rotation){
$this->namedtag->ItemRotation->setValue($rotation); $this->namedtag->setByte(self::TAG_ITEM_ROTATION, $rotation);
$this->onChanged(); $this->onChanged();
} }
public function getItemDropChance() : float{ public function getItemDropChance() : float{
return $this->namedtag->ItemDropChance->getValue(); return $this->namedtag->getFloat(self::TAG_ITEM_DROP_CHANCE);
} }
public function setItemDropChance(float $chance){ public function setItemDropChance(float $chance){
$this->namedtag->ItemDropChance->setValue($chance); $this->namedtag->setFloat(self::TAG_ITEM_DROP_CHANCE, $chance);
$this->onChanged(); $this->onChanged();
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->ItemDropChance = $this->namedtag->ItemDropChance; $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_DROP_CHANCE));
$nbt->ItemRotation = $this->namedtag->ItemRotation; $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_ROTATION));
if($this->hasItem()){ if($this->hasItem()){
$nbt->Item = $this->namedtag->Item; $nbt->setTag($this->namedtag->getTag(self::TAG_ITEM));
} }
} }
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->ItemDropChance = new FloatTag("ItemDropChance", 1.0); $nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, 1.0);
$nbt->ItemRotation = new ByteTag("ItemRotation", 0); $nbt->setByte(self::TAG_ITEM_ROTATION, 0);
} }
} }

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
/** /**
* This trait implements most methods in the {@link Nameable} interface. It should only be used by Tiles. * This trait implements most methods in the {@link Nameable} interface. It should only be used by Tiles.
@ -46,7 +45,7 @@ trait NameableTrait{
*/ */
public function getName() : string{ public function getName() : string{
$nbt = $this->getNBT(); $nbt = $this->getNBT();
return isset($nbt->CustomName) ? ((string) $nbt->CustomName->getValue()) : $this->getDefaultName(); return $nbt->getString("CustomName") ?? $this->getDefaultName();
} }
/** /**
@ -55,17 +54,17 @@ trait NameableTrait{
public function setName(string $name) : void{ public function setName(string $name) : void{
$nbt = $this->getNBT(); $nbt = $this->getNBT();
if($name === ""){ if($name === ""){
unset($nbt->CustomName); $nbt->removeTag("CustomName");
return; return;
} }
$nbt->CustomName = new StringTag("CustomName", $name); $nbt->setString("CustomName", $name);
} }
/** /**
* @return bool * @return bool
*/ */
public function hasName() : bool{ public function hasName() : bool{
return isset($this->getNBT()->CustomName); return $this->getNBT()->hasTag("CustomName");
} }
} }

View File

@ -33,20 +33,24 @@ use pocketmine\Player;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
class Sign extends Spawnable{ class Sign extends Spawnable{
const TAG_TEXT_BLOB = "Text";
const TAG_TEXT_LINE = "Text%d"; //sprintf()able
const TAG_CREATOR = "Creator";
/** @var string[] */ /** @var string[] */
protected $text = ["", "", "", ""]; protected $text = ["", "", "", ""];
public function __construct(Level $level, CompoundTag $nbt){ public function __construct(Level $level, CompoundTag $nbt){
if(isset($nbt->Text)){ //MCPE 1.2 save format if($nbt->getTag(self::TAG_TEXT_BLOB) instanceof StringTag){ //MCPE 1.2 save format
$this->text = explode("\n", $nbt->Text->getValue()); $this->text = explode("\n", $nbt->getString(self::TAG_TEXT_BLOB));
unset($nbt->Text); assert(count($this->text) === 4, "Too many lines!");
$nbt->removeTag(self::TAG_TEXT_BLOB);
}else{ }else{
for($i = 1; $i <= 4; ++$i){ for($i = 1; $i <= 4; ++$i){
$textKey = "Text$i"; $textKey = sprintf(self::TAG_TEXT_LINE, $i);
if(isset($nbt->$textKey)){ if($nbt->getTag($textKey) instanceof StringTag){
$this->text[$i - 1] = $nbt->$textKey->getValue(); $this->text[$i - 1] = $nbt->getString($textKey);
unset($nbt->$textKey); $nbt->removeTag($textKey);
} }
} }
} }
@ -56,14 +60,14 @@ class Sign extends Spawnable{
public function saveNBT() : void{ public function saveNBT() : void{
parent::saveNBT(); parent::saveNBT();
$this->namedtag->Text = new StringTag("Text", implode("\n", $this->text)); $this->namedtag->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));
for($i = 1; $i <= 4; ++$i){ //Backwards-compatibility for($i = 1; $i <= 4; ++$i){ //Backwards-compatibility
$textKey = "Text$i"; $textKey = sprintf(self::TAG_TEXT_LINE, $i);
$this->namedtag->$textKey = new StringTag($textKey, $this->getLine($i - 1)); $this->namedtag->setString($textKey, $this->getLine($i - 1));
} }
unset($this->namedtag->Creator); $this->namedtag->removeTag(self::TAG_CREATOR);
} }
/** /**
@ -128,22 +132,22 @@ class Sign extends Spawnable{
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->Text = new StringTag("Text", implode("\n", $this->text)); $nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));
} }
public function updateCompoundTag(CompoundTag $nbt, Player $player) : bool{ public function updateCompoundTag(CompoundTag $nbt, Player $player) : bool{
if($nbt["id"] !== Tile::SIGN){ if($nbt->getString("id") !== Tile::SIGN){
return false; return false;
} }
if(isset($nbt->Text)){ if(($blob = $nbt->getString(self::TAG_TEXT_BLOB)) !== null){
$lines = array_pad(explode("\n", $nbt->Text->getValue()), 4, ""); $lines = array_pad(explode("\n", $blob), 4, "");
}else{ }else{
$lines = [ $lines = [
$nbt->Text1->getValue(), $nbt->getString(sprintf(self::TAG_TEXT_LINE, 1)),
$nbt->Text2->getValue(), $nbt->getString(sprintf(self::TAG_TEXT_LINE, 2)),
$nbt->Text3->getValue(), $nbt->getString(sprintf(self::TAG_TEXT_LINE, 3)),
$nbt->Text4->getValue() $nbt->getString(sprintf(self::TAG_TEXT_LINE, 4))
]; ];
} }
@ -151,7 +155,7 @@ class Sign extends Spawnable{
$ev = new SignChangeEvent($this->getBlock(), $player, array_map(function(string $line) use ($removeFormat){ return TextFormat::clean($line, $removeFormat); }, $lines)); $ev = new SignChangeEvent($this->getBlock(), $player, array_map(function(string $line) use ($removeFormat){ return TextFormat::clean($line, $removeFormat); }, $lines));
if(!isset($this->namedtag->Creator) or $this->namedtag->Creator->getValue() !== $player->getRawUniqueId()){ if(($creatorUUID = $this->namedtag->getString(self::TAG_CREATOR)) !== null and $creatorUUID !== $player->getRawUniqueId()){
$ev->setCancelled(); $ev->setCancelled();
} }
@ -168,12 +172,11 @@ class Sign extends Spawnable{
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{
for($i = 1; $i <= 4; ++$i){ for($i = 1; $i <= 4; ++$i){
$key = "Text$i"; $nbt->setString(sprintf(self::TAG_TEXT_LINE, $i), "");
$nbt->$key = new StringTag($key, "");
} }
if($player !== null){ if($player !== null){
$nbt->Creator = new StringTag("Creator", $player->getRawUniqueId()); $nbt->setString(self::TAG_CREATOR, $player->getRawUniqueId());
} }
} }

View File

@ -38,37 +38,40 @@ class Skull extends Spawnable{
const TYPE_CREEPER = 4; const TYPE_CREEPER = 4;
const TYPE_DRAGON = 5; const TYPE_DRAGON = 5;
const TAG_SKULL_TYPE = "SkullType";
const TAG_ROT = "Rot";
public function __construct(Level $level, CompoundTag $nbt){ public function __construct(Level $level, CompoundTag $nbt){
if(!isset($nbt->SkullType)){ if(!($nbt->getTag(self::TAG_SKULL_TYPE) instanceof ByteTag)){
$nbt->SkullType = new ByteTag("SkullType", 0); $nbt->setTag(new ByteTag(self::TAG_SKULL_TYPE, 0));
} }
if(!isset($nbt->Rot)){ if(!($nbt->getTag(self::TAG_ROT) instanceof ByteTag)){
$nbt->Rot = new ByteTag("Rot", 0); $nbt->setTag(new ByteTag(self::TAG_ROT, 0));
} }
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
} }
public function setType(int $type){ public function setType(int $type){
$this->namedtag->SkullType->setValue($type); $this->namedtag->setByte(self::TAG_SKULL_TYPE, $type);
$this->onChanged(); $this->onChanged();
} }
public function getType() : int{ public function getType() : int{
return $this->namedtag->SkullType->getValue(); return $this->namedtag->getByte(self::TAG_SKULL_TYPE);
} }
public function addAdditionalSpawnData(CompoundTag $nbt) : void{ public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->SkullType = $this->namedtag->SkullType; $nbt->setTag($this->namedtag->getTag(self::TAG_SKULL_TYPE));
$nbt->Rot = $this->namedtag->Rot; $nbt->setTag($this->namedtag->getTag(self::TAG_ROT));
} }
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->SkullType = new ByteTag("SkullType", $item !== null ? $item->getDamage() : self::TYPE_SKELETON); $nbt->setByte(self::TAG_SKULL_TYPE, $item !== null ? $item->getDamage() : self::TYPE_SKELETON);
$rot = 0; $rot = 0;
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->Rot = new ByteTag("Rot", $rot); $nbt->setByte("Rot", $rot);
} }
} }

View File

@ -81,10 +81,10 @@ abstract class Spawnable extends Tile{
*/ */
final public function getSpawnCompound() : CompoundTag{ final public function getSpawnCompound() : CompoundTag{
$nbt = new CompoundTag("", [ $nbt = new CompoundTag("", [
$this->namedtag->id, $this->namedtag->getTag("id"),
$this->namedtag->x, $this->namedtag->getTag("x"),
$this->namedtag->y, $this->namedtag->getTag("y"),
$this->namedtag->z $this->namedtag->getTag("z")
]); ]);
$this->addAdditionalSpawnData($nbt); $this->addAdditionalSpawnData($nbt);
return $nbt; return $nbt;

View File

@ -136,14 +136,14 @@ abstract class Tile extends Position{
$this->namedtag = $nbt; $this->namedtag = $nbt;
$this->server = $level->getServer(); $this->server = $level->getServer();
$this->setLevel($level); $this->setLevel($level);
$this->chunk = $level->getChunk($this->namedtag->x->getValue() >> 4, $this->namedtag->z->getValue() >> 4, false); $this->chunk = $level->getChunk($this->namedtag->getInt("x") >> 4, $this->namedtag->getInt("z") >> 4, false);
assert($this->chunk !== null); assert($this->chunk !== null);
$this->name = ""; $this->name = "";
$this->id = Tile::$tileCount++; $this->id = Tile::$tileCount++;
$this->x = $this->namedtag->x->getValue(); $this->x = $this->namedtag->getInt("x");
$this->y = $this->namedtag->y->getValue(); $this->y = $this->namedtag->getInt("y");
$this->z = $this->namedtag->z->getValue(); $this->z = $this->namedtag->getInt("z");
$this->chunk->addTile($this); $this->chunk->addTile($this);
$this->getLevel()->addTile($this); $this->getLevel()->addTile($this);
@ -154,10 +154,10 @@ abstract class Tile extends Position{
} }
public function saveNBT() : void{ public function saveNBT() : void{
$this->namedtag->id->setValue(static::getSaveId()); $this->namedtag->setString("id", static::getSaveId());
$this->namedtag->x->setValue($this->x); $this->namedtag->setInt("x", $this->x);
$this->namedtag->y->setValue($this->y); $this->namedtag->setInt("y", $this->y);
$this->namedtag->z->setValue($this->z); $this->namedtag->setInt("z", $this->z);
} }
public function getNBT() : CompoundTag{ public function getNBT() : CompoundTag{
@ -167,7 +167,7 @@ abstract class Tile extends Position{
public function getCleanedNBT() : ?CompoundTag{ public function getCleanedNBT() : ?CompoundTag{
$this->saveNBT(); $this->saveNBT();
$tag = clone $this->namedtag; $tag = clone $this->namedtag;
unset($tag->x, $tag->y, $tag->z, $tag->id); $tag->removeTag("x", "y", "z", "id");
if($tag->getCount() > 0){ if($tag->getCount() > 0){
return $tag; return $tag;
}else{ }else{