diff --git a/composer.json b/composer.json index 253f16144..096c42360 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,8 @@ "pocketmine/snooze": "^0.3.0", "pocketmine/spl": "dev-master", "ramsey/uuid": "^4.1", - "respect/validation": "^2.0" + "respect/validation": "^2.0", + "webmozart/path-util": "^2.3" }, "require-dev": { "phpstan/phpstan": "0.12.90", diff --git a/composer.lock b/composer.lock index cfa81060e..400311eba 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1ec8a08d7688ec903c9b67945feab26e", + "content-hash": "3e3b505ec39bbf9e449e0466f154d5aa", "packages": [ { "name": "adhocore/json-comment", @@ -1310,6 +1310,114 @@ } ], "time": "2021-05-27T09:27:20+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "support": { + "issues": "https://github.com/webmozart/path-util/issues", + "source": "https://github.com/webmozart/path-util/tree/2.3.0" + }, + "time": "2015-12-17T08:42:14+00:00" } ], "packages-dev": [ @@ -3435,64 +3543,6 @@ } ], "time": "2020-07-12T23:59:07+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" - }, - "time": "2021-03-09T10:59:23+00:00" } ], "aliases": [], diff --git a/src/CrashDump.php b/src/CrashDump.php index 6758ba884..e6f72de5f 100644 --- a/src/CrashDump.php +++ b/src/CrashDump.php @@ -31,6 +31,7 @@ use pocketmine\plugin\PluginManager; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Filesystem; use pocketmine\utils\Utils; +use Webmozart\PathUtil\Path; use function base64_encode; use function date; use function error_get_last; @@ -103,10 +104,12 @@ class CrashDump{ public function __construct(Server $server){ $this->time = microtime(true); $this->server = $server; - if(!is_dir($this->server->getDataPath() . "crashdumps")){ - mkdir($this->server->getDataPath() . "crashdumps"); + + $crashPath = Path::join($this->server->getDataPath(), "crashdumps"); + if(!is_dir($crashPath)){ + mkdir($crashPath); } - $this->path = $this->server->getDataPath() . "crashdumps/" . date("D_M_j-H.i.s-T_Y", (int) $this->time) . ".log"; + $this->path = Path::join($crashPath, date("D_M_j-H.i.s-T_Y", (int) $this->time) . ".log"); $fp = @fopen($this->path, "wb"); if(!is_resource($fp)){ throw new \RuntimeException("Could not create Crash Dump"); @@ -193,12 +196,12 @@ class CrashDump{ if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-settings", true)){ $this->data["parameters"] = (array) $argv; - if(($serverDotProperties = @file_get_contents($this->server->getDataPath() . "server.properties")) !== false){ + if(($serverDotProperties = @file_get_contents(Path::join($this->server->getDataPath(), "server.properties"))) !== false){ $this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $serverDotProperties); }else{ $this->data["server.properties"] = $serverDotProperties; } - if(($pocketmineDotYml = @file_get_contents($this->server->getDataPath() . "pocketmine.yml")) !== false){ + if(($pocketmineDotYml = @file_get_contents(Path::join($this->server->getDataPath(), "pocketmine.yml"))) !== false){ $this->data["pocketmine.yml"] = $pocketmineDotYml; }else{ $this->data["pocketmine.yml"] = ""; diff --git a/src/MemoryManager.php b/src/MemoryManager.php index b54eed878..0a84e6b07 100644 --- a/src/MemoryManager.php +++ b/src/MemoryManager.php @@ -30,6 +30,7 @@ use pocketmine\timings\Timings; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Process; use pocketmine\utils\Utils; +use Webmozart\PathUtil\Path; use function arsort; use function count; use function fclose; @@ -316,7 +317,7 @@ class MemoryManager{ mkdir($outputFolder, 0777, true); } - $obData = fopen($outputFolder . "/objects.js", "wb+"); + $obData = fopen(Path::join($outputFolder, "objects.js"), "wb+"); $data = []; @@ -367,7 +368,7 @@ class MemoryManager{ } } - file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); $logger->info("Wrote $staticCount static properties"); if(isset($GLOBALS)){ //This might be null if we're on a different thread @@ -395,7 +396,7 @@ class MemoryManager{ $globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize); } - file_put_contents($outputFolder . "/globalVariables.js", json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); $logger->info("Wrote $globalCount global variables"); } @@ -411,7 +412,7 @@ class MemoryManager{ $functionStaticVarsCount += count($vars); } } - file_put_contents($outputFolder . '/functionStaticVars.js', json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); $logger->info("Wrote $functionStaticVarsCount function static variables"); $data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize); @@ -483,11 +484,11 @@ class MemoryManager{ fclose($obData); - file_put_contents($outputFolder . "/serverEntry.js", json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); - file_put_contents($outputFolder . "/referenceCounts.js", json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); arsort($instanceCounts, SORT_NUMERIC); - file_put_contents($outputFolder . "/instanceCounts.js", json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); $logger->info("Finished!"); diff --git a/src/PocketMine.php b/src/PocketMine.php index b154a8f12..0fce540ef 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -33,6 +33,7 @@ namespace pocketmine { use pocketmine\utils\Terminal; use pocketmine\utils\Timezone; use pocketmine\wizard\SetupWizard; + use Webmozart\PathUtil\Path; use function extension_loaded; use function phpversion; use function preg_match; @@ -234,7 +235,7 @@ namespace pocketmine { mkdir($dataPath, 0777, true); } - $lockFilePath = $dataPath . '/server.lock'; + $lockFilePath = Path::join($dataPath, 'server.lock'); if(($pid = Filesystem::createLockFile($lockFilePath)) !== null){ critical_error("Another " . VersionInfo::NAME . " instance (PID $pid) is already using this folder (" . realpath($dataPath) . ")."); critical_error("Please stop the other server first before running a new one."); @@ -252,14 +253,14 @@ namespace pocketmine { Terminal::init(); } - $logger = new MainLogger($dataPath . "server.log", Terminal::hasFormattingCodes(), "Server", new \DateTimeZone(Timezone::get())); + $logger = new MainLogger(Path::join($dataPath, "server.log"), Terminal::hasFormattingCodes(), "Server", new \DateTimeZone(Timezone::get())); \GlobalLogger::set($logger); emit_performance_warnings($logger); $exitCode = 0; do{ - if(!file_exists($dataPath . "server.properties") and !isset($opts["no-wizard"])){ + if(!file_exists(Path::join($dataPath, "server.properties")) and !isset($opts["no-wizard"])){ $installer = new SetupWizard($dataPath); if(!$installer->run()){ $exitCode = -1; diff --git a/src/Server.php b/src/Server.php index aef04a98e..5b355f8b4 100644 --- a/src/Server.php +++ b/src/Server.php @@ -105,6 +105,7 @@ use pocketmine\world\World; use pocketmine\world\WorldCreationOptions; use pocketmine\world\WorldManager; use Ramsey\Uuid\UuidInterface; +use Webmozart\PathUtil\Path; use function array_shift; use function array_sum; use function base64_encode; @@ -515,7 +516,7 @@ class Server{ } private function getPlayerDataPath(string $username) : string{ - return $this->getDataPath() . '/players/' . strtolower($username) . '.dat'; + return Path::join($this->getDataPath(), 'players', strtolower($username) . '.dat'); } /** @@ -811,33 +812,33 @@ class Server{ $this->logger = $logger; try{ - 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); + foreach([ + $dataPath, + $pluginPath, + Path::join($dataPath, "worlds"), + Path::join($dataPath, "players") + ] as $neededPath){ + if(!file_exists($neededPath)){ + mkdir($neededPath, 0777); + } } $this->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR; $this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR; $this->logger->info("Loading server configuration"); - if(!file_exists($this->dataPath . "pocketmine.yml")){ - $content = file_get_contents(\pocketmine\RESOURCE_PATH . "pocketmine.yml"); + $pocketmineYmlPath = Path::join($this->dataPath, "pocketmine.yml"); + if(!file_exists($pocketmineYmlPath)){ + $content = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "pocketmine.yml")); if(VersionInfo::IS_DEVELOPMENT_BUILD){ $content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content); } - @file_put_contents($this->dataPath . "pocketmine.yml", $content); + @file_put_contents($pocketmineYmlPath, $content); } $this->configGroup = new ServerConfigGroup( - new Config($this->dataPath . "pocketmine.yml", Config::YAML, []), - new Config($this->dataPath . "server.properties", Config::PROPERTIES, [ + new Config($pocketmineYmlPath, Config::YAML, []), + new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES, [ "motd" => VersionInfo::NAME . " Server", "server-port" => 19132, "white-list" => false, @@ -934,16 +935,20 @@ class Server{ $this->doTitleTick = $this->configGroup->getPropertyBool("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); - 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"); + $this->operators = new Config(Path::join($this->dataPath, "ops.txt"), Config::ENUM); + $this->whitelist = new Config(Path::join($this->dataPath, "white-list.txt"), Config::ENUM); + + $bannedTxt = Path::join($this->dataPath, "banned.txt"); + $bannedPlayersTxt = Path::join($this->dataPath, "banned-players.txt"); + if(file_exists($bannedTxt) and !file_exists($bannedPlayersTxt)){ + @rename($bannedTxt, $bannedPlayersTxt); } - @touch($this->dataPath . "banned-players.txt"); - $this->banByName = new BanList($this->dataPath . "banned-players.txt"); + @touch($bannedPlayersTxt); + $this->banByName = new BanList($bannedPlayersTxt); $this->banByName->load(); - @touch($this->dataPath . "banned-ips.txt"); - $this->banByIP = new BanList($this->dataPath . "banned-ips.txt"); + $bannedIpsTxt = Path::join($this->dataPath, "banned-ips.txt"); + @touch($bannedIpsTxt); + $this->banByIP = new BanList($bannedIpsTxt); $this->banByIP->load(); $this->maxPlayers = $this->configGroup->getConfigInt("max-players", 20); @@ -985,14 +990,14 @@ class Server{ $this->commandMap = new SimpleCommandMap($this); - $this->craftingManager = CraftingManagerFromDataHelper::make(\pocketmine\RESOURCE_PATH . '/vanilla/recipes.json'); + $this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "recipes.json")); - $this->resourceManager = new ResourcePackManager($this->getDataPath() . "resource_packs" . DIRECTORY_SEPARATOR, $this->logger); + $this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger); $pluginGraylist = null; - $graylistFile = $this->dataPath . "plugin_list.yml"; + $graylistFile = Path::join($this->dataPath, "plugin_list.yml"); if(!file_exists($graylistFile)){ - copy(\pocketmine\RESOURCE_PATH . 'plugin_list.yml', $graylistFile); + copy(Path::join(\pocketmine\RESOURCE_PATH, 'plugin_list.yml'), $graylistFile); } try{ $pluginGraylist = PluginGraylist::fromArray(yaml_parse(file_get_contents($graylistFile))); @@ -1001,7 +1006,7 @@ class Server{ $this->forceShutdown(); return; } - $this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool("plugins.legacy-data-dir", true) ? null : $this->getDataPath() . "plugin_data" . DIRECTORY_SEPARATOR, $pluginGraylist); + $this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool("plugins.legacy-data-dir", true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist); $this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader)); $this->pluginManager->registerInterface(new ScriptPluginLoader()); @@ -1015,7 +1020,7 @@ class Server{ $this->logger->warning($this->language->translateString("pocketmine.level.badDefaultFormat", [$formatName])); } - $this->worldManager = new WorldManager($this, $this->dataPath . "/worlds", $providerManager); + $this->worldManager = new WorldManager($this, Path::join($this->dataPath, "worlds"), $providerManager); $this->worldManager->setAutoSave($this->configGroup->getConfigBool("auto-save", $this->worldManager->getAutoSave())); $this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt("ticks-per.autosave", 6000)); @@ -1504,7 +1509,7 @@ class Server{ if($this->configGroup->getPropertyBool("auto-report.enabled", true)){ $report = true; - $stamp = $this->getDataPath() . "crashdumps/.last_crash"; + $stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash"); $crashInterval = 120; //2 minutes if(file_exists($stamp) and !($report = (filemtime($stamp) + $crashInterval < time()))){ $this->logger->debug("Not sending crashdump due to last crash less than $crashInterval seconds ago"); diff --git a/src/command/defaults/DumpMemoryCommand.php b/src/command/defaults/DumpMemoryCommand.php index 34c1da9e6..0f5710304 100644 --- a/src/command/defaults/DumpMemoryCommand.php +++ b/src/command/defaults/DumpMemoryCommand.php @@ -25,6 +25,7 @@ namespace pocketmine\command\defaults; use pocketmine\command\CommandSender; use pocketmine\permission\DefaultPermissionNames; +use Webmozart\PathUtil\Path; use function date; class DumpMemoryCommand extends VanillaCommand{ @@ -43,7 +44,7 @@ class DumpMemoryCommand extends VanillaCommand{ return true; } - $sender->getServer()->getMemoryManager()->dumpServerMemory($args[0] ?? ($sender->getServer()->getDataPath() . "/memory_dumps/" . date("D_M_j-H.i.s-T_Y")), 48, 80); + $sender->getServer()->getMemoryManager()->dumpServerMemory($args[0] ?? (Path::join($sender->getServer()->getDataPath(), "memory_dumps" . date("D_M_j-H.i.s-T_Y"))), 48, 80); return true; } } diff --git a/src/command/defaults/TimingsCommand.php b/src/command/defaults/TimingsCommand.php index e4dbc72a0..21018d50a 100644 --- a/src/command/defaults/TimingsCommand.php +++ b/src/command/defaults/TimingsCommand.php @@ -34,6 +34,7 @@ use pocketmine\scheduler\BulkCurlTaskOperation; use pocketmine\timings\TimingsHandler; use pocketmine\utils\InternetException; use pocketmine\utils\InternetRequestResult; +use Webmozart\PathUtil\Path; use function count; use function fclose; use function file_exists; @@ -107,14 +108,14 @@ class TimingsCommand extends VanillaCommand{ $fileTimings = fopen("php://temp", "r+b"); }else{ $index = 0; - $timingFolder = $sender->getServer()->getDataPath() . "timings/"; + $timingFolder = Path::join($sender->getServer()->getDataPath(), "timings"); if(!file_exists($timingFolder)){ mkdir($timingFolder, 0777); } - $timings = $timingFolder . "timings.txt"; + $timings = Path::join($timingFolder, "timings.txt"); while(file_exists($timings)){ - $timings = $timingFolder . "timings" . (++$index) . ".txt"; + $timings = Path::join($timingFolder, "timings" . (++$index) . ".txt"); } $fileTimings = fopen($timings, "a+b"); diff --git a/src/data/bedrock/LegacyBlockIdToStringIdMap.php b/src/data/bedrock/LegacyBlockIdToStringIdMap.php index e46fefb9d..c9e0212b0 100644 --- a/src/data/bedrock/LegacyBlockIdToStringIdMap.php +++ b/src/data/bedrock/LegacyBlockIdToStringIdMap.php @@ -24,11 +24,12 @@ declare(strict_types=1); namespace pocketmine\data\bedrock; use pocketmine\utils\SingletonTrait; +use Webmozart\PathUtil\Path; final class LegacyBlockIdToStringIdMap extends LegacyToStringBidirectionalIdMap{ use SingletonTrait; public function __construct(){ - parent::__construct(\pocketmine\RESOURCE_PATH . 'vanilla/block_id_map.json'); + parent::__construct(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'block_id_map.json')); } } diff --git a/src/data/bedrock/LegacyEntityIdToStringIdMap.php b/src/data/bedrock/LegacyEntityIdToStringIdMap.php index b12cc8bce..fa37bfbd9 100644 --- a/src/data/bedrock/LegacyEntityIdToStringIdMap.php +++ b/src/data/bedrock/LegacyEntityIdToStringIdMap.php @@ -24,11 +24,12 @@ declare(strict_types=1); namespace pocketmine\data\bedrock; use pocketmine\utils\SingletonTrait; +use Webmozart\PathUtil\Path; final class LegacyEntityIdToStringIdMap extends LegacyToStringBidirectionalIdMap{ use SingletonTrait; public function __construct(){ - parent::__construct(\pocketmine\RESOURCE_PATH . '/vanilla/entity_id_map.json'); + parent::__construct(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'entity_id_map.json')); } } diff --git a/src/data/bedrock/LegacyItemIdToStringIdMap.php b/src/data/bedrock/LegacyItemIdToStringIdMap.php index 93219a549..083f2024b 100644 --- a/src/data/bedrock/LegacyItemIdToStringIdMap.php +++ b/src/data/bedrock/LegacyItemIdToStringIdMap.php @@ -24,11 +24,12 @@ declare(strict_types=1); namespace pocketmine\data\bedrock; use pocketmine\utils\SingletonTrait; +use Webmozart\PathUtil\Path; final class LegacyItemIdToStringIdMap extends LegacyToStringBidirectionalIdMap{ use SingletonTrait; public function __construct(){ - parent::__construct(\pocketmine\RESOURCE_PATH . 'vanilla/item_id_map.json'); + parent::__construct(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'item_id_map.json')); } } diff --git a/src/inventory/CreativeInventory.php b/src/inventory/CreativeInventory.php index a2666d1be..99ad5f60e 100644 --- a/src/inventory/CreativeInventory.php +++ b/src/inventory/CreativeInventory.php @@ -26,9 +26,9 @@ namespace pocketmine\inventory; use pocketmine\item\Durable; use pocketmine\item\Item; use pocketmine\utils\SingletonTrait; +use Webmozart\PathUtil\Path; use function file_get_contents; use function json_decode; -use const DIRECTORY_SEPARATOR; final class CreativeInventory{ use SingletonTrait; @@ -37,7 +37,7 @@ final class CreativeInventory{ private $creative = []; private function __construct(){ - $creativeItems = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla" . DIRECTORY_SEPARATOR . "creativeitems.json"), true); + $creativeItems = json_decode(file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "creativeitems.json")), true); foreach($creativeItems as $data){ $item = Item::jsonDeserialize($data); diff --git a/src/item/LegacyStringToItemParser.php b/src/item/LegacyStringToItemParser.php index 6eaa62ff9..ca7559e64 100644 --- a/src/item/LegacyStringToItemParser.php +++ b/src/item/LegacyStringToItemParser.php @@ -25,6 +25,7 @@ namespace pocketmine\item; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; +use Webmozart\PathUtil\Path; use function explode; use function file_get_contents; use function is_array; @@ -51,7 +52,7 @@ final class LegacyStringToItemParser{ private static function make() : self{ $result = new self(ItemFactory::getInstance()); - $mappingsRaw = @file_get_contents(\pocketmine\RESOURCE_PATH . '/item_from_string_bc_map.json'); + $mappingsRaw = @file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, 'item_from_string_bc_map.json')); if($mappingsRaw === false) throw new AssumptionFailedError("Missing required resource file"); $mappings = json_decode($mappingsRaw, true); diff --git a/src/lang/Language.php b/src/lang/Language.php index efac90e00..29cb311a7 100644 --- a/src/lang/Language.php +++ b/src/lang/Language.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\lang; +use Webmozart\PathUtil\Path; use function array_filter; use function array_map; use function explode; @@ -51,7 +52,7 @@ class Language{ */ public static function getLanguageList(string $path = "") : array{ if($path === ""){ - $path = \pocketmine\RESOURCE_PATH . "locale/"; + $path = Path::join(\pocketmine\RESOURCE_PATH, "locale"); } if(is_dir($path)){ @@ -100,7 +101,7 @@ class Language{ $this->langName = strtolower($lang); if($path === null){ - $path = \pocketmine\RESOURCE_PATH . "locale/"; + $path = Path::join(\pocketmine\RESOURCE_PATH, "locale"); } $this->lang = self::loadLang($path, $this->langName); @@ -120,7 +121,7 @@ class Language{ * @phpstan-return array */ protected static function loadLang(string $path, string $languageCode) : array{ - $file = $path . $languageCode . ".ini"; + $file = Path::join($path, $languageCode . ".ini"); if(file_exists($file)){ return array_map('\stripcslashes', parse_ini_file($file, false, INI_SCANNER_RAW)); } diff --git a/src/network/mcpe/cache/StaticPacketCache.php b/src/network/mcpe/cache/StaticPacketCache.php index 51bc879e0..901fe875c 100644 --- a/src/network/mcpe/cache/StaticPacketCache.php +++ b/src/network/mcpe/cache/StaticPacketCache.php @@ -28,6 +28,7 @@ use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket; use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer; use pocketmine\network\mcpe\protocol\types\CacheableNbt; use pocketmine\utils\SingletonTrait; +use Webmozart\PathUtil\Path; use function file_get_contents; class StaticPacketCache{ @@ -49,8 +50,8 @@ class StaticPacketCache{ private static function make() : self{ return new self( - BiomeDefinitionListPacket::create(self::loadCompoundFromFile(\pocketmine\RESOURCE_PATH . '/vanilla/biome_definitions.nbt')), - AvailableActorIdentifiersPacket::create(self::loadCompoundFromFile(\pocketmine\RESOURCE_PATH . '/vanilla/entity_identifiers.nbt')) + BiomeDefinitionListPacket::create(self::loadCompoundFromFile(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'biome_definitions.nbt'))), + AvailableActorIdentifiersPacket::create(self::loadCompoundFromFile(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'entity_identifiers.nbt'))) ); } diff --git a/src/network/mcpe/convert/GlobalItemTypeDictionary.php b/src/network/mcpe/convert/GlobalItemTypeDictionary.php index 349ddc3bb..c1537fa7c 100644 --- a/src/network/mcpe/convert/GlobalItemTypeDictionary.php +++ b/src/network/mcpe/convert/GlobalItemTypeDictionary.php @@ -27,6 +27,7 @@ use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary; use pocketmine\network\mcpe\protocol\types\ItemTypeEntry; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; +use Webmozart\PathUtil\Path; use function file_get_contents; use function is_array; use function is_bool; @@ -38,7 +39,7 @@ final class GlobalItemTypeDictionary{ use SingletonTrait; private static function make() : self{ - $data = file_get_contents(\pocketmine\RESOURCE_PATH . '/vanilla/required_item_list.json'); + $data = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'required_item_list.json')); if($data === false) throw new AssumptionFailedError("Missing required resource file"); $table = json_decode($data, true); if(!is_array($table)){ diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index 30a53ebd1..d1a7c3a58 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\convert; use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; +use Webmozart\PathUtil\Path; use function array_key_exists; use function file_get_contents; use function is_array; @@ -64,14 +65,14 @@ final class ItemTranslator{ private $complexNetToCoreMapping = []; private static function make() : self{ - $data = file_get_contents(\pocketmine\RESOURCE_PATH . '/vanilla/r16_to_current_item_map.json'); + $data = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'r16_to_current_item_map.json')); if($data === false) throw new AssumptionFailedError("Missing required resource file"); $json = json_decode($data, true); if(!is_array($json) or !isset($json["simple"], $json["complex"]) || !is_array($json["simple"]) || !is_array($json["complex"])){ throw new AssumptionFailedError("Invalid item table format"); } - $legacyStringToIntMapRaw = file_get_contents(\pocketmine\RESOURCE_PATH . '/vanilla/item_id_map.json'); + $legacyStringToIntMapRaw = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'item_id_map.json')); if($legacyStringToIntMapRaw === false){ throw new AssumptionFailedError("Missing required resource file"); } diff --git a/src/network/mcpe/convert/RuntimeBlockMapping.php b/src/network/mcpe/convert/RuntimeBlockMapping.php index 91359f451..95dbcb8fb 100644 --- a/src/network/mcpe/convert/RuntimeBlockMapping.php +++ b/src/network/mcpe/convert/RuntimeBlockMapping.php @@ -31,6 +31,7 @@ use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; +use Webmozart\PathUtil\Path; use function file_get_contents; /** @@ -47,7 +48,7 @@ final class RuntimeBlockMapping{ private $bedrockKnownStates; private function __construct(){ - $canonicalBlockStatesFile = file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/canonical_block_states.nbt"); + $canonicalBlockStatesFile = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "canonical_block_states.nbt")); if($canonicalBlockStatesFile === false){ throw new AssumptionFailedError("Missing required resource file"); } @@ -65,7 +66,7 @@ final class RuntimeBlockMapping{ $legacyIdMap = LegacyBlockIdToStringIdMap::getInstance(); /** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */ $legacyStateMap = []; - $legacyStateMapReader = new PacketSerializer(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.bin")); + $legacyStateMapReader = new PacketSerializer(file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "r12_to_current_block_map.bin"))); $nbtReader = new NetworkNbtSerializer(); while(!$legacyStateMapReader->feof()){ $id = $legacyStateMapReader->getString(); diff --git a/src/plugin/PluginBase.php b/src/plugin/PluginBase.php index 02d232534..eae2aeec3 100644 --- a/src/plugin/PluginBase.php +++ b/src/plugin/PluginBase.php @@ -31,6 +31,7 @@ use pocketmine\scheduler\TaskScheduler; use pocketmine\Server; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Config; +use Webmozart\PathUtil\Path; use function count; use function dirname; use function fclose; @@ -86,7 +87,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{ $this->dataFolder = rtrim($dataFolder, "/" . DIRECTORY_SEPARATOR) . "/"; //TODO: this is accessed externally via reflection, not unused $this->file = rtrim($file, "/" . DIRECTORY_SEPARATOR) . "/"; - $this->configFile = $this->dataFolder . "config.yml"; + $this->configFile = Path::join($this->dataFolder, "config.yml"); $prefix = $this->getDescription()->getPrefix(); $this->logger = new PluginLogger($server->getLogger(), $prefix !== "" ? $prefix : $this->getName()); @@ -261,7 +262,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{ return false; } - $out = $this->dataFolder . $filename; + $out = Path::join($this->dataFolder, $filename); if(!file_exists(dirname($out))){ mkdir(dirname($out), 0755, true); } diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 4b7c1b960..f42669b1d 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -39,6 +39,7 @@ use pocketmine\Server; use pocketmine\timings\TimingsHandler; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Utils; +use Webmozart\PathUtil\Path; use function array_intersect; use function array_merge; use function class_exists; @@ -59,7 +60,6 @@ use function shuffle; use function stripos; use function strpos; use function strtolower; -use const DIRECTORY_SEPARATOR; /** * Manages all the plugins @@ -121,9 +121,9 @@ class PluginManager{ private function getDataDirectory(string $pluginPath, string $pluginName) : string{ if($this->pluginDataDirectory !== null){ - return $this->pluginDataDirectory . $pluginName; + return Path::join($this->pluginDataDirectory, $pluginName); } - return dirname($pluginPath) . DIRECTORY_SEPARATOR . $pluginName; + return Path::join(dirname($pluginPath), $pluginName); } /** diff --git a/src/resourcepacks/ResourcePackManager.php b/src/resourcepacks/ResourcePackManager.php index 1b6af4549..08b9a90ae 100644 --- a/src/resourcepacks/ResourcePackManager.php +++ b/src/resourcepacks/ResourcePackManager.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\resourcepacks; use pocketmine\utils\Config; +use Webmozart\PathUtil\Path; use function array_keys; use function copy; use function count; @@ -63,11 +64,12 @@ class ResourcePackManager{ throw new \InvalidArgumentException("Resource packs path $path exists and is not a directory"); } - if(!file_exists($this->path . "resource_packs.yml")){ - copy(\pocketmine\RESOURCE_PATH . "resource_packs.yml", $this->path . "resource_packs.yml"); + $resourcePacksYml = Path::join($this->path, "resource_packs.yml"); + if(!file_exists($resourcePacksYml)){ + copy(Path::join(\pocketmine\RESOURCE_PATH, "resource_packs.yml"), $resourcePacksYml); } - $resourcePacksConfig = new Config($this->path . "resource_packs.yml", Config::YAML, []); + $resourcePacksConfig = new Config($resourcePacksYml, Config::YAML, []); $this->serverForceResources = (bool) $resourcePacksConfig->get("force_resources", false); @@ -84,7 +86,7 @@ class ResourcePackManager{ continue; } try{ - $packPath = $this->path . DIRECTORY_SEPARATOR . $pack; + $packPath = Path::join($this->path, $pack); if(!file_exists($packPath)){ throw new ResourcePackException("File or directory not found"); } @@ -120,7 +122,7 @@ class ResourcePackManager{ * Returns the directory which resource packs are loaded from. */ public function getPath() : string{ - return $this->path; + return $this->path . DIRECTORY_SEPARATOR; } /** diff --git a/src/scheduler/DumpWorkerMemoryTask.php b/src/scheduler/DumpWorkerMemoryTask.php index 213721fae..01ff11463 100644 --- a/src/scheduler/DumpWorkerMemoryTask.php +++ b/src/scheduler/DumpWorkerMemoryTask.php @@ -24,7 +24,7 @@ declare(strict_types=1); namespace pocketmine\scheduler; use pocketmine\MemoryManager; -use const DIRECTORY_SEPARATOR; +use Webmozart\PathUtil\Path; /** * Task used to dump memory from AsyncWorkers @@ -46,7 +46,7 @@ class DumpWorkerMemoryTask extends AsyncTask{ public function onRun() : void{ MemoryManager::dumpMemory( $this->worker, - $this->outputFolder . DIRECTORY_SEPARATOR . "AsyncWorker#" . $this->worker->getAsyncWorkerId(), + Path::join($this->outputFolder, "AsyncWorker#" . $this->worker->getAsyncWorkerId()), $this->maxNesting, $this->maxStringSize, new \PrefixedLogger($this->worker->getLogger(), "Memory Dump") diff --git a/src/utils/Config.php b/src/utils/Config.php index dfd41bda9..0a42deac3 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -23,11 +23,10 @@ declare(strict_types=1); namespace pocketmine\utils; +use Webmozart\PathUtil\Path; use function array_change_key_case; use function array_keys; -use function array_pop; use function array_shift; -use function basename; use function count; use function date; use function explode; @@ -152,8 +151,7 @@ class Config{ $this->type = $type; if($this->type === Config::DETECT){ - $extension = explode(".", basename($this->file)); - $extension = strtolower(trim(array_pop($extension))); + $extension = strtolower(Path::getExtension($this->file)); if(isset(Config::$formats[$extension])){ $this->type = Config::$formats[$extension]; }else{ diff --git a/src/utils/Filesystem.php b/src/utils/Filesystem.php index 531becc78..9a89976e6 100644 --- a/src/utils/Filesystem.php +++ b/src/utils/Filesystem.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\utils; +use Webmozart\PathUtil\Path; use function copy; use function dirname; use function fclose; @@ -79,10 +80,11 @@ final class Filesystem{ if($objects === false) throw new AssumptionFailedError("scandir() shouldn't return false when is_dir() returns true"); foreach($objects as $object){ if($object !== "." and $object !== ".."){ - if(is_dir($dir . "/" . $object)){ - self::recursiveUnlink($dir . "/" . $object); + $fullObject = Path::join($dir, $object); + if(is_dir($fullObject)){ + self::recursiveUnlink($fullObject); }else{ - unlink($dir . "/" . $object); + unlink($fullObject); } } } @@ -128,7 +130,7 @@ final class Filesystem{ if($object === "." || $object === ".."){ continue; } - self::recursiveCopyInternal($origin . "/" . $object, $destination . "/" . $object); + self::recursiveCopyInternal(Path::join($origin, $object), Path::join($destination, $object)); } }else{ $dirName = dirname($destination); diff --git a/src/wizard/SetupWizard.php b/src/wizard/SetupWizard.php index 5491422c6..31d71e551 100644 --- a/src/wizard/SetupWizard.php +++ b/src/wizard/SetupWizard.php @@ -35,6 +35,7 @@ use pocketmine\utils\Config; use pocketmine\utils\Internet; use pocketmine\utils\InternetException; use pocketmine\VersionInfo; +use Webmozart\PathUtil\Path; use function fgets; use function sleep; use function strtolower; @@ -88,7 +89,7 @@ class SetupWizard{ } //this has to happen here to prevent user avoiding agreeing to license - $config = new Config($this->dataPath . "/server.properties", Config::PROPERTIES); + $config = new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES); $config->set("language", $lang); $config->save(); @@ -138,7 +139,7 @@ LICENSE; } private function generateBaseConfig() : void{ - $config = new Config($this->dataPath . "/server.properties", Config::PROPERTIES); + $config = new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES); $config->set("motd", ($name = $this->getInput($this->lang->get("name_your_server"), self::DEFAULT_NAME))); $config->set("server-name", $name); @@ -175,14 +176,14 @@ LICENSE; if($op === ""){ $this->error($this->lang->get("op_warning")); }else{ - $ops = new Config($this->dataPath . "/ops.txt", Config::ENUM); + $ops = new Config(Path::join($this->dataPath, "ops.txt"), Config::ENUM); $ops->set($op, true); $ops->save(); } $this->message($this->lang->get("whitelist_info")); - $config = new Config($this->dataPath . "/server.properties", Config::PROPERTIES); + $config = new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES); if(strtolower($this->getInput($this->lang->get("whitelist_enable"), "n", "y/N")) === "y"){ $this->error($this->lang->get("whitelist_warning")); $config->set("white-list", true); @@ -193,7 +194,7 @@ LICENSE; } private function networkFunctions() : void{ - $config = new Config($this->dataPath . "/server.properties", Config::PROPERTIES); + $config = new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES); $this->error($this->lang->get("query_warning1")); $this->error($this->lang->get("query_warning2")); if(strtolower($this->getInput($this->lang->get("query_disable"), "n", "y/N")) === "y"){ diff --git a/src/world/WorldManager.php b/src/world/WorldManager.php index 9bca16ad2..4fb3df5b2 100644 --- a/src/world/WorldManager.php +++ b/src/world/WorldManager.php @@ -37,6 +37,7 @@ use pocketmine\world\format\io\WorldProvider; use pocketmine\world\format\io\WorldProviderManager; use pocketmine\world\format\io\WritableWorldProvider; use pocketmine\world\generator\GeneratorManager; +use Webmozart\PathUtil\Path; use function array_keys; use function array_shift; use function assert; @@ -49,7 +50,6 @@ use function microtime; use function round; use function sprintf; use function trim; -use const DIRECTORY_SEPARATOR; class WorldManager{ /** @var string */ @@ -228,7 +228,7 @@ class WorldManager{ } $this->server->getLogger()->notice("Upgrading world \"$name\" to new format. This may take a while."); - $converter = new FormatConverter($provider, $this->providerManager->getDefault(), $this->server->getDataPath() . "backups" . DIRECTORY_SEPARATOR . "worlds", $this->server->getLogger()); + $converter = new FormatConverter($provider, $this->providerManager->getDefault(), Path::join($this->server->getDataPath(), "backups", "worlds"), $this->server->getLogger()); $provider = $converter->execute(); $this->server->getLogger()->notice("Upgraded world \"$name\" to new format successfully. Backed up pre-conversion world at " . $converter->getBackupPath()); @@ -300,7 +300,7 @@ class WorldManager{ } private function getWorldPath(string $name) : string{ - return $this->dataPath . "/" . $name . "/"; + return Path::join($this->dataPath, $name) . "/"; //TODO: check if we still need the trailing dirsep (I'm a little scared to remove it) } public function isWorldGenerated(string $name) : bool{ diff --git a/src/world/format/io/FormatConverter.php b/src/world/format/io/FormatConverter.php index 2dfc5b624..053e26c37 100644 --- a/src/world/format/io/FormatConverter.php +++ b/src/world/format/io/FormatConverter.php @@ -27,6 +27,7 @@ use pocketmine\utils\Filesystem; use pocketmine\utils\Utils; use pocketmine\world\generator\GeneratorManager; use pocketmine\world\WorldCreationOptions; +use Webmozart\PathUtil\Path; use function basename; use function crc32; use function file_exists; @@ -71,7 +72,7 @@ class FormatConverter{ } $nextSuffix = ""; do{ - $this->backupPath = $backupPath . DIRECTORY_SEPARATOR . basename($this->oldProvider->getPath()) . $nextSuffix; + $this->backupPath = Path::join($backupPath, basename($this->oldProvider->getPath()) . $nextSuffix); $nextSuffix = "_" . crc32(random_bytes(4)); }while(file_exists($this->backupPath)); } diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index 53df6a190..aaffee8fb 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -47,6 +47,7 @@ use pocketmine\world\format\io\WritableWorldProvider; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\format\SubChunk; use pocketmine\world\WorldCreationOptions; +use Webmozart\PathUtil\Path; use function array_map; use function array_values; use function chr; @@ -62,7 +63,6 @@ use function strlen; use function substr; use function trim; use function unpack; -use const DIRECTORY_SEPARATOR; use const LEVELDB_ZLIB_RAW_COMPRESSION; class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ @@ -110,7 +110,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ * @throws \LevelDBException */ private static function createDB(string $path) : \LevelDB{ - return new \LevelDB($path . "/db", [ + return new \LevelDB(Path::join($path, "db"), [ "compression" => LEVELDB_ZLIB_RAW_COMPRESSION, "block_size" => 64 * 1024 //64KB, big enough for most chunks ]); @@ -129,7 +129,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ } protected function loadLevelData() : WorldData{ - return new BedrockWorldData($this->getPath() . DIRECTORY_SEPARATOR . "level.dat"); + return new BedrockWorldData(Path::join($this->getPath(), "level.dat")); } public function getWorldMinY() : int{ @@ -141,14 +141,15 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ } public static function isValid(string $path) : bool{ - return file_exists($path . "/level.dat") and is_dir($path . "/db/"); + return file_exists(Path::join($path, "level.dat")) and is_dir(Path::join($path, "db")); } public static function generate(string $path, string $name, WorldCreationOptions $options) : void{ self::checkForLevelDBExtension(); - if(!file_exists($path . "/db")){ - mkdir($path . "/db", 0777, true); + $dbPath = Path::join($path, "db"); + if(!file_exists($dbPath)){ + mkdir($dbPath, 0777, true); } BedrockWorldData::generate($path, $name, $options); diff --git a/src/world/format/io/region/RegionWorldProvider.php b/src/world/format/io/region/RegionWorldProvider.php index 212691b28..3765a33eb 100644 --- a/src/world/format/io/region/RegionWorldProvider.php +++ b/src/world/format/io/region/RegionWorldProvider.php @@ -32,6 +32,7 @@ use pocketmine\world\format\io\BaseWorldProvider; use pocketmine\world\format\io\data\JavaWorldData; use pocketmine\world\format\io\exception\CorruptedChunkException; use pocketmine\world\format\io\WorldData; +use Webmozart\PathUtil\Path; use function assert; use function file_exists; use function is_dir; @@ -43,7 +44,6 @@ use function strlen; use function strrpos; use function substr; use function time; -use const DIRECTORY_SEPARATOR; use const SCANDIR_SORT_NONE; abstract class RegionWorldProvider extends BaseWorldProvider{ @@ -59,8 +59,8 @@ abstract class RegionWorldProvider extends BaseWorldProvider{ abstract protected static function getPcWorldFormatVersion() : int; public static function isValid(string $path) : bool{ - if(file_exists($path . "/level.dat") and is_dir($path . "/region/")){ - foreach(scandir($path . "/region/", SCANDIR_SORT_NONE) as $file){ + if(file_exists(Path::join($path, "level.dat")) and is_dir($regionPath = Path::join($path, "region"))){ + foreach(scandir($regionPath, SCANDIR_SORT_NONE) as $file){ $extPos = strrpos($file, "."); if($extPos !== false && substr($file, $extPos + 1) === static::getRegionFileExtension()){ //we don't care if other region types exist, we only care if this format is possible @@ -76,7 +76,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{ protected $regions = []; protected function loadLevelData() : WorldData{ - return new JavaWorldData($this->getPath() . DIRECTORY_SEPARATOR . "level.dat"); + return new JavaWorldData(Path::join($this->getPath(), "level.dat")); } public function doGarbageCollection() : void{ @@ -106,7 +106,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{ * Returns the path to a specific region file based on its X/Z coordinates */ protected function pathToRegion(int $regionX, int $regionZ) : string{ - return $this->path . "/region/r.$regionX.$regionZ." . static::getRegionFileExtension(); + return Path::join($this->path, "region", "r.$regionX.$regionZ." . static::getRegionFileExtension()); } protected function loadRegion(int $regionX, int $regionZ) : RegionLoader{ @@ -205,7 +205,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{ private function createRegionIterator() : \RegexIterator{ return new \RegexIterator( new \FilesystemIterator( - $this->path . '/region/', + Path::join($this->path, 'region'), \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS ), '/\/r\.(-?\d+)\.(-?\d+)\.' . static::getRegionFileExtension() . '$/', diff --git a/src/world/format/io/region/WritableRegionWorldProvider.php b/src/world/format/io/region/WritableRegionWorldProvider.php index 156caa3e6..ed1b9eba7 100644 --- a/src/world/format/io/region/WritableRegionWorldProvider.php +++ b/src/world/format/io/region/WritableRegionWorldProvider.php @@ -27,6 +27,7 @@ use pocketmine\world\format\Chunk; use pocketmine\world\format\io\data\JavaWorldData; use pocketmine\world\format\io\WritableWorldProvider; use pocketmine\world\WorldCreationOptions; +use Webmozart\PathUtil\Path; use function file_exists; use function mkdir; @@ -42,8 +43,9 @@ abstract class WritableRegionWorldProvider extends RegionWorldProvider implement mkdir($path, 0777, true); } - if(!file_exists($path . "/region")){ - mkdir($path . "/region", 0777); + $regionPath = Path::join($path, "region"); + if(!file_exists($regionPath)){ + mkdir($regionPath, 0777); } JavaWorldData::generate($path, $name, $options, static::getPcWorldFormatVersion()); diff --git a/tests/phpunit/world/format/io/region/RegionLoaderTest.php b/tests/phpunit/world/format/io/region/RegionLoaderTest.php index 0de5babc1..7bb72b5d6 100644 --- a/tests/phpunit/world/format/io/region/RegionLoaderTest.php +++ b/tests/phpunit/world/format/io/region/RegionLoaderTest.php @@ -25,6 +25,7 @@ namespace pocketmine\world\format\io\region; use PHPUnit\Framework\TestCase; use pocketmine\world\format\ChunkException; +use Webmozart\PathUtil\Path; use function bin2hex; use function clearstatcache; use function file_exists; @@ -32,7 +33,6 @@ use function random_bytes; use function str_repeat; use function sys_get_temp_dir; use function unlink; -use const DIRECTORY_SEPARATOR; class RegionLoaderTest extends TestCase{ @@ -42,7 +42,7 @@ class RegionLoaderTest extends TestCase{ private $region; public function setUp() : void{ - $this->regionPath = sys_get_temp_dir() . '/test.testregion'; + $this->regionPath = Path::join(sys_get_temp_dir(), 'test.testregion'); if(file_exists($this->regionPath)){ unlink($this->regionPath); } @@ -140,7 +140,7 @@ class RegionLoaderTest extends TestCase{ clearstatcache(); do{ - $randfile = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)) . ".mca"; + $randfile = Path::join(sys_get_temp_dir(), bin2hex(random_bytes(6)) . ".mca"); }while(file_exists($randfile)); $this->expectException(\RuntimeException::class); RegionLoader::loadExisting($randfile);