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

Public Member Functions

 nbtSerialize (Chunk $chunk)
 
 nbtDeserialize (string $data)
 
 getWorldHeight ()
 
 getGenerator ()
 
 getGeneratorOptions ()
 
 getChunk (int $chunkX, int $chunkZ, bool $create=false)
 
 setChunk (int $chunkX, int $chunkZ, Chunk $chunk)
 
 saveChunk (int $chunkX, int $chunkZ)
 
 saveChunks ()
 
 loadChunk (int $chunkX, int $chunkZ, bool $create=false)
 
 unloadChunk (int $chunkX, int $chunkZ, bool $safe=true)
 
 unloadChunks ()
 
 isChunkLoaded (int $chunkX, int $chunkZ)
 
 isChunkGenerated (int $chunkX, int $chunkZ)
 
 isChunkPopulated (int $chunkX, int $chunkZ)
 
 getLoadedChunks ()
 
 doGarbageCollection ()
 
 getEmptyChunk (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 getRegionIndex (int $chunkX, int $chunkZ, &$x, &$z)
 

Data Fields

const REGION_FILE_EXTENSION = "mcr"
 

Protected Member Functions

 getRegion (int $x, int $z)
 
 loadRegion (int $x, int $z)
 

Protected Attributes

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

Member Function Documentation

◆ close()

close ( )

Implements LevelProvider.

525  {
526  $this->unloadChunks();
527  foreach($this->regions as $index => $region){
528  $region->close();
529  unset($this->regions[$index]);
530  }
531  $this->level = null;
532  }

◆ doGarbageCollection()

doGarbageCollection ( )

Implements LevelProvider.

474  {
475  $limit = time() - 300;
476  foreach($this->regions as $index => $region){
477  if($region->lastUsed <= $limit){
478  $region->close();
479  unset($this->regions[$index]);
480  }
481  }
482  }

◆ 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.

258  {
259  if(!file_exists($path)){
260  mkdir($path, 0777, true);
261  }
262 
263  if(!file_exists($path . "/region")){
264  mkdir($path . "/region", 0777);
265  }
266  //TODO, add extra details
267  $levelData = new CompoundTag("Data", [
268  "hardcore" => new ByteTag("hardcore", 0),
269  "initialized" => new ByteTag("initialized", 1),
270  "GameType" => new IntTag("GameType", 0),
271  "generatorVersion" => new IntTag("generatorVersion", 1), //2 in MCPE
272  "SpawnX" => new IntTag("SpawnX", 128),
273  "SpawnY" => new IntTag("SpawnY", 70),
274  "SpawnZ" => new IntTag("SpawnZ", 128),
275  "version" => new IntTag("version", 19133),
276  "DayTime" => new IntTag("DayTime", 0),
277  "LastPlayed" => new LongTag("LastPlayed", microtime(true) * 1000),
278  "RandomSeed" => new LongTag("RandomSeed", $seed),
279  "SizeOnDisk" => new LongTag("SizeOnDisk", 0),
280  "Time" => new LongTag("Time", 0),
281  "generatorName" => new StringTag("generatorName", Generator::getGeneratorName($generator)),
282  "generatorOptions" => new StringTag("generatorOptions", isset($options["preset"]) ? $options["preset"] : ""),
283  "LevelName" => new StringTag("LevelName", $name),
284  "GameRules" => new CompoundTag("GameRules", [])
285  ]);
286  $nbt = new NBT(NBT::BIG_ENDIAN);
287  $nbt->setData(new CompoundTag("", [
288  "Data" => $levelData
289  ]));
290  $buffer = $nbt->writeCompressed();
291  file_put_contents($path . "level.dat", $buffer);
292  }

◆ getChunk()

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

Implements LevelProvider.

315  {
316  $index = Level::chunkHash($chunkX, $chunkZ);
317  if(isset($this->chunks[$index])){
318  return $this->chunks[$index];
319  }else{
320  $this->loadChunk($chunkX, $chunkZ, $create);
321 
322  return $this->chunks[$index] ?? null;
323  }
324  }

◆ getEmptyChunk()

getEmptyChunk ( int  $chunkX,
int  $chunkZ 
)
Parameters
int$chunkX
int$chunkZ
Returns
Chunk
501  {
502  return Chunk::getEmptyChunk($chunkX, $chunkZ);
503  }

◆ getGenerator()

getGenerator ( )
Returns
string

Implements LevelProvider.

297  : string{
298  return (string) $this->levelData["generatorName"];
299  }

◆ getGeneratorOptions()

getGeneratorOptions ( )
Returns
array

Implements LevelProvider.

304  : array{
305  return ["preset" => $this->levelData["generatorOptions"]];
306  }

◆ getLoadedChunks()

getLoadedChunks ( )
Returns
array

Implements LevelProvider.

470  : array{
471  return $this->chunks;
472  }

◆ getProviderName()

static getProviderName ( )
static
Returns
string

Implements LevelProvider.

212  : string{
213  return "mcregion";
214  }

◆ getRegion()

getRegion ( int  $x,
int  $z 
)
protected
Parameters
int$x
int$z
Returns
RegionLoader
511  {
512  return $this->regions[Level::chunkHash($x, $z)] ?? null;
513  }

◆ getRegionIndex()

static getRegionIndex ( int  $chunkX,
int  $chunkZ,
$x,
$z 
)
static
Parameters
int$chunkX
int$chunkZ
int&$x
int&$z
490  {
491  $x = $chunkX >> 5;
492  $z = $chunkZ >> 5;
493  }

◆ getWorldHeight()

getWorldHeight ( )
Returns
int

Implements LevelProvider.

219  : int{
220  //TODO: add world height options
221  return 128;
222  }

◆ isChunkGenerated()

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

Implements LevelProvider.

444  : bool{
445  if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) !== null){
446  return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32) and $this->getChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32, true)->isGenerated();
447  }
448 
449  return false;
450  }

