GenisysPro  for Minecraft PE/Windows 10 v1.1.x
Feature-rich server software for Minecraft PE and Windows 10 Edition
LevelDB Class Reference

Public Member Functions

 __construct (Level $level, string $path)
 
 getWorldHeight ()
 
 saveLevelData ()
 
 unloadChunks ()
 
 getGenerator ()
 
 getGeneratorOptions ()
 
 getLoadedChunks ()
 
 isChunkLoaded (int $x, int $z)
 
 saveChunks ()
 
 loadChunk (int $chunkX, int $chunkZ, bool $create=false)
 
 unloadChunk (int $x, int $z, bool $safe=true)
 
 saveChunk (int $chunkX, int $chunkZ)
 
 getChunk (int $chunkX, int $chunkZ, bool $create=false)
 
 getDatabase ()
 
 setChunk (int $chunkX, int $chunkZ, Chunk $chunk)
 
 isChunkGenerated (int $chunkX, int $chunkZ)
 
 isChunkPopulated (int $chunkX, int $chunkZ)
 
 close ()
 
- Public Member Functions inherited from BaseLevelProvider
 __construct (Level $level, string $path)
 
 getPath ()
 
 getServer ()
 
 getLevel ()
 
 getName ()
 
 getTime ()
 
 setTime ($value)
 
 getSeed ()
 
 setSeed ($value)
 
 getSpawn ()
 
 setSpawn (Vector3 $pos)
 
 doGarbageCollection ()
 
 getLevelData ()
 
 saveLevelData ()
 
 requestChunkTask (int $x, int $z)
 

Static Public Member Functions

static getProviderName ()
 
static isValid (string $path)
 
static generate (string $path, string $name, $seed, string $generator, array $options=[])
 
static chunkIndex (int $chunkX, int $chunkZ)
 

Data Fields

const TAG_DATA_2D = "\x2d"
 
const TAG_DATA_2D_LEGACY = "\x2e"
 
const TAG_SUBCHUNK_PREFIX = "\x2f"
 
const TAG_LEGACY_TERRAIN = "0"
 
const TAG_BLOCK_ENTITY = "1"
 
const TAG_ENTITY = "2"
 
const TAG_PENDING_TICK = "3"
 
const TAG_BLOCK_EXTRA_DATA = "4"
 
const TAG_BIOME_STATE = "5"
 
const TAG_VERSION = "v"
 
const ENTRY_FLAT_WORLD_LAYERS = "game_flatworldlayers"
 
const GENERATOR_LIMITED = 0
 
const GENERATOR_INFINITE = 1
 
const GENERATOR_FLAT = 2
 
const CURRENT_STORAGE_VERSION = 5
 

Protected Attributes

 $chunks = []
 
 $db
 
- Protected Attributes inherited from BaseLevelProvider
 $level
 
 $path
 
 $levelData
 
 $asyncChunkRequest = false
 

Constructor & Destructor Documentation

◆ __construct()

__construct ( Level  $level,
string  $path 
)

LevelDB constructor.

Parameters
Level$level
string$path

Implements LevelProvider.

75  {
76  $this->level = $level;
77  $this->path = $path;
78  if(!file_exists($this->path)){
79  mkdir($this->path, 0777, true);
80  }
81  $nbt = new NBT(NBT::LITTLE_ENDIAN);
82  $nbt->read(substr(file_get_contents($this->getPath() . "level.dat"), 8));
83  $levelData = $nbt->getData();
84  if($levelData instanceof CompoundTag){
85  $this->levelData = $levelData;
86  }else{
87  throw new LevelException("Invalid level.dat");
88  }
89 
90  $this->db = new \LevelDB($this->path . "/db", [
91  "compression" => LEVELDB_ZLIB_COMPRESSION
92  ]);
93 
94  if(isset($this->levelData->StorageVersion) and $this->levelData->StorageVersion->getValue() > self::CURRENT_STORAGE_VERSION){
95  throw new LevelException("Specified LevelDB world format version is newer than the version supported by the server");
96  }
97 
98  if(!isset($this->levelData->generatorName)){
99  if(isset($this->levelData->Generator)){
100  switch((int) $this->levelData->Generator->getValue()){ //Detect correct generator from MCPE data
101  case self::GENERATOR_FLAT:
102  $this->levelData->generatorName = new StringTag("generatorName", Generator::getGenerator("FLAT"));
103  if(($layers = $this->db->get(self::ENTRY_FLAT_WORLD_LAYERS)) !== false){ //Detect existing custom flat layers
104  $layers = trim($layers, "[]");
105  }else{
106  $layers = "7,3,3,2";
107  }
108  $this->levelData->generatorOptions = new StringTag("generatorOptions", "2;" . $layers . ";1");
109  break;
110  case self::GENERATOR_INFINITE:
111  //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)
112  $this->levelData->generatorName = new StringTag("generatorName", Generator::getGenerator("DEFAULT"));
113  $this->levelData->generatorOptions = new StringTag("generatorOptions", "");
114  break;
115  case self::GENERATOR_LIMITED:
116  throw new LevelException("Limited worlds are not currently supported");
117  default:
118  throw new LevelException("Unknown LevelDB world format type, this level cannot be loaded");
119  }
120  }else{
121  $this->levelData->generatorName = new StringTag("generatorName", Generator::getGenerator("DEFAULT"));
122  }
123  }
124 
125  if(!isset($this->levelData->generatorOptions)){
126  $this->levelData->generatorOptions = new StringTag("generatorOptions", "");
127  }
128  }

