46    private string $backupPath;
 
   47    private \Logger $logger;
 
   49    public function __construct(
 
   54        private int $chunksPerProgressUpdate = 256
 
   56        $this->logger = new \PrefixedLogger($logger, 
"World Converter: " . $this->oldProvider->getWorldData()->getName());
 
   58        if(!file_exists($backupPath)){
 
   59            @mkdir($backupPath, 0777, 
true);
 
   63            $this->backupPath = Path::join($backupPath, basename($this->oldProvider->getPath()) . $nextSuffix);
 
   64            $nextSuffix = 
"_" . crc32(random_bytes(4));
 
   65        }
while(file_exists($this->backupPath));
 
   68    public function getBackupPath() : 
string{
 
   69        return $this->backupPath;
 
   72    public function execute() : 
void{
 
   73        $new = $this->generateNew();
 
   75        $this->populateLevelData($new->getWorldData());
 
   76        $this->convertTerrain($new);
 
   78        $path = $this->oldProvider->getPath();
 
   79        $this->oldProvider->close();
 
   82        $this->logger->info(
"Backing up pre-conversion world to " . $this->backupPath);
 
   83        if(!@rename($path, $this->backupPath)){
 
   84            $this->logger->warning(
"Moving old world files for backup failed, attempting copy instead. This might take a long time.");
 
   85            Filesystem::recursiveCopy($path, $this->backupPath);
 
   86            Filesystem::recursiveUnlink($path);
 
   88        if(!@rename($new->getPath(), $path)){
 
   90            $this->logger->debug(
"Relocation of new world files to location failed, attempting copy and delete instead");
 
   91            Filesystem::recursiveCopy($new->getPath(), $path);
 
   92            Filesystem::recursiveUnlink($new->getPath());
 
   95        $this->logger->info(
"Conversion completed");
 
   99        $this->logger->info(
"Generating new world");
 
  100        $data = $this->oldProvider->getWorldData();
 
  102        $convertedOutput = rtrim($this->oldProvider->getPath(), 
"/" . DIRECTORY_SEPARATOR) . 
"_converted" . DIRECTORY_SEPARATOR;
 
  103        if(file_exists($convertedOutput)){
 
  104            $this->logger->info(
"Found previous conversion attempt, deleting...");
 
  105            Filesystem::recursiveUnlink($convertedOutput);
 
  107        $this->newProvider->generate($convertedOutput, $data->getName(), WorldCreationOptions::create()
 
  110            ->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($data->getGenerator())?->getGeneratorClass() ?? Normal::class)
 
  111            ->setGeneratorOptions($data->getGeneratorOptions())
 
  112            ->setSeed($data->getSeed())
 
  113            ->setSpawnPosition($data->getSpawn())
 
  114            ->setDifficulty($data->getDifficulty())
 
  117        return $this->newProvider->fromPath($convertedOutput, $this->logger);
 
  120    private function populateLevelData(
WorldData $data) : 
void{
 
  121        $this->logger->info(
"Converting world manifest");
 
  122        $oldData = $this->oldProvider->getWorldData();
 
  128        $data->setSpawn($oldData->getSpawn());
 
  129        $data->setTime($oldData->getTime());
 
  132        $this->logger->info(
"Finished converting manifest");
 
  137        $this->logger->info(
"Calculating chunk count");
 
  138        $count = $this->oldProvider->calculateChunkCount();
 
  139        $this->logger->info(
"Discovered $count chunks");
 
  143        $start = microtime(
true);
 
  145        foreach($this->oldProvider->getAllChunks(
true, $this->logger) as $coords => $loadedChunkData){
 
  146            [$chunkX, $chunkZ] = $coords;
 
  147            $new->
saveChunk($chunkX, $chunkZ, $loadedChunkData->getData(), Chunk::DIRTY_FLAGS_ALL);
 
  149            if(($counter % $this->chunksPerProgressUpdate) === 0){
 
  150                $time = microtime(
true);
 
  151                $diff = $time - $thisRound;
 
  153                $this->logger->info(
"Converted $counter / $count chunks (" . floor($this->chunksPerProgressUpdate / $diff) . 
" chunks/sec)");
 
  156            if(($counter % (2 ** 16)) === 0){
 
  160        $total = microtime(
true) - $start;
 
  161        $this->logger->info(
"Converted $counter / $counter chunks in " . round($total, 3) . 
" seconds (" . floor($counter / $total) . 
" chunks/sec)");