◆ isChunkLoaded()

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

Implements LevelProvider.

434  : bool{
435  return isset($this->chunks[Level::chunkHash($chunkX, $chunkZ)]);
436  }

◆ isChunkPopulated()

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

Implements LevelProvider.

458  : bool{
459  $chunk = $this->getChunk($chunkX, $chunkZ);
460  if($chunk !== null){
461  return $chunk->isPopulated();
462  }else{
463  return false;
464  }
465  }

◆ isValid()

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

Implements LevelProvider.

229  : bool{
230  $isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/"));
231 
232  if($isValid){
233  $files = glob($path . "/region/*.mc*");
234  if(empty($files)){ //possible glob() issue on some systems
235  $files = array_filter(scandir($path . "/region/"), function($file){
236  return substr($file, strrpos($file, ".") + 1, 2) === "mc"; //region file
237  });
238  }
239 
240  foreach($files as $f){
241  if(substr($f, strrpos($f, ".") + 1) !== static::REGION_FILE_EXTENSION){
242  $isValid = false;
243  break;
244  }
245  }
246  }
247 
248  return $isValid;
249  }

◆ loadChunk()

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

PhpStrictTypeCheckingInspection

PhpStrictTypeCheckingInspection

Implements LevelProvider.

379  : bool{
380  $index = Level::chunkHash($chunkX, $chunkZ);
381  if(isset($this->chunks[$index])){
382  return true;
383  }
384  $regionX = $regionZ = null;
385  self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
387  $this->loadRegion($regionX, $regionZ);
388  $this->level->timings->syncChunkLoadDataTimer->startTiming();
390  $chunk = $this->getRegion($regionX, $regionZ)->readChunk($chunkX - $regionX * 32, $chunkZ - $regionZ * 32);
391  if($chunk === null and $create){
392  $chunk = $this->getEmptyChunk($chunkX, $chunkZ);
393  }
394  $this->level->timings->syncChunkLoadDataTimer->stopTiming();
395 
396  if($chunk !== null){
397  $this->chunks[$index] = $chunk;
398  return true;
399  }else{
400  return false;
401  }
402  }

◆ loadRegion()

loadRegion ( int  $x,
int  $z 
)
protected
Parameters
int$x
int$z
519  {
520  if(!isset($this->regions[$index = Level::chunkHash($x, $z)])){
521  $this->regions[$index] = new RegionLoader($this, $x, $z, static::REGION_FILE_EXTENSION);
522  }
523  }

◆ nbtDeserialize()

