write($levelData); file_put_contents($path . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer); } protected function load() : ?CompoundTag{ $nbt = new LittleEndianNbtSerializer(); $levelData = $nbt->read(substr(file_get_contents($this->dataPath), 8)); $version = $levelData->getInt("StorageVersion", INT32_MAX, true); if($version > self::CURRENT_STORAGE_VERSION){ throw new UnsupportedLevelFormatException("Specified LevelDB world format version ($version) is not supported by " . \pocketmine\NAME); } return $levelData; } protected function fix() : void{ if(!$this->compoundTag->hasTag("generatorName", StringTag::class)){ if($this->compoundTag->hasTag("Generator", IntTag::class)){ switch($this->compoundTag->getInt("Generator")){ //Detect correct generator from MCPE data case self::GENERATOR_FLAT: $this->compoundTag->setString("generatorName", "flat"); $this->compoundTag->setString("generatorOptions", "2;7,3,3,2;1"); break; case self::GENERATOR_INFINITE: //TODO: add a null generator which does not generate missing chunks (to allow importing back to MCPE and generating more normal terrain without PocketMine messing things up) $this->compoundTag->setString("generatorName", "default"); $this->compoundTag->setString("generatorOptions", ""); break; case self::GENERATOR_LIMITED: throw new UnsupportedLevelFormatException("Limited worlds are not currently supported"); default: throw new UnsupportedLevelFormatException("Unknown LevelDB world format type, this world cannot be loaded"); } }else{ $this->compoundTag->setString("generatorName", "default"); } }elseif(($generatorName = self::hackyFixForGeneratorClasspathInLevelDat($this->compoundTag->getString("generatorName"))) !== null){ $this->compoundTag->setString("generatorName", $generatorName); } if(!$this->compoundTag->hasTag("generatorOptions", StringTag::class)){ $this->compoundTag->setString("generatorOptions", ""); } } public function save() : void{ $this->compoundTag->setInt("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL); $this->compoundTag->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION); $nbt = new LittleEndianNbtSerializer(); $buffer = $nbt->write($this->compoundTag); file_put_contents($this->dataPath, Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer); } public function getDifficulty() : int{ return $this->compoundTag->getInt("Difficulty", Level::DIFFICULTY_NORMAL); } public function setDifficulty(int $difficulty) : void{ $this->compoundTag->setInt("Difficulty", $difficulty); //yes, this is intended! (in PE: int, PC: byte) } public function getRainTime() : int{ return $this->compoundTag->getInt("rainTime", 0); } public function setRainTime(int $ticks) : void{ $this->compoundTag->setInt("rainTime", $ticks); } public function getRainLevel() : float{ return $this->compoundTag->getFloat("rainLevel", 0.0); } public function setRainLevel(float $level) : void{ $this->compoundTag->setFloat("rainLevel", $level); } public function getLightningTime() : int{ return $this->compoundTag->getInt("lightningTime", 0); } public function setLightningTime(int $ticks) : void{ $this->compoundTag->setInt("lightningTime", $ticks); } public function getLightningLevel() : float{ return $this->compoundTag->getFloat("lightningLevel", 0.0); } public function setLightningLevel(float $level) : void{ $this->compoundTag->setFloat("lightningLevel", $level); } }