If this class is modified, remember to modify the PHP C extension.
Beispiel #1
2
 private function getOptimalFlowDirections()
 {
     if ($this->temporalVector === \null) {
         $this->temporalVector = new Vector3(0, 0, 0);
     }
     for ($j = 0; $j < 4; ++$j) {
         $this->flowCost[$j] = 1000;
         $x = $this->x;
         $y = $this->y;
         $z = $this->z;
         if ($j === 0) {
             --$x;
         } elseif ($j === 1) {
             ++$x;
         } elseif ($j === 2) {
             --$z;
         } elseif ($j === 3) {
             ++$z;
         }
         $block = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
         if (!$block->canBeFlowedInto() and !$block instanceof Liquid) {
             continue;
         } elseif ($block instanceof Liquid and $block->getDamage() === 0) {
             continue;
         } elseif ($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()) {
             $this->flowCost[$j] = 0;
         } else {
             $this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j);
         }
     }
     $minCost = $this->flowCost[0];
     for ($i = 1; $i < 4; ++$i) {
         if ($this->flowCost[$i] < $minCost) {
             $minCost = $this->flowCost[$i];
         }
     }
     for ($i = 0; $i < 4; ++$i) {
         $this->isOptimalFlowDirection[$i] = $this->flowCost[$i] === $minCost;
     }
     return $this->isOptimalFlowDirection;
 }
Beispiel #2
0
 public function isInside(Vector3 $v)
 {
     if (!$this->isValid()) {
         return false;
     }
     return min($this->x1, $this->x2) <= $v->x and min($this->y1, $this->y2) <= $v->y and min($this->z1, $this->z2) <= $v->z and max($this->x1, $this->x2) >= $v->x and max($this->y1, $this->y2) >= $v->y and max($this->z1, $this->z2) >= $v->z and !$v instanceof Position or $v->getLevel()->getName() === $this->levelName;
 }
Beispiel #3
0
 public function calcWeather($currentTick)
 {
     if ($this->canCalculate()) {
         $tickDiff = $currentTick - $this->lastUpdate;
         $this->duration -= $tickDiff;
         if ($this->duration <= 0) {
             $duration = mt_rand(min($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax), max($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax));
             if ($this->weatherNow === self::SUNNY) {
                 $weather = $this->randomWeatherData[array_rand($this->randomWeatherData)];
                 $this->setWeather($weather, $duration);
             } else {
                 $weather = self::SUNNY;
                 $this->setWeather($weather, $duration);
             }
         }
         if ($this->weatherNow > 0 and $this->level->getServer()->lightningTime > 0 and is_int($this->duration / $this->level->getServer()->lightningTime)) {
             $players = $this->level->getPlayers();
             if (count($players) > 0) {
                 $p = $players[array_rand($players)];
                 $x = $p->x + mt_rand(-64, 64);
                 $z = $p->z + mt_rand(-64, 64);
                 $y = $this->level->getHighestBlockAt($x, $z);
                 $this->level->spawnLightning($this->temporalVector->setComponents($x, $y, $z));
             }
         }
     }
     $this->lastUpdate = $currentTick;
 }
 /**
  * @param Vector3 $v
  * @param mixed $data
  * @param int $id
  * @param FullChunk $chunk
  */
 public function __construct($v, $data, $id = -2, $chunk = null)
 {
     $this->data = $data;
     if (!$v instanceof Vector3) {
         if ($v instanceof FullChunk) {
             $v->removeEntity($this);
         }
         throw new \RuntimeException("BadConstructCustomHuman");
     }
     $nbt = new Compound();
     $nbt->Pos = new Enum("Motion", [new Double(0, $v->x), new Double(1, $v->y), new Double(2, $v->z)]);
     $nbt->Motion = new Enum("Motion", [new Double(0, 0), new Double(1, 0), new Double(2, 0)]);
     $nbt->Rotation = new Enum("Rotation", [new Float(0, $this->getDefaultYaw()), new Float(1, $this->getDefaultPitch())]);
     $nbt->FallDistance = new Float("FallDistance", 0);
     $nbt->Fire = new Short("Fire", 0);
     $nbt->Air = new Short("Air", 0);
     $nbt->OnGround = new Byte("OnGround", 1);
     $nbt->Invulnerable = new Byte("Invulnerable", 1);
     $nbt->Health = new Short("Health", 20);
     $nbt->NameTag = $this->getDefaultName();
     $nbt->Inventory = new Enum("Inventory", []);
     $nbt->Inventory->setTagType(NBT::TAG_Compound);
     $this->inventory = new PlayerInventory($this);
     $this->setSkin($this->getDefaultSkin());
     parent::__construct($chunk, $nbt);
 }
 public function isInside(Vector3 $v)
 {
     $out = true;
     $out = ($out and $v->distance($this->centre) <= $this->radius);
     if ($v instanceof Position) {
         $out = ($out and $v->getLevel()->getName() === $this->centre->getLevel()->getName());
     }
     return $out;
 }
Beispiel #6
0
 public function isInside(Vector3 $v)
 {
     if (!$this->isValid()) {
         return false;
     }
     if ($v instanceof Position and $v->getLevel()->getName() !== $this->levelName) {
         return false;
     }
     return $v->distanceSquared($this->center) <= $this->radiusSquared;
 }
Beispiel #7
0
 public function onUpdate($currentTick)
 {
     if ($this->closed !== false) {
         return false;
     }
     if (++$this->switchDirectionTicker === 100) {
         $this->switchDirectionTicker = 0;
         if (mt_rand(0, 100) < 50) {
             $this->swimDirection = null;
         }
     }
     $this->lastUpdate = $currentTick;
     $this->timings->startTiming();
     $hasUpdate = parent::onUpdate($currentTick);
     if ($this->isAlive()) {
         if ($this->y > 62 and $this->swimDirection !== null) {
             $this->swimDirection->y = -0.5;
         }
         /*$inWater = $this->isInsideOfAir();
         		if(!$inWater){
         			//$this->motionY -= $this->gravity;
         			$this->swimDirection = null;
         		}else*/
         if ($this->swimDirection !== null) {
             if ($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2 <= $this->swimDirection->lengthSquared()) {
                 $this->motionX = $this->swimDirection->x * $this->swimSpeed;
                 $this->motionY = $this->swimDirection->y * $this->swimSpeed;
                 $this->motionZ = $this->swimDirection->z * $this->swimSpeed;
             }
         } else {
             $this->swimDirection = $this->generateRandomDirection();
             $this->swimSpeed = mt_rand(50, 100);
         }
         $expectedPos = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ);
         $this->move($this->motionX, $this->motionY, $this->motionZ);
         if ($expectedPos->distanceSquared($this) > 0) {
             $this->swimDirection = $this->generateRandomDirection();
             $this->swimSpeed = mt_rand(50, 100);
         }
         $friction = 1 - $this->drag;
         $this->motionX *= $friction;
         $this->motionY *= 1 - $this->drag;
         $this->motionZ *= $friction;
         $f = sqrt($this->motionX ** 2 + $this->motionZ ** 2);
         $this->yaw = -atan2($this->motionX, $this->motionZ) * 180 / M_PI;
         $this->pitch = -atan2($f, $this->motionY) * 180 / M_PI;
         if ($this->onGround) {
             $this->motionY *= -0.5;
         }
         $this->updateMovement();
     }
     $this->timings->stopTiming();
     return $hasUpdate or !$this->onGround or abs($this->motionX) > 1.0E-5 or abs($this->motionY) > 1.0E-5 or abs($this->motionZ) > 1.0E-5;
 }
 /**
  * Checks whether the passed {@link Vector3} is included in this {@link Space}.<br>
  * Floating point vectors are accepted.<br>
  * <br>
  * The contents of this function are based on <a
  * href="http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html">Wolfram|MathWorld: Point-Lne Distance
  * (3-Dimensional)</a>, whereas {@code X0 = $v, X1 = $this->baseCenter, X2 = $this->topCenter}.
  *
  * @param Vector3 $v the coordinates to check.
  *
  * @return bool whether <code> $v</code> is inside the space.
  */
 public function isInside(Vector3 $v)
 {
     if (!$this->isValid()) {
         return false;
     }
     if ($v instanceof Position and $v->getLevel()->getName() !== $this->levelName) {
         return false;
     }
     $distSquared = $v->subtract($this->baseCenter)->cross($v->subtract($this->topCenter))->lengthSquared() / $this->topCenter->subtract($this->baseCenter)->lengthSquared();
     // |---|
     return $distSquared <= $this->radiusSquared;
     // |(X0 - X1) x (X0 - X2)| / |X2 - X1|
 }
Beispiel #9
0
 public static function createEffectArrow(Player $player, Vector3 $position, Vector3 $speed, $yaw, $pitch, $r, $g, $b, $critical)
 {
     $nbtTag = new Compound("", ["Pos" => new Enum("Pos", [new Double("", $position->getX()), new Double("", $position->getY()), new Double("", $position->getZ())]), "Rotation" => new Enum("Rotation", [new Float("", $yaw), new Float("", $pitch)])]);
     $arrow = new EffectArrow($player->chunk, $nbtTag, $r, $g, $b, $player, $critical);
     $arrow->setMotion($speed);
     $launchEvent = new ProjectileLaunchEvent($arrow);
     Server::getInstance()->getPluginManager()->callEvent($launchEvent);
     if ($launchEvent->isCancelled()) {
         $arrow->kill();
         return null;
     } else {
         return $arrow;
     }
 }
Beispiel #10
0
 public function onPlayerInteract(PlayerInteractEvent $e)
 {
     // Implement the CompassTP thingie...
     $pl = $e->getPlayer();
     if (!$pl->hasPermission("toybox.compasstp")) {
         return;
     }
     $hand = $pl->getInventory()->getItemInHand();
     if ($hand->getID() != $this->item) {
         return;
     }
     $pos = $pl->getPosition()->add(0, $pl->getEyeHeight(), 0);
     $start = new Vector3($pos->getX(), $pos->getY(), $pos->getZ());
     $lv = $pl->getLevel();
     for ($start = new Vector3($pos->getX(), $pos->getY(), $pos->getZ()); $start->distance($pos) < 120; $pos = $pos->add($pl->getDirectionVector())) {
         $block = $lv->getBlock($pos->floor());
         if ($block->getId() != 0) {
             break;
         }
     }
     if ($block->getId() == 0) {
         $pl->sendMessage(mc::_("Can not teleport to the void!"));
         return;
     }
     $pos = $pos->subtract($pl->getDirectionVector());
     $dist = $start->distance($pos);
     if ($dist < 2.8) {
         $pl->sendMessage(mc::_("Not teleporting..."));
         $pl->sendMessage(mc::_("You could easily walk there!"));
         return;
     }
     //echo "Block: ".$block->getName()." (".$block->getId().")\n";
     //print_r($pos);
     //echo "Distance: ".$start->distance($pos)."\n";
     $pl->sendMessage(mc::_("Teleporting... %1%", intval($dist)));
     $pos = $pos->add(0, 1, 0);
     /*$cb = new CallbackTask([$this,"delayedTP"],[$pl->getName(),
       $pos->getX(),
       $pos->getY(),
       $pos->getZ()]);
       $this->owner->getServer()->getScheduler()->scheduleDelayedTask($cb,20);
       //$pl->teleport($pos);
       return;*/
     $m = 5.0;
     for ($f = 1.0; $f <= $m; $f++) {
         $ticks = intval($f) * 5;
         $x = ($pos->getX() - $start->getX()) * $f / $m + $start->getX();
         $y = ($pos->getY() - $start->getY()) * $f / $m + $start->getY();
         $z = ($pos->getZ() - $start->getZ()) * $f / $m + $start->getZ();
         $c = new PluginCallbackTask($this->owner, [$this, "delayedTP"], [$pl->getName(), $x, $y, $z]);
         $this->owner->getServer()->getScheduler()->scheduleDelayedTask($c, $ticks);
     }
 }
Beispiel #11
0
 public function onUpdate($type)
 {
     if ($type === Level::BLOCK_UPDATE_NORMAL) {
         $faces = array_flip(array(2 => 2, 3 => 4, 4 => 5, 5 => 3));
         if ($this->getSide(Vector3::getOppositeSide($faces[$this->meta % 4 + 2]))->isTransparent() === true) {
             $this->getLevel()->useBreakOn($this);
             return Level::BLOCK_UPDATE_NORMAL;
         }
     } elseif ($type === Level::BLOCK_UPDATE_RANDOM) {
         if (mt_rand(0, 2) === 1) {
             if ($this->meta < 8) {
                 $block = clone $this;
                 $block->meta += 4;
                 Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
                 if (!$ev->isCancelled()) {
                     $this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
                 } else {
                     return Level::BLOCK_UPDATE_RANDOM;
                 }
             }
         } else {
             return Level::BLOCK_UPDATE_RANDOM;
         }
     }
     return false;
 }
 public function __construct($x, $y, $z, $id, $class, $data)
 {
     parent::__construct($x, $y, $z);
     $this->id = $id;
     $this->class = $class;
     $this->data = $data;
 }
Beispiel #13
0
 public function onUpdate($currentTick)
 {
     if ($this->closed !== false) {
         return false;
     }
     $this->lastUpdate = $currentTick;
     $this->timings->startTiming();
     $hasUpdate = true;
     //parent::onUpdate($currentTick);
     if ($this->isAlive()) {
         $expectedPos = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ);
         $expBlock0 = $this->getLevel()->getBlock($expectedPos->add(0, -1, 0)->round());
         $expBlock1 = $this->getLevel()->getBlock($expectedPos->add(0, 0, 0)->round());
         if ($expBlock0->getId() == 0) {
             $this->motionY -= $this->gravity;
             //重力计算
             $this->motionX = 0;
             $this->motionZ = 0;
         } else {
             $this->motionY = 0;
         }
         if ($expBlock1->getId() != 0) {
             $this->motionY += 0.1;
         }
         $this->move($this->motionX, $this->motionY, $this->motionZ);
         if ($this->isFreeMoving) {
             $this->motionX = 0;
             $this->motionZ = 0;
             $this->isFreeMoving = false;
         }
         /*$friction = 1 - $this->drag;
         
         			$this->motionX *= $friction;
         			$this->motionY *= 1 - $this->drag;
         			$this->motionZ *= $friction;*/
         $f = sqrt($this->motionX ** 2 + $this->motionZ ** 2);
         $this->yaw = -atan2($this->motionX, $this->motionZ) * 180 / M_PI;
         //视角计算
         //$this->pitch = (-atan2($f, $this->motionY) * 180 / M_PI);
         $this->updateMovement();
     }
     $this->timings->stopTiming();
     return $hasUpdate or !$this->onGround or abs($this->motionX) > 1.0E-5 or abs($this->motionY) > 1.0E-5 or abs($this->motionZ) > 1.0E-5;
 }
 public function __construct($x, $y, $z, $nameTag, $yaw, $pitch, Item $item, $skin, $slim = false)
 {
     parent::__construct($x, $y, $z);
     $this->nameTag = $nameTag;
     $this->yaw = $yaw;
     $this->pitch = $pitch;
     $this->item = $item;
     $this->skin = $skin;
     $this->slim = $slim;
     $this->metadata = [Entity::DATA_FLAGS => [Entity::DATA_TYPE_BYTE, 0], Entity::DATA_AIR => [Entity::DATA_TYPE_SHORT, 300], Entity::DATA_NAMETAG => [Entity::DATA_TYPE_STRING, $this->nameTag], Entity::DATA_SHOW_NAMETAG => [Entity::DATA_TYPE_BYTE, 1], Entity::DATA_SILENT => [Entity::DATA_TYPE_BYTE, 1], Entity::DATA_NO_AI => [Entity::DATA_TYPE_BYTE, 1]];
 }
Beispiel #15
0
 public function __construct(Level $level, Vector3 $pos)
 {
     if (!($pos instanceof Vector3 && $level instanceof Level)) {
         echo "this is not Floor!\n";
     }
     $this->vector = $pos;
     $this->x = $pos->getX();
     $this->y = $pos->getY();
     $this->z = $pos->getZ();
     $this->level = $level;
     $this->block = $level->getBlock($pos);
     $this->id = $this->block->getId();
     $this->data = $this->block->getDamage();
     $this->height = 128;
     //$this->level->getHeightMap($this->x, $this->z);
     echo "max height: {$this->height}\n";
     if (!($this->isElevatorBlock($this->block) || $this->isExtensionFloorBlock($this->block))) {
         echo "THIS IS NOT FLOOR!\n";
     }
 }
 public function calcWeather($currentTick)
 {
     if ($this->canCalculate()) {
         $tickDiff = $currentTick - $this->lastUpdate;
         $this->duration -= $tickDiff;
         if ($this->duration <= 0) {
             //0晴天1下雨2雷雨3阴天雷
             if ($this->weatherNow == self::SUNNY) {
                 $weather = $this->randomWeatherData[array_rand($this->randomWeatherData)];
                 $duration = mt_rand(min($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax), max($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax));
                 $this->level->getServer()->getPluginManager()->callEvent($ev = new WeatherChangeEvent($this->level, $weather, $duration));
                 if (!$ev->isCancelled()) {
                     $this->weatherNow = $ev->getWeather();
                     $this->strength1 = mt_rand(90000, 110000);
                     $this->strength2 = mt_rand(30000, 40000);
                     $this->duration = $ev->getDuration();
                     $this->changeWeather($this->weatherNow, $this->strength1, $this->strength2);
                 }
             } else {
                 $weather = self::SUNNY;
                 $duration = mt_rand(min($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax), max($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax));
                 $this->level->getServer()->getPluginManager()->callEvent($ev = new WeatherChangeEvent($this->level, $weather, $duration));
                 if (!$ev->isCancelled()) {
                     $this->weatherNow = $ev->getWeather();
                     $this->strength1 = 0;
                     $this->strength2 = 0;
                     $this->duration = $ev->getDuration();
                     $this->changeWeather($this->weatherNow, $this->strength1, $this->strength2);
                 }
             }
         }
         if ($this->weatherNow > 0 and $this->level->getServer()->lightningTime > 0 and is_int($this->duration / $this->level->getServer()->lightningTime)) {
             $players = $this->level->getPlayers();
             if (count($players) > 0) {
                 $p = $players[array_rand($players)];
                 $x = $p->x + mt_rand(-64, 64);
                 $z = $p->z + mt_rand(-64, 64);
                 $y = $this->level->getHighestBlockAt($x, $z);
                 $this->level->spawnLightning($this->temporalVector->setComponents($x, $y, $z));
             }
             /*foreach($this->level->getPlayers() as $p){
             			if(mt_rand(0, 1) == 1){
             				$x = $p->getX() + rand(-100, 100);
             				$y = $p->getY() + rand(20, 50);
             				$z = $p->getZ() + rand(-100, 100);
             				$this->level->sendLighting($x, $y, $z, $p);
             			}
             		}*/
         }
     }
     $this->lastUpdate = $currentTick;
 }
Beispiel #17
0
 public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null)
 {
     if ($face !== 0 && $face !== 1) {
         $faces = [3 => 3, 2 => 4, 4 => 2, 5 => 1];
         $this->meta = $faces[$face];
         if ($this->getSide(Vector3::getOppositeSide($face))->getId() === Block::TRIPWIRE) {
             $this->meta & 0x1;
         }
         $this->getLevel()->setBlock($block, Block::get(Block::TRIPWIRE_HOOK, $this->meta), true);
         return true;
     }
     return false;
 }
Beispiel #18
0
 public function onBreak(Item $item)
 {
     $sound = new EndermanTeleportSound($this);
     $this->getLevel()->addSound($sound);
     $particle = new PortalParticle($this);
     $this->getLevel()->addParticle($particle);
     $block = $this;
     //$this->getLevel()->setBlock($block, new Block(Block::PORTAL, 0));//在破坏处放置一个方块防止计算出错
     if ($this->getLevel()->getBlock($this->temporalVector->setComponents($block->x - 1, $block->y, $block->z))->getId() == Block::PORTAL or $this->getLevel()->getBlock($this->temporalVector->setComponents($block->x + 1, $block->y, $block->z))->getId() == Block::PORTAL) {
         //x方向
         for ($x = $block->x; $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $block->y, $block->z))->getId() == Block::PORTAL; $x++) {
             for ($y = $block->y; $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $block->z))->getId() == Block::PORTAL; $y++) {
                 $this->getLevel()->setBlock($this->temporalVector->setComponents($x, $y, $block->z), new Air());
             }
             for ($y = $block->y - 1; $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $block->z))->getId() == Block::PORTAL; $y--) {
                 $this->getLevel()->setBlock($this->temporalVector->setComponents($x, $y, $block->z), new Air());
             }
         }
         for ($x = $block->x - 1; $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $block->y, $block->z))->getId() == Block::PORTAL; $x--) {
             for ($y = $block->y; $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $block->z))->getId() == Block::PORTAL; $y++) {
                 $this->getLevel()->setBlock($this->temporalVector->setComponents($x, $y, $block->z), new Air());
             }
             for ($y = $block->y - 1; $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $block->z))->getId() == Block::PORTAL; $y--) {
                 $this->getLevel()->setBlock($this->temporalVector->setComponents($x, $y, $block->z), new Air());
             }
         }
     } else {
         //z方向
         for ($z = $block->z; $this->getLevel()->getBlock($this->temporalVector->setComponents($block->x, $block->y, $z))->getId() == Block::PORTAL; $z++) {
             for ($y = $block->y; $this->getLevel()->getBlock($this->temporalVector->setComponents($block->x, $y, $z))->getId() == Block::PORTAL; $y++) {
                 $this->getLevel()->setBlock($this->temporalVector->setComponents($block->x, $y, $z), new Air());
             }
             for ($y = $block->y - 1; $this->getLevel()->getBlock($this->temporalVector->setComponents($block->x, $y, $z))->getId() == Block::PORTAL; $y--) {
                 $this->getLevel()->setBlock($this->temporalVector->setComponents($block->x, $y, $z), new Air());
             }
         }
         for ($z = $block->z - 1; $this->getLevel()->getBlock($this->temporalVector->setComponents($block->x, $block->y, $z))->getId() == Block::PORTAL; $z--) {
             for ($y = $block->y; $this->getLevel()->getBlock($this->temporalVector->setComponents($block->x, $y, $z))->getId() == Block::PORTAL; $y++) {
                 $this->getLevel()->setBlock($this->temporalVector->setComponents($block->x, $y, $z), new Air());
             }
             for ($y = $block->y - 1; $this->getLevel()->getBlock($this->temporalVector->setComponents($block->x, $y, $z))->getId() == Block::PORTAL; $y--) {
                 $this->getLevel()->setBlock($this->temporalVector->setComponents($block->x, $y, $z), new Air());
             }
         }
     }
     parent::onBreak($item);
 }
Beispiel #19
0
 /**
  * @return bool
  */
 public function explodeA()
 {
     if ($this->size < 0.1) {
         return false;
     }
     $vector = new Vector3(0, 0, 0);
     $vBlock = new Vector3(0, 0, 0);
     $mRays = intval($this->rays - 1);
     for ($i = 0; $i < $this->rays; ++$i) {
         for ($j = 0; $j < $this->rays; ++$j) {
             for ($k = 0; $k < $this->rays; ++$k) {
                 if ($i === 0 or $i === $mRays or $j === 0 or $j === $mRays or $k === 0 or $k === $mRays) {
                     $vector->setComponents($i / $mRays * 2 - 1, $j / $mRays * 2 - 1, $k / $mRays * 2 - 1);
                     $vector->setComponents($vector->x / ($len = $vector->length()) * $this->stepLen, $vector->y / $len * $this->stepLen, $vector->z / $len * $this->stepLen);
                     $pointerX = $this->source->x;
                     $pointerY = $this->source->y;
                     $pointerZ = $this->source->z;
                     for ($blastForce = $this->size * (mt_rand(700, 1300) / 1000); $blastForce > 0; $blastForce -= $this->stepLen * 0.75) {
                         $x = (int) $pointerX;
                         $y = (int) $pointerY;
                         $z = (int) $pointerZ;
                         $vBlock->x = $pointerX >= $x ? $x : $x - 1;
                         $vBlock->y = $pointerY >= $y ? $y : $y - 1;
                         $vBlock->z = $pointerZ >= $z ? $z : $z - 1;
                         if ($vBlock->y < 0 or $vBlock->y > 127) {
                             break;
                         }
                         $block = $this->level->getBlock($vBlock);
                         if ($block->getId() !== 0) {
                             $blastForce -= ($block->getHardness() / 5 + 0.3) * $this->stepLen;
                             if ($blastForce > 0) {
                                 if (!isset($this->affectedBlocks[$index = PHP_INT_SIZE === 8 ? ($block->x & 0xfffffff) << 35 | ($block->y & 0x7f) << 28 | $block->z & 0xfffffff : $block->x . ":" . $block->y . ":" . $block->z])) {
                                     $this->affectedBlocks[$index] = $block;
                                 }
                             }
                         }
                         $pointerX += $vector->x;
                         $pointerY += $vector->y;
                         $pointerZ += $vector->z;
                     }
                 }
             }
         }
     }
     return true;
 }
 public function onUpdate($currentTick)
 {
     if ($this->closed !== false) {
         return false;
     }
     if ($this->getLevel()->getServer()->aiConfig["zombie"] != 2) {
         return parent::onUpdate($currentTick);
     }
     $this->lastUpdate = $currentTick;
     $this->timings->startTiming();
     $hasUpdate = parent::onUpdate($currentTick);
     if ($this->isAlive()) {
         /* Don't use time directly
          * Instead, get remainder of current time divided by 24,000
          * This tells us the time of day, which is what we really need
          */
         $timeOfDay = abs($this->getLevel()->getTime() % 24000);
         if (0 < $timeOfDay and $timeOfDay < 13000) {
             $this->setOnFire(2);
         }
         //僵尸起火
         $p = $this->getNearestPlayer();
         //找到最近的可以被仇恨的玩家
         if (!$p) {
             $this->hated = false;
             if (++$this->moveTicker >= 100) {
                 $this->moveDirection = $this->generateRandomDirection();
                 $this->moveTicker = 0;
             }
         } else {
             $this->hated = $p;
             if ($p->distance($this) <= $this->fire_r) {
                 $p->setOnFire(2);
             }
             //点燃玩家
             if (!$this->tempTicking) {
                 if (++$this->hateTicker >= 10 or $this->moveDirection == null) {
                     //每0.5秒获取僵尸前进的新方向
                     $this->moveDirection = $this->generateDirection($p);
                     $this->hateTicker = 0;
                 }
             }
         }
         if ($this->tempTicking) {
             //帮助僵尸寻找新的方向走出困境
             if (++$this->tempTicker >= 20) {
                 $this->tempTicking = false;
                 $this->tempTicker = 0;
             }
         }
         if ($this->hated instanceof Player) {
             //攻击玩家
             if ($this->hated->distance($this) < $this->attack_r) {
                 $this->hated->attack(2, new EntityDamageByEntityEvent($this, $this->hated, EntityDamageEvent::CAUSE_ENTITY_ATTACK, 2));
             }
         }
         if ($this->moveDirection != null) {
             if ($this->motionX ** 2 + $this->motionZ ** 2 <= $this->moveDirection->lengthSquared()) {
                 $motionY = $this->getVelY();
                 //僵尸运动计算
                 if ($motionY >= 0) {
                     $this->motionX = $this->moveDirection->x * $this->moveSpeed;
                     $this->motionZ = $this->moveDirection->z * $this->moveSpeed;
                     $this->motionY = $motionY;
                 } else {
                     $this->moveDirection = $this->generateRandomDirection();
                     //生成随机运动方向
                     $this->moveTicker = 0;
                     $this->tempTicking = true;
                 }
             }
         } else {
             $this->moveDirection = $this->generateRandomDirection();
             $this->moveTicker = 0;
         }
         //var_dump($this->moveDirection,$this->motionX,$this->motionZ);
         $expectedPos = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ);
         if ($this->motionY == 0) {
             $this->motionY -= $this->gravity;
         }
         //重力计算
         $this->move($this->motionX, $this->motionY, $this->motionZ);
         if ($expectedPos->distanceSquared($this) > 0) {
             $this->moveDirection = $this->generateRandomDirection();
         }
         $friction = 1 - $this->drag;
         $this->motionX *= $friction;
         //$this->motionY *= 1 - $this->drag;
         $this->motionZ *= $friction;
         $f = sqrt($this->motionX ** 2 + $this->motionZ ** 2);
         $this->yaw = -atan2($this->motionX, $this->motionZ) * 180 / M_PI;
         //视角计算
         //$this->pitch = (-atan2($f, $this->motionY) * 180 / M_PI);
         $this->updateMovement();
     }
     $this->timings->stopTiming();
     return $hasUpdate or !$this->onGround or abs($this->motionX) > 1.0E-5 or abs($this->motionY) > 1.0E-5 or abs($this->motionZ) > 1.0E-5;
 }
Beispiel #21
0
 public function __construct(Level $level, Vector3 $start, Vector3 $direction, $yOffset = 0, $maxDistance = 0)
 {
     $this->level = $level;
     $this->maxDistance = (int) $maxDistance;
     $this->blockQueue = new \SplFixedArray(3);
     $startClone = new Vector3($start->x, $start->y, $start->z);
     $startClone->y += $yOffset;
     $this->currentDistance = 0;
     $mainDirection = 0;
     $secondDirection = 0;
     $thirdDirection = 0;
     $mainPosition = 0;
     $secondPosition = 0;
     $thirdPosition = 0;
     $pos = new Vector3($startClone->x, $startClone->y, $startClone->z);
     $startBlock = $this->level->getBlock(new Vector3(floor($pos->x), floor($pos->y), floor($pos->z)));
     if ($this->getXLength($direction) > $mainDirection) {
         $this->mainFace = $this->getXFace($direction);
         $mainDirection = $this->getXLength($direction);
         $mainPosition = $this->getXPosition($direction, $startClone, $startBlock);
         $this->secondFace = $this->getYFace($direction);
         $secondDirection = $this->getYLength($direction);
         $secondPosition = $this->getYPosition($direction, $startClone, $startBlock);
         $this->thirdFace = $this->getZFace($direction);
         $thirdDirection = $this->getZLength($direction);
         $thirdPosition = $this->getZPosition($direction, $startClone, $startBlock);
     }
     if ($this->getYLength($direction) > $mainDirection) {
         $this->mainFace = $this->getYFace($direction);
         $mainDirection = $this->getYLength($direction);
         $mainPosition = $this->getYPosition($direction, $startClone, $startBlock);
         $this->secondFace = $this->getZFace($direction);
         $secondDirection = $this->getZLength($direction);
         $secondPosition = $this->getZPosition($direction, $startClone, $startBlock);
         $this->thirdFace = $this->getXFace($direction);
         $thirdDirection = $this->getXLength($direction);
         $thirdPosition = $this->getXPosition($direction, $startClone, $startBlock);
     }
     if ($this->getZLength($direction) > $mainDirection) {
         $this->mainFace = $this->getZFace($direction);
         $mainDirection = $this->getZLength($direction);
         $mainPosition = $this->getZPosition($direction, $startClone, $startBlock);
         $this->secondFace = $this->getXFace($direction);
         $secondDirection = $this->getXLength($direction);
         $secondPosition = $this->getXPosition($direction, $startClone, $startBlock);
         $this->thirdFace = $this->getYFace($direction);
         $thirdDirection = $this->getYLength($direction);
         $thirdPosition = $this->getYPosition($direction, $startClone, $startBlock);
     }
     $d = $mainPosition / $mainDirection;
     $secondd = $secondPosition - $secondDirection * $d;
     $thirdd = $thirdPosition - $thirdDirection * $d;
     $this->secondError = floor($secondd * self::$gridSize);
     $this->secondStep = round($secondDirection / $mainDirection * self::$gridSize);
     $this->thirdError = floor($thirdd * self::$gridSize);
     $this->thirdStep = round($thirdDirection / $mainDirection * self::$gridSize);
     if ($this->secondError + $this->secondStep <= 0) {
         $this->secondError = -$this->secondStep + 1;
     }
     if ($this->thirdError + $this->thirdStep <= 0) {
         $this->thirdError = -$this->thirdStep + 1;
     }
     $lastBlock = $startBlock->getSide(Vector3::getOppositeSide($this->mainFace));
     if ($this->secondError < 0) {
         $this->secondError += self::$gridSize;
         $lastBlock = $lastBlock->getSide(Vector3::getOppositeSide($this->secondFace));
     }
     if ($this->thirdError < 0) {
         $this->thirdError += self::$gridSize;
         $lastBlock = $lastBlock->getSide(Vector3::getOppositeSide($this->thirdFace));
     }
     $this->secondError -= self::$gridSize;
     $this->thirdError -= self::$gridSize;
     $this->blockQueue[0] = $lastBlock;
     $this->currentBlock = -1;
     $this->scan();
     $startBlockFound = false;
     for ($cnt = $this->currentBlock; $cnt >= 0; --$cnt) {
         if ($this->blockEquals($this->blockQueue[$cnt], $startBlock)) {
             $this->currentBlock = $cnt;
             $startBlockFound = true;
             break;
         }
     }
     if (!$startBlockFound) {
         throw new \InvalidStateException("Start block missed in BlockIterator");
     }
     $this->maxDistanceInt = round($maxDistance / (sqrt($mainDirection ** 2 + $secondDirection ** 2 + $thirdDirection ** 2) / $mainDirection));
 }
Beispiel #22
0
 /**
  * Returns a side Vector
  *
  * @param int $side
  * @param int $step
  *
  * @return Position
  *
  * @throws LevelException
  */
 public function getSide($side, $step = 1)
 {
     if (!$this->isValid()) {
         throw new LevelException("Undefined Level reference");
     }
     return Position::fromObject(parent::getSide($side, $step), $this->level);
 }
Beispiel #23
0
 /**
  * Zombie initialization routine and freely walking mode cycle timer
  * Timer:20 ticks
  */
 public function ZombieRandomWalkCalc()
 {
     $this->dif = Server::getInstance()->getDifficulty();
     //$this->getLogger()->info(count($this->plugin->zombie));
     $zo = $this->entity;
     if ($this->willMove()) {
         if (!isset($this->data)) {
             $this->data = array('ID' => $zo->getId(), 'IsChasing' => false, 'motionx' => 0, 'motiony' => 0, 'motionz' => 0, 'hurt' => 10, 'time' => 10, 'x' => 0, 'y' => 0, 'z' => 0, 'oldv3' => $zo->getLocation(), 'yup' => 20, 'up' => 0, 'yaw' => $zo->yaw, 'pitch' => 0, 'level' => $zo->getLevel()->getName(), 'xxx' => 0, 'zzz' => 0, 'gotimer' => 10, 'swim' => 0, 'jump' => 0.01, 'canjump' => true, 'drop' => false, 'canAttack' => 0, 'knockBack' => false);
             $zom =& $this->data;
             $zom['x'] = $zo->getX();
             $zom['y'] = $zo->getY();
             $zom['z'] = $zo->getZ();
         }
         $zom =& $this->data;
         if ($zom['IsChasing'] === false) {
             //Walk mode
             if ($zom['gotimer'] == 0 or $zom['gotimer'] == 10) {
                 //Limit rotation rate
                 $newmx = mt_rand(-5, 5) / 10;
                 while (abs($newmx - $zom['motionx']) >= 0.7) {
                     $newmx = mt_rand(-5, 5) / 10;
                 }
                 $zom['motionx'] = $newmx;
                 $newmz = mt_rand(-5, 5) / 10;
                 while (abs($newmz - $zom['motionz']) >= 0.7) {
                     $newmz = mt_rand(-5, 5) / 10;
                 }
                 $zom['motionz'] = $newmz;
             } elseif ($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24) {
                 $zom['motionx'] = 0;
                 $zom['motionz'] = 0;
                 //Zombie stop
             }
             $zom['gotimer'] += 0.5;
             if ($zom['gotimer'] >= 22) {
                 $zom['gotimer'] = 0;
             }
             //Reset timer walk
             //$zom['motionx'] = mt_rand(-10,10)/10;
             //$zom['motionz'] = mt_rand(-10,10)/10;
             $zom['yup'] = 0;
             $zom['up'] = 0;
             //$width = $this->width;
             $pos = new Vector3($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1, $zom['z'] + $zom['motionz']);
             //目标坐标
             $zy = $this->ifjump($zo->getLevel(), $pos);
             if ($zy === false) {
                 //if can not move forward
                 $pos2 = new Vector3($zom['x'], $zom['y'], $zom['z']);
                 //Target coordinates
                 if ($this->ifjump($zo->getLevel(), $pos2) === false) {
                     //Original coordinate
                     $pos2 = new Vector3($zom['x'], $zom['y'] - 1, $zom['z']);
                     //decline
                     $zom['up'] = 1;
                     $zom['yup'] = 0;
                 } else {
                     $zom['motionx'] = -$zom['motionx'];
                     $zom['motionz'] = -$zom['motionz'];
                     //He turned 180 degrees
                     $zom['up'] = 0;
                 }
             } else {
                 $pos2 = new Vector3($zom['x'] + $zom['motionx'], $zy - 1, $zom['z'] + $zom['motionz']);
                 //Target coordinates
                 if ($pos2->y - $zom['y'] < 0) {
                     $zom['up'] = 1;
                 } else {
                     $zom['up'] = 0;
                 }
             }
             if ($zom['motionx'] == 0 and $zom['motionz'] == 0) {
                 //Zombie stop
             } else {
                 //Steering computing
                 $yaw = $this->getyaw($zom['motionx'], $zom['motionz']);
                 //$zo->setRotation($yaw,0);
                 $zom['yaw'] = $yaw;
                 $zom['pitch'] = 0;
             }
             //Update zombie coordinates
             if (!$zom['knockBack']) {
                 $zom['x'] = $pos2->getX();
                 $zom['z'] = $pos2->getZ();
                 $zom['y'] = $pos2->getY();
             }
             $zom['motiony'] = $pos2->getY() - $zo->getY();
             //echo($zo->getY()."\n");
             //var_dump($pos2);
             //var_dump($zom['motiony']);
             $zo->setPosition($pos2);
             //echo "SetPosition \n";
         }
     }
 }
Beispiel #24
0
 /**
  * @param Vector3|Position|Location $pos
  * @param float                     $yaw
  * @param float                     $pitch
  *
  * @return bool
  */
 public function teleport(Vector3 $pos, $yaw = null, $pitch = null)
 {
     if ($pos instanceof Location) {
         $yaw = $yaw === null ? $pos->yaw : $yaw;
         $pitch = $pitch === null ? $pos->pitch : $pitch;
     }
     $from = Position::fromObject($this, $this->level);
     $to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->level);
     $this->server->getPluginManager()->callEvent($ev = new EntityTeleportEvent($this, $from, $to));
     if ($ev->isCancelled()) {
         return false;
     }
     $this->ySize = 0;
     $pos = $ev->getTo();
     $this->setMotion($this->temporalVector->setComponents(0, 0, 0));
     if ($this->setPositionAndRotation($pos, $yaw === null ? $this->yaw : $yaw, $pitch === null ? $this->pitch : $pitch) !== false) {
         $this->resetFallDistance();
         $this->onGround = true;
         $this->lastX = $this->x;
         $this->lastY = $this->y;
         $this->lastZ = $this->z;
         $this->lastYaw = $this->yaw;
         $this->lastPitch = $this->pitch;
         $this->updateMovement();
         return true;
     }
     return false;
 }
Beispiel #25
0
 public function SkeletonRandomWalkCalc()
 {
     $this->dif = $this->plugin->getServer()->getDifficulty();
     //$this->getLogger()->info("僵尸数量:".count($this->plugin->Skeleton));
     foreach ($this->plugin->getServer()->getLevels() as $level) {
         foreach ($level->getEntities() as $zo) {
             if ($zo instanceof Skeleton) {
                 if ($this->plugin->willMove($zo)) {
                     if (!isset($this->plugin->Skeleton[$zo->getId()])) {
                         $this->plugin->Skeleton[$zo->getId()] = array('ID' => $zo->getId(), 'IsChasing' => false, 'motionx' => 0, 'motiony' => 0, 'motionz' => 0, 'hurt' => 10, 'time' => 10, 'x' => 0, 'y' => 0, 'z' => 0, 'oldv3' => $zo->getLocation(), 'yup' => 20, 'up' => 0, 'yaw' => $zo->yaw, 'pitch' => 0, 'level' => $zo->getLevel()->getName(), 'xxx' => 0, 'zzz' => 0, 'gotimer' => 10, 'swim' => 0, 'jump' => 0.01, 'canjump' => true, 'drop' => false, 'canAttack' => 0, 'shoot' => 20, 'knockBack' => false);
                         $zom =& $this->plugin->Skeleton[$zo->getId()];
                         $zom['x'] = $zo->getX();
                         $zom['y'] = $zo->getY();
                         $zom['z'] = $zo->getZ();
                     }
                     $zom =& $this->plugin->Skeleton[$zo->getId()];
                     if ($zom['IsChasing'] === false) {
                         //自由行走模式
                         if ($zom['gotimer'] == 0 or $zom['gotimer'] == 10) {
                             //限制转动幅度
                             $newmx = mt_rand(-5, 5) / 10;
                             while (abs($newmx - $zom['motionx']) >= 0.7) {
                                 $newmx = mt_rand(-5, 5) / 10;
                             }
                             $zom['motionx'] = $newmx;
                             $newmz = mt_rand(-5, 5) / 10;
                             while (abs($newmz - $zom['motionz']) >= 0.7) {
                                 $newmz = mt_rand(-5, 5) / 10;
                             }
                             $zom['motionz'] = $newmz;
                         } elseif ($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24) {
                             $zom['motionx'] = 0;
                             $zom['motionz'] = 0;
                             //僵尸停止
                         }
                         $zom['gotimer'] += 0.5;
                         if ($zom['gotimer'] >= 22) {
                             $zom['gotimer'] = 0;
                         }
                         //重置走路计时器
                         //$zom['motionx'] = mt_rand(-10,10)/10;
                         //$zom['motionz'] = mt_rand(-10,10)/10;
                         $zom['yup'] = 0;
                         $zom['up'] = 0;
                         //boybook的y轴判断法
                         //$width = $this->width;
                         $pos = new Vector3($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1, $zom['z'] + $zom['motionz']);
                         //目标坐标
                         $zy = $this->plugin->ifjump($zo->getLevel(), $pos);
                         if ($zy === false) {
                             //前方不可前进
                             $pos2 = new Vector3($zom['x'], $zom['y'], $zom['z']);
                             //目标坐标
                             if ($this->plugin->ifjump($zo->getLevel(), $pos2) === false) {
                                 //原坐标依然是悬空
                                 $pos2 = new Vector3($zom['x'], $zom['y'] - 1, $zom['z']);
                                 //下降
                                 $zom['up'] = 1;
                                 $zom['yup'] = 0;
                             } else {
                                 $zom['motionx'] = -$zom['motionx'];
                                 $zom['motionz'] = -$zom['motionz'];
                                 //转向180度,向身后走
                                 $zom['up'] = 0;
                             }
                         } else {
                             $pos2 = new Vector3($zom['x'] + $zom['motionx'], $zy - 1, $zom['z'] + $zom['motionz']);
                             //目标坐标
                             if ($pos2->y - $zom['y'] < 0) {
                                 $zom['up'] = 1;
                             } else {
                                 $zom['up'] = 0;
                             }
                         }
                         if ($zom['motionx'] == 0 and $zom['motionz'] == 0) {
                             //僵尸停止
                         } else {
                             //转向计算
                             $yaw = $this->plugin->getyaw($zom['motionx'], $zom['motionz']);
                             //$zo->setRotation($yaw,0);
                             $zom['yaw'] = $yaw;
                             $zom['pitch'] = 0;
                         }
                         //更新僵尸坐标
                         if (!$zom['knockBack']) {
                             $zom['x'] = $pos2->getX();
                             $zom['z'] = $pos2->getZ();
                             $zom['y'] = $pos2->getY();
                         }
                         $zom['motiony'] = $pos2->getY() - $zo->getY();
                         //echo($zo->getY()."\n");
                         //var_dump($pos2);
                         //var_dump($zom['motiony']);
                         $zo->setPosition($pos2);
                         //echo "SetPosition \n";
                     }
                 }
             }
         }
     }
 }
Beispiel #26
-1
 /**
  * @param Vector3 $source
  * @param Item    $item
  * @param Vector3 $motion
  * @param int     $delay
  */
 public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, $delay = 10)
 {
     $motion = $motion === null ? new Vector3(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1) : $motion;
     if ($item->getId() > 0 and $item->getCount() > 0) {
         $itemEntity = Entity::createEntity("Item", $this->getChunk($source->getX() >> 4, $source->getZ() >> 4), new Compound("", ["Pos" => new Enum("Pos", [new Double("", $source->getX()), new Double("", $source->getY()), new Double("", $source->getZ())]), "Motion" => new Enum("Motion", [new Double("", $motion->x), new Double("", $motion->y), new Double("", $motion->z)]), "Rotation" => new Enum("Rotation", [new Float("", lcg_value() * 360), new Float("", 0)]), "Health" => new Short("Health", 5), "Item" => new Compound("Item", ["id" => new Short("id", $item->getId()), "Damage" => new Short("Damage", $item->getDamage()), "Count" => new Byte("Count", $item->getCount())]), "PickupDelay" => new Short("PickupDelay", $delay)]));
         $itemEntity->spawnToAll();
     }
 }
Beispiel #27
-1
 /**
  * @param Level   $level
  * @param Vector3 $v3
  * @param bool    $hate
  * @param bool    $reason
  * @return bool|float|string
  * 判断某坐标是否可以行走
  * 并给出原因
  */
 public function ifjump(Level $level, Vector3 $v3, $hate = false, $reason = false)
 {
     //boybook Y轴算法核心函数
     $x = floor($v3->getX());
     $y = floor($v3->getY());
     $z = floor($v3->getZ());
     //echo ($y." ");
     if ($this->whatBlock($level, new Vector3($x, $y, $z)) == "air") {
         //echo "前方空气 ";
         if ($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "block" or new Vector3($x, $y - 1, $z) == "climb") {
             //方块
             //echo "考虑向前 ";
             if ($this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "half" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "high") {
                 //上方一格被堵住了
                 //echo "上方卡住 \n";
                 if ($reason) {
                     return 'up!';
                 }
                 return false;
                 //上方卡住
             } else {
                 //echo "GO向前走 \n";
                 if ($reason) {
                     return 'GO';
                 }
                 return $y;
                 //向前走
             }
         } elseif ($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "half") {
             //半砖
             //echo "下到半砖 \n";
             if ($reason) {
                 return 'half';
             }
             return $y - 0.5;
             //向下跳0.5格
         } elseif ($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "lava") {
             //岩浆
             //echo "前方岩浆 \n";
             if ($reason) {
                 return 'lava';
             }
             return false;
             //前方岩浆
         } elseif ($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "air") {
             //空气
             //echo "考虑向下跳 ";
             if ($this->whatBlock($level, new Vector3($x, $y - 2, $z)) == "block") {
                 //echo "GO向下跳 \n";
                 if ($reason) {
                     return 'down';
                 }
                 return $y - 1;
                 //向下跳
             } else {
                 //前方悬崖
                 //echo "前方悬崖 \n";
                 if ($reason) {
                     return 'fall';
                 }
                 /*	if ($hate === false) {
                 				return false;
                 			}
                 			else {
                 				return $y-1;  //向下跳
                 			}*/
             }
         }
     } elseif ($this->whatBlock($level, new Vector3($x, $y, $z)) == "half") {
         //半砖
         //echo "前方半砖 \n";
         if ($this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "half" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "high") {
             //上方一格被堵住了
             //return false;  //上方卡住
         } else {
             if ($reason) {
                 return 'halfGO';
             }
             return $y + 0.5;
         }
     } elseif ($this->whatBlock($level, new Vector3($x, $y, $z)) == "lava") {
         //岩浆
         //echo "前方岩浆 \n";
         if ($reason) {
             return 'lava';
         }
         return false;
     } elseif ($this->whatBlock($level, new Vector3($x, $y, $z)) == "high") {
         //1.5格高方块
         //echo "前方栅栏 \n";
         if ($reason) {
             return 'high';
         }
         return false;
     } elseif ($this->whatBlock($level, new Vector3($x, $y, $z)) == "climb") {
         //梯子
         //echo "前方梯子 \n";
         //return $y;
         if ($reason) {
             return 'climb';
         }
         if ($hate) {
             return $y + 0.7;
         } else {
             return $y + 0.5;
         }
     } else {
         //考虑向上
         //echo "考虑向上 ";
         if ($this->whatBlock($level, new Vector3($x, $y + 1, $z)) != "air") {
             //前方是面墙
             //echo "前方是墙 \n";
             if ($reason) {
                 return 'wall';
             }
             return false;
         } else {
             if ($this->whatBlock($level, new Vector3($x, $y + 2, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 2, $z)) == "half" or $this->whatBlock($level, new Vector3($x, $y + 2, $z)) == "high") {
                 //上方两格被堵住了
                 //echo "2格处被堵 \n";
                 if ($reason) {
                     return 'up2!';
                 }
                 return false;
             } else {
                 //echo "GO向上跳 \n";
                 if ($reason) {
                     return 'upGO';
                 }
                 return $y + 1;
                 //向上跳
             }
         }
     }
     return false;
 }
Beispiel #28
-1
 /**
  * @param Vector3 $spawn default null
  *
  * @return bool|Position
  */
 public function getSafeSpawn($spawn = null)
 {
     if (!$spawn instanceof Vector3) {
         $spawn = $this->getSpawn();
     }
     if ($spawn instanceof Vector3) {
         $x = (int) round($spawn->x);
         $y = (int) round($spawn->y);
         $z = (int) round($spawn->z);
         for (; $y > 0; --$y) {
             $v = new Vector3($x, $y, $z);
             $b = $this->getBlock($v->getSide(0));
             if ($b === false) {
                 return $spawn;
             } elseif (!$b instanceof Air) {
                 break;
             }
         }
         for (; $y < 128; ++$y) {
             $v = new Vector3($x, $y, $z);
             if ($this->getBlock($v->getSide(1)) instanceof Air) {
                 if ($this->getBlock($v) instanceof Air) {
                     return new Position($x, $y, $z, $this);
                 }
             } else {
                 ++$y;
             }
         }
         return new Position($x, $y, $z, $this);
     }
     return false;
 }
Beispiel #29
-2
 public function setPosition(Vector3 $pos)
 {
     if ($this->closed) {
         return false;
     }
     if ($pos instanceof Position and $pos->level !== null and $pos->level !== $this->level) {
         if ($this->switchLevel($pos->getLevel()) === false) {
             return false;
         }
     }
     $this->x = $pos->x;
     $this->y = $pos->y;
     $this->z = $pos->z;
     $radius = $this->width / 2;
     $this->boundingBox->setBounds($pos->x - $radius, $pos->y, $pos->z - $radius, $pos->x + $radius, $pos->y + $this->height, $pos->z + $radius);
     $this->checkChunks();
     return true;
 }
Beispiel #30
-2
 /**
  * Handles a Minecraft packet
  * TODO: Separate all of this in handlers
  *
  * WARNING: Do not use this, it's only for internal use.
  * Changes to this function won't be recorded on the version.
  *
  * @param DataPacket $packet
  */
 public function handleDataPacket(DataPacket $packet)
 {
     if ($this->connected === false) {
         return;
     }
     if ($packet::NETWORK_ID === ProtocolInfo::BATCH_PACKET) {
         /** @var BatchPacket $packet */
         $this->server->getNetwork()->processBatch($packet, $this);
         return;
     }
     $timings = Timings::getReceiveDataPacketTimings($packet);
     $timings->startTiming();
     $this->server->getPluginManager()->callEvent($ev = new DataPacketReceiveEvent($this, $packet));
     if ($ev->isCancelled()) {
         $timings->stopTiming();
         return;
     }
     switch ($packet::NETWORK_ID) {
         case ProtocolInfo::LOGIN_PACKET:
             if ($this->loggedIn) {
                 break;
             }
             $this->username = TextFormat::clean($packet->username);
             $this->displayName = $this->username;
             $this->setNameTag($this->username);
             $this->iusername = strtolower($this->username);
             if (count($this->server->getOnlinePlayers()) >= $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)) {
                 break;
             }
             if ($packet->protocol1 !== ProtocolInfo::CURRENT_PROTOCOL) {
                 if ($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL) {
                     $message = "disconnectionScreen.outdatedClient";
                     $pk = new PlayStatusPacket();
                     $pk->status = PlayStatusPacket::LOGIN_FAILED_CLIENT;
                     $this->directDataPacket($pk);
                 } else {
                     $message = "disconnectionScreen.outdatedServer";
                     $pk = new PlayStatusPacket();
                     $pk->status = PlayStatusPacket::LOGIN_FAILED_SERVER;
                     $this->directDataPacket($pk);
                 }
                 $this->close("", $message, false);
                 break;
             }
             $this->randomClientId = $packet->clientId;
             $this->loginData = ["clientId" => $packet->clientId, "loginData" => null];
             $this->uuid = $packet->clientUUID;
             $this->rawUUID = $this->uuid->toBinary();
             $this->clientSecret = $packet->clientSecret;
             $valid = true;
             $len = strlen($packet->username);
             if ($len > 16 or $len < 3) {
                 $valid = false;
             }
             for ($i = 0; $i < $len and $valid; ++$i) {
                 $c = ord($packet->username[$i]);
                 if ($c >= ord("a") and $c <= ord("z") or $c >= ord("A") and $c <= ord("Z") or $c >= ord("0") and $c <= ord("9") or $c === ord("_")) {
                     continue;
                 }
                 $valid = false;
                 break;
             }
             if (!$valid or $this->iusername === "rcon" or $this->iusername === "console") {
                 $this->close("", "disconnectionScreen.invalidName");
                 break;
             }
             if (strlen($packet->skin) !== 64 * 32 * 4 and strlen($packet->skin) !== 64 * 64 * 4) {
                 $this->close("", "disconnectionScreen.invalidSkin");
                 break;
             }
             $this->setSkin($packet->skin, $packet->skinname, $packet->oldclient, $packet->slim, $packet->transparent);
             $this->server->getPluginManager()->callEvent($ev = new PlayerPreLoginEvent($this, "Plugin reason"));
             if ($ev->isCancelled()) {
                 $this->close("", $ev->getKickMessage());
                 break;
             }
             $this->onPlayerPreLogin();
             break;
         case ProtocolInfo::MOVE_PLAYER_PACKET:
             $newPos = new Vector3($packet->x, $packet->y - $this->getEyeHeight(), $packet->z);
             $revert = false;
             if (!$this->isAlive() or $this->spawned !== true) {
                 $revert = true;
                 $this->forceMovement = new Vector3($this->x, $this->y, $this->z);
             }
             if ($this->teleportPosition !== null or $this->forceMovement instanceof Vector3 and (($dist = $newPos->distanceSquared($this->forceMovement)) > 0.1 or $revert)) {
                 $this->sendPosition($this->forceMovement, $packet->yaw, $packet->pitch);
             } else {
                 $packet->yaw %= 360;
                 $packet->pitch %= 360;
                 if ($packet->yaw < 0) {
                     $packet->yaw += 360;
                 }
                 $this->setRotation($packet->yaw, $packet->pitch);
                 $this->newPosition = $newPos;
                 $this->forceMovement = null;
             }
             break;
         case ProtocolInfo::MOB_EQUIPMENT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             if ($packet->slot === 0x28 or $packet->slot === 0 or $packet->slot === 255) {
                 //0 for 0.8.0 compatibility
                 $packet->slot = -1;
                 //Air
             } else {
                 $packet->slot -= 9;
                 //Get real block slot
             }
             /** @var Item $item */
             $item = null;
             if ($this->isCreative()) {
                 //Creative mode match
                 $item = $packet->item;
                 $slot = Item::getCreativeItemIndex($item);
             } else {
                 $item = $this->inventory->getItem($packet->slot);
                 $slot = $packet->slot;
             }
             if ($packet->slot === -1) {
                 //Air
                 if ($this->isCreative()) {
                     $found = false;
                     for ($i = 0; $i < $this->inventory->getHotbarSize(); ++$i) {
                         if ($this->inventory->getHotbarSlotIndex($i) === -1) {
                             $this->inventory->setHeldItemIndex($i);
                             $found = true;
                             break;
                         }
                     }
                     if (!$found) {
                         //couldn't find a empty slot (error)
                         $this->inventory->sendContents($this);
                         break;
                     }
                 } else {
                     if ($packet->selectedSlot >= 0 and $packet->selectedSlot < 9) {
                         $this->inventory->setHeldItemIndex($packet->selectedSlot);
                         $this->inventory->setHeldItemSlot($packet->slot);
                     } else {
                         $this->inventory->sendContents($this);
                         break;
                     }
                 }
             } elseif ($item === null or $slot === -1 or !$item->deepEquals($packet->item)) {
                 // packet error or not implemented
                 $this->inventory->sendContents($this);
                 break;
             } elseif ($this->isCreative()) {
                 $this->inventory->setHeldItemIndex($packet->selectedSlot);
                 $this->inventory->setItem($packet->selectedSlot, $item);
                 $this->inventory->setHeldItemSlot($packet->selectedSlot);
             } else {
                 if ($packet->selectedSlot >= 0 and $packet->selectedSlot < $this->inventory->getHotbarSize()) {
                     $this->inventory->setHeldItemIndex($packet->selectedSlot);
                     $this->inventory->setHeldItemSlot($slot);
                 } else {
                     $this->inventory->sendContents($this);
                     break;
                 }
             }
             $this->inventory->sendHeldItem($this->hasSpawned);
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             break;
         case ProtocolInfo::USE_ITEM_PACKET:
             if ($this->spawned === false or !$this->isAlive() or $this->blocked) {
                 break;
             }
             $blockVector = new Vector3($packet->x, $packet->y, $packet->z);
             $this->craftingType = 0;
             if ($packet->face >= 0 and $packet->face <= 5) {
                 //Use Block, place
                 $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
                 if (!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13) or $this->isSpectator()) {
                 } elseif ($this->isCreative()) {
                     $item = $this->inventory->getItemInHand();
                     if ($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true) {
                         break;
                     }
                 } elseif (!$this->inventory->getItemInHand()->deepEquals($packet->item)) {
                     $this->inventory->sendHeldItem($this);
                 } else {
                     $item = $this->inventory->getItemInHand();
                     $oldItem = clone $item;
                     //TODO: Implement adventure mode checks
                     if ($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this)) {
                         if (!$item->deepEquals($oldItem) or $item->getCount() !== $oldItem->getCount()) {
                             $this->inventory->setItemInHand($item);
                             $this->inventory->sendHeldItem($this->hasSpawned);
                         }
                         break;
                     }
                 }
                 $this->inventory->sendHeldItem($this);
                 if ($blockVector->distanceSquared($this) > 10000) {
                     break;
                 }
                 $target = $this->level->getBlock($blockVector);
                 $block = $target->getSide($packet->face);
                 $this->level->sendBlocks([$this], [$target, $block], UpdateBlockPacket::FLAG_ALL_PRIORITY);
                 break;
             } elseif ($packet->face === 0xff) {
                 $aimPos = (new Vector3($packet->x / 32768, $packet->y / 32768, $packet->z / 32768))->normalize();
                 if ($this->isCreative()) {
                     $item = $this->inventory->getItemInHand();
                 } elseif (!$this->inventory->getItemInHand()->deepEquals($packet->item)) {
                     $this->inventory->sendHeldItem($this);
                     break;
                 } else {
                     $item = $this->inventory->getItemInHand();
                 }
                 $ev = new PlayerInteractEvent($this, $item, $aimPos, $packet->face, PlayerInteractEvent::RIGHT_CLICK_AIR);
                 $this->server->getPluginManager()->callEvent($ev);
                 if ($ev->isCancelled()) {
                     $this->inventory->sendHeldItem($this);
                     break;
                 }
                 if ($item->getId() === Item::SNOWBALL) {
                     $nbt = new Compound("", ["Pos" => new Enum("Pos", [new Double("", $this->x), new Double("", $this->y + $this->getEyeHeight()), new Double("", $this->z)]), "Motion" => new Enum("Motion", [new Double("", $aimPos->x), new Double("", $aimPos->y), new Double("", $aimPos->z)]), "Rotation" => new Enum("Rotation", [new Float("", $this->yaw), new Float("", $this->pitch)])]);
                     $f = 1.5;
                     $snowball = Entity::createEntity("Snowball", $this->chunk, $nbt, $this);
                     $snowball->setMotion($snowball->getMotion()->multiply($f));
                     if ($this->isSurvival()) {
                         $item->setCount($item->getCount() - 1);
                         $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));
                     }
                     if ($snowball instanceof Projectile) {
                         $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($snowball));
                         if ($projectileEv->isCancelled()) {
                             $snowball->kill();
                         } else {
                             $snowball->spawnToAll();
                             $this->level->addSound(new LaunchSound($this), $this->getViewers());
                         }
                     } else {
                         $snowball->spawnToAll();
                     }
                 }
                 $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, true);
                 $this->startAction = $this->server->getTick();
             }
             break;
         case ProtocolInfo::PLAYER_ACTION_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive() and $packet->action !== PlayerActionPacket::ACTION_RESPAWN and $packet->action !== PlayerActionPacket::ACTION_DIMENSION_CHANGE) {
                 break;
             }
             $packet->eid = $this->id;
             $pos = new Vector3($packet->x, $packet->y, $packet->z);
             switch ($packet->action) {
                 case PlayerActionPacket::ACTION_START_BREAK:
                     if ($this->lastBreak !== PHP_INT_MAX or $pos->distanceSquared($this) > 10000) {
                         break;
                     }
                     $target = $this->level->getBlock($pos);
                     $ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, $packet->face, $target->getId() === 0 ? PlayerInteractEvent::LEFT_CLICK_AIR : PlayerInteractEvent::LEFT_CLICK_BLOCK);
                     $this->getServer()->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->inventory->sendHeldItem($this);
                         break;
                     }
                     $this->lastBreak = microtime(true);
                     break;
                 case PlayerActionPacket::ACTION_ABORT_BREAK:
                     $this->lastBreak = PHP_INT_MAX;
                     break;
                 case PlayerActionPacket::ACTION_RELEASE_ITEM:
                     if ($this->startAction > -1 and $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION)) {
                         if ($this->inventory->getItemInHand()->getId() === Item::BOW) {
                             $bow = $this->inventory->getItemInHand();
                             if ($this->isSurvival() and !$this->inventory->contains(Item::get(Item::ARROW, 0, 1))) {
                                 $this->inventory->sendContents($this);
                                 break;
                             }
                             $nbt = new Compound("", ["Pos" => new Enum("Pos", [new Double("", $this->x), new Double("", $this->y + $this->getEyeHeight()), new Double("", $this->z)]), "Motion" => new Enum("Motion", [new Double("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new Double("", -sin($this->pitch / 180 * M_PI)), new Double("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new Enum("Rotation", [new Float("", $this->yaw), new Float("", $this->pitch)]), "Fire" => new Short("Fire", $this->isOnFire() ? 45 * 60 : 0)]);
                             $diff = $this->server->getTick() - $this->startAction;
                             $p = $diff / 20;
                             $f = min(($p ** 2 + $p * 2) / 3, 1) * 2;
                             $ev = new EntityShootBowEvent($this, $bow, Entity::createEntity("Arrow", $this->chunk, $nbt, $this, $f == 2 ? true : false), $f);
                             if ($f < 0.1 or $diff < 5) {
                                 $ev->setCancelled();
                             }
                             $this->server->getPluginManager()->callEvent($ev);
                             if ($ev->isCancelled()) {
                                 $ev->getProjectile()->kill();
                                 $this->inventory->sendContents($this);
                             } else {
                                 $ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce()));
                                 if ($this->isSurvival()) {
                                     $this->inventory->removeItem(Item::get(Item::ARROW, 0, 1));
                                     $bow->setDamage($bow->getDamage() + 1);
                                     if ($bow->getDamage() >= 385) {
                                         $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 0));
                                     } else {
                                         $this->inventory->setItemInHand($bow);
                                     }
                                 }
                                 if ($ev->getProjectile() instanceof Projectile) {
                                     $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($ev->getProjectile()));
                                     if ($projectileEv->isCancelled()) {
                                         $ev->getProjectile()->kill();
                                     } else {
                                         $ev->getProjectile()->spawnToAll();
                                         $this->level->addSound(new LaunchSound($this), $this->getViewers());
                                     }
                                 } else {
                                     $ev->getProjectile()->spawnToAll();
                                 }
                             }
                         }
                     } elseif ($this->inventory->getItemInHand()->getId() === Item::BUCKET and $this->inventory->getItemInHand()->getDamage() === 1) {
                         //Milk!
                         $this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $this->inventory->getItemInHand()));
                         if ($ev->isCancelled()) {
                             $this->inventory->sendContents($this);
                             break;
                         }
                         $pk = new EntityEventPacket();
                         $pk->eid = $this->getId();
                         $pk->event = EntityEventPacket::USE_ITEM;
                         $this->dataPacket($pk);
                         Server::broadcastPacket($this->getViewers(), $pk);
                         if ($this->isSurvival()) {
                             $slot = $this->inventory->getItemInHand();
                             --$slot->count;
                             $this->inventory->setItemInHand($slot);
                             $this->inventory->addItem(Item::get(Item::BUCKET, 0, 1));
                         }
                         $this->removeAllEffects();
                     } else {
                         $this->inventory->sendContents($this);
                     }
                     break;
                 case PlayerActionPacket::ACTION_STOP_SLEEPING:
                     $this->stopSleep();
                     break;
                 case PlayerActionPacket::ACTION_RESPAWN:
                     if ($this->spawned === false or $this->isAlive() or !$this->isOnline()) {
                         break;
                     }
                     if ($this->server->isHardcore()) {
                         $this->setBanned(true);
                         break;
                     }
                     $this->craftingType = 0;
                     $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn()));
                     $this->teleport($ev->getRespawnPosition());
                     $this->setSprinting(false);
                     $this->setSneaking(false);
                     $this->extinguish();
                     $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 300);
                     $this->deadTicks = 0;
                     $this->noDamageTicks = 60;
                     $this->setHealth($this->getMaxHealth());
                     $this->removeAllEffects();
                     $this->sendData($this);
                     $this->sendSettings();
                     $this->inventory->sendContents($this);
                     $this->inventory->sendArmorContents($this);
                     $this->blocked = false;
                     $this->spawnToAll();
                     $this->scheduleUpdate();
                     break;
                 case PlayerActionPacket::ACTION_START_SPRINT:
                     $ev = new PlayerToggleSprintEvent($this, true);
                     $this->server->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->sendData($this);
                     } else {
                         $this->setSprinting(true);
                     }
                     break;
                 case PlayerActionPacket::ACTION_STOP_SPRINT:
                     $ev = new PlayerToggleSprintEvent($this, false);
                     $this->server->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->sendData($this);
                     } else {
                         $this->setSprinting(false);
                     }
                     break;
                 case PlayerActionPacket::ACTION_START_SNEAK:
                     $ev = new PlayerToggleSneakEvent($this, true);
                     $this->server->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->sendData($this);
                     } else {
                         $this->setSneaking(true);
                     }
                     break;
                 case PlayerActionPacket::ACTION_STOP_SNEAK:
                     $ev = new PlayerToggleSneakEvent($this, false);
                     $this->server->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->sendData($this);
                     } else {
                         $this->setSneaking(false);
                     }
                     break;
             }
             $this->startAction = -1;
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             break;
         case ProtocolInfo::REMOVE_BLOCK_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = 0;
             $vector = new Vector3($packet->x, $packet->y, $packet->z);
             if ($this->isCreative()) {
                 $item = $this->inventory->getItemInHand();
             } else {
                 $item = $this->inventory->getItemInHand();
             }
             $oldItem = clone $item;
             if ($this->canInteract($vector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 6) and $this->level->useBreakOn($vector, $item, $this)) {
                 if ($this->isSurvival()) {
                     if (!$item->deepEquals($oldItem) or $item->getCount() !== $oldItem->getCount()) {
                         $this->inventory->setItemInHand($item);
                         $this->inventory->sendHeldItem($this->hasSpawned);
                     }
                 }
                 break;
             }
             $this->inventory->sendContents($this);
             $target = $this->level->getBlock($vector);
             $tile = $this->level->getTile($vector);
             $this->level->sendBlocks([$this], [$target], UpdateBlockPacket::FLAG_ALL_PRIORITY);
             $this->inventory->sendHeldItem($this);
             if ($tile instanceof Spawnable) {
                 $tile->spawnTo($this);
             }
             break;
         case ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET:
             break;
         case ProtocolInfo::INTERACT_PACKET:
             if ($this->spawned === false or !$this->isAlive() or $this->blocked) {
                 break;
             }
             $this->craftingType = 0;
             $target = $this->level->getEntity($packet->target);
             $cancelled = false;
             if ($target instanceof Player and $this->server->getConfigBoolean("pvp", true) === false) {
                 $cancelled = true;
             }
             if ($target instanceof Entity and $this->getGamemode() !== Player::VIEW and $this->isAlive() and $target->isAlive()) {
                 if ($target instanceof DroppedItem or $target instanceof Arrow) {
                     $this->kick("Attempting to attack an invalid entity");
                     $this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidEntity", [$this->getName()]));
                     break;
                 }
                 $item = $this->inventory->getItemInHand();
                 $damageTable = [Item::WOODEN_SWORD => 4, Item::GOLD_SWORD => 4, Item::STONE_SWORD => 5, Item::IRON_SWORD => 6, Item::DIAMOND_SWORD => 7, Item::WOODEN_AXE => 3, Item::GOLD_AXE => 3, Item::STONE_AXE => 3, Item::IRON_AXE => 5, Item::DIAMOND_AXE => 6, Item::WOODEN_PICKAXE => 2, Item::GOLD_PICKAXE => 2, Item::STONE_PICKAXE => 3, Item::IRON_PICKAXE => 4, Item::DIAMOND_PICKAXE => 5, Item::WOODEN_SHOVEL => 1, Item::GOLD_SHOVEL => 1, Item::STONE_SHOVEL => 2, Item::IRON_SHOVEL => 3, Item::DIAMOND_SHOVEL => 4];
                 $damage = [EntityDamageEvent::MODIFIER_BASE => isset($damageTable[$item->getId()]) ? $damageTable[$item->getId()] : 1];
                 if (!$this->canInteract($target, 8)) {
                     $cancelled = true;
                 } elseif ($target instanceof Player) {
                     if (($target->getGamemode() & 0x1) > 0) {
                         break;
                     } elseif ($this->server->getConfigBoolean("pvp") !== true or $this->server->getDifficulty() === 0) {
                         $cancelled = true;
                     }
                     $armorValues = [Item::LEATHER_CAP => 1, Item::LEATHER_TUNIC => 3, Item::LEATHER_PANTS => 2, Item::LEATHER_BOOTS => 1, Item::CHAIN_HELMET => 1, Item::CHAIN_CHESTPLATE => 5, Item::CHAIN_LEGGINGS => 4, Item::CHAIN_BOOTS => 1, Item::GOLD_HELMET => 1, Item::GOLD_CHESTPLATE => 5, Item::GOLD_LEGGINGS => 3, Item::GOLD_BOOTS => 1, Item::IRON_HELMET => 2, Item::IRON_CHESTPLATE => 6, Item::IRON_LEGGINGS => 5, Item::IRON_BOOTS => 2, Item::DIAMOND_HELMET => 3, Item::DIAMOND_CHESTPLATE => 8, Item::DIAMOND_LEGGINGS => 6, Item::DIAMOND_BOOTS => 3];
                     $points = 0;
                     foreach ($target->getInventory()->getArmorContents() as $index => $i) {
                         if (isset($armorValues[$i->getId()])) {
                             $points += $armorValues[$i->getId()];
                         }
                     }
                     $damage[EntityDamageEvent::MODIFIER_ARMOR] = -floor($damage[EntityDamageEvent::MODIFIER_BASE] * $points * 0.04);
                 }
                 $ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage);
                 if ($cancelled) {
                     $ev->setCancelled();
                 }
                 $target->attack($ev->getFinalDamage(), $ev);
                 if ($ev->isCancelled()) {
                     if ($item->isTool() and $this->isSurvival()) {
                         $this->inventory->sendContents($this);
                     }
                     break;
                 }
                 if ($item->isTool() and $this->isSurvival()) {
                     if ($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()) {
                         $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1));
                     } else {
                         $this->inventory->setItemInHand($item);
                     }
                 }
             }
             break;
         case ProtocolInfo::ANIMATE_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             $this->server->getPluginManager()->callEvent($ev = new PlayerAnimationEvent($this, $packet->action));
             if ($ev->isCancelled()) {
                 break;
             }
             $pk = new AnimatePacket();
             $pk->eid = $this->getId();
             $pk->action = $ev->getAnimationType();
             Server::broadcastPacket($this->getViewers(), $pk);
             break;
         case ProtocolInfo::SET_HEALTH_PACKET:
             //Not used
             break;
         case ProtocolInfo::ENTITY_EVENT_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = 0;
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             //TODO: check if this should be true
             switch ($packet->event) {
                 case 9:
                     //Eating
                     $items = [Item::APPLE => 4, Item::MUSHROOM_STEW => 10, Item::BEETROOT_SOUP => 10, Item::BREAD => 5, Item::RAW_PORKCHOP => 3, Item::COOKED_PORKCHOP => 8, Item::RAW_BEEF => 3, Item::STEAK => 8, Item::COOKED_CHICKEN => 6, Item::RAW_CHICKEN => 2, Item::MELON_SLICE => 2, Item::GOLDEN_APPLE => 10, Item::PUMPKIN_PIE => 8, Item::CARROT => 4, Item::POTATO => 1, Item::BAKED_POTATO => 6, Item::COOKIE => 2, Item::COOKED_FISH => 5, Item::COOKED_SALMON => 6, Item::RAW_FISH => 2, Item::RAW_SALMON => 2, Item::CLOWN_FISH => 1, Item::PUFFER_FISH => 1];
                     $slot = $this->inventory->getItemInHand();
                     if ($this->getHealth() < $this->getMaxHealth() and isset($items[$slot->getId()])) {
                         $this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $slot));
                         if ($ev->isCancelled()) {
                             $this->inventory->sendContents($this);
                             break;
                         }
                         $pk = new EntityEventPacket();
                         $pk->eid = $this->getId();
                         $pk->event = EntityEventPacket::USE_ITEM;
                         $this->dataPacket($pk);
                         Server::broadcastPacket($this->getViewers(), $pk);
                         $amount = $items[$slot->getId()];
                         $ev = new EntityRegainHealthEvent($this, $amount, EntityRegainHealthEvent::CAUSE_EATING);
                         $this->heal($ev->getAmount(), $ev);
                         --$slot->count;
                         $this->inventory->setItemInHand($slot);
                         if ($slot->getId() === Item::MUSHROOM_STEW or $slot->getId() === Item::BEETROOT_SOUP) {
                             $this->inventory->addItem(Item::get(Item::BOWL, 0, 1));
                         } elseif ($slot->getId() === Item::PUFFER_FISH) {
                             //Pufferfish
                             //$this->addEffect(Effect::getEffect(Effect::HUNGER)->setAmplifier(2)->setDuration(15 * 20));
                             $this->addEffect(Effect::getEffect(Effect::NAUSEA)->setAmplifier(1)->setDuration(15 * 20));
                             $this->addEffect(Effect::getEffect(Effect::POISON)->setAmplifier(3)->setDuration(60 * 20));
                         }
                     }
                     break;
             }
             break;
         case ProtocolInfo::DROP_ITEM_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $item = $this->inventory->getItemInHand();
             $ev = new PlayerDropItemEvent($this, $item);
             $this->server->getPluginManager()->callEvent($ev);
             if ($ev->isCancelled()) {
                 $this->inventory->sendContents($this);
                 break;
             }
             $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1));
             $motion = $this->getDirectionVector()->multiply(0.4);
             $this->level->dropItem($this->add(0, 1.3, 0), $item, $motion, 40);
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             break;
         case ProtocolInfo::TEXT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = 0;
             if ($packet->type === TextPacket::TYPE_CHAT) {
                 $packet->message = TextFormat::clean($packet->message, $this->removeFormat);
                 foreach (explode("\n", $packet->message) as $message) {
                     if (trim($message) != "" and strlen($message) <= 255 and $this->messageCounter-- > 0) {
                         $ev = new PlayerCommandPreprocessEvent($this, $message);
                         if (mb_strlen($ev->getMessage(), "UTF-8") > 320) {
                             $ev->setCancelled();
                         }
                         $this->server->getPluginManager()->callEvent($ev);
                         if ($ev->isCancelled()) {
                             break;
                         }
                         if (substr($ev->getMessage(), 0, 1) === "/") {
                             //Command
                             Timings::$playerCommandTimer->startTiming();
                             $this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 1));
                             Timings::$playerCommandTimer->stopTiming();
                         } else {
                             $this->server->getPluginManager()->callEvent($ev = new PlayerChatEvent($this, $ev->getMessage()));
                             if (!$ev->isCancelled()) {
                                 $this->server->broadcastMessage($this->getServer()->getLanguage()->translateString($ev->getFormat(), [$ev->getPlayer()->getDisplayName(), $ev->getMessage()]), $ev->getRecipients());
                             }
                         }
                     }
                 }
             }
             break;
         case ProtocolInfo::CONTAINER_CLOSE_PACKET:
             if ($this->spawned === false or $packet->windowid === 0) {
                 break;
             }
             $this->craftingType = 0;
             $this->currentTransaction = null;
             if (isset($this->windowIndex[$packet->windowid])) {
                 $this->server->getPluginManager()->callEvent(new InventoryCloseEvent($this->windowIndex[$packet->windowid], $this));
                 $this->removeWindow($this->windowIndex[$packet->windowid]);
             } else {
                 unset($this->windowIndex[$packet->windowid]);
             }
             break;
         case ProtocolInfo::CRAFTING_EVENT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             } elseif (!isset($this->windowIndex[$packet->windowId])) {
                 $this->inventory->sendContents($this);
                 $pk = new ContainerClosePacket();
                 $pk->windowid = $packet->windowId;
                 $this->dataPacket($pk);
                 break;
             }
             $recipe = $this->server->getCraftingManager()->getRecipe($packet->id);
             if ($recipe === null or ($recipe instanceof BigShapelessRecipe or $recipe instanceof BigShapedRecipe) and $this->craftingType === 0) {
                 $this->inventory->sendContents($this);
                 break;
             }
             foreach ($packet->input as $i => $item) {
                 if ($item->getDamage() === -1 or $item->getDamage() === 0xffff) {
                     $item->setDamage(null);
                 }
                 if ($i < 9 and $item->getId() > 0) {
                     $item->setCount(1);
                 }
             }
             $canCraft = true;
             if ($recipe instanceof ShapedRecipe) {
                 for ($x = 0; $x < 3 and $canCraft; ++$x) {
                     for ($y = 0; $y < 3; ++$y) {
                         $item = $packet->input[$y * 3 + $x];
                         $ingredient = $recipe->getIngredient($x, $y);
                         if ($item->getCount() > 0) {
                             if ($ingredient === null or !$ingredient->deepEquals($item, $ingredient->getDamage() !== null, $ingredient->getCompoundTag() !== null)) {
                                 $canCraft = false;
                                 break;
                             }
                         }
                     }
                 }
             } elseif ($recipe instanceof ShapelessRecipe) {
                 $needed = $recipe->getIngredientList();
                 for ($x = 0; $x < 3 and $canCraft; ++$x) {
                     for ($y = 0; $y < 3; ++$y) {
                         $item = clone $packet->input[$y * 3 + $x];
                         foreach ($needed as $k => $n) {
                             if ($n->deepEquals($item, $n->getDamage() !== null, $n->getCompoundTag() !== null)) {
                                 $remove = min($n->getCount(), $item->getCount());
                                 $n->setCount($n->getCount() - $remove);
                                 $item->setCount($item->getCount() - $remove);
                                 if ($n->getCount() === 0) {
                                     unset($needed[$k]);
                                 }
                             }
                         }
                         if ($item->getCount() > 0) {
                             $canCraft = false;
                             break;
                         }
                     }
                 }
                 if (count($needed) > 0) {
                     $canCraft = false;
                 }
             } else {
                 $canCraft = false;
             }
             /** @var Item[] $ingredients */
             $ingredients = $packet->input;
             $result = $packet->output[0];
             if (!$canCraft or !$recipe->getResult()->deepEquals($result)) {
                 $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": expected " . $recipe->getResult() . ", got " . $result . ", using: " . implode(", ", $ingredients));
                 $this->inventory->sendContents($this);
                 break;
             }
             $used = array_fill(0, $this->inventory->getSize(), 0);
             foreach ($ingredients as $ingredient) {
                 $slot = -1;
                 foreach ($this->inventory->getContents() as $index => $i) {
                     if ($ingredient->getId() !== 0 and $ingredient->deepEquals($i, $i->getDamage() !== null) and $i->getCount() - $used[$index] >= 1) {
                         $slot = $index;
                         $used[$index]++;
                         break;
                     }
                 }
                 if ($ingredient->getId() !== 0 and $slot === -1) {
                     $canCraft = false;
                     break;
                 }
             }
             if (!$canCraft) {
                 $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": client does not have enough items, using: " . implode(", ", $ingredients));
                 $this->inventory->sendContents($this);
                 break;
             }
             $this->server->getPluginManager()->callEvent($ev = new CraftItemEvent($this, $ingredients, $recipe));
             if ($ev->isCancelled()) {
                 $this->inventory->sendContents($this);
                 break;
             }
             foreach ($used as $slot => $count) {
                 if ($count === 0) {
                     continue;
                 }
                 $item = $this->inventory->getItem($slot);
                 if ($item->getCount() > $count) {
                     $newItem = clone $item;
                     $newItem->setCount($item->getCount() - $count);
                 } else {
                     $newItem = Item::get(Item::AIR, 0, 0);
                 }
                 $this->inventory->setItem($slot, $newItem);
             }
             $extraItem = $this->inventory->addItem($recipe->getResult());
             if (count($extraItem) > 0) {
                 foreach ($extraItem as $item) {
                     $this->level->dropItem($this, $item);
                 }
             }
             switch ($recipe->getResult()->getId()) {
                 case Item::WORKBENCH:
                     $this->awardAchievement("buildWorkBench");
                     break;
                 case Item::WOODEN_PICKAXE:
                     $this->awardAchievement("buildPickaxe");
                     break;
                 case Item::FURNACE:
                     $this->awardAchievement("buildFurnace");
                     break;
                 case Item::WOODEN_HOE:
                     $this->awardAchievement("buildHoe");
                     break;
                 case Item::BREAD:
                     $this->awardAchievement("makeBread");
                     break;
                 case Item::CAKE:
                     //TODO: detect complex recipes like cake that leave remains
                     $this->awardAchievement("bakeCake");
                     $this->inventory->addItem(Item::get(Item::BUCKET, 0, 3));
                     break;
                 case Item::STONE_PICKAXE:
                 case Item::GOLD_PICKAXE:
                 case Item::IRON_PICKAXE:
                 case Item::DIAMOND_PICKAXE:
                     $this->awardAchievement("buildBetterPickaxe");
                     break;
                 case Item::WOODEN_SWORD:
                     $this->awardAchievement("buildSword");
                     break;
                 case Item::DIAMOND:
                     $this->awardAchievement("diamond");
                     break;
             }
             break;
         case ProtocolInfo::CONTAINER_SET_SLOT_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             if ($packet->slot < 0) {
                 break;
             }
             if ($packet->windowid === 0) {
                 //Our inventory
                 if ($packet->slot >= $this->inventory->getSize()) {
                     break;
                 }
                 if ($this->isCreative()) {
                     if (Item::getCreativeItemIndex($packet->item) !== -1) {
                         $this->inventory->setItem($packet->slot, $packet->item);
                         $this->inventory->setHotbarSlotIndex($packet->slot, $packet->slot);
                         //links $hotbar[$packet->slot] to $slots[$packet->slot]
                     }
                 }
                 $transaction = new BaseTransaction($this->inventory, $packet->slot, $this->inventory->getItem($packet->slot), $packet->item);
             } elseif ($packet->windowid === ContainerSetContentPacket::SPECIAL_ARMOR) {
                 //Our armor
                 if ($packet->slot >= 4) {
                     break;
                 }
                 $transaction = new BaseTransaction($this->inventory, $packet->slot + $this->inventory->getSize(), $this->inventory->getArmorItem($packet->slot), $packet->item);
             } elseif (isset($this->windowIndex[$packet->windowid])) {
                 $this->craftingType = 0;
                 $inv = $this->windowIndex[$packet->windowid];
                 $transaction = new BaseTransaction($inv, $packet->slot, $inv->getItem($packet->slot), $packet->item);
             } else {
                 break;
             }
             if ($transaction->getSourceItem()->deepEquals($transaction->getTargetItem()) and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()) {
                 //No changes!
                 //No changes, just a local inventory update sent by the server
                 break;
             }
             if ($this->currentTransaction === null or $this->currentTransaction->getCreationTime() < microtime(true) - 8) {
                 if ($this->currentTransaction !== null) {
                     foreach ($this->currentTransaction->getInventories() as $inventory) {
                         if ($inventory instanceof PlayerInventory) {
                             $inventory->sendArmorContents($this);
                         }
                         $inventory->sendContents($this);
                     }
                 }
                 $this->currentTransaction = new SimpleTransactionGroup($this);
             }
             $this->currentTransaction->addTransaction($transaction);
             if ($this->currentTransaction->canExecute()) {
                 $achievements = [];
                 foreach ($this->currentTransaction->getTransactions() as $ts) {
                     $inv = $ts->getInventory();
                     if ($inv instanceof FurnaceInventory) {
                         if ($ts->getSlot() === 2) {
                             switch ($inv->getResult()->getId()) {
                                 case Item::IRON_INGOT:
                                     $achievements[] = "acquireIron";
                                     break;
                             }
                         }
                     }
                 }
                 if ($this->currentTransaction->execute()) {
                     foreach ($achievements as $a) {
                         $this->awardAchievement($a);
                     }
                 }
                 $this->currentTransaction = null;
             }
             break;
         case ProtocolInfo::BLOCK_ENTITY_DATA_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = 0;
             $pos = new Vector3($packet->x, $packet->y, $packet->z);
             if ($pos->distanceSquared($this) > 10000) {
                 break;
             }
             $t = $this->level->getTile($pos);
             if ($t instanceof Sign) {
                 $nbt = new NBT(NBT::LITTLE_ENDIAN);
                 $nbt->read($packet->namedtag);
                 $nbt = $nbt->getData();
                 if ($nbt["id"] !== Tile::SIGN) {
                     $t->spawnTo($this);
                 } else {
                     $ev = new SignChangeEvent($t->getBlock(), $this, [TextFormat::clean($nbt["Text1"], $this->removeFormat), TextFormat::clean($nbt["Text2"], $this->removeFormat), TextFormat::clean($nbt["Text3"], $this->removeFormat), TextFormat::clean($nbt["Text4"], $this->removeFormat)]);
                     if (!isset($t->namedtag->Creator) or $t->namedtag["Creator"] !== $this->getRawUniqueId()) {
                         $ev->setCancelled();
                     } else {
                         foreach ($ev->getLines() as $line) {
                             if (mb_strlen($line, "UTF-8") > 16) {
                                 $ev->setCancelled();
                             }
                         }
                     }
                     $this->server->getPluginManager()->callEvent($ev);
                     if (!$ev->isCancelled()) {
                         $t->setText($ev->getLine(0), $ev->getLine(1), $ev->getLine(2), $ev->getLine(3));
                     } else {
                         $t->spawnTo($this);
                     }
                 }
             }
             break;
         default:
             break;
     }
     $timings->stopTiming();
 }