Skip to content

Commit 657c07b

Browse files
committed
Remove dependencies on hotbar and offhand inventory to get equipment
It's always grated at me that the call chain to get the held item is so long
1 parent 3c6b099 commit 657c07b

File tree

11 files changed

+58
-71
lines changed

11 files changed

+58
-71
lines changed

src/command/defaults/EnchantCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function execute(CommandSender $sender, string $commandLabel, array $args
5656
return true;
5757
}
5858

59-
$item = $player->getHotbar()->getHeldItem();
59+
$item = $player->getMainHandItem();
6060

6161
if($item->isNull()){
6262
$sender->sendMessage(KnownTranslationFactory::commands_enchant_noItem());
@@ -79,7 +79,7 @@ public function execute(CommandSender $sender, string $commandLabel, array $args
7979

8080
//this is necessary to deal with enchanted books, which are a different item type than regular books
8181
$enchantedItem = EnchantingHelper::enchantItem($item, [new EnchantmentInstance($enchantment, $level)]);
82-
$player->getHotbar()->setHeldItem($enchantedItem);
82+
$player->setMainHandItem($enchantedItem);
8383

8484
self::broadcastCommandMessage($sender, KnownTranslationFactory::commands_enchant_success($player->getName()));
8585
return true;

src/entity/ExperienceManager.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,10 @@ public function onPickupXp(int $xpValue) : void{
243243
//TODO: replace this with a more generic equipment getting/setting interface
244244
$equipment = [];
245245

246-
if(($item = $this->entity->getHotbar()->getHeldItem()) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){
246+
if(($item = $this->entity->getMainHandItem()) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){
247247
$equipment[$mainHandIndex] = $item;
248248
}
249-
if(($item = $this->entity->getOffHandInventory()->getItem(0)) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){
249+
if(($item = $this->entity->getOffHandItem()) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){
250250
$equipment[$offHandIndex] = $item;
251251
}
252252
foreach($this->entity->getArmorInventory()->getContents() as $k => $armorItem){
@@ -263,9 +263,9 @@ public function onPickupXp(int $xpValue) : void{
263263
$xpValue -= (int) ceil($repairAmount / 2);
264264

265265
if($k === $mainHandIndex){
266-
$this->entity->getHotbar()->setHeldItem($repairItem);
266+
$this->entity->setMainHandItem($repairItem);
267267
}elseif($k === $offHandIndex){
268-
$this->entity->getOffHandInventory()->setItem(0, $repairItem);
268+
$this->entity->setOffHandItem($repairItem);
269269
}else{
270270
$this->entity->getArmorInventory()->setItem($k, $repairItem);
271271
}

src/entity/Human.php

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,22 @@ public function getInventory() : Inventory{
245245
return $this->inventory;
246246
}
247247

248+
public function getMainHandItem() : Item{
249+
return $this->inventory->getItem($this->hotbar->getSelectedIndex());
250+
}
251+
252+
public function setMainHandItem(Item $item) : void{
253+
$this->inventory->setItem($this->hotbar->getSelectedIndex(), $item);
254+
}
255+
256+
public function getOffHandItem() : Item{
257+
return $this->offHandInventory->getItem(0);
258+
}
259+
260+
public function setOffHandItem(Item $item) : void{
261+
$this->offHandInventory->setItem(0, $item);
262+
}
263+
248264
public function getOffHandInventory() : Inventory{ return $this->offHandInventory; }
249265

250266
public function getEnderInventory() : Inventory{
@@ -279,7 +295,7 @@ protected function initEntity(CompoundTag $nbt) : void{
279295
$this->xpManager = new ExperienceManager($this);
280296

281297
$this->inventory = new SimpleInventory(36);
282-
$this->hotbar = new Hotbar($this->inventory);
298+
$this->hotbar = new Hotbar();
283299

284300
$syncHeldItem = fn() => NetworkBroadcastUtils::broadcastEntityEvent(
285301
$this->getViewers(),
@@ -323,7 +339,7 @@ function(Inventory $unused, array $oldItems) use ($syncHeldItem) : void{
323339
}
324340
$offHand = $nbt->getCompoundTag(self::TAG_OFF_HAND_ITEM);
325341
if($offHand !== null){
326-
$this->offHandInventory->setItem(0, Item::nbtDeserialize($offHand));
342+
$this->setOffHandItem(Item::nbtDeserialize($offHand));
327343
}
328344
$this->offHandInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(fn() => NetworkBroadcastUtils::broadcastEntityEvent(
329345
$this->getViewers(),
@@ -383,7 +399,7 @@ public function applyDamageModifiers(EntityDamageEvent $source) : void{
383399

384400
$type = $source->getCause();
385401
if($type !== EntityDamageEvent::CAUSE_SUICIDE && $type !== EntityDamageEvent::CAUSE_VOID
386-
&& ($this->hotbar->getHeldItem() instanceof Totem || $this->offHandInventory->getItem(0) instanceof Totem)){
402+
&& ($this->getMainHandItem() instanceof Totem || $this->getOffHandItem() instanceof Totem)){
387403

388404
$compensation = $this->getHealth() - $source->getFinalDamage() - 1;
389405
if($compensation <= -1){
@@ -405,13 +421,13 @@ protected function applyPostDamageEffects(EntityDamageEvent $source) : void{
405421
$this->broadcastAnimation(new TotemUseAnimation($this));
406422
$this->broadcastSound(new TotemUseSound());
407423

408-
$hand = $this->hotbar->getHeldItem();
424+
$hand = $this->getMainHandItem();
409425
if($hand instanceof Totem){
410426
$hand->pop(); //Plugins could alter max stack size
411-
$this->hotbar->setHeldItem($hand);
412-
}elseif(($offHand = $this->offHandInventory->getItem(0)) instanceof Totem){
427+
$this->setMainHandItem($hand);
428+
}elseif(($offHand = $this->getOffHandItem()) instanceof Totem){
413429
$offHand->pop();
414-
$this->offHandInventory->setItem(0, $offHand);
430+
$this->setOffHandItem($offHand);
415431
}
416432
}
417433
}
@@ -459,7 +475,7 @@ public function saveNBT() : CompoundTag{
459475

460476
$nbt->setInt(self::TAG_SELECTED_INVENTORY_SLOT, $this->hotbar->getSelectedIndex());
461477

462-
$offHandItem = $this->offHandInventory->getItem(0);
478+
$offHandItem = $this->getOffHandItem();
463479
if(!$offHandItem->isNull()){
464480
$nbt->setTag(self::TAG_OFF_HAND_ITEM, $offHandItem->nbtSerialize());
465481
}
@@ -511,7 +527,7 @@ protected function sendSpawnPacket(Player $player) : void{
511527
$this->location->pitch,
512528
$this->location->yaw,
513529
$this->location->yaw, //TODO: head yaw
514-
ItemStackWrapper::legacy($typeConverter->coreItemStackToNet($this->hotbar->getHeldItem())),
530+
ItemStackWrapper::legacy($typeConverter->coreItemStackToNet($this->getMainHandItem())),
515531
GameMode::SURVIVAL,
516532
$this->getAllNetworkData(),
517533
new PropertySyncData([], []),

src/entity/object/ItemEntity.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ public function onCollideWithPlayer(Player $player) : void{
322322

323323
$item = $this->getItem();
324324
$playerInventory = match(true){
325-
$player->getOffHandInventory()->getItem(0)->canStackWith($item) && $player->getOffHandInventory()->getAddableItemQuantity($item) > 0 => $player->getOffHandInventory(),
325+
$player->getOffHandItem()->canStackWith($item) && $player->getOffHandInventory()->getAddableItemQuantity($item) > 0 => $player->getOffHandInventory(),
326326
$player->getInventory()->getAddableItemQuantity($item) > 0 => $player->getInventory(),
327327
default => null
328328
};

src/entity/projectile/Arrow.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public function onCollideWithPlayer(Player $player) : void{
172172
$item = VanillaItems::ARROW();
173173
$playerInventory = match(true){
174174
!$player->hasFiniteResources() => null, //arrows are not picked up in creative
175-
$player->getOffHandInventory()->getItem(0)->canStackWith($item) && $player->getOffHandInventory()->canAddItem($item) => $player->getOffHandInventory(),
175+
$player->getOffHandItem()->canStackWith($item) && $player->getOffHandInventory()->canAddItem($item) => $player->getOffHandInventory(),
176176
$player->getInventory()->canAddItem($item) => $player->getInventory(),
177177
default => null
178178
};

src/inventory/Hotbar.php

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,8 @@ final class Hotbar{
3636
protected ObjectSet $selectedIndexChangeListeners;
3737

3838
public function __construct(
39-
private Inventory $inventory,
4039
private int $size = 9
4140
){
42-
if($this->inventory->getSize() < $this->size){
43-
throw new \InvalidArgumentException("Inventory size must be at least $this->size");
44-
}
4541
$this->selectedIndexChangeListeners = new ObjectSet();
4642
}
4743

@@ -58,16 +54,6 @@ private function throwIfNotHotbarSlot(int $slot) : void{
5854
}
5955
}
6056

61-
/**
62-
* Returns the item in the specified hotbar slot.
63-
*
64-
* @throws \InvalidArgumentException if the hotbar slot index is out of range
65-
*/
66-
public function getHotbarSlotItem(int $hotbarSlot) : Item{
67-
$this->throwIfNotHotbarSlot($hotbarSlot);
68-
return $this->inventory->getItem($hotbarSlot);
69-
}
70-
7157
/**
7258
* Returns the hotbar slot number the holder is currently holding.
7359
*/
@@ -99,20 +85,6 @@ public function setSelectedIndex(int $hotbarSlot) : void{
9985
*/
10086
public function getSelectedIndexChangeListeners() : ObjectSet{ return $this->selectedIndexChangeListeners; }
10187

102-
/**
103-
* Returns the currently-held item.
104-
*/
105-
public function getHeldItem() : Item{
106-
return $this->getHotbarSlotItem($this->selectedIndex);
107-
}
108-
109-
/**
110-
* Sets the item in the currently-held slot to the specified item.
111-
*/
112-
public function setHeldItem(Item $item) : void{
113-
$this->inventory->setItem($this->getSelectedIndex(), $item);
114-
}
115-
11688
/**
11789
* Returns the number of slots in the hotbar.
11890
*/

src/item/Armor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public function onClickAir(Player $player, Vector3 $directionVector, array &$ret
145145
$thisCopy = clone $this;
146146
$new = $thisCopy->pop();
147147
$player->getArmorInventory()->setItem($this->getArmorSlot(), $new);
148-
$player->getHotbar()->setHeldItem($existing);
148+
$player->setMainHandItem($existing);
149149
$sound = $new->getMaterial()->getEquipSound();
150150
if($sound !== null){
151151
$player->broadcastSound($sound);

src/network/mcpe/StandardEntityEventBroadcaster.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,22 +102,21 @@ public function onEntityRemoved(array $recipients, Entity $entity) : void{
102102
}
103103

104104
public function onMobMainHandItemChange(array $recipients, Human $mob) : void{
105-
//TODO: we could send zero for slot here because remote players don't need to know which slot was selected
106-
$inv = $mob->getHotbar();
105+
$item = $mob->getMainHandItem();
107106
$this->sendDataPacket($recipients, MobEquipmentPacket::create(
108107
$mob->getId(),
109-
ItemStackWrapper::legacy($this->typeConverter->coreItemStackToNet($inv->getHeldItem())),
110-
$inv->getSelectedIndex(),
111-
$inv->getSelectedIndex(),
108+
ItemStackWrapper::legacy($this->typeConverter->coreItemStackToNet($item)),
109+
0,
110+
0,
112111
ContainerIds::INVENTORY
113112
));
114113
}
115114

116115
public function onMobOffHandItemChange(array $recipients, Human $mob) : void{
117-
$inv = $mob->getOffHandInventory();
116+
$item = $mob->getOffHandItem();
118117
$this->sendDataPacket($recipients, MobEquipmentPacket::create(
119118
$mob->getId(),
120-
ItemStackWrapper::legacy($this->typeConverter->coreItemStackToNet($inv->getItem(0))),
119+
ItemStackWrapper::legacy($this->typeConverter->coreItemStackToNet($item)),
121120
0,
122121
0,
123122
ContainerIds::OFFHAND

src/network/mcpe/handler/InGamePacketHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ public function handleActorEvent(ActorEventPacket $packet) : bool{
307307

308308
switch($packet->eventId){
309309
case ActorEvent::EATING_ITEM: //TODO: ignore this and handle it server-side
310-
$item = $this->player->getHotbar()->getHeldItem();
310+
$item = $this->player->getMainHandItem();
311311
if($item->isNull()){
312312
return false;
313313
}

src/player/Player.php

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,7 +1649,7 @@ public function selectHotbarSlot(int $hotbarSlot) : bool{
16491649
private function returnItemsFromAction(Item $oldHeldItem, Item $newHeldItem, array $extraReturnedItems) : void{
16501650
$heldItemChanged = false;
16511651

1652-
if(!$newHeldItem->equalsExact($oldHeldItem) && $oldHeldItem->equalsExact($this->hotbar->getHeldItem())){
1652+
if(!$newHeldItem->equalsExact($oldHeldItem) && $oldHeldItem->equalsExact($this->getMainHandItem())){
16531653
//determine if the item was changed in some meaningful way, or just damaged/changed count
16541654
//if it was really changed we always need to set it, whether we have finite resources or not
16551655
$newReplica = clone $oldHeldItem;
@@ -1666,7 +1666,7 @@ private function returnItemsFromAction(Item $oldHeldItem, Item $newHeldItem, arr
16661666
if($newHeldItem instanceof Durable && $newHeldItem->isBroken()){
16671667
$this->broadcastSound(new ItemBreakSound());
16681668
}
1669-
$this->hotbar->setHeldItem($newHeldItem);
1669+
$this->setMainHandItem($newHeldItem);
16701670
$heldItemChanged = true;
16711671
}
16721672
}
@@ -1676,7 +1676,7 @@ private function returnItemsFromAction(Item $oldHeldItem, Item $newHeldItem, arr
16761676
}
16771677

16781678
if($heldItemChanged && count($extraReturnedItems) > 0 && $newHeldItem->isNull()){
1679-
$this->hotbar->setHeldItem(array_shift($extraReturnedItems));
1679+
$this->setMainHandItem(array_shift($extraReturnedItems));
16801680
}
16811681
foreach($this->inventory->addItem(...$extraReturnedItems) as $drop){
16821682
//TODO: we can't generate a transaction for this since the items aren't coming from an inventory :(
@@ -1698,7 +1698,7 @@ private function returnItemsFromAction(Item $oldHeldItem, Item $newHeldItem, arr
16981698
*/
16991699
public function useHeldItem() : bool{
17001700
$directionVector = $this->getDirectionVector();
1701-
$item = $this->hotbar->getHeldItem();
1701+
$item = $this->getMainHandItem();
17021702
$oldItem = clone $item;
17031703

17041704
$ev = new PlayerItemUseEvent($this, $item, $directionVector);
@@ -1732,7 +1732,7 @@ public function useHeldItem() : bool{
17321732
* @return bool if the consumption succeeded.
17331733
*/
17341734
public function consumeHeldItem() : bool{
1735-
$slot = $this->hotbar->getHeldItem();
1735+
$slot = $this->getMainHandItem();
17361736
if($slot instanceof ConsumableItem){
17371737
$oldItem = clone $slot;
17381738

@@ -1765,7 +1765,7 @@ public function consumeHeldItem() : bool{
17651765
*/
17661766
public function releaseHeldItem() : bool{
17671767
try{
1768-
$item = $this->hotbar->getHeldItem();
1768+
$item = $this->getMainHandItem();
17691769
if(!$this->isUsingItem() || $this->hasItemCooldown($item)){
17701770
return false;
17711771
}
@@ -1843,13 +1843,13 @@ private function equipOrAddPickedItem(int $existingSlot, Item $item) : void{
18431843
}else{
18441844
$firstEmpty = $this->inventory->firstEmpty();
18451845
if($firstEmpty === -1){ //full inventory
1846-
$this->hotbar->setHeldItem($item);
1846+
$this->setMainHandItem($item);
18471847
}elseif($firstEmpty < $this->hotbar->getSize()){
18481848
$this->inventory->setItem($firstEmpty, $item);
18491849
$this->hotbar->setSelectedIndex($firstEmpty);
18501850
}else{
18511851
$this->inventory->swap($this->hotbar->getSelectedIndex(), $firstEmpty);
1852-
$this->hotbar->setHeldItem($item);
1852+
$this->setMainHandItem($item);
18531853
}
18541854
}
18551855
}
@@ -1866,7 +1866,7 @@ public function attackBlock(Vector3 $pos, Facing $face) : bool{
18661866

18671867
$target = $this->getWorld()->getBlock($pos);
18681868

1869-
$ev = new PlayerInteractEvent($this, $this->hotbar->getHeldItem(), $target, null, $face, PlayerInteractEvent::LEFT_CLICK_BLOCK);
1869+
$ev = new PlayerInteractEvent($this, $this->getMainHandItem(), $target, null, $face, PlayerInteractEvent::LEFT_CLICK_BLOCK);
18701870
if($this->isSpectator()){
18711871
$ev->cancel();
18721872
}
@@ -1875,7 +1875,7 @@ public function attackBlock(Vector3 $pos, Facing $face) : bool{
18751875
return false;
18761876
}
18771877
$this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers());
1878-
if($target->onAttack($this->hotbar->getHeldItem(), $face, $this)){
1878+
if($target->onAttack($this->getMainHandItem(), $face, $this)){
18791879
return true;
18801880
}
18811881

@@ -1916,7 +1916,7 @@ public function breakBlock(Vector3 $pos) : bool{
19161916
if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? self::MAX_REACH_DISTANCE_CREATIVE : self::MAX_REACH_DISTANCE_SURVIVAL)){
19171917
$this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers());
19181918
$this->stopBreakBlock($pos);
1919-
$item = $this->hotbar->getHeldItem();
1919+
$item = $this->getMainHandItem();
19201920
$oldItem = clone $item;
19211921
$returnedItems = [];
19221922
if($this->getWorld()->useBreakOn($pos, $item, $this, true, $returnedItems)){
@@ -1941,7 +1941,7 @@ public function interactBlock(Vector3 $pos, Facing $face, Vector3 $clickOffset)
19411941

19421942
if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? self::MAX_REACH_DISTANCE_CREATIVE : self::MAX_REACH_DISTANCE_SURVIVAL)){
19431943
$this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers());
1944-
$item = $this->hotbar->getHeldItem(); //this is a copy of the real item
1944+
$item = $this->getMainHandItem(); //this is a copy of the real item
19451945
$oldItem = clone $item;
19461946
$returnedItems = [];
19471947
if($this->getWorld()->useItemOn($pos, $item, $face, $clickOffset, $this, true, $returnedItems)){
@@ -1970,7 +1970,7 @@ public function attackEntity(Entity $entity) : bool{
19701970
return false;
19711971
}
19721972

1973-
$heldItem = $this->hotbar->getHeldItem();
1973+
$heldItem = $this->getMainHandItem();
19741974
$oldItem = clone $heldItem;
19751975

19761976
$ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints());
@@ -2056,15 +2056,15 @@ public function interactEntity(Entity $entity, Vector3 $clickPos) : bool{
20562056

20572057
$ev->call();
20582058

2059-
$item = $this->hotbar->getHeldItem();
2059+
$item = $this->getMainHandItem();
20602060
$oldItem = clone $item;
20612061
if(!$ev->isCancelled()){
20622062
if($item->onInteractEntity($this, $entity, $clickPos)){
2063-
if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->hotbar->getHeldItem())){
2063+
if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->getMainHandItem())){
20642064
if($item instanceof Durable && $item->isBroken()){
20652065
$this->broadcastSound(new ItemBreakSound());
20662066
}
2067-
$this->hotbar->setHeldItem($item);
2067+
$this->setMainHandItem($item);
20682068
}
20692069
}
20702070
return $entity->onInteract($this, $clickPos);

0 commit comments

Comments
 (0)