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;
class Bed extends Spawnable{
const TAG_COLOR = "color";
public function __construct(Level $level, CompoundTag $nbt){
if(!isset($nbt->color) or !($nbt->color instanceof ByteTag)){
$nbt->color = new ByteTag("color", 14); //default to old red
if(!($nbt->getTag(self::TAG_COLOR) instanceof ByteTag)){
$nbt->setTag(new ByteTag(self::TAG_COLOR, 14)); //default to old red
}
parent::__construct($level, $nbt);
}
public function getColor() : int{
return $this->namedtag->color->getValue();
return $this->namedtag->getByte(self::TAG_COLOR);
}
public function setColor(int $color){
$this->namedtag->color->setValue($color & 0x0f);
$this->namedtag->setByte(self::TAG_COLOR, $color & 0x0f);
$this->onChanged();
}
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{
$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\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
use NameableTrait;
const TAG_PAIRX = "pairx";
const TAG_PAIRZ = "pairz";
const TAG_PAIR_LEAD = "pairlead";
/** @var ChestInventory */
protected $inventory;
/** @var DoubleChestInventory */
@ -49,8 +51,8 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
parent::__construct($level, $nbt);
$this->inventory = new ChestInventory($this);
if(!isset($this->namedtag->Items) or !($this->namedtag->Items instanceof ListTag)){
$this->namedtag->Items = new ListTag("Items", [], NBT::TAG_Compound);
if(!($this->namedtag->getTag("Items") instanceof ListTag)){
$this->namedtag->setTag(new ListTag("Items", [], NBT::TAG_Compound));
}
for($i = 0; $i < $this->getSize(); ++$i){
@ -75,7 +77,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
}
public function saveNBT() : void{
$this->namedtag->Items->setValue([]);
$this->namedtag->setTag(new ListTag("Items", [], NBT::TAG_Compound));
for($index = 0; $index < $this->getSize(); ++$index){
$this->setItem($index, $this->inventory->getItem($index));
}
@ -94,8 +96,11 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
* @return int
*/
protected function getSlotIndex(int $index) : int{
foreach($this->namedtag->Items as $i => $slot){
if($slot->Slot->getValue() === $index){
$items = $this->namedtag->getListTag("Items");
assert($items instanceof ListTag);
foreach($items as $i => $slot){
/** @var CompoundTag $slot */
if($slot->getByte("Slot") === $index){
return (int) $i;
}
}
@ -115,7 +120,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
if($i < 0){
return ItemFactory::get(Item::AIR, 0, 0);
}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);
$items = $this->namedtag->getListTag("Items");
assert($items instanceof ListTag);
if($item->isNull()){
if($i >= 0){
unset($this->namedtag->Items[$i]);
unset($items[$i]);
}
}elseif($i < 0){
for($i = 0; $i <= $this->getSize(); ++$i){
if(!isset($this->namedtag->Items[$i])){
if(!isset($items[$i])){
break;
}
}
$this->namedtag->Items[$i] = $d;
$items[$i] = $d;
}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(){
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
$this->doubleInventory = null;
@ -182,7 +192,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
}
}else{
$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(){
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{
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){
return $tile;
}
@ -226,11 +236,11 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
}
private function createPair(Chest $tile){
$this->namedtag->pairx = new IntTag("pairx", $tile->x);
$this->namedtag->pairz = new IntTag("pairz", $tile->z);
$this->namedtag->setInt(self::TAG_PAIRX, $tile->x);
$this->namedtag->setInt(self::TAG_PAIRZ, $tile->z);
$tile->namedtag->pairx = new IntTag("pairx", $this->x);
$tile->namedtag->pairz = new IntTag("pairz", $this->z);
$tile->namedtag->setInt(self::TAG_PAIRX, $this->x);
$tile->namedtag->setInt(self::TAG_PAIRZ, $this->z);
}
public function unpair(){
@ -239,12 +249,12 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
}
$tile = $this->getPair();
unset($this->namedtag->pairx, $this->namedtag->pairz);
$this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
$this->spawnToAll();
if($tile instanceof Chest){
unset($tile->namedtag->pairx, $tile->namedtag->pairz);
$tile->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
$tile->checkPairing();
$tile->spawnToAll();
}
@ -255,20 +265,20 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
public function addAdditionalSpawnData(CompoundTag $nbt) : void{
if($this->isPaired()){
$nbt->pairx = $this->namedtag->pairx;
$nbt->pairz = $this->namedtag->pairz;
$nbt->setTag($this->namedtag->getTag(self::TAG_PAIRX));
$nbt->setTag($this->namedtag->getTag(self::TAG_PAIRZ));
}
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{
$nbt->Items = new ListTag("Items", [], NBT::TAG_Compound);
$nbt->setTag(new ListTag("Items", [], NBT::TAG_Compound));
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\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
class EnchantTable extends Spawnable implements Nameable{
@ -41,13 +40,13 @@ class EnchantTable extends Spawnable implements Nameable{
public function addAdditionalSpawnData(CompoundTag $nbt) : void{
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{
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;
class FlowerPot extends Spawnable{
const TAG_ITEM = "item";
const TAG_ITEM_DATA = "mData";
public function __construct(Level $level, CompoundTag $nbt){
if(!isset($nbt->item)){
$nbt->item = new ShortTag("item", 0);
if(!($nbt->getTag(self::TAG_ITEM) instanceof ShortTag)){
$nbt->setTag(new ShortTag(self::TAG_ITEM, 0));
}
if(!isset($nbt->mData)){
$nbt->mData = new IntTag("mData", 0);
if(!($nbt->getTag(self::TAG_ITEM_DATA) instanceof IntTag)){
$nbt->setTag(new IntTag(self::TAG_ITEM_DATA, 0));
}
parent::__construct($level, $nbt);
}
@ -68,12 +70,12 @@ class FlowerPot extends Spawnable{
}
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){
$this->namedtag->item->setValue($item->getId());
$this->namedtag->mData->setValue($item->getDamage());
$this->namedtag->setShort(self::TAG_ITEM, $item->getId());
$this->namedtag->setInt(self::TAG_ITEM_DATA, $item->getDamage());
$this->onChanged();
}
@ -86,12 +88,12 @@ class FlowerPot extends Spawnable{
}
public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->item = $this->namedtag->item;
$nbt->mData = $this->namedtag->mData;
$nbt->setTag($this->namedtag->getTag(self::TAG_ITEM));
$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{
$nbt->item = new ShortTag("item", 0);
$nbt->mData = new IntTag("mData", 0);
$nbt->setShort(self::TAG_ITEM, 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\ListTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
use pocketmine\Player;
class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
use NameableTrait;
const TAG_BURN_TIME = "BurnTime";
const TAG_COOK_TIME = "CookTime";
const TAG_MAX_TIME = "MaxTime";
const TAG_BURN_TICKS = "BurnTicks";
/** @var FurnaceInventory */
protected $inventory;
public function __construct(Level $level, CompoundTag $nbt){
if(!isset($nbt->BurnTime) or $nbt->BurnTime->getValue() < 0){
$nbt->BurnTime = new ShortTag("BurnTime", 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(!($nbt->getTag(self::TAG_BURN_TIME) instanceof ShortTag) or $nbt->getShort(self::TAG_BURN_TIME) < 0){
$nbt->setTag(new ShortTag(self::TAG_BURN_TIME, 0));
}
if(!isset($nbt->BurnTicks)){
$nbt->BurnTicks = new ShortTag("BurnTicks", 0);
if(!
($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);
$this->inventory = new FurnaceInventory($this);
if(!isset($this->namedtag->Items) or !($this->namedtag->Items instanceof ListTag)){
$this->namedtag->Items = new ListTag("Items", [], NBT::TAG_Compound);
if(!($this->namedtag->getTag("Items") instanceof ListTag)){
$this->namedtag->setTag(new ListTag("Items", [], NBT::TAG_Compound));
}
for($i = 0; $i < $this->getSize(); ++$i){
$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();
}
}
@ -97,7 +107,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
}
public function saveNBT() : void{
$this->namedtag->Items->setValue([]);
$this->namedtag->setTag(new ListTag("Items", [], NBT::TAG_Compound));
for($index = 0; $index < $this->getSize(); ++$index){
$this->setItem($index, $this->inventory->getItem($index));
}
@ -116,8 +126,9 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
* @return int
*/
protected function getSlotIndex(int $index) : int{
foreach($this->namedtag->Items as $i => $slot){
if($slot->Slot->getValue() === $index){
foreach($this->namedtag->getListTag("Items") as $i => $slot){
/** @var CompoundTag $slot */
if($slot->getByte("Slot") === $index){
return (int) $i;
}
}
@ -137,7 +148,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
if($i < 0){
return ItemFactory::get(Item::AIR, 0, 0);
}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);
$items = $this->namedtag->getListTag("Items");
assert($items instanceof ListTag);
if($item->isNull()){
if($i >= 0){
unset($this->namedtag->Items[$i]);
unset($items[$i]);
}
}elseif($i < 0){
for($i = 0; $i <= $this->getSize(); ++$i){
if(!isset($this->namedtag->Items[$i])){
if(!isset($items[$i])){
break;
}
}
$this->namedtag->Items[$i] = $d;
$items[$i] = $d;
}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;
}
$this->namedtag->MaxTime->setValue($ev->getBurnTime());
$this->namedtag->BurnTime->setValue($ev->getBurnTime());
$this->namedtag->BurnTicks->setValue(0);
$this->namedtag->setShort(self::TAG_MAX_TIME, $ev->getBurnTime());
$this->namedtag->setShort(self::TAG_BURN_TIME, $ev->getBurnTime());
$this->namedtag->setShort(self::TAG_BURN_TICKS, 0);
if($this->getBlock()->getId() === Block::FURNACE){
$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();
$this->inventory->setFuel($fuel);
}
@ -210,17 +226,17 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
$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()));
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);
}
if($this->namedtag->BurnTime->getValue() > 0){
$this->namedtag->BurnTime->setValue($this->namedtag->BurnTime->getValue() - 1);
$this->namedtag->BurnTicks->setValue((int) ceil($this->namedtag->BurnTime->getValue() / $this->namedtag->MaxTime->getValue() * 200));
if($this->namedtag->getShort(self::TAG_BURN_TIME) > 0){
$this->namedtag->setShort(self::TAG_BURN_TIME, $this->namedtag->getShort(self::TAG_BURN_TIME) - 1);
$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){
$this->namedtag->CookTime->setValue($this->namedtag->CookTime->getValue() + 1);
if($this->namedtag->CookTime->getValue() >= 200){ //10 seconds
$this->namedtag->setShort(self::TAG_COOK_TIME, $this->namedtag->getShort(self::TAG_COOK_TIME) + 1);
if($this->namedtag->getShort(self::TAG_COOK_TIME) >= 200){ //10 seconds
$product = ItemFactory::get($smelt->getResult()->getId(), $smelt->getResult()->getDamage(), $product->getCount() + 1);
$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->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){
$this->namedtag->BurnTime->setValue(0);
$this->namedtag->CookTime->setValue(0);
$this->namedtag->BurnTicks->setValue(0);
}elseif($this->namedtag->getShort(self::TAG_BURN_TIME) <= 0){
$this->namedtag->setShort(self::TAG_BURN_TIME, 0);
$this->namedtag->setShort(self::TAG_COOK_TIME, 0);
$this->namedtag->setShort(self::TAG_BURN_TICKS, 0);
}else{
$this->namedtag->CookTime->setValue(0);
$this->namedtag->setShort(self::TAG_COOK_TIME, 0);
}
$ret = true;
}else{
if($this->getBlock()->getId() === Block::BURNING_FURNACE){
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FURNACE, $this->getBlock()->getDamage()), true);
}
$this->namedtag->BurnTime->setValue(0);
$this->namedtag->CookTime->setValue(0);
$this->namedtag->BurnTicks->setValue(0);
$this->namedtag->setShort(self::TAG_BURN_TIME, 0);
$this->namedtag->setShort(self::TAG_COOK_TIME, 0);
$this->namedtag->setShort(self::TAG_BURN_TICKS, 0);
}
foreach($this->getInventory()->getViewers() as $player){
@ -256,16 +272,15 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
$pk = new ContainerSetDataPacket();
$pk->windowId = $windowId;
$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);
$pk = new ContainerSetDataPacket();
$pk->windowId = $windowId;
$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);
}
}
$this->timings->stopTiming();
@ -274,19 +289,19 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
}
public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->BurnTime = $this->namedtag->BurnTime;
$nbt->CookTime = $this->namedtag->CookTime;
$nbt->setTag($this->namedtag->getTag(self::TAG_BURN_TIME));
$nbt->setTag($this->namedtag->getTag(self::TAG_COOK_TIME));
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{
$nbt->Items = new ListTag("Items", [], NBT::TAG_Compound);
$nbt->setTag(new ListTag("Items", [], NBT::TAG_Compound));
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;
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){
if(!isset($nbt->ItemRotation)){
$nbt->ItemRotation = new ByteTag("ItemRotation", 0);
if(!($nbt->getTag(self::TAG_ITEM_ROTATION) instanceof ByteTag)){
$nbt->setTag(new ByteTag(self::TAG_ITEM_ROTATION, 0));
}
if(!isset($nbt->ItemDropChance)){
$nbt->ItemDropChance = new FloatTag("ItemDropChance", 1.0);
if(!($nbt->getTag(self::TAG_ITEM_DROP_CHANCE) instanceof FloatTag)){
$nbt->setTag(new FloatTag(self::TAG_ITEM_DROP_CHANCE, 1.0));
}
parent::__construct($level, $nbt);
@ -51,52 +54,52 @@ class ItemFrame extends Spawnable{
}
public function getItem() : Item{
if(isset($this->namedtag->Item)){
return Item::nbtDeserialize($this->namedtag->Item);
}else{
return ItemFactory::get(Item::AIR, 0, 0);
$c = $this->namedtag->getCompoundTag(self::TAG_ITEM);
if($c !== null){
return Item::nbtDeserialize($c);
}
return ItemFactory::get(Item::AIR, 0, 0);
}
public function setItem(Item $item = null){
if($item !== null and !$item->isNull()){
$this->namedtag->Item = $item->nbtSerialize(-1, "Item");
$this->namedtag->setTag($item->nbtSerialize(-1, self::TAG_ITEM));
}else{
unset($this->namedtag->Item);
$this->namedtag->removeTag(self::TAG_ITEM);
}
$this->onChanged();
}
public function getItemRotation() : int{
return $this->namedtag->ItemRotation->getValue();
return $this->namedtag->getByte(self::TAG_ITEM_ROTATION);
}
public function setItemRotation(int $rotation){
$this->namedtag->ItemRotation->setValue($rotation);
$this->namedtag->setByte(self::TAG_ITEM_ROTATION, $rotation);
$this->onChanged();
}
public function getItemDropChance() : float{
return $this->namedtag->ItemDropChance->getValue();
return $this->namedtag->getFloat(self::TAG_ITEM_DROP_CHANCE);
}
public function setItemDropChance(float $chance){
$this->namedtag->ItemDropChance->setValue($chance);
$this->namedtag->setFloat(self::TAG_ITEM_DROP_CHANCE, $chance);
$this->onChanged();
}
public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->ItemDropChance = $this->namedtag->ItemDropChance;
$nbt->ItemRotation = $this->namedtag->ItemRotation;
$nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_DROP_CHANCE));
$nbt->setTag($this->namedtag->getTag(self::TAG_ITEM_ROTATION));
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{
$nbt->ItemDropChance = new FloatTag("ItemDropChance", 1.0);
$nbt->ItemRotation = new ByteTag("ItemRotation", 0);
$nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, 1.0);
$nbt->setByte(self::TAG_ITEM_ROTATION, 0);
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\tile;
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.
@ -46,7 +45,7 @@ trait NameableTrait{
*/
public function getName() : string{
$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{
$nbt = $this->getNBT();
if($name === ""){
unset($nbt->CustomName);
$nbt->removeTag("CustomName");
return;
}
$nbt->CustomName = new StringTag("CustomName", $name);
$nbt->setString("CustomName", $name);
}
/**
* @return 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;
class Sign extends Spawnable{
const TAG_TEXT_BLOB = "Text";
const TAG_TEXT_LINE = "Text%d"; //sprintf()able
const TAG_CREATOR = "Creator";
/** @var string[] */
protected $text = ["", "", "", ""];
public function __construct(Level $level, CompoundTag $nbt){
if(isset($nbt->Text)){ //MCPE 1.2 save format
$this->text = explode("\n", $nbt->Text->getValue());
unset($nbt->Text);
if($nbt->getTag(self::TAG_TEXT_BLOB) instanceof StringTag){ //MCPE 1.2 save format
$this->text = explode("\n", $nbt->getString(self::TAG_TEXT_BLOB));
assert(count($this->text) === 4, "Too many lines!");
$nbt->removeTag(self::TAG_TEXT_BLOB);
}else{
for($i = 1; $i <= 4; ++$i){
$textKey = "Text$i";
if(isset($nbt->$textKey)){
$this->text[$i - 1] = $nbt->$textKey->getValue();
unset($nbt->$textKey);
$textKey = sprintf(self::TAG_TEXT_LINE, $i);
if($nbt->getTag($textKey) instanceof StringTag){
$this->text[$i - 1] = $nbt->getString($textKey);
$nbt->removeTag($textKey);
}
}
}
@ -56,14 +60,14 @@ class Sign extends Spawnable{
public function saveNBT() : void{
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
$textKey = "Text$i";
$this->namedtag->$textKey = new StringTag($textKey, $this->getLine($i - 1));
$textKey = sprintf(self::TAG_TEXT_LINE, $i);
$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{
$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{
if($nbt["id"] !== Tile::SIGN){
if($nbt->getString("id") !== Tile::SIGN){
return false;
}
if(isset($nbt->Text)){
$lines = array_pad(explode("\n", $nbt->Text->getValue()), 4, "");
if(($blob = $nbt->getString(self::TAG_TEXT_BLOB)) !== null){
$lines = array_pad(explode("\n", $blob), 4, "");
}else{
$lines = [
$nbt->Text1->getValue(),
$nbt->Text2->getValue(),
$nbt->Text3->getValue(),
$nbt->Text4->getValue()
$nbt->getString(sprintf(self::TAG_TEXT_LINE, 1)),
$nbt->getString(sprintf(self::TAG_TEXT_LINE, 2)),
$nbt->getString(sprintf(self::TAG_TEXT_LINE, 3)),
$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));
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();
}
@ -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{
for($i = 1; $i <= 4; ++$i){
$key = "Text$i";
$nbt->$key = new StringTag($key, "");
$nbt->setString(sprintf(self::TAG_TEXT_LINE, $i), "");
}
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_DRAGON = 5;
const TAG_SKULL_TYPE = "SkullType";
const TAG_ROT = "Rot";
public function __construct(Level $level, CompoundTag $nbt){
if(!isset($nbt->SkullType)){
$nbt->SkullType = new ByteTag("SkullType", 0);
if(!($nbt->getTag(self::TAG_SKULL_TYPE) instanceof ByteTag)){
$nbt->setTag(new ByteTag(self::TAG_SKULL_TYPE, 0));
}
if(!isset($nbt->Rot)){
$nbt->Rot = new ByteTag("Rot", 0);
if(!($nbt->getTag(self::TAG_ROT) instanceof ByteTag)){
$nbt->setTag(new ByteTag(self::TAG_ROT, 0));
}
parent::__construct($level, $nbt);
}
public function setType(int $type){
$this->namedtag->SkullType->setValue($type);
$this->namedtag->setByte(self::TAG_SKULL_TYPE, $type);
$this->onChanged();
}
public function getType() : int{
return $this->namedtag->SkullType->getValue();
return $this->namedtag->getByte(self::TAG_SKULL_TYPE);
}
public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->SkullType = $this->namedtag->SkullType;
$nbt->Rot = $this->namedtag->Rot;
$nbt->setTag($this->namedtag->getTag(self::TAG_SKULL_TYPE));
$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{
$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;
if($face === Vector3::SIDE_UP and $player !== null){
$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{
$nbt = new CompoundTag("", [
$this->namedtag->id,
$this->namedtag->x,
$this->namedtag->y,
$this->namedtag->z
$this->namedtag->getTag("id"),
$this->namedtag->getTag("x"),
$this->namedtag->getTag("y"),
$this->namedtag->getTag("z")
]);
$this->addAdditionalSpawnData($nbt);
return $nbt;

View File

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