namedtag->HealF)){ $this->namedtag->Health = new Short("Health", (int) $this->namedtag["HealF"]); unset($this->namedtag->HealF); } if(!isset($this->namedtag->Health) or !($this->namedtag->Health instanceof Short)){ $this->namedtag->Health = new Short("Health", $this->getMaxHealth()); } $this->setHealth($this->namedtag["Health"]); } public function saveNBT(){ parent::saveNBT(); $this->namedtag->Health = new Short("Health", $this->getHealth()); } public abstract function getName(); public function hasLineOfSight(Entity $entity){ //TODO: head height return true; //return $this->getLevel()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null; } public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){ if($this->attackTime > 0 or $this->noDamageTicks > 0){ $lastCause = $this->getLastDamageCause(); if($lastCause instanceof EntityDamageEvent and $lastCause->getDamage() >= $damage){ if($source instanceof EntityDamageEvent){ $source->setCancelled(); $this->server->getPluginManager()->callEvent($source); $damage = $source->getFinalDamage(); if($source->isCancelled()){ return; } }else{ return; } }else{ return; } }elseif($source instanceof EntityDamageEvent){ $this->server->getPluginManager()->callEvent($source); $damage = $source->getFinalDamage(); if($source->isCancelled()){ return; } } $this->setLastDamageCause($source); if($source instanceof EntityDamageByEntityEvent){ $e = $source->getDamager(); $deltaX = $this->x - $e->x; $deltaZ = $this->z - $e->z; $yaw = atan2($deltaX, $deltaZ); $this->knockBack($e, $damage, sin($yaw), cos($yaw), $source->getKnockBack()); } $this->setHealth($this->getHealth() - $damage); $pk = new EntityEventPacket(); $pk->eid = $this->getId(); $pk->event = $this->getHealth() <= 0 ? 3 : 2; //Ouch! Server::broadcastPacket($this->hasSpawned, $pk); $this->attackTime = 10; //0.5 seconds cooldown } public function knockBack(Entity $attacker, $damage, $x, $z, $base = 0.4){ $f = sqrt($x ** 2 + $z ** 2); $motion = new Vector3($this->motionX, $this->motionY, $this->motionZ); $motion->x /= 2; $motion->y /= 2; $motion->z /= 2; $motion->x += ($x / $f) * $base; $motion->y += $base; $motion->z += ($z / $f) * $base; if($motion->y > $base){ $motion->y = $base; } $this->setMotion($motion); } public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){ $this->setHealth($this->getHealth() + $amount); } public function kill(){ if($this->dead){ return; } parent::kill(); $this->server->getPluginManager()->callEvent($ev = new EntityDeathEvent($this, $this->getDrops())); foreach($ev->getDrops() as $item){ $this->getLevel()->dropItem($this, $item); } } public function entityBaseTick($tickDiff = 1){ Timings::$timerEntityBaseTick->startTiming(); if($this->dead === true){ ++$this->deadTicks; if($this->deadTicks >= 10){ $this->despawnFromAll(); if(!($this instanceof Player)){ $this->close(); } } Timings::$timerEntityBaseTick->stopTiming(); return $this->deadTicks < 10; } parent::entityBaseTick($tickDiff); if($this->dead !== true and $this->isInsideOfSolid()){ $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 1); $this->attack($ev->getFinalDamage(), $ev); } if($this->dead !== true and $this->isInsideOfWater()){ $this->airTicks -= $tickDiff; if($this->airTicks <= -20){ $this->airTicks = 0; $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_DROWNING, 2); $this->attack($ev->getFinalDamage(), $ev); } }else{ $this->airTicks = 300; } if($this->attackTime > 0){ $this->attackTime -= $tickDiff; } Timings::$timerEntityBaseTick->stopTiming(); } /** * @return ItemItem[] */ public function getDrops(){ return []; } /** * @param int $maxDistance * @param int $maxLength * @param array $transparent * * @return Block[] */ public function getLineOfSight($maxDistance, $maxLength = 0, array $transparent = []){ if($maxDistance > 120){ $maxDistance = 120; } if(count($transparent) === 0){ $transparent = null; } $blocks = []; $nextIndex = 0; $itr = new BlockIterator($this->level, $this->getPosition(), $this->getDirectionVector(), $this->getEyeHeight(), $maxDistance); while($itr->valid()){ $itr->next(); $block = $itr->current(); $blocks[$nextIndex++] = $block; if($maxLength !== 0 and count($blocks) > $maxLength){ array_shift($blocks); --$nextIndex; } $id = $block->getId(); if($transparent === null){ if($id !== 0){ break; } }else{ if(!isset($transparent[$id])){ break; } } } return $blocks; } /** * @param int $maxDistance * @param array $transparent * * @return Block */ public function getTargetBlock($maxDistance, array $transparent = []){ try{ $block = $this->getLineOfSight($maxDistance, 1, $transparent)[0]; if($block instanceof Block){ return $block; } }catch (\ArrayOutOfBoundsException $e){ } return null; } }