From f6e6f15c639bc09e8384416f1111eb12eff2f0b1 Mon Sep 17 00:00:00 2001 From: ipad54 <63200545+ipad54@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:28:17 +0300 Subject: [PATCH] Implemented a proper way to handle items cooldown (#6405) --- src/item/ChorusFruit.php | 4 +++ src/item/EnderPearl.php | 4 +++ src/item/Item.php | 14 +++++++++ src/item/ItemCooldownTags.php | 45 +++++++++++++++++++++++++++++ src/network/mcpe/NetworkSession.php | 10 +++++++ src/player/Player.php | 13 ++++++--- 6 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 src/item/ItemCooldownTags.php diff --git a/src/item/ChorusFruit.php b/src/item/ChorusFruit.php index c12724d7c..e10c51957 100644 --- a/src/item/ChorusFruit.php +++ b/src/item/ChorusFruit.php @@ -88,4 +88,8 @@ class ChorusFruit extends Food{ public function getCooldownTicks() : int{ return 20; } + + public function getCooldownTag() : ?string{ + return ItemCooldownTags::CHORUS_FRUIT; + } } diff --git a/src/item/EnderPearl.php b/src/item/EnderPearl.php index 76bcb358e..7109d3ae0 100644 --- a/src/item/EnderPearl.php +++ b/src/item/EnderPearl.php @@ -45,4 +45,8 @@ class EnderPearl extends ProjectileItem{ public function getCooldownTicks() : int{ return 20; } + + public function getCooldownTag() : ?string{ + return ItemCooldownTags::ENDER_PEARL; + } } diff --git a/src/item/Item.php b/src/item/Item.php index 1a74345b5..205f15e13 100644 --- a/src/item/Item.php +++ b/src/item/Item.php @@ -654,6 +654,20 @@ class Item implements \JsonSerializable{ return 0; } + /** + * Returns a tag that identifies a group of items that should have cooldown at the same time + * regardless of their state or type. + * When cooldown starts, any other items with the same cooldown tag can't be used until the cooldown expires. + * Such behaviour can be seen in goat horns and shields. + * + * If tag is null, item state id will be used to store cooldown. + * + * @see ItemCooldownTags + */ + public function getCooldownTag() : ?string{ + return null; + } + /** * Compares an Item to this Item and check if they match. * diff --git a/src/item/ItemCooldownTags.php b/src/item/ItemCooldownTags.php new file mode 100644 index 000000000..f0ef6d169 --- /dev/null +++ b/src/item/ItemCooldownTags.php @@ -0,0 +1,45 @@ +sendDataPacket(OpenSignPacket::create(BlockPosition::fromVector3($signPosition), $frontSide)); } + public function onItemCooldownChanged(Item $item, int $ticks) : void{ + $this->sendDataPacket(PlayerStartItemCooldownPacket::create( + GlobalItemDataHandlers::getSerializer()->serializeType($item)->getName(), + $ticks + )); + } + public function tick() : void{ if(!$this->isConnected()){ $this->dispose(); diff --git a/src/player/Player.php b/src/player/Player.php index d442c6a3b..8ae206e1a 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -283,7 +283,11 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ protected string $locale = "en_US"; protected int $startAction = -1; - /** @var int[] ID => ticks map */ + + /** + * @phpstan-var array + * @var int[] stateId|cooldownTag => ticks map + */ protected array $usedItemsCooldown = []; private int $lastEmoteTick = 0; @@ -697,7 +701,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ */ public function getItemCooldownExpiry(Item $item) : int{ $this->checkItemCooldowns(); - return $this->usedItemsCooldown[$item->getStateId()] ?? 0; + return $this->usedItemsCooldown[$item->getCooldownTag() ?? $item->getStateId()] ?? 0; } /** @@ -705,7 +709,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ */ public function hasItemCooldown(Item $item) : bool{ $this->checkItemCooldowns(); - return isset($this->usedItemsCooldown[$item->getStateId()]); + return isset($this->usedItemsCooldown[$item->getCooldownTag() ?? $item->getStateId()]); } /** @@ -714,7 +718,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ public function resetItemCooldown(Item $item, ?int $ticks = null) : void{ $ticks = $ticks ?? $item->getCooldownTicks(); if($ticks > 0){ - $this->usedItemsCooldown[$item->getStateId()] = $this->server->getTick() + $ticks; + $this->usedItemsCooldown[$item->getCooldownTag() ?? $item->getStateId()] = $this->server->getTick() + $ticks; + $this->getNetworkSession()->onItemCooldownChanged($item, $ticks); } }