128        if($world === $this->getDefaultWorld() && !$forceUnload){
 
  129            throw new \InvalidArgumentException(
"The default world cannot be unloaded while running, please switch worlds.");
 
  131        if($world->isDoingTick()){
 
  132            throw new \InvalidArgumentException(
"Cannot unload a world during world tick");
 
  135        $ev = 
new WorldUnloadEvent($world);
 
  138        if(!$forceUnload && $ev->isCancelled()){
 
  142        $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_unloading($world->getDisplayName())));
 
  143        if(count($world->getPlayers()) !== 0){
 
  145                $safeSpawn = $this->defaultWorld !== 
null && $this->defaultWorld !== $world ? $this->defaultWorld->getSafeSpawn() : 
null;
 
  146            }
catch(WorldException $e){
 
  149            foreach($world->getPlayers() as $player){
 
  150                if($safeSpawn === 
null){
 
  151                    $player->disconnect(
"Forced default world unload");
 
  153                    $player->teleport($safeSpawn);
 
  158        if($world === $this->defaultWorld){
 
  159            $this->defaultWorld = 
null;
 
  161        unset($this->worlds[$world->getId()]);
 
 
  174    public function loadWorld(
string $name, 
bool $autoUpgrade = 
false) : bool{
 
  175        if(trim($name) === 
""){
 
  176            throw new \InvalidArgumentException(
"Invalid empty world name");
 
  178        if($this->isWorldLoaded($name)){
 
  180        }elseif(!$this->isWorldGenerated($name)){
 
  184        $path = $this->getWorldPath($name);
 
  186        $providers = $this->providerManager->getMatchingProviders($path);
 
  187        if(count($providers) !== 1){
 
  188            $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError(
 
  190                count($providers) === 0 ?
 
  191                    KnownTranslationFactory::pocketmine_level_unknownFormat() :
 
  192                    KnownTranslationFactory::pocketmine_level_ambiguousFormat(implode(
", ", array_keys($providers)))
 
  196        $providerClass = array_shift($providers);
 
  199            $provider = $providerClass->fromPath($path, 
new \
PrefixedLogger($this->
server->getLogger(), 
"World Provider: $name"));
 
  200        }
catch(CorruptedWorldException $e){
 
  201            $this->
server->getLogger()->error($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError(
 
  203                KnownTranslationFactory::pocketmine_level_corrupted($e->getMessage())
 
  206        }
catch(UnsupportedWorldFormatException $e){
 
  207            $this->
server->getLogger()->error($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError(
 
  209                KnownTranslationFactory::pocketmine_level_unsupportedFormat($e->getMessage())
 
  214        $generatorEntry = GeneratorManager::getInstance()->getGenerator($provider->getWorldData()->getGenerator());
 
  215        if($generatorEntry === 
null){
 
  216            $this->
server->getLogger()->error($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError(
 
  218                KnownTranslationFactory::pocketmine_level_unknownGenerator($provider->getWorldData()->getGenerator())
 
  223            $generatorEntry->validateGeneratorOptions($provider->getWorldData()->getGeneratorOptions());
 
  224        }
catch(InvalidGeneratorOptionsException $e){
 
  225            $this->
server->getLogger()->error($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError(
 
  227                KnownTranslationFactory::pocketmine_level_invalidGeneratorOptions(
 
  228                    $provider->getWorldData()->getGeneratorOptions(),
 
  229                    $provider->getWorldData()->getGenerator(),
 
  235        if(!($provider instanceof WritableWorldProvider)){
 
  237                throw new UnsupportedWorldFormatException(
"World \"$name\" is in an unsupported format and needs to be upgraded");
 
  239            $this->
server->getLogger()->notice($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_conversion_start($name)));
 
  241            $providerClass = $this->providerManager->getDefault();
 
  242            $converter = 
new FormatConverter($provider, $providerClass, Path::join($this->
server->getDataPath(), 
"backups", 
"worlds"), $this->server->getLogger());
 
  243            $converter->execute();
 
  244            $provider = $providerClass->fromPath($path, 
new \
PrefixedLogger($this->
server->getLogger(), 
"World Provider: $name"));
 
  246            $this->
server->getLogger()->notice($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_conversion_finish($name, $converter->getBackupPath())));
 
  249        $world = 
new World($this->server, $name, $provider, $this->
server->getAsyncPool());
 
  251        $this->worlds[$world->getId()] = $world;
 
  252        $world->setAutoSave($this->autoSave);
 
  254        (
new WorldLoadEvent($world))->call();
 
 
  265        if(trim($name) === 
"" || $this->isWorldGenerated($name)){
 
  269        $providerEntry = $this->providerManager->getDefault();
 
  271        $path = $this->getWorldPath($name);
 
  272        $providerEntry->generate($path, $name, $options);
 
  274        $world = 
new World($this->server, $name, $providerEntry->fromPath($path, 
new \
PrefixedLogger($this->
server->getLogger(), 
"World Provider: $name")), $this->server->getAsyncPool());
 
  275        $this->worlds[$world->getId()] = $world;
 
  277        $world->setAutoSave($this->autoSave);
 
  283        if($backgroundGeneration){
 
  284            $this->
server->getLogger()->notice($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_backgroundGeneration($name)));
 
  286            $spawnLocation = $world->getSpawnLocation();
 
  287            $centerX = $spawnLocation->getFloorX() >> Chunk::COORD_BIT_SIZE;
 
  288            $centerZ = $spawnLocation->getFloorZ() >> Chunk::COORD_BIT_SIZE;
 
  290            $selected = iterator_to_array((
new ChunkSelector())->selectChunks(8, $centerX, $centerZ), preserve_keys: 
false);
 
  292            $total = count($selected);
 
  293            foreach($selected as $index){
 
  294                World::getXZ($index, $chunkX, $chunkZ);
 
  295                $world->orderChunkPopulation($chunkX, $chunkZ, 
null)->onCompletion(
 
  296                    static function() use ($world, &$done, $total) : 
void{
 
  297                        $oldProgress = (int) floor(($done / $total) * 100);
 
  298                        $newProgress = (int) floor((++$done / $total) * 100);
 
  299                        if(intdiv($oldProgress, 10) !== intdiv($newProgress, 10) || $done === $total || $done === 1){
 
  300                            $world->getLogger()->info($world->getServer()->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_spawnTerrainGenerationProgress(strval($done), strval($total), strval($newProgress))));
 
  303                    static function() : 
void{