Separate held item index change listener logic from PlayerInventory

This commit is contained in:
Dylan K. Taylor 2021-01-12 16:44:25 +00:00
parent 01c867b608
commit c70c0b55df
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
5 changed files with 48 additions and 17 deletions

View File

@ -264,7 +264,12 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
}
}
$this->inventory->setHeldItemIndex($nbt->getInt("SelectedInventorySlot", 0), false);
$this->inventory->setHeldItemIndex($nbt->getInt("SelectedInventorySlot", 0));
$this->inventory->getHeldItemIndexChangeListeners()->add(function(int $oldIndex) : void{
foreach($this->getViewers() as $viewer){
$viewer->getNetworkSession()->onMobEquipmentChange($this);
}
});
$this->hungerManager->setFood((float) $nbt->getInt("foodLevel", (int) $this->hungerManager->getFood()));
$this->hungerManager->setExhaustion($nbt->getFloat("foodExhaustionLevel", $this->hungerManager->getExhaustion()));
@ -457,6 +462,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
protected function onDispose() : void{
$this->inventory->removeAllViewers();
$this->inventory->getHeldItemIndexChangeListeners()->clear();
$this->enderChestInventory->removeAllViewers();
parent::onDispose();
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\inventory;
use Ds\Set;
use pocketmine\entity\Human;
use pocketmine\item\Item;
use pocketmine\player\Player;
@ -35,8 +36,15 @@ class PlayerInventory extends BaseInventory{
/** @var int */
protected $itemInHandIndex = 0;
/**
* @var \Closure[]|Set
* @phpstan-var Set<\Closure(int $oldIndex) : void>
*/
protected $heldItemIndexChangeListeners;
public function __construct(Human $player){
$this->holder = $player;
$this->heldItemIndexChangeListeners = new Set();
parent::__construct(36);
}
@ -73,25 +81,27 @@ class PlayerInventory extends BaseInventory{
/**
* Sets which hotbar slot the player is currently loading.
*
* @param int $hotbarSlot 0-8 index of the hotbar slot to hold
* @param bool $send Whether to send updates back to the inventory holder. This should usually be true for plugin calls.
* It should only be false to prevent feedback loops of equipment packets between client and server.
* @param int $hotbarSlot 0-8 index of the hotbar slot to hold
*
* @throws \InvalidArgumentException if the hotbar slot is out of range
*/
public function setHeldItemIndex(int $hotbarSlot, bool $send = true) : void{
public function setHeldItemIndex(int $hotbarSlot) : void{
$this->throwIfNotHotbarSlot($hotbarSlot);
$oldIndex = $this->itemInHandIndex;
$this->itemInHandIndex = $hotbarSlot;
if($this->holder instanceof Player and $send){
$this->holder->getNetworkSession()->getInvManager()->syncSelectedHotbarSlot();
}
foreach($this->holder->getViewers() as $viewer){
$viewer->getNetworkSession()->onMobEquipmentChange($this->holder);
foreach($this->heldItemIndexChangeListeners as $callback){
$callback($oldIndex);
}
}
/**
* @return \Closure[]|Set
* @phpstan-return Set<\Closure(int $oldIndex) : void>
*/
public function getHeldItemIndexChangeListeners() : Set{ return $this->heldItemIndexChangeListeners; }
/**
* Returns the currently-held item.
*/

View File

@ -76,6 +76,8 @@ class InventoryManager{
* @phpstan-var array<int, array<int, Item>>
*/
private $initiatedSlotChanges = [];
/** @var int */
private $clientSelectedHotbarSlot = -1;
public function __construct(Player $player, NetworkSession $session){
$this->player = $player;
@ -84,6 +86,10 @@ class InventoryManager{
$this->add(ContainerIds::INVENTORY, $this->player->getInventory());
$this->add(ContainerIds::ARMOR, $this->player->getArmorInventory());
$this->add(ContainerIds::UI, $this->player->getCursorInventory());
$this->player->getInventory()->getHeldItemIndexChangeListeners()->add(function() : void{
$this->syncSelectedHotbarSlot();
});
}
private function add(int $id, Inventory $inventory) : void{
@ -206,13 +212,21 @@ class InventoryManager{
}
}
public function onClientSelectHotbarSlot(int $slot) : void{
$this->clientSelectedHotbarSlot = $slot;
}
public function syncSelectedHotbarSlot() : void{
$this->session->sendDataPacket(MobEquipmentPacket::create(
$this->player->getId(),
TypeConverter::getInstance()->coreItemStackToNet($this->player->getInventory()->getItemInHand()),
$this->player->getInventory()->getHeldItemIndex(),
ContainerIds::INVENTORY
));
$selected = $this->player->getInventory()->getHeldItemIndex();
if($selected !== $this->clientSelectedHotbarSlot){
$this->session->sendDataPacket(MobEquipmentPacket::create(
$this->player->getId(),
TypeConverter::getInstance()->coreItemStackToNet($this->player->getInventory()->getItemInHand()),
$selected,
ContainerIds::INVENTORY
));
$this->clientSelectedHotbarSlot = $selected;
}
}
public function syncCreative() : void{

View File

@ -448,6 +448,7 @@ class InGamePacketHandler extends PacketHandler{
}
public function handleMobEquipment(MobEquipmentPacket $packet) : bool{
$this->session->getInvManager()->onClientSelectHotbarSlot($packet->hotbarSlot);
if(!$this->player->selectHotbarSlot($packet->hotbarSlot)){
$this->session->getInvManager()->syncSelectedHotbarSlot();
}

View File

@ -1373,7 +1373,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
return false;
}
$this->inventory->setHeldItemIndex($hotbarSlot, false);
$this->inventory->setHeldItemIndex($hotbarSlot);
$this->setUsingItem(false);
return true;