Member Function Documentation

◆ chunkIndex()

static chunkIndex ( int  $chunkX,
int  $chunkZ 
)
static
Parameters
int$chunkX
int$chunkZ
Returns
string
607  : string{
608  return Binary::writeLInt($chunkX) . Binary::writeLInt($chunkZ);
609  }

◆ close()

close ( )

Implements LevelProvider.

650  {
651  $this->unloadChunks();
652  $this->db->close();
653  $this->level = null;
654  }

◆ generate()

static generate ( string  $path,
string  $name,
  $seed,
string  $generator,
array  $options = [] 
)
static
Parameters
string$path
string$name
int | string$seed
string$generator
array$options

Implements LevelProvider.

160  {
161  if(!file_exists($path)){
162  mkdir($path, 0777, true);
163  }
164 
165  if(!file_exists($path . "/db")){
166  mkdir($path . "/db", 0777, true);
167  }
168 
169  switch($generator){
170  case Flat::class:
171  $generatorType = self::GENERATOR_FLAT;
172  break;
173  default:
174  $generatorType = self::GENERATOR_INFINITE;
175  //TODO: add support for limited worlds
176  }
177 
178  $levelData = new CompoundTag("", [
179  //Vanilla fields
180  "DayCycleStopTime" => new IntTag("DayCycleStopTime", -1),
181  "Difficulty" => new IntTag("Difficulty", 2),
182  "ForceGameType" => new ByteTag("ForceGameType", 0),
183  "GameType" => new IntTag("GameType", 0),
184  "Generator" => new IntTag("Generator", $generatorType),
185  "LastPlayed" => new LongTag("LastPlayed", time()),
186  "LevelName" => new StringTag("LevelName", $name),
187  "NetworkVersion" => new IntTag("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL),
188  //"Platform" => new IntTag("Platform", 2), //TODO: find out what the possible values are for
189  "RandomSeed" => new LongTag("RandomSeed", $seed),
190  "SpawnX" => new IntTag("SpawnX", 0),
191  "SpawnY" => new IntTag("SpawnY", 32767),
192  "SpawnZ" => new IntTag("SpawnZ", 0),
193  "StorageVersion" => new IntTag("StorageVersion", self::CURRENT_STORAGE_VERSION),
194  "Time" => new LongTag("Time", 0),
195  "eduLevel" => new ByteTag("eduLevel", 0),
196  "falldamage" => new ByteTag("falldamage", 1),
197  "firedamage" => new ByteTag("firedamage", 1),
198  "hasBeenLoadedInCreative" => new ByteTag("hasBeenLoadedInCreative", 1), //badly named, this actually determines whether achievements can be earned in this world...
199  "immutableWorld" => new ByteTag("immutableWorld", 0),
200  "lightningLevel" => new FloatTag("lightningLevel", 0.0),
201  "lightningTime" => new IntTag("lightningTime", 0),
202  "pvp" => new ByteTag("pvp", 1),
203  "rainLevel" => new FloatTag("rainLevel", 0.0),
204  "rainTime" => new IntTag("rainTime", 0),
205  "spawnMobs" => new ByteTag("spawnMobs", 1),
206  "texturePacksRequired" => new ByteTag("texturePacksRequired", 0), //TODO
207 
208  //Additional PocketMine-MP fields
209  "GameRules" => new CompoundTag("GameRules", []),
210  "hardcore" => new ByteTag("hardcore", 0),
211  "generatorName" => new StringTag("generatorName", Generator::getGeneratorName($generator)),
212  "generatorOptions" => new StringTag("generatorOptions", $options["preset"] ?? "")
213  ]);
214 
215  $nbt = new NBT(NBT::LITTLE_ENDIAN);
216  $nbt->setData($levelData);
217  $buffer = $nbt->write();
218  file_put_contents($path . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer);
219 
220 
221  $db = new \LevelDB($path . "/db", [
222  "compression" => LEVELDB_ZLIB_COMPRESSION
223  ]);
224 
225  if($generatorType === self::GENERATOR_FLAT and isset($options["preset"])){
226  $layers = explode(";", $options["preset"])[1] ?? "";
227  if($layers !== ""){
228  $out = "[";
229  foreach(Flat::parseLayers($layers) as $result){
230  $out .= $result[0] . ","; //only id, meta will unfortunately not survive :(
231  }
232  $out = rtrim($out, ",") . "]"; //remove trailing comma
233  $db->put(self::ENTRY_FLAT_WORLD_LAYERS, $out); //Add vanilla flatworld layers to allow terrain generation by MCPE to continue seamlessly
234  }
235  }
236 
237  $db->close();
238 
239  }

◆ getChunk()

getChunk ( int  $chunkX,
int  $chunkZ,
bool  $create = false 
)
Parameters
int$chunkX
int$chunkZ
bool$create
Returns
Chunk|null

Implements LevelProvider.

567  {
568  $index = Level::chunkHash($chunkX, $chunkZ);
569  if(isset($this->chunks[$index])){
570  return $this->chunks[$index];
571  }else{
572  $this->loadChunk($chunkX, $chunkZ, $create);
573 
574  return $this->chunks[$index] ?? null;
575  }
576  }

◆ getDatabase()

getDatabase ( )
Returns
581  {
582  return $this->db;
583  }

◆ getGenerator()

getGenerator ( )
Returns
string

Implements LevelProvider.

258  : string{
259  return $this->levelData["generatorName"];
260  }

◆ getGeneratorOptions()

getGeneratorOptions ( )
Returns
array

Implements LevelProvider.

265  : array{
266  return ["preset" => $this->levelData["generatorOptions"]];
267  }

◆ getLoadedChunks()

getLoadedChunks ( )
Returns
array

Implements LevelProvider.

272  : array{
273  return $this->chunks;
274  }

◆ getProviderName()

static getProviderName ( )
static
Returns
string

Implements LevelProvider.

133  : string{
134  return "leveldb";
135  }

◆ getWorldHeight()

getWorldHeight ( )
Returns
int

Implements LevelProvider.

140  : int{
141  return 256;
142  }

◆ isChunkGenerated()

isChunkGenerated ( int  $chunkX,
int  $chunkZ 
)
Parameters
int$chunkX
int$chunkZ
Returns
bool

Implements LevelProvider.

627  : bool{
628  if($this->chunkExists($chunkX, $chunkZ) and ($chunk = $this->getChunk($chunkX, $chunkZ, false)) !== null){
629  return true;
630  }
631 
632  return false;
633  }

◆ isChunkLoaded()

isChunkLoaded ( int  $x,
int  $z 
)
Parameters
int$x
int$z
Returns
bool

Implements LevelProvider.

282  : bool{
283  return isset($this->chunks[Level::chunkHash($x, $z)]);
284  }

◆ isChunkPopulated()

isChunkPopulated ( int  $chunkX,
int  $chunkZ 
)
Parameters
int$chunkX
int$chunkZ
Returns
bool

Implements LevelProvider.

641  : bool{
642  $chunk = $this->getChunk($chunkX, $chunkZ);
643  if($chunk instanceof Chunk){
644  return $chunk->isPopulated();
645  }else{
646  return false;
647  }
648  }

◆ isValid()

static isValid ( string  $path)
static
Parameters
string$path
Returns
bool

Implements LevelProvider.

149  : bool{
150  return file_exists($path . "/level.dat") and is_dir($path . "/db/");
151  }

◆ loadChunk()

loadChunk ( int  $chunkX,
int  $chunkZ,
bool  $create = false 
)
Parameters
int$chunkX
int$chunkZ
bool$create
Returns
bool

Implements LevelProvider.

299  : bool{
300  if(isset($this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)])){
301  return true;
302  }
303 
304  $this->level->timings->syncChunkLoadDataTimer->startTiming();
305  $chunk = $this->readChunk($chunkX, $chunkZ);
306  if($chunk === null and $create){
307  $chunk = Chunk::getEmptyChunk($chunkX, $chunkZ);
308  }
309  $this->level->timings->syncChunkLoadDataTimer->stopTiming();
310 
311  if($chunk !== null){
312  $this->chunks[$index] = $chunk;
313 
314  return true;
315  }else{
316  return false;
317  }
318  }

