Пример #1
0
 /**
  * @param \ClassLoader    $autoloader
  * @param \ThreadedLogger $logger
  * @param string          $filePath
  * @param string          $dataPath
  * @param string          $pluginPath
  */
 public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $filePath, $dataPath, $pluginPath)
 {
     self::$instance = $this;
     $this->autoloader = $autoloader;
     $this->logger = $logger;
     $this->filePath = $filePath;
     if (!file_exists($dataPath . "worlds/")) {
         mkdir($dataPath . "worlds/", 0777);
     }
     if (!file_exists($dataPath . "players/")) {
         mkdir($dataPath . "players/", 0777);
     }
     if (!file_exists($dataPath . "CrashDump/")) {
         mkdir($dataPath . "CrashDump/", 0777);
     }
     if (!file_exists($pluginPath)) {
         mkdir($pluginPath, 0777);
     }
     $this->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
     $this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
     $this->console = new CommandReader();
     $version = new VersionString($this->getPocketMineVersion());
     $this->logger->info(TextFormat::GREEN . "  ____            _        _   __  __ _                     " . TextFormat::AQUA . " _____ _ _ _       ");
     $this->logger->info(TextFormat::GREEN . " |  _ \\ ___   ___| | _____| |_|  \\/  (_)_ __   ___          " . TextFormat::AQUA . "| ____| (_) |_ ___ ");
     $this->logger->info(TextFormat::GREEN . " | |_) / _ \\ / __| |/ / _ \\ __| |\\/| | | '_ \\ / _ \\  _____  " . TextFormat::AQUA . "|  _| | | | __/ _ \\ ");
     $this->logger->info(TextFormat::GREEN . " |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/ |_____| " . TextFormat::AQUA . "| |___| | | ||  __/");
     $this->logger->info(TextFormat::GREEN . " |_|   \\___/ \\___|_|\\_\\___|\\__|_|  |_|_|_| |_|\\___|         " . TextFormat::AQUA . "|_____|_|_|\\__\\___|");
     $this->logger->info(TextFormat::GREEN . "                               Version: " . TextFormat::AQUA . $version);
     $this->logger->info("Loading pocketmine.yml...");
     if (!file_exists($this->dataPath . "pocketmine.yml")) {
         $content = file_get_contents($this->filePath . "src/pocketmine/resources/pocketmine.yml");
         if ($version->isDev()) {
             $content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content);
         }
         @file_put_contents($this->dataPath . "pocketmine.yml", $content);
     }
     $this->config = new Config($this->dataPath . "pocketmine.yml", Config::YAML, []);
     $this->logger->info("Loading server properties...");
     $this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, ["motd" => "Minecraft: PE Server", "server-port" => 19132, "white-list" => false, "announce-player-achievements" => true, "spawn-protection" => 16, "max-players" => 20, "allow-flight" => false, "spawn-animals" => true, "spawn-mobs" => true, "gamemode" => 0, "force-gamemode" => false, "hardcore" => false, "pvp" => true, "difficulty" => 1, "generator-settings" => "", "level-name" => "world", "level-seed" => "", "level-type" => "DEFAULT", "enable-query" => true, "enable-rcon" => false, "rcon.password" => substr(base64_encode(@Utils::getRandomBytes(20, false)), 3, 10), "auto-save" => true]);
     $this->forceLanguage = $this->getProperty("settings.force-language", false);
     $this->baseLang = new BaseLang($this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE));
     $this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));
     $this->memoryManager = new MemoryManager($this);
     $this->logger->info($this->getLanguage()->translateString("pocketmine.server.start", [TextFormat::AQUA . $this->getVersion()]));
     if (($poolSize = $this->getProperty("settings.async-workers", "auto")) === "auto") {
         $poolSize = ServerScheduler::$WORKERS;
         $processors = Utils::getCoreCount() - 2;
         if ($processors > 0) {
             $poolSize = max(1, $processors);
         }
     }
     ServerScheduler::$WORKERS = $poolSize;
     if ($this->getProperty("network.batch-threshold", 256) >= 0) {
         Network::$BATCH_THRESHOLD = (int) $this->getProperty("network.batch-threshold", 256);
     } else {
         Network::$BATCH_THRESHOLD = -1;
     }
     $this->networkCompressionLevel = $this->getProperty("network.compression-level", 7);
     $this->networkCompressionAsync = $this->getProperty("network.async-compression", true);
     $this->autoTickRate = (bool) $this->getProperty("level-settings.auto-tick-rate", true);
     $this->autoTickRateLimit = (int) $this->getProperty("level-settings.auto-tick-rate-limit", 20);
     $this->alwaysTickPlayers = (int) $this->getProperty("level-settings.always-tick-players", false);
     $this->baseTickRate = (int) $this->getProperty("level-settings.base-tick-rate", 1);
     $this->scheduler = new ServerScheduler();
     if ($this->getConfigBoolean("enable-rcon", false) === true) {
         $this->rcon = new RCON($this, $this->getConfigString("rcon.password", ""), $this->getConfigInt("rcon.port", $this->getPort()), ($ip = $this->getIp()) != "" ? $ip : "0.0.0.0", $this->getConfigInt("rcon.threads", 1), $this->getConfigInt("rcon.clients-per-thread", 50));
     }
     $this->entityMetadata = new EntityMetadataStore();
     $this->playerMetadata = new PlayerMetadataStore();
     $this->levelMetadata = new LevelMetadataStore();
     $this->operators = new Config($this->dataPath . "ops.txt", Config::ENUM);
     $this->whitelist = new Config($this->dataPath . "white-list.txt", Config::ENUM);
     if (file_exists($this->dataPath . "banned.txt") and !file_exists($this->dataPath . "banned-players.txt")) {
         @rename($this->dataPath . "banned.txt", $this->dataPath . "banned-players.txt");
     }
     @touch($this->dataPath . "banned-players.txt");
     $this->banByName = new BanList($this->dataPath . "banned-players.txt");
     $this->banByName->load();
     @touch($this->dataPath . "banned-ips.txt");
     $this->banByIP = new BanList($this->dataPath . "banned-ips.txt");
     $this->banByIP->load();
     $this->maxPlayers = $this->getConfigInt("max-players", 20);
     $this->setAutoSave($this->getConfigBoolean("auto-save", true));
     if ($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3) {
         $this->setConfigInt("difficulty", 3);
     }
     define("pocketmine\\DEBUG", (int) $this->getProperty("debug.level", 1));
     if ($this->logger instanceof MainLogger) {
         $this->logger->setLogDebug(\pocketmine\DEBUG > 1);
     }
     if (\pocketmine\DEBUG >= 0) {
         @cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
     }
     $this->logger->info($this->getLanguage()->translateString("pocketmine.server.networkStart", [$this->getIp() === "" ? "*" : $this->getIp(), $this->getPort()]));
     define("BOOTUP_RANDOM", @Utils::getRandomBytes(16));
     $this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort());
     $this->getLogger()->debug("Server unique id: " . $this->getServerUniqueId());
     $this->getLogger()->debug("Machine unique id: " . Utils::getMachineUniqueId());
     $this->network = new Network($this);
     $this->network->setName($this->getMotd());
     $this->logger->info($this->getLanguage()->translateString("pocketmine.server.info", [$this->getName(), ($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::WHITE, $this->getCodename(), $this->getApiVersion()]));
     $this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));
     Timings::init();
     $this->consoleSender = new ConsoleCommandSender();
     $this->commandMap = new SimpleCommandMap($this);
     $this->registerEntities();
     $this->registerTiles();
     InventoryType::init();
     Block::init();
     Item::init();
     Biome::init();
     Effect::init();
     Enchantment::init();
     Attribute::init();
     /** TODO: @deprecated */
     TextWrapper::init();
     $this->craftingManager = new CraftingManager();
     $this->pluginManager = new PluginManager($this, $this->commandMap);
     $this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender);
     $this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false));
     $this->profilingTickRate = (double) $this->getProperty("settings.profile-report-trigger", 20);
     $this->pluginManager->registerInterface(PharPluginLoader::class);
     $this->pluginManager->registerInterface(ScriptPluginLoader::class);
     set_exception_handler([$this, "exceptionHandler"]);
     register_shutdown_function([$this, "crashDump"]);
     $this->queryRegenerateTask = new QueryRegenerateEvent($this, 5);
     $this->network->registerInterface(new RakLibInterface($this));
     $this->pluginManager->loadPlugins($this->pluginPath);
     $this->updater = new AutoUpdater($this, $this->getProperty("auto-updater.host", "www.pocketmine.net"));
     $this->enablePlugins(PluginLoadOrder::STARTUP);
     LevelProviderManager::addProvider($this, Anvil::class);
     LevelProviderManager::addProvider($this, McRegion::class);
     if (extension_loaded("leveldb")) {
         $this->logger->debug($this->getLanguage()->translateString("pocketmine.debug.enable"));
         LevelProviderManager::addProvider($this, LevelDB::class);
     }
     Generator::addGenerator(Flat::class, "flat");
     Generator::addGenerator(Normal::class, "normal");
     Generator::addGenerator(Normal::class, "default");
     Generator::addGenerator(Nether::class, "hell");
     Generator::addGenerator(Nether::class, "nether");
     foreach ((array) $this->getProperty("worlds", []) as $name => $worldSetting) {
         if ($this->loadLevel($name) === false) {
             $seed = $this->getProperty("worlds.{$name}.seed", time());
             $options = explode(":", $this->getProperty("worlds.{$name}.generator", Generator::getGenerator("default")));
             $generator = Generator::getGenerator(array_shift($options));
             if (count($options) > 0) {
                 $options = ["preset" => implode(":", $options)];
             } else {
                 $options = [];
             }
             $this->generateLevel($name, $seed, $generator, $options);
         }
     }
     if ($this->getDefaultLevel() === null) {
         $default = $this->getConfigString("level-name", "world");
         if (trim($default) == "") {
             $this->getLogger()->warning("level-name cannot be null, using default");
             $default = "world";
             $this->setConfigString("level-name", "world");
         }
         if ($this->loadLevel($default) === false) {
             $seed = $this->getConfigInt("level-seed", time());
             $this->generateLevel($default, $seed === 0 ? time() : $seed);
         }
         $this->setDefaultLevel($this->getLevelByName($default));
     }
     $this->properties->save(true);
     if (!$this->getDefaultLevel() instanceof Level) {
         $this->getLogger()->emergency($this->getLanguage()->translateString("pocketmine.level.defaultError"));
         $this->forceShutdown();
         return;
     }
     if ($this->getProperty("ticks-per.autosave", 6000) > 0) {
         $this->autoSaveTicks = (int) $this->getProperty("ticks-per.autosave", 6000);
     }
     $this->enablePlugins(PluginLoadOrder::POSTWORLD);
     $this->start();
 }
