From d6c923b525a510c6c7675714b6286c53db3a89c4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Apr 2023 22:33:30 +0100 Subject: [PATCH] ExperienceOrb: add get/setDespawnDelay closes #5645 the code for this is borrowed from ItemEntity. I didn't feel like a base class was appropriate, and we can't (yet) declare constants in traits. --- src/entity/object/ExperienceOrb.php | 36 ++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/entity/object/ExperienceOrb.php b/src/entity/object/ExperienceOrb.php index 2b5932e9c..b2db15642 100644 --- a/src/entity/object/ExperienceOrb.php +++ b/src/entity/object/ExperienceOrb.php @@ -32,6 +32,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityIds; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; use pocketmine\player\Player; +use function max; use function sqrt; class ExperienceOrb extends Entity{ @@ -48,6 +49,10 @@ class ExperienceOrb extends Entity{ /** Split sizes used for dropping experience orbs. */ public const ORB_SPLIT_SIZES = [2477, 1237, 617, 307, 149, 73, 37, 17, 7, 3, 1]; //This is indexed biggest to smallest so that we can return as soon as we found the biggest value. + public const DEFAULT_DESPAWN_DELAY = 6000; + public const NEVER_DESPAWN = -1; + public const MAX_DESPAWN_DELAY = 32767 + self::DEFAULT_DESPAWN_DELAY; //max value storable by mojang NBT :( + /** * Returns the largest size of normal XP orb that will be spawned for the specified amount of XP. Used to split XP * up into multiple orbs when an amount of XP is dropped. @@ -82,7 +87,10 @@ class ExperienceOrb extends Entity{ public $gravity = 0.04; public $drag = 0.02; - /** @var int */ + /** + * @var int + * @deprecated + */ protected $age = 0; /** @@ -100,6 +108,8 @@ class ExperienceOrb extends Entity{ /** @var int */ protected $xpValue; + private int $despawnDelay = self::DEFAULT_DESPAWN_DELAY; + public function __construct(Location $location, int $xpValue, ?CompoundTag $nbt = null){ $this->xpValue = $xpValue; parent::__construct($location, $nbt); @@ -111,12 +121,22 @@ class ExperienceOrb extends Entity{ parent::initEntity($nbt); $this->age = $nbt->getShort(self::TAG_AGE, 0); + if($this->age === -32768){ + $this->despawnDelay = self::NEVER_DESPAWN; + }else{ + $this->despawnDelay = max(0, self::DEFAULT_DESPAWN_DELAY - $this->age); + } } public function saveNBT() : CompoundTag{ $nbt = parent::saveNBT(); - $nbt->setShort(self::TAG_AGE, $this->age); + if($this->despawnDelay === self::NEVER_DESPAWN){ + $age = -32768; + }else{ + $age = self::DEFAULT_DESPAWN_DELAY - $this->despawnDelay; + } + $nbt->setShort(self::TAG_AGE, $age); $nbt->setShort(self::TAG_VALUE_PC, $this->getXpValue()); $nbt->setInt(self::TAG_VALUE_PE, $this->getXpValue()); @@ -124,6 +144,15 @@ class ExperienceOrb extends Entity{ return $nbt; } + public function getDespawnDelay() : int{ return $this->despawnDelay; } + + public function setDespawnDelay(int $despawnDelay) : void{ + if(($despawnDelay < 0 || $despawnDelay > self::MAX_DESPAWN_DELAY) && $despawnDelay !== self::NEVER_DESPAWN){ + throw new \InvalidArgumentException("Despawn ticker must be in range 0 ... " . self::MAX_DESPAWN_DELAY . " or " . self::NEVER_DESPAWN . ", got $despawnDelay"); + } + $this->despawnDelay = $despawnDelay; + } + public function getXpValue() : int{ return $this->xpValue; } @@ -161,7 +190,8 @@ class ExperienceOrb extends Entity{ $hasUpdate = parent::entityBaseTick($tickDiff); $this->age += $tickDiff; - if($this->age > 6000){ + $this->despawnDelay -= $tickDiff; + if($this->despawnDelay <= 0){ $this->flagForDespawn(); return true; }