◆ saveChunk()

saveChunk ( int  $chunkX,
int  $chunkZ 
)
Parameters
int$chunkX
int$chunkZ
Returns
bool

Implements LevelProvider.

546  : bool{
547  if($this->isChunkLoaded($chunkX, $chunkZ)){
548  $chunk = $this->getChunk($chunkX, $chunkZ);
549  if(!$chunk->isGenerated()){
550  throw new \InvalidStateException("Cannot save un-generated chunk");
551  }
552  $this->writeChunk($chunk);
553 
554  return true;
555  }
556 
557  return false;
558  }

◆ saveChunks()

saveChunks ( )

Implements LevelProvider.

286  {
287  foreach($this->chunks as $chunk){
288  $this->saveChunk($chunk->getX(), $chunk->getZ());
289  }
290  }

◆ saveLevelData()

saveLevelData ( )
241  {
242  $nbt = new NBT(NBT::LITTLE_ENDIAN);
243  $nbt->setData($this->levelData);
244  $buffer = $nbt->write();
245  file_put_contents($this->getPath() . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer);
246  }

◆ setChunk()

setChunk ( int  $chunkX,
int  $chunkZ,
Chunk  $chunk 
)
Parameters
int$chunkX
int$chunkZ
Chunk$chunk

Implements LevelProvider.

