Fixed remaining cases of undefined behaviour on ambiguous world format

It was still possible to produce undefined behaviour by creating a db folder in a region-based world, or adding regions to a leveldb world. This now solves the problem completely by refusing to load the world if multiple formats match the world.
This commit is contained in:
Dylan K. Taylor 2018-10-04 19:43:31 +01:00
parent 0cc4bc48cc
commit a273a0c8a9
4 changed files with 23 additions and 26 deletions

View File

@ -1035,13 +1035,17 @@ class Server{
$path = $this->getDataPath() . "worlds/" . $name . "/";
$providerClass = LevelProviderManager::getProvider($path);
if($providerClass === null){
$this->logger->error($this->getLanguage()->translateString("pocketmine.level.loadError", [$name, "Cannot identify format of world"]));
$providers = LevelProviderManager::getMatchingProviders($path);
if(count($providers) !== 1){
$this->logger->error($this->language->translateString("pocketmine.level.loadError", [
$name,
empty($providers) ?
$this->language->translateString("pocketmine.level.unknownFormat") :
$this->language->translateString("pocketmine.level.ambiguousFormat", [implode(", ", array_keys($providers))])
]));
return false;
}
$providerClass = array_shift($providers);
/** @see LevelProvider::__construct() */
$level = new Level($this, $name, new $providerClass($path));

@ -1 +1 @@
Subproject commit 7f12f293bfad76e5c07b929c893e848728064977
Subproject commit e738dc7ca0171a1a16e3682fc2a7619c059988b9

View File

@ -87,17 +87,17 @@ abstract class LevelProviderManager{
*
* @param string $path
*
* @return string|null
* @return string[]|LevelProvider[]
*/
public static function getProvider(string $path){
foreach(self::$providers as $provider){
/** @var $provider LevelProvider */
public static function getMatchingProviders(string $path) : array{
$result = [];
foreach(self::$providers as $alias => $provider){
/** @var LevelProvider|string $provider */
if($provider::isValid($path)){
return $provider;
$result[$alias] = $provider;
}
}
return null;
return $result;
}
/**

View File

@ -45,23 +45,16 @@ abstract class RegionLevelProvider extends BaseLevelProvider{
abstract protected static function getPcWorldFormatVersion() : int;
public static function isValid(string $path) : bool{
$isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/"));
if($isValid){
$files = array_filter(scandir($path . "/region/", SCANDIR_SORT_NONE), function($file){
return substr($file, strrpos($file, ".") + 1, 2) === "mc"; //region file
});
$ext = static::getRegionFileExtension();
foreach($files as $f){
if(substr($f, strrpos($f, ".") + 1) !== $ext){
$isValid = false;
break;
if(file_exists($path . "/level.dat") and is_dir($path . "/region/")){
foreach(scandir($path . "/region/", SCANDIR_SORT_NONE) as $file){
if(substr($file, strrpos($file, ".") + 1) === static::getRegionFileExtension()){
//we don't care if other region types exist, we only care if this format is possible
return true;
}
}
}
return $isValid;
return false;
}
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []){