diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index aa5518afd..012d47258 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -80,6 +80,7 @@ use pocketmine\item\Durable; use pocketmine\item\enchantment\EnchantmentInstance; use pocketmine\item\enchantment\MeleeWeaponEnchantment; use pocketmine\item\Item; +use pocketmine\item\ItemUseResult; use pocketmine\item\WritableBook; use pocketmine\item\WrittenBook; use pocketmine\lang\TextContainer; @@ -2061,11 +2062,14 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, return false; } - if($item->onClickAir($this, $directionVector)){ + $result = $item->onClickAir($this, $directionVector); + if($result === ItemUseResult::success()){ $this->resetItemCooldown($item); if($this->isSurvival()){ $this->inventory->setItemInHand($item); } + }elseif($result === ItemUseResult::fail()){ + $this->inventory->sendHeldItem($this); } //TODO: check if item has a release action - if it doesn't, this shouldn't be set @@ -2120,11 +2124,16 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, $this->inventory->sendContents($this); return false; } - if($item->onReleaseUsing($this)){ + $result = $item->onReleaseUsing($this); + if($result === ItemUseResult::success()){ $this->resetItemCooldown($item); $this->inventory->setItemInHand($item); return true; } + if($result === ItemUseResult::fail()){ + $this->inventory->sendContents($this); + return true; + } } return false; diff --git a/src/pocketmine/item/Bow.php b/src/pocketmine/item/Bow.php index 9d1b50013..ec694619d 100644 --- a/src/pocketmine/item/Bow.php +++ b/src/pocketmine/item/Bow.php @@ -47,10 +47,9 @@ class Bow extends Tool{ return 385; } - public function onReleaseUsing(Player $player) : bool{ + public function onReleaseUsing(Player $player) : ItemUseResult{ if($player->isSurvival() and !$player->getInventory()->contains(ItemFactory::get(Item::ARROW, 0, 1))){ - $player->getInventory()->sendContents($player); - return false; + return ItemUseResult::fail(); } $nbt = EntityFactory::createBaseNBT( @@ -93,30 +92,32 @@ class Bow extends Tool{ if($ev->isCancelled()){ $entity->flagForDespawn(); - $player->getInventory()->sendContents($player); - }else{ - $entity->setMotion($entity->getMotion()->multiply($ev->getForce())); - if($player->isSurvival()){ - if(!$infinity){ //TODO: tipped arrows are still consumed when Infinity is applied - $player->getInventory()->removeItem(ItemFactory::get(Item::ARROW, 0, 1)); - } - $this->applyDamage(1); - } - - if($entity instanceof Projectile){ - $projectileEv = new ProjectileLaunchEvent($entity); - $projectileEv->call(); - if($projectileEv->isCancelled()){ - $ev->getProjectile()->flagForDespawn(); - }else{ - $ev->getProjectile()->spawnToAll(); - $player->getLevel()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_BOW); - } - }else{ - $entity->spawnToAll(); - } + return ItemUseResult::fail(); } - return true; + $entity->setMotion($entity->getMotion()->multiply($ev->getForce())); + + if($entity instanceof Projectile){ + $projectileEv = new ProjectileLaunchEvent($entity); + $projectileEv->call(); + if($projectileEv->isCancelled()){ + $ev->getProjectile()->flagForDespawn(); + return ItemUseResult::fail(); + } + + $ev->getProjectile()->spawnToAll(); + $player->getLevel()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_BOW); + }else{ + $entity->spawnToAll(); + } + + if($player->isSurvival()){ + if(!$infinity){ //TODO: tipped arrows are still consumed when Infinity is applied + $player->getInventory()->removeItem(ItemFactory::get(Item::ARROW, 0, 1)); + } + $this->applyDamage(1); + } + + return ItemUseResult::success(); } } diff --git a/src/pocketmine/item/Bucket.php b/src/pocketmine/item/Bucket.php index 3650e45f3..5a17c2de1 100644 --- a/src/pocketmine/item/Bucket.php +++ b/src/pocketmine/item/Bucket.php @@ -36,7 +36,7 @@ class Bucket extends Item{ return 16; } - public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{ + public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : ItemUseResult{ //TODO: move this to generic placement logic if($blockClicked instanceof Liquid and $blockClicked->isSource()){ $stack = clone $this; @@ -58,13 +58,12 @@ class Bucket extends Item{ }else{ $player->getInventory()->addItem($ev->getItem()); } - }else{ - $player->getInventory()->sendContents($player); + return ItemUseResult::success(); } - return true; + return ItemUseResult::fail(); } - return false; + return ItemUseResult::none(); } } diff --git a/src/pocketmine/item/FlintSteel.php b/src/pocketmine/item/FlintSteel.php index a144c59cb..f36b687fa 100644 --- a/src/pocketmine/item/FlintSteel.php +++ b/src/pocketmine/item/FlintSteel.php @@ -35,7 +35,7 @@ class FlintSteel extends Tool{ parent::__construct(self::FLINT_STEEL, 0, "Flint and Steel"); } - public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{ + public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : ItemUseResult{ if($blockReplace->getId() === self::AIR){ $level = $player->getLevel(); assert($level !== null); @@ -44,10 +44,10 @@ class FlintSteel extends Tool{ $this->applyDamage(1); - return true; + return ItemUseResult::success(); } - return false; + return ItemUseResult::none(); } public function getMaxDurability() : int{ diff --git a/src/pocketmine/item/Item.php b/src/pocketmine/item/Item.php index 60296abf7..d877b204e 100644 --- a/src/pocketmine/item/Item.php +++ b/src/pocketmine/item/Item.php @@ -735,10 +735,10 @@ class Item implements ItemIds, \JsonSerializable{ * @param int $face * @param Vector3 $clickVector * - * @return bool + * @return ItemUseResult */ - public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{ - return false; + public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : ItemUseResult{ + return ItemUseResult::none(); } /** @@ -748,10 +748,10 @@ class Item implements ItemIds, \JsonSerializable{ * @param Player $player * @param Vector3 $directionVector * - * @return bool + * @return ItemUseResult */ - public function onClickAir(Player $player, Vector3 $directionVector) : bool{ - return false; + public function onClickAir(Player $player, Vector3 $directionVector) : ItemUseResult{ + return ItemUseResult::none(); } /** @@ -760,10 +760,10 @@ class Item implements ItemIds, \JsonSerializable{ * * @param Player $player * - * @return bool + * @return ItemUseResult */ - public function onReleaseUsing(Player $player) : bool{ - return false; + public function onReleaseUsing(Player $player) : ItemUseResult{ + return ItemUseResult::none(); } /** diff --git a/src/pocketmine/item/ItemUseResult.php b/src/pocketmine/item/ItemUseResult.php new file mode 100644 index 000000000..78b89802c --- /dev/null +++ b/src/pocketmine/item/ItemUseResult.php @@ -0,0 +1,65 @@ +canBeReplaced()){ - return false; + return ItemUseResult::none(); } //TODO: move this to generic placement logic $resultBlock = BlockFactory::get($this->liquidId); - if($resultBlock instanceof Liquid){ + if($resultBlock instanceof Liquid){ //TODO: this should never be false $ev = new PlayerBucketEmptyEvent($player, $blockReplace, $face, $this, ItemFactory::get(Item::BUCKET)); $ev->call(); if(!$ev->isCancelled()){ @@ -69,13 +69,12 @@ class LiquidBucket extends Item{ if($player->isSurvival()){ $player->getInventory()->setItemInHand($ev->getItem()); } - }else{ - $player->getInventory()->sendContents($player); + return ItemUseResult::success(); } - return true; + return ItemUseResult::fail(); } - return false; + return ItemUseResult::none(); } } diff --git a/src/pocketmine/item/PaintingItem.php b/src/pocketmine/item/PaintingItem.php index 2856b7f92..03c51a14c 100644 --- a/src/pocketmine/item/PaintingItem.php +++ b/src/pocketmine/item/PaintingItem.php @@ -38,9 +38,9 @@ class PaintingItem extends Item{ parent::__construct(self::PAINTING, 0, "Painting"); } - public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{ + public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : ItemUseResult{ if(Facing::axis($face) === Facing::AXIS_Y){ - return false; + return ItemUseResult::none(); } $motives = []; diff --git a/src/pocketmine/item/ProjectileItem.php b/src/pocketmine/item/ProjectileItem.php index 14bb8e587..02b564d13 100644 --- a/src/pocketmine/item/ProjectileItem.php +++ b/src/pocketmine/item/ProjectileItem.php @@ -53,7 +53,7 @@ abstract class ProjectileItem extends Item{ } - public function onClickAir(Player $player, Vector3 $directionVector) : bool{ + public function onClickAir(Player $player, Vector3 $directionVector) : ItemUseResult{ $nbt = EntityFactory::createBaseNBT($player->add(0, $player->getEyeHeight(), 0), $directionVector, $player->yaw, $player->pitch); $this->addExtraTags($nbt); @@ -68,14 +68,15 @@ abstract class ProjectileItem extends Item{ $projectileEv->call(); if($projectileEv->isCancelled()){ $projectile->flagForDespawn(); - }else{ - $projectile->spawnToAll(); - - $player->getLevel()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_THROW, 0, EntityIds::PLAYER); + return ItemUseResult::fail(); } + $projectile->spawnToAll(); + + $player->getLevel()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_THROW, 0, EntityIds::PLAYER); + $this->pop(); - return true; + return ItemUseResult::success(); } } diff --git a/src/pocketmine/item/SpawnEgg.php b/src/pocketmine/item/SpawnEgg.php index 7c7d86d28..364280928 100644 --- a/src/pocketmine/item/SpawnEgg.php +++ b/src/pocketmine/item/SpawnEgg.php @@ -50,7 +50,7 @@ class SpawnEgg extends Item{ $this->entityClass = $entityClass; } - public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{ + public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : ItemUseResult{ $nbt = EntityFactory::createBaseNBT($blockReplace->add(0.5, 0, 0.5), null, lcg_value() * 360, 0); if($this->hasCustomName()){ @@ -60,6 +60,7 @@ class SpawnEgg extends Item{ $entity = EntityFactory::create($this->entityClass, $player->getLevel(), $nbt); $this->pop(); $entity->spawnToAll(); - return true; + //TODO: what if the entity was marked for deletion? + return ItemUseResult::success(); } } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 4359f1b44..3ad2f7656 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -44,6 +44,7 @@ use pocketmine\event\level\SpawnChangeEvent; use pocketmine\event\player\PlayerInteractEvent; use pocketmine\item\Item; use pocketmine\item\ItemFactory; +use pocketmine\item\ItemUseResult; use pocketmine\level\biome\Biome; use pocketmine\level\format\Chunk; use pocketmine\level\format\ChunkException; @@ -1798,8 +1799,11 @@ class Level implements ChunkManager, Metadatable{ return true; } - if(!$player->isSneaking() and $item->onActivate($player, $blockReplace, $blockClicked, $face, $clickVector)){ - return true; + if(!$player->isSneaking()){ + $result = $item->onActivate($player, $blockReplace, $blockClicked, $face, $clickVector); + if($result !== ItemUseResult::none()){ + return $result === ItemUseResult::success(); + } } }else{ return false;