Tiles no longer store their NBT at runtime

This is a significant breaking change for anything utilizing Tiles as they now do not store their NBT at runtime anymore.
This is another step in the process of ridding PocketMine-MP of runtime NBT.

It can be noticed that all tiles are now using class fields to store properties instead of NBT, which is much faster, uses less memory and is also more concise when written in code.

Highlights:
- Tile->namedtag has been removed.
- Tile->saveNBT() now accepts a CompoundTag() parameter. Typically it's expected that this will be fed a newly-created CompoundTag (this part may be improved in the future).
- New internal methods Tile->readSaveData() and Tile->writeSaveData() have been added. Instead of overriding __construct() and saveNBT() to load and save properties from NBT, you should now implement these methods instead.

This is not final and will see further changes before it's done.
This commit is contained in:
Dylan K. Taylor 2018-06-03 18:29:08 +01:00
parent a22e5616f6
commit fa21cd96c5
14 changed files with 96 additions and 131 deletions

View File

@ -456,8 +456,8 @@ class LevelDB extends BaseLevelProvider{
$tiles = [];
foreach($chunk->getTiles() as $tile){
if(!$tile->isClosed()){
$tile->saveNBT();
$tiles[] = $tile->namedtag;
$tile->saveNBT($tileTag = new CompoundTag());
$tiles[] = $tileTag;
}
}
$this->writeTags($tiles, $index . self::TAG_BLOCK_ENTITY);

View File

@ -75,8 +75,8 @@ class Anvil extends McRegion{
$tiles = [];
foreach($chunk->getTiles() as $tile){
$tile->saveNBT();
$tiles[] = $tile->namedtag;
$tile->saveNBT($tileTag = new CompoundTag());
$tiles[] = $tileTag;
}
$nbt->setTag(new ListTag("TileEntities", $tiles, NBT::TAG_Compound));

View File

@ -94,8 +94,8 @@ class McRegion extends BaseLevelProvider{
$tiles = [];
foreach($chunk->getTiles() as $tile){
$tile->saveNBT();
$tiles[] = $tile->namedtag;
$tile->saveNBT($tileTag = new CompoundTag());
$tiles[] = $tileTag;
}
$nbt->setTag(new ListTag("TileEntities", $tiles, NBT::TAG_Compound));

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\tile;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
@ -107,19 +106,16 @@ class Banner extends Spawnable implements Nameable{
*/
private $patterns;
public function __construct(Level $level, CompoundTag $nbt){
protected function readSaveData(CompoundTag $nbt) : void{
$this->baseColor = $nbt->getInt(self::TAG_BASE, self::COLOR_BLACK, true);
$this->patterns = $nbt->getListTag(self::TAG_PATTERNS) ?? new ListTag(self::TAG_PATTERNS);
$nbt->removeTag(self::TAG_BASE, self::TAG_PATTERNS);
$this->loadName($nbt);
parent::__construct($level, $nbt);
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setInt(self::TAG_BASE, $this->baseColor);
$this->namedtag->setTag($this->patterns);
$this->saveName($this->namedtag);
protected function writeSaveData(CompoundTag $nbt) : void{
$nbt->setInt(self::TAG_BASE, $this->baseColor);
$nbt->setTag($this->patterns);
$this->saveName($nbt);
}
public function addAdditionalSpawnData(CompoundTag $nbt) : void{

View File

@ -25,7 +25,6 @@ namespace pocketmine\tile;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player;
@ -35,13 +34,6 @@ class Bed extends Spawnable{
/** @var int */
private $color = 14; //default to old red
public function __construct(Level $level, CompoundTag $nbt){
$this->color = $nbt->getByte(self::TAG_COLOR, 14, true);
$nbt->removeTag(self::TAG_COLOR);
parent::__construct($level, $nbt);
}
public function getColor() : int{
return $this->color;
}
@ -51,13 +43,16 @@ class Bed extends Spawnable{
$this->onChanged();
}
public function addAdditionalSpawnData(CompoundTag $nbt) : void{
protected function readSaveData(CompoundTag $nbt) : void{
$this->color = $nbt->getByte(self::TAG_COLOR, 14, true);
}
protected function writeSaveData(CompoundTag $nbt) : void{
$nbt->setByte(self::TAG_COLOR, $this->color);
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setByte(self::TAG_COLOR, $this->color);
public function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->setByte(self::TAG_COLOR, $this->color);
}
protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{

View File

@ -26,7 +26,6 @@ namespace pocketmine\tile;
use pocketmine\inventory\ChestInventory;
use pocketmine\inventory\DoubleChestInventory;
use pocketmine\inventory\InventoryHolder;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
@ -50,19 +49,26 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
/** @var int|null */
private $pairZ;
public function __construct(Level $level, CompoundTag $nbt){
protected function readSaveData(CompoundTag $nbt) : void{
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);
$this->loadName($nbt);
parent::__construct($level, $nbt);
$this->inventory = new ChestInventory($this);
$this->loadItems($this->namedtag);
$this->loadItems($nbt);
}
protected function writeSaveData(CompoundTag $nbt) : void{
if($this->isPaired()){
$nbt->setInt(self::TAG_PAIRX, $this->pairX);
$nbt->setInt(self::TAG_PAIRZ, $this->pairZ);
}else{
$nbt->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
}
$this->saveName($nbt);
$this->saveItems($nbt);
}
public function close() : void{
@ -81,18 +87,6 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
}
}
public function saveNBT() : void{
parent::saveNBT();
if($this->isPaired()){
$this->namedtag->setInt(self::TAG_PAIRX, $this->pairX);
$this->namedtag->setInt(self::TAG_PAIRZ, $this->pairZ);
}else{
$this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
}
$this->saveItems($this->namedtag);
$this->saveName($this->namedtag);
}
/**
* @return ChestInventory|DoubleChestInventory
*/

View File

@ -23,20 +23,10 @@ declare(strict_types=1);
namespace pocketmine\tile;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
class EnchantTable extends Spawnable implements Nameable{
use NameableTrait;
public function __construct(Level $level, CompoundTag $nbt){
$this->loadName($nbt);
parent::__construct($level, $nbt);
}
public function saveNBT() : void{
parent::saveNBT();
$this->saveName($this->namedtag);
use NameableTrait{
loadName as readSaveData;
saveName as writeSaveData;
}
/**

View File

@ -27,6 +27,14 @@ use pocketmine\nbt\tag\CompoundTag;
class EnderChest extends Spawnable{
protected function readSaveData(CompoundTag $nbt) : void{
}
protected function writeSaveData(CompoundTag $nbt) : void{
}
public function addAdditionalSpawnData(CompoundTag $nbt) : void{
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\tile;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
class FlowerPot extends Spawnable{
@ -35,17 +34,13 @@ class FlowerPot extends Spawnable{
/** @var Item */
private $item;
public function __construct(Level $level, CompoundTag $nbt){
//TODO: check PC format
protected function readSaveData(CompoundTag $nbt) : void{
$this->item = ItemFactory::get($nbt->getShort(self::TAG_ITEM, 0, true), $nbt->getInt(self::TAG_ITEM_DATA, 0, true), 1);
$nbt->removeTag(self::TAG_ITEM, self::TAG_ITEM_DATA);
parent::__construct($level, $nbt);
}
public function saveNBT() : void{
$this->namedtag->setShort(self::TAG_ITEM, $this->item->getId());
$this->namedtag->setInt(self::TAG_ITEM_DATA, $this->item->getDamage());
protected function writeSaveData(CompoundTag $nbt) : void{
$nbt->setShort(self::TAG_ITEM, $this->item->getId());
$nbt->setInt(self::TAG_ITEM_DATA, $this->item->getDamage());
}
public function canAddItem(Item $item) : bool{

View File

@ -56,6 +56,13 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
private $maxTime;
public function __construct(Level $level, CompoundTag $nbt){
parent::__construct($level, $nbt);
if($this->burnTime > 0){
$this->scheduleUpdate();
}
}
protected function readSaveData(CompoundTag $nbt) : void{
$this->burnTime = max(0, $nbt->getShort(self::TAG_BURN_TIME, 0, true));
$this->cookTime = $nbt->getShort(self::TAG_COOK_TIME, 0, true);
@ -70,14 +77,16 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
$this->loadName($nbt);
parent::__construct($level, $nbt);
$this->inventory = new FurnaceInventory($this);
$this->loadItems($this->namedtag);
$this->loadItems($nbt);
}
if($this->burnTime > 0){
$this->scheduleUpdate();
}
protected function writeSaveData(CompoundTag $nbt) : void{
$nbt->setShort(self::TAG_BURN_TIME, $this->burnTime);
$nbt->setShort(self::TAG_COOK_TIME, $this->cookTime);
$nbt->setShort(self::TAG_MAX_TIME, $this->maxTime);
$this->saveName($nbt);
$this->saveItems($nbt);
}
/**
@ -96,16 +105,6 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
}
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setShort(self::TAG_BURN_TIME, $this->burnTime);
$this->namedtag->setShort(self::TAG_COOK_TIME, $this->cookTime);
$this->namedtag->setShort(self::TAG_MAX_TIME, $this->maxTime);
$this->saveItems($this->namedtag);
$this->saveName($this->namedtag);
}
/**
* @return FurnaceInventory
*/

View File

@ -25,7 +25,6 @@ namespace pocketmine\tile;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
class ItemFrame extends Spawnable{
@ -40,7 +39,7 @@ class ItemFrame extends Spawnable{
/** @var float */
private $itemDropChance;
public function __construct(Level $level, CompoundTag $nbt){
protected function readSaveData(CompoundTag $nbt) : void{
if(($itemTag = $nbt->getCompoundTag(self::TAG_ITEM)) !== null){
$this->item = Item::nbtDeserialize($itemTag);
}else{
@ -48,16 +47,12 @@ class ItemFrame extends Spawnable{
}
$this->itemRotation = $nbt->getByte(self::TAG_ITEM_ROTATION, 0, true);
$this->itemDropChance = $nbt->getFloat(self::TAG_ITEM_DROP_CHANCE, 1.0, true);
$nbt->removeTag(self::TAG_ITEM, self::TAG_ITEM_ROTATION, self::TAG_ITEM_DROP_CHANCE);
parent::__construct($level, $nbt);
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance);
$this->namedtag->setByte(self::TAG_ITEM_ROTATION, $this->itemRotation);
$this->namedtag->setTag($this->item->nbtSerialize(-1, self::TAG_ITEM));
protected function writeSaveData(CompoundTag $nbt) : void{
$nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance);
$nbt->setByte(self::TAG_ITEM_ROTATION, $this->itemRotation);
$nbt->setTag($this->item->nbtSerialize(-1, self::TAG_ITEM));
}
public function hasItem() : bool{

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\tile;
use pocketmine\event\block\SignChangeEvent;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
@ -37,7 +36,7 @@ class Sign extends Spawnable{
/** @var string[] */
protected $text = ["", "", "", ""];
public function __construct(Level $level, CompoundTag $nbt){
protected function readSaveData(CompoundTag $nbt) : void{
if($nbt->hasTag(self::TAG_TEXT_BLOB, StringTag::class)){ //MCPE 1.2 save format
$this->text = array_pad(explode("\n", $nbt->getString(self::TAG_TEXT_BLOB)), 4, "");
assert(count($this->text) === 4, "Too many lines!");
@ -51,17 +50,14 @@ class Sign extends Spawnable{
}
}
}
parent::__construct($level, $nbt);
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));
protected function writeSaveData(CompoundTag $nbt) : void{
$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));
for($i = 1; $i <= 4; ++$i){ //Backwards-compatibility
$textKey = sprintf(self::TAG_TEXT_LINE, $i);
$this->namedtag->setString($textKey, $this->getLine($i - 1));
$nbt->setString($textKey, $this->getLine($i - 1));
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\tile;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player;
@ -47,17 +46,14 @@ class Skull extends Spawnable{
/** @var int */
private $skullRotation;
public function __construct(Level $level, CompoundTag $nbt){
protected function readSaveData(CompoundTag $nbt) : void{
$this->skullType = $nbt->getByte(self::TAG_SKULL_TYPE, self::TYPE_SKELETON, true);
$this->skullRotation = $nbt->getByte(self::TAG_ROT, 0, true);
$nbt->removeTag(self::TAG_SKULL_TYPE, self::TAG_ROT);
parent::__construct($level, $nbt);
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setByte(self::TAG_SKULL_TYPE, $this->skullType);
$this->namedtag->setByte(self::TAG_ROT, $this->skullRotation);
protected function writeSaveData(CompoundTag $nbt) : void{
$nbt->setByte(self::TAG_SKULL_TYPE, $this->skullType);
$nbt->setByte(self::TAG_ROT, $this->skullRotation);
}
public function setType(int $type){

View File

@ -74,8 +74,6 @@ abstract class Tile extends Position{
public $id;
/** @var bool */
public $closed = false;
/** @var CompoundTag */
public $namedtag;
/** @var Server */
protected $server;
/** @var TimingsHandler */
@ -155,12 +153,12 @@ abstract class Tile extends Position{
public function __construct(Level $level, CompoundTag $nbt){
$this->timings = Timings::getTileEntityTimings($this);
$this->namedtag = $nbt;
$this->server = $level->getServer();
$this->name = "";
$this->id = Tile::$tileCount++;
parent::__construct($this->namedtag->getInt(self::TAG_X), $this->namedtag->getInt(self::TAG_Y), $this->namedtag->getInt(self::TAG_Z), $level);
parent::__construct($nbt->getInt(self::TAG_X), $nbt->getInt(self::TAG_Y), $nbt->getInt(self::TAG_Z), $level);
$this->readSaveData($nbt);
$this->getLevel()->addTile($this);
}
@ -169,26 +167,31 @@ abstract class Tile extends Position{
return $this->id;
}
public function saveNBT() : void{
$this->namedtag->setString(self::TAG_ID, static::getSaveId());
$this->namedtag->setInt(self::TAG_X, $this->x);
$this->namedtag->setInt(self::TAG_Y, $this->y);
$this->namedtag->setInt(self::TAG_Z, $this->z);
}
/**
* Reads additional data from the CompoundTag on tile creation.
*
* @param CompoundTag $nbt
*/
abstract protected function readSaveData(CompoundTag $nbt) : void;
public function getNBT() : CompoundTag{
return $this->namedtag;
/**
* Writes additional save data to a CompoundTag, not including generic things like ID and coordinates.
*
* @param CompoundTag $nbt
*/
abstract protected function writeSaveData(CompoundTag $nbt) : void;
public function saveNBT(CompoundTag $nbt) : void{
$nbt->setString(self::TAG_ID, static::getSaveId());
$nbt->setInt(self::TAG_X, $this->x);
$nbt->setInt(self::TAG_Y, $this->y);
$nbt->setInt(self::TAG_Z, $this->z);
$this->writeSaveData($nbt);
}
public function getCleanedNBT() : ?CompoundTag{
$this->saveNBT();
$tag = clone $this->namedtag;
$tag->removeTag(self::TAG_X, self::TAG_Y, self::TAG_Z, self::TAG_ID);
if($tag->getCount() > 0){
return $tag;
}else{
return null;
}
$this->writeSaveData($tag = new CompoundTag());
return $tag->getCount() > 0 ? $tag : null;
}
/**
@ -270,8 +273,6 @@ abstract class Tile extends Position{
$this->level->removeTile($this);
$this->setLevel(null);
}
$this->namedtag = null;
}
}