Enable various types of interaction to return items to the player, without needing to have a bunch of boilerplate creative mode and held item checks

it became glaringly obvious that this was needed because of #4827 and #4868.

this is further needed with the addition of cauldrons.
This commit is contained in:
Dylan K. Taylor
2022-07-16 19:50:33 +01:00
parent 4afd3dcabf
commit d0ff6d2e36
69 changed files with 177 additions and 155 deletions

View File

@@ -54,6 +54,7 @@ use pocketmine\event\player\PlayerChatEvent;
use pocketmine\event\player\PlayerCommandPreprocessEvent;
use pocketmine\event\player\PlayerDeathEvent;
use pocketmine\event\player\PlayerDisplayNameChangeEvent;
use pocketmine\event\player\PlayerDropItemEvent;
use pocketmine\event\player\PlayerEmoteEvent;
use pocketmine\event\player\PlayerEntityInteractEvent;
use pocketmine\event\player\PlayerExhaustEvent;
@@ -1443,6 +1444,39 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
return true;
}
/**
* @param Item[] $extraReturnedItems
*/
private function returnItemsFromAction(Item $oldHeldItem, Item $newHeldItem, array $extraReturnedItems) : void{
$heldItemChanged = false;
if($this->hasFiniteResources()){
if(!$newHeldItem->equalsExact($oldHeldItem) && $oldHeldItem->equalsExact($this->inventory->getItemInHand())){
if($newHeldItem instanceof Durable && $newHeldItem->isBroken()){
$this->broadcastSound(new ItemBreakSound());
}
$this->inventory->setItemInHand($newHeldItem);
$heldItemChanged = true;
}
}else{
$newHeldItem = $oldHeldItem;
}
if($heldItemChanged && count($extraReturnedItems) > 0 && $newHeldItem->isNull()){
$this->inventory->setItemInHand(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 :(
$ev = new PlayerDropItemEvent($this, $drop);
if($this->isSpectator()){
$ev->cancel();
}
$ev->call();
if(!$ev->isCancelled()){
$this->dropItem($drop);
}
}
}
/**
* Activates the item in hand, for example throwing a projectile.
*
@@ -1464,18 +1498,14 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
return false;
}
$result = $item->onClickAir($this, $directionVector);
$returnedItems = [];
$result = $item->onClickAir($this, $directionVector, $returnedItems);
if($result->equals(ItemUseResult::FAIL())){
return false;
}
$this->resetItemCooldown($item);
if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->inventory->getItemInHand())){
if($item instanceof Durable && $item->isBroken()){
$this->broadcastSound(new ItemBreakSound());
}
$this->inventory->setItemInHand($item);
}
$this->returnItemsFromAction($oldItem, $item, $returnedItems);
$this->setUsingItem($item instanceof Releasable && $item->canStartUsingItem($this));
@@ -1505,11 +1535,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->setUsingItem(false);
$this->resetItemCooldown($slot);
if($this->hasFiniteResources() && $oldItem->equalsExact($this->inventory->getItemInHand())){
$slot->pop();
$this->inventory->setItemInHand($slot);
$this->inventory->addItem($slot->getResidue());
}
$slot->pop();
$this->returnItemsFromAction($oldItem, $slot, [$slot->getResidue()]);
return true;
}
@@ -1531,15 +1558,11 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$oldItem = clone $item;
$result = $item->onReleaseUsing($this);
$returnedItems = [];
$result = $item->onReleaseUsing($this, $returnedItems);
if($result->equals(ItemUseResult::SUCCESS())){
$this->resetItemCooldown($item);
if(!$item->equalsExact($oldItem) && $oldItem->equalsExact($this->inventory->getItemInHand())){
if($item instanceof Durable && $item->isBroken()){
$this->broadcastSound(new ItemBreakSound());
}
$this->inventory->setItemInHand($item);
}
$this->returnItemsFromAction($oldItem, $item, $returnedItems);
return true;
}
@@ -1652,13 +1675,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->stopBreakBlock($pos);
$item = $this->inventory->getItemInHand();
$oldItem = clone $item;
if($this->getWorld()->useBreakOn($pos, $item, $this, true)){
if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->inventory->getItemInHand())){
if($item instanceof Durable && $item->isBroken()){
$this->broadcastSound(new ItemBreakSound());
}
$this->inventory->setItemInHand($item);
}
$returnedItems = [];
if($this->getWorld()->useBreakOn($pos, $item, $this, true, $returnedItems)){
$this->returnItemsFromAction($oldItem, $item, $returnedItems);
$this->hungerManager->exhaust(0.005, PlayerExhaustEvent::CAUSE_MINING);
return true;
}
@@ -1681,13 +1700,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers());
$item = $this->inventory->getItemInHand(); //this is a copy of the real item
$oldItem = clone $item;
if($this->getWorld()->useItemOn($pos, $item, $face, $clickOffset, $this, true)){
if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->inventory->getItemInHand())){
if($item instanceof Durable && $item->isBroken()){
$this->broadcastSound(new ItemBreakSound());
}
$this->inventory->setItemInHand($item);
}
$returnedItems = [];
if($this->getWorld()->useItemOn($pos, $item, $face, $clickOffset, $this, true, $returnedItems)){
$this->returnItemsFromAction($oldItem, $item, $returnedItems);
return true;
}
}else{
@@ -1762,12 +1777,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
if($this->isAlive()){
//reactive damage like thorns might cause us to be killed by attacking another mob, which
//would mean we'd already have dropped the inventory by the time we reached here
if($heldItem->onAttackEntity($entity) && $this->hasFiniteResources() && $oldItem->equalsExact($this->inventory->getItemInHand())){ //always fire the hook, even if we are survival
if($heldItem instanceof Durable && $heldItem->isBroken()){
$this->broadcastSound(new ItemBreakSound());
}
$this->inventory->setItemInHand($heldItem);
}
$returnedItems = [];
$heldItem->onAttackEntity($entity, $returnedItems);
$this->returnItemsFromAction($oldItem, $heldItem, $returnedItems);
$this->hungerManager->exhaust(0.1, PlayerExhaustEvent::CAUSE_ATTACK);
}