nbtDeserialize ( string  $data)
Parameters
string$data
Returns
Chunk|null
126  {
127  $nbt = new NBT(NBT::BIG_ENDIAN);
128  try{
129  $nbt->readCompressed($data, ZLIB_ENCODING_DEFLATE);
130 
131  $chunk = $nbt->getData();
132 
133  if(!isset($chunk->Level) or !($chunk->Level instanceof CompoundTag)){
134  throw new ChunkException("Invalid NBT format");
135  }
136 
137  $chunk = $chunk->Level;
138 
139  $subChunks = [];
140  $fullIds = isset($chunk->Blocks) ? $chunk->Blocks->getValue() : str_repeat("\x00", 32768);
141  $fullData = isset($chunk->Data) ? $chunk->Data->getValue() : (str_repeat("\x00", 16384));
142  $fullSkyLight = isset($chunk->SkyLight) ? $chunk->SkyLight->getValue() : str_repeat("\xff", 16384);
143  $fullBlockLight = isset($chunk->BlockLight) ? $chunk->BlockLight->getValue() : (str_repeat("\x00", 16384));
144 
145  for($y = 0; $y < 8; ++$y){
146  $offset = ($y << 4);
147  $ids = "";
148  for($i = 0; $i < 256; ++$i){
149  $ids .= substr($fullIds, $offset, 16);
150  $offset += 128;
151  }
152  $data = "";
153  $offset = ($y << 3);
154  for($i = 0; $i < 256; ++$i){
155  $data .= substr($fullData, $offset, 8);
156  $offset += 64;
157  }
158  $skyLight = "";
159  $offset = ($y << 3);
160  for($i = 0; $i < 256; ++$i){
161  $skyLight .= substr($fullSkyLight, $offset, 8);
162  $offset += 64;
163  }
164  $blockLight = "";
165  $offset = ($y << 3);
166  for($i = 0; $i < 256; ++$i){
167  $blockLight .= substr($fullBlockLight, $offset, 8);
168  $offset += 64;
169  }
170  $subChunks[$y] = new SubChunk($ids, $data, $skyLight, $blockLight);
171  }
172 
173  if(isset($chunk->BiomeColors)){
174  $biomeIds = ChunkUtils::convertBiomeColors($chunk->BiomeColors->getValue()); //Convert back to original format
175  }elseif(isset($chunk->Biomes)){
176  $biomeIds = $chunk->Biomes->getValue();
177  }else{
178  $biomeIds = "";
179  }
180 
181  $heightMap = [];
182  if(isset($chunk->HeightMap)){
183  if($chunk->HeightMap instanceof ByteArrayTag){
184  $heightMap = array_values(unpack("C*", $chunk->HeightMap->getValue()));
185  }elseif($chunk->HeightMap instanceof IntArrayTag){
186  $heightMap = $chunk->HeightMap->getValue(); #blameshoghicp
187  }
188  }
189 
190  $result = new Chunk(
191  $chunk["xPos"],
192  $chunk["zPos"],
193  $subChunks,
194  isset($chunk->Entities) ? $chunk->Entities->getValue() : [],
195  isset($chunk->TileEntities) ? $chunk->TileEntities->getValue() : [],
196  $biomeIds,
197  $heightMap
198  );
199  $result->setLightPopulated(isset($chunk->LightPopulated) ? ((bool) $chunk->LightPopulated->getValue()) : false);
200  $result->setPopulated(isset($chunk->TerrainPopulated) ? ((bool) $chunk->TerrainPopulated->getValue()) : false);
201  $result->setGenerated(true);
202  return $result;
203  }catch(\Throwable $e){
204  MainLogger::getLogger()->logException($e);
205  return null;
206  }
207  }

◆ nbtSerialize()

