Extract ServerConfigGroup from Server

this API isn't very nice, but it's pretty much the same as the original, and at least this can be _kinda_ unit-tested...
This commit is contained in:
Dylan K. Taylor 2020-05-24 15:48:03 +01:00
parent b05fab3e3c
commit fe649d8d70
15 changed files with 258 additions and 204 deletions

View File

@ -183,7 +183,7 @@ class CrashDump{
private function extraData() : void{
global $argv;
if($this->server->getProperty("auto-report.send-settings", true) !== false){
if($this->server->getConfigGroup()->getProperty("auto-report.send-settings", true) !== false){
$this->data["parameters"] = (array) $argv;
$this->data["server.properties"] = @file_get_contents($this->server->getDataPath() . "server.properties");
$this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $this->data["server.properties"]);
@ -199,7 +199,7 @@ class CrashDump{
}
$this->data["extensions"] = $extensions;
if($this->server->getProperty("auto-report.send-phpinfo", true) !== false){
if($this->server->getConfigGroup()->getProperty("auto-report.send-phpinfo", true) !== false){
ob_start();
phpinfo();
$this->data["phpinfo"] = ob_get_contents();
@ -261,7 +261,7 @@ class CrashDump{
$this->addLine("Code:");
$this->data["code"] = [];
if($this->server->getProperty("auto-report.send-code", true) !== false and file_exists($error["fullFile"])){
if($this->server->getConfigGroup()->getProperty("auto-report.send-code", true) !== false and file_exists($error["fullFile"])){
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
if($file !== false){
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){

View File

@ -118,15 +118,15 @@ class MemoryManager{
$this->server = $server;
$this->logger = new \PrefixedLogger($server->getLogger(), "Memory Manager");
$this->init();
$this->init($server->getConfigGroup());
}
private function init() : void{
$this->memoryLimit = ((int) $this->server->getProperty("memory.main-limit", 0)) * 1024 * 1024;
private function init(ServerConfigGroup $config) : void{
$this->memoryLimit = ((int) $config->getProperty("memory.main-limit", 0)) * 1024 * 1024;
$defaultMemory = 1024;
if(preg_match("/([0-9]+)([KMGkmg])/", $this->server->getConfigString("memory-limit", ""), $matches) > 0){
if(preg_match("/([0-9]+)([KMGkmg])/", $config->getConfigString("memory-limit", ""), $matches) > 0){
$m = (int) $matches[1];
if($m <= 0){
$defaultMemory = 0;
@ -148,7 +148,7 @@ class MemoryManager{
}
}
$hardLimit = ((int) $this->server->getProperty("memory.main-hard-limit", $defaultMemory));
$hardLimit = ((int) $config->getProperty("memory.main-hard-limit", $defaultMemory));
if($hardLimit <= 0){
ini_set("memory_limit", '-1');
@ -156,22 +156,22 @@ class MemoryManager{
ini_set("memory_limit", $hardLimit . "M");
}
$this->globalMemoryLimit = ((int) $this->server->getProperty("memory.global-limit", 0)) * 1024 * 1024;
$this->checkRate = (int) $this->server->getProperty("memory.check-rate", 20);
$this->continuousTrigger = (bool) $this->server->getProperty("memory.continuous-trigger", true);
$this->continuousTriggerRate = (int) $this->server->getProperty("memory.continuous-trigger-rate", 30);
$this->globalMemoryLimit = ((int) $config->getProperty("memory.global-limit", 0)) * 1024 * 1024;
$this->checkRate = (int) $config->getProperty("memory.check-rate", 20);
$this->continuousTrigger = (bool) $config->getProperty("memory.continuous-trigger", true);
$this->continuousTriggerRate = (int) $config->getProperty("memory.continuous-trigger-rate", 30);
$this->garbageCollectionPeriod = (int) $this->server->getProperty("memory.garbage-collection.period", 36000);
$this->garbageCollectionTrigger = (bool) $this->server->getProperty("memory.garbage-collection.low-memory-trigger", true);
$this->garbageCollectionAsync = (bool) $this->server->getProperty("memory.garbage-collection.collect-async-worker", true);
$this->garbageCollectionPeriod = (int) $config->getProperty("memory.garbage-collection.period", 36000);
$this->garbageCollectionTrigger = (bool) $config->getProperty("memory.garbage-collection.low-memory-trigger", true);
$this->garbageCollectionAsync = (bool) $config->getProperty("memory.garbage-collection.collect-async-worker", true);
$this->lowMemChunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
$this->lowMemChunkGC = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
$this->lowMemChunkRadiusOverride = (int) $config->getProperty("memory.max-chunks.chunk-radius", 4);
$this->lowMemChunkGC = (bool) $config->getProperty("memory.max-chunks.trigger-chunk-collect", true);
$this->lowMemDisableChunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
$this->lowMemClearWorldCache = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);
$this->lowMemDisableChunkCache = (bool) $config->getProperty("memory.world-caches.disable-chunk-cache", true);
$this->lowMemClearWorldCache = (bool) $config->getProperty("memory.world-caches.low-memory-trigger", true);
$this->dumpWorkers = (bool) $this->server->getProperty("memory.memory-dump.dump-async-worker", true);
$this->dumpWorkers = (bool) $config->getProperty("memory.memory-dump.dump-async-worker", true);
gc_enable();
}

View File

@ -99,7 +99,6 @@ use pocketmine\world\generator\GeneratorManager;
use pocketmine\world\generator\normal\Normal;
use pocketmine\world\World;
use pocketmine\world\WorldManager;
use function array_key_exists;
use function array_shift;
use function array_sum;
use function base64_encode;
@ -114,12 +113,10 @@ use function file_put_contents;
use function filemtime;
use function get_class;
use function getmypid;
use function getopt;
use function implode;
use function ini_set;
use function is_a;
use function is_array;
use function is_bool;
use function is_string;
use function json_decode;
use function max;
@ -275,13 +272,8 @@ class Server{
/** @var QueryInfo */
private $queryInfo;
/** @var Config */
private $properties;
/** @var mixed[] */
private $propertyCache = [];
/** @var Config */
private $config;
/** @var ServerConfigGroup */
private $configGroup;
/** @var Player[] */
private $playerList = [];
@ -342,11 +334,11 @@ class Server{
}
public function getPort() : int{
return $this->getConfigInt("server-port", 19132);
return $this->configGroup->getConfigInt("server-port", 19132);
}
public function getViewDistance() : int{
return max(2, $this->getConfigInt("view-distance", 8));
return max(2, $this->configGroup->getConfigInt("view-distance", 8));
}
/**
@ -357,7 +349,7 @@ class Server{
}
public function getIp() : string{
$str = $this->getConfigString("server-ip");
$str = $this->configGroup->getConfigString("server-ip");
return $str !== "" ? $str : "0.0.0.0";
}
@ -369,30 +361,30 @@ class Server{
}
public function getGamemode() : GameMode{
return GameMode::fromMagicNumber($this->getConfigInt("gamemode", 0) & 0b11);
return GameMode::fromMagicNumber($this->configGroup->getConfigInt("gamemode", 0) & 0b11);
}
public function getForceGamemode() : bool{
return $this->getConfigBool("force-gamemode", false);
return $this->configGroup->getConfigBool("force-gamemode", false);
}
/**
* Returns Server global difficulty. Note that this may be overridden in individual worlds.
*/
public function getDifficulty() : int{
return $this->getConfigInt("difficulty", World::DIFFICULTY_NORMAL);
return $this->configGroup->getConfigInt("difficulty", World::DIFFICULTY_NORMAL);
}
public function hasWhitelist() : bool{
return $this->getConfigBool("white-list", false);
return $this->configGroup->getConfigBool("white-list", false);
}
public function isHardcore() : bool{
return $this->getConfigBool("hardcore", false);
return $this->configGroup->getConfigBool("hardcore", false);
}
public function getMotd() : string{
return $this->getConfigString("motd", \pocketmine\NAME . " Server");
return $this->configGroup->getConfigString("motd", \pocketmine\NAME . " Server");
}
/**
@ -493,7 +485,7 @@ class Server{
}
public function shouldSavePlayerData() : bool{
return (bool) $this->getProperty("player.save-player-data", true);
return (bool) $this->configGroup->getProperty("player.save-player-data", true);
}
/**
@ -625,74 +617,8 @@ class Server{
return $this->getPlayerByRawUUID($uuid->toBinary());
}
/**
* @param mixed $defaultValue
*
* @return mixed
*/
public function getProperty(string $variable, $defaultValue = null){
if(!array_key_exists($variable, $this->propertyCache)){
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
$this->propertyCache[$variable] = $v[$variable];
}else{
$this->propertyCache[$variable] = $this->config->getNested($variable);
}
}
return $this->propertyCache[$variable] ?? $defaultValue;
}
public function getConfigString(string $variable, string $defaultValue = "") : string{
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
return (string) $v[$variable];
}
return $this->properties->exists($variable) ? (string) $this->properties->get($variable) : $defaultValue;
}
public function setConfigString(string $variable, string $value) : void{
$this->properties->set($variable, $value);
}
public function getConfigInt(string $variable, int $defaultValue = 0) : int{
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
return (int) $v[$variable];
}
return $this->properties->exists($variable) ? (int) $this->properties->get($variable) : $defaultValue;
}
public function setConfigInt(string $variable, int $value) : void{
$this->properties->set($variable, $value);
}
public function getConfigBool(string $variable, bool $defaultValue = false) : bool{
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
$value = $v[$variable];
}else{
$value = $this->properties->exists($variable) ? $this->properties->get($variable) : $defaultValue;
}
if(is_bool($value)){
return $value;
}
switch(strtolower($value)){
case "on":
case "true":
case "1":
case "yes":
return true;
}
return false;
}
public function setConfigBool(string $variable, bool $value) : void{
$this->properties->set($variable, $value ? "1" : "0");
public function getConfigGroup() : ServerConfigGroup{
return $this->configGroup;
}
/**
@ -775,7 +701,7 @@ class Server{
* @return string[][]
*/
public function getCommandAliases() : array{
$section = $this->getProperty("aliases");
$section = $this->configGroup->getProperty("aliases");
$result = [];
if(is_array($section)){
foreach($section as $key => $value){
@ -827,7 +753,7 @@ class Server{
$this->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
$this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
$this->logger->info("Loading pocketmine.yml...");
$this->logger->info("Loading server configuration");
if(!file_exists($this->dataPath . "pocketmine.yml")){
$content = file_get_contents(\pocketmine\RESOURCE_PATH . "pocketmine.yml");
if(\pocketmine\IS_DEVELOPMENT_BUILD){
@ -835,37 +761,38 @@ class Server{
}
@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" => \pocketmine\NAME . " Server",
"server-port" => 19132,
"white-list" => false,
"max-players" => 20,
"gamemode" => 0,
"force-gamemode" => false,
"hardcore" => false,
"pvp" => true,
"difficulty" => World::DIFFICULTY_NORMAL,
"generator-settings" => "",
"level-name" => "world",
"level-seed" => "",
"level-type" => "DEFAULT",
"enable-query" => true,
"auto-save" => true,
"view-distance" => 8,
"xbox-auth" => true,
"language" => "eng"
]);
$this->configGroup = new ServerConfigGroup(
new Config($this->dataPath . "pocketmine.yml", Config::YAML, []),
new Config($this->dataPath . "server.properties", Config::PROPERTIES, [
"motd" => \pocketmine\NAME . " Server",
"server-port" => 19132,
"white-list" => false,
"max-players" => 20,
"gamemode" => 0,
"force-gamemode" => false,
"hardcore" => false,
"pvp" => true,
"difficulty" => World::DIFFICULTY_NORMAL,
"generator-settings" => "",
"level-name" => "world",
"level-seed" => "",
"level-type" => "DEFAULT",
"enable-query" => true,
"auto-save" => true,
"view-distance" => 8,
"xbox-auth" => true,
"language" => "eng"
])
);
$debugLogLevel = (int) $this->getProperty("debug.level", 1);
$debugLogLevel = (int) $this->configGroup->getProperty("debug.level", 1);
if($this->logger instanceof MainLogger){
$this->logger->setLogDebug($debugLogLevel > 1);
}
$this->forceLanguage = (bool) $this->getProperty("settings.force-language", false);
$selectedLang = $this->getConfigString("language", $this->getProperty("settings.language", Language::FALLBACK_LANGUAGE));
$this->forceLanguage = (bool) $this->configGroup->getProperty("settings.force-language", false);
$selectedLang = $this->configGroup->getConfigString("language", $this->configGroup->getProperty("settings.language", Language::FALLBACK_LANGUAGE));
try{
$this->language = new Language($selectedLang);
}catch(LanguageNotFoundException $e){
@ -881,7 +808,7 @@ class Server{
$this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));
if(\pocketmine\IS_DEVELOPMENT_BUILD){
if(!((bool) $this->getProperty("settings.enable-dev-builds", false))){
if(!((bool) $this->configGroup->getProperty("settings.enable-dev-builds", false))){
$this->logger->emergency($this->language->translateString("pocketmine.server.devBuild.error1", [\pocketmine\NAME]));
$this->logger->emergency($this->language->translateString("pocketmine.server.devBuild.error2"));
$this->logger->emergency($this->language->translateString("pocketmine.server.devBuild.error3"));
@ -903,7 +830,7 @@ class Server{
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.start", [TextFormat::AQUA . $this->getVersion() . TextFormat::RESET]));
if(($poolSize = $this->getProperty("settings.async-workers", "auto")) === "auto"){
if(($poolSize = $this->configGroup->getProperty("settings.async-workers", "auto")) === "auto"){
$poolSize = 2;
$processors = Utils::getCoreCount() - 2;
@ -914,25 +841,25 @@ class Server{
$poolSize = max(1, (int) $poolSize);
}
$this->asyncPool = new AsyncPool($poolSize, max(-1, (int) $this->getProperty("memory.async-worker-hard-limit", 256)), $this->autoloader, $this->logger);
$this->asyncPool = new AsyncPool($poolSize, max(-1, (int) $this->configGroup->getProperty("memory.async-worker-hard-limit", 256)), $this->autoloader, $this->logger);
$netCompressionThreshold = -1;
if($this->getProperty("network.batch-threshold", 256) >= 0){
$netCompressionThreshold = (int) $this->getProperty("network.batch-threshold", 256);
if($this->configGroup->getProperty("network.batch-threshold", 256) >= 0){
$netCompressionThreshold = (int) $this->configGroup->getProperty("network.batch-threshold", 256);
}
$netCompressionLevel = (int) $this->getProperty("network.compression-level", 7);
$netCompressionLevel = (int) $this->configGroup->getProperty("network.compression-level", 7);
if($netCompressionLevel < 1 or $netCompressionLevel > 9){
$this->logger->warning("Invalid network compression level $netCompressionLevel set, setting to default 7");
$netCompressionLevel = 7;
}
ZlibCompressor::setInstance(new ZlibCompressor($netCompressionLevel, $netCompressionThreshold, ZlibCompressor::DEFAULT_MAX_DECOMPRESSION_SIZE));
$this->networkCompressionAsync = (bool) $this->getProperty("network.async-compression", true);
$this->networkCompressionAsync = (bool) $this->configGroup->getProperty("network.async-compression", true);
NetworkCipher::$ENABLED = (bool) $this->getProperty("network.enable-encryption", true);
NetworkCipher::$ENABLED = (bool) $this->configGroup->getProperty("network.enable-encryption", true);
$this->doTitleTick = ((bool) $this->getProperty("console.title-tick", true)) && Terminal::hasFormattingCodes();
$this->doTitleTick = ((bool) $this->configGroup->getProperty("console.title-tick", true)) && Terminal::hasFormattingCodes();
$this->operators = new Config($this->dataPath . "ops.txt", Config::ENUM);
$this->whitelist = new Config($this->dataPath . "white-list.txt", Config::ENUM);
@ -946,9 +873,9 @@ class Server{
$this->banByIP = new BanList($this->dataPath . "banned-ips.txt");
$this->banByIP->load();
$this->maxPlayers = $this->getConfigInt("max-players", 20);
$this->maxPlayers = $this->configGroup->getConfigInt("max-players", 20);
$this->onlineMode = $this->getConfigBool("xbox-auth", true);
$this->onlineMode = $this->configGroup->getConfigBool("xbox-auth", true);
if($this->onlineMode){
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.auth.enabled"));
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.authProperty.enabled"));
@ -958,8 +885,8 @@ class Server{
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authProperty.disabled"));
}
if($this->getConfigBool("hardcore", false) and $this->getDifficulty() < World::DIFFICULTY_HARD){
$this->setConfigInt("difficulty", World::DIFFICULTY_HARD);
if($this->configGroup->getConfigBool("hardcore", false) and $this->getDifficulty() < World::DIFFICULTY_HARD){
$this->configGroup->setConfigInt("difficulty", World::DIFFICULTY_HARD);
}
@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
@ -980,8 +907,8 @@ class Server{
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));
Timings::init();
TimingsHandler::setEnabled((bool) $this->getProperty("settings.enable-profiling", false));
$this->profilingTickRate = (float) $this->getProperty("settings.profile-report-trigger", 20);
TimingsHandler::setEnabled((bool) $this->configGroup->getProperty("settings.enable-profiling", false));
$this->profilingTickRate = (float) $this->configGroup->getProperty("settings.profile-report-trigger", 20);
$this->commandMap = new SimpleCommandMap($this);
@ -1004,13 +931,13 @@ class Server{
$this->forceShutdown();
return;
}
$this->pluginManager = new PluginManager($this, ((bool) $this->getProperty("plugins.legacy-data-dir", true)) ? null : $this->getDataPath() . "plugin_data" . DIRECTORY_SEPARATOR, $pluginGraylist);
$this->pluginManager = new PluginManager($this, ((bool) $this->configGroup->getProperty("plugins.legacy-data-dir", true)) ? null : $this->getDataPath() . "plugin_data" . DIRECTORY_SEPARATOR, $pluginGraylist);
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
$this->pluginManager->registerInterface(new ScriptPluginLoader());
$providerManager = WorldProviderManager::getInstance();
if(
($format = $providerManager->getProviderByName($formatName = (string) $this->getProperty("level-settings.default-format"))) !== null and
($format = $providerManager->getProviderByName($formatName = (string) $this->configGroup->getProperty("level-settings.default-format"))) !== null and
is_a($format, WritableWorldProvider::class, true)
){
$providerManager->setDefault($format);
@ -1019,10 +946,10 @@ class Server{
}
$this->worldManager = new WorldManager($this, $this->dataPath . "/worlds");
$this->worldManager->setAutoSave($this->getConfigBool("auto-save", $this->worldManager->getAutoSave()));
$this->worldManager->setAutoSaveInterval((int) $this->getProperty("ticks-per.autosave", 6000));
$this->worldManager->setAutoSave($this->configGroup->getConfigBool("auto-save", $this->worldManager->getAutoSave()));
$this->worldManager->setAutoSaveInterval((int) $this->configGroup->getProperty("ticks-per.autosave", 6000));
$this->updater = new AutoUpdater($this, $this->getProperty("auto-updater.host", "update.pmmp.io"));
$this->updater = new AutoUpdater($this, $this->configGroup->getProperty("auto-updater.host", "update.pmmp.io"));
$this->queryInfo = new QueryInfo($this);
@ -1031,7 +958,7 @@ class Server{
$this->pluginManager->loadPlugins($this->pluginPath);
$this->enablePlugins(PluginLoadOrder::STARTUP());
foreach((array) $this->getProperty("worlds", []) as $name => $options){
foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){
if($options === null){
$options = [];
}elseif(!is_array($options)){
@ -1053,18 +980,18 @@ class Server{
}
if($this->worldManager->getDefaultWorld() === null){
$default = $this->getConfigString("level-name", "world");
$default = $this->configGroup->getConfigString("level-name", "world");
if(trim($default) == ""){
$this->getLogger()->warning("level-name cannot be null, using default");
$default = "world";
$this->setConfigString("level-name", "world");
$this->configGroup->setConfigString("level-name", "world");
}
if(!$this->worldManager->loadWorld($default, true)){
$this->worldManager->generateWorld(
$default,
Generator::convertSeed($this->getConfigString("level-seed")),
GeneratorManager::getInstance()->getGenerator($this->getConfigString("level-type")),
["preset" => $this->getConfigString("generator-settings")]
Generator::convertSeed($this->configGroup->getConfigString("level-seed")),
GeneratorManager::getInstance()->getGenerator($this->configGroup->getConfigString("level-type")),
["preset" => $this->configGroup->getConfigString("generator-settings")]
);
}
@ -1083,7 +1010,7 @@ class Server{
$this->network->registerInterface(new RakLibInterface($this));
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.networkStart", [$this->getIp(), $this->getPort()]));
if($this->getConfigBool("enable-query", true)){
if($this->configGroup->getConfigBool("enable-query", true)){
$this->network->registerRawPacketHandler(new QueryHandler($this));
}
@ -1091,7 +1018,7 @@ class Server{
$this->network->blockAddress($entry->getName(), -1);
}
if((bool) $this->getProperty("network.upnp-forwarding", false)){
if((bool) $this->configGroup->getProperty("network.upnp-forwarding", false)){
try{
$this->network->registerInterface(new UPnP($this->logger, Internet::getInternalIP(), $this->getPort()));
}catch(\RuntimeException $e){
@ -1099,14 +1026,12 @@ class Server{
}
}
if((bool) $this->getProperty("settings.send-usage", true)){
if((bool) $this->configGroup->getProperty("settings.send-usage", true)){
$this->sendUsageTicker = 6000;
$this->sendUsage(SendUsageTask::TYPE_OPEN);
}
if($this->properties->hasChanged()){
$this->properties->save();
}
$this->configGroup->save();
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.defaultGameMode", [$this->getGamemode()->getTranslationKey()]));
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.donate", [TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET]));
@ -1380,7 +1305,7 @@ class Server{
}
if($this->network instanceof Network){
$this->network->getSessionManager()->close($this->getProperty("settings.shutdown-message", "Server closed"));
$this->network->getSessionManager()->close($this->configGroup->getProperty("settings.shutdown-message", "Server closed"));
}
if($this->worldManager instanceof WorldManager){
@ -1398,9 +1323,9 @@ class Server{
$this->asyncPool->shutdown();
}
if($this->properties !== null and $this->properties->hasChanged()){
if($this->configGroup !== null){
$this->getLogger()->debug("Saving properties");
$this->properties->save();
$this->configGroup->save();
}
if($this->console instanceof CommandReader){
@ -1485,7 +1410,7 @@ class Server{
$this->logger->emergency($this->getLanguage()->translateString("pocketmine.crash.submit", [$dump->getPath()]));
if($this->getProperty("auto-report.enabled", true) !== false){
if($this->configGroup->getProperty("auto-report.enabled", true) !== false){
$report = true;
$stamp = $this->getDataPath() . "crashdumps/.last_crash";
@ -1514,7 +1439,7 @@ class Server{
}
if($report){
$url = ((bool) $this->getProperty("auto-report.use-https", true) ? "https" : "http") . "://" . $this->getProperty("auto-report.host", "crash.pmmp.io") . "/submit/api";
$url = ((bool) $this->configGroup->getProperty("auto-report.use-https", true) ? "https" : "http") . "://" . $this->configGroup->getProperty("auto-report.host", "crash.pmmp.io") . "/submit/api";
$reply = Internet::postURL($url, [
"report" => "yes",
"name" => $this->getName() . " " . $this->getPocketMineVersion(),
@ -1593,7 +1518,7 @@ class Server{
}
public function sendUsage(int $type = SendUsageTask::TYPE_STATUS) : void{
if((bool) $this->getProperty("anonymous-statistics.enabled", true)){
if((bool) $this->configGroup->getProperty("anonymous-statistics.enabled", true)){
$this->asyncPool->submitTask(new SendUsageTask($this, $type, $this->uniquePlayers));
}
$this->uniquePlayers = [];

128
src/ServerConfigGroup.php Normal file
View File

@ -0,0 +1,128 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine;
use pocketmine\utils\Config;
use function array_key_exists;
use function getopt;
use function is_bool;
use function strtolower;
final class ServerConfigGroup{
/** @var Config */
private $pocketmineYml;
/** @var Config */
private $serverProperties;
/**
* @var mixed[]
* @phpstan-var array<string, mixed>
*/
private $propertyCache = [];
public function __construct(Config $pocketmineYml, Config $serverProperties){
$this->pocketmineYml = $pocketmineYml;
$this->serverProperties = $serverProperties;
}
/**
* @param mixed $defaultValue
*
* @return mixed
*/
public function getProperty(string $variable, $defaultValue = null){
if(!array_key_exists($variable, $this->propertyCache)){
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
$this->propertyCache[$variable] = $v[$variable];
}else{
$this->propertyCache[$variable] = $this->pocketmineYml->getNested($variable);
}
}
return $this->propertyCache[$variable] ?? $defaultValue;
}
public function getConfigString(string $variable, string $defaultValue = "") : string{
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
return (string) $v[$variable];
}
return $this->serverProperties->exists($variable) ? (string) $this->serverProperties->get($variable) : $defaultValue;
}
public function setConfigString(string $variable, string $value) : void{
$this->serverProperties->set($variable, $value);
}
public function getConfigInt(string $variable, int $defaultValue = 0) : int{
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
return (int) $v[$variable];
}
return $this->serverProperties->exists($variable) ? (int) $this->serverProperties->get($variable) : $defaultValue;
}
public function setConfigInt(string $variable, int $value) : void{
$this->serverProperties->set($variable, $value);
}
public function getConfigBool(string $variable, bool $defaultValue = false) : bool{
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
$value = $v[$variable];
}else{
$value = $this->serverProperties->exists($variable) ? $this->serverProperties->get($variable) : $defaultValue;
}
if(is_bool($value)){
return $value;
}
switch(strtolower($value)){
case "on":
case "true":
case "1":
case "yes":
return true;
}
return false;
}
public function setConfigBool(string $variable, bool $value) : void{
$this->serverProperties->set($variable, $value ? "1" : "0");
}
public function save() : void{
if($this->serverProperties->hasChanged()){
$this->serverProperties->save();
}
if($this->pocketmineYml->hasChanged()){
$this->pocketmineYml->save();
}
}
}

View File

@ -56,7 +56,7 @@ class DefaultGamemodeCommand extends VanillaCommand{
return true;
}
$sender->getServer()->setConfigInt("gamemode", $gameMode->getMagicNumber());
$sender->getServer()->getConfigGroup()->setConfigInt("gamemode", $gameMode->getMagicNumber());
$sender->sendMessage(new TranslationContainer("commands.defaultgamemode.success", [$gameMode->getTranslationKey()]));
return true;
}

View File

@ -57,7 +57,7 @@ class DifficultyCommand extends VanillaCommand{
}
if($difficulty !== -1){
$sender->getServer()->setConfigInt("difficulty", $difficulty);
$sender->getServer()->getConfigGroup()->setConfigInt("difficulty", $difficulty);
//TODO: add per-world support
foreach($sender->getServer()->getWorldManager()->getWorlds() as $world){

View File

@ -119,7 +119,7 @@ class TimingsCommand extends VanillaCommand{
];
fclose($fileTimings);
$host = $sender->getServer()->getProperty("timings.host", "timings.pmmp.io");
$host = $sender->getServer()->getConfigGroup()->getProperty("timings.host", "timings.pmmp.io");
$sender->getServer()->getAsyncPool()->submitTask(new class($sender, $host, $agent, $data) extends BulkCurlTask{
private const TLS_KEY_SENDER = "sender";

View File

@ -64,12 +64,12 @@ class WhitelistCommand extends VanillaCommand{
return true;
case "on":
$sender->getServer()->setConfigBool("white-list", true);
$sender->getServer()->getConfigGroup()->setConfigBool("white-list", true);
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.whitelist.enabled"));
return true;
case "off":
$sender->getServer()->setConfigBool("white-list", false);
$sender->getServer()->getConfigGroup()->setConfigBool("white-list", false);
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.whitelist.disabled"));
return true;

View File

@ -97,7 +97,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
$threadToMainBuffer,
new InternetAddress($this->server->getIp(), $this->server->getPort(), 4),
$this->rakServerId,
(int) $this->server->getProperty("network.max-mtu-size", 1492),
(int) $this->server->getConfigGroup()->getProperty("network.max-mtu-size", 1492),
self::MCPE_RAKNET_PROTOCOL_VERSION,
$this->sleeper
);

View File

@ -76,7 +76,7 @@ final class QueryInfo{
public function __construct(Server $server){
$this->serverName = $server->getMotd();
$this->listPlugins = $server->getProperty("settings.query-plugins", true);
$this->listPlugins = $server->getConfigGroup()->getProperty("settings.query-plugins", true);
$this->plugins = $server->getPluginManager()->getPlugins();
$this->players = $server->getOnlinePlayers();

View File

@ -269,8 +269,8 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$this->xuid = $this->playerInfo->getXuid();
$this->perm = new PermissibleBase($this);
$this->chunksPerTick = (int) $this->server->getProperty("chunk-sending.per-tick", 4);
$this->spawnThreshold = (int) (($this->server->getProperty("chunk-sending.spawn-radius", 4) ** 2) * M_PI);
$this->chunksPerTick = (int) $this->server->getConfigGroup()->getProperty("chunk-sending.per-tick", 4);
$this->spawnThreshold = (int) (($this->server->getConfigGroup()->getProperty("chunk-sending.spawn-radius", 4) ** 2) * M_PI);
$namedtag = $this->server->getOfflinePlayerData($this->username); //TODO: make this async
@ -556,7 +556,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
public function setViewDistance(int $distance) : void{
$this->viewDistance = $this->server->getAllowedViewDistance($distance);
$this->spawnThreshold = (int) (min($this->viewDistance, $this->server->getProperty("chunk-sending.spawn-radius", 4)) ** 2 * M_PI);
$this->spawnThreshold = (int) (min($this->viewDistance, $this->server->getConfigGroup()->getProperty("chunk-sending.spawn-radius", 4)) ** 2 * M_PI);
$this->nextChunkOrderRun = 0;
@ -836,7 +836,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$this->spawnToAll();
if($this->server->getUpdater()->hasUpdate() and $this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE) and $this->server->getProperty("auto-updater.on-update.warn-ops", true)){
if($this->server->getUpdater()->hasUpdate() and $this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE) and $this->server->getConfigGroup()->getProperty("auto-updater.on-update.warn-ops", true)){
$this->server->getUpdater()->showPlayerUpdate($this);
}
@ -1675,7 +1675,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$oldItem = clone $heldItem;
$ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints());
if(!$this->canInteract($entity->getLocation(), 8) or ($entity instanceof Player and !$this->server->getConfigBool("pvp"))){
if(!$this->canInteract($entity->getLocation(), 8) or ($entity instanceof Player and !$this->server->getConfigGroup()->getConfigBool("pvp"))){
$ev->setCancelled();
}

View File

@ -60,7 +60,7 @@ class SendUsageTask extends AsyncTask{
* @phpstan-param array<string, string> $playerList
*/
public function __construct(Server $server, int $type, array $playerList = []){
$endpoint = "http://" . $server->getProperty("anonymous-statistics.host", "stats.pocketmine.net") . "/";
$endpoint = "http://" . $server->getConfigGroup()->getProperty("anonymous-statistics.host", "stats.pocketmine.net") . "/";
$data = [];
$data["uniqueServerId"] = $server->getServerUniqueId()->toString();

View File

@ -57,7 +57,7 @@ class AutoUpdater{
$this->logger = new \PrefixedLogger($server->getLogger(), "Auto Updater");
$this->endpoint = "http://$endpoint/api/";
if((bool) $server->getProperty("auto-updater.enabled", true)){
if((bool) $server->getConfigGroup()->getProperty("auto-updater.enabled", true)){
$this->doCheck();
}
}
@ -77,7 +77,7 @@ class AutoUpdater{
$this->checkUpdate();
if($this->hasUpdate()){
(new UpdateNotifyEvent($this))->call();
if((bool) $this->server->getProperty("auto-updater.on-update.warn-console", true)){
if((bool) $this->server->getConfigGroup()->getProperty("auto-updater.on-update.warn-console", true)){
$this->showConsoleUpdate();
}
}else{
@ -187,7 +187,7 @@ class AutoUpdater{
* Returns the channel used for update checking (stable, beta, dev)
*/
public function getChannel() : string{
$channel = strtolower($this->server->getProperty("auto-updater.preferred-channel", "stable"));
$channel = strtolower($this->server->getConfigGroup()->getProperty("auto-updater.preferred-channel", "stable"));
if($channel !== "stable" and $channel !== "beta" and $channel !== "alpha" and $channel !== "development"){
$channel = "stable";
}

View File

@ -347,12 +347,13 @@ class World implements ChunkManager{
$this->time = $this->provider->getWorldData()->getTime();
$this->chunkTickRadius = min($this->server->getViewDistance(), max(1, (int) $this->server->getProperty("chunk-ticking.tick-radius", 4)));
$this->chunksPerTick = (int) $this->server->getProperty("chunk-ticking.per-tick", 40);
$this->tickedBlocksPerSubchunkPerTick = (int) $this->server->getProperty("chunk-ticking.blocks-per-subchunk-per-tick", self::DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK);
$this->chunkPopulationQueueSize = (int) $this->server->getProperty("chunk-generation.population-queue-size", 2);
$cfg = $this->server->getConfigGroup();
$this->chunkTickRadius = min($this->server->getViewDistance(), max(1, (int) $cfg->getProperty("chunk-ticking.tick-radius", 4)));
$this->chunksPerTick = (int) $cfg->getProperty("chunk-ticking.per-tick", 40);
$this->tickedBlocksPerSubchunkPerTick = (int) $cfg->getProperty("chunk-ticking.blocks-per-subchunk-per-tick", self::DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK);
$this->chunkPopulationQueueSize = (int) $cfg->getProperty("chunk-generation.population-queue-size", 2);
$dontTickBlocks = array_fill_keys($this->server->getProperty("chunk-ticking.disable-block-ticking", []), true);
$dontTickBlocks = array_fill_keys($cfg->getProperty("chunk-ticking.disable-block-ticking", []), true);
foreach(BlockFactory::getInstance()->getAllKnownStates() as $state){
if(!isset($dontTickBlocks[$state->getId()]) and $state->ticksRandomly()){

View File

@ -65,16 +65,6 @@ parameters:
count: 1
path: ../../../src/Server.php
-
message: "#^Cannot cast array\\<int, mixed\\>\\|string\\|false to string\\.$#"
count: 1
path: ../../../src/Server.php
-
message: "#^Cannot cast array\\<int, mixed\\>\\|string\\|false to int\\.$#"
count: 1
path: ../../../src/Server.php
-
message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|false given\\.$#"
count: 1
@ -90,6 +80,16 @@ parameters:
count: 1
path: ../../../src/Server.php
-
message: "#^Cannot cast array\\<int, mixed\\>\\|string\\|false to string\\.$#"
count: 1
path: ../../../src/ServerConfigGroup.php
-
message: "#^Cannot cast array\\<int, mixed\\>\\|string\\|false to int\\.$#"
count: 1
path: ../../../src/ServerConfigGroup.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\format\\\\Chunk\\:\\:setFullBlock\\(\\) expects int, float\\|int given\\.$#"
count: 1