PocketMine-MP 5.15.1 git-5ef247620a7c6301a849b54e5ef1009217729fc8
JavaWorldData.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\world\format\io\data;
25
38use Symfony\Component\Filesystem\Path;
39use function ceil;
40use function file_put_contents;
41use function microtime;
42use function zlib_decode;
43use function zlib_encode;
44use const ZLIB_ENCODING_GZIP;
45
47
48 private const TAG_DAY_TIME = "DayTime";
49 private const TAG_DIFFICULTY = "Difficulty";
50 private const TAG_FORMAT_VERSION = "version";
51 private const TAG_GAME_RULES = "GameRules";
52 private const TAG_GAME_TYPE = "GameType";
53 private const TAG_GENERATOR_VERSION = "generatorVersion";
54 private const TAG_HARDCORE = "hardcore";
55 private const TAG_INITIALIZED = "initialized";
56 private const TAG_LAST_PLAYED = "LastPlayed";
57 private const TAG_RAINING = "raining";
58 private const TAG_RAIN_TIME = "rainTime";
59 private const TAG_ROOT_DATA = "Data";
60 private const TAG_SIZE_ON_DISK = "SizeOnDisk";
61 private const TAG_THUNDERING = "thundering";
62 private const TAG_THUNDER_TIME = "thunderTime";
63
64 public static function generate(string $path, string $name, WorldCreationOptions $options, int $version = 19133) : void{
65 //TODO, add extra details
66
67 $worldData = CompoundTag::create()
68 ->setByte(self::TAG_HARDCORE, 0)
69 ->setByte(self::TAG_DIFFICULTY, $options->getDifficulty())
70 ->setByte(self::TAG_INITIALIZED, 1)
71 ->setInt(self::TAG_GAME_TYPE, 0)
72 ->setInt(self::TAG_GENERATOR_VERSION, 1) //2 in MCPE
73 ->setInt(self::TAG_SPAWN_X, $options->getSpawnPosition()->getFloorX())
74 ->setInt(self::TAG_SPAWN_Y, $options->getSpawnPosition()->getFloorY())
75 ->setInt(self::TAG_SPAWN_Z, $options->getSpawnPosition()->getFloorZ())
76 ->setInt(self::TAG_FORMAT_VERSION, $version)
77 ->setInt(self::TAG_DAY_TIME, 0)
78 ->setLong(self::TAG_LAST_PLAYED, (int) (microtime(true) * 1000))
79 ->setLong(self::TAG_RANDOM_SEED, $options->getSeed())
80 ->setLong(self::TAG_SIZE_ON_DISK, 0)
81 ->setLong(self::TAG_TIME, 0)
82 ->setString(self::TAG_GENERATOR_NAME, GeneratorManager::getInstance()->getGeneratorName($options->getGeneratorClass()))
83 ->setString(self::TAG_GENERATOR_OPTIONS, $options->getGeneratorOptions())
84 ->setString(self::TAG_LEVEL_NAME, $name)
85 ->setTag(self::TAG_GAME_RULES, new CompoundTag());
86
87 $nbt = new BigEndianNbtSerializer();
88 $buffer = zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag(self::TAG_ROOT_DATA, $worldData))), ZLIB_ENCODING_GZIP);
89 file_put_contents(Path::join($path, "level.dat"), $buffer);
90 }
91
92 protected function load() : CompoundTag{
93 try{
94 $rawLevelData = Filesystem::fileGetContents($this->dataPath);
95 }catch(\RuntimeException $e){
96 throw new CorruptedWorldException($e->getMessage(), 0, $e);
97 }
98 $nbt = new BigEndianNbtSerializer();
99 $decompressed = @zlib_decode($rawLevelData);
100 if($decompressed === false){
101 throw new CorruptedWorldException("Failed to decompress level.dat contents");
102 }
103 try{
104 $worldData = $nbt->read($decompressed)->mustGetCompoundTag();
105 }catch(NbtDataException $e){
106 throw new CorruptedWorldException($e->getMessage(), 0, $e);
107 }
108
109 $dataTag = $worldData->getTag(self::TAG_ROOT_DATA);
110 if(!($dataTag instanceof CompoundTag)){
111 throw new CorruptedWorldException("Missing '" . self::TAG_ROOT_DATA . "' key or wrong type");
112 }
113 return $dataTag;
114 }
115
116 protected function fix() : void{
117 $generatorNameTag = $this->compoundTag->getTag(self::TAG_GENERATOR_NAME);
118 if(!($generatorNameTag instanceof StringTag)){
119 $this->compoundTag->setString(self::TAG_GENERATOR_NAME, "default");
120 }elseif(($generatorName = self::hackyFixForGeneratorClasspathInLevelDat($generatorNameTag->getValue())) !== null){
121 $this->compoundTag->setString(self::TAG_GENERATOR_NAME, $generatorName);
122 }
123
124 if(!($this->compoundTag->getTag(self::TAG_GENERATOR_OPTIONS) instanceof StringTag)){
125 $this->compoundTag->setString(self::TAG_GENERATOR_OPTIONS, "");
126 }
127 }
128
129 public function save() : void{
130 $this->compoundTag->setLong(VersionInfo::TAG_WORLD_DATA_VERSION, VersionInfo::WORLD_DATA_VERSION);
131
132 $nbt = new BigEndianNbtSerializer();
133 $buffer = Utils::assumeNotFalse(zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag(self::TAG_ROOT_DATA, $this->compoundTag))), ZLIB_ENCODING_GZIP));
134 Filesystem::safeFilePutContents($this->dataPath, $buffer);
135 }
136
137 public function getDifficulty() : int{
138 return $this->compoundTag->getByte(self::TAG_DIFFICULTY, World::DIFFICULTY_NORMAL);
139 }
140
141 public function setDifficulty(int $difficulty) : void{
142 $this->compoundTag->setByte(self::TAG_DIFFICULTY, $difficulty);
143 }
144
145 public function getRainTime() : int{
146 return $this->compoundTag->getInt(self::TAG_RAIN_TIME, 0);
147 }
148
149 public function setRainTime(int $ticks) : void{
150 $this->compoundTag->setInt(self::TAG_RAIN_TIME, $ticks);
151 }
152
153 public function getRainLevel() : float{
154 return (float) $this->compoundTag->getByte(self::TAG_RAINING, 0);
155 }
156
157 public function setRainLevel(float $level) : void{
158 $this->compoundTag->setByte(self::TAG_RAINING, (int) ceil($level));
159 }
160
161 public function getLightningTime() : int{
162 return $this->compoundTag->getInt(self::TAG_THUNDER_TIME, 0);
163 }
164
165 public function setLightningTime(int $ticks) : void{
166 $this->compoundTag->setInt(self::TAG_THUNDER_TIME, $ticks);
167 }
168
169 public function getLightningLevel() : float{
170 return (float) $this->compoundTag->getByte(self::TAG_THUNDERING, 0);
171 }
172
173 public function setLightningLevel(float $level) : void{
174 $this->compoundTag->setByte(self::TAG_THUNDERING, (int) ceil($level));
175 }
176}