public function onPlayerRespawn(PlayerRespawnEvent $event) { //TODO send kit info if (isset($this->players[$event->getPlayer()->getName()])) { unset($this->players[$event->getPlayer()->getName()]); } }
public function onRespawn(PlayerRespawnEvent $e) { $cfg = $this->getConfig(); $player = $e->getPlayer(); $player->getInventory()->setItem(25, Item::get($cfg->get("HidePlayers-Item"), 0, 1)); $player->getInventory()->setItem(26, Item::get($cfg->get("ShowPlayers-Item"), 0, 1)); }
public function onPlayerRespawn(PlayerRespawnEvent $event) { $player = $event->getPlayer(); if ($player instanceof Player) { $this->plugin->petOwnerRegister($player, $event->getRespawnPosition()->getLevel()->getName()); } }
public function onPlayerRespawned(PlayerRespawnEvent $event) { $p = $event->getPlayer(); $level = $p->getLevel(); $light = new AddEntityPacket(); $light->type = 93; $light->eid = Entity::$entityCount++; $light->metadata = array(); $light->speedX = 9; $light->speedY = 0; $light->speedZ = -9; $light->yaw = $p->getYaw(); $light->pitch = $p->getPitch(); $light->x = $p->x; $light->y = $p->y; $light->z = $p->z; foreach ($level->getPlayers() as $pl) { $pl->dataPacket($light); $pl->addEffect(Effect::getEffect(Effect::SPEED)->setAmplifier(3)->setDuration(30000)); $pl->setGamemode(2); $pl->getInventory()->addItem(new Item(Item::COOKIE, 0, 64)); $pl->getInventory()->addItem(new Item(Item::SLIMEBALL, 0, 1)); $pl->getInventory()->addItem(new Item(Item::COAL, 0, 1)); $pl->getInventory()->addItem(new Item(Item::GUNPOWDER, 0, 1)); } }
public function onRespawn(PlayerRespawnEvent $event) { $x = $this->plugin->getServer()->getDefaultLevel()->getSafeSpawn()->getX(); $y = $this->plugin->getServer()->getDefaultLevel()->getSafeSpawn()->getY(); $z = $this->plugin->getServer()->getDefaultLevel()->getSafeSpawn()->getZ(); $event->setRespawnPosition(new Position($x, $y, $z)); $this->debug->onDebug('Zum Start respawnt'); }
public function onRespawn(PlayerRespawnEvent $event) { $cg = $this->getConfig(); $enablerecieveafterdeath = $cg->get("Enable-Receive-After-Death"); if ($enablerecieveafterdeath == true) { $p = $event->getPlayer(); $this->getServer()->getScheduler()->scheduleDelayedTask(new FineTask([$this, "Receive"], [$p]), 0); } }
public function checkRespawn(PlayerRespawnEvent $event) { $player = $event->getPlayer(); foreach ($player->getInventory()->getContents() as $item) { if ($item->getID() == Item::CRAFTING_TABLE) { return; } } $player->getInventory()->addItem(Item::get(Item::CRAFTING_TABLE)); }
/** * * @param PlayerRespawnEvent $event * * */ public function onPlayerRespawn(PlayerRespawnEvent $event) { $this->plugin->log("[HG] StatueListener: onPlayerRespawn for player " . $event->getPlayer()->getName()); $player = $event->getPlayer(); if (!isset($this->plugin->getStatueManager()->npcsSpawns[$player->getName()])) { $builder = new StatueBuilder($this->plugin); $builder->displayStatues($player, $this->plugin->statueManager->npcs); // $this->builder->spawnHallOfFrameWinners (); $this->plugin->getStatueManager->npcsSpawns[$player->getName()] = $player->getName(); } }
public function onPlayerRespawn(PlayerRespawnEvent $event) { if ($this->plugin->hasPlayedBefore($event->getPlayer()) && $this->plugin->isJailed($event->getPlayer())) { $t = $this->getPlugin()->data->getAll(); $j = $this->getPlugin()->data2->getAll(); $jail = $t[$event->getPlayer()->getName()]["jail"]; if ($this->getPlugin()->jailExists($jail)) { $event->setRespawnPosition(new Position($j[$jail]["x"], $j[$jail]["y"], $j[$jail]["z"], $this->getPlugin()->getServer()->getLevelByName($j[$jail]["world"]))); } } }
public function onPlayerRespawn(PlayerRespawnEvent $event) { $isMoveRequired = true; foreach (self::$respawnableGames as $game) { if ($game->isPlayerPlaying($event->getPlayer()->getName())) { $isMoveRequired = false; break; } } if ($isMoveRequired) { $event->setRespawnPosition(Server::getInstance()->getDefaultLevel()->getSpawnLocation()); } }
public function onRespawn(PlayerRespawnEvent $ent) { $player = $ent->getPlayer(); $lightningbolt = new AddEntityPacket(); $lightningbolt->type = 93; $lightningbolt->eid = Entity::$entityCount++; $lightningbolt->metadata = array(); $lightningbolt->speedX = 0; $lightningbolt->speedY = 0; $lightningbolt->speedZ = 0; $lightningbolt->x = $player->x; $lightningbolt->y = $player->y; $lightningbolt->z = $player->z; $player->dataPacket($lightningbolt); }
public function onRespawn(PlayerRespawnEvent $event) { $player = $event->getPlayer(); $name = $player->getName(); $coordinate = $this->temp->getNested("{$name}"); if (!isset($coordinate)) { return; } else { $targetWorld = $this->getServer()->getLevelByName($coordinate); $spawn = $targetWorld->getSpawnLocation(); $x = $spawn->getX(); $y = $spawn->getY(); $z = $spawn->getZ(); $event->setRespawnPosition($spawn); $this->temp->remove("{$name}"); } }
/** * @priority high */ public function onDeath(PlayerRespawnEvent $event) { $level = $event->getPlayer()->getLevel(); $pillarPos = new Position($event->getPlayer()->x, $event->getPlayer()->y, $event->getPlayer()->z, $level); for ($h = 1; $h <= 30; $h++) { $pillarPos->setComponents($pillarPos->x, ++$pillarPos->y, $pillarPos->z); $level->addParticle(new RedstoneParticle($pillarPos, 10)); } $pillarPos->setComponents($pillarPos->x, $pillarPos->y - 10, $pillarPos->z); $headPos = new Position($pillarPos->x, $pillarPos->y, $pillarPos->z, $level); for ($r = -5; $r <= 5; $r++) { $headPos->setComponents($pillarPos->x + $r, $pillarPos->y, $pillarPos->z); $level->addParticle(new ExplodeParticle($headPos)); $p = new RedstoneParticle($headPos, 10); $level->addParticle($p); } }
public function onPlayerRespawn(PlayerRespawnEvent $event) { $name = $event->getPlayer()->getName(); $p = $event->getPlayer(); $worldname = $this->config->get("Respawnworld"); if ($reason == "disconnectionScreen.serverFull") { $pl = $event->getPlayer(); $addr1 = $this->config->get("IP"); $addr2 = $this->config->get("Port"); $ft = $this->getServer()->getPluginManager()->getPlugin("FastTransfer"); if (!$ft) { $this->getLogger()->info("FAST TRANSFER NOT INSTALLED"); return; } $this->getLogger()->info(MT::YELLOW . "{$name} transfer to {$addr1} {$addr2}"); $ft->transferPlayer($pl, $addr1, $addr2); $event->setCancelled(true); } }
public function onPlayerRespawn(PlayerRespawnEvent $event) { $this->cfg = $this->plugin->getConfig()->getAll(); $player = $event->getPlayer(); //Check if the victim is a Player if ($player instanceof Player) { //Teleport Player on Death: 1 = Teleport to spawn 2 = Teleport to Hub if ($this->cfg["teleport-on-death"] == 1) { //Check if spawn exists if ($this->plugin->SpawnExists($player->getLevel())) { $pos = $this->plugin->getSpawn($player->getLevel()); $event->setRespawnPosition(new Position($pos["X"], $pos["Y"], $pos["Z"]), $pos["Yaw"], $pos["Pitch"]); } } elseif ($this->cfg["teleport-on-death"] == 2) { //Check if hub exists if ($this->plugin->HubExists()) { $this->plugin->teleportToHub($player); } } } }
public function playerSpawn(PlayerRespawnEvent $event) { $player = $event->getPlayer(); $authorized = "denied"; if ($this->SignShop->getSetup()->get("signCreated") == "admin" && $player->isOp()) { $authorized = "allow"; } if ($this->SignShop->getSetup()->get("signCreated") == "all") { $authorized = "allow"; } if ($this->SignShop->getProvider()->existsPlayer($player->getName())) { $get = $this->SignShop->getProvider()->getPlayer($player->getName()); if ($get["changed"] < $this->SignShop->getSetup()->get("lastChanged")) { $get["authorized"] = $authorized; $get["changed"] = time(); $this->SignShop->getProvider()->setPlayer($player->getName(), $get); } } else { $this->SignShop->getProvider()->setPlayer($player->getName(), ["authorized" => $authorized, "changed" => time(), "echo" => true]); } }
public function onRespawn(PlayerRespawnEvent $e) { if ($this->getConfig()->get("Respawn") === true) { $p = $e->getPlayer(); $level = $p->getLevel(); $light = new AddEntityPacket(); $light->type = 93; $light->eid = Entity::$entityCount++; $light->metadata = array(); $light->speedX = 0; $light->speedY = 0; $light->speedZ = 0; $light->yaw = $p->getYaw(); $light->pitch = $p->getPitch(); $light->x = $p->x; $light->y = $p->y; $light->z = $p->z; foreach ($level->getPlayers() as $pl) { $pl->dataPacket($light); } } }
public function onRespawn(PlayerRespawnEvent $event) { $event->setRespawnPosition($this->respawnPosition); }
public function onRespawn(PlayerRespawnEvent $event) { $player = $event->getPlayer(); $player->setNameTag($player->getName()); }
/** * @priority MONITOR */ public function onRespawnEvent(PlayerRespawnEvent $ev) { $pl = $ev->getPlayer(); $this->addFx([$pl]); }
public function onRespawn(PlayerRespawnEvent $event) { $player = $event->getPlayer(); $config = $this->getConfig()->getAll(); if ($config["Nametag"]["Enabled"] === true) { $this->getServer()->getScheduler()->scheduleDelayedTask(new Task($this, $player), 1); } }
protected function sendNextChunk() { if ($this->connected === false) { return; } $count = 0; foreach ($this->loadQueue as $index => $distance) { if ($count >= $this->chunksPerTick) { break; } Level::getXZ($index, $X, $Z); if (!$this->level->isChunkPopulated($X, $Z)) { $this->level->generateChunk($X, $Z); if ($this->spawned) { continue; } else { break; } } ++$count; unset($this->loadQueue[$index]); $this->usedChunks[$index] = true; $this->level->useChunk($X, $Z, $this); $chunk = $this->level->getChunk($X, $Z); if ($chunk instanceof AnvilChunk) { $this->kick("Playing on Anvil worlds is not yet implemented"); //TODO! /*$pk = new ChunkDataPacket(); $pk->chunkX = $X; $pk->chunkZ = $Z; $pk->groundUp = true; $ids = ""; $meta = ""; $blockLight = ""; $skyLight = ""; $biomeIds = $chunk->getBiomeIdArray(); $bitmap = 0; for($s = 0; $s < 8; ++$s){ $section = $chunk->getSection($s); if(!($section instanceof EmptyChunkSection)){ $bitmap |= 1 << $s; }else{ continue; } $ids .= $section->getIdArray(); $meta .= $section->getDataArray(); $blockLight .= $section->getLightArray(); $skyLight .= $section->getSkyLightArray(); } $pk->payload = zlib_encode($ids . $meta . $blockLight . $skyLight . $biomeIds, ZLIB_ENCODING_DEFLATE, Level::$COMPRESSION_LEVEL); $pk->primaryBitmap = $bitmap; $this->putRawPacket($pk);*/ } elseif ($chunk instanceof McRegionChunk) { $task = new McRegionToAnvil($this, $chunk); $this->server->getScheduler()->scheduleAsyncTask($task); } elseif ($chunk instanceof LevelDBChunk) { $task = new LevelDBToAnvil($this, $chunk); $this->server->getScheduler()->scheduleAsyncTask($task); } foreach ($chunk->getEntities() as $entity) { if ($entity !== $this) { $entity->spawnTo($this); } } foreach ($chunk->getTiles() as $tile) { if ($tile instanceof Spawnable) { $tile->spawnTo($this); } } } if (count($this->usedChunks) >= 4 and $this->spawned === false) { $this->bigBrother_setTitleBar(TextFormat::YELLOW . TextFormat::BOLD . "This is a beta version of BigBrother.", 0); $this->spawned = true; $pk = new SetTimePacket(); $pk->time = $this->level->getTime(); $pk->started = $this->level->stopTime == false; $this->dataPacket($pk); $pos = $this->level->getSafeSpawn($this); $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $pos)); $this->teleport($ev->getRespawnPosition()); $this->sendSettings(); $this->inventory->sendContents($this); $this->inventory->sendArmorContents($this); $this->server->getPluginManager()->callEvent($ev = new PlayerJoinEvent($this, TextFormat::YELLOW . $this->getName() . " joined the game")); if (strlen(trim($ev->getJoinMessage())) > 0) { $this->server->broadcastMessage($ev->getJoinMessage()); } $this->spawnToAll(); if ($this->server->getUpdater()->hasUpdate() and $this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)) { $this->server->getUpdater()->showPlayerUpdate($this); } } }
public function onRespawn(PlayerRespawnEvent $event) { $player = $event->getPlayer(); $this->getServer()->getScheduler()->scheduleDelayedTask(new TeleportTask($this, $player->getName()), 5); if (!$player->getInventory()->contains(Item::get(self::GRENADE_ID))) { $player->getInventory()->addItem(Item::get(self::GRENADE_ID, 0, 2)); } if (!$player->getInventory()->contains(Item::get(self::GUN_ID))) { $player->getInventory()->addItem(Item::get(self::GUN_ID)); } $this->players[$player->getName()][3] = time(); if (isset($this->players[$player->getName()][0])) { $this->players[$player->getName()][0]->setAmmo($this->players[$player->getName()][0]->getDefaultAmmo()); } }
/** * @param PlayerRespawnEvent $event * * @priority MONITOR */ public function onPlayerRespawn(PlayerRespawnEvent $event) { if (!$this->plugin->isPlayerAuthenticated($event->getPlayer())) { $this->plugin->sendAuthenticateMessage($event->getPlayer()); } }
public function onPlayerRespawn(PlayerRespawnEvent $ev) { $pl = $ev->getPlayer(); $level = $pl->getLocation()->getLevel(); $this->spawnPlayerCases($pl, $level); }
/** * Handles a Minecraft packet * TODO: Separate all of this in handlers * * WARNING: Do not use this, it's only for internal use. * Changes to this function won't be recorded on the version. * * @param DataPacket $packet */ public function handleDataPacket(DataPacket $packet) { if ($this->connected === false) { return; } if ($packet->pid() === ProtocolInfo::BATCH_PACKET) { /** @var BatchPacket $packet */ $this->server->getNetwork()->processBatch($packet, $this); return; } $this->server->getPluginManager()->callEvent($ev = new DataPacketReceiveEvent($this, $packet)); if ($ev->isCancelled()) { return; } switch ($packet->pid()) { case ProtocolInfo::LOGIN_PACKET: /* * A/N: Not going to implement any session code until it actually does stuff. * Single line functions are obnoxious to follow. */ if ($this->loggedIn === true) { break; } $this->username = TextFormat::clean($packet->username); $this->displayName = $this->username; $this->setNameTag($this->username); $this->iusername = strtolower($this->username); $this->randomClientId = $packet->clientId; $this->loginData = ["clientId" => $packet->clientId, "loginData" => null]; $this->uuid = $packet->clientUUID; $this->rawUUID = $this->uuid->toBinary(); $this->clientSecret = $packet->clientSecret; $this->protocol = $packet->protocol1; if (count($this->server->getOnlinePlayers()) > $this->server->getMaxPlayers() and $this->kick("Server is full")) { break; } if ($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL) { $message = ""; if ($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL) { $message = "Please update Minecraft PE to join."; $pk = new PlayStatusPacket(); $pk->status = PlayStatusPacket::LOGIN_FAILED_CLIENT; $this->dataPacket($pk); } else { $message = "Please use an older version of Minecraft PE."; $pk = new PlayStatusPacket(); $pk->status = PlayStatusPacket::LOGIN_FAILED_SERVER; $this->dataPacket($pk); } $this->close("", $message, false); return; } if (strpos($packet->username, "") !== false or preg_match('#^[a-zA-Z0-9_]{3,16}$#', $packet->username) == 0 or $this->username === "" or $this->iusername === "rcon" or $this->iusername === "console" or strlen($packet->username) > 16 or strlen($packet->username) < 3) { $this->close("", "Please choose a valid username."); return; } if (strlen($packet->skin) < 64 * 32 * 4) { $this->close("", "Invalid skin.", false); return; } $this->setSkin($packet->skin, $packet->slim); $this->server->getPluginManager()->callEvent($ev = new PlayerPreLoginEvent($this, "Plugin reason")); if ($ev->isCancelled()) { $this->close("", $ev->getKickMessage()); return; } if (!$this->server->isWhitelisted(strtolower($this->getName()))) { $this->close(TextFormat::YELLOW . $this->username . " has left the game", "Server is private."); return; } elseif ($this->server->getNameBans()->isBanned(strtolower($this->getName())) or $this->server->getIPBans()->isBanned($this->getAddress())) { $this->close(TextFormat::YELLOW . $this->username . " has left the game", "You have been banned."); return; } if ($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)) { $this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this); } if ($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)) { $this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this); } foreach ($this->server->getOnlinePlayers() as $p) { if ($p !== $this and strtolower($p->getName()) === strtolower($this->getName())) { if ($p->kick("You connected from somewhere else.") === false) { $this->close(TextFormat::YELLOW . $this->getName() . " has left the game", "You connected from somewhere else."); return; } else { return; } } } $nbt = $this->server->getOfflinePlayerData($this->username); if (!isset($nbt->NameTag)) { $nbt->NameTag = new String("NameTag", $this->username); } else { $nbt["NameTag"] = $this->username; } $this->gamemode = $nbt["playerGameType"] & 0x3; if ($this->server->getForceGamemode()) { $this->gamemode = $this->server->getGamemode(); $nbt->playerGameType = new Int("playerGameType", $this->gamemode); } $this->allowFlight = $this->isCreative(); if (($level = $this->server->getLevelByName($nbt["Level"])) === null) { $this->setLevel($this->server->getDefaultLevel(), true); $nbt["Level"] = $this->level->getName(); $nbt["Pos"][0] = $this->level->getSpawnLocation()->x; $nbt["Pos"][1] = $this->level->getSpawnLocation()->y + 5; $nbt["Pos"][2] = $this->level->getSpawnLocation()->z; } else { $this->setLevel($level, true); } if (!$nbt instanceof Compound) { $this->close(TextFormat::YELLOW . $this->username . " has left the game", "Corrupt joining data, check your connection."); return; } $this->achievements = []; /** @var Byte $achievement */ foreach ($nbt->Achievements as $achievement) { $this->achievements[$achievement->getName()] = $achievement->getValue() > 0 ? true : false; } $nbt->lastPlayed = new Long("lastPlayed", floor(microtime(true) * 1000)); parent::__construct($this->level->getChunk($nbt["Pos"][0] >> 4, $nbt["Pos"][2] >> 4, true), $nbt); $this->loggedIn = true; $this->server->addOnlinePlayer($this); $this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason")); if ($ev->isCancelled()) { $this->close(TextFormat::YELLOW . $this->username . " has left the game", $ev->getKickMessage()); return; } if ($this->isCreative()) { $this->inventory->setHeldItemSlot(0); } else { $this->inventory->setHeldItemSlot($this->inventory->getHotbarSlotIndex(0)); } $pk = new PlayStatusPacket(); $pk->status = PlayStatusPacket::LOGIN_SUCCESS; $this->dataPacket($pk); $this->uuid = $packet->clientUUID; $this->rawUUID = $this->uuid->toBinary(); $this->clientSecret = $packet->clientSecret; if ($this->spawnPosition === null and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level) { $this->spawnPosition = new Position($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level); } $spawnPosition = $this->getSpawn(); $pk = new StartGamePacket(); $pk->seed = -1; $pk->dimension = 0; $pk->x = $this->x; $pk->y = $this->y; $pk->z = $this->z; $pk->spawnX = (int) $spawnPosition->x; $pk->spawnY = (int) $spawnPosition->y; $pk->spawnZ = (int) $spawnPosition->z; $pk->generator = 1; //0 old, 1 infinite, 2 flat $pk->gamemode = $this->gamemode & 0x1; $pk->eid = 0; //Always use EntityID as zero for the actual player $this->dataPacket($pk); $pk = new SetTimePacket(); $pk->time = $this->level->getTime(); $pk->started = $this->level->stopTime == false; $this->dataPacket($pk); $pk = new SetSpawnPositionPacket(); $pk->x = (int) $spawnPosition->x; $pk->y = (int) $spawnPosition->y; $pk->z = (int) $spawnPosition->z; $this->dataPacket($pk); if ($this->getHealth() <= 0) { $this->dead = true; } $pk = new SetDifficultyPacket(); $pk->difficulty = $this->server->getDifficulty(); $this->dataPacket($pk); $this->server->getLogger()->info(TextFormat::AQUA . $this->username . TextFormat::WHITE . "/" . TextFormat::AQUA . $this->ip . " connected"); if ($this->gamemode === Player::SPECTATOR) { $pk = new ContainerSetContentPacket(); $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE; $this->dataPacket($pk); } else { $pk = new ContainerSetContentPacket(); $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE; foreach (Item::getCreativeItems() as $item) { $pk->slots[] = clone $item; } $this->dataPacket($pk); } $this->server->sendFullPlayerListData($this); $this->server->sendRecipeList($this); // $this->orderChunks(); // $this->sendNextChunk(); break; case ProtocolInfo::MOVE_PLAYER_PACKET: $newPos = new Vector3($packet->x, $packet->y - $this->getEyeHeight(), $packet->z); $revert = false; if ($this->dead === true or $this->spawned !== true) { $revert = true; $this->forceMovement = new Vector3($this->x, $this->y, $this->z); } if ($this->forceMovement instanceof Vector3 and (($dist = $newPos->distanceSquared($this->forceMovement)) > 0.04 or $revert)) { $this->sendPosition($this->forceMovement, $packet->yaw, $packet->pitch); } else { $packet->yaw %= 360; $packet->pitch %= 360; if ($packet->yaw < 0) { $packet->yaw += 360; } $this->setRotation($packet->yaw, $packet->pitch); $this->newPosition = $newPos; $this->forceMovement = null; } break; case ProtocolInfo::MOB_EQUIPMENT_PACKET: if ($this->spawned === false or $this->dead === true) { break; } if ($packet->slot === 0x28 or $packet->slot === 0 or $packet->slot === 255) { //0 for 0.8.0 compatibility $packet->slot = -1; //Air } else { $packet->slot -= 9; //Get real block slot } /** @var Item $item */ $item = null; if ($this->isCreative()) { //Creative mode match $item = $packet->item; $slot = Item::getCreativeItemIndex($item); } else { $item = $this->inventory->getItem($packet->slot); $slot = $packet->slot; } if ($packet->slot === -1) { //Air if ($this->isCreative()) { $found = false; for ($i = 0; $i < $this->inventory->getHotbarSize(); ++$i) { if ($this->inventory->getHotbarSlotIndex($i) === -1) { $this->inventory->setHeldItemIndex($i); $found = true; break; } } if (!$found) { //couldn't find a empty slot (error) $this->inventory->sendContents($this); break; } } else { if ($packet->selectedSlot >= 0 and $packet->selectedSlot < 9) { $this->inventory->setHeldItemIndex($packet->selectedSlot); $this->inventory->setHeldItemSlot($packet->slot); } else { $this->inventory->sendContents($this); break; } } } elseif ($item === null or $slot === -1 or !$item->deepEquals($packet->item)) { // packet error or not implemented $this->inventory->sendContents($this); break; } elseif ($this->isCreative()) { $this->inventory->setHeldItemIndex($packet->selectedSlot); $this->inventory->setItem($packet->selectedSlot, $item); $this->inventory->setHeldItemSlot($packet->selectedSlot); } else { if ($packet->selectedSlot >= 0 and $packet->selectedSlot < 9) { $this->inventory->setHeldItemIndex($packet->selectedSlot); $this->inventory->setHeldItemSlot($slot); } else { $this->inventory->sendContents($this); break; } } $this->inventory->sendHeldItem($this->hasSpawned); $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); break; case ProtocolInfo::USE_ITEM_PACKET: if ($this->spawned === false or $this->dead === true or $this->blocked) { break; } $blockVector = new Vector3($packet->x, $packet->y, $packet->z); $this->craftingType = 0; if ($packet->face >= 0 and $packet->face <= 5) { //Use Block, place $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); if ($blockVector->distance($this) > 10 or $this->isCreative() and $this->isAdventure()) { } elseif ($this->isCreative()) { $item = $this->inventory->getItemInHand(); if ($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true) { break; } } elseif (!$this->inventory->getItemInHand()->deepEquals($packet->item)) { $this->inventory->sendHeldItem($this); } else { $item = $this->inventory->getItemInHand(); $oldItem = clone $item; //TODO: Implement adventure mode checks if ($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this)) { if (!$item->deepEquals($oldItem) or $item->getCount() !== $oldItem->getCount()) { $this->inventory->setItemInHand($item, $this); $this->inventory->sendHeldItem($this->hasSpawned); } break; } } $this->inventory->sendHeldItem($this); if ($blockVector->distanceSquared($this) > 10000) { break; } $target = $this->level->getBlock($blockVector); $block = $target->getSide($packet->face); $this->level->sendBlocks([$this], [$target, $block], UpdateBlockPacket::FLAG_ALL_PRIORITY); break; } elseif ($packet->face === 0xff) { $aimPos = (new Vector3($packet->x / 32768, $packet->y / 32768, $packet->z / 32768))->normalize(); if ($this->isCreative()) { $item = $this->inventory->getItemInHand(); } elseif (!$this->inventory->getItemInHand()->deepEquals($packet->item)) { $this->inventory->sendHeldItem($this); break; } else { $item = $this->inventory->getItemInHand(); } $ev = new PlayerInteractEvent($this, $item, $aimPos, $packet->face, PlayerInteractEvent::RIGHT_CLICK_AIR); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->inventory->sendHeldItem($this); break; } if ($item->getId() === Item::SNOWBALL) { $nbt = new Compound("", ["Pos" => new Enum("Pos", [new Double("", $this->x), new Double("", $this->y + $this->getEyeHeight()), new Double("", $this->z)]), "Motion" => new Enum("Motion", [new Double("", $aimPos->x), new Double("", $aimPos->y), new Double("", $aimPos->z)]), "Rotation" => new Enum("Rotation", [new Float("", $this->yaw), new Float("", $this->pitch)])]); $f = 1.5; $snowball = Entity::createEntity("Snowball", $this->chunk, $nbt, $this); $snowball->setMotion($snowball->getMotion()->multiply($f)); if ($this->isSurvival()) { $item->setCount($item->getCount() - 1); $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR)); } if ($snowball instanceof Projectile) { $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($snowball)); if ($projectileEv->isCancelled()) { $snowball->kill(); } else { $snowball->spawnToAll(); $this->level->addSound(new LaunchSound($this), $this->getViewers()); } } else { $snowball->spawnToAll(); } } $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, true); $this->startAction = $this->server->getTick(); } break; case ProtocolInfo::PLAYER_ACTION_PACKET: if ($this->spawned === false or $this->blocked === true or $this->dead === true and $packet->action !== 7) { break; } $this->craftingType = 0; $packet->eid = $this->id; $pos = new Vector3($packet->x, $packet->y, $packet->z); switch ($packet->action) { case PlayerActionPacket::ACTION_START_BREAK: if ($this->lastBreak !== PHP_INT_MAX or $pos->distanceSquared($this) > 10000) { break; } $target = $this->level->getBlock($pos); $ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, $packet->face, $target->getId() === 0 ? PlayerInteractEvent::LEFT_CLICK_AIR : PlayerInteractEvent::LEFT_CLICK_BLOCK); $this->getServer()->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->inventory->sendHeldItem($this); break; } $this->lastBreak = microtime(true); break; case PlayerActionPacket::ACTION_ABORT_BREAK: $this->lastBreak = PHP_INT_MAX; break; case PlayerActionPacket::ACTION_RELEASE_ITEM: if ($this->startAction > -1 and $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION)) { if ($this->inventory->getItemInHand()->getId() === Item::BOW) { $bow = $this->inventory->getItemInHand(); if ($this->isSurvival() and !$this->inventory->contains(Item::get(Item::ARROW, 0, 1))) { $this->inventory->sendContents($this); break; } $nbt = new Compound("", ["Pos" => new Enum("Pos", [new Double("", $this->x), new Double("", $this->y + $this->getEyeHeight()), new Double("", $this->z)]), "Motion" => new Enum("Motion", [new Double("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new Double("", -sin($this->pitch / 180 * M_PI)), new Double("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new Enum("Rotation", [new Float("", $this->yaw), new Float("", $this->pitch)]), "Fire" => new Short("Fire", $this->isOnFire() ? 45 * 60 : 0)]); $diff = $this->server->getTick() - $this->startAction; $p = $diff / 20; $f = min(($p ** 2 + $p * 2) / 3, 1) * 2; $ev = new EntityShootBowEvent($this, $bow, Entity::createEntity("Arrow", $this->chunk, $nbt, $this, $f == 2 ? true : false), $f); if ($f < 0.1 or $diff < 5) { $ev->setCancelled(); } $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $ev->getProjectile()->kill(); $this->inventory->sendContents($this); } else { $ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce())); if ($this->isSurvival()) { $this->inventory->removeItem(Item::get(Item::ARROW, 0, 1)); $bow->setDamage($bow->getDamage() + 1); if ($bow->getDamage() >= 385) { $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 0)); } else { $this->inventory->setItemInHand($bow); } } if ($ev->getProjectile() instanceof Projectile) { $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($ev->getProjectile())); if ($projectileEv->isCancelled()) { $ev->getProjectile()->kill(); } else { $ev->getProjectile()->spawnToAll(); $this->level->addSound(new LaunchSound($this), $this->getViewers()); } } else { $ev->getProjectile()->spawnToAll(); } } } } elseif ($this->inventory->getItemInHand()->getId() === Item::BUCKET and $this->inventory->getItemInHand()->getDamage() === 1) { //Milk! $this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $this->inventory->getItemInHand())); if ($ev->isCancelled()) { $this->inventory->sendContents($this); break; } $pk = new EntityEventPacket(); $pk->eid = $this->getId(); $pk->event = EntityEventPacket::USE_ITEM; $this->dataPacket($pk); Server::broadcastPacket($this->getViewers(), $pk); if ($this->isSurvival()) { $slot = $this->inventory->getItemInHand(); --$slot->count; $this->inventory->setItemInHand($slot); $this->inventory->addItem(Item::get(Item::BUCKET, 0, 1)); } $this->removeAllEffects(); } else { $this->inventory->sendContents($this); } break; case PlayerActionPacket::ACTION_STOP_SLEEPING: $this->stopSleep(); break; case PlayerActionPacket::ACTION_RESPAWN: if ($this->spawned === false or $this->isAlive() or !$this->isOnline()) { break; } if ($this->server->isHardcore()) { $this->setBanned(true); break; } $this->craftingType = 0; $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn())); $this->teleport($ev->getRespawnPosition()); $this->setSprinting(false); $this->setSneaking(false); $this->extinguish(); $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 300); $this->deadTicks = 0; $this->dead = false; $this->noDamageTicks = 60; $this->setHealth($this->getMaxHealth()); $this->setFood(20); $this->starvationTick = 0; $this->foodTick = 0; $this->lastSentVitals = 10; $this->foodUsageTime = 0; $this->removeAllEffects(); $this->sendData($this); $this->sendSettings(); $this->inventory->sendContents($this); $this->inventory->sendArmorContents($this); $this->blocked = false; $this->spawnToAll(); $this->scheduleUpdate(); break; case PlayerActionPacket::ACTION_START_SPRINT: $ev = new PlayerToggleSprintEvent($this, true); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->sendData($this); } else { $this->setSprinting(true); } break; case PlayerActionPacket::ACTION_STOP_SPRINT: $ev = new PlayerToggleSprintEvent($this, false); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->sendData($this); } else { $this->setSprinting(false); } break; case PlayerActionPacket::ACTION_START_SNEAK: $ev = new PlayerToggleSneakEvent($this, true); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->sendData($this); } else { $this->setSneaking(true); } break; case PlayerActionPacket::ACTION_STOP_SNEAK: $ev = new PlayerToggleSneakEvent($this, false); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->sendData($this); } else { $this->setSneaking(false); } break; } $this->startAction = -1; $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); break; case ProtocolInfo::REMOVE_BLOCK_PACKET: if ($this->spawned === false or $this->blocked === true or $this->dead === true) { break; } $this->craftingType = 0; $vector = new Vector3($packet->x, $packet->y, $packet->z); if ($this->isCreative()) { $item = $this->inventory->getItemInHand(); } else { $item = $this->inventory->getItemInHand(); } $oldItem = clone $item; if ($this->level->useBreakOn($vector, $item, $this) === true) { if ($this->isSurvival()) { if (!$item->equals($oldItem, true) or $item->getCount() !== $oldItem->getCount()) { $this->inventory->setItemInHand($item, $this); $this->inventory->sendHeldItem($this->hasSpawned); } } break; } $this->inventory->sendContents($this); $target = $this->level->getBlock($vector); $tile = $this->level->getTile($vector); $this->level->sendBlocks([$this], [$target], UpdateBlockPacket::FLAG_ALL_PRIORITY); $this->inventory->sendHeldItem($this); if ($tile instanceof Spawnable) { $tile->spawnTo($this); } break; case ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET: break; case ProtocolInfo::INTERACT_PACKET: if ($this->spawned === false or $this->dead === true or $this->blocked) { break; } $this->craftingType = 0; $target = $this->level->getEntity($packet->target); $cancelled = false; if ($target instanceof Player and $this->server->getConfigBoolean("pvp", true) === false) { $cancelled = true; } if ($target instanceof Entity and $this->getGamemode() !== Player::VIEW and $this->dead !== true and $target->dead !== true) { if ($target instanceof DroppedItem or $target instanceof Arrow) { $this->kick("Attempting to attack an invalid entity"); $this->server->getLogger()->warning("Player " . $this->getName() . " tried to attack an invalid entity"); return; } $item = $this->inventory->getItemInHand(); $damageTable = [Item::WOODEN_SWORD => 4, Item::GOLD_SWORD => 4, Item::STONE_SWORD => 5, Item::IRON_SWORD => 6, Item::DIAMOND_SWORD => 7, Item::WOODEN_AXE => 3, Item::GOLD_AXE => 3, Item::STONE_AXE => 3, Item::IRON_AXE => 5, Item::DIAMOND_AXE => 6, Item::WOODEN_PICKAXE => 2, Item::GOLD_PICKAXE => 2, Item::STONE_PICKAXE => 3, Item::IRON_PICKAXE => 4, Item::DIAMOND_PICKAXE => 5, Item::WOODEN_SHOVEL => 1, Item::GOLD_SHOVEL => 1, Item::STONE_SHOVEL => 2, Item::IRON_SHOVEL => 3, Item::DIAMOND_SHOVEL => 4]; $damage = [EntityDamageEvent::MODIFIER_BASE => isset($damageTable[$item->getId()]) ? $damageTable[$item->getId()] : 1]; if ($this->distance($target) > 8) { $cancelled = true; } elseif ($target instanceof Player) { if (($target->getGamemode() & 0x1) > 0) { break; } elseif ($this->server->getConfigBoolean("pvp") !== true or $this->server->getDifficulty() === 0) { $cancelled = true; } $armorValues = [Item::LEATHER_CAP => 1, Item::LEATHER_TUNIC => 3, Item::LEATHER_PANTS => 2, Item::LEATHER_BOOTS => 1, Item::CHAIN_HELMET => 1, Item::CHAIN_CHESTPLATE => 5, Item::CHAIN_LEGGINGS => 4, Item::CHAIN_BOOTS => 1, Item::GOLD_HELMET => 1, Item::GOLD_CHESTPLATE => 5, Item::GOLD_LEGGINGS => 3, Item::GOLD_BOOTS => 1, Item::IRON_HELMET => 2, Item::IRON_CHESTPLATE => 6, Item::IRON_LEGGINGS => 5, Item::IRON_BOOTS => 2, Item::DIAMOND_HELMET => 3, Item::DIAMOND_CHESTPLATE => 8, Item::DIAMOND_LEGGINGS => 6, Item::DIAMOND_BOOTS => 3]; $points = 0; foreach ($target->getInventory()->getArmorContents() as $index => $i) { if (isset($armorValues[$i->getId()])) { $points += $armorValues[$i->getId()]; } } $damage[EntityDamageEvent::MODIFIER_ARMOR] = -floor($damage[EntityDamageEvent::MODIFIER_BASE] * $points * 0.04); } $ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage); if ($cancelled) { $ev->setCancelled(); } $target->attack($ev->getFinalDamage(), $ev); if ($ev->isCancelled()) { if ($item->isTool() and $this->isSurvival()) { $this->inventory->sendContents($this); } break; } if ($item->isTool() and $this->isSurvival()) { if ($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()) { $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1), $this); } else { $this->inventory->setItemInHand($item, $this); } } } break; case ProtocolInfo::ANIMATE_PACKET: if ($this->spawned === false or $this->dead === true) { break; } $this->server->getPluginManager()->callEvent($ev = new PlayerAnimationEvent($this, $packet->action)); if ($ev->isCancelled()) { break; } $pk = new AnimatePacket(); $pk->eid = $this->getId(); $pk->action = $ev->getAnimationType(); Server::broadcastPacket($this->getViewers(), $pk); break; case ProtocolInfo::SET_HEALTH_PACKET: //Not used break; case ProtocolInfo::ENTITY_EVENT_PACKET: if ($this->spawned === false or $this->blocked === true or $this->dead === true) { break; } $this->craftingType = 0; $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); //TODO: check if this should be true switch ($packet->event) { case 9: //Eating $this->eatFoodInHand(); break; } break; case ProtocolInfo::DROP_ITEM_PACKET: if ($this->spawned === false or $this->blocked === true or $this->dead === true) { break; } if (!$this->inventory->contains($packet->item)) { $this->inventory->sendContents($this); break; } $slot = $this->inventory->first($packet->item); if ($slot == -1) { break; } $item = $this->inventory->getItem($slot); $ev = new PlayerDropItemEvent($this, $item); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->inventory->sendSlot($slot, $this); break; } $this->inventory->setItem($slot, Item::get(Item::AIR, null, 0)); $motion = $this->getDirectionVector()->multiply(0.4); $this->level->dropItem($this->add(0, 1.3, 0), $item, $motion, 40); $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); break; case ProtocolInfo::TEXT_PACKET: if ($this->spawned === false or $this->dead === true) { break; } $this->craftingType = 0; if ($packet->type === TextPacket::TYPE_CHAT) { $packet->message = TextFormat::clean($packet->message, $this->removeFormat); foreach (explode("\n", $packet->message) as $message) { if (trim($message) != "" and strlen($message) <= 255 and $this->messageCounter-- > 0) { $ev = new PlayerCommandPreprocessEvent($this, $message); if (mb_strlen($ev->getMessage(), "UTF-8") > 320) { $ev->setCancelled(); } $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { break; } if (substr($ev->getMessage(), 0, 1) === "/") { //Command Timings::$playerCommandTimer->startTiming(); $this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 1)); Timings::$playerCommandTimer->stopTiming(); } else { $this->server->getPluginManager()->callEvent($ev = new PlayerChatEvent($this, $ev->getMessage())); if (!$ev->isCancelled()) { $this->server->broadcastMessage($ev->getPlayer()->getDisplayName() . ": " . $ev->getMessage(), $ev->getRecipients()); } } $ev = new PlayerCommandPostprocessEvent($this, $message); $this->server->getPluginManager()->callEvent($ev); } } } break; case ProtocolInfo::CONTAINER_CLOSE_PACKET: if ($this->spawned === false or $packet->windowid === 0) { break; } $this->craftingType = 0; $this->currentTransaction = null; if (isset($this->windowIndex[$packet->windowid])) { $this->server->getPluginManager()->callEvent(new InventoryCloseEvent($this->windowIndex[$packet->windowid], $this)); $this->removeWindow($this->windowIndex[$packet->windowid]); } else { unset($this->windowIndex[$packet->windowid]); } break; case ProtocolInfo::CRAFTING_EVENT_PACKET: if ($this->spawned === false or $this->dead) { break; } elseif (!isset($this->windowIndex[$packet->windowId])) { $this->inventory->sendContents($this); $pk = new ContainerClosePacket(); $pk->windowid = $packet->windowId; $this->dataPacket($pk); break; } $recipe = $this->server->getCraftingManager()->getRecipe($packet->id); if ($recipe === null or ($recipe instanceof BigShapelessRecipe or $recipe instanceof BigShapedRecipe) and $this->craftingType === 0) { $this->inventory->sendContents($this); break; } foreach ($packet->input as $i => $item) { if ($item->getDamage() === -1 or $item->getDamage() === 0xffff) { $item->setDamage(null); } if ($i < 9 and $item->getId() > 0) { $item->setCount(1); } } $canCraft = true; if ($recipe instanceof ShapedRecipe) { for ($x = 0; $x < 3 and $canCraft; ++$x) { for ($y = 0; $y < 3; ++$y) { $item = $packet->input[$y * 3 + $x]; $ingredient = $recipe->getIngredient($x, $y); if ($item->getCount() > 0 and $item->getId() > 0) { if ($ingredient === null or !$ingredient->deepEquals($item, $ingredient->getDamage() !== null, $ingredient->getCompoundTag() !== null)) { $canCraft = false; break; } } elseif ($ingredient !== null and $ingredient->getId() !== 0) { $canCraft = false; break; } } } } elseif ($recipe instanceof ShapelessRecipe) { $needed = $recipe->getIngredientList(); for ($x = 0; $x < 3 and $canCraft; ++$x) { for ($y = 0; $y < 3; ++$y) { $item = clone $packet->input[$y * 3 + $x]; foreach ($needed as $k => $n) { if ($n === $item and $n->getDamage() !== null and $n->getCompoundTag() !== null) { $remove = min($n->getCount(), $item->getCount()); $n->setCount($n->getCount() - $remove); $item->setCount($item->getCount() - $remove); if ($n->getCount() === 0) { unset($needed[$k]); } } } if ($item->getCount() > 0) { $canCraft = false; break; } } } if (count($needed) > 0) { $canCraft = false; } } else { $canCraft = false; } /** @var Item[] $ingredients */ $ingredients = $packet->input; $result = $packet->output[0]; if (!$canCraft or !$recipe->getResult() === $result) { $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": expected " . $recipe->getResult() . ", got " . $result . ", using: " . implode(", ", $ingredients)); $this->inventory->sendContents($this); break; } $used = array_fill(0, $this->inventory->getSize(), 0); foreach ($ingredients as $ingredient) { $slot = -1; foreach ($this->inventory->getContents() as $index => $i) { if ($ingredient->getId() !== 0 and $ingredient === $i and $i->getDamage() !== null and $i->getCount() - $used[$index] >= 1) { $slot = $index; $used[$index]++; break; } } if ($ingredient->getId() !== 0 and $slot === -1) { $canCraft = false; break; } } if (!$canCraft) { $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": client does not have enough items, using: " . implode(", ", $ingredients)); $this->inventory->sendContents($this); break; } $this->server->getPluginManager()->callEvent($ev = new CraftItemEvent($ingredients, $recipe)); if ($ev->isCancelled()) { $this->inventory->sendContents($this); break; } foreach ($used as $slot => $count) { if ($count === 0) { continue; } $item = $this->inventory->getItem($slot); if ($item->getCount() > $count) { $newItem = clone $item; $newItem->setCount($item->getCount() - $count); } else { $newItem = Item::get(Item::AIR, 0, 0); } $this->inventory->setItem($slot, $newItem); } $extraItem = $this->inventory->addItem($recipe->getResult()); if (count($extraItem) > 0) { foreach ($extraItem as $item) { $this->level->dropItem($this, $item); } } switch ($recipe->getResult()->getId()) { case Item::WORKBENCH: $this->awardAchievement("buildWorkBench"); break; case Item::WOODEN_PICKAXE: $this->awardAchievement("buildPickaxe"); break; case Item::FURNACE: $this->awardAchievement("buildFurnace"); break; case Item::WOODEN_HOE: $this->awardAchievement("buildHoe"); break; case Item::BREAD: $this->awardAchievement("makeBread"); break; case Item::CAKE: //TODO: detect complex recipes like cake that leave remains $this->awardAchievement("bakeCake"); $this->inventory->addItem(Item::get(Item::BUCKET, 0, 3)); break; case Item::STONE_PICKAXE: case Item::GOLD_PICKAXE: case Item::IRON_PICKAXE: case Item::DIAMOND_PICKAXE: $this->awardAchievement("buildBetterPickaxe"); break; case Item::WOODEN_SWORD: $this->awardAchievement("buildSword"); break; case Item::DIAMOND: $this->awardAchievement("diamond"); break; } break; case ProtocolInfo::CONTAINER_SET_SLOT_PACKET: if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) { break; } if ($packet->slot < 0) { break; } if ($packet->windowid === 0) { //Our inventory if ($packet->slot >= $this->inventory->getSize()) { break; } if ($this->isCreative()) { if (Item::getCreativeItemIndex($packet->item) !== -1) { $this->inventory->setItem($packet->slot, $packet->item); $this->inventory->setHotbarSlotIndex($packet->slot, $packet->slot); //links $hotbar[$packet->slot] to $slots[$packet->slot] } } $transaction = new BaseTransaction($this->inventory, $packet->slot, $this->inventory->getItem($packet->slot), $packet->item); } elseif ($packet->windowid === ContainerSetContentPacket::SPECIAL_ARMOR) { //Our armor if ($packet->slot >= 4) { break; } $transaction = new BaseTransaction($this->inventory, $packet->slot + $this->inventory->getSize(), $this->inventory->getArmorItem($packet->slot), $packet->item); } elseif (isset($this->windowIndex[$packet->windowid])) { $this->craftingType = 0; $inv = $this->windowIndex[$packet->windowid]; $transaction = new BaseTransaction($inv, $packet->slot, $inv->getItem($packet->slot), $packet->item); } else { break; } if ($transaction->getSourceItem() === $transaction->getTargetItem() and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()) { //No changes! //No changes, just a local inventory update sent by the server break; } if ($this->currentTransaction === null or $this->currentTransaction->getCreationTime() < microtime(true) - 8) { if ($this->currentTransaction !== null) { foreach ($this->currentTransaction->getInventories() as $inventory) { if ($inventory instanceof PlayerInventory) { $inventory->sendArmorContents($this); } $inventory->sendContents($this); } } $this->currentTransaction = new SimpleTransactionGroup($this); } $this->currentTransaction->addTransaction($transaction); if ($this->currentTransaction->canExecute()) { $achievements = []; foreach ($this->currentTransaction->getTransactions() as $ts) { $inv = $ts->getInventory(); if ($inv instanceof FurnaceInventory) { if ($ts->getSlot() === 2) { switch ($inv->getResult()->getId()) { case Item::IRON_INGOT: $achievements[] = "acquireIron"; break; } } } } if ($this->currentTransaction->execute()) { foreach ($achievements as $a) { $this->awardAchievement($a); } } $this->currentTransaction = null; } break; case ProtocolInfo::TILE_ENTITY_DATA_PACKET: if ($this->spawned === false or $this->blocked === true or $this->dead === true) { break; } $this->craftingType = 0; $pos = new Vector3($packet->x, $packet->y, $packet->z); if ($pos->distanceSquared($this) > 10000) { break; } $t = $this->level->getTile($pos); if ($t instanceof Sign) { $nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt->read($packet->namedtag); $nbt = $nbt->getData(); if ($nbt["id"] !== Tile::SIGN) { $t->spawnTo($this); } else { $ev = new SignChangeEvent($t->getBlock(), $this, [TextFormat::clean($nbt["Text1"], $this->removeFormat), TextFormat::clean($nbt["Text2"], $this->removeFormat), TextFormat::clean($nbt["Text3"], $this->removeFormat), TextFormat::clean($nbt["Text4"], $this->removeFormat)]); if (!isset($t->namedtag->Creator) or $t->namedtag["Creator"] !== $this->username) { $ev->setCancelled(true); } $this->server->getPluginManager()->callEvent($ev); if (!$ev->isCancelled()) { $t->setText($ev->getLine(0), $ev->getLine(1), $ev->getLine(2), $ev->getLine(3)); } else { $t->spawnTo($this); } } } break; default: break; } }
public function onRespawn(PlayerRespawnEvent $event) { $player = $event->getPlayer(); if ($this->isOtu($player->getName()) or $this->isRuna($player->getName())) { if ($this->isAutoRespawnInJail()) { $respawn = $event->getRespawnPosition(); if (!(($pos = $this->getRespawnPosition($player->getName())) === false)) { //todo 関数名が紛らわしいので後で変更 $respawn = $pos; } $event->setRespawnPosition($respawn); } } }
/** * 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; } }
public function onRespawn(PlayerRespawnEvent $event) { $player = $event->getPlayer(); foreach ($this->hungerItem as $hungerItem) { $player->getInventory()->remove($hungerItem); } $air = Item::get(Item::AIR); $player->getInventory()->setArmorContents([$air, $air, $air, $air]); $player->getInventory()->sendArmorContents($player); if (isset($this->touchedQueue[$event->getPlayer()->getName()])) { unset($this->touchedQueue[$event->getPlayer()->getName()]); } }
/** * Handles a Minecraft packet * TODO: Separate all of this in handlers * * WARNING: Do not use this, it's only for internal use. * Changes to this function won't be recorded on the version. * * @param DataPacket $packet */ public function handleDataPacket(DataPacket $packet) { if ($this->connected === false) { return; } if ($packet::NETWORK_ID === ProtocolInfo::BATCH_PACKET) { /** @var BatchPacket $packet */ $this->server->getNetwork()->processBatch($packet, $this); return; } $timings = Timings::getReceiveDataPacketTimings($packet); $timings->startTiming(); $this->server->getPluginManager()->callEvent($ev = new DataPacketReceiveEvent($this, $packet)); if ($ev->isCancelled()) { $timings->stopTiming(); return; } switch ($packet::NETWORK_ID) { case ProtocolInfo::LOGIN_PACKET: if ($this->loggedIn) { break; } $this->username = TextFormat::clean($packet->username); $this->displayName = $this->username; $this->setNameTag($this->username); $this->iusername = strtolower($this->username); if (count($this->server->getOnlinePlayers()) >= $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)) { break; } if ($packet->protocol1 !== ProtocolInfo::CURRENT_PROTOCOL) { if ($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL) { $message = "disconnectionScreen.outdatedClient"; $pk = new PlayStatusPacket(); $pk->status = PlayStatusPacket::LOGIN_FAILED_CLIENT; $this->directDataPacket($pk); } else { $message = "disconnectionScreen.outdatedServer"; $pk = new PlayStatusPacket(); $pk->status = PlayStatusPacket::LOGIN_FAILED_SERVER; $this->directDataPacket($pk); } $this->close("", $message, false); break; } $this->randomClientId = $packet->clientId; $this->loginData = ["clientId" => $packet->clientId, "loginData" => null]; $this->uuid = $packet->clientUUID; $this->rawUUID = $this->uuid->toBinary(); $this->clientSecret = $packet->clientSecret; $valid = true; $len = strlen($packet->username); if ($len > 16 or $len < 3) { $valid = false; } for ($i = 0; $i < $len and $valid; ++$i) { $c = ord($packet->username[$i]); if ($c >= ord("a") and $c <= ord("z") or $c >= ord("A") and $c <= ord("Z") or $c >= ord("0") and $c <= ord("9") or $c === ord("_")) { continue; } $valid = false; break; } if (!$valid or $this->iusername === "rcon" or $this->iusername === "console") { $this->close("", "disconnectionScreen.invalidName"); break; } if (strlen($packet->skin) !== 64 * 32 * 4 and strlen($packet->skin) !== 64 * 64 * 4) { $this->close("", "disconnectionScreen.invalidSkin"); break; } $this->setSkin($packet->skin, $packet->skinname, $packet->oldclient, $packet->slim, $packet->transparent); $this->server->getPluginManager()->callEvent($ev = new PlayerPreLoginEvent($this, "Plugin reason")); if ($ev->isCancelled()) { $this->close("", $ev->getKickMessage()); break; } $this->onPlayerPreLogin(); break; case ProtocolInfo::MOVE_PLAYER_PACKET: $newPos = new Vector3($packet->x, $packet->y - $this->getEyeHeight(), $packet->z); $revert = false; if (!$this->isAlive() or $this->spawned !== true) { $revert = true; $this->forceMovement = new Vector3($this->x, $this->y, $this->z); } if ($this->teleportPosition !== null or $this->forceMovement instanceof Vector3 and (($dist = $newPos->distanceSquared($this->forceMovement)) > 0.1 or $revert)) { $this->sendPosition($this->forceMovement, $packet->yaw, $packet->pitch); } else { $packet->yaw %= 360; $packet->pitch %= 360; if ($packet->yaw < 0) { $packet->yaw += 360; } $this->setRotation($packet->yaw, $packet->pitch); $this->newPosition = $newPos; $this->forceMovement = null; } break; case ProtocolInfo::MOB_EQUIPMENT_PACKET: if ($this->spawned === false or !$this->isAlive()) { break; } if ($packet->slot === 0x28 or $packet->slot === 0 or $packet->slot === 255) { //0 for 0.8.0 compatibility $packet->slot = -1; //Air } else { $packet->slot -= 9; //Get real block slot } /** @var Item $item */ $item = null; if ($this->isCreative()) { //Creative mode match $item = $packet->item; $slot = Item::getCreativeItemIndex($item); } else { $item = $this->inventory->getItem($packet->slot); $slot = $packet->slot; } if ($packet->slot === -1) { //Air if ($this->isCreative()) { $found = false; for ($i = 0; $i < $this->inventory->getHotbarSize(); ++$i) { if ($this->inventory->getHotbarSlotIndex($i) === -1) { $this->inventory->setHeldItemIndex($i); $found = true; break; } } if (!$found) { //couldn't find a empty slot (error) $this->inventory->sendContents($this); break; } } else { if ($packet->selectedSlot >= 0 and $packet->selectedSlot < 9) { $this->inventory->setHeldItemIndex($packet->selectedSlot); $this->inventory->setHeldItemSlot($packet->slot); } else { $this->inventory->sendContents($this); break; } } } elseif ($item === null or $slot === -1 or !$item->deepEquals($packet->item)) { // packet error or not implemented $this->inventory->sendContents($this); break; } elseif ($this->isCreative()) { $this->inventory->setHeldItemIndex($packet->selectedSlot); $this->inventory->setItem($packet->selectedSlot, $item); $this->inventory->setHeldItemSlot($packet->selectedSlot); } else { if ($packet->selectedSlot >= 0 and $packet->selectedSlot < $this->inventory->getHotbarSize()) { $this->inventory->setHeldItemIndex($packet->selectedSlot); $this->inventory->setHeldItemSlot($slot); } else { $this->inventory->sendContents($this); break; } } $this->inventory->sendHeldItem($this->hasSpawned); $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); break; case ProtocolInfo::USE_ITEM_PACKET: if ($this->spawned === false or !$this->isAlive() or $this->blocked) { break; } $blockVector = new Vector3($packet->x, $packet->y, $packet->z); $this->craftingType = 0; if ($packet->face >= 0 and $packet->face <= 5) { //Use Block, place $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); if (!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13) or $this->isSpectator()) { } elseif ($this->isCreative()) { $item = $this->inventory->getItemInHand(); if ($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true) { break; } } elseif (!$this->inventory->getItemInHand()->deepEquals($packet->item)) { $this->inventory->sendHeldItem($this); } else { $item = $this->inventory->getItemInHand(); $oldItem = clone $item; //TODO: Implement adventure mode checks if ($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this)) { if (!$item->deepEquals($oldItem) or $item->getCount() !== $oldItem->getCount()) { $this->inventory->setItemInHand($item); $this->inventory->sendHeldItem($this->hasSpawned); } break; } } $this->inventory->sendHeldItem($this); if ($blockVector->distanceSquared($this) > 10000) { break; } $target = $this->level->getBlock($blockVector); $block = $target->getSide($packet->face); $this->level->sendBlocks([$this], [$target, $block], UpdateBlockPacket::FLAG_ALL_PRIORITY); break; } elseif ($packet->face === 0xff) { $aimPos = (new Vector3($packet->x / 32768, $packet->y / 32768, $packet->z / 32768))->normalize(); if ($this->isCreative()) { $item = $this->inventory->getItemInHand(); } elseif (!$this->inventory->getItemInHand()->deepEquals($packet->item)) { $this->inventory->sendHeldItem($this); break; } else { $item = $this->inventory->getItemInHand(); } $ev = new PlayerInteractEvent($this, $item, $aimPos, $packet->face, PlayerInteractEvent::RIGHT_CLICK_AIR); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->inventory->sendHeldItem($this); break; } if ($item->getId() === Item::SNOWBALL) { $nbt = new Compound("", ["Pos" => new Enum("Pos", [new Double("", $this->x), new Double("", $this->y + $this->getEyeHeight()), new Double("", $this->z)]), "Motion" => new Enum("Motion", [new Double("", $aimPos->x), new Double("", $aimPos->y), new Double("", $aimPos->z)]), "Rotation" => new Enum("Rotation", [new Float("", $this->yaw), new Float("", $this->pitch)])]); $f = 1.5; $snowball = Entity::createEntity("Snowball", $this->chunk, $nbt, $this); $snowball->setMotion($snowball->getMotion()->multiply($f)); if ($this->isSurvival()) { $item->setCount($item->getCount() - 1); $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR)); } if ($snowball instanceof Projectile) { $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($snowball)); if ($projectileEv->isCancelled()) { $snowball->kill(); } else { $snowball->spawnToAll(); $this->level->addSound(new LaunchSound($this), $this->getViewers()); } } else { $snowball->spawnToAll(); } } $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, true); $this->startAction = $this->server->getTick(); } break; case ProtocolInfo::PLAYER_ACTION_PACKET: if ($this->spawned === false or $this->blocked === true or !$this->isAlive() and $packet->action !== PlayerActionPacket::ACTION_RESPAWN and $packet->action !== PlayerActionPacket::ACTION_DIMENSION_CHANGE) { break; } $packet->eid = $this->id; $pos = new Vector3($packet->x, $packet->y, $packet->z); switch ($packet->action) { case PlayerActionPacket::ACTION_START_BREAK: if ($this->lastBreak !== PHP_INT_MAX or $pos->distanceSquared($this) > 10000) { break; } $target = $this->level->getBlock($pos); $ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, $packet->face, $target->getId() === 0 ? PlayerInteractEvent::LEFT_CLICK_AIR : PlayerInteractEvent::LEFT_CLICK_BLOCK); $this->getServer()->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->inventory->sendHeldItem($this); break; } $this->lastBreak = microtime(true); break; case PlayerActionPacket::ACTION_ABORT_BREAK: $this->lastBreak = PHP_INT_MAX; break; case PlayerActionPacket::ACTION_RELEASE_ITEM: if ($this->startAction > -1 and $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION)) { if ($this->inventory->getItemInHand()->getId() === Item::BOW) { $bow = $this->inventory->getItemInHand(); if ($this->isSurvival() and !$this->inventory->contains(Item::get(Item::ARROW, 0, 1))) { $this->inventory->sendContents($this); break; } $nbt = new Compound("", ["Pos" => new Enum("Pos", [new Double("", $this->x), new Double("", $this->y + $this->getEyeHeight()), new Double("", $this->z)]), "Motion" => new Enum("Motion", [new Double("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new Double("", -sin($this->pitch / 180 * M_PI)), new Double("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new Enum("Rotation", [new Float("", $this->yaw), new Float("", $this->pitch)]), "Fire" => new Short("Fire", $this->isOnFire() ? 45 * 60 : 0)]); $diff = $this->server->getTick() - $this->startAction; $p = $diff / 20; $f = min(($p ** 2 + $p * 2) / 3, 1) * 2; $ev = new EntityShootBowEvent($this, $bow, Entity::createEntity("Arrow", $this->chunk, $nbt, $this, $f == 2 ? true : false), $f); if ($f < 0.1 or $diff < 5) { $ev->setCancelled(); } $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $ev->getProjectile()->kill(); $this->inventory->sendContents($this); } else { $ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce())); if ($this->isSurvival()) { $this->inventory->removeItem(Item::get(Item::ARROW, 0, 1)); $bow->setDamage($bow->getDamage() + 1); if ($bow->getDamage() >= 385) { $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 0)); } else { $this->inventory->setItemInHand($bow); } } if ($ev->getProjectile() instanceof Projectile) { $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($ev->getProjectile())); if ($projectileEv->isCancelled()) { $ev->getProjectile()->kill(); } else { $ev->getProjectile()->spawnToAll(); $this->level->addSound(new LaunchSound($this), $this->getViewers()); } } else { $ev->getProjectile()->spawnToAll(); } } } } elseif ($this->inventory->getItemInHand()->getId() === Item::BUCKET and $this->inventory->getItemInHand()->getDamage() === 1) { //Milk! $this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $this->inventory->getItemInHand())); if ($ev->isCancelled()) { $this->inventory->sendContents($this); break; } $pk = new EntityEventPacket(); $pk->eid = $this->getId(); $pk->event = EntityEventPacket::USE_ITEM; $this->dataPacket($pk); Server::broadcastPacket($this->getViewers(), $pk); if ($this->isSurvival()) { $slot = $this->inventory->getItemInHand(); --$slot->count; $this->inventory->setItemInHand($slot); $this->inventory->addItem(Item::get(Item::BUCKET, 0, 1)); } $this->removeAllEffects(); } else { $this->inventory->sendContents($this); } break; case PlayerActionPacket::ACTION_STOP_SLEEPING: $this->stopSleep(); break; case PlayerActionPacket::ACTION_RESPAWN: if ($this->spawned === false or $this->isAlive() or !$this->isOnline()) { break; } if ($this->server->isHardcore()) { $this->setBanned(true); break; } $this->craftingType = 0; $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn())); $this->teleport($ev->getRespawnPosition()); $this->setSprinting(false); $this->setSneaking(false); $this->extinguish(); $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 300); $this->deadTicks = 0; $this->noDamageTicks = 60; $this->setHealth($this->getMaxHealth()); $this->removeAllEffects(); $this->sendData($this); $this->sendSettings(); $this->inventory->sendContents($this); $this->inventory->sendArmorContents($this); $this->blocked = false; $this->spawnToAll(); $this->scheduleUpdate(); break; case PlayerActionPacket::ACTION_START_SPRINT: $ev = new PlayerToggleSprintEvent($this, true); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->sendData($this); } else { $this->setSprinting(true); } break; case PlayerActionPacket::ACTION_STOP_SPRINT: $ev = new PlayerToggleSprintEvent($this, false); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->sendData($this); } else { $this->setSprinting(false); } break; case PlayerActionPacket::ACTION_START_SNEAK: $ev = new PlayerToggleSneakEvent($this, true); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->sendData($this); } else { $this->setSneaking(true); } break; case PlayerActionPacket::ACTION_STOP_SNEAK: $ev = new PlayerToggleSneakEvent($this, false); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->sendData($this); } else { $this->setSneaking(false); } break; } $this->startAction = -1; $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); break; case ProtocolInfo::REMOVE_BLOCK_PACKET: if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) { break; } $this->craftingType = 0; $vector = new Vector3($packet->x, $packet->y, $packet->z); if ($this->isCreative()) { $item = $this->inventory->getItemInHand(); } else { $item = $this->inventory->getItemInHand(); } $oldItem = clone $item; if ($this->canInteract($vector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 6) and $this->level->useBreakOn($vector, $item, $this)) { if ($this->isSurvival()) { if (!$item->deepEquals($oldItem) or $item->getCount() !== $oldItem->getCount()) { $this->inventory->setItemInHand($item); $this->inventory->sendHeldItem($this->hasSpawned); } } break; } $this->inventory->sendContents($this); $target = $this->level->getBlock($vector); $tile = $this->level->getTile($vector); $this->level->sendBlocks([$this], [$target], UpdateBlockPacket::FLAG_ALL_PRIORITY); $this->inventory->sendHeldItem($this); if ($tile instanceof Spawnable) { $tile->spawnTo($this); } break; case ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET: break; case ProtocolInfo::INTERACT_PACKET: if ($this->spawned === false or !$this->isAlive() or $this->blocked) { break; } $this->craftingType = 0; $target = $this->level->getEntity($packet->target); $cancelled = false; if ($target instanceof Player and $this->server->getConfigBoolean("pvp", true) === false) { $cancelled = true; } if ($target instanceof Entity and $this->getGamemode() !== Player::VIEW and $this->isAlive() and $target->isAlive()) { if ($target instanceof DroppedItem or $target instanceof Arrow) { $this->kick("Attempting to attack an invalid entity"); $this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidEntity", [$this->getName()])); break; } $item = $this->inventory->getItemInHand(); $damageTable = [Item::WOODEN_SWORD => 4, Item::GOLD_SWORD => 4, Item::STONE_SWORD => 5, Item::IRON_SWORD => 6, Item::DIAMOND_SWORD => 7, Item::WOODEN_AXE => 3, Item::GOLD_AXE => 3, Item::STONE_AXE => 3, Item::IRON_AXE => 5, Item::DIAMOND_AXE => 6, Item::WOODEN_PICKAXE => 2, Item::GOLD_PICKAXE => 2, Item::STONE_PICKAXE => 3, Item::IRON_PICKAXE => 4, Item::DIAMOND_PICKAXE => 5, Item::WOODEN_SHOVEL => 1, Item::GOLD_SHOVEL => 1, Item::STONE_SHOVEL => 2, Item::IRON_SHOVEL => 3, Item::DIAMOND_SHOVEL => 4]; $damage = [EntityDamageEvent::MODIFIER_BASE => isset($damageTable[$item->getId()]) ? $damageTable[$item->getId()] : 1]; if (!$this->canInteract($target, 8)) { $cancelled = true; } elseif ($target instanceof Player) { if (($target->getGamemode() & 0x1) > 0) { break; } elseif ($this->server->getConfigBoolean("pvp") !== true or $this->server->getDifficulty() === 0) { $cancelled = true; } $armorValues = [Item::LEATHER_CAP => 1, Item::LEATHER_TUNIC => 3, Item::LEATHER_PANTS => 2, Item::LEATHER_BOOTS => 1, Item::CHAIN_HELMET => 1, Item::CHAIN_CHESTPLATE => 5, Item::CHAIN_LEGGINGS => 4, Item::CHAIN_BOOTS => 1, Item::GOLD_HELMET => 1, Item::GOLD_CHESTPLATE => 5, Item::GOLD_LEGGINGS => 3, Item::GOLD_BOOTS => 1, Item::IRON_HELMET => 2, Item::IRON_CHESTPLATE => 6, Item::IRON_LEGGINGS => 5, Item::IRON_BOOTS => 2, Item::DIAMOND_HELMET => 3, Item::DIAMOND_CHESTPLATE => 8, Item::DIAMOND_LEGGINGS => 6, Item::DIAMOND_BOOTS => 3]; $points = 0; foreach ($target->getInventory()->getArmorContents() as $index => $i) { if (isset($armorValues[$i->getId()])) { $points += $armorValues[$i->getId()]; } } $damage[EntityDamageEvent::MODIFIER_ARMOR] = -floor($damage[EntityDamageEvent::MODIFIER_BASE] * $points * 0.04); } $ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage); if ($cancelled) { $ev->setCancelled(); } $target->attack($ev->getFinalDamage(), $ev); if ($ev->isCancelled()) { if ($item->isTool() and $this->isSurvival()) { $this->inventory->sendContents($this); } break; } if ($item->isTool() and $this->isSurvival()) { if ($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()) { $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1)); } else { $this->inventory->setItemInHand($item); } } } break; case ProtocolInfo::ANIMATE_PACKET: if ($this->spawned === false or !$this->isAlive()) { break; } $this->server->getPluginManager()->callEvent($ev = new PlayerAnimationEvent($this, $packet->action)); if ($ev->isCancelled()) { break; } $pk = new AnimatePacket(); $pk->eid = $this->getId(); $pk->action = $ev->getAnimationType(); Server::broadcastPacket($this->getViewers(), $pk); break; case ProtocolInfo::SET_HEALTH_PACKET: //Not used break; case ProtocolInfo::ENTITY_EVENT_PACKET: if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) { break; } $this->craftingType = 0; $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); //TODO: check if this should be true switch ($packet->event) { case 9: //Eating $items = [Item::APPLE => 4, Item::MUSHROOM_STEW => 10, Item::BEETROOT_SOUP => 10, Item::BREAD => 5, Item::RAW_PORKCHOP => 3, Item::COOKED_PORKCHOP => 8, Item::RAW_BEEF => 3, Item::STEAK => 8, Item::COOKED_CHICKEN => 6, Item::RAW_CHICKEN => 2, Item::MELON_SLICE => 2, Item::GOLDEN_APPLE => 10, Item::PUMPKIN_PIE => 8, Item::CARROT => 4, Item::POTATO => 1, Item::BAKED_POTATO => 6, Item::COOKIE => 2, Item::COOKED_FISH => 5, Item::COOKED_SALMON => 6, Item::RAW_FISH => 2, Item::RAW_SALMON => 2, Item::CLOWN_FISH => 1, Item::PUFFER_FISH => 1]; $slot = $this->inventory->getItemInHand(); if ($this->getHealth() < $this->getMaxHealth() and isset($items[$slot->getId()])) { $this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $slot)); if ($ev->isCancelled()) { $this->inventory->sendContents($this); break; } $pk = new EntityEventPacket(); $pk->eid = $this->getId(); $pk->event = EntityEventPacket::USE_ITEM; $this->dataPacket($pk); Server::broadcastPacket($this->getViewers(), $pk); $amount = $items[$slot->getId()]; $ev = new EntityRegainHealthEvent($this, $amount, EntityRegainHealthEvent::CAUSE_EATING); $this->heal($ev->getAmount(), $ev); --$slot->count; $this->inventory->setItemInHand($slot); if ($slot->getId() === Item::MUSHROOM_STEW or $slot->getId() === Item::BEETROOT_SOUP) { $this->inventory->addItem(Item::get(Item::BOWL, 0, 1)); } elseif ($slot->getId() === Item::PUFFER_FISH) { //Pufferfish //$this->addEffect(Effect::getEffect(Effect::HUNGER)->setAmplifier(2)->setDuration(15 * 20)); $this->addEffect(Effect::getEffect(Effect::NAUSEA)->setAmplifier(1)->setDuration(15 * 20)); $this->addEffect(Effect::getEffect(Effect::POISON)->setAmplifier(3)->setDuration(60 * 20)); } } break; } break; case ProtocolInfo::DROP_ITEM_PACKET: if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) { break; } $item = $this->inventory->getItemInHand(); $ev = new PlayerDropItemEvent($this, $item); $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { $this->inventory->sendContents($this); break; } $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1)); $motion = $this->getDirectionVector()->multiply(0.4); $this->level->dropItem($this->add(0, 1.3, 0), $item, $motion, 40); $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); break; case ProtocolInfo::TEXT_PACKET: if ($this->spawned === false or !$this->isAlive()) { break; } $this->craftingType = 0; if ($packet->type === TextPacket::TYPE_CHAT) { $packet->message = TextFormat::clean($packet->message, $this->removeFormat); foreach (explode("\n", $packet->message) as $message) { if (trim($message) != "" and strlen($message) <= 255 and $this->messageCounter-- > 0) { $ev = new PlayerCommandPreprocessEvent($this, $message); if (mb_strlen($ev->getMessage(), "UTF-8") > 320) { $ev->setCancelled(); } $this->server->getPluginManager()->callEvent($ev); if ($ev->isCancelled()) { break; } if (substr($ev->getMessage(), 0, 1) === "/") { //Command Timings::$playerCommandTimer->startTiming(); $this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 1)); Timings::$playerCommandTimer->stopTiming(); } else { $this->server->getPluginManager()->callEvent($ev = new PlayerChatEvent($this, $ev->getMessage())); if (!$ev->isCancelled()) { $this->server->broadcastMessage($this->getServer()->getLanguage()->translateString($ev->getFormat(), [$ev->getPlayer()->getDisplayName(), $ev->getMessage()]), $ev->getRecipients()); } } } } } break; case ProtocolInfo::CONTAINER_CLOSE_PACKET: if ($this->spawned === false or $packet->windowid === 0) { break; } $this->craftingType = 0; $this->currentTransaction = null; if (isset($this->windowIndex[$packet->windowid])) { $this->server->getPluginManager()->callEvent(new InventoryCloseEvent($this->windowIndex[$packet->windowid], $this)); $this->removeWindow($this->windowIndex[$packet->windowid]); } else { unset($this->windowIndex[$packet->windowid]); } break; case ProtocolInfo::CRAFTING_EVENT_PACKET: if ($this->spawned === false or !$this->isAlive()) { break; } elseif (!isset($this->windowIndex[$packet->windowId])) { $this->inventory->sendContents($this); $pk = new ContainerClosePacket(); $pk->windowid = $packet->windowId; $this->dataPacket($pk); break; } $recipe = $this->server->getCraftingManager()->getRecipe($packet->id); if ($recipe === null or ($recipe instanceof BigShapelessRecipe or $recipe instanceof BigShapedRecipe) and $this->craftingType === 0) { $this->inventory->sendContents($this); break; } foreach ($packet->input as $i => $item) { if ($item->getDamage() === -1 or $item->getDamage() === 0xffff) { $item->setDamage(null); } if ($i < 9 and $item->getId() > 0) { $item->setCount(1); } } $canCraft = true; if ($recipe instanceof ShapedRecipe) { for ($x = 0; $x < 3 and $canCraft; ++$x) { for ($y = 0; $y < 3; ++$y) { $item = $packet->input[$y * 3 + $x]; $ingredient = $recipe->getIngredient($x, $y); if ($item->getCount() > 0) { if ($ingredient === null or !$ingredient->deepEquals($item, $ingredient->getDamage() !== null, $ingredient->getCompoundTag() !== null)) { $canCraft = false; break; } } } } } elseif ($recipe instanceof ShapelessRecipe) { $needed = $recipe->getIngredientList(); for ($x = 0; $x < 3 and $canCraft; ++$x) { for ($y = 0; $y < 3; ++$y) { $item = clone $packet->input[$y * 3 + $x]; foreach ($needed as $k => $n) { if ($n->deepEquals($item, $n->getDamage() !== null, $n->getCompoundTag() !== null)) { $remove = min($n->getCount(), $item->getCount()); $n->setCount($n->getCount() - $remove); $item->setCount($item->getCount() - $remove); if ($n->getCount() === 0) { unset($needed[$k]); } } } if ($item->getCount() > 0) { $canCraft = false; break; } } } if (count($needed) > 0) { $canCraft = false; } } else { $canCraft = false; } /** @var Item[] $ingredients */ $ingredients = $packet->input; $result = $packet->output[0]; if (!$canCraft or !$recipe->getResult()->deepEquals($result)) { $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": expected " . $recipe->getResult() . ", got " . $result . ", using: " . implode(", ", $ingredients)); $this->inventory->sendContents($this); break; } $used = array_fill(0, $this->inventory->getSize(), 0); foreach ($ingredients as $ingredient) { $slot = -1; foreach ($this->inventory->getContents() as $index => $i) { if ($ingredient->getId() !== 0 and $ingredient->deepEquals($i, $i->getDamage() !== null) and $i->getCount() - $used[$index] >= 1) { $slot = $index; $used[$index]++; break; } } if ($ingredient->getId() !== 0 and $slot === -1) { $canCraft = false; break; } } if (!$canCraft) { $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": client does not have enough items, using: " . implode(", ", $ingredients)); $this->inventory->sendContents($this); break; } $this->server->getPluginManager()->callEvent($ev = new CraftItemEvent($this, $ingredients, $recipe)); if ($ev->isCancelled()) { $this->inventory->sendContents($this); break; } foreach ($used as $slot => $count) { if ($count === 0) { continue; } $item = $this->inventory->getItem($slot); if ($item->getCount() > $count) { $newItem = clone $item; $newItem->setCount($item->getCount() - $count); } else { $newItem = Item::get(Item::AIR, 0, 0); } $this->inventory->setItem($slot, $newItem); } $extraItem = $this->inventory->addItem($recipe->getResult()); if (count($extraItem) > 0) { foreach ($extraItem as $item) { $this->level->dropItem($this, $item); } } switch ($recipe->getResult()->getId()) { case Item::WORKBENCH: $this->awardAchievement("buildWorkBench"); break; case Item::WOODEN_PICKAXE: $this->awardAchievement("buildPickaxe"); break; case Item::FURNACE: $this->awardAchievement("buildFurnace"); break; case Item::WOODEN_HOE: $this->awardAchievement("buildHoe"); break; case Item::BREAD: $this->awardAchievement("makeBread"); break; case Item::CAKE: //TODO: detect complex recipes like cake that leave remains $this->awardAchievement("bakeCake"); $this->inventory->addItem(Item::get(Item::BUCKET, 0, 3)); break; case Item::STONE_PICKAXE: case Item::GOLD_PICKAXE: case Item::IRON_PICKAXE: case Item::DIAMOND_PICKAXE: $this->awardAchievement("buildBetterPickaxe"); break; case Item::WOODEN_SWORD: $this->awardAchievement("buildSword"); break; case Item::DIAMOND: $this->awardAchievement("diamond"); break; } break; case ProtocolInfo::CONTAINER_SET_SLOT_PACKET: if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) { break; } if ($packet->slot < 0) { break; } if ($packet->windowid === 0) { //Our inventory if ($packet->slot >= $this->inventory->getSize()) { break; } if ($this->isCreative()) { if (Item::getCreativeItemIndex($packet->item) !== -1) { $this->inventory->setItem($packet->slot, $packet->item); $this->inventory->setHotbarSlotIndex($packet->slot, $packet->slot); //links $hotbar[$packet->slot] to $slots[$packet->slot] } } $transaction = new BaseTransaction($this->inventory, $packet->slot, $this->inventory->getItem($packet->slot), $packet->item); } elseif ($packet->windowid === ContainerSetContentPacket::SPECIAL_ARMOR) { //Our armor if ($packet->slot >= 4) { break; } $transaction = new BaseTransaction($this->inventory, $packet->slot + $this->inventory->getSize(), $this->inventory->getArmorItem($packet->slot), $packet->item); } elseif (isset($this->windowIndex[$packet->windowid])) { $this->craftingType = 0; $inv = $this->windowIndex[$packet->windowid]; $transaction = new BaseTransaction($inv, $packet->slot, $inv->getItem($packet->slot), $packet->item); } else { break; } if ($transaction->getSourceItem()->deepEquals($transaction->getTargetItem()) and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()) { //No changes! //No changes, just a local inventory update sent by the server break; } if ($this->currentTransaction === null or $this->currentTransaction->getCreationTime() < microtime(true) - 8) { if ($this->currentTransaction !== null) { foreach ($this->currentTransaction->getInventories() as $inventory) { if ($inventory instanceof PlayerInventory) { $inventory->sendArmorContents($this); } $inventory->sendContents($this); } } $this->currentTransaction = new SimpleTransactionGroup($this); } $this->currentTransaction->addTransaction($transaction); if ($this->currentTransaction->canExecute()) { $achievements = []; foreach ($this->currentTransaction->getTransactions() as $ts) { $inv = $ts->getInventory(); if ($inv instanceof FurnaceInventory) { if ($ts->getSlot() === 2) { switch ($inv->getResult()->getId()) { case Item::IRON_INGOT: $achievements[] = "acquireIron"; break; } } } } if ($this->currentTransaction->execute()) { foreach ($achievements as $a) { $this->awardAchievement($a); } } $this->currentTransaction = null; } break; case ProtocolInfo::BLOCK_ENTITY_DATA_PACKET: if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) { break; } $this->craftingType = 0; $pos = new Vector3($packet->x, $packet->y, $packet->z); if ($pos->distanceSquared($this) > 10000) { break; } $t = $this->level->getTile($pos); if ($t instanceof Sign) { $nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt->read($packet->namedtag); $nbt = $nbt->getData(); if ($nbt["id"] !== Tile::SIGN) { $t->spawnTo($this); } else { $ev = new SignChangeEvent($t->getBlock(), $this, [TextFormat::clean($nbt["Text1"], $this->removeFormat), TextFormat::clean($nbt["Text2"], $this->removeFormat), TextFormat::clean($nbt["Text3"], $this->removeFormat), TextFormat::clean($nbt["Text4"], $this->removeFormat)]); if (!isset($t->namedtag->Creator) or $t->namedtag["Creator"] !== $this->getRawUniqueId()) { $ev->setCancelled(); } else { foreach ($ev->getLines() as $line) { if (mb_strlen($line, "UTF-8") > 16) { $ev->setCancelled(); } } } $this->server->getPluginManager()->callEvent($ev); if (!$ev->isCancelled()) { $t->setText($ev->getLine(0), $ev->getLine(1), $ev->getLine(2), $ev->getLine(3)); } else { $t->spawnTo($this); } } } break; default: break; } $timings->stopTiming(); }