diff --git a/src/world/format/io/data/BaseNbtWorldData.php b/src/world/format/io/data/BaseNbtWorldData.php index e02bcf21f..ecd9b483c 100644 --- a/src/world/format/io/data/BaseNbtWorldData.php +++ b/src/world/format/io/data/BaseNbtWorldData.php @@ -32,6 +32,15 @@ use pocketmine\world\format\io\WorldData; use function file_exists; abstract class BaseNbtWorldData implements WorldData{ + protected const TAG_LEVEL_NAME = "LevelName"; + protected const TAG_GENERATOR_NAME = "generatorName"; + protected const TAG_GENERATOR_OPTIONS = "generatorOptions"; + protected const TAG_RANDOM_SEED = "RandomSeed"; + protected const TAG_TIME = "Time"; + protected const TAG_SPAWN_X = "SpawnX"; + protected const TAG_SPAWN_Y = "SpawnY"; + protected const TAG_SPAWN_Z = "SpawnZ"; + protected CompoundTag $compoundTag; /** @@ -104,40 +113,40 @@ abstract class BaseNbtWorldData implements WorldData{ /* The below are common between PC and PE */ public function getName() : string{ - return $this->compoundTag->getString("LevelName"); + return $this->compoundTag->getString(self::TAG_LEVEL_NAME); } public function getGenerator() : string{ - return $this->compoundTag->getString("generatorName", "DEFAULT"); + return $this->compoundTag->getString(self::TAG_GENERATOR_NAME, "DEFAULT"); } public function getGeneratorOptions() : string{ - return $this->compoundTag->getString("generatorOptions", ""); + return $this->compoundTag->getString(self::TAG_GENERATOR_OPTIONS, ""); } public function getSeed() : int{ - return $this->compoundTag->getLong("RandomSeed"); + return $this->compoundTag->getLong(self::TAG_RANDOM_SEED); } public function getTime() : int{ - if(($timeTag = $this->compoundTag->getTag("Time")) instanceof IntTag){ //some older PM worlds had this in the wrong format + if(($timeTag = $this->compoundTag->getTag(self::TAG_TIME)) instanceof IntTag){ //some older PM worlds had this in the wrong format return $timeTag->getValue(); } - return $this->compoundTag->getLong("Time", 0); + return $this->compoundTag->getLong(self::TAG_TIME, 0); } public function setTime(int $value) : void{ - $this->compoundTag->setLong("Time", $value); + $this->compoundTag->setLong(self::TAG_TIME, $value); } public function getSpawn() : Vector3{ - return new Vector3($this->compoundTag->getInt("SpawnX"), $this->compoundTag->getInt("SpawnY"), $this->compoundTag->getInt("SpawnZ")); + return new Vector3($this->compoundTag->getInt(self::TAG_SPAWN_X), $this->compoundTag->getInt(self::TAG_SPAWN_Y), $this->compoundTag->getInt(self::TAG_SPAWN_Z)); } public function setSpawn(Vector3 $pos) : void{ - $this->compoundTag->setInt("SpawnX", $pos->getFloorX()); - $this->compoundTag->setInt("SpawnY", $pos->getFloorY()); - $this->compoundTag->setInt("SpawnZ", $pos->getFloorZ()); + $this->compoundTag->setInt(self::TAG_SPAWN_X, $pos->getFloorX()); + $this->compoundTag->setInt(self::TAG_SPAWN_Y, $pos->getFloorY()); + $this->compoundTag->setInt(self::TAG_SPAWN_Z, $pos->getFloorZ()); } } diff --git a/src/world/format/io/data/BedrockWorldData.php b/src/world/format/io/data/BedrockWorldData.php index 9cdeef0fc..d628bd5c4 100644 --- a/src/world/format/io/data/BedrockWorldData.php +++ b/src/world/format/io/data/BedrockWorldData.php @@ -54,6 +54,29 @@ class BedrockWorldData extends BaseNbtWorldData{ public const GENERATOR_INFINITE = 1; public const GENERATOR_FLAT = 2; + private const TAG_DAY_CYCLE_STOP_TIME = "DayCycleStopTime"; + private const TAG_DIFFICULTY = "Difficulty"; + private const TAG_FORCE_GAME_TYPE = "ForceGameType"; + private const TAG_GAME_TYPE = "GameType"; + private const TAG_GENERATOR = "Generator"; + private const TAG_LAST_PLAYED = "LastPlayed"; + private const TAG_NETWORK_VERSION = "NetworkVersion"; + private const TAG_STORAGE_VERSION = "StorageVersion"; + private const TAG_IS_EDU = "eduLevel"; + private const TAG_FALL_DAMAGE_ENABLED = "falldamage"; + private const TAG_FIRE_DAMAGE_ENABLED = "firedamage"; + private const TAG_ACHIEVEMENTS_DISABLED = "hasBeenLoadedInCreative"; + private const TAG_IMMUTABLE_WORLD = "immutableWorld"; + private const TAG_LIGHTNING_LEVEL = "lightningLevel"; + private const TAG_LIGHTNING_TIME = "lightningTime"; + private const TAG_PVP_ENABLED = "pvp"; + private const TAG_RAIN_LEVEL = "rainLevel"; + private const TAG_RAIN_TIME = "rainTime"; + private const TAG_SPAWN_MOBS = "spawnMobs"; + private const TAG_TEXTURE_PACKS_REQUIRED = "texturePacksRequired"; + private const TAG_HARDCORE = "hardcore"; + private const TAG_GAME_RULES = "GameRules"; + public static function generate(string $path, string $name, WorldCreationOptions $options) : void{ switch($options->getGeneratorClass()){ case Flat::class: @@ -66,39 +89,39 @@ class BedrockWorldData extends BaseNbtWorldData{ $worldData = CompoundTag::create() //Vanilla fields - ->setInt("DayCycleStopTime", -1) - ->setInt("Difficulty", $options->getDifficulty()) - ->setByte("ForceGameType", 0) - ->setInt("GameType", 0) - ->setInt("Generator", $generatorType) - ->setLong("LastPlayed", time()) - ->setString("LevelName", $name) - ->setInt("NetworkVersion", self::CURRENT_STORAGE_NETWORK_VERSION) + ->setInt(self::TAG_DAY_CYCLE_STOP_TIME, -1) + ->setInt(self::TAG_DIFFICULTY, $options->getDifficulty()) + ->setByte(self::TAG_FORCE_GAME_TYPE, 0) + ->setInt(self::TAG_GAME_TYPE, 0) + ->setInt(self::TAG_GENERATOR, $generatorType) + ->setLong(self::TAG_LAST_PLAYED, time()) + ->setString(self::TAG_LEVEL_NAME, $name) + ->setInt(self::TAG_NETWORK_VERSION, self::CURRENT_STORAGE_NETWORK_VERSION) //->setInt("Platform", 2) //TODO: find out what the possible values are for - ->setLong("RandomSeed", $options->getSeed()) - ->setInt("SpawnX", $options->getSpawnPosition()->getFloorX()) - ->setInt("SpawnY", $options->getSpawnPosition()->getFloorY()) - ->setInt("SpawnZ", $options->getSpawnPosition()->getFloorZ()) - ->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION) - ->setLong("Time", 0) - ->setByte("eduLevel", 0) - ->setByte("falldamage", 1) - ->setByte("firedamage", 1) - ->setByte("hasBeenLoadedInCreative", 1) //badly named, this actually determines whether achievements can be earned in this world... - ->setByte("immutableWorld", 0) - ->setFloat("lightningLevel", 0.0) - ->setInt("lightningTime", 0) - ->setByte("pvp", 1) - ->setFloat("rainLevel", 0.0) - ->setInt("rainTime", 0) - ->setByte("spawnMobs", 1) - ->setByte("texturePacksRequired", 0) //TODO + ->setLong(self::TAG_RANDOM_SEED, $options->getSeed()) + ->setInt(self::TAG_SPAWN_X, $options->getSpawnPosition()->getFloorX()) + ->setInt(self::TAG_SPAWN_Y, $options->getSpawnPosition()->getFloorY()) + ->setInt(self::TAG_SPAWN_Z, $options->getSpawnPosition()->getFloorZ()) + ->setInt(self::TAG_STORAGE_VERSION, self::CURRENT_STORAGE_VERSION) + ->setLong(self::TAG_TIME, 0) + ->setByte(self::TAG_IS_EDU, 0) + ->setByte(self::TAG_FALL_DAMAGE_ENABLED, 1) + ->setByte(self::TAG_FIRE_DAMAGE_ENABLED, 1) + ->setByte(self::TAG_ACHIEVEMENTS_DISABLED, 1) //badly named, this actually determines whether achievements can be earned in this world... + ->setByte(self::TAG_IMMUTABLE_WORLD, 0) + ->setFloat(self::TAG_LIGHTNING_LEVEL, 0.0) + ->setInt(self::TAG_LIGHTNING_TIME, 0) + ->setByte(self::TAG_PVP_ENABLED, 1) + ->setFloat(self::TAG_RAIN_LEVEL, 0.0) + ->setInt(self::TAG_RAIN_TIME, 0) + ->setByte(self::TAG_SPAWN_MOBS, 1) + ->setByte(self::TAG_TEXTURE_PACKS_REQUIRED, 0) //TODO //Additional PocketMine-MP fields - ->setTag("GameRules", new CompoundTag()) - ->setByte("hardcore", 0) - ->setString("generatorName", GeneratorManager::getInstance()->getGeneratorName($options->getGeneratorClass())) - ->setString("generatorOptions", $options->getGeneratorOptions()); + ->setTag(self::TAG_GAME_RULES, new CompoundTag()) + ->setByte(self::TAG_HARDCORE, 0) + ->setString(self::TAG_GENERATOR_NAME, GeneratorManager::getInstance()->getGeneratorName($options->getGeneratorClass())) + ->setString(self::TAG_GENERATOR_OPTIONS, $options->getGeneratorOptions()); $nbt = new LittleEndianNbtSerializer(); $buffer = $nbt->write(new TreeRoot($worldData)); @@ -120,7 +143,7 @@ class BedrockWorldData extends BaseNbtWorldData{ throw new CorruptedWorldException($e->getMessage(), 0, $e); } - $version = $worldData->getInt("StorageVersion", Limits::INT32_MAX); + $version = $worldData->getInt(self::TAG_STORAGE_VERSION, Limits::INT32_MAX); if($version > self::CURRENT_STORAGE_VERSION){ throw new UnsupportedWorldFormatException("LevelDB world format version $version is currently unsupported"); } @@ -129,18 +152,18 @@ class BedrockWorldData extends BaseNbtWorldData{ } protected function fix() : void{ - $generatorNameTag = $this->compoundTag->getTag("generatorName"); + $generatorNameTag = $this->compoundTag->getTag(self::TAG_GENERATOR_NAME); if(!($generatorNameTag instanceof StringTag)){ - if(($mcpeGeneratorTypeTag = $this->compoundTag->getTag("Generator")) instanceof IntTag){ + if(($mcpeGeneratorTypeTag = $this->compoundTag->getTag(self::TAG_GENERATOR)) instanceof IntTag){ switch($mcpeGeneratorTypeTag->getValue()){ //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"); + $this->compoundTag->setString(self::TAG_GENERATOR_NAME, "flat"); + $this->compoundTag->setString(self::TAG_GENERATOR_OPTIONS, "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", ""); + $this->compoundTag->setString(self::TAG_GENERATOR_NAME, "default"); + $this->compoundTag->setString(self::TAG_GENERATOR_OPTIONS, ""); break; case self::GENERATOR_LIMITED: throw new UnsupportedWorldFormatException("Limited worlds are not currently supported"); @@ -148,20 +171,20 @@ class BedrockWorldData extends BaseNbtWorldData{ throw new UnsupportedWorldFormatException("Unknown LevelDB generator type"); } }else{ - $this->compoundTag->setString("generatorName", "default"); + $this->compoundTag->setString(self::TAG_GENERATOR_NAME, "default"); } }elseif(($generatorName = self::hackyFixForGeneratorClasspathInLevelDat($generatorNameTag->getValue())) !== null){ - $this->compoundTag->setString("generatorName", $generatorName); + $this->compoundTag->setString(self::TAG_GENERATOR_NAME, $generatorName); } - if(!($this->compoundTag->getTag("generatorOptions")) instanceof StringTag){ - $this->compoundTag->setString("generatorOptions", ""); + if(!($this->compoundTag->getTag(self::TAG_GENERATOR_OPTIONS)) instanceof StringTag){ + $this->compoundTag->setString(self::TAG_GENERATOR_OPTIONS, ""); } } public function save() : void{ - $this->compoundTag->setInt("NetworkVersion", self::CURRENT_STORAGE_NETWORK_VERSION); - $this->compoundTag->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION); + $this->compoundTag->setInt(self::TAG_NETWORK_VERSION, self::CURRENT_STORAGE_NETWORK_VERSION); + $this->compoundTag->setInt(self::TAG_STORAGE_VERSION, self::CURRENT_STORAGE_VERSION); $nbt = new LittleEndianNbtSerializer(); $buffer = $nbt->write(new TreeRoot($this->compoundTag)); @@ -169,42 +192,42 @@ class BedrockWorldData extends BaseNbtWorldData{ } public function getDifficulty() : int{ - return $this->compoundTag->getInt("Difficulty", World::DIFFICULTY_NORMAL); + return $this->compoundTag->getInt(self::TAG_DIFFICULTY, World::DIFFICULTY_NORMAL); } public function setDifficulty(int $difficulty) : void{ - $this->compoundTag->setInt("Difficulty", $difficulty); //yes, this is intended! (in PE: int, PC: byte) + $this->compoundTag->setInt(self::TAG_DIFFICULTY, $difficulty); //yes, this is intended! (in PE: int, PC: byte) } public function getRainTime() : int{ - return $this->compoundTag->getInt("rainTime", 0); + return $this->compoundTag->getInt(self::TAG_RAIN_TIME, 0); } public function setRainTime(int $ticks) : void{ - $this->compoundTag->setInt("rainTime", $ticks); + $this->compoundTag->setInt(self::TAG_RAIN_TIME, $ticks); } public function getRainLevel() : float{ - return $this->compoundTag->getFloat("rainLevel", 0.0); + return $this->compoundTag->getFloat(self::TAG_RAIN_LEVEL, 0.0); } public function setRainLevel(float $level) : void{ - $this->compoundTag->setFloat("rainLevel", $level); + $this->compoundTag->setFloat(self::TAG_RAIN_LEVEL, $level); } public function getLightningTime() : int{ - return $this->compoundTag->getInt("lightningTime", 0); + return $this->compoundTag->getInt(self::TAG_LIGHTNING_TIME, 0); } public function setLightningTime(int $ticks) : void{ - $this->compoundTag->setInt("lightningTime", $ticks); + $this->compoundTag->setInt(self::TAG_LIGHTNING_TIME, $ticks); } public function getLightningLevel() : float{ - return $this->compoundTag->getFloat("lightningLevel", 0.0); + return $this->compoundTag->getFloat(self::TAG_LIGHTNING_LEVEL, 0.0); } public function setLightningLevel(float $level) : void{ - $this->compoundTag->setFloat("lightningLevel", $level); + $this->compoundTag->setFloat(self::TAG_LIGHTNING_LEVEL, $level); } } diff --git a/src/world/format/io/data/JavaWorldData.php b/src/world/format/io/data/JavaWorldData.php index e53d857ad..817cee0fe 100644 --- a/src/world/format/io/data/JavaWorldData.php +++ b/src/world/format/io/data/JavaWorldData.php @@ -46,31 +46,49 @@ use const ZLIB_ENCODING_GZIP; class JavaWorldData extends BaseNbtWorldData{ + private const TAG_DAY_TIME = "DayTime"; + private const TAG_DIFFICULTY = "Difficulty"; + private const TAG_FORMAT_VERSION = "version"; + private const TAG_GAME_RULES = "GameRules"; + private const TAG_GAME_TYPE = "GameType"; + private const TAG_GENERATOR_VERSION = "generatorVersion"; + private const TAG_HARDCORE = "hardcore"; + private const TAG_INITIALIZED = "initialized"; + private const TAG_LAST_PLAYED = "LastPlayed"; + private const TAG_LIGHTNING_LEVEL = "lightningLevel"; + private const TAG_RAINING = "raining"; + private const TAG_RAIN_LEVEL = "rainLevel"; + private const TAG_RAIN_TIME = "rainTime"; + private const TAG_ROOT_DATA = "Data"; + private const TAG_SIZE_ON_DISK = "SizeOnDisk"; + private const TAG_THUNDERING = "thundering"; + private const TAG_THUNDER_TIME = "thunderTime"; + public static function generate(string $path, string $name, WorldCreationOptions $options, int $version = 19133) : void{ //TODO, add extra details $worldData = CompoundTag::create() - ->setByte("hardcore", 0) - ->setByte("Difficulty", $options->getDifficulty()) - ->setByte("initialized", 1) - ->setInt("GameType", 0) - ->setInt("generatorVersion", 1) //2 in MCPE - ->setInt("SpawnX", $options->getSpawnPosition()->getFloorX()) - ->setInt("SpawnY", $options->getSpawnPosition()->getFloorY()) - ->setInt("SpawnZ", $options->getSpawnPosition()->getFloorZ()) - ->setInt("version", $version) - ->setInt("DayTime", 0) - ->setLong("LastPlayed", (int) (microtime(true) * 1000)) - ->setLong("RandomSeed", $options->getSeed()) - ->setLong("SizeOnDisk", 0) - ->setLong("Time", 0) - ->setString("generatorName", GeneratorManager::getInstance()->getGeneratorName($options->getGeneratorClass())) - ->setString("generatorOptions", $options->getGeneratorOptions()) - ->setString("LevelName", $name) - ->setTag("GameRules", new CompoundTag()); + ->setByte(self::TAG_HARDCORE, 0) + ->setByte(self::TAG_DIFFICULTY, $options->getDifficulty()) + ->setByte(self::TAG_INITIALIZED, 1) + ->setInt(self::TAG_GAME_TYPE, 0) + ->setInt(self::TAG_GENERATOR_VERSION, 1) //2 in MCPE + ->setInt(self::TAG_SPAWN_X, $options->getSpawnPosition()->getFloorX()) + ->setInt(self::TAG_SPAWN_Y, $options->getSpawnPosition()->getFloorY()) + ->setInt(self::TAG_SPAWN_Z, $options->getSpawnPosition()->getFloorZ()) + ->setInt(self::TAG_FORMAT_VERSION, $version) + ->setInt(self::TAG_DAY_TIME, 0) + ->setLong(self::TAG_LAST_PLAYED, (int) (microtime(true) * 1000)) + ->setLong(self::TAG_RANDOM_SEED, $options->getSeed()) + ->setLong(self::TAG_SIZE_ON_DISK, 0) + ->setLong(self::TAG_TIME, 0) + ->setString(self::TAG_GENERATOR_NAME, GeneratorManager::getInstance()->getGeneratorName($options->getGeneratorClass())) + ->setString(self::TAG_GENERATOR_OPTIONS, $options->getGeneratorOptions()) + ->setString(self::TAG_LEVEL_NAME, $name) + ->setTag(self::TAG_GAME_RULES, new CompoundTag()); $nbt = new BigEndianNbtSerializer(); - $buffer = zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag("Data", $worldData))), ZLIB_ENCODING_GZIP); + $buffer = zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag(self::TAG_ROOT_DATA, $worldData))), ZLIB_ENCODING_GZIP); file_put_contents(Path::join($path, "level.dat"), $buffer); } @@ -90,79 +108,79 @@ class JavaWorldData extends BaseNbtWorldData{ throw new CorruptedWorldException($e->getMessage(), 0, $e); } - $dataTag = $worldData->getTag("Data"); + $dataTag = $worldData->getTag(self::TAG_ROOT_DATA); if(!($dataTag instanceof CompoundTag)){ - throw new CorruptedWorldException("Missing 'Data' key or wrong type"); + throw new CorruptedWorldException("Missing '" . self::TAG_ROOT_DATA . "' key or wrong type"); } return $dataTag; } protected function fix() : void{ - $generatorNameTag = $this->compoundTag->getTag("generatorName"); + $generatorNameTag = $this->compoundTag->getTag(self::TAG_GENERATOR_NAME); if(!($generatorNameTag instanceof StringTag)){ - $this->compoundTag->setString("generatorName", "default"); + $this->compoundTag->setString(self::TAG_GENERATOR_NAME, "default"); }elseif(($generatorName = self::hackyFixForGeneratorClasspathInLevelDat($generatorNameTag->getValue())) !== null){ - $this->compoundTag->setString("generatorName", $generatorName); + $this->compoundTag->setString(self::TAG_GENERATOR_NAME, $generatorName); } - if(!($this->compoundTag->getTag("generatorOptions") instanceof StringTag)){ - $this->compoundTag->setString("generatorOptions", ""); + if(!($this->compoundTag->getTag(self::TAG_GENERATOR_OPTIONS) instanceof StringTag)){ + $this->compoundTag->setString(self::TAG_GENERATOR_OPTIONS, ""); } } public function save() : void{ $nbt = new BigEndianNbtSerializer(); - $buffer = Utils::assumeNotFalse(zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag("Data", $this->compoundTag))), ZLIB_ENCODING_GZIP)); + $buffer = Utils::assumeNotFalse(zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag(self::TAG_ROOT_DATA, $this->compoundTag))), ZLIB_ENCODING_GZIP)); Filesystem::safeFilePutContents($this->dataPath, $buffer); } public function getDifficulty() : int{ - return $this->compoundTag->getByte("Difficulty", World::DIFFICULTY_NORMAL); + return $this->compoundTag->getByte(self::TAG_DIFFICULTY, World::DIFFICULTY_NORMAL); } public function setDifficulty(int $difficulty) : void{ - $this->compoundTag->setByte("Difficulty", $difficulty); + $this->compoundTag->setByte(self::TAG_DIFFICULTY, $difficulty); } public function getRainTime() : int{ - return $this->compoundTag->getInt("rainTime", 0); + return $this->compoundTag->getInt(self::TAG_RAIN_TIME, 0); } public function setRainTime(int $ticks) : void{ - $this->compoundTag->setInt("rainTime", $ticks); + $this->compoundTag->setInt(self::TAG_RAIN_TIME, $ticks); } public function getRainLevel() : float{ - if(($rainLevelTag = $this->compoundTag->getTag("rainLevel")) instanceof FloatTag){ //PocketMine/MCPE + if(($rainLevelTag = $this->compoundTag->getTag(self::TAG_RAIN_LEVEL)) instanceof FloatTag){ //PocketMine/MCPE return $rainLevelTag->getValue(); } - return (float) $this->compoundTag->getByte("raining", 0); //PC vanilla + return (float) $this->compoundTag->getByte(self::TAG_RAINING, 0); //PC vanilla } public function setRainLevel(float $level) : void{ - $this->compoundTag->setFloat("rainLevel", $level); //PocketMine/MCPE - $this->compoundTag->setByte("raining", (int) ceil($level)); //PC vanilla + $this->compoundTag->setFloat(self::TAG_RAIN_LEVEL, $level); //PocketMine/MCPE + $this->compoundTag->setByte(self::TAG_RAINING, (int) ceil($level)); //PC vanilla } public function getLightningTime() : int{ - return $this->compoundTag->getInt("thunderTime", 0); + return $this->compoundTag->getInt(self::TAG_THUNDER_TIME, 0); } public function setLightningTime(int $ticks) : void{ - $this->compoundTag->setInt("thunderTime", $ticks); + $this->compoundTag->setInt(self::TAG_THUNDER_TIME, $ticks); } public function getLightningLevel() : float{ - if(($lightningLevelTag = $this->compoundTag->getTag("lightningLevel")) instanceof FloatTag){ //PocketMine/MCPE + if(($lightningLevelTag = $this->compoundTag->getTag(self::TAG_LIGHTNING_LEVEL)) instanceof FloatTag){ //PocketMine/MCPE return $lightningLevelTag->getValue(); } - return (float) $this->compoundTag->getByte("thundering", 0); //PC vanilla + return (float) $this->compoundTag->getByte(self::TAG_THUNDERING, 0); //PC vanilla } public function setLightningLevel(float $level) : void{ - $this->compoundTag->setFloat("lightningLevel", $level); //PocketMine/MCPE - $this->compoundTag->setByte("thundering", (int) ceil($level)); //PC vanilla + $this->compoundTag->setFloat(self::TAG_LIGHTNING_LEVEL, $level); //PocketMine/MCPE + $this->compoundTag->setByte(self::TAG_THUNDERING, (int) ceil($level)); //PC vanilla } }