Implemented block break XP drops

This commit is contained in:
Dylan K. Taylor 2018-04-15 19:03:18 +01:00
parent 1e2122d854
commit 532269a484
9 changed files with 84 additions and 3 deletions

View File

@ -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.

View File

@ -57,4 +57,7 @@ class CoalOre extends Solid{
];
}
public function getXpDropForTool(Item $item) : int{
return mt_rand(0, 2);
}
}

View File

@ -56,4 +56,8 @@ class DiamondOre extends Solid{
ItemFactory::get(Item::DIAMOND)
];
}
protected function getXpDropAmount() : int{
return mt_rand(3, 7);
}
}

View File

@ -57,4 +57,7 @@ class LapisOre extends Solid{
];
}
protected function getXpDropAmount() : int{
return mt_rand(2, 5);
}
}

View File

@ -57,4 +57,8 @@ class MonsterSpawner extends Transparent{
public function isAffectedBySilkTouch() : bool{
return false;
}
protected function getXpDropAmount() : int{
return mt_rand(15, 43);
}
}

View File

@ -57,4 +57,7 @@ class NetherQuartzOre extends Solid{
];
}
protected function getXpDropAmount() : int{
return mt_rand(2, 5);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}