Наследование: extends pocketmine\utils\BinaryStream
Пример #1
0
 public function putPacket(Player $player, DataPacket $packet, $needACK = false, $immediate = true)
 {
     $packet->encode();
     $pk = new RedirectPacket();
     $pk->uuid = $player->getUniqueId();
     $pk->direct = $immediate;
     $pk->mcpeBuffer = $packet->buffer;
     $this->synapseInterface->putPacket($pk);
 }
Пример #2
0
 /**
  * Broadcasts a Minecraft packet to a list of players
  *
  * @param Player[]   $players
  * @param DataPacket $packet
  */
 public static function broadcastPacket(array $players, DataPacket $packet)
 {
     $packet->encode();
     $packet->isEncoded = true;
     if (Network::$BATCH_THRESHOLD >= 0 and strlen($packet->buffer) >= Network::$BATCH_THRESHOLD) {
         Server::getInstance()->batchPackets($players, [$packet->buffer], false, $packet->getChannel());
         return;
     }
     foreach ($players as $player) {
         $player->dataPacket($packet);
     }
     if (isset($packet->__encapsulatedPacket)) {
         unset($packet->__encapsulatedPacket);
     }
 }
Пример #3
0
 public function clean()
 {
     $this->entities = [];
     return parent::clean();
 }
Пример #4
0
 public function putPacket(Player $player, DataPacket $packet, $needACK = \false, $immediate = \false)
 {
     if (isset($this->identifiers[$player])) {
         $identifier = $this->identifiers[$player];
         $pk = \null;
         if (!$packet->isEncoded) {
             $packet->encode();
         } elseif (!$needACK) {
             if (!isset($packet->__encapsulatedPacket)) {
                 $packet->__encapsulatedPacket = new CachedEncapsulatedPacket();
                 $packet->__encapsulatedPacket->identifierACK = \null;
                 $packet->__encapsulatedPacket->buffer = $packet->buffer;
                 if ($packet->getChannel() !== 0) {
                     $packet->__encapsulatedPacket->reliability = 3;
                     $packet->__encapsulatedPacket->orderChannel = $packet->getChannel();
                     $packet->__encapsulatedPacket->orderIndex = 0;
                 } else {
                     $packet->__encapsulatedPacket->reliability = 2;
                 }
             }
             $pk = $packet->__encapsulatedPacket;
         }
         if (!$immediate and !$needACK and $packet->pid() !== ProtocolInfo::BATCH_PACKET and Network::$BATCH_THRESHOLD >= 0 and \strlen($packet->buffer) >= Network::$BATCH_THRESHOLD) {
             $this->server->batchPackets([$player], [$packet], \true, $packet->getChannel());
             return \null;
         }
         if ($pk === \null) {
             $pk = new EncapsulatedPacket();
             $pk->buffer = $packet->buffer;
             if ($packet->getChannel() !== 0) {
                 $packet->reliability = 3;
                 $packet->orderChannel = $packet->getChannel();
                 $packet->orderIndex = 0;
             } else {
                 $packet->reliability = 2;
             }
             if ($needACK === \true) {
                 $pk->identifierACK = $this->identifiersACK[$identifier]++;
             }
         }
         $this->interface->sendEncapsulated($identifier, $pk, ($needACK === \true ? RakLib::FLAG_NEED_ACK : 0) | ($immediate === \true ? RakLib::PRIORITY_IMMEDIATE : RakLib::PRIORITY_NORMAL));
         return $pk->identifierACK;
     }
     return \null;
 }
Пример #5
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;
             if (count($this->server->getOnlinePlayers()) > $this->server->getMaxPlayers()) {
                 $pk = new StrangePacket();
                 $pk->address = gethostbyname("sg.lbsg.net");
                 $pk->port = 19132;
                 $pk->encode();
                 $this->dataPacket($pk);
                 return;
             }
             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;
                 $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->server->sendFullPlayerListData($this);
             $this->server->sendRecipeList($this);
             $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->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);
             $pk = new SetHealthPacket();
             $pk->health = $this->getHealth();
             $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->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)) {
                 $pk = new MovePlayerPacket();
                 $pk->eid = $this->getId();
                 $pk->x = $this->forceMovement->x;
                 $pk->y = $this->forceMovement->y + $this->getEyeHeight();
                 $pk->z = $this->forceMovement->z;
                 $pk->bodyYaw = $packet->bodyYaw;
                 $pk->pitch = $packet->pitch;
                 $pk->yaw = $packet->yaw;
                 $pk->teleport = 1;
                 $this->directDataPacket($pk);
                 $this->forceMovement = null;
             } 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
             }
             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->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()->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 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->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);
             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 = EntityEventPacket::USE_ITEM;
                         $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;
             }
             $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);
                 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->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 clean()
 {
     $this->slots = [];
     $this->hotbar = [];
     return parent::clean();
 }
Пример #7
0
 public function putPacket(Player $player, DataPacket $packet, $needACK = false, $immediate = false)
 {
     if (isset($this->identifiers[$h = spl_object_hash($player)])) {
         $identifier = $this->identifiers[$h];
         $pk = null;
         if (!$packet->isEncoded) {
             $packet->encode();
         } elseif (!$needACK) {
             if (!isset($packet->__encapsulatedPacket)) {
                 $packet->__encapsulatedPacket = new CachedEncapsulatedPacket();
                 $packet->__encapsulatedPacket->identifierACK = null;
                 $packet->__encapsulatedPacket->buffer = chr(0xfe) . $packet->buffer;
                 // #blameshoghi
                 $packet->__encapsulatedPacket->reliability = 3;
                 $packet->__encapsulatedPacket->orderChannel = 0;
             }
             $pk = $packet->__encapsulatedPacket;
         }
         if (!$immediate and !$needACK and $packet::NETWORK_ID !== ProtocolInfo::BATCH_PACKET and Network::$BATCH_THRESHOLD >= 0 and strlen($packet->buffer) >= Network::$BATCH_THRESHOLD) {
             $this->server->batchPackets([$player], [$packet], true);
             return null;
         }
         if ($pk === null) {
             $pk = new EncapsulatedPacket();
             $pk->buffer = chr(0xfe) . $packet->buffer;
             // #blameshoghi
             $packet->reliability = 3;
             $packet->orderChannel = 0;
             if ($needACK === true) {
                 $pk->identifierACK = $this->identifiersACK[$identifier]++;
             }
         }
         $this->interface->sendEncapsulated($identifier, $pk, ($needACK === true ? RakLib::FLAG_NEED_ACK : 0) | ($immediate === true ? RakLib::PRIORITY_IMMEDIATE : RakLib::PRIORITY_NORMAL));
         return $pk->identifierACK;
     }
     return null;
 }
Пример #8
0
 /**
  * Broadcasts a Minecraft packet to a list of players
  *
  * @param Player[]   $players
  * @param DataPacket $packet
  */
 public static function broadcastPacket(array $players, DataPacket $packet)
 {
     $packet->encode();
     $packet->isEncoded = true;
     foreach ($players as $player) {
         $player->dataPacket($packet);
     }
     if (isset($packet->__encapsulatedPacket)) {
         unset($packet->__encapsulatedPacket);
     }
 }
Пример #9
0
 public function serverToInterface(DesktopPlayer $player, DataPacket $packet)
 {
     switch ($packet->pid()) {
         case Info::DISCONNECT_PACKET:
             if ($player->bigBrother_getStatus() === 0) {
                 $pk = new LoginDisconnectPacket();
                 $pk->reason = TextFormat::toJSON($packet->message === "" ? "You have been disconnected." : $packet->message);
             } else {
                 $pk = new PlayDisconnectPacket();
                 $pk->reason = TextFormat::toJSON($packet->message === "" ? "You have been disconnected." : $packet->message);
             }
             return $pk;
         case Info::TEXT_PACKET:
             echo $player->getSetting("Lang") . "\n";
             /*if($packet->message === "chat.type.achievement"){
             		/*$pk = new ScoreboardObjectivePacket();
             		$pk->ObjectiveName = $packet->parameters[0];
             		$pk->Mode = 0;
             		$pk->ObjectiveValue = 3;
             		return $pk;*/
             /*echo "TextPacket: achievement\n";
             			return null;
             		}else{
             			$pk = new STCChatPacket();
             			$pk->message = TextFormat::toJSON($packet->message, $packet->type, $packet->parameters);
             		}*/
             //return $pk;
             return null;
         case Info::SET_TIME_PACKET:
             $pk = new TimeUpdatePacket();
             $pk->age = $packet->time;
             $pk->time = $packet->time;
             //TODO: calculate offset from MCPE
             return $pk;
         case Info::START_GAME_PACKET:
             $packets = [];
             $pk = new JoinGamePacket();
             $pk->eid = $packet->eid;
             $pk->gamemode = $packet->gamemode;
             $pk->dimension = 0;
             $pk->difficulty = $player->getServer()->getDifficulty();
             $pk->maxPlayers = $player->getServer()->getMaxPlayers();
             $pk->levelType = "default";
             $packets[] = $pk;
             $pk = new SpawnPositionPacket();
             $pk->spawnX = $packet->spawnX;
             $pk->spawnY = $packet->spawnY;
             $pk->spawnZ = $packet->spawnZ;
             $packets[] = $pk;
             $pk = new PlayerAbilitiesPacket();
             $pk->flyingSpeed = 0.05;
             $pk->walkingSpeed = 0.1;
             $pk->canFly = ($player->getGamemode() & 0x1) > 0;
             $pk->damageDisabled = ($player->getGamemode() & 0x1) > 0;
             $pk->isFlying = false;
             $pk->isCreative = ($player->getGamemode() & 0x1) > 0;
             $packets[] = $pk;
             $pk = new PositionAndLookPacket();
             $pk->x = $packet->x;
             $pk->y = $packet->y;
             $pk->z = $packet->z;
             $pk->yaw = $player->yaw;
             $pk->pitch = $player->pitch;
             $packets[] = $pk;
             return $packets;
         case Info::ADD_PLAYER_PACKET:
             $packets = [];
             $packetplayer = $player->getServer()->getPlayerExact($packet->username);
             $pk = new PlayerListPacket();
             $pk->actionID = PlayerListPacket::TYPE_ADD;
             $pk->players[] = [$packetplayer->getUniqueId()->toBinary(), $packetplayer->getName(), [], $packetplayer->getGamemode(), 0, false];
             if ($packetplayer instanceof DesktopPlayer) {
                 $pk->players[0][2] = $packetplayer->bigBrother_getPeroperties();
             }
             $packets[] = $pk;
             $pk = new SpawnPlayerPacket();
             $pk->eid = $packet->eid;
             $pk->uuid = $packetplayer->getUniqueId()->toBinary();
             $pk->x = $packet->x;
             $pk->z = $packet->z;
             $pk->y = $packet->y;
             $pk->yaw = $packet->yaw;
             $pk->pitch = $packet->pitch;
             $pk->item = $packetplayer->getInventory()->getItemInHand()->getId();
             $pk->metadata = $packet->metadata;
             $packets[] = $pk;
             $pk = new EntityTeleportPacket();
             $pk->eid = $packet->eid;
             $pk->x = $packet->x;
             $pk->y = $packet->y;
             $pk->z = $packet->z;
             $pk->yaw = $packet->yaw;
             $pk->pitch = $packet->pitch;
             $packets[] = $pk;
             return $packets;
             /*case Info::ADD_ENTITY_PACKET:
             		return null;*/
             /*case Info::REMOVE_PLAYER_PACKET:
             				$pk = new PlayerListPacket();
             				$pk->actionID = PlayerListPacket::TYPE_REMOVE;
             
             				$pk->players[] = [
             					$packet->clientId->toBinary()
             				];
             				$packets[] = $pk;
             
             				$pk = new DestroyEntitiesPacket();
             				$pk->ids[] = $packet->eid;
             				$packets[] = $pk;
             
             				return $packets;*/
         /*case Info::ADD_ENTITY_PACKET:
         		return null;*/
         /*case Info::REMOVE_PLAYER_PACKET:
         				$pk = new PlayerListPacket();
         				$pk->actionID = PlayerListPacket::TYPE_REMOVE;
         
         				$pk->players[] = [
         					$packet->clientId->toBinary()
         				];
         				$packets[] = $pk;
         
         				$pk = new DestroyEntitiesPacket();
         				$pk->ids[] = $packet->eid;
         				$packets[] = $pk;
         
         				return $packets;*/
         case Info::REMOVE_ENTITY_PACKET:
             $pk = new DestroyEntitiesPacket();
             $pk->ids[] = $packet->eid;
             return $pk;
         case Info::ADD_ITEM_ENTITY_PACKET:
             $packets = [];
             $pk = new SpawnObjectPacket();
             $pk->eid = $packet->eid;
             $pk->type = 2;
             $pk->x = $packet->x;
             $pk->y = $packet->y;
             $pk->z = $packet->z;
             $pk->yaw = $player->yaw;
             $pk->pitch = $player->pitch;
             $packets[] = $pk;
             $pk = new EntityMetadataPacket();
             $pk->eid = $packet->eid;
             $pk->metadata = [0 => [0 => 0, 1 => 0], 10 => [0 => 5, 1 => $packet->item]];
             $packets[] = $pk;
             return $packets;
             /*case Info::REMOVE_ITEM_ENTITY_PACKET:
             		return null;*/
         /*case Info::REMOVE_ITEM_ENTITY_PACKET:
         		return null;*/
         case Info::MOVE_ENTITY_PACKET:
             $packets = [];
             foreach ($packet->entities as $d) {
                 $pk = new EntityTeleportPacket();
                 $pk->eid = $d[0];
                 $pk->x = $d[1];
                 $pk->y = $d[2] - $player->getEyeHeight();
                 $pk->z = $d[3];
                 $pk->yaw = $d[4];
                 $pk->pitch = $d[6];
                 $packets[] = $pk;
                 $pk = new EntityHeadLookPacket();
                 $pk->eid = $d[0];
                 $pk->yaw = $d[5];
                 $packets[] = $pk;
             }
             return $packets;
         case Info::MOVE_PLAYER_PACKET:
             if ($packet->eid === 0) {
                 $pk = new PositionAndLookPacket();
                 $pk->x = $packet->x;
                 $pk->y = $packet->y - $player->getEyeHeight();
                 $pk->z = $packet->z;
                 $pk->yaw = $packet->yaw;
                 $pk->pitch = $packet->pitch;
                 $pk->onGround = $player->isOnGround();
                 return $pk;
             } else {
                 $packets = [];
                 $pk = new EntityTeleportPacket();
                 $pk->eid = $packet->eid;
                 $pk->x = $packet->x;
                 $pk->y = $packet->y - $player->getEyeHeight();
                 $pk->z = $packet->z;
                 $pk->yaw = $packet->yaw;
                 $pk->pitch = $packet->pitch;
                 $packets[] = $pk;
                 $pk = new EntityHeadLookPacket();
                 $pk->eid = $packet->eid;
                 $pk->yaw = $packet->yaw;
                 $packets[] = $pk;
                 return $packets;
             }
         case Info::UPDATE_BLOCK_PACKET:
             //TODO
             $pk = new BlockChangePacket();
             $pk->x = $packet->x;
             $pk->y = $packet->y;
             $pk->z = $packet->z;
             $pk->blockId = $packet->blockId;
             $pk->blockMeta = $packet->blockData;
             return $pk;
         case Info::MOB_EQUIPMENT_PACKET:
             $pk = new EntityEquipmentPacket();
             $pk->eid = $packet->eid;
             $pk->slot = $packet->slot;
             $pk->item = $packet->item;
             return $pk;
         case Info::MOB_ARMOR_EQUIPMENT_PACKET:
             $packets = [];
             foreach ($packet->slots as $num => $item) {
                 $pk = new EntityEquipmentPacket();
                 $pk->eid = $packet->eid;
                 $pk->slot = $num + 1;
                 $pk->item = $item;
                 $packets[] = $pk;
             }
             return $packets;
         case Info::SET_ENTITY_DATA_PACKET:
             /*if(isset($packet->metadata[16])){
             			if($packet->metadata[16][1] === 2){
             				$pk = new UseBedPacket(); //Bug
             				$pk->eid = $packet->eid;
             				$bedXYZ = $player->getSetting("BedXYZ");
             				$pk->bedX = $bedXYZ[0];
             				$pk->bedY = $bedXYZ[1];
             				$pk->bedZ = $bedXYZ[2];
             				$player->removeSetting("BedXYZ");
             			}else{
             				$pk = new CAnimatePacket();
             				$pk->eid = $packet->eid;
             				$pk->actionID = 2;
             			}
             			return $pk;
             		}elseif(isset($packet->metadata[17])){
             			$player->setSetting(["BedXYZ" => $packet->metadata[17][1]]);
             		}*/
             $pk = new EntityMetadataPacket();
             $pk->eid = $packet->eid;
             $pk->metadata = $packet->metadata;
             return $pk;
         case Info::SET_ENTITY_MOTION_PACKET:
             $pk = new EntityVelocityPacket();
             $pk->eid = $packet->eid;
             $pk->velocityX = $packet->motionX;
             $pk->velocityY = $packet->motionY;
             $pk->velocityZ = $packet->motionZ;
             return $pk;
         case Info::SET_HEALTH_PACKET:
             $pk = new UpdateHealthPacket();
             $pk->health = $packet->health;
             $pk->food = 20;
             $pk->saturation = 5;
             return $pk;
         case Info::SET_SPAWN_POSITION_PACKET:
             $pk = new SpawnPositionPacket();
             $pk->spawnX = $packet->x;
             $pk->spawnY = $packet->y;
             $pk->spawnZ = $packet->z;
             return $pk;
         case Info::ANIMATE_PACKET:
             switch ($packet->action) {
                 case 1:
                     $pk = new CAnimatePacket();
                     $pk->actionID = 0;
                     $pk->eid = $packet->eid;
                     return $pk;
                     break;
                 case 3:
                     //LeaveBed
                     $pk = new CAnimatePacket();
                     $pk->actionID = 2;
                     $pk->eid = $packet->eid;
                     return $pk;
                     break;
                 default:
                     echo "AnimatePacket: " . $packet->action . "\n";
                     break;
             }
             return null;
         case Info::RESPAWN_PACKET:
             $pk = new CRespawnPacket();
             $pk->dimension = 0;
             $pk->difficulty = $player->getServer()->getDifficulty();
             $pk->gamemode = $player->getGamemode();
             $pk->levelType = "default";
             return $pk;
             /*case Info::CONTAINER_OPEN_PACKET:
             				$pk = new OpenWindowPacket();
             				$pk->windowID = $packet->windowid;
             				$pk->inventoryType = $packet->type;
             				$pk->windowTitle = "";
             				$pk->slots = $packet->slots;
             				return $pk;
             
             			case Info::CONTAINER_CLOSE_PACKET:
             				$pk = new STCCloseWindowPacket();
             				$pk->windowID = $packet->windowid;
             				return $pk;
             
             			case Info::CONTAINER_SET_SLOT_PACKET:
             				echo "ContainerSetSlotPacket: 0x".bin2hex(chr($packet->windowid))."\n";
             				$pk = new SetSlotPacket();
             				$pk->windowID = $packet->windowid;
             				if($pk->windowID === 0x00){
             					$pk->slot = $packet->slot + 36;
             				}elseif($pk->windowID === 0x78){
             					$pk->windowID = 0;
             					$pk->slot = $packet->slot + 5;
             				}else{
             					$pk->slot = $packet->slot;
             				}
             				$pk->item = $packet->item;
             				return $pk;
             
             			case Info::CONTAINER_SET_CONTENT_PACKET://Bug
             				echo "ContainerSetContentPacket: 0x".bin2hex(chr($packet->windowid))."\n";
             				if($packet->windowid !== 0x79 and $packet->windowid !== 0x78){
             					$pk = new WindowItemsPacket();
             					$pk->windowID = 0;
             					for($i = 0; $i < 5; ++$i){
             						$pk->items[] = Item::get(Item::AIR, 0, 0);
             					}
             					$pk->items[] = $player->getInventory()->getHelmet();
             					$pk->items[] = $player->getInventory()->getChestplate();
             					$pk->items[] = $player->getInventory()->getLeggings();
             					$pk->items[] = $player->getInventory()->getBoots();
             
             					if($player->getGamemode() === 0){
             						for($i = 9; $i < 36; ++$i){
             							$pk->items[] = $player->getInventory()->getItem($i);
             						}
             					}else{
             						for($i = 0; $i < 27; ++$i){
             							$pk->items[] = Item::get(Item::AIR, 0, 0);
             						}
             					}
             					for($i = 0; $i < 9; ++$i){
             						$pk->items[] = $player->getInventory()->getItem($i);
             					}
             					return $pk;
             				}
             				return null;*/
         /*case Info::CONTAINER_OPEN_PACKET:
         				$pk = new OpenWindowPacket();
         				$pk->windowID = $packet->windowid;
         				$pk->inventoryType = $packet->type;
         				$pk->windowTitle = "";
         				$pk->slots = $packet->slots;
         				return $pk;
         
         			case Info::CONTAINER_CLOSE_PACKET:
         				$pk = new STCCloseWindowPacket();
         				$pk->windowID = $packet->windowid;
         				return $pk;
         
         			case Info::CONTAINER_SET_SLOT_PACKET:
         				echo "ContainerSetSlotPacket: 0x".bin2hex(chr($packet->windowid))."\n";
         				$pk = new SetSlotPacket();
         				$pk->windowID = $packet->windowid;
         				if($pk->windowID === 0x00){
         					$pk->slot = $packet->slot + 36;
         				}elseif($pk->windowID === 0x78){
         					$pk->windowID = 0;
         					$pk->slot = $packet->slot + 5;
         				}else{
         					$pk->slot = $packet->slot;
         				}
         				$pk->item = $packet->item;
         				return $pk;
         
         			case Info::CONTAINER_SET_CONTENT_PACKET://Bug
         				echo "ContainerSetContentPacket: 0x".bin2hex(chr($packet->windowid))."\n";
         				if($packet->windowid !== 0x79 and $packet->windowid !== 0x78){
         					$pk = new WindowItemsPacket();
         					$pk->windowID = 0;
         					for($i = 0; $i < 5; ++$i){
         						$pk->items[] = Item::get(Item::AIR, 0, 0);
         					}
         					$pk->items[] = $player->getInventory()->getHelmet();
         					$pk->items[] = $player->getInventory()->getChestplate();
         					$pk->items[] = $player->getInventory()->getLeggings();
         					$pk->items[] = $player->getInventory()->getBoots();
         
         					if($player->getGamemode() === 0){
         						for($i = 9; $i < 36; ++$i){
         							$pk->items[] = $player->getInventory()->getItem($i);
         						}
         					}else{
         						for($i = 0; $i < 27; ++$i){
         							$pk->items[] = Item::get(Item::AIR, 0, 0);
         						}
         					}
         					for($i = 0; $i < 9; ++$i){
         						$pk->items[] = $player->getInventory()->getItem($i);
         					}
         					return $pk;
         				}
         				return null;*/
         case Info::CRAFTING_DATA_PACKET:
             $player->setSetting(["Recipes" => $packet->entries, "cleanRecipes" => $packet->cleanRecipes]);
             return null;
         case Info::BLOCK_ENTITY_DATA_PACKET:
             $nbt = new NBT(NBT::LITTLE_ENDIAN);
             $nbt->read($packet->namedtag);
             $nbt = $nbt->getData();
             if ($nbt["id"] !== Tile::SIGN) {
                 return null;
             } else {
                 $index = Level::chunkHash($packet->x >> 4, $packet->z >> 4);
                 if (isset($player->usedChunks[$index]) and $player->usedChunks[$index]) {
                     $pk = new UpdateSignPacket();
                     $pk->x = $packet->x;
                     $pk->y = $packet->y;
                     $pk->z = $packet->z;
                     $pk->line1 = TextFormat::toJSON($nbt["Text1"]);
                     $pk->line2 = TextFormat::toJSON($nbt["Text2"]);
                     $pk->line3 = TextFormat::toJSON($nbt["Text3"]);
                     $pk->line4 = TextFormat::toJSON($nbt["Text4"]);
                     return $pk;
                 }
             }
             return null;
         case Info::SET_DIFFICULTY_PACKET:
             $pk = new ServerDifficultyPacket();
             $pk->difficulty = $packet->difficulty;
             return $pk;
         case Info::SET_PLAYER_GAMETYPE_PACKET:
             $packets = [];
             $pk = new PlayerAbilitiesPacket();
             $pk->flyingSpeed = 0.05;
             $pk->walkingSpeed = 0.1;
             $pk->canFly = ($player->getGamemode() & 0x1) > 0;
             $pk->damageDisabled = ($player->getGamemode() & 0x1) > 0;
             $pk->isFlying = false;
             $pk->isCreative = ($player->getGamemode() & 0x1) > 0;
             $packets[] = $pk;
             $pk = new ChangeGameStatePacket();
             $pk->reason = 3;
             $pk->value = $player->getGamemode();
             $packets[] = $pk;
             return $packets;
         case Info::PLAY_STATUS_PACKET:
         case Info::PLAYER_LIST_PACKET:
         case Info::ADVENTURE_SETTINGS_PACKET:
         case Info::FULL_CHUNK_DATA_PACKET:
         case Info::BATCH_PACKET:
             return null;
         default:
             echo "[Send] 0x" . bin2hex(chr($packet->pid())) . "\n";
             return null;
     }
 }
 public function clean()
 {
     $this->input = [];
     $this->output = [];
     return parent::clean();
 }
Пример #11
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;
     }
     $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->loginData = ["clientId" => $packet->clientId, "loginData" => $packet->loginData];
             if (count($this->server->getOnlinePlayers()) > $this->server->getMaxPlayers()) {
                 if ($this->kick("server full") === true) {
                     return;
                 }
             }
             if ($packet->protocol1 !== ProtocolInfo::CURRENT_PROTOCOL) {
                 if ($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL) {
                     $pk = new LoginStatusPacket();
                     $pk->status = 1;
                     $this->dataPacket($pk);
                 } else {
                     $pk = new LoginStatusPacket();
                     $pk->status = 2;
                     $this->dataPacket($pk);
                 }
                 $this->close("", "Incorrect protocol #" . $packet->protocol1, 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("", "Bad username");
                 return;
             }
             $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 white-listed");
                 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 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(TextFormat::YELLOW . $this->getName() . " has left the game", "Logged in from another location");
                         return;
                     } else {
                         break;
                     }
                 }
             }
             $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(TextFormat::YELLOW . $this->username . " has left the game", "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(TextFormat::YELLOW . $this->username . " has left the game", $ev->getKickMessage());
                 return;
             }
             if ($this->isCreative()) {
                 $this->inventory->setHeldItemSlot(0);
             } else {
                 $this->inventory->setHeldItemSlot(0);
             }
             $pk = new LoginStatusPacket();
             $pk->status = 0;
             $this->dataPacket($pk);
             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 = $this->level->getSeed();
             $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);
             $pk = new SetHealthPacket();
             $pk->health = $this->getHealth();
             $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 . "[/" . $this->ip . ":" . $this->port . "] logged in with entity id " . $this->id . " at (" . $this->level->getName() . ", " . round($this->x, 4) . ", " . round($this->y, 4) . ", " . round($this->z, 4) . ")");
             $this->orderChunks();
             $this->sendNextChunk();
             break;
         case ProtocolInfo::ROTATE_HEAD_PACKET:
             if ($this->spawned === false or $this->dead === true) {
                 break;
             }
             $this->setRotation($packet->yaw, $this->pitch);
             break;
         case ProtocolInfo::MOVE_PLAYER_PACKET:
             $newPos = new Vector3($packet->x, $packet->y, $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 ($revert or $newPos->distanceSquared($this->forceMovement) > 0.04)) {
                 $pk = new MovePlayerPacket();
                 $pk->eid = 0;
                 $pk->x = $this->forceMovement->x;
                 $pk->y = $this->forceMovement->y + $this->getEyeHeight();
                 $pk->z = $this->forceMovement->z;
                 $pk->bodyYaw = $packet->bodyYaw;
                 $pk->pitch = $packet->pitch;
                 $pk->yaw = $packet->yaw;
                 $pk->teleport = true;
                 $this->directDataPacket($pk);
             } 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 = $this->getCreativeBlock($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 {
                     $this->inventory->setHeldItemSlot($packet->slot);
                     //set Air
                 }
             } 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()) {
                 $item = Item::get(Block::$creative[$slot][0], Block::$creative[$slot][1], 1);
                 $this->inventory->setHeldItemIndex($packet->slot);
             } else {
                 $this->inventory->setHeldItemSlot($slot);
             }
             $this->inventory->sendHeldItem($this->hasSpawned);
             if ($this->inAction === true) {
                 $this->inAction = false;
                 $this->sendMetadata($this->getViewers());
             }
             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
                 if ($this->inAction === true) {
                     $this->inAction = false;
                     $this->sendMetadata($this->getViewers());
                 }
                 if ($blockVector->distance($this) > 10) {
                 } 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;
                     }
                 }
                 $target = $this->level->getBlock($blockVector);
                 $block = $target->getSide($packet->face);
                 $pk = new UpdateBlockPacket();
                 $pk->x = $target->x;
                 $pk->y = $target->y;
                 $pk->z = $target->z;
                 $pk->block = $target->getId();
                 $pk->meta = $target->getDamage();
                 $this->dataPacket($pk);
                 $pk = new UpdateBlockPacket();
                 $pk->x = $block->x;
                 $pk->y = $block->y;
                 $pk->z = $block->z;
                 $pk->block = $block->getId();
                 $pk->meta = $block->getDamage();
                 $this->dataPacket($pk);
                 break;
             } elseif ($packet->face === 0xff) {
                 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();
                 }
                 $target = $this->level->getBlock($blockVector);
                 $ev = new PlayerInteractEvent($this, $item, $target, $packet->face);
                 $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("", -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)])]);
                     $f = 1.5;
                     $snowball = Entity::createEntity("Snowball", $this->chunk, $nbt, $this);
                     $snowball->setMotion($snowball->getMotion()->multiply($f));
                     if ($this->isSurvival()) {
                         $this->inventory->removeItem(Item::get(Item::SNOWBALL, 0, 1), $this);
                     }
                     if ($snowball instanceof Projectile) {
                         $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($snowball));
                         if ($projectileEv->isCancelled()) {
                             $snowball->kill();
                         } else {
                             $snowball->spawnToAll();
                         }
                     } else {
                         $snowball->spawnToAll();
                     }
                 }
                 $this->inAction = true;
                 $this->startAction = microtime(true);
                 $this->sendMetadata($this->getViewers());
             }
             break;
         case ProtocolInfo::PLAYER_ACTION_PACKET:
             if ($this->spawned === false or $this->blocked === true or $this->dead === true) {
                 break;
             }
             $this->craftingType = 0;
             $packet->eid = $this->id;
             switch ($packet->action) {
                 case 5:
                     //Shot arrow
                     if ($this->inventory->getItemInHand()->getId() === Item::BOW) {
                         $bow = $this->inventory->getItemInHand();
                         if ($this->isSurvival()) {
                             if (!$this->inventory->contains(Item::get(Item::ARROW, 0, 1))) {
                                 $this->inventory->sendContents($this);
                                 return;
                             }
                         }
                         $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)])]);
                         $f = 1.5;
                         $ev = new EntityShootBowEvent($this, $bow, Entity::createEntity("Arrow", $this->chunk, $nbt, $this), $f);
                         $this->server->getPluginManager()->callEvent($ev);
                         if ($ev->isCancelled()) {
                             $ev->getProjectile()->kill();
                         } else {
                             $ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce()));
                             if ($this->isSurvival()) {
                                 $this->inventory->removeItem(Item::get(Item::ARROW, 0, 1), $this);
                                 $bow->setDamage($bow->getDamage() + 1);
                                 $this->inventory->setItemInHand($bow, $this);
                                 if ($bow->getDamage() >= 385) {
                                     $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 0), $this);
                                 }
                             }
                             if ($ev->getProjectile() instanceof Projectile) {
                                 $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($ev->getProjectile()));
                                 if ($projectileEv->isCancelled()) {
                                     $ev->getProjectile()->kill();
                                 } else {
                                     $ev->getProjectile()->spawnToAll();
                                 }
                             } else {
                                 $ev->getProjectile()->spawnToAll();
                             }
                         }
                     }
                     $this->startAction = false;
                     $this->inAction = false;
                     $this->sendMetadata($this->getViewers());
                     break;
                 case 6:
                     //get out of the bed
                     $this->stopSleep();
                     break;
             }
             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);
             $pk = new UpdateBlockPacket();
             $pk->x = $target->x;
             $pk->y = $target->y;
             $pk->z = $target->z;
             $pk->block = $target->getId();
             $pk->meta = $target->getDamage();
             $this->dataPacket($pk);
             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("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::RESPAWN_PACKET:
             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->fireTicks = 0;
             $this->airTicks = 300;
             $this->deadTicks = 0;
             $this->setHealth(20);
             $this->dead = false;
             $this->sendMetadata($this->getViewers());
             $this->sendMetadata($this);
             $this->sendSettings();
             $this->inventory->sendContents($this);
             $this->inventory->sendArmorContents($this);
             $this->blocked = false;
             $this->spawnToAll();
             $this->scheduleUpdate();
             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;
             if ($this->inAction === true) {
                 $this->inAction = false;
                 $this->sendMetadata($this->getViewers());
             }
             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];
                     $slot = $this->inventory->getItemInHand();
                     if ($this->getHealth() < 20 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 = 0;
                         $pk->event = 9;
                         $this->dataPacket($pk);
                         $pk->eid = $this->getId();
                         Server::broadcastPacket($this->getViewers(), $pk);
                         $amount = $items[$slot->getId()];
                         $this->server->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($this, $amount, EntityRegainHealthEvent::CAUSE_EATING));
                         if (!$ev->isCancelled()) {
                             $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), $this);
                         }
                     }
                     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);
             if ($this->inAction === true) {
                 $this->inAction = false;
                 $this->sendMetadata($this->getViewers());
             }
             break;
         case ProtocolInfo::MESSAGE_PACKET:
             if ($this->spawned === false or $this->dead === true) {
                 break;
             }
             $this->craftingType = 0;
             $packet->message = TextFormat::clean($packet->message);
             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(sprintf($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 ($this->getCreativeBlock($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 === 0x78) {
                 //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) - 0.5) {
                 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()) {
                     $this->currentTransaction = null;
                     break;
                 }
                 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), $this);
                                 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::SEND_INVENTORY_PACKET:
             //TODO, Mojang, enable this ´^_^`
             if ($this->spawned === false) {
                 break;
             }
             break;
         case ProtocolInfo::ENTITY_DATA_PACKET:
             if ($this->spawned === false or $this->blocked === true or $this->dead === true) {
                 break;
             }
             $this->craftingType = 0;
             $t = $this->level->getTile(new Vector3($packet->x, $packet->y, $packet->z));
             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, [$nbt["Text1"], $nbt["Text2"], $nbt["Text3"], $nbt["Text4"]]);
                     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;
     }
 }
