54    public const CURRENT_STORAGE_VERSION = WorldDataVersions::STORAGE;
 
   55    public const CURRENT_STORAGE_NETWORK_VERSION = WorldDataVersions::NETWORK;
 
   56    public const CURRENT_CLIENT_VERSION_TARGET = WorldDataVersions::LAST_OPENED_IN;
 
   58    public const GENERATOR_LIMITED = 0;
 
   59    public const GENERATOR_INFINITE = 1;
 
   60    public const GENERATOR_FLAT = 2;
 
   62    private const TAG_DAY_CYCLE_STOP_TIME = 
"DayCycleStopTime";
 
   63    private const TAG_DIFFICULTY = 
"Difficulty";
 
   64    private const TAG_FORCE_GAME_TYPE = 
"ForceGameType";
 
   65    private const TAG_GAME_TYPE = 
"GameType";
 
   66    private const TAG_GENERATOR = 
"Generator";
 
   67    private const TAG_LAST_PLAYED = 
"LastPlayed";
 
   68    private const TAG_NETWORK_VERSION = 
"NetworkVersion";
 
   69    private const TAG_STORAGE_VERSION = 
"StorageVersion";
 
   70    private const TAG_IS_EDU = 
"eduLevel";
 
   71    private const TAG_FALL_DAMAGE_ENABLED = 
"falldamage";
 
   72    private const TAG_FIRE_DAMAGE_ENABLED = 
"firedamage";
 
   73    private const TAG_ACHIEVEMENTS_DISABLED = 
"hasBeenLoadedInCreative";
 
   74    private const TAG_IMMUTABLE_WORLD = 
"immutableWorld";
 
   75    private const TAG_LIGHTNING_LEVEL = 
"lightningLevel";
 
   76    private const TAG_LIGHTNING_TIME = 
"lightningTime";
 
   77    private const TAG_PVP_ENABLED = 
"pvp";
 
   78    private const TAG_RAIN_LEVEL = 
"rainLevel";
 
   79    private const TAG_RAIN_TIME = 
"rainTime";
 
   80    private const TAG_SPAWN_MOBS = 
"spawnMobs";
 
   81    private const TAG_TEXTURE_PACKS_REQUIRED = 
"texturePacksRequired";
 
   82    private const TAG_LAST_OPENED_WITH_VERSION = 
"lastOpenedWithVersion";
 
   83    private const TAG_COMMANDS_ENABLED = 
"commandsEnabled";
 
   85    public static function generate(
string $path, 
string $name, 
WorldCreationOptions $options) : 
void{
 
   88                $generatorType = self::GENERATOR_FLAT;
 
   91                $generatorType = self::GENERATOR_INFINITE;
 
   95        $worldData = CompoundTag::create()
 
   97            ->setInt(self::TAG_DAY_CYCLE_STOP_TIME, -1)
 
   98            ->setInt(self::TAG_DIFFICULTY, $options->getDifficulty())
 
   99            ->setByte(self::TAG_FORCE_GAME_TYPE, 0)
 
  100            ->setInt(self::TAG_GAME_TYPE, 0)
 
  101            ->setInt(self::TAG_GENERATOR, $generatorType)
 
  102            ->setLong(self::TAG_LAST_PLAYED, time())
 
  103            ->setString(self::TAG_LEVEL_NAME, $name)
 
  104            ->setInt(self::TAG_NETWORK_VERSION, self::CURRENT_STORAGE_NETWORK_VERSION)
 
  106            ->setLong(self::TAG_RANDOM_SEED, $options->getSeed())
 
  107            ->setInt(self::TAG_SPAWN_X, $options->getSpawnPosition()->getFloorX())
 
  108            ->setInt(self::TAG_SPAWN_Y, $options->getSpawnPosition()->getFloorY())
 
  109            ->setInt(self::TAG_SPAWN_Z, $options->getSpawnPosition()->getFloorZ())
 
  110            ->setInt(self::TAG_STORAGE_VERSION, self::CURRENT_STORAGE_VERSION)
 
  111            ->setLong(self::TAG_TIME, 0)
 
  112            ->setByte(self::TAG_IS_EDU, 0)
 
  113            ->setByte(self::TAG_FALL_DAMAGE_ENABLED, 1)
 
  114            ->setByte(self::TAG_FIRE_DAMAGE_ENABLED, 1)
 
  115            ->setByte(self::TAG_ACHIEVEMENTS_DISABLED, 1) 
 
  116            ->setByte(self::TAG_IMMUTABLE_WORLD, 0)
 
  117            ->setFloat(self::TAG_LIGHTNING_LEVEL, 0.0)
 
  118            ->setInt(self::TAG_LIGHTNING_TIME, 0)
 
  119            ->setByte(self::TAG_PVP_ENABLED, 1)
 
  120            ->setFloat(self::TAG_RAIN_LEVEL, 0.0)
 
  121            ->setInt(self::TAG_RAIN_TIME, 0)
 
  122            ->setByte(self::TAG_SPAWN_MOBS, 1)
 
  123            ->setByte(self::TAG_TEXTURE_PACKS_REQUIRED, 0) 
 
  124            ->setByte(self::TAG_COMMANDS_ENABLED, 1)
 
  125            ->setTag(self::TAG_LAST_OPENED_WITH_VERSION, 
new ListTag(array_map(fn(
int $v) => 
new IntTag($v), self::CURRENT_CLIENT_VERSION_TARGET)))
 
  128            ->setString(self::TAG_GENERATOR_NAME, GeneratorManager::getInstance()->getGeneratorName($options->
getGeneratorClass()))
 
  129            ->setString(self::TAG_GENERATOR_OPTIONS, $options->getGeneratorOptions());
 
  132        $buffer = $nbt->write(
new TreeRoot($worldData));
 
  133        file_put_contents(Path::join($path, 
"level.dat"), Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer);
 
  138            $rawLevelData = 
Filesystem::fileGetContents($this->dataPath);
 
  139        }
