oldProvider = $oldProvider; Utils::testValidInstance($newProvider, WritableLevelProvider::class); $this->newProvider = $newProvider; $this->logger = new \PrefixedLogger($logger, "World Converter - " . $this->oldProvider->getLevelData()->getName()); if(!file_exists($backupPath)){ @mkdir($backupPath, 0777, true); } $nextSuffix = ""; do{ $this->backupPath = $backupPath . DIRECTORY_SEPARATOR . basename($this->oldProvider->getPath()) . $nextSuffix; $nextSuffix = "_" . crc32(random_bytes(4)); }while(file_exists($this->backupPath)); } public function getBackupPath() : string{ return $this->backupPath; } public function execute() : WritableLevelProvider{ $new = $this->generateNew(); $this->populateLevelData($new->getLevelData()); $this->convertTerrain($new); $path = $this->oldProvider->getPath(); $this->oldProvider->close(); $new->close(); $this->logger->info("Backing up pre-conversion world to " . $this->backupPath); rename($path, $this->backupPath); rename($new->getPath(), $path); $this->logger->info("Conversion completed"); /** * @see WritableLevelProvider::__construct() */ return new $this->newProvider($path); } private function generateNew() : WritableLevelProvider{ $this->logger->info("Generating new world"); $data = $this->oldProvider->getLevelData(); $convertedOutput = rtrim($this->oldProvider->getPath(), "/\\") . "_converted" . DIRECTORY_SEPARATOR; if(file_exists($convertedOutput)){ $this->logger->info("Found previous conversion attempt, deleting..."); Utils::recursiveUnlink($convertedOutput); } $this->newProvider::generate($convertedOutput, $data->getName(), $data->getSeed(), GeneratorManager::getGenerator($data->getGenerator()), $data->getGeneratorOptions()); /** * @see WritableLevelProvider::__construct() */ return new $this->newProvider($convertedOutput); } private function populateLevelData(LevelData $data) : void{ $this->logger->info("Converting world manifest"); $oldData = $this->oldProvider->getLevelData(); $data->setDifficulty($oldData->getDifficulty()); $data->setLightningLevel($oldData->getLightningLevel()); $data->setLightningTime($oldData->getLightningTime()); $data->setRainLevel($oldData->getRainLevel()); $data->setRainTime($oldData->getRainTime()); $data->setSpawn($oldData->getSpawn()); $data->setTime($oldData->getTime()); $this->logger->info("Finished converting manifest"); //TODO: add more properties as-needed } private function convertTerrain(WritableLevelProvider $new) : void{ $this->logger->info("Calculating chunk count"); $count = $this->oldProvider->calculateChunkCount(); $this->logger->info("Discovered $count chunks"); $counter = 0; $start = microtime(true); $thisRound = $start; static $reportInterval = 256; foreach($this->oldProvider->getAllChunks(true, $this->logger) as $chunk){ $new->saveChunk($chunk); $counter++; if(($counter % $reportInterval) === 0){ $time = microtime(true); $diff = $time - $thisRound; $thisRound = $time; $this->logger->info("Converted $counter / $count chunks (" . floor($reportInterval / $diff) . " chunks/sec)"); } } $total = microtime(true) - $start; $this->logger->info("Converted $counter / $counter chunks in " . round($total, 3) . " seconds (" . floor($counter / $total) . " chunks/sec)"); } }