Kill entity runtime NBT (#2361)

This commit is contained in:
Dylan K. Taylor 2018-08-14 13:33:02 +01:00 committed by GitHub
parent 4b7300de8d
commit 0273e2484e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 224 additions and 210 deletions

View File

@ -1885,18 +1885,18 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->server->addOnlinePlayer($this);
}
protected function initHumanData() : void{
protected function initHumanData(CompoundTag $nbt) : void{
$this->setNameTag($this->username);
}
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->addDefaultWindows();
$this->firstPlayed = $this->namedtag->getLong("firstPlayed", $now = (int) (microtime(true) * 1000));
$this->lastPlayed = $this->namedtag->getLong("lastPlayed", $now);
$this->firstPlayed = $nbt->getLong("firstPlayed", $now = (int) (microtime(true) * 1000));
$this->lastPlayed = $nbt->getLong("lastPlayed", $now);
$this->gamemode = $this->namedtag->getInt("playerGameType", self::SURVIVAL) & 0x03;
$this->gamemode = $nbt->getInt("playerGameType", self::SURVIVAL) & 0x03;
if($this->server->getForceGamemode()){
$this->gamemode = $this->server->getGamemode();
}
@ -1912,15 +1912,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->setCanClimb();
$this->achievements = [];
$achievements = $this->namedtag->getCompoundTag("Achievements") ?? [];
$achievements = $nbt->getCompoundTag("Achievements") ?? [];
/** @var ByteTag $achievement */
foreach($achievements as $achievement){
$this->achievements[$achievement->getName()] = $achievement->getValue() !== 0;
}
if(!$this->hasValidSpawnPosition()){
if(($level = $this->server->getLevelByName($this->namedtag->getString("SpawnLevel", ""))) instanceof Level){
$this->spawnPosition = new Position($this->namedtag->getInt("SpawnX"), $this->namedtag->getInt("SpawnY"), $this->namedtag->getInt("SpawnZ"), $level);
if(($level = $this->server->getLevelByName($nbt->getString("SpawnLevel", ""))) instanceof Level){
$this->spawnPosition = new Position($nbt->getInt("SpawnX"), $nbt->getInt("SpawnY"), $nbt->getInt("SpawnZ"), $level);
}else{
$this->spawnPosition = $this->level->getSafeSpawn();
}
@ -2916,21 +2916,21 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
throw new \InvalidStateException("Tried to save closed player");
}
parent::saveNBT();
$nbt = $this->saveNBT();
if($this->isValid()){
$this->namedtag->setString("Level", $this->level->getFolderName());
$nbt->setString("Level", $this->level->getFolderName());
}
if($this->hasValidSpawnPosition()){
$this->namedtag->setString("SpawnLevel", $this->spawnPosition->getLevel()->getFolderName());
$this->namedtag->setInt("SpawnX", $this->spawnPosition->getFloorX());
$this->namedtag->setInt("SpawnY", $this->spawnPosition->getFloorY());
$this->namedtag->setInt("SpawnZ", $this->spawnPosition->getFloorZ());
$nbt->setString("SpawnLevel", $this->spawnPosition->getLevel()->getFolderName());
$nbt->setInt("SpawnX", $this->spawnPosition->getFloorX());
$nbt->setInt("SpawnY", $this->spawnPosition->getFloorY());
$nbt->setInt("SpawnZ", $this->spawnPosition->getFloorZ());
if(!$this->isAlive()){
//hack for respawn after quit
$this->namedtag->setTag(new ListTag("Pos", [
$nbt->setTag(new ListTag("Pos", [
new DoubleTag("", $this->spawnPosition->x),
new DoubleTag("", $this->spawnPosition->y),
new DoubleTag("", $this->spawnPosition->z)
@ -2942,13 +2942,13 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
foreach($this->achievements as $achievement => $status){
$achievements->setByte($achievement, $status ? 1 : 0);
}
$this->namedtag->setTag($achievements);
$nbt->setTag($achievements);
$this->namedtag->setInt("playerGameType", $this->gamemode);
$this->namedtag->setLong("firstPlayed", $this->firstPlayed);
$this->namedtag->setLong("lastPlayed", (int) floor(microtime(true) * 1000));
$nbt->setInt("playerGameType", $this->gamemode);
$nbt->setLong("firstPlayed", $this->firstPlayed);
$nbt->setLong("lastPlayed", (int) floor(microtime(true) * 1000));
$this->server->saveOfflinePlayerData($this->username, $this->namedtag, $async);
$this->server->saveOfflinePlayerData($this->username, $nbt, $async);
}
public function kill() : void{

View File

@ -436,8 +436,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public $lastUpdate;
/** @var int */
public $fireTicks = 0;
/** @var CompoundTag */
public $namedtag;
/** @var bool */
public $canCollide = true;
@ -495,13 +493,12 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
$this->id = Entity::$entityCount++;
$this->namedtag = $nbt;
$this->server = $level->getServer();
/** @var float[] $pos */
$pos = $this->namedtag->getListTag("Pos")->getAllValues();
$pos = $nbt->getListTag("Pos")->getAllValues();
/** @var float[] $rotation */
$rotation = $this->namedtag->getListTag("Rotation")->getAllValues();
$rotation = $nbt->getListTag("Rotation")->getAllValues();
parent::__construct($pos[0], $pos[1], $pos[2], $rotation[0], $rotation[1], $level);
assert(!is_nan($this->x) and !is_infinite($this->x) and !is_nan($this->y) and !is_infinite($this->y) and !is_nan($this->z) and !is_infinite($this->z));
@ -514,15 +511,15 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
throw new \InvalidStateException("Cannot create entities in unloaded chunks");
}
if($this->namedtag->hasTag("Motion", ListTag::class)){
if($nbt->hasTag("Motion", ListTag::class)){
/** @var float[] $motion */
$motion = $this->namedtag->getListTag("Motion")->getAllValues();
$motion = $nbt->getListTag("Motion")->getAllValues();
$this->setMotion($this->temporalVector->setComponents(...$motion));
}
$this->resetLastMovements();
$this->fallDistance = $this->namedtag->getFloat("FallDistance", 0.0);
$this->fallDistance = $nbt->getFloat("FallDistance", 0.0);
$this->propertyManager = new DataPropertyManager();
@ -534,14 +531,14 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->propertyManager->setFloat(self::DATA_BOUNDING_BOX_WIDTH, $this->width);
$this->propertyManager->setFloat(self::DATA_BOUNDING_BOX_HEIGHT, $this->height);
$this->fireTicks = $this->namedtag->getShort("Fire", 0);
$this->fireTicks = $nbt->getShort("Fire", 0);
if($this->isOnFire()){
$this->setGenericFlag(self::DATA_FLAG_ONFIRE);
}
$this->propertyManager->setShort(self::DATA_AIR, $this->namedtag->getShort("Air", 300));
$this->onGround = $this->namedtag->getByte("OnGround", 0) !== 0;
$this->invulnerable = $this->namedtag->getByte("Invulnerable", 0) !== 0;
$this->propertyManager->setShort(self::DATA_AIR, $nbt->getShort("Air", 300));
$this->onGround = $nbt->getByte("OnGround", 0) !== 0;
$this->invulnerable = $nbt->getByte("Invulnerable", 0) !== 0;
$this->attributeMap = new AttributeMap();
$this->addAttributes();
@ -549,7 +546,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->setGenericFlag(self::DATA_FLAG_AFFECTED_BY_GRAVITY, true);
$this->setGenericFlag(self::DATA_FLAG_HAS_COLLISION, true);
$this->initEntity();
$this->initEntity($nbt);
$this->propertyManager->clearDirtyProperties(); //Prevents resending properties that were set during construction
$this->chunk->addEntity($this);
@ -838,54 +835,52 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
return current(self::$saveNames[static::class]);
}
public function saveNBT() : void{
public function saveNBT() : CompoundTag{
$nbt = new CompoundTag();
if(!($this instanceof Player)){
$this->namedtag->setString("id", $this->getSaveId(), true);
$nbt->setString("id", $this->getSaveId(), true);
if($this->getNameTag() !== ""){
$this->namedtag->setString("CustomName", $this->getNameTag());
$this->namedtag->setByte("CustomNameVisible", $this->isNameTagVisible() ? 1 : 0);
}else{
$this->namedtag->removeTag("CustomName", "CustomNameVisible");
$nbt->setString("CustomName", $this->getNameTag());
$nbt->setByte("CustomNameVisible", $this->isNameTagVisible() ? 1 : 0);
}
}
$this->namedtag->setTag(new ListTag("Pos", [
$nbt->setTag(new ListTag("Pos", [
new DoubleTag("", $this->x),
new DoubleTag("", $this->y),
new DoubleTag("", $this->z)
]));
$this->namedtag->setTag(new ListTag("Motion", [
$nbt->setTag(new ListTag("Motion", [
new DoubleTag("", $this->motion->x),
new DoubleTag("", $this->motion->y),
new DoubleTag("", $this->motion->z)
]));
$this->namedtag->setTag(new ListTag("Rotation", [
$nbt->setTag(new ListTag("Rotation", [
new FloatTag("", $this->yaw),
new FloatTag("", $this->pitch)
]));
$this->namedtag->setFloat("FallDistance", $this->fallDistance);
$this->namedtag->setShort("Fire", $this->fireTicks);
$this->namedtag->setShort("Air", $this->propertyManager->getShort(self::DATA_AIR));
$this->namedtag->setByte("OnGround", $this->onGround ? 1 : 0);
$this->namedtag->setByte("Invulnerable", $this->invulnerable ? 1 : 0);
$nbt->setFloat("FallDistance", $this->fallDistance);
$nbt->setShort("Fire", $this->fireTicks);
$nbt->setShort("Air", $this->propertyManager->getShort(self::DATA_AIR));
$nbt->setByte("OnGround", $this->onGround ? 1 : 0);
$nbt->setByte("Invulnerable", $this->invulnerable ? 1 : 0);
return $nbt;
}
protected function initEntity() : void{
assert($this->namedtag instanceof CompoundTag);
protected function initEntity(CompoundTag $nbt) : void{
if($nbt->hasTag("CustomName", StringTag::class)){
$this->setNameTag($nbt->getString("CustomName"));
if($this->namedtag->hasTag("CustomName", StringTag::class)){
$this->setNameTag($this->namedtag->getString("CustomName"));
if($this->namedtag->hasTag("CustomNameVisible", StringTag::class)){
if($nbt->hasTag("CustomNameVisible", StringTag::class)){
//Older versions incorrectly saved this as a string (see 890f72dbf23a77f294169b79590770470041adc4)
$this->setNameTagVisible($this->namedtag->getString("CustomNameVisible") !== "");
$this->namedtag->removeTag("CustomNameVisible");
$this->setNameTagVisible($nbt->getString("CustomNameVisible") !== "");
}else{
$this->setNameTagVisible($this->namedtag->getByte("CustomNameVisible", 1) !== 0);
$this->setNameTagVisible($nbt->getByte("CustomNameVisible", 1) !== 0);
}
}
}
@ -2036,7 +2031,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->setLevel(null);
}
$this->namedtag = null;
$this->lastDamageCause = null;
}
}

View File

@ -578,13 +578,15 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
/**
* For Human entities which are not players, sets their properties such as nametag, skin and UUID from NBT.
*
* @param CompoundTag $nbt
*/
protected function initHumanData() : void{
if($this->namedtag->hasTag("NameTag", StringTag::class)){
$this->setNameTag($this->namedtag->getString("NameTag"));
protected function initHumanData(CompoundTag $nbt) : void{
if($nbt->hasTag("NameTag", StringTag::class)){
$this->setNameTag($nbt->getString("NameTag"));
}
$skin = $this->namedtag->getCompoundTag("Skin");
$skin = $nbt->getCompoundTag("Skin");
if($skin !== null){
$this->setSkin(new Skin(
$skin->getString("Name"),
@ -598,17 +600,17 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
$this->uuid = UUID::fromData((string) $this->getId(), $this->skin->getSkinData(), $this->getNameTag());
}
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->setPlayerFlag(self::DATA_PLAYER_FLAG_SLEEP, false);
$this->propertyManager->setBlockPos(self::DATA_PLAYER_BED_POSITION, null);
$this->inventory = new PlayerInventory($this);
$this->enderChestInventory = new EnderChestInventory();
$this->initHumanData();
$this->initHumanData($nbt);
$inventoryTag = $this->namedtag->getListTag("Inventory");
$inventoryTag = $nbt->getListTag("Inventory");
if($inventoryTag !== null){
$armorListener = $this->armorInventory->getEventProcessor();
$this->armorInventory->setEventProcessor(null);
@ -628,7 +630,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
$this->armorInventory->setEventProcessor($armorListener);
}
$enderChestInventoryTag = $this->namedtag->getListTag("EnderChestInventory");
$enderChestInventoryTag = $nbt->getListTag("EnderChestInventory");
if($enderChestInventoryTag !== null){
/** @var CompoundTag $item */
foreach($enderChestInventoryTag as $i => $item){
@ -636,21 +638,21 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
}
}
$this->inventory->setHeldItemIndex($this->namedtag->getInt("SelectedInventorySlot", 0), false);
$this->inventory->setHeldItemIndex($nbt->getInt("SelectedInventorySlot", 0), false);
$this->inventory->setEventProcessor(new EntityInventoryEventProcessor($this));
$this->setFood((float) $this->namedtag->getInt("foodLevel", (int) $this->getFood(), true));
$this->setExhaustion($this->namedtag->getFloat("foodExhaustionLevel", $this->getExhaustion(), true));
$this->setSaturation($this->namedtag->getFloat("foodSaturationLevel", $this->getSaturation(), true));
$this->foodTickTimer = $this->namedtag->getInt("foodTickTimer", $this->foodTickTimer, true);
$this->setFood((float) $nbt->getInt("foodLevel", (int) $this->getFood(), true));
$this->setExhaustion($nbt->getFloat("foodExhaustionLevel", $this->getExhaustion(), true));
$this->setSaturation($nbt->getFloat("foodSaturationLevel", $this->getSaturation(), true));
$this->foodTickTimer = $nbt->getInt("foodTickTimer", $this->foodTickTimer, true);
$this->setXpLevel($this->namedtag->getInt("XpLevel", $this->getXpLevel(), true));
$this->setXpProgress($this->namedtag->getFloat("XpP", $this->getXpProgress(), true));
$this->totalXp = $this->namedtag->getInt("XpTotal", $this->totalXp, true);
$this->setXpLevel($nbt->getInt("XpLevel", $this->getXpLevel(), true));
$this->setXpProgress($nbt->getFloat("XpP", $this->getXpProgress(), true));
$this->totalXp = $nbt->getInt("XpTotal", $this->totalXp, true);
if($this->namedtag->hasTag("XpSeed", IntTag::class)){
$this->xpSeed = $this->namedtag->getInt("XpSeed");
if($nbt->hasTag("XpSeed", IntTag::class)){
$this->xpSeed = $nbt->getInt("XpSeed");
}else{
$this->xpSeed = random_int(INT32_MIN, INT32_MAX);
}
@ -764,21 +766,21 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
), function(Item $item) : bool{ return !$item->hasEnchantment(Enchantment::VANISHING); });
}
public function saveNBT() : void{
parent::saveNBT();
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$this->namedtag->setInt("foodLevel", (int) $this->getFood(), true);
$this->namedtag->setFloat("foodExhaustionLevel", $this->getExhaustion(), true);
$this->namedtag->setFloat("foodSaturationLevel", $this->getSaturation(), true);
$this->namedtag->setInt("foodTickTimer", $this->foodTickTimer);
$nbt->setInt("foodLevel", (int) $this->getFood(), true);
$nbt->setFloat("foodExhaustionLevel", $this->getExhaustion(), true);
$nbt->setFloat("foodSaturationLevel", $this->getSaturation(), true);
$nbt->setInt("foodTickTimer", $this->foodTickTimer);
$this->namedtag->setInt("XpLevel", $this->getXpLevel());
$this->namedtag->setFloat("XpP", $this->getXpProgress());
$this->namedtag->setInt("XpTotal", $this->totalXp);
$this->namedtag->setInt("XpSeed", $this->xpSeed);
$nbt->setInt("XpLevel", $this->getXpLevel());
$nbt->setFloat("XpP", $this->getXpProgress());
$nbt->setInt("XpTotal", $this->totalXp);
$nbt->setInt("XpSeed", $this->xpSeed);
$inventoryTag = new ListTag("Inventory", [], NBT::TAG_Compound);
$this->namedtag->setTag($inventoryTag);
$nbt->setTag($inventoryTag);
if($this->inventory !== null){
//Normal inventory
$slotCount = $this->inventory->getSize() + $this->inventory->getHotbarSize();
@ -797,7 +799,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
}
}
$this->namedtag->setInt("SelectedInventorySlot", $this->inventory->getHeldItemIndex());
$nbt->setInt("SelectedInventorySlot", $this->inventory->getHeldItemIndex());
}
if($this->enderChestInventory !== null){
@ -812,11 +814,11 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
}
}
$this->namedtag->setTag(new ListTag("EnderChestInventory", $items, NBT::TAG_Compound));
$nbt->setTag(new ListTag("EnderChestInventory", $items, NBT::TAG_Compound));
}
if($this->skin !== null){
$this->namedtag->setTag(new CompoundTag("Skin", [
$nbt->setTag(new CompoundTag("Skin", [
new StringTag("Name", $this->skin->getSkinId()),
new ByteArrayTag("Data", $this->skin->getSkinData()),
new ByteArrayTag("CapeData", $this->skin->getCapeData()),
@ -824,6 +826,8 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
new ByteArrayTag("GeometryData", $this->skin->getGeometryData())
]));
}
return $nbt;
}
public function spawnTo(Player $player) : void{

View File

@ -74,8 +74,8 @@ abstract class Living extends Entity implements Damageable{
abstract public function getName() : string;
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->armorInventory = new ArmorInventory($this);
//TODO: load/save armor inventory contents
@ -83,21 +83,17 @@ abstract class Living extends Entity implements Damageable{
$health = $this->getMaxHealth();
if($this->namedtag->hasTag("HealF", FloatTag::class)){
$health = $this->namedtag->getFloat("HealF");
$this->namedtag->removeTag("HealF");
}elseif($this->namedtag->hasTag("Health")){
$healthTag = $this->namedtag->getTag("Health");
if($nbt->hasTag("HealF", FloatTag::class)){
$health = $nbt->getFloat("HealF");
}elseif($nbt->hasTag("Health")){
$healthTag = $nbt->getTag("Health");
$health = (float) $healthTag->getValue(); //Older versions of PocketMine-MP incorrectly saved this as a short instead of a float
if(!($healthTag instanceof FloatTag)){
$this->namedtag->removeTag("Health");
}
}
$this->setHealth($health);
/** @var CompoundTag[]|ListTag $activeEffectsTag */
$activeEffectsTag = $this->namedtag->getListTag("ActiveEffects");
$activeEffectsTag = $nbt->getListTag("ActiveEffects");
if($activeEffectsTag !== null){
foreach($activeEffectsTag as $e){
$effect = Effect::getEffect($e->getByte("Id"));
@ -150,9 +146,9 @@ abstract class Living extends Entity implements Damageable{
$this->attributeMap->getAttribute(Attribute::ABSORPTION)->setValue($absorption);
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setFloat("Health", $this->getHealth(), true);
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setFloat("Health", $this->getHealth(), true);
if(count($this->effects) > 0){
$effects = [];
@ -166,10 +162,10 @@ abstract class Living extends Entity implements Damageable{
]);
}
$this->namedtag->setTag(new ListTag("ActiveEffects", $effects));
}else{
$this->namedtag->removeTag("ActiveEffects");
$nbt->setTag(new ListTag("ActiveEffects", $effects));
}
return $nbt;
}

View File

@ -28,6 +28,7 @@ use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
class Squid extends WaterAnimal{
@ -42,9 +43,9 @@ class Squid extends WaterAnimal{
private $switchDirectionTicker = 0;
public function initEntity() : void{
public function initEntity(CompoundTag $nbt) : void{
$this->setMaxHealth(10);
parent::initEntity();
parent::initEntity($nbt);
}
public function getName() : string{

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\entity;
use pocketmine\nbt\tag\CompoundTag;
class Villager extends Creature implements NPC, Ageable{
public const PROFESSION_FARMER = 0;
public const PROFESSION_LIBRARIAN = 1;
@ -39,11 +41,11 @@ class Villager extends Creature implements NPC, Ageable{
return "Villager";
}
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
/** @var int $profession */
$profession = $this->namedtag->getInt("Profession", self::PROFESSION_FARMER);
$profession = $nbt->getInt("Profession", self::PROFESSION_FARMER);
if($profession > 4 or $profession < 0){
$profession = self::PROFESSION_FARMER;
@ -52,9 +54,11 @@ class Villager extends Creature implements NPC, Ageable{
$this->setProfession($profession);
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setInt("Profession", $this->getProfession());
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setInt("Profession", $this->getProfession());
return $nbt;
}
/**

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\object;
use pocketmine\entity\Entity;
use pocketmine\entity\Human;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\Player;
@ -100,28 +101,30 @@ class ExperienceOrb extends Entity{
*/
protected $targetPlayerRuntimeId = null;
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->age = $this->namedtag->getShort("Age", 0);
$this->age = $nbt->getShort("Age", 0);
$value = 0;
if($this->namedtag->hasTag(self::TAG_VALUE_PC, ShortTag::class)){ //PC
$value = $this->namedtag->getShort(self::TAG_VALUE_PC);
}elseif($this->namedtag->hasTag(self::TAG_VALUE_PE, IntTag::class)){ //PE save format
$value = $this->namedtag->getInt(self::TAG_VALUE_PE);
if($nbt->hasTag(self::TAG_VALUE_PC, ShortTag::class)){ //PC
$value = $nbt->getShort(self::TAG_VALUE_PC);
}elseif($nbt->hasTag(self::TAG_VALUE_PE, IntTag::class)){ //PE save format
$value = $nbt->getInt(self::TAG_VALUE_PE);
}
$this->setXpValue($value);
}
public function saveNBT() : void{
parent::saveNBT();
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$this->namedtag->setShort("Age", $this->age);
$nbt->setShort("Age", $this->age);
$this->namedtag->setShort(self::TAG_VALUE_PC, $this->getXpValue());
$this->namedtag->setInt(self::TAG_VALUE_PE, $this->getXpValue());
$nbt->setShort(self::TAG_VALUE_PC, $this->getXpValue());
$nbt->setInt(self::TAG_VALUE_PE, $this->getXpValue());
return $nbt;
}
public function getXpValue() : int{

View File

@ -32,6 +32,7 @@ use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\ItemFactory;
use pocketmine\level\Position;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
class FallingBlock extends Entity{
@ -50,24 +51,23 @@ class FallingBlock extends Entity{
public $canCollide = false;
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$blockId = 0;
//TODO: 1.8+ save format
if($this->namedtag->hasTag("TileID", IntTag::class)){
$blockId = $this->namedtag->getInt("TileID");
}elseif($this->namedtag->hasTag("Tile", ByteTag::class)){
$blockId = $this->namedtag->getByte("Tile");
$this->namedtag->removeTag("Tile");
if($nbt->hasTag("TileID", IntTag::class)){
$blockId = $nbt->getInt("TileID");
}elseif($nbt->hasTag("Tile", ByteTag::class)){
$blockId = $nbt->getByte("Tile");
}
if($blockId === 0){
throw new \UnexpectedValueException("Invalid " . get_class($this) . " entity: block ID is 0 or missing");
}
$damage = $this->namedtag->getByte("Data", 0);
$damage = $nbt->getByte("Data", 0);
$this->block = BlockFactory::get($blockId, $damage);
@ -133,9 +133,11 @@ class FallingBlock extends Entity{
return $this->block->getDamage();
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setInt("TileID", $this->block->getId(), true);
$this->namedtag->setByte("Data", $this->block->getDamage());
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setInt("TileID", $this->block->getId(), true);
$nbt->setByte("Data", $this->block->getDamage());
return $nbt;
}
}

View File

@ -28,6 +28,7 @@ use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent;
use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\item\Item;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\AddItemEntityPacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\Player;
@ -53,18 +54,18 @@ class ItemEntity extends Entity{
public $canCollide = false;
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->setMaxHealth(5);
$this->setHealth($this->namedtag->getShort("Health", (int) $this->getHealth()));
$this->age = $this->namedtag->getShort("Age", $this->age);
$this->pickupDelay = $this->namedtag->getShort("PickupDelay", $this->pickupDelay);
$this->owner = $this->namedtag->getString("Owner", $this->owner);
$this->thrower = $this->namedtag->getString("Thrower", $this->thrower);
$this->setHealth($nbt->getShort("Health", (int) $this->getHealth()));
$this->age = $nbt->getShort("Age", $this->age);
$this->pickupDelay = $nbt->getShort("PickupDelay", $this->pickupDelay);
$this->owner = $nbt->getString("Owner", $this->owner);
$this->thrower = $nbt->getString("Thrower", $this->thrower);
$itemTag = $this->namedtag->getCompoundTag("Item");
$itemTag = $nbt->getCompoundTag("Item");
if($itemTag === null){
throw new \UnexpectedValueException("Invalid " . get_class($this) . " entity: expected \"Item\" NBT tag not found");
}
@ -114,18 +115,20 @@ class ItemEntity extends Entity{
return true;
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setTag($this->item->nbtSerialize(-1, "Item"));
$this->namedtag->setShort("Health", (int) $this->getHealth());
$this->namedtag->setShort("Age", $this->age);
$this->namedtag->setShort("PickupDelay", $this->pickupDelay);
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setTag($this->item->nbtSerialize(-1, "Item"));
$nbt->setShort("Health", (int) $this->getHealth());
$nbt->setShort("Age", $this->age);
$nbt->setShort("PickupDelay", $this->pickupDelay);
if($this->owner !== null){
$this->namedtag->setString("Owner", $this->owner);
$nbt->setString("Owner", $this->owner);
}
if($this->thrower !== null){
$this->namedtag->setString("Thrower", $this->thrower);
$nbt->setString("Thrower", $this->thrower);
}
return $nbt;
}
/**

View File

@ -70,20 +70,22 @@ class Painting extends Entity{
parent::__construct($level, $nbt);
}
protected function initEntity() : void{
protected function initEntity(CompoundTag $nbt) : void{
$this->setMaxHealth(1);
$this->setHealth(1);
parent::initEntity();
parent::initEntity($nbt);
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setInt("TileX", (int) $this->blockIn->x);
$this->namedtag->setInt("TileY", (int) $this->blockIn->y);
$this->namedtag->setInt("TileZ", (int) $this->blockIn->z);
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setInt("TileX", (int) $this->blockIn->x);
$nbt->setInt("TileY", (int) $this->blockIn->y);
$nbt->setInt("TileZ", (int) $this->blockIn->z);
$this->namedtag->setByte("Facing", (int) $this->direction);
$this->namedtag->setByte("Direction", (int) $this->direction); //Save both for full compatibility
$nbt->setByte("Facing", (int) $this->direction);
$nbt->setByte("Direction", (int) $this->direction); //Save both for full compatibility
return $nbt;
}
public function kill() : void{

View File

@ -28,6 +28,7 @@ use pocketmine\entity\Explosive;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ExplosionPrimeEvent;
use pocketmine\level\Explosion;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
@ -53,11 +54,11 @@ class PrimedTNT extends Entity implements Explosive{
}
}
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
if($this->namedtag->hasTag("Fuse", ShortTag::class)){
$this->fuse = $this->namedtag->getShort("Fuse");
if($nbt->hasTag("Fuse", ShortTag::class)){
$this->fuse = $nbt->getShort("Fuse");
}else{
$this->fuse = 80;
}
@ -73,9 +74,11 @@ class PrimedTNT extends Entity implements Explosive{
return false;
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setShort("Fuse", $this->fuse, true); //older versions incorrectly saved this as a byte
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setShort("Fuse", $this->fuse, true); //older versions incorrectly saved this as a byte
return $nbt;
}
public function entityBaseTick(int $tickDiff = 1) : bool{

View File

@ -66,16 +66,16 @@ class Arrow extends Projectile{
$this->setCritical($critical);
}
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->pickupMode = $this->namedtag->getByte(self::TAG_PICKUP, self::PICKUP_ANY, true);
$this->pickupMode = $nbt->getByte(self::TAG_PICKUP, self::PICKUP_ANY, true);
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setByte(self::TAG_PICKUP, $this->pickupMode, true);
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setByte(self::TAG_PICKUP, $this->pickupMode);
return $nbt;
}
public function isCritical() : bool{

View File

@ -69,33 +69,33 @@ abstract class Projectile extends Entity{
}
}
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->setMaxHealth(1);
$this->setHealth(1);
$this->age = $this->namedtag->getShort("Age", $this->age);
$this->damage = $this->namedtag->getDouble("damage", $this->damage);
$this->age = $nbt->getShort("Age", $this->age);
$this->damage = $nbt->getDouble("damage", $this->damage);
do{
$blockHit = null;
$blockId = null;
$blockData = null;
if($this->namedtag->hasTag("tileX", IntTag::class) and $this->namedtag->hasTag("tileY", IntTag::class) and $this->namedtag->hasTag("tileZ", IntTag::class)){
$blockHit = new Vector3($this->namedtag->getInt("tileX"), $this->namedtag->getInt("tileY"), $this->namedtag->getInt("tileZ"));
if($nbt->hasTag("tileX", IntTag::class) and $nbt->hasTag("tileY", IntTag::class) and $nbt->hasTag("tileZ", IntTag::class)){
$blockHit = new Vector3($nbt->getInt("tileX"), $nbt->getInt("tileY"), $nbt->getInt("tileZ"));
}else{
break;
}
if($this->namedtag->hasTag("blockId", IntTag::class)){
$blockId = $this->namedtag->getInt("blockId");
if($nbt->hasTag("blockId", IntTag::class)){
$blockId = $nbt->getInt("blockId");
}else{
break;
}
if($this->namedtag->hasTag("blockData", ByteTag::class)){
$blockData = $this->namedtag->getByte("blockData");
if($nbt->hasTag("blockData", ByteTag::class)){
$blockData = $nbt->getByte("blockData");
}else{
break;
}
@ -141,21 +141,23 @@ abstract class Projectile extends Entity{
return (int) ceil($this->motion->length() * $this->damage);
}
public function saveNBT() : void{
parent::saveNBT();
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$this->namedtag->setShort("Age", $this->age);
$this->namedtag->setDouble("damage", $this->damage);
$nbt->setShort("Age", $this->age);
$nbt->setDouble("damage", $this->damage);
if($this->blockHit !== null){
$this->namedtag->setInt("tileX", $this->blockHit->x);
$this->namedtag->setInt("tileY", $this->blockHit->y);
$this->namedtag->setInt("tileZ", $this->blockHit->z);
$nbt->setInt("tileX", $this->blockHit->x);
$nbt->setInt("tileY", $this->blockHit->y);
$nbt->setInt("tileZ", $this->blockHit->z);
//we intentionally use different ones to PC because we don't have stringy IDs
$this->namedtag->setInt("blockId", $this->blockHitId);
$this->namedtag->setByte("blockData", $this->blockHitData);
$nbt->setInt("blockId", $this->blockHitId);
$nbt->setByte("blockData", $this->blockHitData);
}
return $nbt;
}
protected function applyDragBeforeGravity() : bool{

View File

@ -31,6 +31,7 @@ use pocketmine\event\entity\ProjectileHitEntityEvent;
use pocketmine\event\entity\ProjectileHitBlockEvent;
use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\item\Potion;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\utils\Color;
@ -42,15 +43,17 @@ class SplashPotion extends Throwable{
protected $gravity = 0.05;
protected $drag = 0.01;
protected function initEntity() : void{
parent::initEntity();
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->setPotionId($this->namedtag->getShort("PotionId", 0));
$this->setPotionId($nbt->getShort("PotionId", 0));
}
public function saveNBT() : void{
parent::saveNBT();
$this->namedtag->setShort("PotionId", $this->getPotionId());
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setShort("PotionId", $this->getPotionId());
return $nbt;
}
public function getResultDamage() : int{

View File

@ -464,8 +464,7 @@ class LevelDB extends BaseLevelProvider{
/** @var CompoundTag[] $entities */
$entities = [];
foreach($chunk->getSavableEntities() as $entity){
$entity->saveNBT();
$entities[] = $entity->namedtag;
$entities[] = $entity->saveNBT();
}
$this->writeTags($entities, $index . self::TAG_ENTITY);

View File

@ -67,8 +67,7 @@ class Anvil extends McRegion{
$entities = [];
foreach($chunk->getSavableEntities() as $entity){
$entity->saveNBT();
$entities[] = $entity->namedtag;
$entities[] = $entity->saveNBT();
}
$nbt->setTag(new ListTag("Entities", $entities, NBT::TAG_Compound));

View File

@ -86,8 +86,7 @@ class McRegion extends BaseLevelProvider{
$entities = [];
foreach($chunk->getSavableEntities() as $entity){
$entity->saveNBT();
$entities[] = $entity->namedtag;
$entities[] = $entity->saveNBT();
}
$nbt->setTag(new ListTag("Entities", $entities, NBT::TAG_Compound));