catch(\RuntimeException $e){
 
  142        if(strlen($rawLevelData) <= 8){
 
  145        $nbt = 
new LittleEndianNbtSerializer();
 
  147            $worldData = $nbt->read(substr($rawLevelData, 8))->mustGetCompoundTag();
 
  148        }
catch(NbtDataException $e){
 
  152        $version = $worldData->getInt(self::TAG_STORAGE_VERSION, Limits::INT32_MAX);
 
  153        if($version === Limits::INT32_MAX){
 
  154            throw new CorruptedWorldException(sprintf(
"Missing '%s' tag in level.dat", self::TAG_STORAGE_VERSION));
 
  156        if($version > self::CURRENT_STORAGE_VERSION){
 
  157            throw new UnsupportedWorldFormatException(
"LevelDB world format version $version is currently unsupported");
 
  161        $protocolVersion = $worldData->getInt(self::TAG_NETWORK_VERSION, Limits::INT32_MAX);
 
  162        if($protocolVersion === Limits::INT32_MAX){
 
  163            throw new CorruptedWorldException(sprintf(
"Missing '%s' tag in level.dat", self::TAG_NETWORK_VERSION));
 
  165        if($protocolVersion > self::CURRENT_STORAGE_NETWORK_VERSION){
 
  166            throw new UnsupportedWorldFormatException(
"LevelDB world protocol version $protocolVersion is currently unsupported");
 
 
  172    protected function fix() : void{
 
  173        $generatorNameTag = $this->compoundTag->getTag(self::TAG_GENERATOR_NAME);
 
  174        if(!($generatorNameTag instanceof 
StringTag)){
 
  175            if(($mcpeGeneratorTypeTag = $this->compoundTag->getTag(self::TAG_GENERATOR)) instanceof 
IntTag){
 
  176                switch($mcpeGeneratorTypeTag->getValue()){ 
 
  177                    case self::GENERATOR_FLAT:
 
  178                        $this->compoundTag->setString(self::TAG_GENERATOR_NAME, 
"flat");
 
  179                        $this->compoundTag->setString(self::TAG_GENERATOR_OPTIONS, 
"2;7,3,3,2;1");
 
  181                    case self::GENERATOR_INFINITE:
 
  183                        $this->compoundTag->setString(self::TAG_GENERATOR_NAME, 
"default");
 
  184                        $this->compoundTag->setString(self::TAG_GENERATOR_OPTIONS, 
"");
 
  186                    case self::GENERATOR_LIMITED:
 
  192                $this->compoundTag->setString(self::TAG_GENERATOR_NAME, 
"default");
 
  194        }elseif(($generatorName = self::hackyFixForGeneratorClasspathInLevelDat($generatorNameTag->getValue())) !== 
null){
 
  195            $this->compoundTag->setString(self::TAG_GENERATOR_NAME, $generatorName);
 
  198        if(!($this->compoundTag->getTag(self::TAG_GENERATOR_OPTIONS)) instanceof 
StringTag){
 
  199            $this->compoundTag->setString(self::TAG_GENERATOR_OPTIONS, 
"");
 
 
  204        $this->compoundTag->setInt(self::TAG_NETWORK_VERSION, self::CURRENT_STORAGE_NETWORK_VERSION);
 
  205        $this->compoundTag->setInt(self::TAG_STORAGE_VERSION, self::CURRENT_STORAGE_VERSION);
 
  206        $this->compoundTag->setTag(self::TAG_LAST_OPENED_WITH_VERSION, 
new ListTag(array_map(fn(
int $v) => 
new IntTag($v), self::CURRENT_CLIENT_VERSION_TARGET)));
 
  207        $this->compoundTag->setLong(VersionInfo::TAG_WORLD_DATA_VERSION, VersionInfo::WORLD_DATA_VERSION);
 
  210        $buffer = $nbt->write(
new TreeRoot($this->compoundTag));
 
  211        Filesystem::safeFilePutContents($this->dataPath, Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer);
 
 
  215        return $this->compoundTag->getInt(self::TAG_DIFFICULTY, 
World::DIFFICULTY_NORMAL);
 
 
  219        $this->compoundTag->setInt(self::TAG_DIFFICULTY, $difficulty); 
 
 
  223        return $this->compoundTag->getInt(self::TAG_RAIN_TIME, 0);
 
 
  227        $this->compoundTag->setInt(self::TAG_RAIN_TIME, $ticks);
 
 
  231        return $this->compoundTag->getFloat(self::TAG_RAIN_LEVEL, 0.0);
 
 
  235        $this->compoundTag->setFloat(self::TAG_RAIN_LEVEL, $level);
 
 
  239        return $this->compoundTag->getInt(self::TAG_LIGHTNING_TIME, 0);
 
 
  243        $this->compoundTag->setInt(self::TAG_LIGHTNING_TIME, $ticks);
 
 
  247        return $this->compoundTag->getFloat(self::TAG_LIGHTNING_LEVEL, 0.0);
 
 
  251        $this->compoundTag->setFloat(self::TAG_LIGHTNING_LEVEL, $level);