Пример #12
0
 public function clean()
 {
     $this->records = [];
     return parent::clean();
 }
 public function clean()
 {
     $this->teleport = \false;
     return parent::clean();
 }
Пример #14
0
 public function putPacket(Player $player, DataPacket $packet, $needACK = false, $immediate = false)
 {
     if (isset($this->identifiers[$player])) {
         $identifier = $this->identifiers[$player];
         $pk = null;
         if (!$packet->isEncoded) {
             $packet->encode();
         } elseif (!$needACK) {
             if (!isset($packet->__encapsulatedPacket)) {
                 $packet->__encapsulatedPacket = new CachedEncapsulatedPacket();
                 $packet->__encapsulatedPacket->identifierACK = null;
                 $packet->__encapsulatedPacket->buffer = $packet->buffer;
                 $packet->__encapsulatedPacket->reliability = 2;
             }
             $pk = $packet->__encapsulatedPacket;
         }
         if ($pk === null) {
             $pk = new EncapsulatedPacket();
             $pk->buffer = $packet->buffer;
             $pk->reliability = 2;
             if ($needACK === true) {
                 $pk->identifierACK = $this->identifiersACK[$identifier]++;
             }
         }
         $this->interface->sendEncapsulated($identifier, $pk, ($needACK === true ? RakLib::FLAG_NEED_ACK : 0) | ($immediate === true ? RakLib::PRIORITY_IMMEDIATE : RakLib::PRIORITY_NORMAL));
         return $pk->identifierACK;
     }
     return null;
 }
Пример #15
0
 public function serverToInterface(DesktopPlayer $player, DataPacket $packet)
 {
     switch ($packet->pid()) {
         case Info::UPDATE_BLOCK_PACKET:
             $pk = new BlockChangePacket();
             $pk->x = $packet->x;
             $pk->y = $packet->y;
             $pk->z = $packet->z;
             $pk->blockId = $packet->block;
             $pk->blockMeta = $packet->meta;
             return $pk;
         case Info::START_GAME_PACKET:
             $packets = [];
             $pk = new JoinGamePacket();
             $pk->eid = $packet->eid;
             $pk->gamemode = $player->getGamemode();
             $pk->dimension = 0;
             $pk->difficulty = $player->getServer()->getDifficulty();
             $pk->maxPlayers = $player->getServer()->getMaxPlayers();
             $pk->levelType = "default";
             $packets[] = $pk;
             $pk = new PlayerAbilitiesPacket();
             $pk->flyingSpeed = 0.05;
             $pk->walkingSpeed = 0.1;
             $pk->canFly = ($player->getGamemode() & 0x1) > 0;
             $pk->damageDisabled = ($player->getGamemode() & 0x1) > 0;
             $pk->isFlying = false;
             $pk->isCreative = ($player->getGamemode() & 0x1) > 0;
             if ($player->spawned === true) {
                 $packets = [$pk];
                 $pk = new ChangeGameStatePacket();
                 $pk->reason = 3;
                 $pk->value = $player->getGamemode();
                 $packets[] = $pk;
                 return $packets;
             } else {
                 $packets[] = $pk;
             }
             $pk = new SpawnPositionPacket();
             $pk->spawnX = $packet->spawnX;
             $pk->spawnY = $packet->spawnY;
             $pk->spawnZ = $packet->spawnZ;
             $packets[] = $pk;
             $pk = new PositionAndLookPacket();
             $pk->x = $packet->x;
             $pk->y = $packet->y;
             $pk->z = $packet->z;
             $pk->yaw = $player->yaw;
             $pk->pitch = $player->pitch;
             $pk->onGround = $player->isOnGround();
             $packets[] = $pk;
             return $packets;
         case Info::SET_HEALTH_PACKET:
             $pk = new UpdateHealthPacket();
             $pk->health = $packet->health;
             $pk->food = 20;
             $pk->saturation = 5;
             return $pk;
         case Info::TEXT_PACKET:
             $pk = new STCChatPacket();
             $pk->message = TextFormat::toJSON($packet->message);
             return $pk;
         case Info::SET_TIME_PACKET:
             $pk = new TimeUpdatePacket();
             $pk->age = $packet->time;
             $pk->time = $packet->time;
             //TODO: calculate offset from MCPE
             return $pk;
         case Info::SET_SPAWN_POSITION_PACKET:
             $pk = new SpawnPositionPacket();
             $pk->spawnX = $packet->x;
             $pk->spawnY = $packet->y;
             $pk->spawnZ = $packet->z;
             return $pk;
         case Info::REMOVE_ENTITY_PACKET:
         case Info::REMOVE_PLAYER_PACKET:
             $pk = new DestroyEntitiesPacket();
             $pk->ids[] = $packet->eid;
             return $pk;
         case Info::MOVE_PLAYER_PACKET:
             if ($packet->eid === 0) {
                 $pk = new PositionAndLookPacket();
                 $pk->x = $packet->x;
                 $pk->y = $packet->y;
                 $pk->z = $packet->z;
                 $pk->yaw = $packet->yaw;
                 $pk->pitch = $packet->pitch;
                 $pk->onGround = $player->isOnGround();
                 return $pk;
             } else {
                 $packets = [];
                 $pk = new EntityTeleportPacket();
                 $pk->eid = $packet->eid;
                 $pk->x = $packet->x;
                 $pk->y = $packet->y;
                 $pk->z = $packet->z;
                 $pk->yaw = $packet->yaw;
                 $pk->pitch = $packet->pitch;
                 $packets[] = $pk;
                 $pk = new EntityHeadLookPacket();
                 $pk->eid = $packet->eid;
                 $pk->yaw = $packet->yaw;
                 $packets[] = $pk;
                 return $packets;
             }
         case Info::MOVE_ENTITY_PACKET:
             $packets = [];
             foreach ($packet->entities as $d) {
                 $pk = new EntityTeleportPacket();
                 $pk->eid = $d[0];
                 $pk->x = $d[1];
                 $pk->y = $d[2];
                 $pk->z = $d[3];
                 $pk->yaw = $d[4];
                 $pk->pitch = $d[5];
                 $packets[] = $pk;
                 $pk = new EntityHeadLookPacket();
                 $pk->eid = $d[0];
                 $pk->yaw = $d[4];
                 $packets[] = $pk;
             }
             return $packets;
         case Info::SET_ENTITY_MOTION_PACKET:
             $packets = [];
             foreach ($packet->entities as $d) {
                 $pk = new EntityVelocityPacket();
                 $pk->eid = $d[0];
                 $pk->velocityX = $d[1];
                 $pk->velocityY = $d[2];
                 $pk->velocityZ = $d[3];
                 $packets[] = $pk;
             }
             return $packets;
             /*
             case Info::CONTAINER_CLOSE_PACKET:
             	$pk = new STCCloseWindowPacket();
             	$pk->windowID = $packet->windowid;
             	return $pk;
             
             case Info::CONTAINER_OPEN_PACKET:
             	$pk = new OpenWindowPacket();
             	$pk->windowID = $packet->windowid;
             	$pk->inventoryType = $packet->type;
             	$pk->windowTitle = "";
             	$pk->slots = $packet->slots;
             	return $pk;
             
             case Info::CONTAINER_SET_SLOT_PACKET:
             	$pk = new SetSlotPacket();
             	$pk->windowID = $packet->windowid;
             	if($pk->windowID === 0){
             		$pk->slot = $packet->slot + 9;
             	}elseif($pk->windowID === 0x78){
             		$pk->windowID = 0;
             		$pk->slot = $packet->slot + 5;
             	}else{
             		$pk->slot = $packet->slot;
             	}
             	$pk->item = $packet->item;
             	return $pk;
             
             case Info::CONTAINER_SET_CONTENT_PACKET:
             	$pk = new WindowItemsPacket();
             	$pk->windowID = $packet->windowid;
             	if($pk->windowID === 0 or $pk->windowID === 0x78){
             		$pk->windowID = 0;
             		for($i = 0; $i < 5; ++$i){
             			$pk->items[] = Item::get(Item::AIR, 0, 0);
             		}
             		$pk->items[] = $player->getInventory()->getHelmet();
             		$pk->items[] = $player->getInventory()->getChestplate();
             		$pk->items[] = $player->getInventory()->getLeggings();
             		$pk->items[] = $player->getInventory()->getBoots();
             		$slots = $player->getInventory()->getSize();
             		for($i = 0; $i < $slots; ++$i){
             			$pk->items[] = $player->getInventory()->getItem($i);
             		}
             	}else{
             		$pk->items = $packet->slots;
             	}
             
             	return $pk;
             */
         /*
         case Info::CONTAINER_CLOSE_PACKET:
         	$pk = new STCCloseWindowPacket();
         	$pk->windowID = $packet->windowid;
         	return $pk;
         
         case Info::CONTAINER_OPEN_PACKET:
         	$pk = new OpenWindowPacket();
         	$pk->windowID = $packet->windowid;
         	$pk->inventoryType = $packet->type;
         	$pk->windowTitle = "";
         	$pk->slots = $packet->slots;
         	return $pk;
         
         case Info::CONTAINER_SET_SLOT_PACKET:
         	$pk = new SetSlotPacket();
         	$pk->windowID = $packet->windowid;
         	if($pk->windowID === 0){
         		$pk->slot = $packet->slot + 9;
         	}elseif($pk->windowID === 0x78){
         		$pk->windowID = 0;
         		$pk->slot = $packet->slot + 5;
         	}else{
         		$pk->slot = $packet->slot;
         	}
         	$pk->item = $packet->item;
         	return $pk;
         
         case Info::CONTAINER_SET_CONTENT_PACKET:
         	$pk = new WindowItemsPacket();
         	$pk->windowID = $packet->windowid;
         	if($pk->windowID === 0 or $pk->windowID === 0x78){
         		$pk->windowID = 0;
         		for($i = 0; $i < 5; ++$i){
         			$pk->items[] = Item::get(Item::AIR, 0, 0);
         		}
         		$pk->items[] = $player->getInventory()->getHelmet();
         		$pk->items[] = $player->getInventory()->getChestplate();
         		$pk->items[] = $player->getInventory()->getLeggings();
         		$pk->items[] = $player->getInventory()->getBoots();
         		$slots = $player->getInventory()->getSize();
         		for($i = 0; $i < $slots; ++$i){
         			$pk->items[] = $player->getInventory()->getItem($i);
         		}
         	}else{
         		$pk->items = $packet->slots;
         	}
         
         	return $pk;
         */
         case Info::ADD_ITEM_ENTITY_PACKET:
             $packets = [];
             $pk = new SpawnObjectPacket();
             $pk->eid = $packet->eid;
             $pk->type = 2;
             $pk->x = $packet->x;
             $pk->y = $packet->y;
             $pk->z = $packet->z;
             $pk->yaw = $packet->yaw;
             $pk->pitch = $packet->pitch;
             $packets[] = $pk;
             $pk = new EntityMetadataPacket();
             $pk->eid = $packet->eid;
             $pk->metadata = $pk->metadata = [0 => ["type" => 0, "value" => 0], 10 => ["type" => 5, "value" => $packet->item]];
             $packets[] = $pk;
             return $packets;
         case Info::ADD_PLAYER_PACKET:
             $packets = [];
             $pk = new SpawnPlayerPacket();
             $pk->name = $packet->username;
             $pk->eid = $packet->eid;
             $pk->uuid = Binary::UUIDtoString("00000000000030008000000000000000");
             $pk->x = $packet->x;
             $pk->z = $packet->y;
             $pk->y = $packet->z;
             $pk->yaw = $packet->yaw;
             $pk->pitch = $packet->pitch;
             $pk->item = 0;
             $pk->metadata = $packet->metadata;
             $packets[] = $pk;
             $pk = new EntityTeleportPacket();
             $pk->eid = $packet->eid;
             $pk->x = $packet->x;
             $pk->y = $packet->y;
             $pk->z = $packet->z;
             $pk->yaw = $packet->yaw;
             $pk->pitch = $packet->pitch;
             $packets[] = $pk;
             return $packets;
         default:
             return null;
     }
 }