Type-hints, strict-types, doc comments and rearrangement for LevelProviders

This commit is contained in:
Dylan K. Taylor 2016-12-22 13:16:25 +00:00
parent a99d7f93d9
commit f4065dd411
4 changed files with 198 additions and 189 deletions

View File

@ -19,6 +19,8 @@
* *
*/ */
declare(strict_types = 1);
namespace pocketmine\level\format; namespace pocketmine\level\format;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
@ -27,26 +29,18 @@ use pocketmine\math\Vector3;
interface LevelProvider{ interface LevelProvider{
const ORDER_YZX = 0;
const ORDER_ZXY = 1;
/** /**
* @param Level $level * @param Level $level
* @param string $path * @param string $path
*/ */
public function __construct(Level $level, $path); public function __construct(Level $level, string $path);
/** /**
* Returns the full provider name, like "anvil" or "mcregion", will be used to find the correct format. * Returns the full provider name, like "anvil" or "mcregion", will be used to find the correct format.
* *
* @return string * @return string
*/ */
public static function getProviderName(); public static function getProviderName() : string;
/**
* @return int
*/
public static function getProviderOrder();
/** /**
* Gets the build height limit of this world * Gets the build height limit of this world
@ -56,17 +50,9 @@ interface LevelProvider{
public function getWorldHeight() : int; public function getWorldHeight() : int;
/** /**
* Requests a MC: PE network chunk to be sent * @return string
*
* @param int $x
* @param int $z
*
* @return \pocketmine\scheduler\AsyncTask|null
*/ */
public function requestChunkTask($x, $z); public function getPath() : string;
/** @return string */
public function getPath();
/** /**
* Tells if the path is a valid level. * Tells if the path is a valid level.
@ -74,105 +60,113 @@ interface LevelProvider{
* *
* @param string $path * @param string $path
* *
* @return true * @return bool
*/ */
public static function isValid($path); public static function isValid(string $path) : bool;
/** /**
* Generate the needed files in the path given * Generate the needed files in the path given
* *
* @param string $path * @param string $path
* @param string $name * @param string $name
* @param int $seed * @param int|string $seed
* @param string $generator * @param string $generator
* @param array[] $options * @param array[] $options
*/ */
public static function generate($path, $name, $seed, $generator, array $options = []); public static function generate(string $path, string $name, $seed, string $generator, array $options = []);
/** /**
* Returns the generator name * Returns the generator name
* *
* @return string * @return string
*/ */
public function getGenerator(); public function getGenerator() : string;
/** /**
* @return array * @return array
*/ */
public function getGeneratorOptions(); public function getGeneratorOptions() : array;
/** /**
* Gets the Chunk object * Gets the Chunk object
* This method must be implemented by all the level formats. * This method must be implemented by all the level formats.
* *
* @param int $X absolute Chunk X value * @param int $chunkX
* @param int $Z absolute Chunk Z value * @param int $chunkZ
* @param bool $create Whether to generate the chunk if it does not exist
*
* @return Chunk
*/
public function getChunk($X, $Z, $create = false);
public function saveChunks();
/**
* @param int $X
* @param int $Z
*/
public function saveChunk($X, $Z);
public function unloadChunks();
/**
* @param int $X
* @param int $Z
* @param bool $create * @param bool $create
* *
* @return bool * @return Chunk|null
*/ */
public function loadChunk($X, $Z, $create = false); public function getChunk(int $chunkX, int $chunkZ, bool $create = false);
/**
* @param int $X
* @param int $Z
* @param bool $safe
*
* @return bool
*/
public function unloadChunk($X, $Z, $safe = true);
/**
* @param int $X
* @param int $Z
*
* @return bool
*/
public function isChunkGenerated($X, $Z);
/**
* @param int $X
* @param int $Z
*
* @return bool
*/
public function isChunkPopulated($X, $Z);
/**
* @param int $X
* @param int $Z
*
* @return bool
*/
public function isChunkLoaded($X, $Z);
/** /**
* @param int $chunkX * @param int $chunkX
* @param int $chunkZ * @param int $chunkZ
* @param Chunk $chunk * @param Chunk $chunk
*
* @return mixed
*/ */
public function setChunk($chunkX, $chunkZ, Chunk $chunk); public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk);
/**
* @param int $chunkX
* @param int $chunkZ
*/
public function saveChunk(int $chunkX, int $chunkZ) : bool;
public function saveChunks();
/**
* @param int $chunkX
* @param int $chunkZ
* @param bool $create
*
* @return bool
*/
public function loadChunk(int $chunkX, int $chunkZ, bool $create = false) : bool;
/**
* @param int $chunkX
* @param int $chunkZ
* @param bool $safe
*
* @return bool
*/
public function unloadChunk(int $chunkX, int $chunkZ, bool $safe = true) : bool;
public function unloadChunks();
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return bool
*/
public function isChunkLoaded(int $chunkX, int $chunkZ) : bool;
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return bool
*/
public function isChunkGenerated(int $chunkX, int $chunkZ) : bool;
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return bool
*/
public function isChunkPopulated(int $chunkX, int $chunkZ) : bool;
/**
* Requests a MC: PE network chunk to be sent
*
* @param int $x
* @param int $z
*
* @return \pocketmine\scheduler\AsyncTask|null
*/
public function requestChunkTask(int $x, int $z);
/** /**
* @return string * @return string
@ -187,7 +181,7 @@ interface LevelProvider{
/** /**
* @param int $value * @param int $value
*/ */
public function setTime($value); public function setTime(int $value);
/** /**
* @return int|string int, or the string numeric representation of a long in 32-bit systems * @return int|string int, or the string numeric representation of a long in 32-bit systems
@ -195,14 +189,14 @@ interface LevelProvider{
public function getSeed(); public function getSeed();
/** /**
* @param int $value * @param int|string $value
*/ */
public function setSeed($value); public function setSeed($value);
/** /**
* @return Vector3 * @return Vector3
*/ */
public function getSpawn(); public function getSpawn() : Vector3;
/** /**
* @param Vector3 $pos * @param Vector3 $pos
@ -212,7 +206,7 @@ interface LevelProvider{
/** /**
* @return Chunk[] * @return Chunk[]
*/ */
public function getLoadedChunks(); public function getLoadedChunks() : array;
public function doGarbageCollection(); public function doGarbageCollection();

View File

@ -19,6 +19,8 @@
* *
*/ */
declare(strict_types = 1);
namespace pocketmine\level\format\anvil; namespace pocketmine\level\format\anvil;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
@ -156,18 +158,14 @@ class Anvil extends McRegion{
/** @var RegionLoader[] */ /** @var RegionLoader[] */
protected $regions = []; protected $regions = [];
/** @var AnvilChunk[] */ /** @var Chunk[] */
protected $chunks = []; protected $chunks = [];
public static function getProviderName(){ public static function getProviderName() : string{
return "anvil"; return "anvil";
} }
public static function getProviderOrder(){ public static function isValid(string $path) : bool{
return self::ORDER_YZX;
}
public static function isValid($path){
$isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/")); $isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/"));
if($isValid){ if($isValid){
@ -189,16 +187,16 @@ class Anvil extends McRegion{
} }
/** /**
* @param $x * @param int $x
* @param $z * @param int $z
* *
* @return RegionLoader * @return RegionLoader
*/ */
protected function getRegion($x, $z){ protected function getRegion(int $x, int $z){
return $this->regions[Level::chunkHash($x, $z)] ?? null; return $this->regions[Level::chunkHash($x, $z)] ?? null;
} }
protected function loadRegion($x, $z){ protected function loadRegion(int $x, int $z){
if(!isset($this->regions[$index = Level::chunkHash($x, $z)])){ if(!isset($this->regions[$index = Level::chunkHash($x, $z)])){
$this->regions[$index] = new RegionLoader($this, $x, $z); $this->regions[$index] = new RegionLoader($this, $x, $z);
} }

View File

@ -19,6 +19,8 @@
* *
*/ */
declare(strict_types = 1);
namespace pocketmine\level\format\generic; namespace pocketmine\level\format\generic;
use pocketmine\level\format\LevelProvider; use pocketmine\level\format\LevelProvider;
@ -40,7 +42,7 @@ abstract class BaseLevelProvider implements LevelProvider{
/** @var CompoundTag */ /** @var CompoundTag */
protected $levelData; protected $levelData;
public function __construct(Level $level, $path){ public function __construct(Level $level, string $path){
$this->level = $level; $this->level = $level;
$this->path = $path; $this->path = $path;
if(!file_exists($this->path)){ if(!file_exists($this->path)){
@ -64,7 +66,7 @@ abstract class BaseLevelProvider implements LevelProvider{
} }
} }
public function getPath(){ public function getPath() : string{
return $this->path; return $this->path;
} }
@ -76,15 +78,15 @@ abstract class BaseLevelProvider implements LevelProvider{
return $this->level; return $this->level;
} }
public function getName(){ public function getName() : string{
return $this->levelData["LevelName"]; return $this->levelData["LevelName"];
} }
public function getTime(){ public function getTime() : int{
return $this->levelData["Time"]; return $this->levelData["Time"];
} }
public function setTime($value){ public function setTime(int $value){
$this->levelData->Time = new IntTag("Time", (int) $value); $this->levelData->Time = new IntTag("Time", (int) $value);
} }
@ -96,7 +98,7 @@ abstract class BaseLevelProvider implements LevelProvider{
$this->levelData->RandomSeed = new LongTag("RandomSeed", $value); $this->levelData->RandomSeed = new LongTag("RandomSeed", $value);
} }
public function getSpawn(){ public function getSpawn() : Vector3{
return new Vector3((float) $this->levelData["SpawnX"], (float) $this->levelData["SpawnY"], (float) $this->levelData["SpawnZ"]); return new Vector3((float) $this->levelData["SpawnX"], (float) $this->levelData["SpawnY"], (float) $this->levelData["SpawnZ"]);
} }
@ -113,7 +115,7 @@ abstract class BaseLevelProvider implements LevelProvider{
/** /**
* @return CompoundTag * @return CompoundTag
*/ */
public function getLevelData(){ public function getLevelData() : CompoundTag{
return $this->levelData; return $this->levelData;
} }
@ -126,7 +128,7 @@ abstract class BaseLevelProvider implements LevelProvider{
file_put_contents($this->getPath() . "level.dat", $buffer); file_put_contents($this->getPath() . "level.dat", $buffer);
} }
public function requestChunkTask($x, $z){ public function requestChunkTask(int $x, int $z){
$chunk = $this->getChunk($x, $z, false); $chunk = $this->getChunk($x, $z, false);
if(!($chunk instanceof GenericChunk)){ if(!($chunk instanceof GenericChunk)){
throw new ChunkException("Invalid Chunk sent"); throw new ChunkException("Invalid Chunk sent");

View File

@ -19,6 +19,8 @@
* *
*/ */
declare(strict_types = 1);
namespace pocketmine\level\format\mcregion; namespace pocketmine\level\format\mcregion;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
@ -36,6 +38,11 @@ use pocketmine\utils\MainLogger;
class McRegion extends BaseLevelProvider{ class McRegion extends BaseLevelProvider{
/**
* @param GenericChunk $chunk
*
* @return string
*/
public static function nbtSerialize(GenericChunk $chunk) : string{ public static function nbtSerialize(GenericChunk $chunk) : string{
$nbt = new CompoundTag("Level", []); $nbt = new CompoundTag("Level", []);
$nbt->xPos = new IntTag("xPos", $chunk->getX()); $nbt->xPos = new IntTag("xPos", $chunk->getX());
@ -101,6 +108,12 @@ class McRegion extends BaseLevelProvider{
return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL); return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
} }
/**
* @param string $data
* @param LevelProvider $provider
*
* @return GenericChunk|null
*/
public static function nbtDeserialize(string $data, LevelProvider $provider = null){ public static function nbtDeserialize(string $data, LevelProvider $provider = null){
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new NBT(NBT::BIG_ENDIAN);
try{ try{
@ -179,18 +192,19 @@ class McRegion extends BaseLevelProvider{
/** @var RegionLoader[] */ /** @var RegionLoader[] */
protected $regions = []; protected $regions = [];
/** @var GenericChunk[] */ /** @var Chunk[] */
protected $chunks = []; protected $chunks = [];
public static function getProviderName(){ public static function getProviderName() : string{
return "mcregion"; return "mcregion";
} }
public static function getProviderOrder(){ public function getWorldHeight() : int{
return self::ORDER_ZXY; //TODO: add world height options
return 128;
} }
public static function isValid($path){ public static function isValid(string $path) : bool{
$isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/")); $isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/"));
if($isValid){ if($isValid){
@ -206,12 +220,7 @@ class McRegion extends BaseLevelProvider{
return $isValid; return $isValid;
} }
public function getWorldHeight() : int{ public static function generate(string $path, string $name, $seed, string $generator, array $options = []){
//TODO: add world height options
return 128;
}
public static function generate($path, $name, $seed, $generator, array $options = []){
if(!file_exists($path)){ if(!file_exists($path)){
mkdir($path, 0777, true); mkdir($path, 0777, true);
} }
@ -247,32 +256,51 @@ class McRegion extends BaseLevelProvider{
file_put_contents($path . "level.dat", $buffer); file_put_contents($path . "level.dat", $buffer);
} }
public static function getRegionIndex($chunkX, $chunkZ, &$x, &$z){ public function getGenerator() : string{
$x = $chunkX >> 5;
$z = $chunkZ >> 5;
}
public function unloadChunks(){
foreach($this->chunks as $chunk){
$this->unloadChunk($chunk->getX(), $chunk->getZ(), false);
}
$this->chunks = [];
}
public function getGenerator(){
return $this->levelData["generatorName"]; return $this->levelData["generatorName"];
} }
public function getGeneratorOptions(){ public function getGeneratorOptions() : array{
return ["preset" => $this->levelData["generatorOptions"]]; return ["preset" => $this->levelData["generatorOptions"]];
} }
public function getLoadedChunks(){ public function getChunk(int $chunkX, int $chunkZ, bool $create = false){
return $this->chunks; $index = Level::chunkHash($chunkX, $chunkZ);
if(isset($this->chunks[$index])){
return $this->chunks[$index];
}else{
$this->loadChunk($chunkX, $chunkZ, $create);
return $this->chunks[$index] ?? null;
}
} }
public function isChunkLoaded($x, $z){ public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk){
return isset($this->chunks[Level::chunkHash($x, $z)]);
$chunk->setProvider($this);
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
$this->loadRegion($regionX, $regionZ);
$chunk->setX($chunkX);
$chunk->setZ($chunkZ);
if(isset($this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)]) and $this->chunks[$index] !== $chunk){
$this->unloadChunk($chunkX, $chunkZ, false);
}
$this->chunks[$index] = $chunk;
}
public function saveChunk(int $chunkX, int $chunkZ) : bool{
if($this->isChunkLoaded($chunkX, $chunkZ)){
$this->getRegion($chunkX >> 5, $chunkZ >> 5)->writeChunk($this->getChunk($chunkX, $chunkZ));
return true;
}
return false;
} }
public function saveChunks(){ public function saveChunks(){
@ -281,17 +309,7 @@ class McRegion extends BaseLevelProvider{
} }
} }
public function doGarbageCollection(){ public function loadChunk(int $chunkX, int $chunkZ, bool $create = false) : bool{
$limit = time() - 300;
foreach($this->regions as $index => $region){
if($region->lastUsed <= $limit){
$region->close();
unset($this->regions[$index]);
}
}
}
public function loadChunk($chunkX, $chunkZ, $create = false){
$index = Level::chunkHash($chunkX, $chunkZ); $index = Level::chunkHash($chunkX, $chunkZ);
if(isset($this->chunks[$index])){ if(isset($this->chunks[$index])){
return true; return true;
@ -314,12 +332,8 @@ class McRegion extends BaseLevelProvider{
} }
} }
public function getEmptyChunk($chunkX, $chunkZ){ public function unloadChunk(int $chunkX, int $chunkZ, bool $safe = true) : bool{
return GenericChunk::getEmptyChunk($chunkX, $chunkZ, $this); $chunk = $this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)] ?? null;
}
public function unloadChunk($x, $z, $safe = true){
$chunk = $this->chunks[$index = Level::chunkHash($x, $z)] ?? null;
if($chunk instanceof Chunk and $chunk->unload(false, $safe)){ if($chunk instanceof Chunk and $chunk->unload(false, $safe)){
unset($this->chunks[$index]); unset($this->chunks[$index]);
return true; return true;
@ -328,66 +342,18 @@ class McRegion extends BaseLevelProvider{
return false; return false;
} }
public function saveChunk($x, $z){ public function unloadChunks(){
if($this->isChunkLoaded($x, $z)){ foreach($this->chunks as $chunk){
$this->getRegion($x >> 5, $z >> 5)->writeChunk($this->getChunk($x, $z)); $this->unloadChunk($chunk->getX(), $chunk->getZ(), false);
}
return true; $this->chunks = [];
} }
return false; public function isChunkLoaded(int $chunkX, int $chunkZ) : bool{
return isset($this->chunks[Level::chunkHash($chunkX, $chunkZ)]);
} }
/** public function isChunkGenerated(int $chunkX, int $chunkZ) : bool{
* @param $x
* @param $z
*
* @return RegionLoader
*/
protected function getRegion($x, $z){
return $this->regions[Level::chunkHash($x, $z)] ?? null;
}
/**
* @param int $chunkX
* @param int $chunkZ
* @param bool $create
*
* @return Chunk
*/
public function getChunk($chunkX, $chunkZ, $create = false){
$index = Level::chunkHash($chunkX, $chunkZ);
if(isset($this->chunks[$index])){
return $this->chunks[$index];
}else{
$this->loadChunk($chunkX, $chunkZ, $create);
return isset($this->chunks[$index]) ? $this->chunks[$index] : null;
}
}
public function setChunk($chunkX, $chunkZ, Chunk $chunk){
if(!($chunk instanceof GenericChunk)){
throw new ChunkException("Invalid Chunk class");
}
$chunk->setProvider($this);
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
$this->loadRegion($regionX, $regionZ);
$chunk->setX($chunkX);
$chunk->setZ($chunkZ);
if(isset($this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)]) and $this->chunks[$index] !== $chunk){
$this->unloadChunk($chunkX, $chunkZ, false);
}
$this->chunks[$index] = $chunk;
}
public function isChunkGenerated($chunkX, $chunkZ){
if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) !== null){ if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) !== null){
return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32) and $this->getChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32, true)->isGenerated(); return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32) and $this->getChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32, true)->isGenerated();
} }
@ -395,7 +361,7 @@ class McRegion extends BaseLevelProvider{
return false; return false;
} }
public function isChunkPopulated($chunkX, $chunkZ){ public function isChunkPopulated(int $chunkX, int $chunkZ) : bool{
$chunk = $this->getChunk($chunkX, $chunkZ); $chunk = $this->getChunk($chunkX, $chunkZ);
if($chunk !== null){ if($chunk !== null){
return $chunk->isPopulated(); return $chunk->isPopulated();
@ -404,7 +370,56 @@ class McRegion extends BaseLevelProvider{
} }
} }
protected function loadRegion($x, $z){ public function getLoadedChunks() : array{
return $this->chunks;
}
public function doGarbageCollection(){
$limit = time() - 300;
foreach($this->regions as $index => $region){
if($region->lastUsed <= $limit){
$region->close();
unset($this->regions[$index]);
}
}
}
/**
* @param int $chunkX
* @param int $chunkZ
* @param int &$x
* @param int &$z
*/
public static function getRegionIndex(int $chunkX, int $chunkZ, &$x, &$z){
$x = $chunkX >> 5;
$z = $chunkZ >> 5;
}
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return GenericChunk
*/
public function getEmptyChunk(int $chunkX, int $chunkZ){
return GenericChunk::getEmptyChunk($chunkX, $chunkZ, $this);
}
/**
* @param int $x
* @param int $z
*
* @return RegionLoader
*/
protected function getRegion(int $x, int $z){
return $this->regions[Level::chunkHash($x, $z)] ?? null;
}
/**
* @param int $x
* @param int $z
*/
protected function loadRegion(int $x, int $z){
if(!isset($this->regions[$index = Level::chunkHash($x, $z)])){ if(!isset($this->regions[$index = Level::chunkHash($x, $z)])){
$this->regions[$index] = new RegionLoader($this, $x, $z); $this->regions[$index] = new RegionLoader($this, $x, $z);
} }