path = $path; $this->loadLevelData(); $this->fixLevelData(); } abstract protected function loadLevelData() : void; abstract protected function fixLevelData() : void; /** * Hack to fix worlds broken previously by older versions of PocketMine-MP which incorrectly saved classpaths of * generators into level.dat on imported (not generated) worlds. * * This should only have affected leveldb worlds as far as I know, because PC format worlds include the * generatorName tag by default. However, MCPE leveldb ones didn't, and so they would get filled in with something * broken. * * This bug took a long time to get found because previously the generator manager would just return the default * generator silently on failure to identify the correct generator, which caused lots of unexpected bugs. * * Only classnames which were written into the level.dat from "fixing" the level data are included here. These are * hardcoded to avoid problems fixing broken worlds in the future if these classes get moved, renamed or removed. * * @param string $className Classname saved in level.dat * * @return null|string Name of the correct generator to replace the broken value */ protected static function hackyFixForGeneratorClasspathInLevelDat(string $className) : ?string{ //THESE ARE DELIBERATELY HARDCODED, DO NOT CHANGE! switch($className){ case 'pocketmine\level\generator\normal\Normal': return "normal"; case 'pocketmine\level\generator\Flat': return "flat"; } return null; } public function getPath() : string{ return $this->path; } public function getName() : string{ return $this->levelData->getString("LevelName"); } public function getTime() : int{ return $this->levelData->getLong("Time", 0, true); } public function setTime(int $value){ $this->levelData->setLong("Time", $value, true); //some older PM worlds had this in the wrong format } public function getSeed() : int{ return $this->levelData->getLong("RandomSeed"); } public function getSpawn() : Vector3{ return new Vector3($this->levelData->getInt("SpawnX"), $this->levelData->getInt("SpawnY"), $this->levelData->getInt("SpawnZ")); } public function setSpawn(Vector3 $pos){ $this->levelData->setInt("SpawnX", $pos->getFloorX()); $this->levelData->setInt("SpawnY", $pos->getFloorY()); $this->levelData->setInt("SpawnZ", $pos->getFloorZ()); } /** * @return CompoundTag */ public function getLevelData() : CompoundTag{ return $this->levelData; } public function loadChunk(int $chunkX, int $chunkZ) : ?Chunk{ return $this->readChunk($chunkX, $chunkZ); } public function saveChunk(Chunk $chunk) : void{ if(!$chunk->isGenerated()){ throw new \InvalidStateException("Cannot save un-generated chunk"); } $this->writeChunk($chunk); } abstract protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk; abstract protected function writeChunk(Chunk $chunk) : void; }