Hi, I've been coding a plugin which when an item is tapped using the "PlayerInteractEvent" it will be removed from the players inventory. The code below works perfectly except for one small problem. Upon clicking / tapping the item on the ground if you have more than one of the same item, (stacked or in different slots) more than one item is removed from the inventory. How can I prevent this? Thanks for your help Code: PHP: /** * @param PlayerInteractEvent $event */ public function onTap(PlayerInteractEvent $event){ $player = $event->getPlayer(); $name = $player->getName(); $item = $player->getInventory()->getItemInHand(); $damage = $item->getDamage(); switch($damage) { case "105": if ($item->getId() === 339){ $item1 = Item::get(339, 105, 1); $player->getInventory()->removeItem($item1); $event->setCancelled(); } break; } }
https://github.com/pmmp/PocketMine-...c/src/pocketmine/inventory/Inventory.php#L110 https://www.php.net/manual/fr/language.operators.comparison.php PHP: public function onTap(PlayerInteractEvent $event){ $player = $event->getPlayer(); $name = $player->getName(); $item = $player->getInventory()->getItemInHand(); $damage = $item->getDamage(); switch($damage) { case "105": if ($item->getId() == 339){ $item1 = Item::get(339, 105, 1); $player->getInventory()->removeItem($item1); } break; } }
Item->getId() returns a string so using the strict comparator is perfectly fine (and better practice). Your code doesn't solve the problem at all. The problem is that removeItem() doesn't care if it has already removed said item from a slot. To solve this you will need to write your own removeItem function that respects the total removed item count: PHP: private function removeItems(Item $item, BaseInventory $inventory){ $checkDamage = !$item->hasAnyDamageValue(); $checkTags = $item->hasCompoundTag(); $checkCount = $item->getCount() === null ? false : true; $count = $item->getCount(); foreach($inventory->getContents() as $index => $i){ if($item->equals($i, $checkDamage, $checkTags)){ if($checkCount && $i->getCount() > $item->getCount()) { $i->setCount($i->getCount() - $count); $inventory->setItem($index, $i); return; } elseif($checkCount && $i->getCount() < $item->getCount()) { $count -= $i->getCount(); $inventory->clear($index); } else { $inventory->clear($index); } } }}
Thank you for the explanation! I knew my code didn’t fix the problem that’s why I asked what was causing it
When using the custom function the code above removes every item with the same ID and damage? How can I make it so that it only clears one at a time?
The function I sent (I think @Ad5001 wrote it for CommandShop) will remove the exact amount of items that is given to it. It will also respect items in different slots.
Here: (thanks for the help) PHP: public function onTap(PlayerInteractEvent $event){ $player = $event->getPlayer(); $name = $player->getName(); $item = $player->getInventory()->getItemInHand(); $damage = $item->getDamage(); switch($damage) { case "101": $testitem= Item::get(450, 101, 1); $item1 = Item::get(310, 0, 1); $item2 = Item::get(311, 0, 1); $item3 = Item::get(312, 0, 1); $item4 = Item::get(313, 0, 1); $pickaxe = Item::get(278, 0, 1); $axe = Item::get(279, 0, 1); $tobegiven1 = [$item1, $item2, $item4, $item3, $pickaxe, $axe]; $rand1 = mt_rand(0, 7); $player->getInventory()->addItem($tobegiven1[$rand1]); $player->sendPopup(TF::YELLOW. "Opening.."); $event->setCancelled(); $this->removeItems($testitem, $player->getInventory()); break; } } /** * @param removeItems $item */ private function removeItems(Item $item, BaseInventory $inventory){ $checkDamage = !$item->hasAnyDamageValue(); $checkTags = $item->hasCompoundTag(); $checkCount = $item->getCount() === null ? false : true; $count = $item->getCount(); foreach($inventory->getContents() as $index => $i){ if($item->equals($i, $checkDamage, $checkTags)){ if($checkCount && $i->getCount() > $item->getCount()) { $i->setCount($i->getCount() - $count); $inventory->setItem($index, $i); return; } elseif($checkCount && $i->getCount() < $item->getCount()) { $count -= $i->getCount(); $inventory->clear($index); } else { $inventory->clear($index); } } } }
Apparently that code was never tested and contains several bugs lol, try that one: PHP: private function removeItems(Item $item, BaseInventory $inventory){ $checkDamage = !$item->hasAnyDamageValue(); $checkTags = $item->hasCompoundTag(); $checkCount = $item->getCount() === null ? false : true; $count = $item->getCount(); foreach($inventory->getContents() as $index => $i){ if($item->equals($i, $checkDamage, $checkTags)){ if($checkCount && $i->getCount() > $count) { $i->setCount($i->getCount() - $count); $inventory->setItem($index, $i); return; } elseif($checkCount && $i->getCount() < $count) { $count -= $i->getCount(); $inventory->clear($index); } else { $inventory->clear($index); return; } } }}