diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 3f1cf0c34..de9adca9d 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1445,9 +1445,7 @@ class Server{ public static function microSleep(int $microseconds){ Server::$sleeper->synchronized(function(int $ms){ - var_dump("Sleeping $ms"); Server::$sleeper->wait($ms); - var_dump("Finished sleep $ms"); }, $microseconds); } @@ -1461,255 +1459,259 @@ class Server{ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $filePath, $dataPath, $pluginPath){ self::$instance = $this; self::$sleeper = \ThreadedFactory::create(); - $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); - } + try{ - 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("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); + $this->filePath = $filePath; + if(!file_exists($dataPath . "worlds/")){ + mkdir($dataPath . "worlds/", 0777); } - @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); + if(!file_exists($dataPath . "players/")){ + mkdir($dataPath . "players/", 0777); } - } - ServerScheduler::$WORKERS = $poolSize; + if(!file_exists($pluginPath)){ + mkdir($pluginPath, 0777); + } - 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->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR; + $this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR; - $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->console = new CommandReader(); - $this->scheduler = new ServerScheduler(); + $version = new VersionString($this->getPocketMineVersion()); - 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->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->entityMetadata = new EntityMetadataStore(); - $this->playerMetadata = new PlayerMetadataStore(); - $this->levelMetadata = new LevelMetadataStore(); + $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->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->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->maxPlayers = $this->getConfigInt("max-players", 20); - $this->setAutoSave($this->getConfigBoolean("auto-save", true)); + $this->memoryManager = new MemoryManager($this); - if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){ - $this->setConfigInt("difficulty", 3); - } + $this->logger->info($this->getLanguage()->translateString("pocketmine.server.start", [TextFormat::AQUA . $this->getVersion()])); - define("pocketmine\\DEBUG", (int) $this->getProperty("debug.level", 1)); - if($this->logger instanceof MainLogger){ - $this->logger->setLogDebug(\pocketmine\DEBUG > 1); - } + if(($poolSize = $this->getProperty("settings.async-workers", "auto")) === "auto"){ + $poolSize = ServerScheduler::$WORKERS; + $processors = Utils::getCoreCount() - 2; - if(\pocketmine\DEBUG >= 0){ - @cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion()); - } + if($processors > 0){ + $poolSize = max(1, $processors); + } + } - $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()); + ServerScheduler::$WORKERS = $poolSize; - $this->getLogger()->debug("Server unique id: " . $this->getServerUniqueId()); - $this->getLogger()->debug("Machine unique id: " . Utils::getMachineUniqueId()); + 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->network = new Network($this); - $this->network->setName($this->getMotd()); + $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()])); + $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(); + Timings::init(); - $this->consoleSender = new ConsoleCommandSender(); - $this->commandMap = new SimpleCommandMap($this); + $this->consoleSender = new ConsoleCommandSender(); + $this->commandMap = new SimpleCommandMap($this); - $this->registerEntities(); - $this->registerTiles(); + $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(); + 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 = (float) $this->getProperty("settings.profile-report-trigger", 20); - $this->pluginManager->registerInterface(PharPluginLoader::class); - $this->pluginManager->registerInterface(ScriptPluginLoader::class); + $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 = (float) $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"]); + register_shutdown_function([$this, "crashDump"]); - $this->queryRegenerateTask = new QueryRegenerateEvent($this, 5); - $this->network->registerInterface(new RakLibInterface($this)); + $this->queryRegenerateTask = new QueryRegenerateEvent($this, 5); + $this->network->registerInterface(new RakLibInterface($this)); - $this->pluginManager->loadPlugins($this->pluginPath); + $this->pluginManager->loadPlugins($this->pluginPath); - $this->updater = new AutoUpdater($this, $this->getProperty("auto-updater.host", "www.pocketmine.net")); + $this->updater = new AutoUpdater($this, $this->getProperty("auto-updater.host", "www.pocketmine.net")); - $this->enablePlugins(PluginLoadOrder::STARTUP); + $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); - } + 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"); + 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 = []; + 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->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->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); } - - - $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(); } /**