/** * @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; self::$sleeper = new \Threaded(); $this->autoloader = $autoloader; $this->logger = $logger; $this->filePath = $filePath; try { if (!file_exists($dataPath . "crashdumps/")) { mkdir($dataPath . "crashdumps/", 0777); } 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($logger); $version = new VersionString($this->getPocketMineVersion()); $reloadpreConfig = false; $this->logger->info("Loading pocketmine.yml..."); if (!file_exists($this->dataPath . "pocketmine.yml")) { //$content = $this->translateConfig(file_get_contents($this->filePath . "src/pocketmine/resources/pocketmine.yml"),"eng"); $content = \file_get_contents($this->filePath . "src/pocketmine/resources/pocketmine.yml"); @\file_put_contents($this->dataPath . "pocketmine.yml", $content); } else { $this->config = new Config($this->dataPath . "pocketmine.yml", Config::YAML, []); $internal_config = yaml_parse(file_get_contents($this->filePath . "src/pocketmine/resources/pocketmine.yml")); if ($this->getProperty("version", 0) < $internal_config['version']) { $this->logger->warning("Outdated pocketmine.yml"); if ($this->getProperty("settings.config-update", true)) { $this->logger->info("Updating pocketmine.yml..."); if (!$this->getProperty("temp-file", false)) { rename($this->dataPath . "pocketmine.yml", $this->dataPath . "pocketmine.yml." . time() . ".bak"); } //$content = $this->translateConfig(file_get_contents($this->filePath . "src/pocketmine/resources/pocketmine.yml"),$this->getProperty("settings.language", "eng")); $content = \file_get_contents($this->filePath . "src/pocketmine/resources/pocketmine.yml"); @\file_put_contents($this->dataPath . "pocketmine.yml", $content); } else { $this->logger->info("Ignore outdated pocketmine.yml"); } } unset($inernal_config); } $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(random_bytes(20)), 3, 10), "auto-save" => true, "online-mode" => false]); if (!extension_loaded("openssl") && $this->getConfigBoolean("online-mode", false)) { $this->logger->warning("The OpenSSL extension is not loaded, and this is required for XBOX authentication to work. If you want to use Xbox Live auth, please use PHP binarys with OpenSSL, or recompile PHP with the OpenSSL extension."); //TODO:TRANSLATE $this->setConfigBool("online-mode", false); } if (extension_loaded("xdebug")) { if (!$this->getProperty("debug.allow-xdebug", false)) { $this->logger->critical("Please do not use a PHP installation with the xDebug extension loaded for a Production server. If you do want to use it however, set debug.allow-xdebug to true."); //TODO:TRANSLATE return; } else { $this->logger->warning("xDebug is enabled, this decreases Performance. Use this for development purposes only."); //TODO:TRANSLATE } } if (!$this->getProperty("I/O.log-to-file", true)) { $this->logger->disable(); $this->logger->info("MainLogger will not write to server.log"); //TODO:TRANSLATE } else { $this->logger->enable(); $this->logger->info("MainLogger will write to server.log"); //TODO:TRANSLATE } $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)); ini_set('assert.exception', 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", random_bytes(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(), $this->getPocketMineVersion(), $this->getCodename(), $this->getApiVersion(), $this->getPocketMineBuild()])); $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(); EnchantmentLevelTable::init(); Color::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); 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", "jenkins.clearskyteam.org")); $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 = getopt("", ["level-seed::"])["level-seed"] ?? $this->properties->get("level-seed", time()); if (!is_numeric($seed) or bccomp($seed, "9223372036854775807") > 0) { $seed = Utils::javaStringHash($seed); } elseif (PHP_INT_SIZE === 8) { $seed = (int) $seed; } $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(); } catch (\Throwable $e) { $this->exceptionHandler($e); } }