mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-04 09:10:00 +00:00
Separate hotbar from player inventory
this allows this functionality to be used with any type of inventory, and also makes it a little nicer to use in many cases.
This commit is contained in:
parent
3e9a96b43a
commit
f98cebbd62
@ -56,7 +56,7 @@ class EnchantCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
|
||||
$item = $player->getInventory()->getItemInHand();
|
||||
$item = $player->getHotbar()->getHeldItem();
|
||||
|
||||
if($item->isNull()){
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_enchant_noItem());
|
||||
@ -79,7 +79,7 @@ class EnchantCommand extends VanillaCommand{
|
||||
|
||||
//this is necessary to deal with enchanted books, which are a different item type than regular books
|
||||
$enchantedItem = EnchantingHelper::enchantItem($item, [new EnchantmentInstance($enchantment, $level)]);
|
||||
$player->getInventory()->setItemInHand($enchantedItem);
|
||||
$player->getHotbar()->setHeldItem($enchantedItem);
|
||||
|
||||
self::broadcastCommandMessage($sender, KnownTranslationFactory::commands_enchant_success($player->getName()));
|
||||
return true;
|
||||
|
@ -243,7 +243,7 @@ class ExperienceManager{
|
||||
//TODO: replace this with a more generic equipment getting/setting interface
|
||||
$equipment = [];
|
||||
|
||||
if(($item = $this->entity->getInventory()->getItemInHand()) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){
|
||||
if(($item = $this->entity->getHotbar()->getHeldItem()) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){
|
||||
$equipment[$mainHandIndex] = $item;
|
||||
}
|
||||
if(($item = $this->entity->getOffHandInventory()->getItem(0)) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){
|
||||
@ -263,7 +263,7 @@ class ExperienceManager{
|
||||
$xpValue -= (int) ceil($repairAmount / 2);
|
||||
|
||||
if($k === $mainHandIndex){
|
||||
$this->entity->getInventory()->setItemInHand($repairItem);
|
||||
$this->entity->getHotbar()->setHeldItem($repairItem);
|
||||
}elseif($k === $offHandIndex){
|
||||
$this->entity->getOffHandInventory()->setItem(0, $repairItem);
|
||||
}else{
|
||||
|
@ -32,6 +32,7 @@ use pocketmine\entity\projectile\ProjectileSource;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\player\PlayerExhaustEvent;
|
||||
use pocketmine\inventory\CallbackInventoryListener;
|
||||
use pocketmine\inventory\Hotbar;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\inventory\InventoryHolder;
|
||||
use pocketmine\inventory\PlayerEnderInventory;
|
||||
@ -100,6 +101,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
|
||||
public function getNetworkTypeId() : string{ return EntityIds::PLAYER; }
|
||||
|
||||
protected Hotbar $hotbar;
|
||||
protected PlayerInventory $inventory;
|
||||
protected PlayerOffHandInventory $offHandInventory;
|
||||
protected PlayerEnderInventory $enderInventory;
|
||||
@ -228,6 +230,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
return min(100, 7 * $this->xpManager->getXpLevel());
|
||||
}
|
||||
|
||||
public function getHotbar() : Hotbar{
|
||||
return $this->hotbar;
|
||||
}
|
||||
|
||||
public function getInventory() : PlayerInventory{
|
||||
return $this->inventory;
|
||||
}
|
||||
@ -266,18 +272,20 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
$this->xpManager = new ExperienceManager($this);
|
||||
|
||||
$this->inventory = new PlayerInventory($this);
|
||||
$this->hotbar = new Hotbar($this->inventory);
|
||||
|
||||
$syncHeldItem = fn() => NetworkBroadcastUtils::broadcastEntityEvent(
|
||||
$this->getViewers(),
|
||||
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobMainHandItemChange($recipients, $this)
|
||||
);
|
||||
$this->inventory->getListeners()->add(new CallbackInventoryListener(
|
||||
function(Inventory $unused, int $slot, Item $unused2) use ($syncHeldItem) : void{
|
||||
if($slot === $this->inventory->getHeldItemIndex()){
|
||||
if($slot === $this->hotbar->getSelectedIndex()){
|
||||
$syncHeldItem();
|
||||
}
|
||||
},
|
||||
function(Inventory $unused, array $oldItems) use ($syncHeldItem) : void{
|
||||
if(array_key_exists($this->inventory->getHeldItemIndex(), $oldItems)){
|
||||
if(array_key_exists($this->hotbar->getSelectedIndex(), $oldItems)){
|
||||
$syncHeldItem();
|
||||
}
|
||||
}
|
||||
@ -326,8 +334,8 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
self::populateInventoryFromListTag($this->enderInventory, $enderChestInventoryItems);
|
||||
}
|
||||
|
||||
$this->inventory->setHeldItemIndex($nbt->getInt(self::TAG_SELECTED_INVENTORY_SLOT, 0));
|
||||
$this->inventory->getHeldItemIndexChangeListeners()->add(fn() => NetworkBroadcastUtils::broadcastEntityEvent(
|
||||
$this->hotbar->setSelectedIndex($nbt->getInt(self::TAG_SELECTED_INVENTORY_SLOT, 0));
|
||||
$this->hotbar->getSelectedIndexChangeListeners()->add(fn() => NetworkBroadcastUtils::broadcastEntityEvent(
|
||||
$this->getViewers(),
|
||||
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobMainHandItemChange($recipients, $this)
|
||||
));
|
||||
@ -367,7 +375,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
|
||||
$type = $source->getCause();
|
||||
if($type !== EntityDamageEvent::CAUSE_SUICIDE && $type !== EntityDamageEvent::CAUSE_VOID
|
||||
&& ($this->inventory->getItemInHand() instanceof Totem || $this->offHandInventory->getItem(0) instanceof Totem)){
|
||||
&& ($this->hotbar->getHeldItem() instanceof Totem || $this->offHandInventory->getItem(0) instanceof Totem)){
|
||||
|
||||
$compensation = $this->getHealth() - $source->getFinalDamage() - 1;
|
||||
if($compensation <= -1){
|
||||
@ -389,10 +397,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
$this->broadcastAnimation(new TotemUseAnimation($this));
|
||||
$this->broadcastSound(new TotemUseSound());
|
||||
|
||||
$hand = $this->inventory->getItemInHand();
|
||||
$hand = $this->hotbar->getHeldItem();
|
||||
if($hand instanceof Totem){
|
||||
$hand->pop(); //Plugins could alter max stack size
|
||||
$this->inventory->setItemInHand($hand);
|
||||
$this->hotbar->setHeldItem($hand);
|
||||
}elseif(($offHand = $this->offHandInventory->getItem(0)) instanceof Totem){
|
||||
$offHand->pop();
|
||||
$this->offHandInventory->setItem(0, $offHand);
|
||||
@ -425,8 +433,8 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
$nbt->setTag(self::TAG_INVENTORY, $inventoryTag);
|
||||
|
||||
//Normal inventory
|
||||
$slotCount = $this->inventory->getSize() + $this->inventory->getHotbarSize();
|
||||
for($slot = $this->inventory->getHotbarSize(); $slot < $slotCount; ++$slot){
|
||||
$slotCount = $this->inventory->getSize() + $this->hotbar->getSize();
|
||||
for($slot = $this->hotbar->getSize(); $slot < $slotCount; ++$slot){
|
||||
$item = $this->inventory->getItem($slot - 9);
|
||||
if(!$item->isNull()){
|
||||
$inventoryTag->push($item->nbtSerialize($slot));
|
||||
@ -441,7 +449,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
}
|
||||
}
|
||||
|
||||
$nbt->setInt(self::TAG_SELECTED_INVENTORY_SLOT, $this->inventory->getHeldItemIndex());
|
||||
$nbt->setInt(self::TAG_SELECTED_INVENTORY_SLOT, $this->hotbar->getSelectedIndex());
|
||||
|
||||
$offHandItem = $this->offHandInventory->getItem(0);
|
||||
if(!$offHandItem->isNull()){
|
||||
@ -495,7 +503,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
$this->location->pitch,
|
||||
$this->location->yaw,
|
||||
$this->location->yaw, //TODO: head yaw
|
||||
ItemStackWrapper::legacy($typeConverter->coreItemStackToNet($this->getInventory()->getItemInHand())),
|
||||
ItemStackWrapper::legacy($typeConverter->coreItemStackToNet($this->hotbar->getHeldItem())),
|
||||
GameMode::SURVIVAL,
|
||||
$this->getAllNetworkData(),
|
||||
new PropertySyncData([], []),
|
||||
@ -529,8 +537,8 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
}
|
||||
|
||||
protected function onDispose() : void{
|
||||
$this->hotbar->getSelectedIndexChangeListeners()->clear();
|
||||
$this->inventory->removeAllViewers();
|
||||
$this->inventory->getHeldItemIndexChangeListeners()->clear();
|
||||
$this->offHandInventory->removeAllViewers();
|
||||
$this->enderInventory->removeAllViewers();
|
||||
parent::onDispose();
|
||||
|
122
src/inventory/Hotbar.php
Normal file
122
src/inventory/Hotbar.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?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\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\utils\ObjectSet;
|
||||
|
||||
final class Hotbar{
|
||||
protected int $selectedIndex = 0;
|
||||
|
||||
/**
|
||||
* @var \Closure[]|ObjectSet
|
||||
* @phpstan-var ObjectSet<\Closure(int $oldIndex) : void>
|
||||
*/
|
||||
protected ObjectSet $selectedIndexChangeListeners;
|
||||
|
||||
public function __construct(
|
||||
private Inventory $inventory,
|
||||
private int $size = 9
|
||||
){
|
||||
if($this->inventory->getSize() < $this->size){
|
||||
throw new \InvalidArgumentException("Inventory size must be at least $this->size");
|
||||
}
|
||||
$this->selectedIndexChangeListeners = new ObjectSet();
|
||||
}
|
||||
|
||||
public function isHotbarSlot(int $slot) : bool{
|
||||
return $slot >= 0 && $slot < $this->getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function throwIfNotHotbarSlot(int $slot) : void{
|
||||
if(!$this->isHotbarSlot($slot)){
|
||||
throw new \InvalidArgumentException("$slot is not a valid hotbar slot index (expected 0 - " . ($this->getSize() - 1) . ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item in the specified hotbar slot.
|
||||
*
|
||||
* @throws \InvalidArgumentException if the hotbar slot index is out of range
|
||||
*/
|
||||
public function getHotbarSlotItem(int $hotbarSlot) : Item{
|
||||
$this->throwIfNotHotbarSlot($hotbarSlot);
|
||||
return $this->inventory->getItem($hotbarSlot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hotbar slot number the holder is currently holding.
|
||||
*/
|
||||
public function getSelectedIndex() : int{
|
||||
return $this->selectedIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets which hotbar slot the player is currently loading.
|
||||
*
|
||||
* @param int $hotbarSlot 0-8 index of the hotbar slot to hold
|
||||
*
|
||||
* @throws \InvalidArgumentException if the hotbar slot is out of range
|
||||
*/
|
||||
public function setSelectedIndex(int $hotbarSlot) : void{
|
||||
$this->throwIfNotHotbarSlot($hotbarSlot);
|
||||
|
||||
$oldIndex = $this->selectedIndex;
|
||||
$this->selectedIndex = $hotbarSlot;
|
||||
|
||||
foreach($this->selectedIndexChangeListeners as $callback){
|
||||
$callback($oldIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Closure[]|ObjectSet
|
||||
* @phpstan-return ObjectSet<\Closure(int $oldIndex) : void>
|
||||
*/
|
||||
public function getSelectedIndexChangeListeners() : ObjectSet{ return $this->selectedIndexChangeListeners; }
|
||||
|
||||
/**
|
||||
* Returns the currently-held item.
|
||||
*/
|
||||
public function getHeldItem() : Item{
|
||||
return $this->getHotbarSlotItem($this->selectedIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item in the currently-held slot to the specified item.
|
||||
*/
|
||||
public function setHeldItem(Item $item) : void{
|
||||
$this->inventory->setItem($this->getSelectedIndex(), $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of slots in the hotbar.
|
||||
*/
|
||||
public function getSize() : int{
|
||||
return $this->size;
|
||||
}
|
||||
}
|
@ -24,102 +24,16 @@ declare(strict_types=1);
|
||||
namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\entity\Human;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\ObjectSet;
|
||||
|
||||
class PlayerInventory extends SimpleInventory{
|
||||
|
||||
protected Human $holder;
|
||||
protected int $itemInHandIndex = 0;
|
||||
|
||||
/**
|
||||
* @var \Closure[]|ObjectSet
|
||||
* @phpstan-var ObjectSet<\Closure(int $oldIndex) : void>
|
||||
*/
|
||||
protected ObjectSet $heldItemIndexChangeListeners;
|
||||
|
||||
public function __construct(Human $player){
|
||||
$this->holder = $player;
|
||||
$this->heldItemIndexChangeListeners = new ObjectSet();
|
||||
parent::__construct(36);
|
||||
}
|
||||
|
||||
public function isHotbarSlot(int $slot) : bool{
|
||||
return $slot >= 0 && $slot < $this->getHotbarSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function throwIfNotHotbarSlot(int $slot) : void{
|
||||
if(!$this->isHotbarSlot($slot)){
|
||||
throw new \InvalidArgumentException("$slot is not a valid hotbar slot index (expected 0 - " . ($this->getHotbarSize() - 1) . ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item in the specified hotbar slot.
|
||||
*
|
||||
* @throws \InvalidArgumentException if the hotbar slot index is out of range
|
||||
*/
|
||||
public function getHotbarSlotItem(int $hotbarSlot) : Item{
|
||||
$this->throwIfNotHotbarSlot($hotbarSlot);
|
||||
return $this->getItem($hotbarSlot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hotbar slot number the holder is currently holding.
|
||||
*/
|
||||
public function getHeldItemIndex() : int{
|
||||
return $this->itemInHandIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets which hotbar slot the player is currently loading.
|
||||
*
|
||||
* @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) : void{
|
||||
$this->throwIfNotHotbarSlot($hotbarSlot);
|
||||
|
||||
$oldIndex = $this->itemInHandIndex;
|
||||
$this->itemInHandIndex = $hotbarSlot;
|
||||
|
||||
foreach($this->heldItemIndexChangeListeners as $callback){
|
||||
$callback($oldIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Closure[]|ObjectSet
|
||||
* @phpstan-return ObjectSet<\Closure(int $oldIndex) : void>
|
||||
*/
|
||||
public function getHeldItemIndexChangeListeners() : ObjectSet{ return $this->heldItemIndexChangeListeners; }
|
||||
|
||||
/**
|
||||
* Returns the currently-held item.
|
||||
*/
|
||||
public function getItemInHand() : Item{
|
||||
return $this->getHotbarSlotItem($this->itemInHandIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item in the currently-held slot to the specified item.
|
||||
*/
|
||||
public function setItemInHand(Item $item) : void{
|
||||
$this->setItem($this->getHeldItemIndex(), $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of slots in the hotbar.
|
||||
*/
|
||||
public function getHotbarSize() : int{
|
||||
return 9;
|
||||
}
|
||||
|
||||
public function getHolder() : Human{
|
||||
return $this->holder;
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ class Armor extends Durable{
|
||||
$thisCopy = clone $this;
|
||||
$new = $thisCopy->pop();
|
||||
$player->getArmorInventory()->setItem($this->getArmorSlot(), $new);
|
||||
$player->getInventory()->setItemInHand($existing);
|
||||
$player->getHotbar()->setHeldItem($existing);
|
||||
$sound = $new->getMaterial()->getEquipSound();
|
||||
if($sound !== null){
|
||||
$player->broadcastSound($sound);
|
||||
|
@ -132,7 +132,7 @@ class InventoryManager{
|
||||
$this->addComplex(UIInventorySlotOffset::CURSOR, $this->player->getCursorInventory());
|
||||
$this->addComplex(UIInventorySlotOffset::CRAFTING2X2_INPUT, $this->player->getCraftingGrid());
|
||||
|
||||
$this->player->getInventory()->getHeldItemIndexChangeListeners()->add($this->syncSelectedHotbarSlot(...));
|
||||
$this->player->getHotbar()->getSelectedIndexChangeListeners()->add($this->syncSelectedHotbarSlot(...));
|
||||
}
|
||||
|
||||
private function associateIdWithInventory(int $id, Inventory $inventory) : void{
|
||||
@ -668,7 +668,7 @@ class InventoryManager{
|
||||
|
||||
public function syncSelectedHotbarSlot() : void{
|
||||
$playerInventory = $this->player->getInventory();
|
||||
$selected = $playerInventory->getHeldItemIndex();
|
||||
$selected = $this->player->getHotbar()->getSelectedIndex();
|
||||
if($selected !== $this->clientSelectedHotbarSlot){
|
||||
$inventoryEntry = $this->inventories[spl_object_id($playerInventory)] ?? null;
|
||||
if($inventoryEntry === null){
|
||||
@ -681,7 +681,7 @@ class InventoryManager{
|
||||
|
||||
$this->session->sendDataPacket(MobEquipmentPacket::create(
|
||||
$this->player->getId(),
|
||||
new ItemStackWrapper($itemStackInfo->getStackId(), $this->session->getTypeConverter()->coreItemStackToNet($playerInventory->getItemInHand())),
|
||||
new ItemStackWrapper($itemStackInfo->getStackId(), $this->session->getTypeConverter()->coreItemStackToNet($playerInventory->getItem($selected))),
|
||||
$selected,
|
||||
$selected,
|
||||
ContainerIds::INVENTORY
|
||||
|
@ -103,12 +103,12 @@ final class StandardEntityEventBroadcaster implements EntityEventBroadcaster{
|
||||
|
||||
public function onMobMainHandItemChange(array $recipients, Human $mob) : void{
|
||||
//TODO: we could send zero for slot here because remote players don't need to know which slot was selected
|
||||
$inv = $mob->getInventory();
|
||||
$inv = $mob->getHotbar();
|
||||
$this->sendDataPacket($recipients, MobEquipmentPacket::create(
|
||||
$mob->getId(),
|
||||
ItemStackWrapper::legacy($this->typeConverter->coreItemStackToNet($inv->getItemInHand())),
|
||||
$inv->getHeldItemIndex(),
|
||||
$inv->getHeldItemIndex(),
|
||||
ItemStackWrapper::legacy($this->typeConverter->coreItemStackToNet($inv->getHeldItem())),
|
||||
$inv->getSelectedIndex(),
|
||||
$inv->getSelectedIndex(),
|
||||
ContainerIds::INVENTORY
|
||||
));
|
||||
}
|
||||
|
@ -304,11 +304,11 @@ class InGamePacketHandler extends PacketHandler{
|
||||
|
||||
switch($packet->eventId){
|
||||
case ActorEvent::EATING_ITEM: //TODO: ignore this and handle it server-side
|
||||
$item = $this->player->getInventory()->getItemInHand();
|
||||
$item = $this->player->getHotbar()->getHeldItem();
|
||||
if($item->isNull()){
|
||||
return false;
|
||||
}
|
||||
$this->player->broadcastAnimation(new ConsumingItemAnimation($this->player, $this->player->getInventory()->getItemInHand()));
|
||||
$this->player->broadcastAnimation(new ConsumingItemAnimation($this->player, $item));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -347,7 +347,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
}
|
||||
|
||||
private function callDummyItemHeldEvent() : void{
|
||||
$slot = $this->inventory->getHeldItemIndex();
|
||||
$slot = $this->hotbar->getSelectedIndex();
|
||||
|
||||
$event = new PlayerItemHeldEvent($this, $this->inventory->getItem($slot), $slot);
|
||||
$event->call();
|
||||
@ -362,7 +362,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
|
||||
$this->inventory->getListeners()->add(new CallbackInventoryListener(
|
||||
function(Inventory $unused, int $slot) : void{
|
||||
if($slot === $this->inventory->getHeldItemIndex()){
|
||||
if($slot === $this->hotbar->getSelectedIndex()){
|
||||
$this->setUsingItem(false);
|
||||
|
||||
$this->callDummyItemHeldEvent();
|
||||
@ -1540,10 +1540,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
}
|
||||
|
||||
public function selectHotbarSlot(int $hotbarSlot) : bool{
|
||||
if(!$this->inventory->isHotbarSlot($hotbarSlot)){ //TODO: exception here?
|
||||
if(!$this->hotbar->isHotbarSlot($hotbarSlot)){ //TODO: exception here?
|
||||
return false;
|
||||
}
|
||||
if($hotbarSlot === $this->inventory->getHeldItemIndex()){
|
||||
if($hotbarSlot === $this->hotbar->getSelectedIndex()){
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1553,7 +1553,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->inventory->setHeldItemIndex($hotbarSlot);
|
||||
$this->hotbar->setSelectedIndex($hotbarSlot);
|
||||
$this->setUsingItem(false);
|
||||
|
||||
return true;
|
||||
@ -1565,7 +1565,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
private function returnItemsFromAction(Item $oldHeldItem, Item $newHeldItem, array $extraReturnedItems) : void{
|
||||
$heldItemChanged = false;
|
||||
|
||||
if(!$newHeldItem->equalsExact($oldHeldItem) && $oldHeldItem->equalsExact($this->inventory->getItemInHand())){
|
||||
if(!$newHeldItem->equalsExact($oldHeldItem) && $oldHeldItem->equalsExact($this->hotbar->getHeldItem())){
|
||||
//determine if the item was changed in some meaningful way, or just damaged/changed count
|
||||
//if it was really changed we always need to set it, whether we have finite resources or not
|
||||
$newReplica = clone $oldHeldItem;
|
||||
@ -1579,7 +1579,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
if($newHeldItem instanceof Durable && $newHeldItem->isBroken()){
|
||||
$this->broadcastSound(new ItemBreakSound());
|
||||
}
|
||||
$this->inventory->setItemInHand($newHeldItem);
|
||||
$this->hotbar->setHeldItem($newHeldItem);
|
||||
$heldItemChanged = true;
|
||||
}
|
||||
}
|
||||
@ -1589,7 +1589,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
}
|
||||
|
||||
if($heldItemChanged && count($extraReturnedItems) > 0 && $newHeldItem->isNull()){
|
||||
$this->inventory->setItemInHand(array_shift($extraReturnedItems));
|
||||
$this->hotbar->setHeldItem(array_shift($extraReturnedItems));
|
||||
}
|
||||
foreach($this->inventory->addItem(...$extraReturnedItems) as $drop){
|
||||
//TODO: we can't generate a transaction for this since the items aren't coming from an inventory :(
|
||||
@ -1611,7 +1611,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
*/
|
||||
public function useHeldItem() : bool{
|
||||
$directionVector = $this->getDirectionVector();
|
||||
$item = $this->inventory->getItemInHand();
|
||||
$item = $this->hotbar->getHeldItem();
|
||||
$oldItem = clone $item;
|
||||
|
||||
$ev = new PlayerItemUseEvent($this, $item, $directionVector);
|
||||
@ -1645,7 +1645,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
* @return bool if the consumption succeeded.
|
||||
*/
|
||||
public function consumeHeldItem() : bool{
|
||||
$slot = $this->inventory->getItemInHand();
|
||||
$slot = $this->hotbar->getHeldItem();
|
||||
if($slot instanceof ConsumableItem){
|
||||
$oldItem = clone $slot;
|
||||
|
||||
@ -1678,7 +1678,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
*/
|
||||
public function releaseHeldItem() : bool{
|
||||
try{
|
||||
$item = $this->inventory->getItemInHand();
|
||||
$item = $this->hotbar->getHeldItem();
|
||||
if(!$this->isUsingItem() || $this->hasItemCooldown($item)){
|
||||
return false;
|
||||
}
|
||||
@ -1748,21 +1748,21 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
|
||||
private function equipOrAddPickedItem(int $existingSlot, Item $item) : void{
|
||||
if($existingSlot !== -1){
|
||||
if($existingSlot < $this->inventory->getHotbarSize()){
|
||||
$this->inventory->setHeldItemIndex($existingSlot);
|
||||
if($existingSlot < $this->hotbar->getSize()){
|
||||
$this->hotbar->setSelectedIndex($existingSlot);
|
||||
}else{
|
||||
$this->inventory->swap($this->inventory->getHeldItemIndex(), $existingSlot);
|
||||
$this->inventory->swap($this->hotbar->getSelectedIndex(), $existingSlot);
|
||||
}
|
||||
}else{
|
||||
$firstEmpty = $this->inventory->firstEmpty();
|
||||
if($firstEmpty === -1){ //full inventory
|
||||
$this->inventory->setItemInHand($item);
|
||||
}elseif($firstEmpty < $this->inventory->getHotbarSize()){
|
||||
$this->hotbar->setHeldItem($item);
|
||||
}elseif($firstEmpty < $this->hotbar->getSize()){
|
||||
$this->inventory->setItem($firstEmpty, $item);
|
||||
$this->inventory->setHeldItemIndex($firstEmpty);
|
||||
$this->hotbar->setSelectedIndex($firstEmpty);
|
||||
}else{
|
||||
$this->inventory->swap($this->inventory->getHeldItemIndex(), $firstEmpty);
|
||||
$this->inventory->setItemInHand($item);
|
||||
$this->inventory->swap($this->hotbar->getSelectedIndex(), $firstEmpty);
|
||||
$this->hotbar->setHeldItem($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1779,7 +1779,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
|
||||
$target = $this->getWorld()->getBlock($pos);
|
||||
|
||||
$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, null, $face, PlayerInteractEvent::LEFT_CLICK_BLOCK);
|
||||
$ev = new PlayerInteractEvent($this, $this->hotbar->getHeldItem(), $target, null, $face, PlayerInteractEvent::LEFT_CLICK_BLOCK);
|
||||
if($this->isSpectator()){
|
||||
$ev->cancel();
|
||||
}
|
||||
@ -1788,7 +1788,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
return false;
|
||||
}
|
||||
$this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers());
|
||||
if($target->onAttack($this->inventory->getItemInHand(), $face, $this)){
|
||||
if($target->onAttack($this->hotbar->getHeldItem(), $face, $this)){
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1829,7 +1829,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? self::MAX_REACH_DISTANCE_CREATIVE : self::MAX_REACH_DISTANCE_SURVIVAL)){
|
||||
$this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers());
|
||||
$this->stopBreakBlock($pos);
|
||||
$item = $this->inventory->getItemInHand();
|
||||
$item = $this->hotbar->getHeldItem();
|
||||
$oldItem = clone $item;
|
||||
$returnedItems = [];
|
||||
if($this->getWorld()->useBreakOn($pos, $item, $this, true, $returnedItems)){
|
||||
@ -1854,7 +1854,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
|
||||
if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? self::MAX_REACH_DISTANCE_CREATIVE : self::MAX_REACH_DISTANCE_SURVIVAL)){
|
||||
$this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers());
|
||||
$item = $this->inventory->getItemInHand(); //this is a copy of the real item
|
||||
$item = $this->hotbar->getHeldItem(); //this is a copy of the real item
|
||||
$oldItem = clone $item;
|
||||
$returnedItems = [];
|
||||
if($this->getWorld()->useItemOn($pos, $item, $face, $clickOffset, $this, true, $returnedItems)){
|
||||
@ -1883,7 +1883,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
return false;
|
||||
}
|
||||
|
||||
$heldItem = $this->inventory->getItemInHand();
|
||||
$heldItem = $this->hotbar->getHeldItem();
|
||||
$oldItem = clone $heldItem;
|
||||
|
||||
$ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints());
|
||||
@ -1969,15 +1969,15 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
|
||||
$ev->call();
|
||||
|
||||
$item = $this->inventory->getItemInHand();
|
||||
$item = $this->hotbar->getHeldItem();
|
||||
$oldItem = clone $item;
|
||||
if(!$ev->isCancelled()){
|
||||
if($item->onInteractEntity($this, $entity, $clickPos)){
|
||||
if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->inventory->getItemInHand())){
|
||||
if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->hotbar->getHeldItem())){
|
||||
if($item instanceof Durable && $item->isBroken()){
|
||||
$this->broadcastSound(new ItemBreakSound());
|
||||
}
|
||||
$this->inventory->setItemInHand($item);
|
||||
$this->hotbar->setHeldItem($item);
|
||||
}
|
||||
}
|
||||
return $entity->onInteract($this, $clickPos);
|
||||
@ -2405,8 +2405,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$this->getWorld()->dropItem($this->location, $item);
|
||||
}
|
||||
|
||||
$this->hotbar->setSelectedIndex(0);
|
||||
$clearInventory = fn(Inventory $inventory) => $inventory->setContents(array_filter($inventory->getContents(), fn(Item $item) => $item->keepOnDeath()));
|
||||
$this->inventory->setHeldItemIndex(0);
|
||||
$clearInventory($this->inventory);
|
||||
$clearInventory($this->armorInventory);
|
||||
$clearInventory($this->offHandInventory);
|
||||
|
@ -66,7 +66,7 @@ final class SurvivalBlockBreakHandler{
|
||||
return 0.0;
|
||||
}
|
||||
//TODO: improve this to take stuff like swimming, ladders, enchanted tools into account, fix wrong tool break time calculations for bad tools (pmmp/PocketMine-MP#211)
|
||||
$breakTimePerTick = $this->block->getBreakInfo()->getBreakTime($this->player->getInventory()->getItemInHand()) * 20;
|
||||
$breakTimePerTick = $this->block->getBreakInfo()->getBreakTime($this->player->getHotbar()->getHeldItem()) * 20;
|
||||
|
||||
if($breakTimePerTick > 0){
|
||||
return 1 / $breakTimePerTick;
|
||||
|
Loading…
x
Reference in New Issue
Block a user