/** * Clear players inventory * @param Player $target */ public static function clearInventory(Player $target) { if ($target->isCreative() || $target->isSpectator()) { return; } $target->getInventory()->clearAll(); }
/** * Uses a item on a position and face, placing it or activating the block * * @param Vector3 $vector * @param Item $item * @param int $face * @param float $fx default 0.0 * @param float $fy default 0.0 * @param float $fz default 0.0 * @param Player $player default null * * @return boolean */ public function useItemOn(Vector3 $vector, Item &$item, $face, $fx = 0.0, $fy = 0.0, $fz = 0.0, Player $player = null) { $target = $this->getBlock($vector); $block = $target->getSide($face); if ($block->y > 127 or $block->y < 0) { return false; } if ($target->getId() === Item::AIR) { return false; } if ($player !== null) { $ev = new PlayerInteractEvent($player, $item, $target, $face, $target->getId() === 0 ? PlayerInteractEvent::RIGHT_CLICK_AIR : PlayerInteractEvent::RIGHT_CLICK_BLOCK); if ($player->isSpectator()) { $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()) { $target->onUpdate(self::BLOCK_UPDATE_TOUCH); if (!$player->isSneaking() and $target->canBeActivated() === true and $target->onActivate($item, $player) === true) { return true; } if (!$player->isSneaking() and $item->canBeActivated() and $item->onActivate($this, $player, $block, $target, $face, $fx, $fy, $fz)) { if ($item->getCount() <= 0) { $item = Item::get(Item::AIR, 0, 0); return true; } } } else { return false; } } elseif ($target->canBeActivated() === true and $target->onActivate($item, $player) === true) { return true; } if ($item->canBePlaced()) { $hand = $item->getBlock(); $hand->position($block); } elseif ($block->getId() === Item::FIRE) { $this->setBlock($block, new Air(), true); return false; } else { return false; } if (!($block->canBeReplaced() === true or $hand->getId() === Item::SLAB and $block->getId() === Item::SLAB)) { return false; //can anyone explain this to me?- Zombie } if ($target->canBeReplaced() === true) { $block = $target; $hand->position($block); //$face = -1; } if ($hand->isSolid() === true and $hand->getBoundingBox() !== null) { $entities = $this->getCollidingEntities($hand->getBoundingBox()); $realCount = 0; foreach ($entities as $e) { if ($e instanceof Arrow or $e instanceof DroppedItem) { continue; } ++$realCount; } if ($player !== null) { if ($diff = $player->getNextPosition()->subtract($player->getPosition()) and $diff->lengthSquared() > 1.0E-5) { $bb = $player->getBoundingBox()->getOffsetBoundingBox($diff->x, $diff->y, $diff->z); if ($hand->getBoundingBox()->intersectsWith($bb)) { ++$realCount; } } } if ($realCount > 0) { return false; //Entity in block } } $tag = $item->getNamedTagEntry("CanPlaceOn"); if ($tag instanceof Enum) { $canPlace = 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()) { $canPlace = true; break; } } } if (!$canPlace) { return false; } } if ($player !== null) { $ev = new BlockPlaceEvent($player, $hand, $block, $target, $item); 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 (count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance) { //set it to cancelled so plugins can bypass this $ev->setCancelled(); } } $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { return false; } } if ($hand->place($item, $block, $target, $face, $fx, $fy, $fz, $player) === false) { return false; } if ($hand->getId() === Item::SIGN_POST or $hand->getId() === Item::WALL_SIGN) { $nbt = new Compound("", ["id" => new String("id", Tile::SIGN), "x" => new Int("x", $block->x), "y" => new Int("y", $block->y), "z" => new Int("z", $block->z), "Text1" => new String("Text1", ""), "Text2" => new String("Text2", ""), "Text3" => new String("Text3", ""), "Text4" => new String("Text4", "")]); if ($player !== null) { $nbt->Creator = new String("Creator", $player->getRawUniqueId()); } if ($item->hasCustomBlockData()) { foreach ($item->getCustomBlockData() as $key => $v) { $nbt->{$key} = $v; } } Tile::createTile("Sign", $this->getChunk($block->x >> 4, $block->z >> 4), $nbt); } $item->setCount($item->getCount() - 1); if ($item->getCount() <= 0) { $item = Item::get(Item::AIR, 0, 0); } return true; }
/** * 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); if ($item === null) { $item = Item::get(Item::AIR, 0, 0); } if ($player !== null) { if ($player->isAdventure() or $player->isSpectator()) { return true; } $ev = new BlockBreakEvent($player, $target, $item, $player->isCreative() ? true : false); if ($player->isSurvival() and $item instanceof Item and !$target->isBreakable($item)) { $ev->setCancelled(); } elseif (!$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 (count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance) { //set it to cancelled so plugins can bypass this $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 ($player->isSurvival() and $this->getServer()->expEnabled) { switch ($target->getId()) { case Block::COAL_ORE: $exp = mt_rand(0, 2); if ($exp > 0) { $this->addExperienceOrb($vector->add(0, 1, 0), $exp); } break; case Block::DIAMOND_ORE: case Block::EMERALD_ORE: $exp = mt_rand(3, 7); $this->addExperienceOrb($vector->add(0, 1, 0), $exp); break; case Block::NETHER_QUARTZ_ORE: case Block::LAPIS_ORE: $exp = mt_rand(2, 5); $this->addExperienceOrb($vector->add(0, 1, 0), $exp); break; case Block::REDSTONE_ORE: case Block::GLOWING_REDSTONE_ORE: $exp = mt_rand(1, 5); $this->addExperienceOrb($vector->add(0, 1, 0), $exp); break; case Block::MONSTER_SPAWNER: $exp = mt_rand(15, 43); $this->addExperienceOrb($vector->add(0, 1, 0), $exp); break; } } } 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) { if (isset($i[0]) && isset($i[1]) && isset($i[2])) { $drops[$k] = Item::get($i[0], $i[1], $i[2]); } } } $above = $this->getBlock(new Vector3($target->x, $target->y + 1, $target->z)); if ($above !== null) { if ($above->getId() === Item::FIRE) { $this->setBlock($above, new Air(), true); } } $tag = $item->getNamedTagEntry("CanDestroy"); if ($tag instanceof EnumTag) { $canBreak = false; foreach ($tag as $v) { if ($v instanceof StringTag) { $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; }
/** * 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()) { $ev->setCancelled(); } if ($player->isSurvival() and $item instanceof Item and !$target->isBreakable($item)) { $ev->setCancelled(); } elseif (!$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 (\count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance) { //set it to cancelled so plugins can bypass this $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(); } 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]); } } $above = $this->getBlock(new Vector3($target->x, $target->y + 1, $target->z)); if ($above !== \null) { if ($above->getId() === Item::FIRE) { $this->setBlock($above, new Air(), \true); } } $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; }
/** * Uses a item on a position and face, placing it or activating the block * * @param Vector3 $vector * @param Item $item * @param int $face * @param float $fx default 0.0 * @param float $fy default 0.0 * @param float $fz default 0.0 * @param Player $player default null * * @return bool */ public function useItemOn(Vector3 $vector, Item &$item, int $face, float $fx = 0.0, float $fy = 0.0, float $fz = 0.0, Player $player = null) { $target = $this->getBlock($vector); $block = $target->getSide($face); if ($block->y > 127 or $block->y < 0) { return false; } if ($target->getId() === Item::AIR) { return false; } if ($player !== null) { $ev = new PlayerInteractEvent($player, $item, $target, $face, $target->getId() === 0 ? PlayerInteractEvent::RIGHT_CLICK_AIR : PlayerInteractEvent::RIGHT_CLICK_BLOCK); if ($player->isSpectator()) { $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()) { $target->onUpdate(self::BLOCK_UPDATE_TOUCH); if (!$player->isSneaking() and $target->canBeActivated() === true and $target->onActivate($item, $player) === true) { return true; } if (!$player->isSneaking() and $item->canBeActivated() and $item->onActivate($this, $player, $block, $target, $face, $fx, $fy, $fz)) { if ($item->getCount() <= 0) { $item = Item::get(Item::AIR, 0, 0); return true; } } } else { return false; } } elseif ($target->canBeActivated() === true and $target->onActivate($item, $player) === true) { return true; } if ($item->canBePlaced()) { $hand = $item->getBlock(); $hand->position($block); } else { return false; } if (!($block->canBeReplaced() === true or $hand->getId() === Item::SLAB and $block->getId() === Item::SLAB)) { return false; } if ($target->canBeReplaced() === true) { $block = $target; $hand->position($block); //$face = -1; } if ($hand->isSolid() === true and $hand->getBoundingBox() !== null) { $entities = $this->getCollidingEntities($hand->getBoundingBox()); $realCount = 0; foreach ($entities as $e) { if ($e instanceof Arrow or $e instanceof DroppedItem) { continue; } ++$realCount; } if ($player !== null) { if ($diff = $player->getNextPosition()->subtract($player->getPosition()) and $diff->lengthSquared() > 1.0E-5) { $bb = $player->getBoundingBox()->getOffsetBoundingBox($diff->x, $diff->y, $diff->z); if ($hand->getBoundingBox()->intersectsWith($bb)) { ++$realCount; } } } if ($realCount > 0) { return false; //Entity in block } } $tag = $item->getNamedTagEntry("CanPlaceOn"); if ($tag instanceof ListTag) { $canPlace = false; foreach ($tag as $v) { if ($v instanceof StringTag) { $entry = Item::fromString($v->getValue()); if ($entry->getId() > 0 and $entry->getBlock() !== null and $entry->getBlock()->getId() === $target->getId()) { $canPlace = true; break; } } } if (!$canPlace) { return false; } } if ($player !== null) { $ev = new BlockPlaceEvent($player, $hand, $block, $target, $item); 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) { //set it to cancelled so plugins can bypass this $ev->setCancelled(); } } $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { return false; } } if ($hand->place($item, $block, $target, $face, $fx, $fy, $fz, $player) === false) { return false; } $this->addSound(new BlockPlaceSound($this->getBlock($block))); //Get updated block, $block is still the original block and cannot be used directly $item->setCount($item->getCount() - 1); if ($item->getCount() <= 0) { $item = Item::get(Item::AIR, 0, 0); } return true; }