public function onSlotChange($index, $before) { parent::onSlotChange($index, $before); if ($index == 0) { $item = $this->getItem(0); if ($item->getId() == Item::AIR) { $this->entries = null; } elseif ($before->getId() == Item::AIR and !$item->hasEnchantments()) { //before enchant if ($this->entries == null) { $enchantAbility = Enchantment::getEnchantAbility($item); $this->entries = []; for ($i = 0; $i < 3; $i++) { $result = []; $level = $this->levels[$i]; $k = $level + mt_rand(0, round(round($enchantAbility / 4) * 2)) + 1; $bonus = ($this->randomFloat() + $this->randomFloat() - 1) * 0.15 + 1; $modifiedLevel = $k * (1 + $bonus) + 0.5; $possible = EnchantmentLevelTable::getPossibleEnchantments($item, $modifiedLevel); $weights = []; $total = 0; for ($j = 0; $j < count($possible); $j++) { $id = $possible[$j]->getId(); $weight = Enchantment::getEnchantWeight($id); $weights[$j] = $weight; $total += $weight; } $v = mt_rand(1, $total + 1); $sum = 0; for ($key = 0; $key < count($weights); ++$key) { $sum += $weights[$key]; if ($sum >= $v) { $key++; break; } } $key--; $enchantment = $possible[$key]; $result[] = $enchantment; unset($possible[$key]); //Extra enchantment while (count($possible) > 0) { $modifiedLevel = round($modifiedLevel / 2); $v = mt_rand(0, 51); if ($v <= $modifiedLevel + 1) { $possible = $this->removeConflictEnchantment($enchantment, $possible); $weights = []; $total = 0; for ($j = 0; $j < count($possible); $j++) { $id = $possible[$j]->getId(); $weight = Enchantment::getEnchantWeight($id); $weights[$j] = $weight; $total += $weight; } $v = mt_rand(1, $total + 1); $sum = 0; for ($key = 0; $key < count($weights); ++$key) { $sum += $weights[$key]; if ($sum >= $v) { $key++; break; } } $key--; $enchantment = $possible[$key]; $result[] = $enchantment; unset($possible[$key]); } else { break; } } $this->entries[$i] = new EnchantmentEntry($result, $level, Enchantment::generateName()); } $this->sendEnchantmentList(); } } } }
/** * @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); } }