Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented a proper way to handle items cooldown #6405

Open
wants to merge 9 commits into
base: minor-next
Choose a base branch
from
4 changes: 4 additions & 0 deletions src/item/ChorusFruit.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,8 @@ public function onConsume(Living $consumer) : void{
public function getCooldownTicks() : int{
return 20;
}

public function getCooldownTag() : ?string{
return ItemCooldownTags::CHORUS_FRUIT;
}
}
4 changes: 4 additions & 0 deletions src/item/EnderPearl.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,8 @@ public function getThrowForce() : float{
public function getCooldownTicks() : int{
return 20;
}

public function getCooldownTag() : ?string{
return ItemCooldownTags::ENDER_PEARL;
}
}
14 changes: 14 additions & 0 deletions src/item/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,20 @@ public function getCooldownTicks() : int{
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.
*
Expand Down
45 changes: 45 additions & 0 deletions src/item/ItemCooldownTags.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/

declare(strict_types=1);

namespace pocketmine\item;

/**
* Tags used by items to determine their cooldown group.
*
* These tag values are not related to Minecraft internal IDs.
* They only share a visual similarity because these are the most obvious values to use.
* Any arbitrary string can be used.
*
* @see Item::getCooldownTag()
*/
final class ItemCooldownTags{

private function __construct(){
//NOOP
}

public const CHORUS_FRUIT = "chorus_fruit";
public const ENDER_PEARL = "ender_pearl";
public const SHIELD = "shield";
public const GOAT_HORN = "goat_horn";
}
10 changes: 10 additions & 0 deletions src/network/mcpe/NetworkSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use pocketmine\event\server\DataPacketReceiveEvent;
use pocketmine\event\server\DataPacketSendEvent;
use pocketmine\form\Form;
use pocketmine\item\Item;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\Translatable;
use pocketmine\math\Vector3;
Expand Down Expand Up @@ -65,6 +66,7 @@
use pocketmine\network\mcpe\protocol\PacketDecodeException;
use pocketmine\network\mcpe\protocol\PacketPool;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerStartItemCooldownPacket;
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
Expand Down Expand Up @@ -111,6 +113,7 @@
use pocketmine\utils\BinaryStream;
use pocketmine\utils\ObjectSet;
use pocketmine\utils\TextFormat;
use pocketmine\world\format\io\GlobalItemDataHandlers;
use pocketmine\world\Position;
use pocketmine\YmlServerProperties;
use function array_map;
Expand Down Expand Up @@ -1289,6 +1292,13 @@ public function onOpenSignEditor(Vector3 $signPosition, bool $frontSide) : void{
$this->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();
Expand Down
13 changes: 9 additions & 4 deletions src/player/Player.php
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,11 @@ public static function isValidUserName(?string $name) : bool{
protected string $locale = "en_US";

protected int $startAction = -1;
/** @var int[] ID => ticks map */

/**
* @phpstan-var array<int|string, int>
* @var int[] stateId|cooldownTag => ticks map
*/
protected array $usedItemsCooldown = [];

private int $lastEmoteTick = 0;
Expand Down Expand Up @@ -697,15 +701,15 @@ public function getItemUseDuration() : int{
*/
public function getItemCooldownExpiry(Item $item) : int{
$this->checkItemCooldowns();
return $this->usedItemsCooldown[$item->getStateId()] ?? 0;
return $this->usedItemsCooldown[$item->getCooldownTag() ?? $item->getStateId()] ?? 0;
}

/**
* Returns whether the player has a cooldown period left before it can use the given item again.
*/
public function hasItemCooldown(Item $item) : bool{
$this->checkItemCooldowns();
return isset($this->usedItemsCooldown[$item->getStateId()]);
return isset($this->usedItemsCooldown[$item->getCooldownTag() ?? $item->getStateId()]);
}

/**
Expand All @@ -714,7 +718,8 @@ public function hasItemCooldown(Item $item) : bool{
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);
}
}

Expand Down