nbtSerialize ( Chunk  $chunk)
Parameters
Chunk$chunk
Returns
string
55  : string{
56  $nbt = new CompoundTag("Level", []);
57  $nbt->xPos = new IntTag("xPos", $chunk->getX());
58  $nbt->zPos = new IntTag("zPos", $chunk->getZ());
59 
60  $nbt->V = new ByteTag("V", 0); //guess
61  $nbt->LastUpdate = new LongTag("LastUpdate", 0); //TODO
62  $nbt->InhabitedTime = new LongTag("InhabitedTime", 0); //TODO
63  $nbt->TerrainPopulated = new ByteTag("TerrainPopulated", $chunk->isPopulated());
64  $nbt->LightPopulated = new ByteTag("LightPopulated", $chunk->isLightPopulated());
65 
66  $ids = "";
67  $data = "";
68  $skyLight = "";
69  $blockLight = "";
70  $subChunks = $chunk->getSubChunks();
71  for($x = 0; $x < 16; ++$x){
72  for($z = 0; $z < 16; ++$z){
73  for($y = 0; $y < 8; ++$y){
74  $subChunk = $subChunks[$y];
75  $ids .= $subChunk->getBlockIdColumn($x, $z);
76  $data .= $subChunk->getBlockDataColumn($x, $z);
77  $skyLight .= $subChunk->getSkyLightColumn($x, $z);
78  $blockLight .= $subChunk->getBlockLightColumn($x, $z);
79  }
80  }
81  }
82 
83  $nbt->Blocks = new ByteArrayTag("Blocks", $ids);
84  $nbt->Data = new ByteArrayTag("Data", $data);
85  $nbt->SkyLight = new ByteArrayTag("SkyLight", $skyLight);
86  $nbt->BlockLight = new ByteArrayTag("BlockLight", $blockLight);
87 
88  $nbt->Biomes = new ByteArrayTag("Biomes", $chunk->getBiomeIdArray());
89  $nbt->HeightMap = new ByteArrayTag("HeightMap", pack("C*", ...$chunk->getHeightMapArray()));
90 
91  $entities = [];
92 
93  foreach($chunk->getEntities() as $entity){
94  if(!($entity instanceof Player) and !$entity->closed){
95  $entity->saveNBT();
96  $entities[] = $entity->namedtag;
97  }
98  }
99 
100  $nbt->Entities = new ListTag("Entities", $entities);
101  $nbt->Entities->setTagType(NBT::TAG_Compound);
102 
103  $tiles = [];
104  foreach($chunk->getTiles() as $tile){
105  $tile->saveNBT();
106  $tiles[] = $tile->namedtag;
107  }
108 
109  $nbt->TileEntities = new ListTag("TileEntities", $tiles);
110  $nbt->TileEntities->setTagType(NBT::TAG_Compound);
111 
112  //TODO: TileTicks
113 
114  $writer = new NBT(NBT::BIG_ENDIAN);
115  $nbt->setName("Level");
116  $writer->setData(new CompoundTag("", ["Level" => $nbt]));
117 
118  return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
119  }

◆ saveChunk()

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

Implements LevelProvider.

352  : bool{
353  if($this->isChunkLoaded($chunkX, $chunkZ)){
354  $chunk = $this->getChunk($chunkX, $chunkZ);
355  if(!$chunk->isGenerated()){
356  throw new \InvalidStateException("Cannot save un-generated chunk");
357  }
358  $this->getRegion($chunkX >> 5, $chunkZ >> 5)->writeChunk($chunk);
359 
360  return true;
361  }
362 
363  return false;
364  }

◆ saveChunks()

saveChunks ( )

Implements LevelProvider.

366  {
367  foreach($this->chunks as $chunk){
368  $this->saveChunk($chunk->getX(), $chunk->getZ());
369  }
370  }

◆ setChunk()

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

Implements LevelProvider.

331  {
332  self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
333  $this->loadRegion($regionX, $regionZ);
334 
335  $chunk->setX($chunkX);
336  $chunk->setZ($chunkZ);
337 
338 
339  if(isset($this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)]) and $this->chunks[$index] !== $chunk){
340  $this->unloadChunk($chunkX, $chunkZ, false);
341  }
342 
343  $this->chunks[$index] = $chunk;
344  }

◆ unloadChunk()

unloadChunk ( int  $chunkX,
int  $chunkZ,
bool  $safe = true 
)
Parameters
int$chunkX
int$chunkZ
bool$safe
Returns
bool

Implements LevelProvider.

411  : bool{
412  $chunk = $this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)] ?? null;
413  if($chunk instanceof Chunk and $chunk->unload($safe)){
414  unset($this->chunks[$index]);
415  return true;
416  }
417 
418  return false;
419  }

◆ unloadChunks()

unloadChunks ( )

Implements LevelProvider.

421  {
422  foreach($this->chunks as $chunk){
423  $this->unloadChunk($chunk->getX(), $chunk->getZ(), false);
424  }
425  $this->chunks = [];
426  }

Field Documentation

◆ $chunks

$chunks = []
protected

◆ $regions

$regions = []
protected

◆ REGION_FILE_EXTENSION

const REGION_FILE_EXTENSION = "mcr"

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