590  {
591  $chunk->setX($chunkX);
592  $chunk->setZ($chunkZ);
593 
594  if(isset($this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)]) and $this->chunks[$index] !== $chunk){
595  $this->unloadChunk($chunkX, $chunkZ, false);
596  }
597 
598  $this->chunks[$index] = $chunk;
599  }

◆ unloadChunk()

unloadChunk ( int  $x,
int  $z,
bool  $safe = true 
)
Parameters
int$x
int$z
bool$safe
Returns
bool

Implements LevelProvider.

529  : bool{
530  $chunk = $this->chunks[$index = Level::chunkHash($x, $z)] ?? null;
531  if($chunk instanceof Chunk and $chunk->unload($safe)){
532  unset($this->chunks[$index]);
533 
534  return true;
535  }
536 
537  return false;
538  }

◆ unloadChunks()

unloadChunks ( )

Implements LevelProvider.

248  {
249  foreach($this->chunks as $chunk){
250  $this->unloadChunk($chunk->getX(), $chunk->getZ(), false);
251  }
252  $this->chunks = [];
253  }

Field Documentation

◆ $chunks

$chunks = []
protected

◆ $db

$db
protected

◆ CURRENT_STORAGE_VERSION

const CURRENT_STORAGE_VERSION = 5

◆ ENTRY_FLAT_WORLD_LAYERS

const ENTRY_FLAT_WORLD_LAYERS = "game_flatworldlayers"

◆ GENERATOR_FLAT

const GENERATOR_FLAT = 2

◆ GENERATOR_INFINITE

const GENERATOR_INFINITE = 1

◆ GENERATOR_LIMITED

const GENERATOR_LIMITED = 0

◆ TAG_BIOME_STATE

const TAG_BIOME_STATE = "5"

◆ TAG_BLOCK_ENTITY

const TAG_BLOCK_ENTITY = "1"

◆ TAG_BLOCK_EXTRA_DATA

const TAG_BLOCK_EXTRA_DATA = "4"

◆ TAG_DATA_2D

const TAG_DATA_2D = "\x2d"

◆ TAG_DATA_2D_LEGACY

const TAG_DATA_2D_LEGACY = "\x2e"

◆ TAG_ENTITY

const TAG_ENTITY = "2"

◆ TAG_LEGACY_TERRAIN

const TAG_LEGACY_TERRAIN = "0"

◆ TAG_PENDING_TICK

const TAG_PENDING_TICK = "3"

◆ TAG_SUBCHUNK_PREFIX

const TAG_SUBCHUNK_PREFIX = "\x2f"

◆ TAG_VERSION

const TAG_VERSION = "v"

The documentation for this class was generated from the following file: