clean() public static méthode

Cleans the string from Minecraft codes and ANSI Escape Codes
public static clean ( string $string, boolean $removeFormat = true ) : mixed
$string string
$removeFormat boolean
Résultat mixed
 public function spawnTo(Player $player)
 {
     if ($player instanceof DesktopPlayer) {
         if ($this !== $player and $this->spawned === true and $player->getLevel() === $this->getLevel() and $player->canSee($this)) {
             $this->hasSpawned[$player->getID()] = $player;
             $pk = new SpawnPlayerPacket();
             if ($player->getRemoveFormat()) {
                 $pk->name = TextFormat::clean($this->nameTag);
             } else {
                 $pk->name = $this->nameTag;
             }
             $pk->eid = $this->getID();
             $pk->uuid = $this->bigBrother_formatedUUID;
             $pk->x = $this->x;
             $pk->z = $this->y;
             $pk->y = $this->z;
             $pk->yaw = $this->yaw;
             $pk->pitch = $this->pitch;
             $pk->item = $this->inventory->getItemInHand()->getID();
             $pk->metadata = $this->getData();
             $pk->data = $this->bigBrother_properties;
             $player->putRawPacket($pk);
             $pk = new EntityTeleportPacket();
             $pk->eid = $this->getID();
             $pk->x = $this->x;
             $pk->z = $this->y;
             $pk->y = $this->z;
             $pk->yaw = $this->yaw;
             $pk->pitch = $this->pitch;
             $player->putRawPacket($pk);
             $pk = new SetEntityMotionPacket();
             $pk->eid = $this->getID();
             $pk->speedX = $this->motionX;
             $pk->speedY = $this->motionY;
             $pk->speedZ = $this->motionZ;
             $player->dataPacket($pk);
             $this->inventory->sendHeldItem($player);
             $this->inventory->sendArmorContents($player);
         }
     } else {
         parent::spawnTo($player);
     }
 }
Exemple #2
0
 public function onPlayerTouch(PlayerInteractEvent $event)
 {
     $player = $event->getPlayer();
     $b = $event->getBlock();
     $name = $event->getPlayer()->getName();
     $name = strtolower($name);
     if ($b->getID() === 63 || $b->getID() === 68) {
         $sign = $player->getLevel()->getTile($b);
         if (!$sign instanceof Sign) {
             return;
         }
         $sign = $sign->getText();
         if (TextFormat::clean($sign[0]) === '[Checkpoint]') {
             $this->data->set($name, array($player->x, $player->y, $player->z, $player->getLevel()->getName()));
             $this->data->save();
             $player->sendMessage($this->getConfig()->get("CheckpointSaved"));
         }
         if (TextFormat::clean($sign[0]) === '[Earn Reward]') {
             $this->data->remove($name, array($player->x, $player->y, $player->z, $player->getLevel()->getName()));
             $this->data->save();
             $player->sendMessage($this->getConfig()->get("EarnReward"));
             if ($this->getConfig()->get("reward-command")) {
                 $player->getServer()->dispatchCommand(new ConsoleCommandSender(), str_ireplace("{PLAYER}", $player->getName(), $this->getConfig()->get("reward-command")));
                 $player->teleport($player->getLevel()->getSafeSpawn());
             }
         }
     }
     if ($b->getID() === $this->getConfig()->get("CheckPointBlock")) {
         $this->data->set($name, array($player->x, $player->y, $player->z, $player->getLevel()->getName()));
         $this->data->save();
         $player->sendMessage($this->getConfig()->get("CheckpointSaved"));
     }
 }
Exemple #3
0
 public function check()
 {
     for ($n = 0; $n < $this->threads; ++$n) {
         if ($this->workers[$n]->isTerminated() === true) {
             $this->workers[$n] = new RCONInstance($this->socket, $this->password, $this->clientsPerThread);
         } elseif ($this->workers[$n]->isWaiting()) {
             if ($this->workers[$n]->response !== "") {
                 $this->server->getLogger()->info($this->workers[$n]->response);
                 $this->workers[$n]->synchronized(function (RCONInstance $thread) {
                     $thread->notify();
                 }, $this->workers[$n]);
             } else {
                 $response = new RemoteConsoleCommandSender();
                 $command = $this->workers[$n]->cmd;
                 $this->server->getPluginManager()->callEvent($ev = new RemoteServerCommandEvent($response, $command));
                 if (!$ev->isCancelled()) {
                     $this->server->dispatchCommand($ev->getSender(), $ev->getCommand());
                 }
                 $this->workers[$n]->response = TextFormat::clean($response->getMessage());
                 $this->workers[$n]->synchronized(function (RCONInstance $thread) {
                     $thread->notify();
                 }, $this->workers[$n]);
             }
         }
     }
 }
 public function onTelegramMessage(TelegramMessageEvent $event)
 {
     if (!PocketTelegram::$broadcastTelegramMessages) {
         return;
     }
     $message = $event->getMessage();
     switch (true) {
         case $message instanceof TextMessage:
             if (PocketTelegram::$enableTelegramCommands and $message->isCommand()) {
                 $this->handleTelegramCommands($message);
                 return;
             }
             $text = $message->getText();
             break;
         case $message instanceof PhotoMessage:
             $text = "(Photo)";
             break;
         default:
             return;
     }
     if ($message->getChat()->getId() !== PocketTelegram::getDefaultChannel()) {
         return;
     }
     if (is_null($from = $message->getFrom()) or is_null($username = $from->getUsername())) {
         return;
     }
     $this->broadcastMessage(PocketTelegram::getInstance()->getConfig()->get("telegramUserPrefix", "@") . $username, TextFormat::clean($text));
 }
 public function onSignChange(SignChangeEvent $event)
 {
     if (strtolower(TextFormat::clean($event->getLine(0))) === "[advancedkits]" and !$event->getPlayer()->hasPermission("advancedkits.admin")) {
         $event->getPlayer()->sendMessage($this->ak->langManager->getTranslation("no-perm-sign"));
         $event->setCancelled();
     }
 }
 public function onPostRelease($rowId)
 {
     if ($this->src === "{BOT}CapsDetector" or $this->src === "{BOT}SwearDetector") {
         return;
     }
     $message = implode("\n", ["{$this->src} @ `{$this->ip}:{$this->port}` executed /console. Message `#{$rowId}``:", MUtils::toMd($this->msg)]);
     $isBot = substr($this->src, 0, 5) === "{BOT}";
     $this->main->getServer()->getScheduler()->scheduleAsyncTask(new PostUrlTask(Credentials::SLACK_WEBHOOK, json_encode(["text" => TextFormat::clean($message), "icon_url" => Credentials::LEGIONPE_ICON_URL, "username" => $isBot ? substr($this->src, 5) : $this->src, "channel" => $isBot ? "#spam" : "#support"])));
 }
 /**
  * Replaces all formatted color codes in the specified message, if revert is true, it will remove all text effects
  * @param string $message
  * @param bool $revert
  * @return string
  */
 public static function replaceSymbols($message, $revert = false)
 {
     $defaultFormat = [TextFormat::BLACK, TextFormat::DARK_BLUE, TextFormat::DARK_GREEN, TextFormat::DARK_AQUA, TextFormat::DARK_RED, TextFormat::DARK_PURPLE, TextFormat::GOLD, TextFormat::GRAY, TextFormat::DARK_GRAY, TextFormat::BLUE, TextFormat::GREEN, TextFormat::AQUA, TextFormat::RED, TextFormat::LIGHT_PURPLE, TextFormat::YELLOW, TextFormat::WHITE, TextFormat::OBFUSCATED, TextFormat::BOLD, TextFormat::STRIKETHROUGH, TextFormat::UNDERLINE, TextFormat::ITALIC, TextFormat::RESET];
     $newFormat = ["&0", "&1", "&2", "&3", "&4", "&5", "&6", "&7", "&8", "&9", "&a", "&b", "&c", "&d", "&e", "&f", "&k", "&l", "&m", "&n", "&o", "&r"];
     if ($revert) {
         return TextFormat::clean($message);
     } else {
         return str_replace($newFormat, $defaultFormat, $message);
     }
 }
 public function onQueryRegen(QueryRegenerateEvent $event)
 {
     $event->setWorld($this->main->query_world());
     $this->main->getPlayersCount($total, $max, $classTotal, $classMax);
     $event->setPlayerCount($classTotal);
     $event->setMaxPlayerCount($classMax);
     $event->setPlayerList([]);
     $event->setServerName(TextFormat::clean($this->main->getServer()->getNetwork()->getName()));
     $extra = $event->getExtraData();
     $extra["class_numplayers"] = $classMax;
     $extra["class_maxplayers"] = $classMax;
     $this->addExtras($extra);
     $event->setExtraData($extra);
 }
 public function onQueryRegen(QueryRegenerateEvent $event)
 {
     $event->setWorld($this->main->query_world());
     $this->main->getPlayersCount($total, $max, $classTotal, $classMax);
     $event->setPlayerCount($classTotal);
     $event->setMaxPlayerCount($classMax);
     $event->setPlayerList([]);
     $event->setServerName(TextFormat::clean($this->main->getServer()->getNetwork()->getName()));
     $extra = $event->getExtraData();
     $name = strtolower(Settings::$CLASSES_NAMES[Settings::$LOCALIZE_CLASS]);
     $extra[$name . "_numplayers"] = $classTotal;
     $extra[$name . "_maxplayers"] = $classMax;
     $this->addExtras($extra);
     $event->setExtraData($extra);
 }
 public function onRun($currentTick)
 {
     foreach ($this->plugin->getServer()->getLevels() as $levels) {
         foreach ($levels->getTiles() as $tiles) {
             if ($tiles instanceof Sign) {
                 $text = $tiles->getText();
                 if (TextFormat::clean(strtolower(trim($text[0]))) === strtolower(trim($this->plugin->sign->get("sign_final_change")))) {
                     $world = $text[1];
                     $level = $this->plugin->getServer()->getLevelByName($world);
                     $players = count($level->getPlayers());
                     $tiles->setText($text[0] = TextFormat::GREEN . $this->plugin->sign->get("sign_final_change"), $text[2] = TextFormat::YELLOW . $players . " players");
                 }
             }
         }
     }
 }
Exemple #11
0
 public function onPlayerTouch(PlayerInteractEvent $event)
 {
     $player = $event->getPlayer();
     $b = $event->getBlock();
     $name = $event->getPlayer()->getName();
     $name = strtolower($name);
     if ($b->getID() == 63 || $b->getID() == 68) {
         $sign = $player->getLevel()->getTile($b);
         if (!$sign instanceof Sign) {
             return;
         }
         $sign = $sign->getText();
         if (TextFormat::clean($sign[0]) === '[Checkpoint]') {
             $this->config->set($name, array($player->x, $player->y, $player->z, $player->getLevel()->getName()));
             $this->config->save();
             $player->sendMessage("Saved");
         } elseif (TextFormat::clean($sign[0]) === '[To Checkpoint]') {
             $pos = $this->config->get($name);
             if (is_array($pos)) {
                 if (count($pos) === 4) {
                     $player->sendMessage("Teleporting to Checkpoint...");
                     $level = $this->getServer()->getLevelByName($pos[3]);
                     if ($level) {
                         $player->teleport(new Position($pos[0], $pos[1], $pos[2], $level));
                     } else {
                         $player->sendMessage("Level is not loaded");
                     }
                 } else {
                     $player->sendMessage("Save Corrupted");
                 }
             } else {
                 $player->sendMessage("No Save Found");
             }
         }
     }
 }
Exemple #12
0
 /**
  * @param SignChangeEvent $event
  */
 public function onSignChange(SignChangeEvent $event)
 {
     // Special Signs
     // Free sign
     if (strtolower(TextFormat::clean($event->getLine(0), true)) === "[free]" && $event->getPlayer()->hasPermission("essentials.sign.create.free")) {
         if (trim($event->getLine(1)) !== "" || $event->getLine(1) !== null) {
             $item_name = $event->getLine(1);
             if (trim($event->getLine(2)) !== "" || $event->getLine(2) !== null) {
                 $damage = $event->getLine(2);
             } else {
                 $damage = 0;
             }
             $item = $this->getAPI()->getItem($item_name . ":" . $damage);
             if ($item->getID() === 0 || $item->getName() === "Air") {
                 $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] Invalid item name/ID");
                 $event->setCancelled(true);
             } else {
                 $event->getPlayer()->sendMessage(TextFormat::GREEN . "Free sign successfully created!");
                 $event->setLine(0, TextFormat::AQUA . "[Free]");
                 $event->setLine(1, $item->getName() === "Unknown" ? $item->getID() : $item->getName());
                 $event->setLine(2, $damage);
             }
         } else {
             $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] You should provide an item name/ID");
             $event->setCancelled(true);
         }
     } elseif (strtolower(TextFormat::clean($event->getLine(0), true)) === "[gamemode]" && $event->getPlayer()->hasPermission("essentials.sign.create.gamemode")) {
         switch (strtolower($event->getLine(1))) {
             case "survival":
             case "0":
                 $event->setLine(1, "Survival");
                 break;
             case "creative":
             case "1":
                 $event->setLine(1, "Creative");
                 break;
             case "adventure":
             case "2":
                 $event->setLine(1, "Adventure");
                 break;
             case "spectator":
             case "view":
             case "3":
                 $event->setLine(1, "Spectator");
                 break;
             default:
                 $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] Unknown Gamemode, you should use \"Survival\", \"Creative\", \"Adventure\" or \"Spectator\"");
                 $event->setCancelled(true);
                 return;
                 break;
         }
         $event->getPlayer()->sendMessage(TextFormat::GREEN . "Gamemode sign successfully created!");
         $event->setLine(0, TextFormat::AQUA . "[Gamemode]");
     } elseif (strtolower(TextFormat::clean($event->getLine(0), true)) === "[heal]" && $event->getPlayer()->hasPermission("essentials.sign.create.heal")) {
         $event->getPlayer()->sendMessage(TextFormat::GREEN . "Heal sign successfully created!");
         $event->setLine(0, TextFormat::AQUA . "[Heal]");
     } elseif (strtolower(TextFormat::clean($event->getLine(0), true)) === "[kit]" && $event->getPlayer()->hasPermission("essentials.sign.create.kit")) {
         if (!$this->getAPI()->kitExists($event->getLine(1))) {
             $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] Kit doesn't exist");
             return;
         }
         $event->getPlayer()->sendMessage(TextFormat::GREEN . "Kit sign successfully created!");
         $event->setLine(0, TextFormat::AQUA . "[Kit]");
     } elseif (strtolower(TextFormat::clean($event->getLine(0), true)) === "[repair]" && $event->getPlayer()->hasPermission("essentials.sign.create.repair")) {
         switch (strtolower($event->getLine(1))) {
             case "hand":
                 $event->setLine(1, "Hand");
                 break;
             case "all":
                 $event->setLine(1, "All");
                 break;
             default:
                 $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] Invalid argument, you should use \"Hand\" or \"All\"");
                 $event->setCancelled(true);
                 return;
                 break;
         }
         $event->getPlayer()->sendMessage(TextFormat::GREEN . "Repair sign successfully created!");
         $event->setLine(0, TextFormat::AQUA . "[Repair]");
     } elseif (strtolower(TextFormat::clean($event->getLine(0), true)) === "[time]" && $event->getPlayer()->hasPermission("essentials.sign.create.time")) {
         switch (strtolower($event->getLine(1))) {
             case "day":
                 $event->setLine(1, "Day");
                 break;
             case "night":
                 $event->setLine(1, "Night");
                 break;
             default:
                 $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] Invalid time, you should use \"Day\" or \"Night\"");
                 $event->setCancelled(true);
                 return;
                 break;
         }
         $event->getPlayer()->sendMessage(TextFormat::GREEN . "Time sign successfully created!");
         $event->setLine(0, TextFormat::AQUA . "[Time]");
     } elseif (strtolower(TextFormat::clean($event->getLine(0), true)) === "[teleport]" && $event->getPlayer()->hasPermission("essentials.sign.create.teleport")) {
         if (!is_numeric($event->getLine(1))) {
             $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] Invalid X position, Teleport sign will not work");
             $event->setCancelled(true);
         } elseif (!is_numeric($event->getLine(2))) {
             $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] Invalid Y position, Teleport sign will not work");
             $event->setCancelled(true);
         } elseif (!is_numeric($event->getLine(3))) {
             $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] Invalid Z position, Teleport sign will not work");
             $event->setCancelled(true);
         } else {
             $event->getPlayer()->sendMessage(TextFormat::GREEN . "Teleport sign successfully created!");
             $event->setLine(0, TextFormat::AQUA . "[Teleport]");
             $event->setLine(1, $event->getLine(1));
             $event->setLine(2, $event->getLine(2));
             $event->setLine(3, $event->getLine(3));
         }
     } elseif (strtolower(TextFormat::clean($event->getLine(0), true)) === "[warp]" && $event->getPlayer()->hasPermission("essentials.sign.create.warp")) {
         $warp = $event->getLine(1);
         if (!$this->getAPI()->warpExists($warp)) {
             $event->getPlayer()->sendMessage(TextFormat::RED . "[Error] Warp doesn't exists");
             $event->setCancelled(true);
         } else {
             $event->getPlayer()->sendMessage(TextFormat::GREEN . "Warp sign successfully created!");
             $event->setLine(0, TextFormat::AQUA . "[Warp]");
         }
     } elseif ($event->getPlayer()->hasPermission("essentials.sign.color")) {
         for ($i = 0; $i < 4; $i++) {
             $event->setLine($i, $this->getAPI()->colorMessage($event->getLine($i)));
         }
     }
 }
Exemple #13
0
 public function getPlayer($player)
 {
     if (!$this->validateName($player, false)) {
         return false;
     }
     $player = strtolower($player);
     $found = false;
     foreach ($this->getServer()->getOnlinePlayers() as $p) {
         if (strtolower(TextFormat::clean($p->getDisplayName(), true)) === $player || strtolower($p->getName()) === $player) {
             $found = $p;
             break;
         }
     }
     // If cannot get the exact player name/nick, try with portions of it
     if (!$found) {
         $found = ($f = $this->getServer()->getPlayer($player)) === null ? false : $f;
         // PocketMine function to get from portions of name
     }
     /*
      * Copy from PocketMine's function (use above xD) but modified to work with Nicknames :P
      *
      * ALL THE RIGHTS FROM THE FOLLOWING CODE BELONGS TO POCKETMINE-MP
      */
     if (!$found) {
         $delta = \PHP_INT_MAX;
         foreach ($this->getServer()->getOnlinePlayers() as $p) {
             // Clean the Display Name due to colored nicks :S
             if (\stripos($n = TextFormat::clean($p->getDisplayName(), true), $player) === 0) {
                 $curDelta = \strlen($n) - \strlen($player);
                 if ($curDelta < $delta) {
                     $found = $p;
                     $delta = $curDelta;
                 }
                 if ($curDelta === 0) {
                     break;
                 }
             }
         }
     }
     return $found;
 }
Exemple #14
0
 public function onInteract(PlayerInteractEvent $event)
 {
     $player = $event->getPlayer();
     $sign = $event->getPlayer()->getLevel()->getTile($event->getBlock());
     if ($event->getBlock()->getId() == 63 or $event->getBlock()->getId() == 68) {
         if ($sign instanceof Sign) {
             $signtext = $sign->getText();
             if (TextFormat::clean($signtext[0]) === "[DeadEnd]") {
                 $player->teleport(126.3, 5, 128.3, DeadEnd - lobby);
                 $player->sendMessage(TextFormat::GOLD . "You entered DeadEnd!");
             }
         }
     }
 }
Exemple #15
0
 /**
  * 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->pid() === ProtocolInfo::BATCH_PACKET) {
         /** @var BatchPacket $packet */
         $this->server->getNetwork()->processBatch($packet, $this);
         return;
     }
     $this->server->getPluginManager()->callEvent($ev = new DataPacketReceiveEvent($this, $packet));
     if ($ev->isCancelled()) {
         return;
     }
     switch ($packet->pid()) {
         case ProtocolInfo::LOGIN_PACKET:
             /*
              * A/N: Not going to implement any session code until it actually does stuff.
              * Single line functions are obnoxious to follow.
              */
             if ($this->loggedIn === true) {
                 break;
             }
             $this->username = TextFormat::clean($packet->username);
             $this->displayName = $this->username;
             $this->setNameTag($this->username);
             $this->iusername = strtolower($this->username);
             $this->randomClientId = $packet->clientId;
             $this->loginData = ["clientId" => $packet->clientId, "loginData" => null];
             $this->uuid = $packet->clientUUID;
             $this->rawUUID = $this->uuid->toBinary();
             $this->clientSecret = $packet->clientSecret;
             $this->protocol = $packet->protocol1;
             if (count($this->server->getOnlinePlayers()) > $this->server->getMaxPlayers() and $this->kick("Server is full")) {
                 break;
             }
             if ($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL) {
                 $message = "";
                 if ($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL) {
                     $message = "Please update Minecraft PE to join.";
                     $pk = new PlayStatusPacket();
                     $pk->status = PlayStatusPacket::LOGIN_FAILED_CLIENT;
                     $this->dataPacket($pk);
                 } else {
                     $message = "Please use an older version of Minecraft PE.";
                     $pk = new PlayStatusPacket();
                     $pk->status = PlayStatusPacket::LOGIN_FAILED_SERVER;
                     $this->dataPacket($pk);
                 }
                 $this->close("", $message, false);
                 return;
             }
             if (strpos($packet->username, "") !== false or preg_match('#^[a-zA-Z0-9_]{3,16}$#', $packet->username) == 0 or $this->username === "" or $this->iusername === "rcon" or $this->iusername === "console" or strlen($packet->username) > 16 or strlen($packet->username) < 3) {
                 $this->close("", "Please choose a valid username.");
                 return;
             }
             if (strlen($packet->skin) < 64 * 32 * 4) {
                 $this->close("", "Invalid skin.", false);
                 return;
             }
             $this->setSkin($packet->skin, $packet->slim);
             $this->server->getPluginManager()->callEvent($ev = new PlayerPreLoginEvent($this, "Plugin reason"));
             if ($ev->isCancelled()) {
                 $this->close("", $ev->getKickMessage());
                 return;
             }
             if (!$this->server->isWhitelisted(strtolower($this->getName()))) {
                 $this->close(TextFormat::YELLOW . $this->username . " has left the game", "Server is private.");
                 return;
             } elseif ($this->server->getNameBans()->isBanned(strtolower($this->getName())) or $this->server->getIPBans()->isBanned($this->getAddress())) {
                 $this->close(TextFormat::YELLOW . $this->username . " has left the game", "You have been banned.");
                 return;
             }
             if ($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)) {
                 $this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this);
             }
             if ($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)) {
                 $this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);
             }
             foreach ($this->server->getOnlinePlayers() as $p) {
                 if ($p !== $this and strtolower($p->getName()) === strtolower($this->getName())) {
                     if ($p->kick("You connected from somewhere else.") === false) {
                         $this->close(TextFormat::YELLOW . $this->getName() . " has left the game", "You connected from somewhere else.");
                         return;
                     } else {
                         return;
                     }
                 }
             }
             $nbt = $this->server->getOfflinePlayerData($this->username);
             if (!isset($nbt->NameTag)) {
                 $nbt->NameTag = new String("NameTag", $this->username);
             } else {
                 $nbt["NameTag"] = $this->username;
             }
             $this->gamemode = $nbt["playerGameType"] & 0x3;
             if ($this->server->getForceGamemode()) {
                 $this->gamemode = $this->server->getGamemode();
                 $nbt->playerGameType = new Int("playerGameType", $this->gamemode);
             }
             $this->allowFlight = $this->isCreative();
             if (($level = $this->server->getLevelByName($nbt["Level"])) === null) {
                 $this->setLevel($this->server->getDefaultLevel(), true);
                 $nbt["Level"] = $this->level->getName();
                 $nbt["Pos"][0] = $this->level->getSpawnLocation()->x;
                 $nbt["Pos"][1] = $this->level->getSpawnLocation()->y + 5;
                 $nbt["Pos"][2] = $this->level->getSpawnLocation()->z;
             } else {
                 $this->setLevel($level, true);
             }
             if (!$nbt instanceof Compound) {
                 $this->close(TextFormat::YELLOW . $this->username . " has left the game", "Corrupt joining data, check your connection.");
                 return;
             }
             $this->achievements = [];
             /** @var Byte $achievement */
             foreach ($nbt->Achievements as $achievement) {
                 $this->achievements[$achievement->getName()] = $achievement->getValue() > 0 ? true : false;
             }
             $nbt->lastPlayed = new Long("lastPlayed", floor(microtime(true) * 1000));
             parent::__construct($this->level->getChunk($nbt["Pos"][0] >> 4, $nbt["Pos"][2] >> 4, true), $nbt);
             $this->loggedIn = true;
             $this->server->addOnlinePlayer($this);
             $this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason"));
             if ($ev->isCancelled()) {
                 $this->close(TextFormat::YELLOW . $this->username . " has left the game", $ev->getKickMessage());
                 return;
             }
             if ($this->isCreative()) {
                 $this->inventory->setHeldItemSlot(0);
             } else {
                 $this->inventory->setHeldItemSlot($this->inventory->getHotbarSlotIndex(0));
             }
             $pk = new PlayStatusPacket();
             $pk->status = PlayStatusPacket::LOGIN_SUCCESS;
             $this->dataPacket($pk);
             $this->uuid = $packet->clientUUID;
             $this->rawUUID = $this->uuid->toBinary();
             $this->clientSecret = $packet->clientSecret;
             if ($this->spawnPosition === null and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level) {
                 $this->spawnPosition = new Position($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level);
             }
             $spawnPosition = $this->getSpawn();
             $pk = new StartGamePacket();
             $pk->seed = -1;
             $pk->dimension = 0;
             $pk->x = $this->x;
             $pk->y = $this->y;
             $pk->z = $this->z;
             $pk->spawnX = (int) $spawnPosition->x;
             $pk->spawnY = (int) $spawnPosition->y;
             $pk->spawnZ = (int) $spawnPosition->z;
             $pk->generator = 1;
             //0 old, 1 infinite, 2 flat
             $pk->gamemode = $this->gamemode & 0x1;
             $pk->eid = 0;
             //Always use EntityID as zero for the actual player
             $this->dataPacket($pk);
             $pk = new SetTimePacket();
             $pk->time = $this->level->getTime();
             $pk->started = $this->level->stopTime == false;
             $this->dataPacket($pk);
             $pk = new SetSpawnPositionPacket();
             $pk->x = (int) $spawnPosition->x;
             $pk->y = (int) $spawnPosition->y;
             $pk->z = (int) $spawnPosition->z;
             $this->dataPacket($pk);
             if ($this->getHealth() <= 0) {
                 $this->dead = true;
             }
             $pk = new SetDifficultyPacket();
             $pk->difficulty = $this->server->getDifficulty();
             $this->dataPacket($pk);
             $this->server->getLogger()->info(TextFormat::AQUA . $this->username . TextFormat::WHITE . "/" . TextFormat::AQUA . $this->ip . " connected");
             if ($this->gamemode === Player::SPECTATOR) {
                 $pk = new ContainerSetContentPacket();
                 $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE;
                 $this->dataPacket($pk);
             } else {
                 $pk = new ContainerSetContentPacket();
                 $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE;
                 foreach (Item::getCreativeItems() as $item) {
                     $pk->slots[] = clone $item;
                 }
                 $this->dataPacket($pk);
             }
             $this->server->sendFullPlayerListData($this);
             $this->server->sendRecipeList($this);
             //				$this->orderChunks();
             //				$this->sendNextChunk();
             break;
         case ProtocolInfo::MOVE_PLAYER_PACKET:
             $newPos = new Vector3($packet->x, $packet->y - $this->getEyeHeight(), $packet->z);
             $revert = false;
             if ($this->dead === true or $this->spawned !== true) {
                 $revert = true;
                 $this->forceMovement = new Vector3($this->x, $this->y, $this->z);
             }
             if ($this->forceMovement instanceof Vector3 and (($dist = $newPos->distanceSquared($this->forceMovement)) > 0.04 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->dead === true) {
                 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 < 9) {
                     $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->dead === true 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 ($blockVector->distance($this) > 10 or $this->isCreative() and $this->isAdventure()) {
                 } 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);
                             $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->dead === true and $packet->action !== 7) {
                 break;
             }
             $this->craftingType = 0;
             $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->dead = false;
                     $this->noDamageTicks = 60;
                     $this->setHealth($this->getMaxHealth());
                     $this->setFood(20);
                     $this->starvationTick = 0;
                     $this->foodTick = 0;
                     $this->lastSentVitals = 10;
                     $this->foodUsageTime = 0;
                     $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->dead === true) {
                 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->level->useBreakOn($vector, $item, $this) === true) {
                 if ($this->isSurvival()) {
                     if (!$item->equals($oldItem, true) or $item->getCount() !== $oldItem->getCount()) {
                         $this->inventory->setItemInHand($item, $this);
                         $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->dead === true 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->dead !== true and $target->dead !== true) {
                 if ($target instanceof DroppedItem or $target instanceof Arrow) {
                     $this->kick("Attempting to attack an invalid entity");
                     $this->server->getLogger()->warning("Player " . $this->getName() . " tried to attack an invalid entity");
                     return;
                 }
                 $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->distance($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), $this);
                     } else {
                         $this->inventory->setItemInHand($item, $this);
                     }
                 }
             }
             break;
         case ProtocolInfo::ANIMATE_PACKET:
             if ($this->spawned === false or $this->dead === true) {
                 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->dead === true) {
                 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
                     $this->eatFoodInHand();
                     break;
             }
             break;
         case ProtocolInfo::DROP_ITEM_PACKET:
             if ($this->spawned === false or $this->blocked === true or $this->dead === true) {
                 break;
             }
             if (!$this->inventory->contains($packet->item)) {
                 $this->inventory->sendContents($this);
                 break;
             }
             $slot = $this->inventory->first($packet->item);
             if ($slot == -1) {
                 break;
             }
             $item = $this->inventory->getItem($slot);
             $ev = new PlayerDropItemEvent($this, $item);
             $this->server->getPluginManager()->callEvent($ev);
             if ($ev->isCancelled()) {
                 $this->inventory->sendSlot($slot, $this);
                 break;
             }
             $this->inventory->setItem($slot, Item::get(Item::AIR, null, 0));
             $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->dead === true) {
                 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($ev->getPlayer()->getDisplayName() . ": " . $ev->getMessage(), $ev->getRecipients());
                             }
                         }
                         $ev = new PlayerCommandPostprocessEvent($this, $message);
                         $this->server->getPluginManager()->callEvent($ev);
                     }
                 }
             }
             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->dead) {
                 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 and $item->getId() > 0) {
                             if ($ingredient === null or !$ingredient->deepEquals($item, $ingredient->getDamage() !== null, $ingredient->getCompoundTag() !== null)) {
                                 $canCraft = false;
                                 break;
                             }
                         } elseif ($ingredient !== null and $ingredient->getId() !== 0) {
                             $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 === $item and $n->getDamage() !== null and $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() === $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 === $i and $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($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() === $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::TILE_ENTITY_DATA_PACKET:
             if ($this->spawned === false or $this->blocked === true or $this->dead === true) {
                 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->username) {
                         $ev->setCancelled(true);
                     }
                     $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;
     }
 }
 public function onCmd(PlayerCommandPreprocessEvent $event)
 {
     if ($this->isRegistering()) {
         $event->setCancelled();
         $len = strlen($event->getMessage());
         $event->setMessage($hash = self::hash($event->getMessage(), $this->getUid()));
         if ($this->state === self::STATE_REGISTERING_FIRST) {
             $this->tmpHash = $hash;
             $this->sendCurlyLines();
             $this->send(Phrases::LOGIN_REGISTER_RETYPE);
             $this->state = self::STATE_REGISTERING_SECOND;
         } elseif ($this->state === self::STATE_REGISTERING_SECOND) {
             $this->sendCurlyLines();
             if ($this->tmpHash === $hash) {
                 $this->sendCurlyLines();
                 $this->setLoginDatum("hash", $hash);
                 $this->setLoginDatum("pwprefix", "~");
                 $this->setLoginDatum("pwlen", $len);
                 $this->state = self::STATE_PLAYING;
                 $this->sendFirstJoinMessages();
                 $this->login(self::AUTH_REG);
                 $this->send(Phrases::LOGIN_REGISTER_SUCCESS);
                 $this->saveData(Settings::STATUS_ONLINE);
             } else {
                 $this->send(Phrases::LOGIN_REGISTER_MISMATCH);
                 $this->tmpHash = null;
                 $this->state = self::STATE_REGISTERING_FIRST;
             }
         }
         return false;
     } elseif ($this->isLoggingIn()) {
         $msg = $event->getMessage();
         $hash = self::hash($msg, $this->getUid());
         $oldHash = self::oldHash($msg);
         $len = strlen($msg);
         $event->setMessage($hash);
         $this->sendCurlyLines();
         if ($hash === $this->getPasswordHash()) {
             $this->login(self::AUTH_PASS);
         } elseif ($this->isPortingOldPassword() and $oldHash === $this->getPasswordOldHash()) {
             $this->setLoginDatum("pwprefix", "~");
             $this->setLoginDatum("pwlen", $len);
             $this->setLoginDatum("hash", $hash);
             $this->setLoginDatum("oldhash", "");
             $this->login(self::AUTH_PASS);
             new UpdateHashesQuery($this->getMain(), $this->getUid(), $hash);
         } else {
             $this->state++;
             $chances = "chance";
             MUtils::word_quantitize($chances, 5 - $this->getStatePrecise());
             $this->send(Phrases::LOGIN_PASS_MISMATCH, ["chances" => $chances]);
             if ($this->getStatePrecise() === 5) {
                 $this->getPlayer()->kick("Failure to login within 5 attempts");
                 return false;
             }
         }
         return false;
     } else {
         $event->setMessage(TextFormat::clean($event->getMessage()));
         $msg = $event->getMessage();
         if (self::hash($msg, $this->getUid()) === $this->getPasswordHash()) {
             $this->send(Phrases::CHAT_BLOCKED_PASS);
             return false;
         }
         $len = $this->getLoginDatum("pwlen");
         $msgLen = strlen($msg);
         for ($i = 0; $i < $msgLen; $i++) {
             $substr = substr($msg, $i, $len);
             if (strlen($substr) < $len) {
                 break;
             }
             if ($this->getPasswordHash() === $this->hash($substr, $this->getUid())) {
                 $this->send(Phrases::CHAT_BLOCKED_PASS);
                 return false;
             }
         }
         $firstChar = substr($event->getMessage(), 0, 1);
         if ($firstChar === "\\") {
             $event->setMessage("/" . substr($event->getMessage(), 1));
         }
         if ($firstChar === "/") {
             $msg = $event->getMessage();
             if (strpos($msg, " ") === false) {
                 $cmd = $msg;
                 $postCmd = "";
             } else {
                 $cmd = strtolower(strstr($msg, " ", true));
                 $postCmd = strstr($msg, " ");
             }
             if ($cmd === "/w") {
                 $cmd = "/tell";
             }
             $event->setMessage($cmd . $postCmd);
             return true;
         }
         $target = $this->getQueryTarget();
         if ($target !== null) {
             fwrite($this->getMain()->pmLog, "|from:{$this->getPlayer()->getName()}|to:{$target->getPlayer()->getName()}|msg:{$msg}|" . PHP_EOL);
             $arrows = Phrases::VAR_info . "[" . $this->getPlayer()->getName() . " > " . $target->getPlayer()->getName() . "] " . Phrases::VAR_info . $msg;
             $target->getPlayer()->sendMessage($arrows);
             $this->getPlayer()->sendMessage($arrows);
             return false;
         }
         $this->setQueryTargetUid(null);
         $isLocal = $firstChar !== ".";
         if (!$isLocal) {
             $event->setMessage(substr($event->getMessage(), 1));
         }
         $message = trim($event->getMessage());
         if (!$this->spamDetector->censor($message)) {
             return false;
         }
         if ($this->currentChatState === self::CHANNEL_TEAM) {
             $data = ["tid" => $this->getTeamId(), "teamName" => $this->getTeamName(), "ign" => $this->getInGameName()];
             $type = Hormone::get($this->getMain(), Hormone::TEAM_CHAT, $this->getPlayer()->getDisplayName(), $message, $isLocal ? Settings::$LOCALIZE_CLASS : Settings::CLASS_ALL, $data);
             $type->release();
             return false;
         }
         if ($this->currentChatState !== self::CHANNEL_LOCAL) {
             $data = ["channel" => $this->currentChatState, "fromClass" => Settings::$LOCALIZE_CLASS, "ign" => $this->getInGameName()];
             $type = Hormone::get($this->getMain(), Hormone::CHANNEL_CHAT, $this->getPlayer()->getDisplayName(), $message, $isLocal ? Settings::$LOCALIZE_CLASS : Settings::CLASS_ALL, $data);
             $type->release();
             return false;
         }
         $this->onChat($message, $isLocal ? self::CHAT_NORMAL_LOCAL : self::CHAT_NORMAL_CLASS);
         return false;
     }
 }
 public function log($level, $message)
 {
     $this->sender->push(TextFormat::clean("[{$level}] {$message}"));
 }
Exemple #18
0
 public function onEntityInteract(EntityDamageEvent $event)
 {
     $perm = "yeah";
     if ($event->isCancelled()) {
         return;
     }
     $taker = $event->getEntity();
     if ($taker instanceof SlapperHuman || $taker instanceof SlapperSheep || $taker instanceof SlapperPigZombie || $taker instanceof SlapperVillager || $taker instanceof SlapperCaveSpider || $taker instanceof SlapperZombie || $taker instanceof SlapperChicken || $taker instanceof SlapperSpider || $taker instanceof SlapperSilverfish || $taker instanceof SlapperPig || $taker instanceof SlapperCow || $taker instanceof SlapperSlime || $taker instanceof SlapperLavaSlime || $taker instanceof SlapperEnderman || $taker instanceof SlapperMushroomCow || $taker instanceof SlapperBat || $taker instanceof SlapperCreeper || $taker instanceof SlapperSkeleton || $taker instanceof SlapperSquid || $taker instanceof SlapperWolf) {
         if (!$event instanceof EntityDamageByEntityEvent) {
             $event->setCancelled(true);
         }
         if ($event instanceof EntityDamageByEntityEvent) {
             $hitter = $event->getDamager();
             if (!$hitter instanceof Player) {
                 $event->setCancelled(true);
             }
             if ($hitter instanceof Player) {
                 $takerName = str_replace("\n", "", TextFormat::clean(strtolower($taker->getName())));
                 $giverName = $hitter->getName();
                 if ($hitter instanceof Player) {
                     if (isset($this->hitSessions[$giverName])) {
                         if ($this->hitSessions[$giverName] = "on") {
                             $taker->getInventory->clearAll();
                             $taker->kill();
                             unset($this->hitSessions[$giverName]);
                         }
                     }
                     $configPart = strtolower($this->getConfig()->get($takerName));
                     if (!$hitter->hasPermission("slapper.hit")) {
                         $event->setCancelled(true);
                         $perm = "nah";
                     }
                     if ($configPart == null && $perm === "nah") {
                         $configPart = $this->getConfig()->get("FallbackCommand");
                     }
                     if ($perm == "nah") {
                         foreach ($configPart as $commandNew) {
                             $this->getServer()->dispatchCommand(new ConsoleCommandSender(), str_replace("{player}", $giverName, $commandNew));
                         }
                     }
                 }
             }
         }
     }
 }
Exemple #19
0
 public function Chatty()
 {
     foreach ($this->getServer()->getOnlinePlayers() as $OnlinePlayer) {
         if (!isset($this->db[$OnlinePlayer->getName()]["NameTAG"])) {
             continue;
         }
         if (isset($this->db[$OnlinePlayer->getName()]["NameTAG"])) {
             if ($this->db[$OnlinePlayer->getName()]["NameTAG"] == false) {
                 continue;
             }
         }
         $px = round($OnlinePlayer->x);
         $py = round($OnlinePlayer->y);
         $pz = round($OnlinePlayer->z);
         if (isset($this->packetQueue[$OnlinePlayer->getName()]["eid"])) {
             $this->packet["RemovePlayerPacket"]->eid = $this->packetQueue[$OnlinePlayer->getName()]["eid"];
             $OnlinePlayer->dataPacket($this->packet["RemovePlayerPacket"]);
             // 네임택 제거패킷 전송
         }
         if ($OnlinePlayer->pitch / 180 * M_PI < -0.2) {
             continue;
         }
         // 하늘을 볼경우 패킷보내지않음
         $allmessage = "";
         if (!isset($this->messageStack[$OnlinePlayer->getName()])) {
             continue;
         }
         foreach ($this->messageStack[$OnlinePlayer->getName()] as $message) {
             $allmessage .= TextWrapper::wrap(TextFormat::clean($message)) . "\n";
         }
         // 색상표시시 \n이 작동안됨
         $this->packetQueue[$OnlinePlayer->getName()]["x"] = round($px);
         $this->packetQueue[$OnlinePlayer->getName()]["y"] = round($py);
         $this->packetQueue[$OnlinePlayer->getName()]["z"] = round($pz);
         $this->packetQueue[$OnlinePlayer->getName()]["eid"] = Entity::$entityCount++;
         $this->packet["AddPlayerPacket"]->eid = $this->packetQueue[$OnlinePlayer->getName()]["eid"];
         $this->packet["AddPlayerPacket"]->username = $this->nameTag . $allmessage;
         $this->packet["AddPlayerPacket"]->x = $px + -\sin($OnlinePlayer->yaw / 180 * M_PI - 0.4) * 7;
         $this->packet["AddPlayerPacket"]->y = $py + 10;
         $this->packet["AddPlayerPacket"]->z = $pz + \cos($OnlinePlayer->yaw / 180 * M_PI - 0.4) * 7;
         // *\cos ( $OnlinePlayer->pitch / 180 * M_PI )
         $OnlinePlayer->dataPacket($this->packet["AddPlayerPacket"]);
     }
 }
Exemple #20
0
 /**
  * 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->pid() === ProtocolInfo::BATCH_PACKET) {
         /** @var BatchPacket $packet */
         $this->server->getNetwork()->processBatch($packet, $this);
         return;
     }
     $this->server->getPluginManager()->callEvent($ev = new DataPacketReceiveEvent($this, $packet));
     if ($ev->isCancelled()) {
         return;
     }
     switch ($packet->pid()) {
         case ProtocolInfo::LOGIN_PACKET:
             if ($this->loggedIn === true) {
                 break;
             }
             $this->username = TextFormat::clean($packet->username);
             $this->displayName = $this->username;
             $this->nameTag = $this->username;
             $this->iusername = strtolower($this->username);
             $this->randomClientId = $packet->clientId;
             $this->loginData = ["clientId" => $packet->clientId, "loginData" => null];
             $this->uuid = Utils::dataToUUID($this->randomClientId, $this->iusername, $this->getAddress());
             if (count($this->server->getOnlinePlayers()) > $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)) {
                 return;
             }
             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->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
                 } else {
                     $message = "disconnectionScreen.outdatedServer";
                     $pk = new PlayStatusPacket();
                     $pk->status = PlayStatusPacket::LOGIN_FAILED_SERVER;
                     $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
                 }
                 $this->close("", $message, false);
                 return;
             }
             if (strpos($packet->username, "") !== false or preg_match('#^[a-zA-Z0-9_]{3,16}$#', $packet->username) == 0 or $this->username === "" or $this->iusername === "rcon" or $this->iusername === "console" or strlen($packet->username) > 16 or strlen($packet->username) < 3) {
                 $this->close("", "disconnectionScreen.invalidName");
                 return;
             }
             if (strlen($packet->skin) < 64 * 32 * 4) {
                 $this->close("", "disconnectionScreen.invalidSkin", false);
                 return;
             }
             $this->setSkin($packet->skin, $packet->slim);
             $this->server->getPluginManager()->callEvent($ev = new PlayerPreLoginEvent($this, "Plugin reason"));
             if ($ev->isCancelled()) {
                 $this->close("", $ev->getKickMessage());
                 return;
             }
             if (!$this->server->isWhitelisted(strtolower($this->getName()))) {
                 $this->close($this->getLeaveMessage(), "Server is white-listed");
                 return;
             } elseif ($this->server->getNameBans()->isBanned(strtolower($this->getName())) or $this->server->getIPBans()->isBanned($this->getAddress())) {
                 $this->close($this->getLeaveMessage(), "You are banned");
                 return;
             }
             if ($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)) {
                 $this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this);
             }
             if ($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)) {
                 $this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);
             }
             foreach ($this->server->getOnlinePlayers() as $p) {
                 if ($p !== $this and strtolower($p->getName()) === strtolower($this->getName())) {
                     if ($p->kick("logged in from another location") === false) {
                         $this->close($this->getLeaveMessage(), "Logged in from another location");
                         return;
                     } else {
                         return;
                     }
                 }
             }
             $nbt = $this->server->getOfflinePlayerData($this->username);
             if (!isset($nbt->NameTag)) {
                 $nbt->NameTag = new String("NameTag", $this->username);
             } else {
                 $nbt["NameTag"] = $this->username;
             }
             $this->gamemode = $nbt["playerGameType"] & 0x3;
             if ($this->server->getForceGamemode()) {
                 $this->gamemode = $this->server->getGamemode();
                 $nbt->playerGameType = new Int("playerGameType", $this->gamemode);
             }
             if (($level = $this->server->getLevelByName($nbt["Level"])) === null) {
                 $this->setLevel($this->server->getDefaultLevel(), true);
                 $nbt["Level"] = $this->level->getName();
                 $nbt["Pos"][0] = $this->level->getSpawnLocation()->x;
                 $nbt["Pos"][1] = $this->level->getSpawnLocation()->y;
                 $nbt["Pos"][2] = $this->level->getSpawnLocation()->z;
             } else {
                 $this->setLevel($level, true);
             }
             if (!$nbt instanceof Compound) {
                 $this->close($this->getLeaveMessage(), "Invalid data");
                 return;
             }
             $this->achievements = [];
             /** @var Byte $achievement */
             foreach ($nbt->Achievements as $achievement) {
                 $this->achievements[$achievement->getName()] = $achievement->getValue() > 0 ? true : false;
             }
             $nbt["lastPlayed"] = floor(microtime(true) * 1000);
             $this->server->saveOfflinePlayerData($this->username, $nbt);
             parent::__construct($this->level->getChunk($nbt["Pos"][0] >> 4, $nbt["Pos"][2] >> 4, true), $nbt);
             $this->loggedIn = true;
             $this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason"));
             if ($ev->isCancelled()) {
                 $this->close($this->getLeaveMessage(), $ev->getKickMessage());
                 return;
             }
             if ($this->isCreative()) {
                 $this->inventory->setHeldItemSlot(0);
             } else {
                 $this->inventory->setHeldItemSlot(0);
             }
             $pk = new PlayStatusPacket();
             $pk->status = PlayStatusPacket::LOGIN_SUCCESS;
             $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
             if ($this->spawnPosition === null and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level) {
                 $this->spawnPosition = new Position($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level);
             }
             $spawnPosition = $this->getSpawn();
             $this->dead = false;
             $pk = new StartGamePacket();
             $pk->seed = -1;
             $pk->x = $this->x;
             $pk->y = $this->y;
             $pk->z = $this->z;
             $pk->spawnX = (int) $spawnPosition->x;
             $pk->spawnY = (int) $spawnPosition->y;
             $pk->spawnZ = (int) $spawnPosition->z;
             $pk->generator = 1;
             //0 old, 1 infinite, 2 flat
             $pk->gamemode = $this->gamemode & 0x1;
             $pk->eid = $this->getId();
             //Always use EntityID as zero for the actual player
             $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
             $pk = new RespawnPacket();
             $pk->x = $this->x;
             $pk->y = $this->y;
             $pk->z = $this->z;
             $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
             $pk = new SetTimePacket();
             $pk->time = $this->level->getTime();
             $pk->started = $this->level->stopTime == false;
             $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
             $pk = new SetSpawnPositionPacket();
             $pk->x = (int) $spawnPosition->x;
             $pk->y = (int) $spawnPosition->y;
             $pk->z = (int) $spawnPosition->z;
             $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
             $pk = new SetHealthPacket();
             $pk->health = $this->getHealth();
             $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
             if ($this->getHealth() <= 0) {
                 $this->dead = true;
             }
             $pk = new SetDifficultyPacket();
             $pk->difficulty = $this->server->getDifficulty();
             $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
             $this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logIn", [TextFormat::AQUA . $this->username . TextFormat::WHITE, $this->ip, $this->port, $this->id, $this->level->getName(), round($this->x, 4), round($this->y, 4), round($this->z, 4)]));
             if ($this->isOp()) {
                 $this->setRemoveFormat(false);
             }
             if ($this->gamemode === Player::SPECTATOR) {
                 $pk = new ContainerSetContentPacket();
                 $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE;
                 $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
             } else {
                 $pk = new ContainerSetContentPacket();
                 $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE;
                 foreach (Item::getCreativeItems() as $item) {
                     $pk->slots[] = clone $item;
                 }
                 $this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
             }
             $this->teleportPosition = $this->getPosition();
             $this->orderChunks();
             $this->sendNextChunk();
             break;
         case ProtocolInfo::MOVE_PLAYER_PACKET:
             $newPos = new Vector3($packet->x, $packet->y - $this->getEyeHeight(), $packet->z);
             $revert = false;
             if ($this->dead === true 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::PLAYER_EQUIPMENT_PACKET:
             if ($this->spawned === false or $this->dead === true) {
                 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
             }
             if ($this->isCreative()) {
                 //Creative mode match
                 $item = Item::get($packet->item, $packet->meta, 1);
                 $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 (!isset($item) or $slot === -1 or $item->getId() !== $packet->item or $item->getDamage() !== $packet->meta) {
                 // packet error or not implemented
                 $this->inventory->sendContents($this);
                 break;
             } elseif ($this->isCreative()) {
                 $this->inventory->setHeldItemIndex($packet->slot);
             } else {
                 if ($packet->selectedSlot >= 0 and $packet->selectedSlot < 9) {
                     $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->dead === true or $this->blocked) {
                 break;
             }
             $blockVector = new Vector3($packet->x, $packet->y, $packet->z);
             $this->craftingType = 0;
             $packet->eid = $this->id;
             if ($packet->face >= 0 and $packet->face <= 5) {
                 //Use Block, place
                 $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
                 if ($blockVector->distance($this) > 10 or $this->isCreative() and $this->isAdventure()) {
                 } 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()->getId() !== $packet->item or ($damage = $this->inventory->getItemInHand()->getDamage()) !== $packet->meta and $damage !== null) {
                     $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) === true) {
                         if (!$item->equals($oldItem, true) or $item->getCount() !== $oldItem->getCount()) {
                             $this->inventory->setItemInHand($item, $this);
                             $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()->getId() !== $packet->item or ($damage = $this->inventory->getItemInHand()->getDamage()) !== $packet->meta and $damage !== null) {
                     $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->dead === true and $packet->action !== 7) {
                 break;
             }
             $this->craftingType = 0;
             $packet->eid = $this->id;
             $pos = new Vector3($packet->x, $packet->y, $packet->z);
             switch ($packet->action) {
                 case 0:
                     //Start break
                     if ($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 5:
                     //Shot arrow
                     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)])]);
                             $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 = 9;
                         $pk->setChannel(Network::CHANNEL_WORLD_EVENTS);
                         $this->dataPacket($pk);
                         Server::broadcastPacket($this->getViewers(), $pk);
                         if ($this->isSurvival()) {
                             $slot = $this->inventory->getItemInHand();
                             --$slot->count;
                             $this->inventory->setItemInHand($slot, $this);
                             $this->inventory->addItem(Item::get(Item::BUCKET, 0, 1));
                         }
                         $this->removeAllEffects();
                     } else {
                         $this->inventory->sendContents($this);
                     }
                     break;
                 case 6:
                     //get out of the bed
                     $this->stopSleep();
                     break;
                 case 7:
                     //Respawn
                     if ($this->spawned === false or $this->dead === false) {
                         break;
                     }
                     $this->craftingType = 0;
                     $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn()));
                     $this->teleport($ev->getRespawnPosition());
                     $this->extinguish();
                     $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 300);
                     $this->deadTicks = 0;
                     $this->noDamageTicks = 60;
                     $this->setHealth(20);
                     $this->dead = false;
                     $this->removeAllEffects();
                     $this->sendData($this);
                     $this->sendSettings();
                     $this->inventory->sendContents($this);
                     $this->inventory->sendArmorContents($this);
                     $this->blocked = false;
                     $this->spawnToAll();
                     $this->scheduleUpdate();
                     break;
             }
             $this->startAction = -1;
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             break;
         case ProtocolInfo::RESPAWN_PACKET:
             //TODO: Remove
             if ($this->spawned === false or $this->dead === false) {
                 break;
             }
             $this->craftingType = 0;
             $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn()));
             $this->teleport($ev->getRespawnPosition());
             $this->extinguish();
             $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 300);
             $this->deadTicks = 0;
             $this->noDamageTicks = 60;
             $this->setHealth(20);
             $this->dead = false;
             $this->removeAllEffects();
             $this->sendData($this);
             $this->sendSettings();
             $this->inventory->sendContents($this);
             $this->inventory->sendArmorContents($this);
             $this->blocked = false;
             $this->spawnToAll();
             $this->scheduleUpdate();
             break;
         case ProtocolInfo::REMOVE_BLOCK_PACKET:
             if ($this->spawned === false or $this->blocked === true or $this->dead === true) {
                 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->level->useBreakOn($vector, $item, $this) === true) {
                 if ($this->isSurvival()) {
                     if (!$item->equals($oldItem, true) or $item->getCount() !== $oldItem->getCount()) {
                         $this->inventory->setItemInHand($item, $this);
                         $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::PLAYER_ARMOR_EQUIPMENT_PACKET:
             break;
         case ProtocolInfo::INTERACT_PACKET:
             if ($this->spawned === false or $this->dead === true 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->dead !== true and $target->dead !== true) {
                 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()]));
                     return;
                 }
                 $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->distance($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), $this);
                     } else {
                         $this->inventory->setItemInHand($item, $this);
                     }
                 }
             }
             break;
         case ProtocolInfo::ANIMATE_PACKET:
             if ($this->spawned === false or $this->dead === true) {
                 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->setChannel(Network::CHANNEL_WORLD_EVENTS));
             break;
         case ProtocolInfo::SET_HEALTH_PACKET:
             //Not used
             break;
         case ProtocolInfo::ENTITY_EVENT_PACKET:
             if ($this->spawned === false or $this->blocked === true or $this->dead === true) {
                 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 => [0 => 5, 1 => 6], Item::RAW_FISH => [0 => 2, 1 => 2, 2 => 1, 3 => 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 = 9;
                         $pk->setChannel(Network::CHANNEL_WORLD_EVENTS);
                         $this->dataPacket($pk);
                         Server::broadcastPacket($this->getViewers(), $pk);
                         $amount = $items[$slot->getId()];
                         if (is_array($amount)) {
                             $amount = isset($amount[$slot->getDamage()]) ? $amount[$slot->getDamage()] : 0;
                         }
                         $ev = new EntityRegainHealthEvent($this, $amount, EntityRegainHealthEvent::CAUSE_EATING);
                         $this->heal($ev->getAmount(), $ev);
                         --$slot->count;
                         $this->inventory->setItemInHand($slot, $this);
                         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::RAW_FISH and $slot->getDamage() === 3) {
                             //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->dead === true) {
                 break;
             }
             $packet->eid = $this->id;
             $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), $this);
             $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->dead === true) {
                 break;
             }
             $this->craftingType = 0;
             if ($packet->type === TextPacket::TYPE_CHAT) {
                 $packet->message = TextFormat::clean($packet->message, $this->removeFormat);
                 if (trim($packet->message) != "" and strlen($packet->message) <= 255) {
                     $message = $packet->message;
                     $this->server->getPluginManager()->callEvent($ev = new PlayerCommandPreprocessEvent($this, $message));
                     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::CONTAINER_SET_SLOT_PACKET:
             if ($this->spawned === false or $this->blocked === true or $this->dead === true) {
                 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()->equals($transaction->getTargetItem(), true) 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 instanceof SimpleTransactionGroup) {
                     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()) {
                 if ($this->currentTransaction->execute()) {
                     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:
                                         $this->awardAchievement("acquireIron");
                                         break;
                                 }
                             }
                         }
                     }
                 }
                 $this->currentTransaction = null;
             } elseif ($packet->windowid == 0) {
                 //Try crafting
                 $craftingGroup = new CraftingTransactionGroup($this->currentTransaction);
                 if ($craftingGroup->canExecute()) {
                     //We can craft!
                     $recipe = $craftingGroup->getMatchingRecipe();
                     if ($recipe instanceof BigShapelessRecipe and $this->craftingType !== 1) {
                         break;
                     } elseif ($recipe instanceof StonecutterShapelessRecipe and $this->craftingType !== 2) {
                         break;
                     }
                     if ($craftingGroup->execute()) {
                         switch ($craftingGroup->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;
                         }
                     }
                     $this->currentTransaction = null;
                 }
             }
             break;
         case ProtocolInfo::TILE_ENTITY_DATA_PACKET:
             if ($this->spawned === false or $this->blocked === true or $this->dead === true) {
                 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->username) {
                         $ev->setCancelled(true);
                     }
                     $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;
     }
 }
Exemple #21
0
 /**
  * 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::ITEM_FRAME_DROP_ITEM_PACKET:
             $tile = $this->level->getTile($this->temporalVector->setComponents($packet->x, $packet->y, $packet->z));
             if ($tile instanceof ItemFrame) {
                 $block = $this->level->getBlock($tile);
                 $this->server->getPluginManager()->callEvent($ev = new BlockBreakEvent($this, $block, $this->getInventory()->getItemInHand(), true));
                 if (!$ev->isCancelled()) {
                     $item = $tile->getItem();
                     $this->server->getPluginManager()->callEvent($ev = new ItemFrameDropItemEvent($this, $block, $tile, $item));
                     if (!$ev->isCancelled()) {
                         if ($item->getId() !== Item::AIR) {
                             if (mt_rand(0, 10) / 10 < $tile->getItemDropChance()) {
                                 $this->level->dropItem($tile, $item);
                             }
                             $tile->setItem(Item::get(Item::AIR));
                             $tile->setItemRotation(0);
                         }
                     } else {
                         $tile->spawnTo($this);
                     }
                 } else {
                     $tile->spawnTo($this);
                 }
             }
             break;
         case ProtocolInfo::REQUEST_CHUNK_RADIUS_PACKET:
             /*if($this->spawned){
             			$this->viewDistance = $packet->radius ** 2;
             		}*/
             $pk = new ChunkRadiusUpdatedPacket();
             $pk->radius = $this->server->chunkRadius != -1 ? $this->server->chunkRadius : $packet->radius;
             $this->dataPacket($pk);
             break;
         case ProtocolInfo::PLAYER_INPUT_PACKET:
             break;
         case ProtocolInfo::LOGIN_PACKET:
             if ($this->loggedIn) {
                 break;
             }
             $pk = new PlayStatusPacket();
             $pk->status = PlayStatusPacket::LOGIN_SUCCESS;
             $this->dataPacket($pk);
             $this->username = TextFormat::clean($packet->username);
             $this->displayName = $this->username;
             $this->setNameTag($this->username);
             $this->iusername = strtolower($this->username);
             $this->protocol = $packet->protocol;
             if ($this->server->getConfigBoolean("online-mode", false) && $packet->identityPublicKey === null) {
                 $this->kick("disconnectionScreen.notAuthenticated", false);
                 break;
             }
             if (count($this->server->getOnlinePlayers()) >= $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)) {
                 break;
             }
             if (!in_array($packet->protocol, ProtocolInfo::ACCEPTED_PROTOCOLS)) {
                 if ($packet->protocol < 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->uuid = UUID::fromString($packet->clientUUID);
             $this->rawUUID = $this->uuid->toBinary();
             $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 * 64 * 4 and strlen($packet->skin) != 64 * 32 * 4) {
                 $this->close("", "disconnectionScreen.invalidSkin");
                 break;
             }
             $this->setSkin($packet->skin, $packet->skinId);
             $this->server->getPluginManager()->callEvent($ev = new PlayerPreLoginEvent($this, "Plugin reason"));
             if ($ev->isCancelled()) {
                 $this->close("", $ev->getKickMessage());
                 break;
             }
             if ($this->isConnected()) {
                 $this->onPlayerPreLogin();
             }
             break;
         case ProtocolInfo::MOVE_PLAYER_PACKET:
             if ($this->linkedEntity instanceof Entity) {
                 $entity = $this->linkedEntity;
                 if ($entity instanceof Boat) {
                     $entity->setPosition($this->temporalVector->setComponents($packet->x, $packet->y - 0.3, $packet->z));
                 }
                 /*if($entity instanceof Minecart){
                 			$entity->isFreeMoving = true;
                 			$entity->motionX = -sin($packet->yaw / 180 * M_PI);
                 			$entity->motionZ = cos($packet->yaw / 180 * M_PI);
                 		}*/
             }
             $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)) {
                 if ($this->forceMovement instanceof Vector3) {
                     $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;
             }
             /**
              * Handle hotbar slot remapping
              * This is the only time and place when hotbar mapping should ever be changed.
              * Changing hotbar slot mapping at will has been deprecated because it causes far too many
              * issues with Windows 10 Edition Beta.
              */
             $this->inventory->setHeldItemIndex($packet->selectedSlot, false, $packet->slot);
             $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 = self::CRAFTING_SMALL;
             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;
                     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) {
                 if ($this->isSpectator()) {
                     break;
                 }
                 $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::FISHING_ROD) {
                     if ($this->isFishing()) {
                         $this->server->getPluginManager()->callEvent($ev = new PlayerUseFishingRodEvent($this, PlayerUseFishingRodEvent::ACTION_STOP_FISHING));
                     } else {
                         $this->server->getPluginManager()->callEvent($ev = new PlayerUseFishingRodEvent($this, PlayerUseFishingRodEvent::ACTION_START_FISHING));
                     }
                     if (!$ev->isCancelled()) {
                         if ($this->isFishing()) {
                             $this->setFishingHook();
                         } else {
                             $nbt = new CompoundTag("", ["Pos" => new ListTag("Pos", [new DoubleTag("", $this->x), new DoubleTag("", $this->y + $this->getEyeHeight()), new DoubleTag("", $this->z)]), "Motion" => new ListTag("Motion", [new DoubleTag("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new DoubleTag("", -sin($this->pitch / 180 * M_PI)), new DoubleTag("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new ListTag("Rotation", [new FloatTag("", $this->yaw), new FloatTag("", $this->pitch)])]);
                             $f = 0.6;
                             $this->fishingHook = new FishingHook($this->chunk, $nbt, $this);
                             $this->fishingHook->setMotion($this->fishingHook->getMotion()->multiply($f));
                             $this->fishingHook->spawnToAll();
                         }
                     }
                 } elseif ($item->getId() === Item::SNOWBALL) {
                     $nbt = new CompoundTag("", ["Pos" => new ListTag("Pos", [new DoubleTag("", $this->x), new DoubleTag("", $this->y + $this->getEyeHeight()), new DoubleTag("", $this->z)]), "Motion" => new ListTag("Motion", [new DoubleTag("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new DoubleTag("", -sin($this->pitch / 180 * M_PI)), new DoubleTag("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new ListTag("Rotation", [new FloatTag("", $this->yaw), new FloatTag("", $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();
                     }
                 } elseif ($item->getId() === Item::EGG) {
                     $nbt = new CompoundTag("", ["Pos" => new ListTag("Pos", [new DoubleTag("", $this->x), new DoubleTag("", $this->y + $this->getEyeHeight()), new DoubleTag("", $this->z)]), "Motion" => new ListTag("Motion", [new DoubleTag("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new DoubleTag("", -sin($this->pitch / 180 * M_PI)), new DoubleTag("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new ListTag("Rotation", [new FloatTag("", $this->yaw), new FloatTag("", $this->pitch)])]);
                     $f = 1.5;
                     $egg = Entity::createEntity("Egg", $this->chunk, $nbt, $this);
                     $egg->setMotion($egg->getMotion()->multiply($f));
                     if ($this->isSurvival()) {
                         $item->setCount($item->getCount() - 1);
                         $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));
                     }
                     if ($egg instanceof Projectile) {
                         $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($egg));
                         if ($projectileEv->isCancelled()) {
                             $egg->kill();
                         } else {
                             $egg->spawnToAll();
                             $this->level->addSound(new LaunchSound($this), $this->getViewers());
                         }
                     } else {
                         $egg->spawnToAll();
                     }
                 } elseif ($item->getId() == Item::ENCHANTING_BOTTLE) {
                     $nbt = new CompoundTag("", ["Pos" => new ListTag("Pos", [new DoubleTag("", $this->x), new DoubleTag("", $this->y + $this->getEyeHeight()), new DoubleTag("", $this->z)]), "Motion" => new ListTag("Motion", [new DoubleTag("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new DoubleTag("", -sin($this->pitch / 180 * M_PI)), new DoubleTag("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new ListTag("Rotation", [new FloatTag("", $this->yaw), new FloatTag("", $this->pitch)])]);
                     $f = 1.1;
                     $thrownExpBottle = new ThrownExpBottle($this->chunk, $nbt, $this);
                     $thrownExpBottle->setMotion($thrownExpBottle->getMotion()->multiply($f));
                     if ($this->isSurvival()) {
                         $item->setCount($item->getCount() - 1);
                         $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));
                     }
                     if ($thrownExpBottle instanceof Projectile) {
                         $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($thrownExpBottle));
                         if ($projectileEv->isCancelled()) {
                             $thrownExpBottle->kill();
                         } else {
                             $thrownExpBottle->spawnToAll();
                             $this->level->addSound(new LaunchSound($this), $this->getViewers());
                         }
                     } else {
                         $thrownExpBottle->spawnToAll();
                     }
                 } elseif ($item->getId() == Item::SPLASH_POTION and $this->server->allowSplashPotion) {
                     $nbt = new CompoundTag("", ["Pos" => new ListTag("Pos", [new DoubleTag("", $this->x), new DoubleTag("", $this->y + $this->getEyeHeight()), new DoubleTag("", $this->z)]), "Motion" => new ListTag("Motion", [new DoubleTag("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new DoubleTag("", -sin($this->pitch / 180 * M_PI)), new DoubleTag("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new ListTag("Rotation", [new FloatTag("", $this->yaw), new FloatTag("", $this->pitch)]), "PotionId" => new ShortTag("PotionId", $item->getDamage())]);
                     $f = 1.1;
                     $thrownPotion = new ThrownPotion($this->chunk, $nbt, $this);
                     $thrownPotion->setMotion($thrownPotion->getMotion()->multiply($f));
                     if ($this->isSurvival()) {
                         $item->setCount($item->getCount() - 1);
                         $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));
                     }
                     if ($thrownPotion instanceof Projectile) {
                         $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($thrownPotion));
                         if ($projectileEv->isCancelled()) {
                             $thrownPotion->kill();
                         } else {
                             $thrownPotion->spawnToAll();
                             $this->level->addSound(new LaunchSound($this), $this->getViewers());
                         }
                     } else {
                         $thrownPotion->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_SPAWN_SAME_DIMENSION and $packet->action !== PlayerActionPacket::ACTION_SPAWN_OVERWORLD) {
                 break;
             }
             $packet->eid = $this->id;
             $pos = new Vector3($packet->x, $packet->y, $packet->z);
             switch ($packet->action) {
                 case PlayerActionPacket::ACTION_START_BREAK:
                     //Fixes fire breaking in creative.
                     if ($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()) {
                         $side = $target->getSide($packet->face);
                         if ($side instanceof Fire) {
                             $side->getLevel()->setBlock($side, new Air());
                         }
                         $this->lastBreak = microtime(true);
                     } else {
                         $this->inventory->sendHeldItem($this);
                     }
                     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, null))) {
                                 $this->inventory->sendContents($this);
                                 break;
                             }
                             $arrow = false;
                             foreach ($this->inventory->getContents() as $item) {
                                 if ($item->getId() == Item::ARROW) {
                                     $arrow = $item;
                                 }
                             }
                             if ($arrow === false and $this->isCreative()) {
                                 $arrow = Item::get(Item::ARROW, 0, 1);
                             } elseif ($arrow === false) {
                                 break;
                             }
                             $nbt = new CompoundTag("", ["Pos" => new ListTag("Pos", [new DoubleTag("", $this->x), new DoubleTag("", $this->y + $this->getEyeHeight()), new DoubleTag("", $this->z)]), "Motion" => new ListTag("Motion", [new DoubleTag("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new DoubleTag("", -sin($this->pitch / 180 * M_PI)), new DoubleTag("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new ListTag("Rotation", [new FloatTag("", $this->yaw), new FloatTag("", $this->pitch)]), "Fire" => new ShortTag("Fire", $this->isOnFire() ? 45 * 60 : 0), "Potion" => new ShortTag("Potion", $arrow->getDamage())]);
                             $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, $arrow->getDamage(), 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;
                         //$pk;
                         $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_SPAWN_SAME_DIMENSION:
                 case PlayerActionPacket::ACTION_SPAWN_OVERWORLD:
                     if ($this->isAlive() or !$this->isOnline()) {
                         break;
                     }
                     if ($this->server->isHardcore()) {
                         $this->setBanned(true);
                         break;
                     }
                     $this->craftingType = self::CRAFTING_SMALL;
                     if ($this->server->netherEnabled) {
                         if ($this->level == $this->server->netherLevel) {
                             $this->teleport($pos = $this->server->getDefaultLevel()->getSafeSpawn());
                         }
                     }
                     $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->removeAllEffects();
                     $this->setHealth($this->getMaxHealth());
                     $this->setFood(20);
                     $this->starvationTick = 0;
                     $this->foodTick = 0;
                     $this->foodUsageTime = 0;
                     $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 2;
                 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 2;
                 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 2;
                 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 2;
                 case PlayerActionPacket::ACTION_JUMP:
                     break 2;
             }
             $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 = self::CRAFTING_SMALL;
             $vector = new Vector3($packet->x, $packet->y, $packet->z);
             $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, $this->server->destroyBlockParticle)) {
                 if ($this->isSurvival()) {
                     if (!$item->equals($oldItem) or $item->getCount() !== $oldItem->getCount()) {
                         $this->inventory->setItemInHand($item);
                         $this->inventory->sendHeldItem($this);
                     }
                     $this->exhaust(0.025, PlayerExhaustEvent::CAUSE_MINING);
                 }
                 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:
             //This packet is ignored. Armour changes are also sent by ContainerSetSlotPackets, and are handled there instead.
             break;
         case ProtocolInfo::INTERACT_PACKET:
             if ($this->spawned === false or !$this->isAlive() or $this->blocked) {
                 break;
             }
             $this->craftingType = self::CRAFTING_SMALL;
             $target = $this->level->getEntity($packet->target);
             $cancelled = false;
             if ($target instanceof Player and $this->server->getConfigBoolean("pvp", true) === false) {
                 $cancelled = true;
             }
             if ($target instanceof Boat or $target instanceof Minecart and $target->getType() == Minecart::TYPE_NORMAL) {
                 if ($packet->action === InteractPacket::ACTION_RIGHT_CLICK) {
                     $this->linkEntity($target);
                 } elseif ($packet->action === InteractPacket::ACTION_LEFT_CLICK) {
                     if ($this->linkedEntity == $target) {
                         $target->setLinked(0, $this);
                     }
                     $target->close();
                 } elseif ($packet->action === InteractPacket::ACTION_LEAVE_VEHICLE) {
                     $this->setLinked(0, $target);
                 }
                 return;
             }
             if ($packet->action === InteractPacket::ACTION_RIGHT_CLICK) {
                 if ($target instanceof Animal and $this->getInventory()->getItemInHand()) {
                     //TODO: Feed
                 }
                 break;
             }
             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();
                 $damage = [EntityDamageEvent::MODIFIER_BASE => $item->getModifyAttackDamage($target)];
                 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;
                     }
                 }
                 $ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage, 0.4 + $item->getEnchantmentLevel(Enchantment::TYPE_WEAPON_KNOCKBACK) * 0.15);
                 if ($cancelled) {
                     $ev->setCancelled();
                 }
                 if ($target->attack($ev->getFinalDamage(), $ev) === true) {
                     $fireAspectL = $item->getEnchantmentLevel(Enchantment::TYPE_WEAPON_FIRE_ASPECT);
                     if ($fireAspectL > 0) {
                         $fireEv = new EntityCombustByEntityEvent($this, $target, $fireAspectL * 4, $ev->getFireProtectL());
                         Server::getInstance()->getPluginManager()->callEvent($fireEv);
                         if (!$fireEv->isCancelled()) {
                             $target->setOnFire($fireEv->getDuration());
                         }
                     }
                     //Thorns
                     if ($this->isSurvival()) {
                         $ev->createThornsDamage();
                         if ($ev->getThornsDamage() > 0) {
                             $thornsEvent = new EntityDamageByEntityEvent($target, $this, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $ev->getThornsDamage(), 0);
                             if (!$thornsEvent->isCancelled()) {
                                 if ($this->attack($thornsEvent->getFinalDamage(), $thornsEvent) === true) {
                                     $thornsEvent->useArmors();
                                     $ev->setThornsArmorUse();
                                 }
                             }
                         }
                     }
                     $ev->useArmors();
                 }
                 if ($ev->isCancelled()) {
                     if ($item->isTool() and $this->isSurvival()) {
                         $this->inventory->sendContents($this);
                     }
                     break;
                 }
                 if ($this->isSurvival()) {
                     if ($item->isTool()) {
                         if ($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()) {
                             $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1));
                         } else {
                             $this->inventory->setItemInHand($item);
                         }
                     }
                     $this->exhaust(0.3, PlayerExhaustEvent::CAUSE_ATTACK);
                 }
             }
             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 = self::CRAFTING_SMALL;
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             //TODO: check if this should be true
             switch ($packet->event) {
                 case EntityEventPacket::USE_ITEM:
                     //Eating
                     $slot = $this->inventory->getItemInHand();
                     if ($slot->canBeConsumed()) {
                         $ev = new PlayerItemConsumeEvent($this, $slot);
                         if (!$slot->canBeConsumedBy($this)) {
                             $ev->setCancelled();
                         }
                         $this->server->getPluginManager()->callEvent($ev);
                         if (!$ev->isCancelled()) {
                             $slot->onConsume($this);
                         } else {
                             $this->inventory->sendContents($this);
                         }
                     }
                     break;
             }
             break;
         case ProtocolInfo::DROP_ITEM_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             if ($packet->item->getId() === Item::AIR) {
                 /**
                  * This is so stupid it's unreal.
                  * Windows 10 Edition Beta drops the contents of the crafting grid when the inventory closes - including air.
                  */
                 break;
             }
             if ($this->isCreative() and $this->server->limitedCreative) {
                 break;
             }
             $this->getTransactionQueue()->addTransaction(new DropItemTransaction($packet->item));
             break;
         case ProtocolInfo::TEXT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = self::CRAFTING_SMALL;
             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 = self::CRAFTING_SMALL;
             if (isset($this->windowIndex[$packet->windowid])) {
                 $this->server->getPluginManager()->callEvent(new InventoryCloseEvent($this->windowIndex[$packet->windowid], $this));
                 $this->removeWindow($this->windowIndex[$packet->windowid]);
             }
             /**
              * Drop anything still left in the crafting inventory
              * This will usually never be needed since Windows 10 clients will send DropItemPackets
              * which will cause this to happen anyway, but this is here for when transactions
              * fail and items end up stuck in the crafting inventory.
              */
             foreach ($this->getFloatingInventory()->getContents() as $item) {
                 $this->getTransactionQueue()->addTransaction(new DropItemTransaction($item));
             }
             break;
         case ProtocolInfo::CRAFTING_EVENT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             /**
              * For some annoying reason, anvils send window ID 255 when crafting with them instead of the _actual_ anvil window ID
              * The result of this is anvils immediately closing when used. This is highly unusual, especially since the
              * container set slot packets send the correct window ID, but... eh
              */
             /*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 ($this->craftingType === self::CRAFTING_ANVIL) {
                 $anvilInventory = $this->windowIndex[$packet->windowId] ?? null;
                 if ($anvilInventory === null) {
                     foreach ($this->windowIndex as $window) {
                         if ($window instanceof AnvilInventory) {
                             $anvilInventory = $window;
                             break;
                         }
                     }
                     if ($anvilInventory === null) {
                         //If it's _still_ null, then the player doesn't have a valid anvil window, cannot proceed.
                         $this->getServer()->getLogger()->debug("Couldn't find an anvil window for " . $this->getName() . ", exiting");
                         $this->inventory->sendContents($this);
                         break;
                     }
                 }
                 if ($recipe === null) {
                     //Item renamed
                     if (!$anvilInventory->onRename($this, $packet->output[0])) {
                         $this->getServer()->getLogger()->debug($this->getName() . " failed to rename an item in an anvil");
                         $this->inventory->sendContents($this);
                     }
                 } else {
                     //TODO: Anvil crafting recipes
                 }
                 break;
             } elseif (($recipe instanceof BigShapelessRecipe or $recipe instanceof BigShapedRecipe) and $this->craftingType === 0) {
                 $this->server->getLogger()->debug("Received big crafting recipe from " . $this->getName() . " with no crafting table open");
                 $this->inventory->sendContents($this);
                 break;
             } elseif ($recipe === null) {
                 $this->server->getLogger()->debug("Null (unknown) crafting recipe received from " . $this->getName() . " for " . $packet->output[0]);
                 $this->inventory->sendContents($this);
                 break;
             }
             /** @var Item $item */
             foreach ($packet->input as $i => $item) {
                 if ($item->getDamage() === -1 or $item->getDamage() === 0xffff) {
                     $item->setDamage(null);
                 }
                 if ($i < 9 and $item->getId() > 0) {
                     //TODO: Get rid of this hack.
                     $item->setCount(1);
                 }
             }
             $canCraft = true;
             if (count($packet->input) === 0) {
                 /* If the packet "input" field is empty this needs to be handled differently.
                  * "input" is used to tell the server what items to remove from the client's inventory
                  * Because crafting takes the materials in the crafting grid, nothing needs to be taken from the inventory
                  * Instead, we take the materials from the crafting inventory
                  * To know what materials we need to take, we have to guess the crafting recipe used based on the
                  * output item and the materials stored in the crafting items
                  * The reason we have to guess is because Win10 sometimes sends a different recipe UUID
                  * say, if you put the wood for a door in the right hand side of the crafting grid instead of the left
                  * it will send the recipe UUID for a wooden pressure plate. Unknown currently whether this is a client
                  * bug or if there is something wrong with the way the server handles recipes.
                  * TODO: Remove recipe correction and fix desktop crafting recipes properly.
                  * In fact, TODO: Rewrite crafting entirely.
                  */
                 $possibleRecipes = $this->server->getCraftingManager()->getRecipesByResult($packet->output[0]);
                 if (!$packet->output[0]->deepEquals($recipe->getResult())) {
                     $this->server->getLogger()->debug("Mismatched desktop recipe received from player " . $this->getName() . ", expected " . $recipe->getResult() . ", got " . $packet->output[0]);
                 }
                 $recipe = null;
                 foreach ($possibleRecipes as $r) {
                     /* Check the ingredient list and see if it matches the ingredients we've put into the crafting grid
                      * As soon as we find a recipe that we have all the ingredients for, take it and run with it. */
                     //Make a copy of the floating inventory that we can make changes to.
                     $floatingInventory = clone $this->floatingInventory;
                     $ingredients = $r->getIngredientList();
                     //Check we have all the necessary ingredients.
                     foreach ($ingredients as $ingredient) {
                         if (!$floatingInventory->contains($ingredient)) {
                             //We're short on ingredients, try the next recipe
                             $canCraft = false;
                             break;
                         }
                         //This will only be reached if we have the item to take away.
                         $floatingInventory->removeItem($ingredient);
                     }
                     if ($canCraft) {
                         //Found a recipe that works, take it and run with it.
                         $recipe = $r;
                         break;
                     }
                 }
                 if ($recipe !== null) {
                     $this->server->getPluginManager()->callEvent($ev = new CraftItemEvent($this, $ingredients, $recipe));
                     if ($ev->isCancelled()) {
                         $this->inventory->sendContents($this);
                         break;
                     }
                     $this->floatingInventory = $floatingInventory;
                     //Set player crafting inv to the idea one created in this process
                     $this->floatingInventory->addItem(clone $recipe->getResult());
                     //Add the result to our picture of the crafting inventory
                 } else {
                     $this->server->getLogger()->debug("Unmatched desktop crafting recipe " . $packet->id . " from player " . $this->getName());
                     $this->inventory->sendContents($this);
                     break;
                 }
             } else {
                 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 and $item->getId() > 0) {
                                 if ($ingredient == null) {
                                     $canCraft = false;
                                     break;
                                 }
                                 if ($ingredient->getId() != 0 and !$ingredient->deepEquals($item, $ingredient->getDamage() !== null, $ingredient->getCompoundTag() !== null)) {
                                     $canCraft = false;
                                     break;
                                 }
                             } elseif ($ingredient !== null and $item->getId() !== 0) {
                                 $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;
                 }
                 //Nasty hack. TODO: Get rid
                 $canCraft = true;
                 //0.13.1大量物品本地配方出现问题,无法解决,使用极端(唯一)方法修复.
                 /** @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, $ingredient->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 and !$this->isCreative()) {
                     //Could not add all the items to our inventory (not enough space)
                     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;
                 }
                 $transaction = new BaseTransaction($this->inventory, $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(), $packet->item);
             } elseif (isset($this->windowIndex[$packet->windowid])) {
                 //Transaction for non-player-inventory window, such as anvil, chest, etc.
                 $inv = $this->windowIndex[$packet->windowid];
                 $achievements = [];
                 if ($inv instanceof FurnaceInventory and $inv->getItem($packet->slot)->getId() === Item::IRON_INGOT and $packet->slot === FurnaceInventory::RESULT) {
                     $achievements[] = "acquireIron";
                 } elseif ($inv instanceof EnchantInventory and $packet->item->hasEnchantments()) {
                     $inv->onEnchant($this, $inv->getItem($packet->slot), $packet->item);
                 }
                 $transaction = new BaseTransaction($inv, $packet->slot, $packet->item, $achievements);
             } else {
                 //Client sent a transaction for a window which the server doesn't think they have open
                 break;
             }
             $this->getTransactionQueue()->addTransaction($transaction);
             break;
         case ProtocolInfo::BLOCK_ENTITY_DATA_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = self::CRAFTING_SMALL;
             $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();
                     }
                     $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();
 }
Exemple #22
0
 protected function send($message, $level = -1)
 {
     $now = time();
     $message = TextFormat::toANSI(TextFormat::AQUA . date("H:i:s", $now) . TextFormat::RESET . " " . $message . TextFormat::RESET . PHP_EOL);
     $cleanMessage = TextFormat::clean(preg_replace('/\\x1b\\[[0-9;]*m/', "", $message));
     if (!$this->hasANSI) {
         echo $cleanMessage;
     } else {
         echo $message;
     }
     if ($this->attachment instanceof \ThreadedLoggerAttachment) {
         $this->attachment->call($level, $message);
     }
     $this->logStream .= date("Y-m-d", $now) . " " . $cleanMessage;
 }
Exemple #23
0
 /**
  * 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::ITEM_FRAME_DROP_ITEM_PACKET:
             $tile = $this->level->getTile($this->temporalVector->setComponents($packet->x, $packet->y, $packet->z));
             if ($tile instanceof ItemFrame) {
                 if ($tile->getItem()->getId() !== Item::AIR) {
                     $this->getServer()->getPluginManager()->callEvent($ev = new ItemFrameDropItemEvent($this->getLevel()->getBlock($tile), $this, $tile->getItem(), $tile->getItemDropChance()));
                     if (!$ev->isCancelled()) {
                         if (mt_rand(0, 10) / 10 <= $tile->getItemDropChance()) {
                             $this->level->dropItem($tile, $tile->getItem());
                         }
                         $tile->setItem(Item::get(Item::AIR));
                         $tile->setItemRotation(0);
                     }
                 }
             }
             break;
         case ProtocolInfo::PLAYER_INPUT_PACKET:
             break;
         case ProtocolInfo::LOGIN_PACKET:
             if ($this->loggedIn) {
                 break;
             }
             $this->username = TextFormat::clean($packet->username);
             $this->displayName = $this->username;
             $this->iusername = strtolower($this->username);
             #$this->setDataProperty(self::DATA_NAMETAG, self::DATA_TYPE_STRING, $this->username, false);
             if ($this->server->getMaxPlayers() !== -1) {
                 if (count($this->server->getOnlinePlayers()) >= $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)) {
                     break;
                 }
             }
             if (!in_array($packet->protocol, ProtocolInfo::ACCEPT_PROTOCOL)) {
                 if ($packet->protocol < 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->uuid = UUID::fromString($packet->clientUUID);
             $this->rawUUID = $this->uuid->toBinary();
             $this->identityPublicKey = $packet->identityPublicKey;
             $this->chainData = $packet->chainData;
             $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->skinId);
             $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:
             /*
             /** EntityLink ** /
             if($this->getlinkType() === Entity::LINK_MASTER){
             	$this->getlinkedTarget()->followEntity($this);
             }
             */
             if ($this->teleportPosition !== null) {
                 break;
             }
             $newPos = new Vector3($packet->x, $packet->y - $this->getEyeHeight(), $packet->z);
             if ($newPos->distanceSquared($this) < 0.01 and $packet->yaw % 360 === $this->yaw and $packet->pitch % 360 === $this->pitch) {
                 //player hasn't moved, just client spamming packets
                 break;
             }
             $revert = false;
             if (!$this->isAlive() or $this->spawned !== true) {
                 $revert = true;
                 $this->forceMovement = new Vector3($this->x, $this->y, $this->z);
             }
             if ($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::ADVENTURE_SETTINGS_PACKET:
             //TODO: player abilities, check for other changes
             if ($packet->isFlying and !$this->allowFlight) {
                 $this->kick("Flying is not enabled on this server");
                 break;
             } else {
                 $this->server->getPluginManager()->callEvent($ev = new PlayerToggleFlightEvent($this, $packet->isFlying));
                 if ($ev->isCancelled()) {
                     $this->sendSettings();
                 } else {
                     $this->flying = $ev->isFlying();
                 }
                 break;
             }
             break;
         case ProtocolInfo::MOB_EQUIPMENT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             /**
              * Handle hotbar slot remapping
              * This is the only time and place when hotbar mapping should ever be changed.
              * Changing hotbar slot mapping at will has been deprecated because it causes far too many
              * issues with Windows 10 Edition Beta.
              */
             $this->inventory->setHeldItemIndex($packet->selectedSlot, false, $packet->slot);
             $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 = self::CRAFTING_SMALL;
             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;
                     }
                 }
                 if ($this->isOnline()) {
                     $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 === -1) {
                 $aimPos = new Vector3(-sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI), -sin($this->pitch / 180 * M_PI), cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI));
                 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;
                 }
                 /** New Launchable Class **/
                 if ($item instanceof Launchable) {
                     $item->Launch($this);
                     if ($this->isSurvival() || $this->isAdventure()) {
                         $item->setCount($item->getCount() - 1);
                         $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));
                     }
                 } elseif ($item->getId() === Item::FISHING_ROD) {
                     if ($this->getHook() !== null) {
                         if ($this->getHook()->closed) {
                             $this->setHook();
                             return;
                         }
                     }
                     if ($this->getHook() instanceof FishingHook) {
                         $this->server->getPluginManager()->callEvent($fish = new PlayerFishEvent($this, $item, $this->getHook()));
                         if (!$ev->isCancelled()) {
                             $damageRod = $this->getHook()->reelLine();
                             #$this->unlinkHookFromPlayer($this);
                         }
                     } else {
                         $f = 0.6;
                         $nbt = new CompoundTag("", ["Pos" => new ListTag("Pos", [new DoubleTag("", $this->x), new DoubleTag("", $this->y + $this->getEyeHeight()), new DoubleTag("", $this->z)]), "Motion" => new ListTag("Motion", [new DoubleTag("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new DoubleTag("", -sin($this->pitch / 180 * M_PI)), new DoubleTag("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new ListTag("Rotation", [new FloatTag("", $this->yaw), new FloatTag("", $this->pitch)])]);
                         $fishingHook = new FishingHook($this->chunk, $nbt, $this);
                         $this->server->getPluginManager()->callEvent($fish = new EntityLaunchFishingRodEvent($this, $item, $fishingHook, $f));
                         if (!$ev->isCancelled()) {
                             $this->linkHookToPlayer($fishingHook);
                             $this->getHook()->setMotion($this->getHook()->getMotion()->multiply($f));
                             $this->getHook()->shootingEntity = $this;
                             $this->getHook()->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;
                     }
                     $block = $target->getSide($packet->face);
                     if ($block->getId() === Block::FIRE) {
                         $this->level->setBlock($block, new Air());
                         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, null))) {
                                 $this->inventory->sendContents($this);
                                 break;
                             }
                             $arrow = false;
                             foreach ($this->inventory->getContents() as $item) {
                                 if ($item->getId() == Item::ARROW) {
                                     $arrow = $item;
                                 }
                             }
                             if ($arrow === false and $this->isCreative()) {
                                 $arrow = Item::get(Item::ARROW, 0, 1);
                             } elseif ($arrow === false) {
                                 break;
                             }
                             $nbt = new CompoundTag("", ["Pos" => new ListTag("Pos", [new DoubleTag("", $this->x), new DoubleTag("", $this->y + $this->getEyeHeight()), new DoubleTag("", $this->z)]), "Motion" => new ListTag("Motion", [new DoubleTag("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new DoubleTag("", -sin($this->pitch / 180 * M_PI)), new DoubleTag("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new ListTag("Rotation", [new FloatTag("", $this->yaw), new FloatTag("", $this->pitch)]), "Fire" => new ShortTag("Fire", $this->isOnFire() ? 45 * 60 : 0), "Potion" => new ShortTag("Potion", $arrow->getDamage())]);
                             $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, $arrow->getDamage(), 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 = self::CRAFTING_SMALL;
                     $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn()));
                     $this->teleport($ev->getRespawnPosition());
                     $this->setSprinting(false);
                     $this->setMovementSpeed(self::DEFAULT_SPEED);
                     //because setSprinting(false) would decrease
                     $this->setSneaking(false);
                     $this->extinguish();
                     $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 400, false);
                     $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 2;
                 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 2;
                 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 2;
                 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 2;
                 case PlayerActionPacket::ACTION_JUMP:
                     break 2;
             }
             $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 = self::CRAFTING_SMALL;
             $vector = new Vector3($packet->x, $packet->y, $packet->z);
             $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, true)) {
                 if ($this->isSurvival()) {
                     if (!$item->equals($oldItem) or $item->getCount() !== $oldItem->getCount()) {
                         $this->inventory->setItemInHand($item);
                         $this->inventory->sendHeldItem($this);
                     }
                     $this->exhaust(0.025, PlayerExhaustEvent::CAUSE_MINING);
                 }
                 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:
             //This packet is ignored. Armour changes are also sent by ContainerSetSlotPackets, and are handled there instead.
             break;
         case ProtocolInfo::INTERACT_PACKET:
             if ($this->spawned === false or !$this->isAlive() or $this->blocked) {
                 break;
             }
             $this->craftingType = self::CRAFTING_SMALL;
             $target = $this->level->getEntity($packet->target);
             $cancelled = false;
             /**
              * EntityLink
              * @todo move into switch
              * @todo linkAPI+minecarts branch merge...
              */
             if ($target !== null && $target->isVehicle()) {
                 if ($packet->action === InteractPacket::ACTION_RIGHT_CLICK) {
                     $this->linkEntity($target);
                     break;
                 } elseif ($packet->action === InteractPacket::ACTION_LEAVE_VEHICLE) {
                     if ($this->isLinked()) {
                         $this->unlinkEntity($this);
                     }
                     break;
                 }
             }
             /**
              * @todo What is this. @XenialDan/@thebigsmileXD
              * @todo move into switch
              */
             if ($packet->action === InteractPacket::ACTION_RIGHT_CLICK && $target instanceof Entity) {
                 $this->getInventory()->getItemInHand()->useOnEntity($target, $this);
                 // this is beta. Should return false anyways
                 break;
             }
             /**
              * New 'handler', please don't put anything above anymore
              */
             switch ($packet->action) {
                 case InteractPacket::ACTION_LEFT_CLICK:
                     //Attack
                     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 => $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 ($this->isSurvival()) {
                             if ($item->isTool()) {
                                 if ($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()) {
                                     $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1));
                                 } else {
                                     $this->inventory->setItemInHand($item);
                                 }
                             }
                             $this->exhaust(0.3, PlayerExhaustEvent::CAUSE_ATTACK);
                         }
                     }
                     break;
                 default:
                     break;
                     //TODO: handle other actions
             }
             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 = self::CRAFTING_SMALL;
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             //TODO: check if this should be true
             switch ($packet->event) {
                 case EntityEventPacket::USE_ITEM:
                     //Eating
                     $slot = $this->inventory->getItemInHand();
                     if ($slot->canBeConsumed()) {
                         $ev = new PlayerItemConsumeEvent($this, $slot);
                         if (!$slot->canBeConsumedBy($this)) {
                             $ev->setCancelled();
                         }
                         $this->server->getPluginManager()->callEvent($ev);
                         if (!$ev->isCancelled()) {
                             $slot->onConsume($this);
                         } else {
                             $this->inventory->sendContents($this);
                         }
                     }
                     break;
             }
             break;
         case ProtocolInfo::DROP_ITEM_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             if ($packet->item->getId() === Item::AIR) {
                 /**
                  * This is so stupid it's unreal.
                  * Windows 10 Edition Beta drops the contents of the crafting grid when the inventory closes - including air.
                  */
                 break;
             }
             $this->getTransactionQueue()->addTransaction(new DropItemTransaction($packet->item));
             break;
         case ProtocolInfo::COMMAND_STEP_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = 0;
             $commandText = $packet->command;
             if ($packet->args !== null) {
                 foreach ($packet->args as $arg) {
                     //command ordering will be an issue
                     $commandText .= " " . $arg;
                 }
             }
             $this->server->getPluginManager()->callEvent($ev = new PlayerCommandPreprocessEvent($this, "/" . $commandText));
             if ($ev->isCancelled()) {
                 break;
             }
             Timings::$playerCommandTimer->startTiming();
             $this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 1));
             Timings::$playerCommandTimer->stopTiming();
             break;
         case ProtocolInfo::TEXT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = self::CRAFTING_SMALL;
             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, 2) === "./") {
                             //Command (./ = fast hack for old plugins post 0.16)
                             Timings::$playerCommandTimer->startTiming();
                             $this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 2));
                             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 = self::CRAFTING_SMALL;
             if (isset($this->windowIndex[$packet->windowid])) {
                 $this->server->getPluginManager()->callEvent(new InventoryCloseEvent($this->windowIndex[$packet->windowid], $this));
                 $this->removeWindow($this->windowIndex[$packet->windowid]);
             }
             /**
              * Drop anything still left in the crafting inventory
              * This will usually never be needed since Windows 10 clients will send DropItemPackets
              * which will cause this to happen anyway, but this is here for when transactions
              * fail and items end up stuck in the crafting inventory.
              */
             foreach ($this->getFloatingInventory()->getContents() as $item) {
                 $this->getTransactionQueue()->addTransaction(new DropItemTransaction($item));
             }
             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];
                         if (!$item instanceof Item) {
                             continue;
                         }
                         $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, $ingredient->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;
                 }
                 $transaction = new BaseTransaction($this->inventory, $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(), $packet->item);
             } elseif (isset($this->windowIndex[$packet->windowid])) {
                 //Transaction for non-player-inventory window, such as anvil, chest, etc.
                 $inv = $this->windowIndex[$packet->windowid];
                 $achievements = [];
                 if ($inv instanceof FurnaceInventory and $inv->getItem($packet->slot)->getId() === Item::IRON_INGOT and $packet->slot === FurnaceInventory::RESULT) {
                     $achievements[] = "acquireIron";
                 } elseif ($inv instanceof EnchantInventory and $packet->item->hasEnchantments()) {
                     $inv->onEnchant($this, $inv->getItem($packet->slot), $packet->item);
                 }
                 $transaction = new BaseTransaction($inv, $packet->slot, $packet->item, $achievements);
             } else {
                 //Client sent a transaction for a window which the server doesn't think they have open
                 break;
             }
             $this->getTransactionQueue()->addTransaction($transaction);
             break;
         case ProtocolInfo::BLOCK_ENTITY_DATA_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = self::CRAFTING_SMALL;
             $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, false, true);
                 $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(TextFormat::clean($line), "UTF-8") > 20){ // TODO: Add pixel width calculation like MiNET
                         				$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;
         case ProtocolInfo::REQUEST_CHUNK_RADIUS_PACKET:
             if ($this->spawned) {
                 $this->viewDistance = $packet->radius ** 2;
             }
             $pk = new ChunkRadiusUpdatedPacket();
             $pk->radius = $packet->radius;
             $this->dataPacket($pk);
             break;
         case ProtocolInfo::SET_PLAYER_GAME_TYPE_PACKET:
             if ($packet->gamemode !== $this->gamemode) {
                 if (!$this->hasPermission("pocketmine.command.gamemode")) {
                     $pk = new SetPlayerGameTypePacket();
                     $pk->gamemode = $this->gamemode & 0x1;
                     $this->dataPacket($pk);
                     $this->sendSettings();
                     break;
                 }
                 $this->setGamemode($packet->gamemode, true);
             }
             break;
         default:
             break;
     }
     $timings->stopTiming();
 }
Exemple #24
0
 protected function send($message, $level, $prefix, $color)
 {
     $now = time();
     $thread = \Thread::getCurrentThread();
     if ($thread === null) {
         $threadName = "Server thread";
     } elseif ($thread instanceof Thread or $thread instanceof Worker) {
         $threadName = $thread->getThreadName() . " thread";
     } else {
         $threadName = (new \ReflectionClass($thread))->getShortName() . " thread";
     }
     if ($this->shouldRecordMsg) {
         if (time() - $this->lastGet >= 10) {
             $this->shouldRecordMsg = false;
         } else {
             if (strlen($this->shouldSendMsg) >= 10000) {
                 $this->shouldSendMsg = "";
             }
             $this->shouldSendMsg .= $color . "|" . $prefix . "|" . trim($message, "\r\n") . "\n";
         }
     }
     $message = TextFormat::toANSI(TextFormat::AQUA . "[" . date("H:i:s", $now) . "] " . TextFormat::RESET . $color . "[" . $threadName . "/" . $prefix . "]:" . " " . $message . TextFormat::RESET);
     //$message = TextFormat::toANSI(TextFormat::AQUA . "[" . date("H:i:s") . "] ". TextFormat::RESET . $color ."<".$prefix . ">" . " " . $message . TextFormat::RESET);
     $cleanMessage = TextFormat::clean($message);
     if (!Terminal::hasFormattingCodes()) {
         echo $cleanMessage . PHP_EOL;
     } else {
         echo $message . PHP_EOL;
     }
     if (isset($this->consoleCallback)) {
         call_user_func($this->consoleCallback);
     }
     if ($this->attachment instanceof \ThreadedLoggerAttachment) {
         $this->attachment->call($level, $message);
     }
     $this->logStream[] = date("Y-m-d", $now) . " " . $cleanMessage . "\n";
     if ($this->logStream->count() === 1) {
         $this->synchronized(function () {
             $this->notify();
         });
     }
 }
Exemple #25
0
 /**
  * Sends a direct chat message to a player
  *
  * @param string $message
  */
 public function sendMessage($message)
 {
     if ($this->removeFormat !== false) {
         $message = TextWrapper::wrap(TextFormat::clean($message));
     }
     $mes = explode("\n", $message);
     foreach ($mes as $m) {
         if ($m !== "") {
             $pk = new MessagePacket();
             $pk->source = "";
             //Do not use this ;)
             $pk->message = $m;
             $this->dataPacket($pk);
         }
     }
 }
 /**
  * Load signs
  */
 public function parseSignPositions(array $signPositions)
 {
     PluginUtils::logOnConsole("[1vs1] - Load signs... " . count($signPositions) . " signs");
     foreach ($signPositions as $n => $signPosition) {
         Server::getInstance()->loadLevel($signPosition[3]);
         if (($level = Server::getInstance()->getLevelByName($signPosition[3])) !== null) {
             $newSignPosition = new Position($signPosition[0], $signPosition[1], $signPosition[2], $level);
             $tile = $level->getTile($newSignPosition);
             if ($tile != null) {
                 $cleanTileTitle = TextFormat::clean($tile->getText()[0]);
                 $cleanOnevsOneTitle = TextFormat::clean(OneVsOne::SIGN_TITLE);
                 // Load it only if it's a sign with OneVsOne title
                 if ($tile !== null && $tile instanceof Sign && $cleanTileTitle === $cleanOnevsOneTitle) {
                     array_push($this->signTiles, $tile);
                     continue;
                 }
             }
         } else {
             PluginUtils::logOnConsole("[1vs1] - Level " . $signPosition[3] . " does not exists. Please check configuration.");
         }
     }
 }
Exemple #27
0
 public function spawnTo(Player $player)
 {
     if ($player !== $this and !isset($this->hasSpawned[$player->getID()])) {
         $this->hasSpawned[$player->getID()] = $player;
         $pk = new AddPlayerPacket();
         $pk->clientID = 0;
         if ($player->getRemoveFormat()) {
             $pk->username = TextFormat::clean($this->nameTag);
         } else {
             $pk->username = $this->nameTag;
         }
         $pk->eid = $this->getID();
         $pk->x = $this->x;
         $pk->y = $this->y;
         $pk->z = $this->z;
         $pk->yaw = $this->yaw;
         $pk->pitch = $this->pitch;
         $pk->unknown1 = 0;
         $pk->unknown2 = 0;
         $pk->metadata = $this->getData();
         $player->dataPacket($pk);
         $pk = new SetEntityMotionPacket();
         $pk->entities = [[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]];
         $player->dataPacket($pk);
         $this->inventory->sendHeldItem($player);
         $this->inventory->sendArmorContents($player);
     }
 }
Exemple #28
0
 protected function send($message, $level, $prefix, $color)
 {
     $now = time();
     $thread = \Thread::getCurrentThread();
     if ($thread === null) {
         $threadName = "Server thread";
     } elseif ($thread instanceof Thread or $thread instanceof Worker) {
         $threadName = $thread->getThreadName() . " thread";
     } else {
         $threadName = (new \ReflectionClass($thread))->getShortName() . " thread";
     }
     $message = TextFormat::toANSI(TextFormat::AQUA . "[" . date("H:i:s", $now) . "] " . TextFormat::RESET . $color . "[" . $prefix . "]:" . " " . $message . TextFormat::RESET);
     //$message = TextFormat::toANSI(TextFormat::AQUA . "[" . date("H:i:s") . "] ". TextFormat::RESET . $color ."<".$prefix . ">" . " " . $message . TextFormat::RESET);
     $cleanMessage = TextFormat::clean($message);
     if (!Terminal::hasFormattingCodes()) {
         echo $cleanMessage . PHP_EOL;
     } else {
         echo $message . PHP_EOL;
     }
     if ($this->attachment instanceof \ThreadedLoggerAttachment) {
         $this->attachment->call($level, $message);
     }
     $this->logStream[] = date("Y-m-d", $now) . " " . $cleanMessage . "\n";
     if ($this->logStream->count() === 1) {
         $this->synchronized(function () {
             $this->notify();
         });
     }
 }
Exemple #29
0
 public function spawnTo(Player $player)
 {
     if ($player !== $this and !isset($this->hasSpawned[$player->getId()])) {
         $this->hasSpawned[$player->getId()] = $player;
         $pk = new AddPlayerPacket();
         $pk->clientID = 0;
         if ($player->getRemoveFormat()) {
             $pk->username = TextFormat::clean($this->nameTag);
         } else {
             $pk->username = $this->nameTag;
         }
         $pk->eid = $this->getId();
         $pk->x = $this->x;
         $pk->y = $this->y;
         $pk->z = $this->z;
         $pk->yaw = $this->yaw;
         $pk->pitch = $this->pitch;
         $item = $this->getInventory()->getItemInHand();
         $pk->item = $item->getId();
         $pk->meta = $item->getDamage();
         $pk->metadata = $this->getData();
         $player->dataPacket($pk);
         $player->addEntityMotion($this->getId(), $this->motionX, $this->motionY, $this->motionZ);
         $this->inventory->sendArmorContents($player);
     }
 }
Exemple #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();
 }