mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-11 08:19:45 +00:00
Separate level data handling from the main LevelProvider
This commit is contained in:
parent
f23bba053b
commit
49e47edcf5
@ -333,11 +333,11 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
$this->provider = $provider;
|
||||
|
||||
$this->displayName = $this->provider->getName();
|
||||
$this->displayName = $this->provider->getLevelData()->getName();
|
||||
$this->worldHeight = $this->provider->getWorldHeight();
|
||||
|
||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.level.preparing", [$this->displayName]));
|
||||
$this->generator = GeneratorManager::getGenerator($this->provider->getGenerator());
|
||||
$this->generator = GeneratorManager::getGenerator($this->provider->getLevelData()->getGenerator());
|
||||
|
||||
$this->folderName = $name;
|
||||
|
||||
@ -346,7 +346,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
$this->neighbourBlockUpdateQueue = new \SplQueue();
|
||||
|
||||
$this->time = $this->provider->getTime();
|
||||
$this->time = $this->provider->getLevelData()->getTime();
|
||||
|
||||
$this->chunkTickRadius = min($this->server->getViewDistance(), max(1, (int) $this->server->getProperty("chunk-ticking.tick-radius", 4)));
|
||||
$this->chunksPerTick = (int) $this->server->getProperty("chunk-ticking.per-tick", 40);
|
||||
@ -389,7 +389,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
public function registerGeneratorToWorker(int $worker) : void{
|
||||
$this->generatorRegisteredWorkers[$worker] = true;
|
||||
$this->server->getAsyncPool()->submitTaskToWorker(new GeneratorRegisterTask($this, $this->generator, $this->provider->getGeneratorOptions()), $worker);
|
||||
$this->server->getAsyncPool()->submitTaskToWorker(new GeneratorRegisterTask($this, $this->generator, $this->provider->getLevelData()->getGeneratorOptions()), $worker);
|
||||
}
|
||||
|
||||
public function unregisterGenerator(){
|
||||
@ -1022,9 +1022,9 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
$this->server->getPluginManager()->callEvent(new LevelSaveEvent($this));
|
||||
|
||||
$this->provider->setTime($this->time);
|
||||
$this->provider->getLevelData()->setTime($this->time);
|
||||
$this->saveChunks();
|
||||
$this->provider->saveLevelData();
|
||||
$this->provider->getLevelData()->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2405,7 +2405,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
* @return Position
|
||||
*/
|
||||
public function getSpawnLocation() : Position{
|
||||
return Position::fromObject($this->provider->getSpawn(), $this);
|
||||
return Position::fromObject($this->provider->getLevelData()->getSpawn(), $this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2415,7 +2415,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
*/
|
||||
public function setSpawnLocation(Vector3 $pos){
|
||||
$previousSpawn = $this->getSpawnLocation();
|
||||
$this->provider->setSpawn($pos);
|
||||
$this->provider->getLevelData()->setSpawn($pos);
|
||||
$this->server->getPluginManager()->callEvent(new SpawnChangeEvent($this, $previousSpawn));
|
||||
}
|
||||
|
||||
@ -2750,7 +2750,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
* @return bool
|
||||
*/
|
||||
public function isSpawnChunk(int $X, int $Z) : bool{
|
||||
$spawn = $this->provider->getSpawn();
|
||||
$spawn = $this->getSpawnLocation();
|
||||
$spawnX = $spawn->x >> 4;
|
||||
$spawnZ = $spawn->z >> 4;
|
||||
|
||||
@ -2861,7 +2861,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
* @return int
|
||||
*/
|
||||
public function getSeed() : int{
|
||||
return $this->provider->getSeed();
|
||||
return $this->provider->getLevelData()->getSeed();
|
||||
}
|
||||
|
||||
public function getWorldHeight() : int{
|
||||
@ -2872,7 +2872,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
* @return int
|
||||
*/
|
||||
public function getDifficulty() : int{
|
||||
return $this->provider->getDifficulty();
|
||||
return $this->provider->getLevelData()->getDifficulty();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2882,7 +2882,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
if($difficulty < 0 or $difficulty > 3){
|
||||
throw new \InvalidArgumentException("Invalid difficulty level $difficulty");
|
||||
}
|
||||
$this->provider->setDifficulty($difficulty);
|
||||
$this->provider->getLevelData()->setDifficulty($difficulty);
|
||||
|
||||
$this->sendDifficulty();
|
||||
}
|
||||
|
@ -25,13 +25,11 @@ namespace pocketmine\level\format\io;
|
||||
|
||||
use pocketmine\level\format\Chunk;
|
||||
use pocketmine\level\LevelException;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
|
||||
abstract class BaseLevelProvider implements LevelProvider{
|
||||
/** @var string */
|
||||
protected $path;
|
||||
/** @var CompoundTag */
|
||||
/** @var LevelData */
|
||||
protected $levelData;
|
||||
|
||||
public function __construct(string $path){
|
||||
@ -40,13 +38,10 @@ abstract class BaseLevelProvider implements LevelProvider{
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
$this->loadLevelData();
|
||||
$this->fixLevelData();
|
||||
$this->levelData = $this->loadLevelData();
|
||||
}
|
||||
|
||||
abstract protected function loadLevelData() : void;
|
||||
|
||||
abstract protected function fixLevelData() : void;
|
||||
abstract protected function loadLevelData() : LevelData;
|
||||
|
||||
/**
|
||||
* Hack to fix worlds broken previously by older versions of PocketMine-MP which incorrectly saved classpaths of
|
||||
@ -66,7 +61,7 @@ abstract class BaseLevelProvider implements LevelProvider{
|
||||
*
|
||||
* @return null|string Name of the correct generator to replace the broken value
|
||||
*/
|
||||
protected static function hackyFixForGeneratorClasspathInLevelDat(string $className) : ?string{
|
||||
public static function hackyFixForGeneratorClasspathInLevelDat(string $className) : ?string{
|
||||
//THESE ARE DELIBERATELY HARDCODED, DO NOT CHANGE!
|
||||
switch($className){
|
||||
case 'pocketmine\level\generator\normal\Normal':
|
||||
@ -82,36 +77,10 @@ abstract class BaseLevelProvider implements LevelProvider{
|
||||
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
|
||||
* @return LevelData
|
||||
*/
|
||||
public function getLevelData() : CompoundTag{
|
||||
public function getLevelData() : LevelData{
|
||||
return $this->levelData;
|
||||
}
|
||||
|
||||
|
136
src/pocketmine/level/format/io/LevelData.php
Normal file
136
src/pocketmine/level/format/io/LevelData.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\level\format\io;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
interface LevelData{
|
||||
|
||||
/**
|
||||
* Saves information about the level state, such as weather, time, etc.
|
||||
*/
|
||||
public function save() : void;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName() : string;
|
||||
|
||||
/**
|
||||
* Returns the generator name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGenerator() : string;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getGeneratorOptions() : array;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSeed() : int;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTime() : int;
|
||||
|
||||
/**
|
||||
* @param int
|
||||
*/
|
||||
public function setTime(int $value) : void;
|
||||
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getSpawn() : Vector3;
|
||||
|
||||
/**
|
||||
* @param Vector3 $pos
|
||||
*/
|
||||
public function setSpawn(Vector3 $pos) : void;
|
||||
|
||||
/**
|
||||
* Returns the world difficulty. This will be one of the Level constants.
|
||||
* @return int
|
||||
*/
|
||||
public function getDifficulty() : int;
|
||||
|
||||
/**
|
||||
* Sets the world difficulty.
|
||||
*
|
||||
* @param int $difficulty
|
||||
*/
|
||||
public function setDifficulty(int $difficulty) : void;
|
||||
|
||||
/**
|
||||
* Returns the time in ticks to the next rain level change.
|
||||
* @return int
|
||||
*/
|
||||
public function getRainTime() : int;
|
||||
|
||||
/**
|
||||
* Sets the time in ticks to the next rain level change.
|
||||
* @param int $ticks
|
||||
*/
|
||||
public function setRainTime(int $ticks) : void;
|
||||
|
||||
/**
|
||||
* @return float 0.0 - 1.0
|
||||
*/
|
||||
public function getRainLevel() : float;
|
||||
|
||||
/**
|
||||
* @param float $level 0.0 - 1.0
|
||||
*/
|
||||
public function setRainLevel(float $level) : void;
|
||||
|
||||
/**
|
||||
* Returns the time in ticks to the next lightning level change.
|
||||
* @return int
|
||||
*/
|
||||
public function getLightningTime() : int;
|
||||
|
||||
/**
|
||||
* Sets the time in ticks to the next lightning level change.
|
||||
* @param int $ticks
|
||||
*/
|
||||
public function setLightningTime(int $ticks) : void;
|
||||
|
||||
/**
|
||||
* @return float 0.0 - 1.0
|
||||
*/
|
||||
public function getLightningLevel() : float;
|
||||
|
||||
/**
|
||||
* @param float $level 0.0 - 1.0
|
||||
*/
|
||||
public function setLightningLevel(float $level) : void;
|
||||
}
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace pocketmine\level\format\io;
|
||||
|
||||
use pocketmine\level\format\Chunk;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
interface LevelProvider{
|
||||
|
||||
@ -66,18 +65,6 @@ interface LevelProvider{
|
||||
*/
|
||||
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []);
|
||||
|
||||
/**
|
||||
* Returns the generator name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGenerator() : string;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getGeneratorOptions() : array;
|
||||
|
||||
/**
|
||||
* Saves a chunk (usually to disk).
|
||||
*
|
||||
@ -98,101 +85,17 @@ interface LevelProvider{
|
||||
*/
|
||||
public function loadChunk(int $chunkX, int $chunkZ) : ?Chunk;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName() : string;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTime() : int;
|
||||
|
||||
/**
|
||||
* @param int
|
||||
*/
|
||||
public function setTime(int $value);
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSeed() : int;
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getSpawn() : Vector3;
|
||||
|
||||
/**
|
||||
* @param Vector3 $pos
|
||||
*/
|
||||
public function setSpawn(Vector3 $pos);
|
||||
|
||||
/**
|
||||
* Returns the world difficulty. This will be one of the Level constants.
|
||||
* @return int
|
||||
*/
|
||||
public function getDifficulty() : int;
|
||||
|
||||
/**
|
||||
* Sets the world difficulty.
|
||||
* @param int $difficulty
|
||||
*/
|
||||
public function setDifficulty(int $difficulty);
|
||||
|
||||
/**
|
||||
* Returns the time in ticks to the next rain level change.
|
||||
* @return int
|
||||
*/
|
||||
public function getRainTime() : int;
|
||||
|
||||
/**
|
||||
* Sets the time in ticks to the next rain level change.
|
||||
* @param int $ticks
|
||||
*/
|
||||
public function setRainTime(int $ticks) : void;
|
||||
|
||||
/**
|
||||
* @return float 0.0 - 1.0
|
||||
*/
|
||||
public function getRainLevel() : float;
|
||||
|
||||
/**
|
||||
* @param float $level 0.0 - 1.0
|
||||
*/
|
||||
public function setRainLevel(float $level) : void;
|
||||
|
||||
/**
|
||||
* Returns the time in ticks to the next lightning level change.
|
||||
* @return int
|
||||
*/
|
||||
public function getLightningTime() : int;
|
||||
|
||||
/**
|
||||
* Sets the time in ticks to the next lightning level change.
|
||||
* @param int $ticks
|
||||
*/
|
||||
public function setLightningTime(int $ticks) : void;
|
||||
|
||||
/**
|
||||
* @return float 0.0 - 1.0
|
||||
*/
|
||||
public function getLightningLevel() : float;
|
||||
|
||||
/**
|
||||
* @param float $level 0.0 - 1.0
|
||||
*/
|
||||
public function setLightningLevel(float $level) : void;
|
||||
|
||||
/**
|
||||
* Performs garbage collection in the level provider, such as cleaning up regions in Region-based worlds.
|
||||
*/
|
||||
public function doGarbageCollection();
|
||||
|
||||
/**
|
||||
* Saves information about the level state, such as weather, time, etc.
|
||||
* Returns information about the world
|
||||
*
|
||||
* @return LevelData
|
||||
*/
|
||||
public function saveLevelData();
|
||||
public function getLevelData() : LevelData;
|
||||
|
||||
/**
|
||||
* Performs cleanups necessary when the level provider is closed and no longer needed.
|
||||
|
100
src/pocketmine/level/format/io/data/BaseNbtLevelData.php
Normal file
100
src/pocketmine/level/format/io/data/BaseNbtLevelData.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\level\format\io\data;
|
||||
|
||||
use pocketmine\level\format\io\LevelData;
|
||||
use pocketmine\level\LevelException;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
|
||||
abstract class BaseNbtLevelData implements LevelData{
|
||||
|
||||
/** @var string */
|
||||
protected $dataPath;
|
||||
|
||||
/** @var CompoundTag */
|
||||
protected $compoundTag;
|
||||
|
||||
public function __construct(string $dataPath){
|
||||
$this->dataPath = $dataPath;
|
||||
|
||||
if(!file_exists($this->dataPath)){
|
||||
throw new LevelException("Level data not found at $dataPath");
|
||||
}
|
||||
|
||||
$this->compoundTag = $this->load();
|
||||
if($this->compoundTag === null){
|
||||
throw new LevelException("Invalid level data");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CompoundTag
|
||||
*/
|
||||
abstract protected function load() : ?CompoundTag;
|
||||
|
||||
abstract protected function fix() : void;
|
||||
|
||||
public function getCompoundTag() : CompoundTag{
|
||||
return $this->compoundTag;
|
||||
}
|
||||
|
||||
|
||||
/* The below are common between PC and PE */
|
||||
|
||||
public function getName() : string{
|
||||
return $this->compoundTag->getString("LevelName");
|
||||
}
|
||||
|
||||
public function getGenerator() : string{
|
||||
return $this->compoundTag->getString("generatorName", "DEFAULT");
|
||||
}
|
||||
|
||||
public function getGeneratorOptions() : array{
|
||||
return ["preset" => $this->compoundTag->getString("generatorOptions", "")];
|
||||
}
|
||||
|
||||
public function getSeed() : int{
|
||||
return $this->compoundTag->getLong("RandomSeed");
|
||||
}
|
||||
|
||||
public function getTime() : int{
|
||||
return $this->compoundTag->getLong("Time", 0, true);
|
||||
}
|
||||
|
||||
public function setTime(int $value) : void{
|
||||
$this->compoundTag->setLong("Time", $value, true); //some older PM worlds had this in the wrong format
|
||||
}
|
||||
|
||||
public function getSpawn() : Vector3{
|
||||
return new Vector3($this->compoundTag->getInt("SpawnX"), $this->compoundTag->getInt("SpawnY"), $this->compoundTag->getInt("SpawnZ"));
|
||||
}
|
||||
|
||||
public function setSpawn(Vector3 $pos) : void{
|
||||
$this->compoundTag->setInt("SpawnX", $pos->getFloorX());
|
||||
$this->compoundTag->setInt("SpawnY", $pos->getFloorY());
|
||||
$this->compoundTag->setInt("SpawnZ", $pos->getFloorZ());
|
||||
}
|
||||
|
||||
}
|
193
src/pocketmine/level/format/io/data/BedrockLevelData.php
Normal file
193
src/pocketmine/level/format/io/data/BedrockLevelData.php
Normal file
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\level\format\io\data;
|
||||
|
||||
use pocketmine\level\format\io\BaseLevelProvider;
|
||||
use pocketmine\level\generator\Flat;
|
||||
use pocketmine\level\generator\GeneratorManager;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\LevelException;
|
||||
use pocketmine\nbt\LittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\LongTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\utils\Binary;
|
||||
|
||||
class BedrockLevelData extends BaseNbtLevelData{
|
||||
|
||||
public const CURRENT_STORAGE_VERSION = 6;
|
||||
|
||||
public const GENERATOR_LIMITED = 0;
|
||||
public const GENERATOR_INFINITE = 1;
|
||||
public const GENERATOR_FLAT = 2;
|
||||
|
||||
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []){
|
||||
switch($generator){
|
||||
case Flat::class:
|
||||
$generatorType = self::GENERATOR_FLAT;
|
||||
break;
|
||||
default:
|
||||
$generatorType = self::GENERATOR_INFINITE;
|
||||
//TODO: add support for limited worlds
|
||||
}
|
||||
|
||||
$levelData = new CompoundTag("", [
|
||||
//Vanilla fields
|
||||
new IntTag("DayCycleStopTime", -1),
|
||||
new IntTag("Difficulty", Level::getDifficultyFromString((string) ($options["difficulty"] ?? "normal"))),
|
||||
new ByteTag("ForceGameType", 0),
|
||||
new IntTag("GameType", 0),
|
||||
new IntTag("Generator", $generatorType),
|
||||
new LongTag("LastPlayed", time()),
|
||||
new StringTag("LevelName", $name),
|
||||
new IntTag("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL),
|
||||
//new IntTag("Platform", 2), //TODO: find out what the possible values are for
|
||||
new LongTag("RandomSeed", $seed),
|
||||
new IntTag("SpawnX", 0),
|
||||
new IntTag("SpawnY", 32767),
|
||||
new IntTag("SpawnZ", 0),
|
||||
new IntTag("StorageVersion", self::CURRENT_STORAGE_VERSION),
|
||||
new LongTag("Time", 0),
|
||||
new ByteTag("eduLevel", 0),
|
||||
new ByteTag("falldamage", 1),
|
||||
new ByteTag("firedamage", 1),
|
||||
new ByteTag("hasBeenLoadedInCreative", 1), //badly named, this actually determines whether achievements can be earned in this world...
|
||||
new ByteTag("immutableWorld", 0),
|
||||
new FloatTag("lightningLevel", 0.0),
|
||||
new IntTag("lightningTime", 0),
|
||||
new ByteTag("pvp", 1),
|
||||
new FloatTag("rainLevel", 0.0),
|
||||
new IntTag("rainTime", 0),
|
||||
new ByteTag("spawnMobs", 1),
|
||||
new ByteTag("texturePacksRequired", 0), //TODO
|
||||
|
||||
//Additional PocketMine-MP fields
|
||||
new CompoundTag("GameRules", []),
|
||||
new ByteTag("hardcore", ($options["hardcore"] ?? false) === true ? 1 : 0),
|
||||
new StringTag("generatorName", GeneratorManager::getGeneratorName($generator)),
|
||||
new StringTag("generatorOptions", $options["preset"] ?? "")
|
||||
]);
|
||||
|
||||
$nbt = new LittleEndianNBTStream();
|
||||
$buffer = $nbt->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 LittleEndianNBTStream();
|
||||
$levelData = $nbt->read(substr(file_get_contents($this->dataPath), 8));
|
||||
if($levelData instanceof CompoundTag){
|
||||
$version = $levelData->getInt("StorageVersion", INT32_MAX, true);
|
||||
if($version > self::CURRENT_STORAGE_VERSION){
|
||||
throw new LevelException("Specified LevelDB world format version ($version) is not supported by " . \pocketmine\NAME);
|
||||
}
|
||||
|
||||
return $levelData;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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 LevelException("Limited worlds are not currently supported");
|
||||
default:
|
||||
throw new LevelException("Unknown LevelDB world format type, this level cannot be loaded");
|
||||
}
|
||||
}else{
|
||||
$this->compoundTag->setString("generatorName", "default");
|
||||
}
|
||||
}elseif(($generatorName = BaseLevelProvider::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 LittleEndianNBTStream();
|
||||
$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);
|
||||
}
|
||||
}
|
148
src/pocketmine/level/format/io/data/JavaLevelData.php
Normal file
148
src/pocketmine/level/format/io/data/JavaLevelData.php
Normal file
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\level\format\io\data;
|
||||
|
||||
use pocketmine\level\format\io\BaseLevelProvider;
|
||||
use pocketmine\level\generator\GeneratorManager;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\nbt\BigEndianNBTStream;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\LongTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
|
||||
class JavaLevelData extends BaseNbtLevelData{
|
||||
|
||||
public static function generate(string $path, string $name, int $seed, string $generator, array $options = [], int $version = 19133){
|
||||
//TODO, add extra details
|
||||
$levelData = new CompoundTag("Data", [
|
||||
new ByteTag("hardcore", ($options["hardcore"] ?? false) === true ? 1 : 0),
|
||||
new ByteTag("Difficulty", Level::getDifficultyFromString((string) ($options["difficulty"] ?? "normal"))),
|
||||
new ByteTag("initialized", 1),
|
||||
new IntTag("GameType", 0),
|
||||
new IntTag("generatorVersion", 1), //2 in MCPE
|
||||
new IntTag("SpawnX", 256),
|
||||
new IntTag("SpawnY", 70),
|
||||
new IntTag("SpawnZ", 256),
|
||||
new IntTag("version", $version),
|
||||
new IntTag("DayTime", 0),
|
||||
new LongTag("LastPlayed", (int) (microtime(true) * 1000)),
|
||||
new LongTag("RandomSeed", $seed),
|
||||
new LongTag("SizeOnDisk", 0),
|
||||
new LongTag("Time", 0),
|
||||
new StringTag("generatorName", GeneratorManager::getGeneratorName($generator)),
|
||||
new StringTag("generatorOptions", $options["preset"] ?? ""),
|
||||
new StringTag("LevelName", $name),
|
||||
new CompoundTag("GameRules", [])
|
||||
]);
|
||||
$nbt = new BigEndianNBTStream();
|
||||
$buffer = $nbt->writeCompressed(new CompoundTag("", [
|
||||
$levelData
|
||||
]));
|
||||
file_put_contents($path . "level.dat", $buffer);
|
||||
}
|
||||
|
||||
protected function load() : ?CompoundTag{
|
||||
$nbt = new BigEndianNBTStream();
|
||||
$levelData = $nbt->readCompressed(file_get_contents($this->dataPath));
|
||||
if($levelData instanceof CompoundTag and $levelData->hasTag("Data", CompoundTag::class)){
|
||||
return $levelData->getCompoundTag("Data");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function fix() : void{
|
||||
if(!$this->compoundTag->hasTag("generatorName", StringTag::class)){
|
||||
$this->compoundTag->setString("generatorName", "default", true);
|
||||
}elseif(($generatorName = BaseLevelProvider::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{
|
||||
$nbt = new BigEndianNBTStream();
|
||||
$this->compoundTag->setName("Data");
|
||||
$buffer = $nbt->writeCompressed(new CompoundTag("", [
|
||||
$this->compoundTag
|
||||
]));
|
||||
file_put_contents($this->dataPath, $buffer);
|
||||
}
|
||||
|
||||
|
||||
public function getDifficulty() : int{
|
||||
return $this->compoundTag->getByte("Difficulty", Level::DIFFICULTY_NORMAL);
|
||||
}
|
||||
|
||||
public function setDifficulty(int $difficulty) : void{
|
||||
$this->compoundTag->setByte("Difficulty", $difficulty);
|
||||
}
|
||||
|
||||
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{
|
||||
if($this->compoundTag->hasTag("rainLevel", FloatTag::class)){ //PocketMine/MCPE
|
||||
return $this->compoundTag->getFloat("rainLevel");
|
||||
}
|
||||
|
||||
return (float) $this->compoundTag->getByte("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
|
||||
}
|
||||
|
||||
public function getLightningTime() : int{
|
||||
return $this->compoundTag->getInt("thunderTime", 0);
|
||||
}
|
||||
|
||||
public function setLightningTime(int $ticks) : void{
|
||||
$this->compoundTag->setInt("thunderTime", $ticks);
|
||||
}
|
||||
|
||||
public function getLightningLevel() : float{
|
||||
if($this->compoundTag->hasTag("lightningLevel", FloatTag::class)){ //PocketMine/MCPE
|
||||
return $this->compoundTag->getFloat("lightningLevel");
|
||||
}
|
||||
|
||||
return (float) $this->compoundTag->getByte("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
|
||||
}
|
||||
}
|
@ -26,17 +26,14 @@ namespace pocketmine\level\format\io\leveldb;
|
||||
use pocketmine\level\format\Chunk;
|
||||
use pocketmine\level\format\io\BaseLevelProvider;
|
||||
use pocketmine\level\format\io\ChunkUtils;
|
||||
use pocketmine\level\format\io\data\BedrockLevelData;
|
||||
use pocketmine\level\format\io\exception\UnsupportedChunkFormatException;
|
||||
use pocketmine\level\format\io\LevelData;
|
||||
use pocketmine\level\format\SubChunk;
|
||||
use pocketmine\level\generator\Flat;
|
||||
use pocketmine\level\generator\GeneratorManager;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\LevelException;
|
||||
use pocketmine\nbt\LittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\{
|
||||
ByteTag, CompoundTag, FloatTag, IntTag, LongTag, StringTag
|
||||
};
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
|
||||
@ -65,11 +62,6 @@ class LevelDB extends BaseLevelProvider{
|
||||
|
||||
public const ENTRY_FLAT_WORLD_LAYERS = "game_flatworldlayers";
|
||||
|
||||
public const GENERATOR_LIMITED = 0;
|
||||
public const GENERATOR_INFINITE = 1;
|
||||
public const GENERATOR_FLAT = 2;
|
||||
|
||||
public const CURRENT_STORAGE_VERSION = 6; //Current MCPE level format version
|
||||
public const CURRENT_LEVEL_CHUNK_VERSION = 7;
|
||||
public const CURRENT_LEVEL_SUBCHUNK_VERSION = 0;
|
||||
|
||||
@ -99,62 +91,8 @@ class LevelDB extends BaseLevelProvider{
|
||||
$this->db = self::createDB($path);
|
||||
}
|
||||
|
||||
protected function loadLevelData() : void{
|
||||
$levelDatPath = $this->getPath() . "level.dat";
|
||||
if(!file_exists($levelDatPath)){
|
||||
throw new LevelException("level.dat not found");
|
||||
}
|
||||
$nbt = new LittleEndianNBTStream();
|
||||
$levelData = $nbt->read(substr(file_get_contents($levelDatPath), 8));
|
||||
if($levelData instanceof CompoundTag){
|
||||
$this->levelData = $levelData;
|
||||
}else{
|
||||
throw new LevelException("Invalid level.dat");
|
||||
}
|
||||
|
||||
$version = $this->levelData->getInt("StorageVersion", INT32_MAX, true);
|
||||
if($version > self::CURRENT_STORAGE_VERSION){
|
||||
throw new LevelException("Specified LevelDB world format version ($version) is not supported by " . \pocketmine\NAME);
|
||||
}
|
||||
}
|
||||
|
||||
protected function fixLevelData() : void{
|
||||
$db = self::createDB($this->path);
|
||||
|
||||
if(!$this->levelData->hasTag("generatorName", StringTag::class)){
|
||||
if($this->levelData->hasTag("Generator", IntTag::class)){
|
||||
switch($this->levelData->getInt("Generator")){ //Detect correct generator from MCPE data
|
||||
case self::GENERATOR_FLAT:
|
||||
$this->levelData->setString("generatorName", "flat");
|
||||
if(($layers = $db->get(self::ENTRY_FLAT_WORLD_LAYERS)) !== false){ //Detect existing custom flat layers
|
||||
$layers = trim($layers, "[]");
|
||||
}else{
|
||||
$layers = "7,3,3,2";
|
||||
}
|
||||
$this->levelData->setString("generatorOptions", "2;" . $layers . ";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->levelData->setString("generatorName", "default");
|
||||
$this->levelData->setString("generatorOptions", "");
|
||||
break;
|
||||
case self::GENERATOR_LIMITED:
|
||||
throw new LevelException("Limited worlds are not currently supported");
|
||||
default:
|
||||
throw new LevelException("Unknown LevelDB world format type, this level cannot be loaded");
|
||||
}
|
||||
}else{
|
||||
$this->levelData->setString("generatorName", "default");
|
||||
}
|
||||
}elseif(($generatorName = self::hackyFixForGeneratorClasspathInLevelDat($this->levelData->getString("generatorName"))) !== null){
|
||||
$this->levelData->setString("generatorName", $generatorName);
|
||||
}
|
||||
|
||||
if(!$this->levelData->hasTag("generatorOptions", StringTag::class)){
|
||||
$this->levelData->setString("generatorOptions", "");
|
||||
}
|
||||
|
||||
$db->close();
|
||||
protected function loadLevelData() : LevelData{
|
||||
return new BedrockLevelData($this->getPath() . "level.dat");
|
||||
}
|
||||
|
||||
public function getWorldHeight() : int{
|
||||
@ -172,130 +110,7 @@ class LevelDB extends BaseLevelProvider{
|
||||
mkdir($path . "/db", 0777, true);
|
||||
}
|
||||
|
||||
switch($generator){
|
||||
case Flat::class:
|
||||
$generatorType = self::GENERATOR_FLAT;
|
||||
break;
|
||||
default:
|
||||
$generatorType = self::GENERATOR_INFINITE;
|
||||
//TODO: add support for limited worlds
|
||||
}
|
||||
|
||||
$levelData = new CompoundTag("", [
|
||||
//Vanilla fields
|
||||
new IntTag("DayCycleStopTime", -1),
|
||||
new IntTag("Difficulty", Level::getDifficultyFromString((string) ($options["difficulty"] ?? "normal"))),
|
||||
new ByteTag("ForceGameType", 0),
|
||||
new IntTag("GameType", 0),
|
||||
new IntTag("Generator", $generatorType),
|
||||
new LongTag("LastPlayed", time()),
|
||||
new StringTag("LevelName", $name),
|
||||
new IntTag("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL),
|
||||
//new IntTag("Platform", 2), //TODO: find out what the possible values are for
|
||||
new LongTag("RandomSeed", $seed),
|
||||
new IntTag("SpawnX", 0),
|
||||
new IntTag("SpawnY", 32767),
|
||||
new IntTag("SpawnZ", 0),
|
||||
new IntTag("StorageVersion", self::CURRENT_STORAGE_VERSION),
|
||||
new LongTag("Time", 0),
|
||||
new ByteTag("eduLevel", 0),
|
||||
new ByteTag("falldamage", 1),
|
||||
new ByteTag("firedamage", 1),
|
||||
new ByteTag("hasBeenLoadedInCreative", 1), //badly named, this actually determines whether achievements can be earned in this world...
|
||||
new ByteTag("immutableWorld", 0),
|
||||
new FloatTag("lightningLevel", 0.0),
|
||||
new IntTag("lightningTime", 0),
|
||||
new ByteTag("pvp", 1),
|
||||
new FloatTag("rainLevel", 0.0),
|
||||
new IntTag("rainTime", 0),
|
||||
new ByteTag("spawnMobs", 1),
|
||||
new ByteTag("texturePacksRequired", 0), //TODO
|
||||
|
||||
//Additional PocketMine-MP fields
|
||||
new CompoundTag("GameRules", []),
|
||||
new ByteTag("hardcore", ($options["hardcore"] ?? false) === true ? 1 : 0),
|
||||
new StringTag("generatorName", GeneratorManager::getGeneratorName($generator)),
|
||||
new StringTag("generatorOptions", $options["preset"] ?? "")
|
||||
]);
|
||||
|
||||
$nbt = new LittleEndianNBTStream();
|
||||
$buffer = $nbt->write($levelData);
|
||||
file_put_contents($path . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer);
|
||||
|
||||
|
||||
$db = self::createDB($path);
|
||||
|
||||
if($generatorType === self::GENERATOR_FLAT and isset($options["preset"])){
|
||||
$layers = explode(";", $options["preset"])[1] ?? "";
|
||||
if($layers !== ""){
|
||||
$out = "[";
|
||||
foreach(Flat::parseLayers($layers) as $result){
|
||||
$out .= $result[0] . ","; //only id, meta will unfortunately not survive :(
|
||||
}
|
||||
$out = rtrim($out, ",") . "]"; //remove trailing comma
|
||||
$db->put(self::ENTRY_FLAT_WORLD_LAYERS, $out); //Add vanilla flatworld layers to allow terrain generation by MCPE to continue seamlessly
|
||||
}
|
||||
}
|
||||
|
||||
$db->close();
|
||||
|
||||
}
|
||||
|
||||
public function saveLevelData(){
|
||||
$this->levelData->setInt("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL);
|
||||
$this->levelData->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION);
|
||||
|
||||
$nbt = new LittleEndianNBTStream();
|
||||
$buffer = $nbt->write($this->levelData);
|
||||
file_put_contents($this->getPath() . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer);
|
||||
}
|
||||
|
||||
public function getGenerator() : string{
|
||||
return $this->levelData->getString("generatorName", "");
|
||||
}
|
||||
|
||||
public function getGeneratorOptions() : array{
|
||||
return ["preset" => $this->levelData->getString("generatorOptions", "")];
|
||||
}
|
||||
|
||||
public function getDifficulty() : int{
|
||||
return $this->levelData->getInt("Difficulty", Level::DIFFICULTY_NORMAL);
|
||||
}
|
||||
|
||||
public function setDifficulty(int $difficulty){
|
||||
$this->levelData->setInt("Difficulty", $difficulty); //yes, this is intended! (in PE: int, PC: byte)
|
||||
}
|
||||
|
||||
public function getRainTime() : int{
|
||||
return $this->levelData->getInt("rainTime", 0);
|
||||
}
|
||||
|
||||
public function setRainTime(int $ticks) : void{
|
||||
$this->levelData->setInt("rainTime", $ticks);
|
||||
}
|
||||
|
||||
public function getRainLevel() : float{
|
||||
return $this->levelData->getFloat("rainLevel", 0.0);
|
||||
}
|
||||
|
||||
public function setRainLevel(float $level) : void{
|
||||
$this->levelData->setFloat("rainLevel", $level);
|
||||
}
|
||||
|
||||
public function getLightningTime() : int{
|
||||
return $this->levelData->getInt("lightningTime", 0);
|
||||
}
|
||||
|
||||
public function setLightningTime(int $ticks) : void{
|
||||
$this->levelData->setInt("lightningTime", $ticks);
|
||||
}
|
||||
|
||||
public function getLightningLevel() : float{
|
||||
return $this->levelData->getFloat("lightningLevel", 0.0);
|
||||
}
|
||||
|
||||
public function setLightningLevel(float $level) : void{
|
||||
$this->levelData->setFloat("lightningLevel", $level);
|
||||
BedrockLevelData::generate($path, $name, $seed, $generator, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,16 +25,9 @@ namespace pocketmine\level\format\io\region;
|
||||
|
||||
use pocketmine\level\format\Chunk;
|
||||
use pocketmine\level\format\io\BaseLevelProvider;
|
||||
use pocketmine\level\generator\GeneratorManager;
|
||||
use pocketmine\level\format\io\data\JavaLevelData;
|
||||
use pocketmine\level\format\io\LevelData;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\LevelException;
|
||||
use pocketmine\nbt\BigEndianNBTStream;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\LongTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\utils\MainLogger;
|
||||
|
||||
abstract class RegionLevelProvider extends BaseLevelProvider{
|
||||
@ -79,128 +72,15 @@ abstract class RegionLevelProvider extends BaseLevelProvider{
|
||||
if(!file_exists($path . "/region")){
|
||||
mkdir($path . "/region", 0777);
|
||||
}
|
||||
//TODO, add extra details
|
||||
$levelData = new CompoundTag("Data", [
|
||||
new ByteTag("hardcore", ($options["hardcore"] ?? false) === true ? 1 : 0),
|
||||
new ByteTag("Difficulty", Level::getDifficultyFromString((string) ($options["difficulty"] ?? "normal"))),
|
||||
new ByteTag("initialized", 1),
|
||||
new IntTag("GameType", 0),
|
||||
new IntTag("generatorVersion", 1), //2 in MCPE
|
||||
new IntTag("SpawnX", 256),
|
||||
new IntTag("SpawnY", 70),
|
||||
new IntTag("SpawnZ", 256),
|
||||
new IntTag("version", static::getPcWorldFormatVersion()),
|
||||
new IntTag("DayTime", 0),
|
||||
new LongTag("LastPlayed", (int) (microtime(true) * 1000)),
|
||||
new LongTag("RandomSeed", $seed),
|
||||
new LongTag("SizeOnDisk", 0),
|
||||
new LongTag("Time", 0),
|
||||
new StringTag("generatorName", GeneratorManager::getGeneratorName($generator)),
|
||||
new StringTag("generatorOptions", $options["preset"] ?? ""),
|
||||
new StringTag("LevelName", $name),
|
||||
new CompoundTag("GameRules", [])
|
||||
]);
|
||||
$nbt = new BigEndianNBTStream();
|
||||
$buffer = $nbt->writeCompressed(new CompoundTag("", [
|
||||
$levelData
|
||||
]));
|
||||
file_put_contents($path . "level.dat", $buffer);
|
||||
|
||||
JavaLevelData::generate($path, $name, $seed, $generator, $options, static::getPcWorldFormatVersion());
|
||||
}
|
||||
|
||||
/** @var RegionLoader[] */
|
||||
protected $regions = [];
|
||||
|
||||
protected function loadLevelData() : void{
|
||||
$levelDatPath = $this->getPath() . "level.dat";
|
||||
if(!file_exists($levelDatPath)){
|
||||
throw new LevelException("level.dat not found");
|
||||
}
|
||||
$nbt = new BigEndianNBTStream();
|
||||
$levelData = $nbt->readCompressed(file_get_contents($levelDatPath));
|
||||
|
||||
if(!($levelData instanceof CompoundTag) or !$levelData->hasTag("Data", CompoundTag::class)){
|
||||
throw new LevelException("Invalid level.dat");
|
||||
}
|
||||
|
||||
$this->levelData = $levelData->getCompoundTag("Data");
|
||||
}
|
||||
|
||||
protected function fixLevelData() : void{
|
||||
if(!$this->levelData->hasTag("generatorName", StringTag::class)){
|
||||
$this->levelData->setString("generatorName", "default", true);
|
||||
}elseif(($generatorName = self::hackyFixForGeneratorClasspathInLevelDat($this->levelData->getString("generatorName"))) !== null){
|
||||
$this->levelData->setString("generatorName", $generatorName);
|
||||
}
|
||||
|
||||
if(!$this->levelData->hasTag("generatorOptions", StringTag::class)){
|
||||
$this->levelData->setString("generatorOptions", "");
|
||||
}
|
||||
}
|
||||
|
||||
public function saveLevelData(){
|
||||
$nbt = new BigEndianNBTStream();
|
||||
$buffer = $nbt->writeCompressed(new CompoundTag("", [
|
||||
$this->levelData
|
||||
]));
|
||||
file_put_contents($this->getPath() . "level.dat", $buffer);
|
||||
}
|
||||
|
||||
public function getGenerator() : string{
|
||||
return $this->levelData->getString("generatorName", "DEFAULT");
|
||||
}
|
||||
|
||||
public function getGeneratorOptions() : array{
|
||||
return ["preset" => $this->levelData->getString("generatorOptions", "")];
|
||||
}
|
||||
|
||||
public function getDifficulty() : int{
|
||||
return $this->levelData->getByte("Difficulty", Level::DIFFICULTY_NORMAL);
|
||||
}
|
||||
|
||||
public function setDifficulty(int $difficulty){
|
||||
$this->levelData->setByte("Difficulty", $difficulty);
|
||||
}
|
||||
|
||||
public function getRainTime() : int{
|
||||
return $this->levelData->getInt("rainTime", 0);
|
||||
}
|
||||
|
||||
public function setRainTime(int $ticks) : void{
|
||||
$this->levelData->setInt("rainTime", $ticks);
|
||||
}
|
||||
|
||||
public function getRainLevel() : float{
|
||||
if($this->levelData->hasTag("rainLevel", FloatTag::class)){ //PocketMine/MCPE
|
||||
return $this->levelData->getFloat("rainLevel");
|
||||
}
|
||||
|
||||
return (float) $this->levelData->getByte("raining", 0); //PC vanilla
|
||||
}
|
||||
|
||||
public function setRainLevel(float $level) : void{
|
||||
$this->levelData->setFloat("rainLevel", $level); //PocketMine/MCPE
|
||||
$this->levelData->setByte("raining", (int) ceil($level)); //PC vanilla
|
||||
}
|
||||
|
||||
public function getLightningTime() : int{
|
||||
return $this->levelData->getInt("thunderTime", 0);
|
||||
}
|
||||
|
||||
public function setLightningTime(int $ticks) : void{
|
||||
$this->levelData->setInt("thunderTime", $ticks);
|
||||
}
|
||||
|
||||
public function getLightningLevel() : float{
|
||||
if($this->levelData->hasTag("lightningLevel", FloatTag::class)){ //PocketMine/MCPE
|
||||
return $this->levelData->getFloat("lightningLevel");
|
||||
}
|
||||
|
||||
return (float) $this->levelData->getByte("thundering", 0); //PC vanilla
|
||||
}
|
||||
|
||||
public function setLightningLevel(float $level) : void{
|
||||
$this->levelData->setFloat("lightningLevel", $level); //PocketMine/MCPE
|
||||
$this->levelData->setByte("thundering", (int) ceil($level)); //PC vanilla
|
||||
protected function loadLevelData() : LevelData{
|
||||
return new JavaLevelData($this->getPath() . "level.dat");
|
||||
}
|
||||
|
||||
public function doGarbageCollection(){
|
||||
|
Loading…
x
Reference in New Issue
Block a user