Constify a bunch of NBT keys, pass 1

This commit is contained in:
Dylan K. Taylor 2022-12-18 22:12:15 +00:00
parent aa374083d8
commit bf44edd179
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
19 changed files with 257 additions and 161 deletions

View File

@ -560,7 +560,7 @@ class Server{
$ev->call();
$class = $ev->getPlayerClass();
if($offlinePlayerData !== null && ($world = $this->worldManager->getWorldByName($offlinePlayerData->getString("Level", ""))) !== null){
if($offlinePlayerData !== null && ($world = $this->worldManager->getWorldByName($offlinePlayerData->getString(Player::TAG_LEVEL, ""))) !== null){
$playerPos = EntityDataHelper::parseLocation($offlinePlayerData, $world);
$spawn = $playerPos->asVector3();
}else{

View File

@ -81,6 +81,15 @@ abstract class Entity{
public const MOTION_THRESHOLD = 0.00001;
protected const STEP_CLIP_MULTIPLIER = 0.4;
private const TAG_FIRE = "Fire"; //TAG_Short
private const TAG_ON_GROUND = "OnGround"; //TAG_Byte
private const TAG_FALL_DISTANCE = "FallDistance"; //TAG_Float
private const TAG_CUSTOM_NAME = "CustomName"; //TAG_String
private const TAG_CUSTOM_NAME_VISIBLE = "CustomNameVisible"; //TAG_Byte
public const TAG_POS = "Pos"; //TAG_List<TAG_Double>|TAG_List<TAG_Float>
public const TAG_MOTION = "Motion"; //TAG_List<TAG_Double>|TAG_List<TAG_Float>
public const TAG_ROTATION = "Rotation"; //TAG_List<TAG_Float>
private static int $entityCount = 1;
/**
@ -233,7 +242,7 @@ abstract class Entity{
$this->recalculateBoundingBox();
if($nbt !== null){
$this->motion = EntityDataHelper::parseVec3($nbt, "Motion", true);
$this->motion = EntityDataHelper::parseVec3($nbt, self::TAG_MOTION, true);
}else{
$this->motion = new Vector3(0, 0, 0);
}
@ -466,17 +475,17 @@ abstract class Entity{
public function saveNBT() : CompoundTag{
$nbt = CompoundTag::create()
->setTag("Pos", new ListTag([
->setTag(self::TAG_POS, new ListTag([
new DoubleTag($this->location->x),
new DoubleTag($this->location->y),
new DoubleTag($this->location->z)
]))
->setTag("Motion", new ListTag([
->setTag(self::TAG_MOTION, new ListTag([
new DoubleTag($this->motion->x),
new DoubleTag($this->motion->y),
new DoubleTag($this->motion->z)
]))
->setTag("Rotation", new ListTag([
->setTag(self::TAG_ROTATION, new ListTag([
new FloatTag($this->location->yaw),
new FloatTag($this->location->pitch)
]));
@ -485,33 +494,33 @@ abstract class Entity{
EntityFactory::getInstance()->injectSaveId(get_class($this), $nbt);
if($this->getNameTag() !== ""){
$nbt->setString("CustomName", $this->getNameTag());
$nbt->setByte("CustomNameVisible", $this->isNameTagVisible() ? 1 : 0);
$nbt->setString(self::TAG_CUSTOM_NAME, $this->getNameTag());
$nbt->setByte(self::TAG_CUSTOM_NAME_VISIBLE, $this->isNameTagVisible() ? 1 : 0);
}
}
$nbt->setFloat("FallDistance", $this->fallDistance);
$nbt->setShort("Fire", $this->fireTicks);
$nbt->setByte("OnGround", $this->onGround ? 1 : 0);
$nbt->setFloat(self::TAG_FALL_DISTANCE, $this->fallDistance);
$nbt->setShort(self::TAG_FIRE, $this->fireTicks);
$nbt->setByte(self::TAG_ON_GROUND, $this->onGround ? 1 : 0);
return $nbt;
}
protected function initEntity(CompoundTag $nbt) : void{
$this->fireTicks = $nbt->getShort("Fire", 0);
$this->fireTicks = $nbt->getShort(self::TAG_FIRE, 0);
$this->onGround = $nbt->getByte("OnGround", 0) !== 0;
$this->onGround = $nbt->getByte(self::TAG_ON_GROUND, 0) !== 0;
$this->fallDistance = $nbt->getFloat("FallDistance", 0.0);
$this->fallDistance = $nbt->getFloat(self::TAG_FALL_DISTANCE, 0.0);
if(($customNameTag = $nbt->getTag("CustomName")) instanceof StringTag){
if(($customNameTag = $nbt->getTag(self::TAG_CUSTOM_NAME)) instanceof StringTag){
$this->setNameTag($customNameTag->getValue());
if(($customNameVisibleTag = $nbt->getTag("CustomNameVisible")) instanceof StringTag){
if(($customNameVisibleTag = $nbt->getTag(self::TAG_CUSTOM_NAME_VISIBLE)) instanceof StringTag){
//Older versions incorrectly saved this as a string (see 890f72dbf23a77f294169b79590770470041adc4)
$this->setNameTagVisible($customNameVisibleTag->getValue() !== "");
}else{
$this->setNameTagVisible($nbt->getByte("CustomNameVisible", 1) !== 0);
$this->setNameTagVisible($nbt->getByte(self::TAG_CUSTOM_NAME_VISIBLE, 1) !== 0);
}
}
}

View File

@ -57,19 +57,19 @@ final class EntityDataHelper{
* @throws SavedDataLoadingException
*/
public static function parseLocation(CompoundTag $nbt, World $world) : Location{
$pos = self::parseVec3($nbt, "Pos", false);
$pos = self::parseVec3($nbt, Entity::TAG_POS, false);
$yawPitch = $nbt->getTag("Rotation");
$yawPitch = $nbt->getTag(Entity::TAG_ROTATION);
if(!($yawPitch instanceof ListTag) || $yawPitch->getTagType() !== NBT::TAG_Float){
throw new SavedDataLoadingException("'Rotation' should be a List<Float>");
throw new SavedDataLoadingException("'" . Entity::TAG_ROTATION . "' should be a List<Float>");
}
/** @var FloatTag[] $values */
$values = $yawPitch->getValue();
if(count($values) !== 2){
throw new SavedDataLoadingException("Expected exactly 2 entries for 'Rotation'");
}
self::validateFloat("Rotation", "yaw", $values[0]->getValue());
self::validateFloat("Rotation", "pitch", $values[1]->getValue());
self::validateFloat(Entity::TAG_ROTATION, "yaw", $values[0]->getValue());
self::validateFloat(Entity::TAG_ROTATION, "pitch", $values[1]->getValue());
return Location::fromObject($pos, $world, $values[0]->getValue(), $values[1]->getValue());
}

View File

@ -66,6 +66,9 @@ use function reset;
final class EntityFactory{
use SingletonTrait;
public const TAG_IDENTIFIER = "identifier"; //TAG_String
public const TAG_LEGACY_ID = "id"; //TAG_Int
/**
* @var \Closure[] save ID => creator function
* @phpstan-var array<int|string, \Closure(World, CompoundTag) : Entity>
@ -113,9 +116,9 @@ final class EntityFactory{
}, ['FallingSand', 'minecraft:falling_block'], LegacyIds::FALLING_BLOCK);
$this->register(ItemEntity::class, function(World $world, CompoundTag $nbt) : ItemEntity{
$itemTag = $nbt->getCompoundTag("Item");
$itemTag = $nbt->getCompoundTag(ItemEntity::TAG_ITEM);
if($itemTag === null){
throw new SavedDataLoadingException("Expected \"Item\" NBT tag not found");
throw new SavedDataLoadingException("Expected \"" . ItemEntity::TAG_ITEM . "\" NBT tag not found");
}
$item = Item::nbtDeserialize($itemTag);
@ -126,14 +129,14 @@ final class EntityFactory{
}, ['Item', 'minecraft:item'], LegacyIds::ITEM);
$this->register(Painting::class, function(World $world, CompoundTag $nbt) : Painting{
$motive = PaintingMotive::getMotiveByName($nbt->getString("Motive"));
$motive = PaintingMotive::getMotiveByName($nbt->getString(Painting::TAG_MOTIVE));
if($motive === null){
throw new SavedDataLoadingException("Unknown painting motive");
}
$blockIn = new Vector3($nbt->getInt("TileX"), $nbt->getInt("TileY"), $nbt->getInt("TileZ"));
if(($directionTag = $nbt->getTag("Direction")) instanceof ByteTag){
$blockIn = new Vector3($nbt->getInt(Painting::TAG_TILE_X), $nbt->getInt(Painting::TAG_TILE_Y), $nbt->getInt(Painting::TAG_TILE_Z));
if(($directionTag = $nbt->getTag(Painting::TAG_DIRECTION_BE)) instanceof ByteTag){
$facing = Painting::DATA_TO_FACING[$directionTag->getValue()] ?? Facing::NORTH;
}elseif(($facingTag = $nbt->getTag("Facing")) instanceof ByteTag){
}elseif(($facingTag = $nbt->getTag(Painting::TAG_FACING_JE)) instanceof ByteTag){
$facing = Painting::DATA_TO_FACING[$facingTag->getValue()] ?? Facing::NORTH;
}else{
throw new SavedDataLoadingException("Missing facing info");
@ -217,7 +220,7 @@ final class EntityFactory{
*/
public function createFromData(World $world, CompoundTag $nbt) : ?Entity{
try{
$saveId = $nbt->getTag("identifier") ?? $nbt->getTag("id");
$saveId = $nbt->getTag(self::TAG_IDENTIFIER) ?? $nbt->getTag(self::TAG_LEGACY_ID);
$func = null;
if($saveId instanceof StringTag){
$func = $this->creationFuncs[$saveId->getValue()] ?? null;
@ -238,7 +241,7 @@ final class EntityFactory{
public function injectSaveId(string $class, CompoundTag $saveData) : void{
if(isset($this->saveNames[$class])){
$saveData->setTag("identifier", new StringTag($this->saveNames[$class]));
$saveData->setTag(self::TAG_IDENTIFIER, new StringTag($this->saveNames[$class]));
}else{
throw new \InvalidArgumentException("Entity $class is not registered");
}

View File

@ -77,6 +77,26 @@ use function random_int;
class Human extends Living implements ProjectileSource, InventoryHolder{
private const TAG_INVENTORY = "Inventory"; //TAG_List<TAG_Compound>
private const TAG_OFF_HAND_ITEM = "OffHandItem"; //TAG_Compound
private const TAG_ENDER_CHEST_INVENTORY = "EnderChestInventory"; //TAG_List<TAG_Compound>
private const TAG_SELECTED_INVENTORY_SLOT = "SelectedInventorySlot"; //TAG_Int
private const TAG_FOOD_LEVEL = "foodLevel"; //TAG_Int
private const TAG_FOOD_EXHAUSTION_LEVEL = "foodExhaustionLevel"; //TAG_Float
private const TAG_FOOD_SATURATION_LEVEL = "foodSaturationLevel"; //TAG_Float
private const TAG_FOOD_TICK_TIMER = "foodTickTimer"; //TAG_Int
private const TAG_XP_LEVEL = "XpLevel"; //TAG_Int
private const TAG_XP_PROGRESS = "XpP"; //TAG_Float
private const TAG_LIFETIME_XP_TOTAL = "XpTotal"; //TAG_Int
private const TAG_XP_SEED = "XpSeed"; //TAG_Int
private const TAG_NAME_TAG = "NameTag"; //TAG_String
private const TAG_SKIN = "Skin"; //TAG_Compound
private const TAG_SKIN_NAME = "Name"; //TAG_String
private const TAG_SKIN_DATA = "Data"; //TAG_ByteArray
private const TAG_SKIN_CAPE_DATA = "CapeData"; //TAG_ByteArray
private const TAG_SKIN_GEOMETRY_NAME = "GeometryName"; //TAG_String
private const TAG_SKIN_GEOMETRY_DATA = "GeometryData"; //TAG_ByteArray
public static function getNetworkTypeId() : string{ return EntityIds::PLAYER; }
/** @var PlayerInventory */
@ -114,16 +134,16 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
* @throws SavedDataLoadingException
*/
public static function parseSkinNBT(CompoundTag $nbt) : Skin{
$skinTag = $nbt->getCompoundTag("Skin");
$skinTag = $nbt->getCompoundTag(self::TAG_SKIN);
if($skinTag === null){
throw new SavedDataLoadingException("Missing skin data");
}
return new Skin( //this throws if the skin is invalid
$skinTag->getString("Name"),
($skinDataTag = $skinTag->getTag("Data")) instanceof StringTag ? $skinDataTag->getValue() : $skinTag->getByteArray("Data"), //old data (this used to be saved as a StringTag in older versions of PM)
$skinTag->getByteArray("CapeData", ""),
$skinTag->getString("GeometryName", ""),
$skinTag->getByteArray("GeometryData", "")
$skinTag->getString(self::TAG_SKIN_NAME),
($skinDataTag = $skinTag->getTag(self::TAG_SKIN_DATA)) instanceof StringTag ? $skinDataTag->getValue() : $skinTag->getByteArray(self::TAG_SKIN_DATA), //old data (this used to be saved as a StringTag in older versions of PM)
$skinTag->getByteArray(self::TAG_SKIN_CAPE_DATA, ""),
$skinTag->getString(self::TAG_SKIN_GEOMETRY_NAME, ""),
$skinTag->getByteArray(self::TAG_SKIN_GEOMETRY_DATA, "")
);
}
@ -221,7 +241,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
* For Human entities which are not players, sets their properties such as nametag, skin and UUID from NBT.
*/
protected function initHumanData(CompoundTag $nbt) : void{
if(($nameTagTag = $nbt->getTag("NameTag")) instanceof StringTag){
if(($nameTagTag = $nbt->getTag(self::TAG_NAME_TAG)) instanceof StringTag){
$this->setNameTag($nameTagTag->getValue());
}
@ -270,7 +290,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
$this->enderInventory = new PlayerEnderInventory($this);
$this->initHumanData($nbt);
$inventoryTag = $nbt->getListTag("Inventory");
$inventoryTag = $nbt->getListTag(self::TAG_INVENTORY);
if($inventoryTag !== null){
$inventoryItems = [];
$armorInventoryItems = [];
@ -290,7 +310,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
self::populateInventoryFromListTag($this->inventory, $inventoryItems);
self::populateInventoryFromListTag($this->armorInventory, $armorInventoryItems);
}
$offHand = $nbt->getCompoundTag("OffHandItem");
$offHand = $nbt->getCompoundTag(self::TAG_OFF_HAND_ITEM);
if($offHand !== null){
$this->offHandInventory->setItem(0, Item::nbtDeserialize($offHand));
}
@ -300,7 +320,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
}
}));
$enderChestInventoryTag = $nbt->getListTag("EnderChestInventory");
$enderChestInventoryTag = $nbt->getListTag(self::TAG_ENDER_CHEST_INVENTORY);
if($enderChestInventoryTag !== null){
$enderChestInventoryItems = [];
@ -311,24 +331,24 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
self::populateInventoryFromListTag($this->enderInventory, $enderChestInventoryItems);
}
$this->inventory->setHeldItemIndex($nbt->getInt("SelectedInventorySlot", 0));
$this->inventory->setHeldItemIndex($nbt->getInt(self::TAG_SELECTED_INVENTORY_SLOT, 0));
$this->inventory->getHeldItemIndexChangeListeners()->add(function(int $oldIndex) : void{
foreach($this->getViewers() as $viewer){
$viewer->getNetworkSession()->onMobMainHandItemChange($this);
}
});
$this->hungerManager->setFood((float) $nbt->getInt("foodLevel", (int) $this->hungerManager->getFood()));
$this->hungerManager->setExhaustion($nbt->getFloat("foodExhaustionLevel", $this->hungerManager->getExhaustion()));
$this->hungerManager->setSaturation($nbt->getFloat("foodSaturationLevel", $this->hungerManager->getSaturation()));
$this->hungerManager->setFoodTickTimer($nbt->getInt("foodTickTimer", $this->hungerManager->getFoodTickTimer()));
$this->hungerManager->setFood((float) $nbt->getInt(self::TAG_FOOD_LEVEL, (int) $this->hungerManager->getFood()));
$this->hungerManager->setExhaustion($nbt->getFloat(self::TAG_FOOD_EXHAUSTION_LEVEL, $this->hungerManager->getExhaustion()));
$this->hungerManager->setSaturation($nbt->getFloat(self::TAG_FOOD_SATURATION_LEVEL, $this->hungerManager->getSaturation()));
$this->hungerManager->setFoodTickTimer($nbt->getInt(self::TAG_FOOD_TICK_TIMER, $this->hungerManager->getFoodTickTimer()));
$this->xpManager->setXpAndProgressNoEvent(
$nbt->getInt("XpLevel", 0),
$nbt->getFloat("XpP", 0.0));
$this->xpManager->setLifetimeTotalXp($nbt->getInt("XpTotal", 0));
$nbt->getInt(self::TAG_XP_LEVEL, 0),
$nbt->getFloat(self::TAG_XP_PROGRESS, 0.0));
$this->xpManager->setLifetimeTotalXp($nbt->getInt(self::TAG_LIFETIME_XP_TOTAL, 0));
if(($xpSeedTag = $nbt->getTag("XpSeed")) instanceof IntTag){
if(($xpSeedTag = $nbt->getTag(self::TAG_XP_SEED)) instanceof IntTag){
$this->xpSeed = $xpSeedTag->getValue();
}else{
$this->xpSeed = random_int(Limits::INT32_MIN, Limits::INT32_MAX);
@ -397,18 +417,18 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setInt("foodLevel", (int) $this->hungerManager->getFood());
$nbt->setFloat("foodExhaustionLevel", $this->hungerManager->getExhaustion());
$nbt->setFloat("foodSaturationLevel", $this->hungerManager->getSaturation());
$nbt->setInt("foodTickTimer", $this->hungerManager->getFoodTickTimer());
$nbt->setInt(self::TAG_FOOD_LEVEL, (int) $this->hungerManager->getFood());
$nbt->setFloat(self::TAG_FOOD_EXHAUSTION_LEVEL, $this->hungerManager->getExhaustion());
$nbt->setFloat(self::TAG_FOOD_SATURATION_LEVEL, $this->hungerManager->getSaturation());
$nbt->setInt(self::TAG_FOOD_TICK_TIMER, $this->hungerManager->getFoodTickTimer());
$nbt->setInt("XpLevel", $this->xpManager->getXpLevel());
$nbt->setFloat("XpP", $this->xpManager->getXpProgress());
$nbt->setInt("XpTotal", $this->xpManager->getLifetimeTotalXp());
$nbt->setInt("XpSeed", $this->xpSeed);
$nbt->setInt(self::TAG_XP_LEVEL, $this->xpManager->getXpLevel());
$nbt->setFloat(self::TAG_XP_PROGRESS, $this->xpManager->getXpProgress());
$nbt->setInt(self::TAG_LIFETIME_XP_TOTAL, $this->xpManager->getLifetimeTotalXp());
$nbt->setInt(self::TAG_XP_SEED, $this->xpSeed);
$inventoryTag = new ListTag([], NBT::TAG_Compound);
$nbt->setTag("Inventory", $inventoryTag);
$nbt->setTag(self::TAG_INVENTORY, $inventoryTag);
if($this->inventory !== null){
//Normal inventory
$slotCount = $this->inventory->getSize() + $this->inventory->getHotbarSize();
@ -427,11 +447,11 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
}
}
$nbt->setInt("SelectedInventorySlot", $this->inventory->getHeldItemIndex());
$nbt->setInt(self::TAG_SELECTED_INVENTORY_SLOT, $this->inventory->getHeldItemIndex());
}
$offHandItem = $this->offHandInventory->getItem(0);
if(!$offHandItem->isNull()){
$nbt->setTag("OffHandItem", $offHandItem->nbtSerialize());
$nbt->setTag(self::TAG_OFF_HAND_ITEM, $offHandItem->nbtSerialize());
}
if($this->enderInventory !== null){
@ -446,16 +466,16 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
}
}
$nbt->setTag("EnderChestInventory", new ListTag($items, NBT::TAG_Compound));
$nbt->setTag(self::TAG_ENDER_CHEST_INVENTORY, new ListTag($items, NBT::TAG_Compound));
}
if($this->skin !== null){
$nbt->setTag("Skin", CompoundTag::create()
->setString("Name", $this->skin->getSkinId())
->setByteArray("Data", $this->skin->getSkinData())
->setByteArray("CapeData", $this->skin->getCapeData())
->setString("GeometryName", $this->skin->getGeometryName())
->setByteArray("GeometryData", $this->skin->getGeometryData())
$nbt->setTag(self::TAG_SKIN, CompoundTag::create()
->setString(self::TAG_SKIN_NAME, $this->skin->getSkinId())
->setByteArray(self::TAG_SKIN_DATA, $this->skin->getSkinData())
->setByteArray(self::TAG_SKIN_CAPE_DATA, $this->skin->getCapeData())
->setString(self::TAG_SKIN_GEOMETRY_NAME, $this->skin->getGeometryName())
->setByteArray(self::TAG_SKIN_GEOMETRY_DATA, $this->skin->getGeometryData())
);
}

View File

@ -77,6 +77,16 @@ use const M_PI;
abstract class Living extends Entity{
protected const DEFAULT_BREATH_TICKS = 300;
private const TAG_LEGACY_HEALTH = "HealF"; //TAG_Float
private const TAG_HEALTH = "Health"; //TAG_Float
private const TAG_BREATH_TICKS = "Air"; //TAG_Short
private const TAG_ACTIVE_EFFECTS = "ActiveEffects"; //TAG_List<TAG_Compound>
private const TAG_EFFECT_ID = "Id"; //TAG_Byte
private const TAG_EFFECT_DURATION = "Duration"; //TAG_Int
private const TAG_EFFECT_AMPLIFIER = "Amplifier"; //TAG_Byte
private const TAG_EFFECT_SHOW_PARTICLES = "ShowParticles"; //TAG_Byte
private const TAG_EFFECT_AMBIENT = "Ambient"; //TAG_Byte
protected $gravity = 0.08;
protected $drag = 0.02;
@ -143,9 +153,9 @@ abstract class Living extends Entity{
$health = $this->getMaxHealth();
if(($healFTag = $nbt->getTag("HealF")) instanceof FloatTag){
if(($healFTag = $nbt->getTag(self::TAG_LEGACY_HEALTH)) instanceof FloatTag){
$health = $healFTag->getValue();
}elseif(($healthTag = $nbt->getTag("Health")) instanceof ShortTag){
}elseif(($healthTag = $nbt->getTag(self::TAG_HEALTH)) instanceof ShortTag){
$health = $healthTag->getValue(); //Older versions of PocketMine-MP incorrectly saved this as a short instead of a float
}elseif($healthTag instanceof FloatTag){
$health = $healthTag->getValue();
@ -153,23 +163,23 @@ abstract class Living extends Entity{
$this->setHealth($health);
$this->setAirSupplyTicks($nbt->getShort("Air", self::DEFAULT_BREATH_TICKS));
$this->setAirSupplyTicks($nbt->getShort(self::TAG_BREATH_TICKS, self::DEFAULT_BREATH_TICKS));
/** @var CompoundTag[]|ListTag|null $activeEffectsTag */
$activeEffectsTag = $nbt->getListTag("ActiveEffects");
$activeEffectsTag = $nbt->getListTag(self::TAG_ACTIVE_EFFECTS);
if($activeEffectsTag !== null){
foreach($activeEffectsTag as $e){
$effect = EffectIdMap::getInstance()->fromId($e->getByte("Id"));
$effect = EffectIdMap::getInstance()->fromId($e->getByte(self::TAG_EFFECT_ID));
if($effect === null){
continue;
}
$this->effectManager->add(new EffectInstance(
$effect,
$e->getInt("Duration"),
Binary::unsignByte($e->getByte("Amplifier")),
$e->getByte("ShowParticles", 1) !== 0,
$e->getByte("Ambient", 0) !== 0
$e->getInt(self::TAG_EFFECT_DURATION),
Binary::unsignByte($e->getByte(self::TAG_EFFECT_AMPLIFIER)),
$e->getByte(self::TAG_EFFECT_SHOW_PARTICLES, 1) !== 0,
$e->getByte(self::TAG_EFFECT_AMBIENT, 0) !== 0
));
}
}
@ -279,22 +289,22 @@ abstract class Living extends Entity{
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setFloat("Health", $this->getHealth());
$nbt->setFloat(self::TAG_HEALTH, $this->getHealth());
$nbt->setShort("Air", $this->getAirSupplyTicks());
$nbt->setShort(self::TAG_BREATH_TICKS, $this->getAirSupplyTicks());
if(count($this->effectManager->all()) > 0){
$effects = [];
foreach($this->effectManager->all() as $effect){
$effects[] = CompoundTag::create()
->setByte("Id", EffectIdMap::getInstance()->toId($effect->getType()))
->setByte("Amplifier", Binary::signByte($effect->getAmplifier()))
->setInt("Duration", $effect->getDuration())
->setByte("Ambient", $effect->isAmbient() ? 1 : 0)
->setByte("ShowParticles", $effect->isVisible() ? 1 : 0);
->setByte(self::TAG_EFFECT_ID, EffectIdMap::getInstance()->toId($effect->getType()))
->setByte(self::TAG_EFFECT_AMPLIFIER, Binary::signByte($effect->getAmplifier()))
->setInt(self::TAG_EFFECT_DURATION, $effect->getDuration())
->setByte(self::TAG_EFFECT_AMBIENT, $effect->isAmbient() ? 1 : 0)
->setByte(self::TAG_EFFECT_SHOW_PARTICLES, $effect->isVisible() ? 1 : 0);
}
$nbt->setTag("ActiveEffects", new ListTag($effects));
$nbt->setTag(self::TAG_ACTIVE_EFFECTS, new ListTag($effects));
}
return $nbt;

View File

@ -36,6 +36,8 @@ class Villager extends Living implements Ageable{
public const PROFESSION_BLACKSMITH = 3;
public const PROFESSION_BUTCHER = 4;
private const TAG_PROFESSION = "Profession"; //TAG_Int
public static function getNetworkTypeId() : string{ return EntityIds::VILLAGER; }
private bool $baby = false;
@ -53,7 +55,7 @@ class Villager extends Living implements Ageable{
parent::initEntity($nbt);
/** @var int $profession */
$profession = $nbt->getInt("Profession", self::PROFESSION_FARMER);
$profession = $nbt->getInt(self::TAG_PROFESSION, self::PROFESSION_FARMER);
if($profession > 4 || $profession < 0){
$profession = self::PROFESSION_FARMER;
@ -64,7 +66,7 @@ class Villager extends Living implements Ageable{
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setInt("Profession", $this->getProfession());
$nbt->setInt(self::TAG_PROFESSION, $this->getProfession());
return $nbt;
}

View File

@ -40,6 +40,7 @@ class ExperienceOrb extends Entity{
public const TAG_VALUE_PC = "Value"; //short
public const TAG_VALUE_PE = "experience value"; //int (WTF?)
private const TAG_AGE = "Age"; //TAG_Short
/** Max distance an orb will follow a player across. */
public const MAX_TARGET_DISTANCE = 8.0;
@ -109,13 +110,13 @@ class ExperienceOrb extends Entity{
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->age = $nbt->getShort("Age", 0);
$this->age = $nbt->getShort(self::TAG_AGE, 0);
}
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setShort("Age", $this->age);
$nbt->setShort(self::TAG_AGE, $this->age);
$nbt->setShort(self::TAG_VALUE_PC, $this->getXpValue());
$nbt->setInt(self::TAG_VALUE_PE, $this->getXpValue());

View File

@ -44,6 +44,10 @@ use function abs;
class FallingBlock extends Entity{
private const TAG_TILE_ID = "TileID"; //TAG_Int
private const TAG_TILE = "Tile"; //TAG_Byte
private const TAG_DATA = "Data"; //TAG_Byte
public static function getNetworkTypeId() : string{ return EntityIds::FALLING_BLOCK; }
protected $gravity = 0.04;
@ -65,9 +69,9 @@ class FallingBlock extends Entity{
$blockId = 0;
//TODO: 1.8+ save format
if(($tileIdTag = $nbt->getTag("TileID")) instanceof IntTag){
if(($tileIdTag = $nbt->getTag(self::TAG_TILE_ID)) instanceof IntTag){
$blockId = $tileIdTag->getValue();
}elseif(($tileTag = $nbt->getTag("Tile")) instanceof ByteTag){
}elseif(($tileTag = $nbt->getTag(self::TAG_TILE)) instanceof ByteTag){
$blockId = $tileTag->getValue();
}
@ -75,7 +79,7 @@ class FallingBlock extends Entity{
throw new SavedDataLoadingException("Missing block info from NBT");
}
$damage = $nbt->getByte("Data", 0);
$damage = $nbt->getByte(self::TAG_DATA, 0);
return $factory->get($blockId, $damage);
}
@ -138,8 +142,8 @@ class FallingBlock extends Entity{
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setInt("TileID", $this->block->getId());
$nbt->setByte("Data", $this->block->getMeta());
$nbt->setInt(self::TAG_TILE_ID, $this->block->getId());
$nbt->setByte(self::TAG_DATA, $this->block->getMeta());
return $nbt;
}

View File

@ -43,6 +43,13 @@ use function max;
class ItemEntity extends Entity{
private const TAG_HEALTH = "Health"; //TAG_Short
private const TAG_AGE = "Age"; //TAG_Short
private const TAG_PICKUP_DELAY = "PickupDelay"; //TAG_Short
private const TAG_OWNER = "Owner"; //TAG_String
private const TAG_THROWER = "Thrower"; //TAG_String
public const TAG_ITEM = "Item"; //TAG_Compound
public static function getNetworkTypeId() : string{ return EntityIds::ITEM; }
public const MERGE_CHECK_PERIOD = 2; //0.1 seconds
@ -81,17 +88,17 @@ class ItemEntity extends Entity{
parent::initEntity($nbt);
$this->setMaxHealth(5);
$this->setHealth($nbt->getShort("Health", (int) $this->getHealth()));
$this->setHealth($nbt->getShort(self::TAG_HEALTH, (int) $this->getHealth()));
$age = $nbt->getShort("Age", 0);
$age = $nbt->getShort(self::TAG_AGE, 0);
if($age === -32768){
$this->despawnDelay = self::NEVER_DESPAWN;
}else{
$this->despawnDelay = max(0, self::DEFAULT_DESPAWN_DELAY - $age);
}
$this->pickupDelay = $nbt->getShort("PickupDelay", $this->pickupDelay);
$this->owner = $nbt->getString("Owner", $this->owner);
$this->thrower = $nbt->getString("Thrower", $this->thrower);
$this->pickupDelay = $nbt->getShort(self::TAG_PICKUP_DELAY, $this->pickupDelay);
$this->owner = $nbt->getString(self::TAG_OWNER, $this->owner);
$this->thrower = $nbt->getString(self::TAG_THROWER, $this->thrower);
}
protected function onFirstUpdate(int $currentTick) : void{
@ -195,20 +202,20 @@ class ItemEntity extends Entity{
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setTag("Item", $this->item->nbtSerialize());
$nbt->setShort("Health", (int) $this->getHealth());
$nbt->setTag(self::TAG_ITEM, $this->item->nbtSerialize());
$nbt->setShort(self::TAG_HEALTH, (int) $this->getHealth());
if($this->despawnDelay === self::NEVER_DESPAWN){
$age = -32768;
}else{
$age = self::DEFAULT_DESPAWN_DELAY - $this->despawnDelay;
}
$nbt->setShort("Age", $age);
$nbt->setShort("PickupDelay", $this->pickupDelay);
$nbt->setShort(self::TAG_AGE, $age);
$nbt->setShort(self::TAG_PICKUP_DELAY, $this->pickupDelay);
if($this->owner !== null){
$nbt->setString("Owner", $this->owner);
$nbt->setString(self::TAG_OWNER, $this->owner);
}
if($this->thrower !== null){
$nbt->setString("Thrower", $this->thrower);
$nbt->setString(self::TAG_THROWER, $this->thrower);
}
return $nbt;

View File

@ -41,6 +41,13 @@ use pocketmine\world\World;
use function ceil;
class Painting extends Entity{
public const TAG_TILE_X = "TileX"; //TAG_Int
public const TAG_TILE_Y = "TileY"; //TAG_Int
public const TAG_TILE_Z = "TileZ"; //TAG_Int
public const TAG_FACING_JE = "Facing"; //TAG_Byte
public const TAG_DIRECTION_BE = "Direction"; //TAG_Byte
public const TAG_MOTIVE = "Motive"; //TAG_String
public static function getNetworkTypeId() : string{ return EntityIds::PAINTING; }
public const DATA_TO_FACING = [
@ -88,14 +95,14 @@ class Painting extends Entity{
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);
$nbt->setInt(self::TAG_TILE_X, (int) $this->blockIn->x);
$nbt->setInt(self::TAG_TILE_Y, (int) $this->blockIn->y);
$nbt->setInt(self::TAG_TILE_Z, (int) $this->blockIn->z);
$nbt->setByte("Facing", self::FACING_TO_DATA[$this->facing]);
$nbt->setByte("Direction", self::FACING_TO_DATA[$this->facing]); //Save both for full compatibility
$nbt->setByte(self::TAG_FACING_JE, self::FACING_TO_DATA[$this->facing]);
$nbt->setByte(self::TAG_DIRECTION_BE, self::FACING_TO_DATA[$this->facing]); //Save both for full compatibility
$nbt->setString("Motive", $this->motive->getName());
$nbt->setString(self::TAG_MOTIVE, $this->motive->getName());
return $nbt;
}

View File

@ -39,6 +39,8 @@ use pocketmine\world\Position;
class PrimedTNT extends Entity implements Explosive{
private const TAG_FUSE = "Fuse"; //TAG_Short
public static function getNetworkTypeId() : string{ return EntityIds::TNT; }
protected $gravity = 0.04;
@ -81,7 +83,7 @@ class PrimedTNT extends Entity implements Explosive{
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->fuse = $nbt->getShort("Fuse", 80);
$this->fuse = $nbt->getShort(self::TAG_FUSE, 80);
}
public function canCollideWith(Entity $entity) : bool{
@ -90,7 +92,7 @@ class PrimedTNT extends Entity implements Explosive{
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setShort("Fuse", $this->fuse);
$nbt->setShort(self::TAG_FUSE, $this->fuse);
return $nbt;
}

View File

@ -52,6 +52,7 @@ class Arrow extends Projectile{
private const TAG_PICKUP = "pickup"; //TAG_Byte
public const TAG_CRIT = "crit"; //TAG_Byte
private const TAG_LIFE = "life"; //TAG_Short
protected $gravity = 0.05;
protected $drag = 0.01;
@ -83,14 +84,14 @@ class Arrow extends Projectile{
$this->pickupMode = $nbt->getByte(self::TAG_PICKUP, self::PICKUP_ANY);
$this->critical = $nbt->getByte(self::TAG_CRIT, 0) === 1;
$this->collideTicks = $nbt->getShort("life", $this->collideTicks);
$this->collideTicks = $nbt->getShort(self::TAG_LIFE, $this->collideTicks);
}
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setByte(self::TAG_PICKUP, $this->pickupMode);
$nbt->setByte(self::TAG_CRIT, $this->critical ? 1 : 0);
$nbt->setShort("life", $this->collideTicks);
$nbt->setShort(self::TAG_LIFE, $this->collideTicks);
return $nbt;
}

View File

@ -50,6 +50,12 @@ use const M_PI;
use const PHP_INT_MAX;
abstract class Projectile extends Entity{
private const TAG_DAMAGE = "damage"; //TAG_Double
private const TAG_TILE_X = "tileX"; //TAG_Int
private const TAG_TILE_Y = "tileY"; //TAG_Int
private const TAG_TILE_Z = "tileZ"; //TAG_Int
private const TAG_BLOCK_ID = "blockId"; //TAG_Int
private const TAG_BLOCK_DATA = "blockData"; //TAG_Byte
/** @var float */
protected $damage = 0.0;
@ -75,22 +81,22 @@ abstract class Projectile extends Entity{
$this->setMaxHealth(1);
$this->setHealth(1);
$this->damage = $nbt->getDouble("damage", $this->damage);
$this->damage = $nbt->getDouble(self::TAG_DAMAGE, $this->damage);
(function() use ($nbt) : void{
if(($tileXTag = $nbt->getTag("tileX")) instanceof IntTag && ($tileYTag = $nbt->getTag("tileY")) instanceof IntTag && ($tileZTag = $nbt->getTag("tileZ")) instanceof IntTag){
if(($tileXTag = $nbt->getTag(self::TAG_TILE_X)) instanceof IntTag && ($tileYTag = $nbt->getTag(self::TAG_TILE_Y)) instanceof IntTag && ($tileZTag = $nbt->getTag(self::TAG_TILE_Z)) instanceof IntTag){
$blockPos = new Vector3($tileXTag->getValue(), $tileYTag->getValue(), $tileZTag->getValue());
}else{
return;
}
if(($blockIdTag = $nbt->getTag("blockId")) instanceof IntTag){
if(($blockIdTag = $nbt->getTag(self::TAG_BLOCK_ID)) instanceof IntTag){
$blockId = $blockIdTag->getValue();
}else{
return;
}
if(($blockDataTag = $nbt->getTag("blockData")) instanceof ByteTag){
if(($blockDataTag = $nbt->getTag(self::TAG_BLOCK_DATA)) instanceof ByteTag){
$blockData = $blockDataTag->getValue();
}else{
return;
@ -134,17 +140,17 @@ abstract class Projectile extends Entity{
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setDouble("damage", $this->damage);
$nbt->setDouble(self::TAG_DAMAGE, $this->damage);
if($this->blockHit !== null){
$pos = $this->blockHit->getPosition();
$nbt->setInt("tileX", $pos->x);
$nbt->setInt("tileY", $pos->y);
$nbt->setInt("tileZ", $pos->z);
$nbt->setInt(self::TAG_TILE_X, $pos->x);
$nbt->setInt(self::TAG_TILE_Y, $pos->y);
$nbt->setInt(self::TAG_TILE_Z, $pos->z);
//we intentionally use different ones to PC because we don't have stringy IDs
$nbt->setInt("blockId", $this->blockHit->getId());
$nbt->setByte("blockData", $this->blockHit->getMeta());
$nbt->setInt(self::TAG_BLOCK_ID, $this->blockHit->getId());
$nbt->setByte(self::TAG_BLOCK_DATA, $this->blockHit->getMeta());
}
return $nbt;

View File

@ -59,6 +59,9 @@ class Item implements \JsonSerializable{
use ItemEnchantmentHandlingTrait;
public const TAG_ENCH = "ench";
private const TAG_ENCH_ID = "id"; //TAG_Short
private const TAG_ENCH_LVL = "lvl"; //TAG_Short
public const TAG_DISPLAY = "display";
public const TAG_BLOCK_ENTITY_TAG = "BlockEntityTag";
@ -67,6 +70,16 @@ class Item implements \JsonSerializable{
public const TAG_KEEP_ON_DEATH = "minecraft:keep_on_death";
private const TAG_ID = "id"; //TAG_Short
private const TAG_COUNT = "Count"; //TAG_Byte
private const TAG_DAMAGE = "Damage"; //TAG_Short
private const TAG_TAG = "tag"; //TAG_Compound
public const TAG_SLOT = "Slot"; //TAG_Byte
private const TAG_CAN_PLACE_ON = "CanPlaceOn"; //TAG_List<TAG_String>
private const TAG_CAN_DESTROY = "CanDestroy"; //TAG_List<TAG_String>
private ItemIdentifier $identifier;
private CompoundTag $nbt;
@ -305,8 +318,8 @@ class Item implements \JsonSerializable{
if($enchantments !== null && $enchantments->getTagType() === NBT::TAG_Compound){
/** @var CompoundTag $enchantment */
foreach($enchantments as $enchantment){
$magicNumber = $enchantment->getShort("id", -1);
$level = $enchantment->getShort("lvl", 0);
$magicNumber = $enchantment->getShort(self::TAG_ENCH_ID, -1);
$level = $enchantment->getShort(self::TAG_ENCH_LVL, 0);
if($level <= 0){
continue;
}
@ -320,7 +333,7 @@ class Item implements \JsonSerializable{
$this->blockEntityTag = $tag->getCompoundTag(self::TAG_BLOCK_ENTITY_TAG);
$this->canPlaceOn = [];
$canPlaceOn = $tag->getListTag("CanPlaceOn");
$canPlaceOn = $tag->getListTag(self::TAG_CAN_PLACE_ON);
if($canPlaceOn !== null && $canPlaceOn->getTagType() === NBT::TAG_String){
/** @var StringTag $entry */
foreach($canPlaceOn as $entry){
@ -328,7 +341,7 @@ class Item implements \JsonSerializable{
}
}
$this->canDestroy = [];
$canDestroy = $tag->getListTag("CanDestroy");
$canDestroy = $tag->getListTag(self::TAG_CAN_DESTROY);
if($canDestroy !== null && $canDestroy->getTagType() === NBT::TAG_String){
/** @var StringTag $entry */
foreach($canDestroy as $entry){
@ -363,8 +376,8 @@ class Item implements \JsonSerializable{
$ench = new ListTag();
foreach($this->getEnchantments() as $enchantmentInstance){
$ench->push(CompoundTag::create()
->setShort("id", EnchantmentIdMap::getInstance()->toId($enchantmentInstance->getType()))
->setShort("lvl", $enchantmentInstance->getLevel())
->setShort(self::TAG_ENCH_ID, EnchantmentIdMap::getInstance()->toId($enchantmentInstance->getType()))
->setShort(self::TAG_ENCH_LVL, $enchantmentInstance->getLevel())
);
}
$tag->setTag(self::TAG_ENCH, $ench);
@ -381,18 +394,18 @@ class Item implements \JsonSerializable{
foreach($this->canPlaceOn as $item){
$canPlaceOn->push(new StringTag($item));
}
$tag->setTag("CanPlaceOn", $canPlaceOn);
$tag->setTag(self::TAG_CAN_PLACE_ON, $canPlaceOn);
}else{
$tag->removeTag("CanPlaceOn");
$tag->removeTag(self::TAG_CAN_PLACE_ON);
}
if(count($this->canDestroy) > 0){
$canDestroy = new ListTag();
foreach($this->canDestroy as $item){
$canDestroy->push(new StringTag($item));
}
$tag->setTag("CanDestroy", $canDestroy);
$tag->setTag(self::TAG_CAN_DESTROY, $canDestroy);
}else{
$tag->removeTag("CanDestroy");
$tag->removeTag(self::TAG_CAN_DESTROY);
}
if($this->keepOnDeath){
@ -688,17 +701,17 @@ class Item implements \JsonSerializable{
*/
public function nbtSerialize(int $slot = -1) : CompoundTag{
$result = CompoundTag::create()
->setShort("id", $this->getId())
->setByte("Count", Binary::signByte($this->count))
->setShort("Damage", $this->getMeta());
->setShort(self::TAG_ID, $this->getId())
->setByte(self::TAG_COUNT, Binary::signByte($this->count))
->setShort(self::TAG_DAMAGE, $this->getMeta());
$tag = $this->getNamedTag();
if($tag->count() > 0){
$result->setTag("tag", $tag);
$result->setTag(self::TAG_TAG, $tag);
}
if($slot !== -1){
$result->setByte("Slot", $slot);
$result->setByte(self::TAG_SLOT, $slot);
}
return $result;
@ -710,14 +723,14 @@ class Item implements \JsonSerializable{
* @throws SavedDataLoadingException
*/
public static function nbtDeserialize(CompoundTag $tag) : Item{
if($tag->getTag("id") === null || $tag->getTag("Count") === null){
if($tag->getTag(self::TAG_ID) === null || $tag->getTag(self::TAG_COUNT) === null){
return VanillaItems::AIR();
}
$count = Binary::unsignByte($tag->getByte("Count"));
$meta = $tag->getShort("Damage", 0);
$count = Binary::unsignByte($tag->getByte(self::TAG_COUNT));
$meta = $tag->getShort(self::TAG_DAMAGE, 0);
$idTag = $tag->getTag("id");
$idTag = $tag->getTag(self::TAG_ID);
if($idTag instanceof ShortTag){
$item = ItemFactory::getInstance()->get($idTag->getValue(), $meta, $count);
}elseif($idTag instanceof StringTag){ //PC item save format
@ -732,7 +745,7 @@ class Item implements \JsonSerializable{
throw new SavedDataLoadingException("Item CompoundTag ID must be an instance of StringTag or ShortTag, " . get_class($idTag) . " given");
}
$itemNBT = $tag->getCompoundTag("tag");
$itemNBT = $tag->getCompoundTag(self::TAG_TAG);
if($itemNBT !== null){
$item->setNamedTag(clone $itemNBT);
}

View File

@ -682,7 +682,7 @@ class NetworkSession{
//TODO: we shouldn't be loading player data here at all, but right now we don't have any choice :(
$this->cachedOfflinePlayerData = $this->server->getOfflinePlayerData($this->info->getUsername());
if($checkXUID){
$recordedXUID = $this->cachedOfflinePlayerData !== null ? $this->cachedOfflinePlayerData->getTag("LastKnownXUID") : null;
$recordedXUID = $this->cachedOfflinePlayerData !== null ? $this->cachedOfflinePlayerData->getTag(Player::TAG_LAST_KNOWN_XUID) : null;
if(!($recordedXUID instanceof StringTag)){
$this->logger->debug("No previous XUID recorded, no choice but to trust this player");
}elseif(!$kickForXUIDMismatch($recordedXUID->getValue())){

View File

@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\handler;
use pocketmine\block\BaseSign;
use pocketmine\block\ItemFrame;
use pocketmine\block\Lectern;
use pocketmine\block\tile\Sign;
use pocketmine\block\utils\SignText;
use pocketmine\entity\animation\ConsumingItemAnimation;
use pocketmine\entity\Attribute;
@ -654,7 +655,7 @@ class InGamePacketHandler extends PacketHandler{
if(!($nbt instanceof CompoundTag)) throw new AssumptionFailedError("PHPStan should ensure this is a CompoundTag"); //for phpstorm's benefit
if($block instanceof BaseSign){
if(($textBlobTag = $nbt->getTag("Text")) instanceof StringTag){
if(($textBlobTag = $nbt->getTag(Sign::TAG_TEXT_BLOB)) instanceof StringTag){
try{
$text = SignText::fromBlob($textBlobTag->getValue());
}catch(\InvalidArgumentException $e){

View File

@ -37,11 +37,11 @@ class OfflinePlayer implements IPlayer{
}
public function getFirstPlayed() : ?int{
return ($this->namedtag !== null && ($firstPlayedTag = $this->namedtag->getTag("firstPlayed")) instanceof LongTag) ? $firstPlayedTag->getValue() : null;
return ($this->namedtag !== null && ($firstPlayedTag = $this->namedtag->getTag(Player::TAG_FIRST_PLAYED)) instanceof LongTag) ? $firstPlayedTag->getValue() : null;
}
public function getLastPlayed() : ?int{
return ($this->namedtag !== null && ($lastPlayedTag = $this->namedtag->getTag("lastPlayed")) instanceof LongTag) ? $lastPlayedTag->getValue() : null;
return ($this->namedtag !== null && ($lastPlayedTag = $this->namedtag->getTag(Player::TAG_LAST_PLAYED)) instanceof LongTag) ? $lastPlayedTag->getValue() : null;
}
public function hasPlayedBefore() : bool{

View File

@ -176,6 +176,16 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
private const MAX_REACH_DISTANCE_SURVIVAL = 7;
private const MAX_REACH_DISTANCE_ENTITY_INTERACTION = 8;
public const TAG_FIRST_PLAYED = "firstPlayed"; //TAG_Long
public const TAG_LAST_PLAYED = "lastPlayed"; //TAG_Long
private const TAG_GAME_MODE = "playerGameType"; //TAG_Int
private const TAG_SPAWN_WORLD = "SpawnLevel"; //TAG_String
private const TAG_SPAWN_X = "SpawnX"; //TAG_Int
private const TAG_SPAWN_Y = "SpawnY"; //TAG_Int
private const TAG_SPAWN_Z = "SpawnZ"; //TAG_Int
public const TAG_LEVEL = "Level"; //TAG_String
public const TAG_LAST_KNOWN_XUID = "LastKnownXUID"; //TAG_String
/**
* Validates the given username.
*/
@ -344,10 +354,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
}
));
$this->firstPlayed = $nbt->getLong("firstPlayed", $now = (int) (microtime(true) * 1000));
$this->lastPlayed = $nbt->getLong("lastPlayed", $now);
$this->firstPlayed = $nbt->getLong(self::TAG_FIRST_PLAYED, $now = (int) (microtime(true) * 1000));
$this->lastPlayed = $nbt->getLong(self::TAG_LAST_PLAYED, $now);
if(!$this->server->getForceGamemode() && ($gameModeTag = $nbt->getTag("playerGameType")) instanceof IntTag){
if(!$this->server->getForceGamemode() && ($gameModeTag = $nbt->getTag(self::TAG_GAME_MODE)) instanceof IntTag){
$this->internalSetGameMode(GameModeIdMap::getInstance()->fromId($gameModeTag->getValue()) ?? GameMode::SURVIVAL()); //TODO: bad hack here to avoid crashes on corrupted data
}else{
$this->internalSetGameMode($this->server->getGamemode());
@ -359,8 +369,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->setNameTagAlwaysVisible();
$this->setCanClimb();
if(($world = $this->server->getWorldManager()->getWorldByName($nbt->getString("SpawnLevel", ""))) instanceof World){
$this->spawnPosition = new Position($nbt->getInt("SpawnX"), $nbt->getInt("SpawnY"), $nbt->getInt("SpawnZ"), $world);
if(($world = $this->server->getWorldManager()->getWorldByName($nbt->getString(self::TAG_SPAWN_WORLD, ""))) instanceof World){
$this->spawnPosition = new Position($nbt->getInt(self::TAG_SPAWN_X), $nbt->getInt(self::TAG_SPAWN_Y), $nbt->getInt(self::TAG_SPAWN_Z), $world);
}
}
@ -2225,23 +2235,23 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
public function getSaveData() : CompoundTag{
$nbt = $this->saveNBT();
$nbt->setString("LastKnownXUID", $this->xuid);
$nbt->setString(self::TAG_LAST_KNOWN_XUID, $this->xuid);
if($this->location->isValid()){
$nbt->setString("Level", $this->getWorld()->getFolderName());
$nbt->setString(self::TAG_LEVEL, $this->getWorld()->getFolderName());
}
if($this->hasValidCustomSpawn()){
$spawn = $this->getSpawn();
$nbt->setString("SpawnLevel", $spawn->getWorld()->getFolderName());
$nbt->setInt("SpawnX", $spawn->getFloorX());
$nbt->setInt("SpawnY", $spawn->getFloorY());
$nbt->setInt("SpawnZ", $spawn->getFloorZ());
$nbt->setString(self::TAG_SPAWN_WORLD, $spawn->getWorld()->getFolderName());
$nbt->setInt(self::TAG_SPAWN_X, $spawn->getFloorX());
$nbt->setInt(self::TAG_SPAWN_Y, $spawn->getFloorY());
$nbt->setInt(self::TAG_SPAWN_Z, $spawn->getFloorZ());
}
$nbt->setInt("playerGameType", GameModeIdMap::getInstance()->toId($this->gamemode));
$nbt->setLong("firstPlayed", $this->firstPlayed);
$nbt->setLong("lastPlayed", (int) floor(microtime(true) * 1000));
$nbt->setInt(self::TAG_GAME_MODE, GameModeIdMap::getInstance()->toId($this->gamemode));
$nbt->setLong(self::TAG_FIRST_PLAYED, $this->firstPlayed);
$nbt->setLong(self::TAG_LAST_PLAYED, (int) floor(microtime(true) * 1000));
return $nbt;
}