Пример #2
0
 /**
  * Sends a direct chat message to a player
  *
  * @param string $message
  */
 public function sendMessage($message)
 {
     if ($this->removeFormat !== false) {
         $message = TextWrapper::wrap(TextFormat::clean($message));
     }
     $mes = explode("\n", $message);
     foreach ($mes as $m) {
         if ($m !== "") {
             $pk = new MessagePacket();
             $pk->source = "";
             //Do not use this ;)
             $pk->message = $m;
             $this->dataPacket($pk);
         }
     }
 }
Пример #3
0
 /**
  * @param \ClassLoader    $autoloader
  * @param \ThreadedLogger $logger
  * @param string          $filePath
  * @param string          $dataPath
  * @param string          $pluginPath
  */
 public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $filePath, $dataPath, $pluginPath)
 {
     self::$instance = $this;
     $this->autoloader = $autoloader;
     $this->logger = $logger;
     $this->filePath = $filePath;
     if (!file_exists($dataPath . "worlds/")) {
         mkdir($dataPath . "worlds/", 0777);
     }
     if (!file_exists($dataPath . "players/")) {
         mkdir($dataPath . "players/", 0777);
     }
     if (!file_exists($pluginPath)) {
         mkdir($pluginPath, 0777);
     }
     $this->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
     $this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
     $this->console = new CommandReader();
     $version = new VersionString($this->getPocketMineVersion());
     $this->logger->info("Starting Minecraft: PE server version " . TextFormat::AQUA . $this->getVersion());
     $this->logger->info("Loading pocketmine-soft.yml...");
     if (!file_exists($this->dataPath . "pocketmine-soft.yml")) {
         $content = file_get_contents($this->filePath . "src/pocketmine/resources/pocketmine-soft.yml");
         @file_put_contents($this->dataPath . "pocketmine-soft.yml", $content);
     }
     $this->softConfig = new Config($this->dataPath . "pocketmine-soft.yml", Config::YAML, []);
     $this->logger->info("Loading pocketmine.yml...");
     if (!file_exists($this->dataPath . "pocketmine.yml")) {
         $content = file_get_contents($this->filePath . "src/pocketmine/resources/pocketmine.yml");
         @file_put_contents($this->dataPath . "pocketmine.yml", $content);
     }
     $this->config = new Config($this->dataPath . "pocketmine.yml", Config::YAML, []);
     $this->logger->info("Loading server properties...");
     $this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, ["motd" => "Minecraft: PE Server", "server-port" => 19132, "memory-limit" => "256M", "white-list" => false, "announce-player-achievements" => true, "spawn-protection" => 16, "max-players" => 20, "allow-flight" => false, "spawn-animals" => true, "spawn-mobs" => true, "gamemode" => 0, "force-gamemode" => false, "hardcore" => false, "pvp" => true, "difficulty" => 1, "generator-settings" => "", "level-name" => "world", "level-seed" => "", "level-type" => "DEFAULT", "enable-query" => true, "enable-rcon" => false, "rcon.password" => substr(base64_encode(@Utils::getRandomBytes(20, false)), 3, 10), "auto-save" => true]);
     ServerScheduler::$WORKERS = 4;
     if ($this->getProperty("network.batch-threshold", 256) >= 0) {
         Network::$BATCH_THRESHOLD = (int) $this->getProperty("network.batch-threshold", 256);
     } else {
         Network::$BATCH_THRESHOLD = -1;
     }
     $this->networkCompressionLevel = $this->getProperty("network.compression-level", 7);
     $this->networkCompressionAsync = $this->getProperty("network.async-compression", true);
     $this->scheduler = new ServerScheduler();
     if ($this->getConfigBoolean("enable-rcon", false) === true) {
         $this->rcon = new RCON($this, $this->getConfigString("rcon.password", ""), $this->getConfigInt("rcon.port", $this->getPort()), ($ip = $this->getIp()) != "" ? $ip : "0.0.0.0", $this->getConfigInt("rcon.threads", 1), $this->getConfigInt("rcon.clients-per-thread", 50));
     }
     $this->entityMetadata = new EntityMetadataStore();
     $this->playerMetadata = new PlayerMetadataStore();
     $this->levelMetadata = new LevelMetadataStore();
     $this->operators = new Config($this->dataPath . "ops.txt", Config::ENUM);
     $this->whitelist = new Config($this->dataPath . "white-list.txt", Config::ENUM);
     if (file_exists($this->dataPath . "banned.txt") and !file_exists($this->dataPath . "banned-players.txt")) {
         @rename($this->dataPath . "banned.txt", $this->dataPath . "banned-players.txt");
     }
     @touch($this->dataPath . "banned-players.txt");
     $this->banByName = new BanList($this->dataPath . "banned-players.txt");
     $this->banByName->load();
     @touch($this->dataPath . "banned-ips.txt");
     $this->banByIP = new BanList($this->dataPath . "banned-ips.txt");
     $this->banByIP->load();
     $this->maxPlayers = $this->getConfigInt("max-players", 20);
     $this->setAutoSave($this->getConfigBoolean("auto-save", true));
     if (($memory = str_replace("B", "", strtoupper($this->getConfigString("memory-limit", "256M")))) !== false) {
         $value = ["M" => 1, "G" => 1024];
         $real = (int) substr($memory, 0, -1) * $value[substr($memory, -1)];
         if ($real < 128) {
             $this->logger->warning($this->getName() . " may not work right with less than 128MB of RAM", true, true, 0);
         }
         @ini_set("memory_limit", $memory);
     } else {
         $this->setConfigString("memory-limit", "256M");
     }
     $this->network = new Network($this);
     if ($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3) {
         $this->setConfigInt("difficulty", 3);
     }
     define("pocketmine\\DEBUG", (int) $this->getProperty("debug.level", 1));
     if ($this->logger instanceof MainLogger) {
         $this->logger->setLogDebug(\pocketmine\DEBUG > 1);
     }
     define("ADVANCED_CACHE", $this->getProperty("settings.advanced-cache", false));
     if (ADVANCED_CACHE == true) {
         $this->logger->info("Advanced cache enabled");
     }
     Level::$COMPRESSION_LEVEL = $this->getProperty("chunk-sending.compression-level", 8);
     if (defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0) {
         @\cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
     }
     $this->logger->info("Starting Minecraft PE server on " . ($this->getIp() === "" ? "*" : $this->getIp()) . ":" . $this->getPort());
     define("BOOTUP_RANDOM", @Utils::getRandomBytes(16));
     $this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort());
     $this->addInterface($this->mainInterface = new RakLibInterface($this));
     $this->logger->info("This server is running " . $this->getName() . " version " . ($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::WHITE . " \"" . $this->getCodename() . "\" (API " . $this->getApiVersion() . ")");
     $this->logger->info($this->getName() . " is distributed under the LGPL License");
     PluginManager::$pluginParentTimer = new TimingsHandler("** Plugins");
     Timings::init();
     $this->consoleSender = new ConsoleCommandSender();
     $this->commandMap = new SimpleCommandMap($this);
     $this->registerEntities();
     $this->registerTiles();
     InventoryType::init();
     Block::init();
     Item::init();
     TextWrapper::init();
     $this->craftingManager = new CraftingManager();
     $this->pluginManager = new PluginManager($this, $this->commandMap);
     $this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender);
     $this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false));
     $this->pluginManager->registerInterface(PharPluginLoader::class);
     \set_exception_handler([$this, "exceptionHandler"]);
     register_shutdown_function([$this, "crashDump"]);
     $plugins = $this->pluginManager->loadPlugins($this->pluginPath);
     $configPlugins = $this->getAdvancedProperty("plugins", []);
     if (count($configPlugins) > 0) {
         $this->getLogger()->info("Checking extra plugins");
         $loadNew = false;
         foreach ($configPlugins as $plugin => $download) {
             if (!isset($plugins[$plugin])) {
                 $path = $this->pluginPath . "/" . $plugin . ".phar";
                 if (substr($download, 0, 4) === "http") {
                     $this->getLogger()->info("Downloading " . $plugin);
                     file_put_contents($path, Utils::getURL($download));
                 } else {
                     file_put_contents($path, file_get_contents($download));
                 }
                 $loadNew = true;
             }
         }
         if ($loadNew) {
             $this->pluginManager->loadPlugins($this->pluginPath);
         }
     }
     $this->enablePlugins(PluginLoadOrder::STARTUP);
     if ($this->getProperty("chunk-generation.use-async", true)) {
         $this->generationManager = new GenerationRequestManager($this);
     } else {
         $this->generationManager = new GenerationInstanceManager($this);
     }
     LevelProviderManager::addProvider($this, Anvil::class);
     LevelProviderManager::addProvider($this, McRegion::class);
     if (extension_loaded("leveldb")) {
         $this->logger->debug("Enabling LevelDB support");
         LevelProviderManager::addProvider($this, LevelDB::class);
     }
     Generator::addGenerator(Flat::class, "flat");
     Generator::addGenerator(Normal::class, "normal");
     Generator::addGenerator(Normal::class, "default");
     foreach ((array) $this->getProperty("worlds", []) as $name => $worldSetting) {
         if ($this->loadLevel($name) === false) {
             $seed = $this->getProperty("worlds.{$name}.seed", time());
             $options = explode(":", $this->getProperty("worlds.{$name}.generator", Generator::getGenerator("default")));
             $generator = Generator::getGenerator(array_shift($options));
             if (count($options) > 0) {
                 $options = ["preset" => implode(":", $options)];
             } else {
                 $options = [];
             }
             $this->generateLevel($name, $seed, $generator, $options);
         }
     }
     if ($this->getDefaultLevel() === null) {
         $default = $this->getConfigString("level-name", "world");
         if (trim($default) == "") {
             $this->getLogger()->warning("level-name cannot be null, using default");
             $default = "world";
             $this->setConfigString("level-name", "world");
         }
         if ($this->loadLevel($default) === false) {
             $seed = $this->getConfigInt("level-seed", time());
             $this->generateLevel($default, $seed === 0 ? time() : $seed);
         }
         $this->setDefaultLevel($this->getLevelByName($default));
     }
     $this->properties->save();
     if (!$this->getDefaultLevel() instanceof Level) {
         $this->getLogger()->emergency("No default level has been loaded");
         $this->forceShutdown();
         return;
     }
     $this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([Cache::class, "cleanup"]), $this->getProperty("ticks-per.cache-cleanup", 900), $this->getProperty("ticks-per.cache-cleanup", 900));
     if ($this->getAutoSave() and $this->getProperty("ticks-per.autosave", 6000) > 0) {
         $this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([$this, "doAutoSave"]), $this->getProperty("ticks-per.autosave", 6000), $this->getProperty("ticks-per.autosave", 6000));
     }
     if ($this->getProperty("chunk-gc.period-in-ticks", 600) > 0) {
         $this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([$this, "doLevelGC"]), $this->getProperty("chunk-gc.period-in-ticks", 600), $this->getProperty("chunk-gc.period-in-ticks", 600));
     }
     $this->scheduler->scheduleRepeatingTask(new GarbageCollectionTask(), 900);
     $this->enablePlugins(PluginLoadOrder::POSTWORLD);
     if ($this->getAdvancedProperty("main.player-shuffle", 0) > 0) {
         $this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([$this, "shufflePlayers"]), $this->getAdvancedProperty("main.player-shuffle", 0), $this->getAdvancedProperty("main.player-shuffle", 0));
     }
     $this->start();
 }
Пример #4
0
 public function Chatty()
 {
     foreach ($this->getServer()->getOnlinePlayers() as $OnlinePlayer) {
         if (!isset($this->db[$OnlinePlayer->getName()]["NameTAG"])) {
             continue;
         }
         if (isset($this->db[$OnlinePlayer->getName()]["NameTAG"])) {
             if ($this->db[$OnlinePlayer->getName()]["NameTAG"] == false) {
                 continue;
             }
         }
         $px = round($OnlinePlayer->x);
         $py = round($OnlinePlayer->y);
         $pz = round($OnlinePlayer->z);
         if (isset($this->packetQueue[$OnlinePlayer->getName()]["eid"])) {
             $this->packet["RemovePlayerPacket"]->eid = $this->packetQueue[$OnlinePlayer->getName()]["eid"];
             $OnlinePlayer->dataPacket($this->packet["RemovePlayerPacket"]);
             // 네임택 제거패킷 전송
         }
         if ($OnlinePlayer->pitch / 180 * M_PI < -0.2) {
             continue;
         }
         // 하늘을 볼경우 패킷보내지않음
         $allmessage = "";
         if (!isset($this->messageStack[$OnlinePlayer->getName()])) {
             continue;
         }
         foreach ($this->messageStack[$OnlinePlayer->getName()] as $message) {
             $allmessage .= TextWrapper::wrap(TextFormat::clean($message)) . "\n";
         }
         // 색상표시시 \n이 작동안됨
         $this->packetQueue[$OnlinePlayer->getName()]["x"] = round($px);
         $this->packetQueue[$OnlinePlayer->getName()]["y"] = round($py);
         $this->packetQueue[$OnlinePlayer->getName()]["z"] = round($pz);
         $this->packetQueue[$OnlinePlayer->getName()]["eid"] = Entity::$entityCount++;
         $this->packet["AddPlayerPacket"]->eid = $this->packetQueue[$OnlinePlayer->getName()]["eid"];
         $this->packet["AddPlayerPacket"]->username = $this->nameTag . $allmessage;
         $this->packet["AddPlayerPacket"]->x = $px + -\sin($OnlinePlayer->yaw / 180 * M_PI - 0.4) * 7;
         $this->packet["AddPlayerPacket"]->y = $py + 10;
         $this->packet["AddPlayerPacket"]->z = $pz + \cos($OnlinePlayer->yaw / 180 * M_PI - 0.4) * 7;
         // *\cos ( $OnlinePlayer->pitch / 180 * M_PI )
         $OnlinePlayer->dataPacket($this->packet["AddPlayerPacket"]);
     }
 }