From 532269a484417967549b8dd918156ae23b707f49 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 15 Apr 2018 19:03:18 +0100 Subject: [PATCH] Implemented block break XP drops --- src/pocketmine/block/Block.php | 24 +++++++++++++++++ src/pocketmine/block/CoalOre.php | 3 +++ src/pocketmine/block/DiamondOre.php | 4 +++ src/pocketmine/block/LapisOre.php | 3 +++ src/pocketmine/block/MonsterSpawner.php | 4 +++ src/pocketmine/block/NetherQuartzOre.php | 3 +++ src/pocketmine/block/RedstoneOre.php | 4 +++ .../event/block/BlockBreakEvent.php | 27 ++++++++++++++++++- src/pocketmine/level/Level.php | 15 +++++++++-- 9 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index 9af0bd1b0..42d77663b 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -471,6 +471,30 @@ class Block extends Position implements BlockIds, Metadatable{ ]; } + /** + * Returns how much XP will be dropped by breaking this block with the given item. + * + * @param Item $item + * + * @return int + */ + public function getXpDropForTool(Item $item) : int{ + if($item->hasEnchantment(Enchantment::SILK_TOUCH) or !$this->isCompatibleWithTool($item)){ + return 0; + } + + return $this->getXpDropAmount(); + } + + /** + * Returns how much XP this block will drop when broken with an appropriate tool. + * + * @return int + */ + protected function getXpDropAmount() : int{ + return 0; + } + /** * Returns whether Silk Touch enchanted tools will cause this block to drop as itself. Since most blocks drop * themselves anyway, this is implicitly true. diff --git a/src/pocketmine/block/CoalOre.php b/src/pocketmine/block/CoalOre.php index 717302f56..7a2c3c2fd 100644 --- a/src/pocketmine/block/CoalOre.php +++ b/src/pocketmine/block/CoalOre.php @@ -57,4 +57,7 @@ class CoalOre extends Solid{ ]; } + public function getXpDropForTool(Item $item) : int{ + return mt_rand(0, 2); + } } diff --git a/src/pocketmine/block/DiamondOre.php b/src/pocketmine/block/DiamondOre.php index 7bbb2e178..cde4604e3 100644 --- a/src/pocketmine/block/DiamondOre.php +++ b/src/pocketmine/block/DiamondOre.php @@ -56,4 +56,8 @@ class DiamondOre extends Solid{ ItemFactory::get(Item::DIAMOND) ]; } + + protected function getXpDropAmount() : int{ + return mt_rand(3, 7); + } } diff --git a/src/pocketmine/block/LapisOre.php b/src/pocketmine/block/LapisOre.php index 194c213ea..c13181cdc 100644 --- a/src/pocketmine/block/LapisOre.php +++ b/src/pocketmine/block/LapisOre.php @@ -57,4 +57,7 @@ class LapisOre extends Solid{ ]; } + protected function getXpDropAmount() : int{ + return mt_rand(2, 5); + } } diff --git a/src/pocketmine/block/MonsterSpawner.php b/src/pocketmine/block/MonsterSpawner.php index 555af6f62..dda589543 100644 --- a/src/pocketmine/block/MonsterSpawner.php +++ b/src/pocketmine/block/MonsterSpawner.php @@ -57,4 +57,8 @@ class MonsterSpawner extends Transparent{ public function isAffectedBySilkTouch() : bool{ return false; } + + protected function getXpDropAmount() : int{ + return mt_rand(15, 43); + } } diff --git a/src/pocketmine/block/NetherQuartzOre.php b/src/pocketmine/block/NetherQuartzOre.php index 3f547dbd1..3726abc02 100644 --- a/src/pocketmine/block/NetherQuartzOre.php +++ b/src/pocketmine/block/NetherQuartzOre.php @@ -57,4 +57,7 @@ class NetherQuartzOre extends Solid{ ]; } + protected function getXpDropAmount() : int{ + return mt_rand(2, 5); + } } diff --git a/src/pocketmine/block/RedstoneOre.php b/src/pocketmine/block/RedstoneOre.php index 837354358..22b8aa739 100644 --- a/src/pocketmine/block/RedstoneOre.php +++ b/src/pocketmine/block/RedstoneOre.php @@ -70,4 +70,8 @@ class RedstoneOre extends Solid{ ItemFactory::get(Item::REDSTONE_DUST, 0, mt_rand(4, 5)) ]; } + + protected function getXpDropAmount() : int{ + return mt_rand(1, 5); + } } diff --git a/src/pocketmine/event/block/BlockBreakEvent.php b/src/pocketmine/event/block/BlockBreakEvent.php index 9ee0ab7e1..93db8478b 100644 --- a/src/pocketmine/event/block/BlockBreakEvent.php +++ b/src/pocketmine/event/block/BlockBreakEvent.php @@ -42,6 +42,8 @@ class BlockBreakEvent extends BlockEvent implements Cancellable{ protected $instaBreak = false; /** @var Item[] */ protected $blockDrops = []; + /** @var int */ + protected $xpDrops; /** * @param Player $player @@ -49,14 +51,16 @@ class BlockBreakEvent extends BlockEvent implements Cancellable{ * @param Item $item * @param bool $instaBreak * @param Item[] $drops + * @param int $xpDrops */ - public function __construct(Player $player, Block $block, Item $item, bool $instaBreak = false, array $drops){ + public function __construct(Player $player, Block $block, Item $item, bool $instaBreak = false, array $drops, int $xpDrops = 0){ parent::__construct($block); $this->item = $item; $this->player = $player; $this->instaBreak = $instaBreak; $this->setDrops($drops); + $this->xpDrops = $xpDrops; } /** @@ -115,4 +119,25 @@ class BlockBreakEvent extends BlockEvent implements Cancellable{ public function setDropsVariadic(Item ...$drops){ $this->blockDrops = $drops; } + + /** + * Returns how much XP will be dropped by breaking this block. + * + * @return int + */ + public function getXpDropAmount() : int{ + return $this->xpDrops; + } + + /** + * Sets how much XP will be dropped by breaking this block. + * + * @param int $amount + */ + public function setXpDrops(int $amount) : void{ + if($amount < 0){ + throw new \InvalidArgumentException("Amount must be at least zero"); + } + $this->xpDrops = $amount; + } } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 4c57046a8..77186ce90 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -1676,10 +1676,16 @@ class Level implements ChunkManager, Metadatable{ $item = ItemFactory::get(Item::AIR, 0, 0); } - $drops = ($player !== null and $player->isCreative()) ? [] : array_merge(...array_map(function(Block $block) use ($item) : array{ return $block->getDrops($item); }, $affectedBlocks)); + $drops = []; + $xpDrop = 0; + + if($player !== null and !$player->isCreative()){ + $drops = array_merge(...array_map(function(Block $block) use ($item) : array{ return $block->getDrops($item); }, $affectedBlocks)); + $xpDrop = array_sum(array_map(function(Block $block) use ($item) : int{ return $block->getXpDropForTool($item); }, $affectedBlocks)); + } if($player !== null){ - $ev = new BlockBreakEvent($player, $target, $item, $player->isCreative(), $drops); + $ev = new BlockBreakEvent($player, $target, $item, $player->isCreative(), $drops, $xpDrop); if(($player->isSurvival() and !$target->isBreakable($item)) or $player->isSpectator()){ $ev->setCancelled(); @@ -1711,6 +1717,7 @@ class Level implements ChunkManager, Metadatable{ } $drops = $ev->getDrops(); + $xpDrop = $ev->getXpDropAmount(); }elseif(!$target->isBreakable($item)){ return false; @@ -1731,6 +1738,10 @@ class Level implements ChunkManager, Metadatable{ } } + if($xpDrop > 0){ + $this->dropExperience($target->add(0.5, 0.5, 0.5), $xpDrop); + } + return true; }