/** * Tries to break a block using a item, including Player time checks if available * It'll try to lower the durability if Item is a tool, and set it to Air if broken. * * @param Vector3 $vector * @param Item &$item (if null, can break anything) * @param Player $player * @param bool $createParticles * * @return boolean */ public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = null, $createParticles = false) { $target = $this->getBlock($vector); //TODO: Adventure mode checks if ($item === null) { $item = Item::get(Item::AIR, 0, 0); } if ($player !== null) { $ev = new BlockBreakEvent($player, $target, $item, $player->isCreative() ? true : false); if ($player->isSpectator() or !$player->isOp() and $player->isAdventure()) { $ev->setCancelled(); } if ($item instanceof Tool) { $item->setDamage($item->getDamage() + $item->getDamageStep($target)); $player->getInventory()->setItemInHand($item); } if ($player->isSurvival() and $item instanceof Item and !$target->isBreakable($item)) { $ev->setCancelled(); } if (!$player->isOp() and ($distance = $this->server->getSpawnRadius()) > -1) { $t = new Vector2($target->x, $target->z); $s = new Vector2($this->getSpawnLocation()->x, $this->getSpawnLocation()->z); if ($t->distance($s) <= $distance) { $ev->setCancelled(); } } $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { return false; } $breakTime = $target->getBreakTime($item); if ($player->isCreative() and $breakTime > 0.15) { $breakTime = 0.15; } if ($player->hasEffect(Effect::SWIFTNESS)) { $breakTime *= 1 - 0.2 * ($player->getEffect(Effect::SWIFTNESS)->getAmplifier() + 1); } if ($player->hasEffect(Effect::MINING_FATIGUE)) { $breakTime *= 1 + 0.3 * ($player->getEffect(Effect::MINING_FATIGUE)->getAmplifier() + 1); } $breakTime -= 0.05; //1 tick compensation if (!$ev->getInstaBreak() and $player->lastBreak + $breakTime > microtime(true)) { return false; } $player->lastBreak = microtime(true); $drops = $ev->getDrops(); if ($this->server->getProperty("experience.enable", true) and $this->server->getProperty("experience.break-drop", true) and $player->isSurvival()) { $exp = $target->getExperience(); $this->spawnExperienceOrb($vector->add(0, 1, 0), $exp); } } elseif ($item !== null and !$target->isBreakable($item)) { return false; } else { $drops = $target->getDrops($item); //Fixes tile entities being deleted before getting drops foreach ($drops as $k => $i) { $drops[$k] = Item::get($i[0], $i[1], $i[2]); } } $tag = $item->getNamedTagEntry("CanDestroy"); if ($tag instanceof Enum) { $canBreak = false; foreach ($tag as $v) { if ($v instanceof String) { $entry = Item::fromString($v->getValue()); if ($entry->getId() > 0 and $entry->getBlock() !== null and $entry->getBlock()->getId() === $target->getId()) { $canBreak = true; break; } } } if (!$canBreak) { return false; } } if ($createParticles) { $players = $this->getChunkPlayers($target->x >> 4, $target->z >> 4); if ($player !== null) { unset($players[$player->getLoaderId()]); } $this->addParticle(new DestroyBlockParticle($target->add(0.5), $target), $players); } $target->onBreak($item); $tile = $this->getTile($target); if ($tile !== null) { if ($tile instanceof InventoryHolder) { if ($tile instanceof Chest) { $tile->unpair(); } foreach ($tile->getInventory()->getContents() as $chestItem) { $this->dropItem($target, $chestItem); } } $tile->close(); } if ($item !== null) { $item->useOn($target); if ($item->isTool() and $item->getDamage() >= $item->getMaxDurability()) { $item = Item::get(Item::AIR, 0, 0); } } if ($player === null or $player->isSurvival()) { foreach ($drops as $drop) { if ($drop->getCount() > 0) { $this->dropItem($vector->add(0.5, 0.5, 0.5), $drop); } } } return true; }