setCritical($critical); } protected function initEntity(CompoundTag $nbt) : void{ parent::initEntity($nbt); $this->pickupMode = $nbt->getByte(self::TAG_PICKUP, self::PICKUP_ANY); $this->collideTicks = $nbt->getShort("life", $this->collideTicks); } public function saveNBT() : CompoundTag{ $nbt = parent::saveNBT(); $nbt->setByte(self::TAG_PICKUP, $this->pickupMode); $nbt->setShort("life", $this->collideTicks); return $nbt; } public function isCritical() : bool{ return $this->critical; } public function setCritical(bool $value = true) : void{ $this->critical = $value; } public function getResultDamage() : int{ $base = parent::getResultDamage(); if($this->isCritical()){ return ($base + mt_rand(0, (int) ($base / 2) + 1)); }else{ return $base; } } public function getPunchKnockback() : float{ return $this->punchKnockback; } public function setPunchKnockback(float $punchKnockback) : void{ $this->punchKnockback = $punchKnockback; } protected function entityBaseTick(int $tickDiff = 1) : bool{ if($this->closed){ return false; } $hasUpdate = parent::entityBaseTick($tickDiff); if($this->blockHit !== null){ $this->collideTicks += $tickDiff; if($this->collideTicks > 1200){ $this->flagForDespawn(); $hasUpdate = true; } }else{ $this->collideTicks = 0; } return $hasUpdate; } protected function onHit(ProjectileHitEvent $event) : void{ $this->setCritical(false); $this->getWorld()->addSound($this->location, new ArrowHitSound()); } protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{ parent::onHitBlock($blockHit, $hitResult); $this->broadcastAnimation(new ArrowShakeAnimation($this, 7)); } protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : void{ parent::onHitEntity($entityHit, $hitResult); if($this->punchKnockback > 0){ $horizontalSpeed = sqrt($this->motion->x ** 2 + $this->motion->z ** 2); if($horizontalSpeed > 0){ $multiplier = $this->punchKnockback * 0.6 / $horizontalSpeed; $entityHit->setMotion($entityHit->getMotion()->add($this->motion->x * $multiplier, 0.1, $this->motion->z * $multiplier)); } } } public function getPickupMode() : int{ return $this->pickupMode; } public function setPickupMode(int $pickupMode) : void{ $this->pickupMode = $pickupMode; } public function onCollideWithPlayer(Player $player) : void{ if($this->blockHit === null){ return; } $item = VanillaItems::ARROW(); $playerInventory = $player->getInventory(); if($player->hasFiniteResources() and !$playerInventory->canAddItem($item)){ return; } $ev = new InventoryPickupArrowEvent($playerInventory, $this); if($this->pickupMode === self::PICKUP_NONE or ($this->pickupMode === self::PICKUP_CREATIVE and !$player->isCreative())){ $ev->setCancelled(); } $ev->call(); if($ev->isCancelled()){ return; } foreach($this->getViewers() as $viewer){ $viewer->getNetworkSession()->onPlayerPickUpItem($player, $this); } $playerInventory->addItem(clone $item); $this->flagForDespawn(); } protected function syncNetworkData() : void{ parent::syncNetworkData(); $this->networkProperties->setGenericFlag(EntityMetadataFlags::CRITICAL, $this->critical); } }