Merge branch 'stable' into next-minor

This commit is contained in:
Dylan K. Taylor
2020-02-10 11:40:08 +00:00
539 changed files with 3706 additions and 6211 deletions

View File

@ -42,15 +42,11 @@ interface ChunkLoader{
/**
* Returns the ChunkLoader id.
* Call Level::generateChunkLoaderId($this) to generate and save it
*
* @return int
*/
public function getLoaderId() : int;
/**
* Returns if the chunk loader is currently active
*
* @return bool
*/
public function isLoaderActive() : bool;
@ -77,22 +73,21 @@ interface ChunkLoader{
/**
* This method will be called when a Chunk is replaced by a new one
*
* @param Chunk $chunk
* @return void
*/
public function onChunkChanged(Chunk $chunk);
/**
* This method will be called when a registered chunk is loaded
*
* @param Chunk $chunk
* @return void
*/
public function onChunkLoaded(Chunk $chunk);
/**
* This method will be called when a registered chunk is unloaded
*
* @param Chunk $chunk
* @return void
*/
public function onChunkUnloaded(Chunk $chunk);
@ -100,7 +95,7 @@ interface ChunkLoader{
* This method will be called when a registered chunk is populated
* Usually it'll be sent with another call to onChunkChanged()
*
* @param Chunk $chunk
* @return void
*/
public function onChunkPopulated(Chunk $chunk);
@ -108,6 +103,8 @@ interface ChunkLoader{
* This method will be called when a block changes in a registered chunk
*
* @param Block|Vector3 $block
*
* @return void
*/
public function onBlockChanged(Vector3 $block);

View File

@ -29,10 +29,6 @@ interface ChunkManager{
/**
* Gets the raw block id.
*
* @param int $x
* @param int $y
* @param int $z
*
* @return int 0-255
*/
public function getBlockIdAt(int $x, int $y, int $z) : int;
@ -40,20 +36,15 @@ interface ChunkManager{
/**
* Sets the raw block id.
*
* @param int $x
* @param int $y
* @param int $z
* @param int $id 0-255
*
* @return void
*/
public function setBlockIdAt(int $x, int $y, int $z, int $id);
/**
* Gets the raw block metadata
*
* @param int $x
* @param int $y
* @param int $z
*
* @return int 0-15
*/
public function getBlockDataAt(int $x, int $y, int $z) : int;
@ -61,92 +52,59 @@ interface ChunkManager{
/**
* Sets the raw block metadata.
*
* @param int $x
* @param int $y
* @param int $z
* @param int $data 0-15
*
* @return void
*/
public function setBlockDataAt(int $x, int $y, int $z, int $data);
/**
* Returns the raw block light level
*
* @param int $x
* @param int $y
* @param int $z
*
* @return int
*/
public function getBlockLightAt(int $x, int $y, int $z) : int;
/**
* Sets the raw block light level
*
* @param int $x
* @param int $y
* @param int $z
* @param int $level
* @return void
*/
public function setBlockLightAt(int $x, int $y, int $z, int $level);
/**
* Returns the highest amount of sky light can reach the specified coordinates.
*
* @param int $x
* @param int $y
* @param int $z
*
* @return int
*/
public function getBlockSkyLightAt(int $x, int $y, int $z) : int;
/**
* Sets the raw block sky light level.
*
* @param int $x
* @param int $y
* @param int $z
* @param int $level
* @return void
*/
public function setBlockSkyLightAt(int $x, int $y, int $z, int $level);
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return Chunk|null
*/
public function getChunk(int $chunkX, int $chunkZ);
/**
* @param int $chunkX
* @param int $chunkZ
* @param Chunk|null $chunk
* @return void
*/
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null);
/**
* Gets the level seed
*
* @return int
*/
public function getSeed() : int;
/**
* Returns the height of the world
* @return int
*/
public function getWorldHeight() : int;
/**
* Returns whether the specified coordinates are within the valid world boundaries, taking world format limitations
* into account.
*
* @param int $x
* @param int $y
* @param int $z
*
* @return bool
*/
public function isInWorld(int $x, int $y, int $z) : bool;
}

View File

@ -60,16 +60,14 @@ class Explosion{
public $affectedBlocks = [];
/** @var float */
public $stepLen = 0.3;
/** @var Entity|Block */
/** @var Entity|Block|null */
private $what;
/** @var SubChunkIteratorManager */
private $subChunkHandler;
/**
* @param Position $center
* @param float $size
* @param Entity|Block $what
* @param Entity|Block|null $what
*/
public function __construct(Position $center, float $size, $what = null){
if(!$center->isValid()){
@ -88,10 +86,8 @@ class Explosion{
}
/**
* Calculates which blocks will be destroyed by this explosion. If explodeB() is called without calling this, no blocks
* Calculates which blocks will be destroyed by this explosion. If explodeB() is called without calling this, no blocks
* will be destroyed.
*
* @return bool
*/
public function explodeA() : bool{
if($this->size < 0.1){
@ -104,7 +100,7 @@ class Explosion{
$currentChunk = null;
$currentSubChunk = null;
$mRays = (int) ($this->rays - 1);
$mRays = $this->rays - 1;
for($i = 0; $i < $this->rays; ++$i){
for($j = 0; $j < $this->rays; ++$j){
for($k = 0; $k < $this->rays; ++$k){
@ -123,6 +119,10 @@ class Explosion{
$vBlock->y = $pointerY >= $y ? $y : $y - 1;
$vBlock->z = $pointerZ >= $z ? $z : $z - 1;
$pointerX += $vector->x;
$pointerY += $vector->y;
$pointerZ += $vector->z;
if(!$this->subChunkHandler->moveTo($vBlock->x, $vBlock->y, $vBlock->z)){
continue;
}
@ -137,10 +137,6 @@ class Explosion{
}
}
}
$pointerX += $vector->x;
$pointerY += $vector->y;
$pointerZ += $vector->z;
}
}
}
@ -153,8 +149,6 @@ class Explosion{
/**
* Executes the explosion's effects on the world. This includes destroying blocks (if any), harming and knocking back entities,
* and creating sounds and particles.
*
* @return bool
*/
public function explodeB() : bool{
$send = [];
@ -208,7 +202,6 @@ class Explosion{
}
}
$air = ItemFactory::get(Item::AIR);
foreach($this->affectedBlocks as $block){

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,6 @@ class Location extends Position{
* @param float|int $z
* @param float $yaw
* @param float $pitch
* @param Level $level
*/
public function __construct($x = 0, $y = 0, $z = 0, $yaw = 0.0, $pitch = 0.0, Level $level = null){
$this->yaw = $yaw;
@ -47,12 +46,8 @@ class Location extends Position{
}
/**
* @param Vector3 $pos
* @param Level|null $level default null
* @param float $yaw default 0.0
* @param float $pitch default 0.0
*
* @return Location
*/
public static function fromObject(Vector3 $pos, Level $level = null, $yaw = 0.0, $pitch = 0.0) : Location{
return new Location($pos->x, $pos->y, $pos->z, $yaw, $pitch, $level ?? (($pos instanceof Position) ? $pos->level : null));
@ -60,17 +55,21 @@ class Location extends Position{
/**
* Return a Location instance
*
* @return Location
*/
public function asLocation() : Location{
return new Location($this->x, $this->y, $this->z, $this->yaw, $this->pitch, $this->level);
}
/**
* @return float
*/
public function getYaw(){
return $this->yaw;
}
/**
* @return float
*/
public function getPitch(){
return $this->pitch;
}

View File

@ -36,21 +36,21 @@ class Position extends Vector3{
* @param float|int $x
* @param float|int $y
* @param float|int $z
* @param Level $level
*/
public function __construct($x = 0, $y = 0, $z = 0, Level $level = null){
parent::__construct($x, $y, $z);
$this->setLevel($level);
}
/**
* @return Position
*/
public static function fromObject(Vector3 $pos, Level $level = null){
return new Position($pos->x, $pos->y, $pos->z, $level);
}
/**
* Return a Position instance
*
* @return Position
*/
public function asPosition() : Position{
return new Position($this->x, $this->y, $this->z, $this->level);
@ -74,8 +74,6 @@ class Position extends Vector3{
/**
* Sets the target Level of the position.
*
* @param Level|null $level
*
* @return $this
*
* @throws \InvalidArgumentException if the specified Level has been closed
@ -91,8 +89,6 @@ class Position extends Vector3{
/**
* Checks if this object has a valid reference to a loaded Level
*
* @return bool
*/
public function isValid() : bool{
if($this->level !== null and $this->level->isClosed()){
@ -107,9 +103,6 @@ class Position extends Vector3{
/**
* Returns a side Vector
*
* @param int $side
* @param int $step
*
* @return Position
*/
public function getSide(int $side, int $step = 1){

View File

@ -32,14 +32,13 @@ class SimpleChunkManager implements ChunkManager{
/** @var Chunk[] */
protected $chunks = [];
/** @var int */
protected $seed;
/** @var int */
protected $worldHeight;
/**
* SimpleChunkManager constructor.
*
* @param int $seed
* @param int $worldHeight
*/
public function __construct(int $seed, int $worldHeight = Level::Y_MAX){
$this->seed = $seed;
@ -49,14 +48,10 @@ class SimpleChunkManager implements ChunkManager{
/**
* Gets the raw block id.
*
* @param int $x
* @param int $y
* @param int $z
*
* @return int 0-255
*/
public function getBlockIdAt(int $x, int $y, int $z) : int{
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
return $chunk->getBlockId($x & 0xf, $y, $z & 0xf);
}
return 0;
@ -65,13 +60,12 @@ class SimpleChunkManager implements ChunkManager{
/**
* Sets the raw block id.
*
* @param int $x
* @param int $y
* @param int $z
* @param int $id 0-255
*
* @return void
*/
public function setBlockIdAt(int $x, int $y, int $z, int $id){
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
$chunk->setBlockId($x & 0xf, $y, $z & 0xf, $id);
}
}
@ -79,14 +73,10 @@ class SimpleChunkManager implements ChunkManager{
/**
* Gets the raw block metadata
*
* @param int $x
* @param int $y
* @param int $z
*
* @return int 0-15
*/
public function getBlockDataAt(int $x, int $y, int $z) : int{
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
return $chunk->getBlockData($x & 0xf, $y, $z & 0xf);
}
return 0;
@ -95,19 +85,18 @@ class SimpleChunkManager implements ChunkManager{
/**
* Sets the raw block metadata.
*
* @param int $x
* @param int $y
* @param int $z
* @param int $data 0-15
*
* @return void
*/
public function setBlockDataAt(int $x, int $y, int $z, int $data){
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
$chunk->setBlockData($x & 0xf, $y, $z & 0xf, $data);
}
}
public function getBlockLightAt(int $x, int $y, int $z) : int{
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
return $chunk->getBlockLight($x & 0xf, $y, $z & 0xf);
}
@ -115,13 +104,13 @@ class SimpleChunkManager implements ChunkManager{
}
public function setBlockLightAt(int $x, int $y, int $z, int $level){
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
$chunk->setBlockLight($x & 0xf, $y, $z & 0xf, $level);
}
}
public function getBlockSkyLightAt(int $x, int $y, int $z) : int{
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
return $chunk->getBlockSkyLight($x & 0xf, $y, $z & 0xf);
}
@ -129,15 +118,12 @@ class SimpleChunkManager implements ChunkManager{
}
public function setBlockSkyLightAt(int $x, int $y, int $z, int $level){
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
$chunk->setBlockSkyLight($x & 0xf, $y, $z & 0xf, $level);
}
}
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return Chunk|null
*/
public function getChunk(int $chunkX, int $chunkZ){
@ -145,9 +131,7 @@ class SimpleChunkManager implements ChunkManager{
}
/**
* @param int $chunkX
* @param int $chunkZ
* @param Chunk|null $chunk
* @return void
*/
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null){
if($chunk === null){
@ -157,14 +141,15 @@ class SimpleChunkManager implements ChunkManager{
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk;
}
/**
* @return void
*/
public function cleanChunks(){
$this->chunks = [];
}
/**
* Gets the level seed
*
* @return int
*/
public function getSeed() : int{
return $this->seed;

View File

@ -43,16 +43,16 @@ abstract class Biome{
public const ICE_PLAINS = 12;
public const SMALL_MOUNTAINS = 20;
public const BIRCH_FOREST = 27;
public const MAX_BIOMES = 256;
/** @var Biome[]|\SplFixedArray */
/**
* @var Biome[]|\SplFixedArray
* @phpstan-var \SplFixedArray<Biome>
*/
private static $biomes;
/** @var int */
@ -76,11 +76,17 @@ abstract class Biome{
/** @var float */
protected $temperature = 0.5;
/**
* @return void
*/
protected static function register(int $id, Biome $biome){
self::$biomes[$id] = $biome;
$biome->setId($id);
}
/**
* @return void
*/
public static function init(){
self::$biomes = new \SplFixedArray(self::MAX_BIOMES);
@ -95,17 +101,11 @@ abstract class Biome{
self::register(self::ICE_PLAINS, new IcePlainsBiome());
self::register(self::SMALL_MOUNTAINS, new SmallMountainsBiome());
self::register(self::BIRCH_FOREST, new ForestBiome(ForestBiome::TYPE_BIRCH));
}
/**
* @param int $id
*
* @return Biome
*/
public static function getBiome(int $id) : Biome{
if(self::$biomes[$id] === null){
self::register($id, new UnknownBiome());
@ -113,19 +113,22 @@ abstract class Biome{
return self::$biomes[$id];
}
/**
* @return void
*/
public function clearPopulators(){
$this->populators = [];
}
/**
* @return void
*/
public function addPopulator(Populator $populator){
$this->populators[] = $populator;
}
/**
* @param ChunkManager $level
* @param int $chunkX
* @param int $chunkZ
* @param Random $random
* @return void
*/
public function populateChunk(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){
foreach($this->populators as $populator){
@ -140,6 +143,9 @@ abstract class Biome{
return $this->populators;
}
/**
* @return void
*/
public function setId(int $id){
if(!$this->registered){
$this->registered = true;
@ -161,6 +167,9 @@ abstract class Biome{
return $this->maxElevation;
}
/**
* @return void
*/
public function setElevation(int $min, int $max){
$this->minElevation = $min;
$this->maxElevation = $max;
@ -175,6 +184,8 @@ abstract class Biome{
/**
* @param Block[] $covers
*
* @return void
*/
public function setGroundCover(array $covers){
$this->groundCover = $covers;

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\level\biome;
class DesertBiome extends SandyBiome{
public function __construct(){

View File

@ -32,6 +32,7 @@ class ForestBiome extends GrassyBiome{
public const TYPE_NORMAL = 0;
public const TYPE_BIRCH = 1;
/** @var int */
public $type;
public function __construct(int $type = self::TYPE_NORMAL){

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\level\biome;
class SmallMountainsBiome extends MountainsBiome{
public function __construct(){

View File

@ -72,7 +72,10 @@ class Chunk{
/** @var int */
protected $height = Chunk::MAX_SUBCHUNKS;
/** @var \SplFixedArray|SubChunkInterface[] */
/**
* @var \SplFixedArray|SubChunkInterface[]
* @phpstan-var \SplFixedArray<SubChunkInterface>
*/
protected $subChunks;
/** @var EmptySubChunk */
@ -86,7 +89,10 @@ class Chunk{
/** @var Entity[] */
protected $entities = [];
/** @var \SplFixedArray|int[] */
/**
* @var \SplFixedArray|int[]
* @phpstan-var \SplFixedArray<int>
*/
protected $heightMap;
/** @var string */
@ -99,12 +105,9 @@ class Chunk{
protected $NBTentities = [];
/**
* @param int $chunkX
* @param int $chunkZ
* @param SubChunkInterface[] $subChunks
* @param CompoundTag[] $entities
* @param CompoundTag[] $tiles
* @param string $biomeIds
* @param int[] $heightMap
*/
public function __construct(int $chunkX, int $chunkZ, array $subChunks = [], array $entities = [], array $tiles = [], string $biomeIds = "", array $heightMap = []){
@ -139,26 +142,23 @@ class Chunk{
$this->NBTentities = $entities;
}
/**
* @return int
*/
public function getX() : int{
return $this->x;
}
/**
* @return int
*/
public function getZ() : int{
return $this->z;
}
/**
* @return void
*/
public function setX(int $x){
$this->x = $x;
}
/**
* @param int $z
* @return void
*/
public function setZ(int $z){
$this->z = $z;
@ -166,8 +166,6 @@ class Chunk{
/**
* Returns the chunk height in count of subchunks.
*
* @return int
*/
public function getHeight() : int{
return $this->height;
@ -194,8 +192,6 @@ class Chunk{
* @param int $z 0-15
* @param int|null $blockId 0-255 if null, does not change
* @param int|null $meta 0-15 if null, does not change
*
* @return bool
*/
public function setBlock(int $x, int $y, int $z, ?int $blockId = null, ?int $meta = null) : bool{
if($this->getSubChunk($y >> 4, true)->setBlock($x, $y & 0x0f, $z, $blockId !== null ? ($blockId & 0xff) : null, $meta !== null ? ($meta & 0x0f) : null)){
@ -225,6 +221,8 @@ class Chunk{
* @param int $y
* @param int $z 0-15
* @param int $id 0-255
*
* @return void
*/
public function setBlockId(int $x, int $y, int $z, int $id){
if($this->getSubChunk($y >> 4, true)->setBlockId($x, $y & 0x0f, $z, $id)){
@ -252,6 +250,8 @@ class Chunk{
* @param int $y
* @param int $z 0-15
* @param int $data 0-15
*
* @return void
*/
public function setBlockData(int $x, int $y, int $z, int $data){
if($this->getSubChunk($y >> 4, true)->setBlockData($x, $y & 0x0f, $z, $data)){
@ -279,6 +279,8 @@ class Chunk{
* @param int $y
* @param int $z 0-15
* @param int $level 0-15
*
* @return void
*/
public function setBlockSkyLight(int $x, int $y, int $z, int $level){
if($this->getSubChunk($y >> 4, true)->setBlockSkyLight($x, $y & 0x0f, $z, $level)){
@ -287,7 +289,7 @@ class Chunk{
}
/**
* @param int $level
* @return void
*/
public function setAllBlockSkyLight(int $level){
$char = chr(($level & 0x0f) | ($level << 4));
@ -317,6 +319,8 @@ class Chunk{
* @param int $y 0-15
* @param int $z 0-15
* @param int $level 0-15
*
* @return void
*/
public function setBlockLight(int $x, int $y, int $z, int $level){
if($this->getSubChunk($y >> 4, true)->setBlockLight($x, $y & 0x0f, $z, $level)){
@ -325,7 +329,7 @@ class Chunk{
}
/**
* @param int $level
* @return void
*/
public function setAllBlockLight(int $level){
$char = chr(($level & 0x0f) | ($level << 4));
@ -368,8 +372,6 @@ class Chunk{
*
* @param int $x 0-15
* @param int $z 0-15
*
* @return int
*/
public function getHeightMap(int $x, int $z) : int{
return $this->heightMap[($z << 4) | $x];
@ -380,7 +382,8 @@ class Chunk{
*
* @param int $x 0-15
* @param int $z 0-15
* @param int $value
*
* @return void
*/
public function setHeightMap(int $x, int $z, int $value){
$this->heightMap[($z << 4) | $x] = $value;
@ -388,6 +391,8 @@ class Chunk{
/**
* Recalculates the heightmap for the whole chunk.
*
* @return void
*/
public function recalculateHeightMap(){
for($z = 0; $z < 16; ++$z){
@ -406,8 +411,8 @@ class Chunk{
* @return int New calculated heightmap value (0-256 inclusive)
*/
public function recalculateHeightMapColumn(int $x, int $z) : int{
$max = $this->getHighestBlockAt($x, $z);
for($y = $max; $y >= 0; --$y){
$y = $this->getHighestBlockAt($x, $z);
for(; $y >= 0; --$y){
if(BlockFactory::$lightFilter[$id = $this->getBlockId($x, $y, $z)] > 1 or BlockFactory::$diffusesSkyLight[$id]){
break;
}
@ -423,6 +428,8 @@ class Chunk{
* if the chunk is light-populated after being terrain-populated.
*
* TODO: fast adjacent light spread
*
* @return void
*/
public function populateSkyLight(){
$maxY = $this->getMaxY();
@ -431,19 +438,17 @@ class Chunk{
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$y = $maxY;
$heightMap = $this->getHeightMap($x, $z);
for($y = $maxY; $y >= $heightMap; --$y){
for(; $y >= $heightMap; --$y){
$this->setBlockSkyLight($x, $y, $z, 15);
}
$light = 15;
for(; $y >= 0; --$y){
if($light > 0){
$light -= BlockFactory::$lightFilter[$this->getBlockId($x, $y, $z)];
if($light <= 0){
break;
}
$light -= BlockFactory::$lightFilter[$this->getBlockId($x, $y, $z)];
if($light <= 0){
break;
}
$this->setBlockSkyLight($x, $y, $z, $light);
}
@ -469,6 +474,8 @@ class Chunk{
* @param int $x 0-15
* @param int $z 0-15
* @param int $biomeId 0-255
*
* @return void
*/
public function setBiomeId(int $x, int $z, int $biomeId){
$this->hasChanged = true;
@ -480,8 +487,6 @@ class Chunk{
*
* @param int $x 0-15
* @param int $z 0-15
*
* @return string
*/
public function getBlockIdColumn(int $x, int $z) : string{
$result = "";
@ -497,8 +502,6 @@ class Chunk{
*
* @param int $x 0-15
* @param int $z 0-15
*
* @return string
*/
public function getBlockDataColumn(int $x, int $z) : string{
$result = "";
@ -513,8 +516,6 @@ class Chunk{
*
* @param int $x 0-15
* @param int $z 0-15
*
* @return string
*/
public function getBlockSkyLightColumn(int $x, int $z) : string{
$result = "";
@ -529,8 +530,6 @@ class Chunk{
*
* @param int $x 0-15
* @param int $z 0-15
*
* @return string
*/
public function getBlockLightColumn(int $x, int $z) : string{
$result = "";
@ -540,50 +539,41 @@ class Chunk{
return $result;
}
/**
* @return bool
*/
public function isLightPopulated() : bool{
return $this->lightPopulated;
}
/**
* @param bool $value
* @return void
*/
public function setLightPopulated(bool $value = true){
$this->lightPopulated = $value;
}
/**
* @return bool
*/
public function isPopulated() : bool{
return $this->terrainPopulated;
}
/**
* @param bool $value
* @return void
*/
public function setPopulated(bool $value = true){
$this->terrainPopulated = $value;
}
/**
* @return bool
*/
public function isGenerated() : bool{
return $this->terrainGenerated;
}
/**
* @param bool $value
* @return void
*/
public function setGenerated(bool $value = true){
$this->terrainGenerated = $value;
}
/**
* @param Entity $entity
* @return void
*/
public function addEntity(Entity $entity){
if($entity->isClosed()){
@ -596,7 +586,7 @@ class Chunk{
}
/**
* @param Entity $entity
* @return void
*/
public function removeEntity(Entity $entity){
unset($this->entities[$entity->getId()]);
@ -606,7 +596,7 @@ class Chunk{
}
/**
* @param Tile $tile
* @return void
*/
public function addTile(Tile $tile){
if($tile->isClosed()){
@ -623,7 +613,7 @@ class Chunk{
}
/**
* @param Tile $tile
* @return void
*/
public function removeTile(Tile $tile){
unset($this->tiles[$tile->getId()]);
@ -689,7 +679,7 @@ class Chunk{
/**
* Deserializes tiles and entities from NBT
*
* @param Level $level
* @return void
*/
public function initChunk(Level $level){
if(!$this->isInit){
@ -697,23 +687,21 @@ class Chunk{
$level->timings->syncChunkLoadEntitiesTimer->startTiming();
foreach($this->NBTentities as $nbt){
if($nbt instanceof CompoundTag){
if(!$nbt->hasTag("id")){ //allow mixed types (because of leveldb)
$changed = true;
continue;
}
if(!$nbt->hasTag("id")){ //allow mixed types (because of leveldb)
$changed = true;
continue;
}
try{
$entity = Entity::createEntity($nbt->getTag("id")->getValue(), $level, $nbt);
if(!($entity instanceof Entity)){
$changed = true;
continue;
}
}catch(\Throwable $t){
$level->getServer()->getLogger()->logException($t);
try{
$entity = Entity::createEntity($nbt->getTag("id")->getValue(), $level, $nbt);
if(!($entity instanceof Entity)){
$changed = true;
continue;
}
}catch(\Throwable $t){
$level->getServer()->getLogger()->logException($t);
$changed = true;
continue;
}
}
$this->NBTentities = [];
@ -721,16 +709,14 @@ class Chunk{
$level->timings->syncChunkLoadTileEntitiesTimer->startTiming();
foreach($this->NBTtiles as $nbt){
if($nbt instanceof CompoundTag){
if(!$nbt->hasTag(Tile::TAG_ID, StringTag::class)){
$changed = true;
continue;
}
if(!$nbt->hasTag(Tile::TAG_ID, StringTag::class)){
$changed = true;
continue;
}
if(Tile::createTile($nbt->getString(Tile::TAG_ID), $level, $nbt) === null){
$changed = true;
continue;
}
if(Tile::createTile($nbt->getString(Tile::TAG_ID), $level, $nbt) === null){
$changed = true;
continue;
}
}
@ -743,9 +729,6 @@ class Chunk{
}
}
/**
* @return string
*/
public function getBiomeIdArray() : string{
return $this->biomeIds;
}
@ -757,15 +740,12 @@ class Chunk{
return $this->heightMap->toArray();
}
/**
* @return bool
*/
public function hasChanged() : bool{
return $this->hasChanged;
}
/**
* @param bool $value
* @return void
*/
public function setChanged(bool $value = true){
$this->hasChanged = $value;
@ -774,10 +754,7 @@ class Chunk{
/**
* Returns the subchunk at the specified subchunk Y coordinate, or an empty, unmodifiable stub if it does not exist or the coordinate is out of range.
*
* @param int $y
* @param bool $generateNew Whether to create a new, modifiable subchunk if there is not one in place
*
* @return SubChunkInterface
*/
public function getSubChunk(int $y, bool $generateNew = false) : SubChunkInterface{
if($y < 0 or $y >= $this->height){
@ -792,11 +769,7 @@ class Chunk{
/**
* Sets a subchunk in the chunk index
*
* @param int $y
* @param SubChunkInterface|null $subChunk
* @param bool $allowEmpty Whether to check if the chunk is empty, and if so replace it with an empty stub
*
* @return bool
*/
public function setSubChunk(int $y, SubChunkInterface $subChunk = null, bool $allowEmpty = false) : bool{
if($y < 0 or $y >= $this->height){
@ -813,6 +786,7 @@ class Chunk{
/**
* @return \SplFixedArray|SubChunkInterface[]
* @phpstan-return \SplFixedArray<SubChunkInterface>
*/
public function getSubChunks() : \SplFixedArray{
return $this->subChunks;
@ -820,8 +794,6 @@ class Chunk{
/**
* Returns the Y coordinate of the highest non-empty subchunk in this chunk.
*
* @return int
*/
public function getHighestSubChunkIndex() : int{
for($y = $this->subChunks->count() - 1; $y >= 0; --$y){
@ -829,16 +801,14 @@ class Chunk{
//No need to thoroughly prune empties at runtime, this will just reduce performance.
continue;
}
break;
return $y;
}
return $y;
return -1;
}
/**
* Returns the count of subchunks that need sending to players
*
* @return int
*/
public function getSubChunkSendCount() : int{
return $this->getHighestSubChunkIndex() + 1;
@ -861,8 +831,6 @@ class Chunk{
/**
* Serializes the chunk for sending to players
*
* @return string
*/
public function networkSerialize() : string{
$result = "";
@ -885,8 +853,6 @@ class Chunk{
/**
* Fast-serializes the chunk for passing between threads
* TODO: tiles and entities
*
* @return string
*/
public function fastSerialize() : string{
$stream = new BinaryStream();
@ -922,10 +888,6 @@ class Chunk{
/**
* Deserializes a fast-serialized chunk
*
* @param string $data
*
* @return Chunk
*/
public static function fastDeserialize(string $data) : Chunk{
$stream = new BinaryStream($data);

View File

@ -38,25 +38,28 @@ if(!defined(__NAMESPACE__ . '\ZERO_NIBBLE_ARRAY')){
}
class SubChunk implements SubChunkInterface{
/** @var string */
protected $ids;
/** @var string */
protected $data;
/** @var string */
protected $blockLight;
/** @var string */
protected $skyLight;
private static function assignData(&$target, string $data, int $length, string $value = "\x00"){
private static function assignData(string $data, int $length, string $value = "\x00") : string{
if(strlen($data) !== $length){
assert($data === "", "Invalid non-zero length given, expected $length, got " . strlen($data));
$target = str_repeat($value, $length);
}else{
$target = $data;
return str_repeat($value, $length);
}
return $data;
}
public function __construct(string $ids = "", string $data = "", string $skyLight = "", string $blockLight = ""){
self::assignData($this->ids, $ids, 4096);
self::assignData($this->data, $data, 2048);
self::assignData($this->skyLight, $skyLight, 2048, "\xff");
self::assignData($this->blockLight, $blockLight, 2048);
$this->ids = self::assignData($ids, 4096);
$this->data = self::assignData($data, 2048);
$this->skyLight = self::assignData($skyLight, 2048, "\xff");
$this->blockLight = self::assignData($blockLight, 2048);
$this->collectGarbage();
}
@ -214,6 +217,9 @@ class SubChunk implements SubChunkInterface{
return "\x00" . $this->ids . $this->data;
}
/**
* @return mixed[]
*/
public function __debugInfo(){
return [];
}

View File

@ -25,181 +25,55 @@ namespace pocketmine\level\format;
interface SubChunkInterface{
/**
* @param bool $checkLight
*
* @return bool
*/
public function isEmpty(bool $checkLight = true) : bool;
/**
* @param int $x
* @param int $y
* @param int $z
*
* @return int
*/
public function getBlockId(int $x, int $y, int $z) : int;
/**
* @param int $x
* @param int $y
* @param int $z
* @param int $id
*
* @return bool
*/
public function setBlockId(int $x, int $y, int $z, int $id) : bool;
/**
* @param int $x
* @param int $y
* @param int $z
*
* @return int
*/
public function getBlockData(int $x, int $y, int $z) : int;
/**
* @param int $x
* @param int $y
* @param int $z
* @param int $data
*
* @return bool
*/
public function setBlockData(int $x, int $y, int $z, int $data) : bool;
/**
* @param int $x
* @param int $y
* @param int $z
*
* @return int
*/
public function getFullBlock(int $x, int $y, int $z) : int;
/**
* @param int $x
* @param int $y
* @param int $z
* @param int|null $id
* @param int|null $data
*
* @return bool
*/
public function setBlock(int $x, int $y, int $z, ?int $id = null, ?int $data = null) : bool;
/**
* @param int $x
* @param int $y
* @param int $z
*
* @return int
*/
public function getBlockLight(int $x, int $y, int $z) : int;
/**
* @param int $x
* @param int $y
* @param int $z
* @param int $level
*
* @return bool
*/
public function setBlockLight(int $x, int $y, int $z, int $level) : bool;
/**
* @param int $x
* @param int $y
* @param int $z
*
* @return int
*/
public function getBlockSkyLight(int $x, int $y, int $z) : int;
/**
* @param int $x
* @param int $y
* @param int $z
* @param int $level
*
* @return bool
*/
public function setBlockSkyLight(int $x, int $y, int $z, int $level) : bool;
/**
* @param int $x
* @param int $z
*
* @return int
*/
public function getHighestBlockAt(int $x, int $z) : int;
/**
* @param int $x
* @param int $z
*
* @return string
*/
public function getBlockIdColumn(int $x, int $z) : string;
/**
* @param int $x
* @param int $z
*
* @return string
*/
public function getBlockDataColumn(int $x, int $z) : string;
/**
* @param int $x
* @param int $z
*
* @return string
*/
public function getBlockLightColumn(int $x, int $z) : string;
/**
* @param int $x
* @param int $z
*
* @return string
*/
public function getBlockSkyLightColumn(int $x, int $z) : string;
/**
* @return string
*/
public function getBlockIdArray() : string;
/**
* @return string
*/
public function getBlockDataArray() : string;
/**
* @return string
*/
public function getBlockSkyLightArray() : string;
/**
* @param string $data
* @return void
*/
public function setBlockSkyLightArray(string $data);
/**
* @return string
*/
public function getBlockLightArray() : string;
/**
* @param string $data
* @return void
*/
public function setBlockLightArray(string $data);
/**
* @return string
*/
public function networkSerialize() : string;
}

View File

@ -143,13 +143,13 @@ abstract class BaseLevelProvider implements LevelProvider{
}
/**
* @return CompoundTag
*/
public function getLevelData() : CompoundTag{
return $this->levelData;
}
/**
* @return void
*/
public function saveLevelData(){
$nbt = new BigEndianNBTStream();
$buffer = $nbt->writeCompressed(new CompoundTag("", [
@ -159,10 +159,6 @@ abstract class BaseLevelProvider implements LevelProvider{
}
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return Chunk|null
* @throws CorruptedChunkException
* @throws UnsupportedChunkFormatException
*/
@ -178,10 +174,6 @@ abstract class BaseLevelProvider implements LevelProvider{
}
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return Chunk|null
* @throws UnsupportedChunkFormatException
* @throws CorruptedChunkException
*/

View File

@ -34,12 +34,17 @@ use function strlen;
class ChunkRequestTask extends AsyncTask{
/** @var int */
protected $levelId;
/** @var string */
protected $chunk;
/** @var int */
protected $chunkX;
/** @var int */
protected $chunkZ;
/** @var int */
protected $compressionLevel;
/** @var int */

View File

@ -98,8 +98,6 @@ if(!extension_loaded('pocketmine_chunkutils')){
* Converts pre-MCPE-1.0 biome color array to biome ID array.
*
* @param int[] $array of biome color values
*
* @return string
*/
public static function convertBiomeColors(array $array) : string{
$result = str_repeat("\x00", 256);

View File

@ -26,142 +26,112 @@ namespace pocketmine\level\format\io;
use pocketmine\level\format\Chunk;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\level\format\io\exception\UnsupportedChunkFormatException;
use pocketmine\level\generator\Generator;
use pocketmine\math\Vector3;
interface LevelProvider{
/**
* @param string $path
*/
public function __construct(string $path);
/**
* Returns the full provider name, like "anvil" or "mcregion", will be used to find the correct format.
*
* @return string
*/
public static function getProviderName() : string;
/**
* Gets the build height limit of this world
*
* @return int
*/
public function getWorldHeight() : int;
/**
* @return string
*/
public function getPath() : string;
/**
* Tells if the path is a valid level.
* This must tell if the current format supports opening the files in the directory
*
* @param string $path
*
* @return bool
*/
public static function isValid(string $path) : bool;
/**
* Generate the needed files in the path given
*
* @param string $path
* @param string $name
* @param int $seed
* @param string $generator
* @param array $options
* @param mixed[] $options
* @phpstan-param class-string<Generator> $generator
* @phpstan-param array<string, mixed> $options
*
* @return void
*/
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
* @return mixed[]
* @phpstan-return array<string, mixed>
*/
public function getGeneratorOptions() : array;
/**
* Saves a chunk (usually to disk).
*
* @param Chunk $chunk
*/
public function saveChunk(Chunk $chunk) : void;
/**
* Loads a chunk (usually from disk storage) and returns it. If the chunk does not exist, null is returned.
*
* @param int $chunkX
* @param int $chunkZ
*
* @return null|Chunk
*
* @throws CorruptedChunkException
* @throws UnsupportedChunkFormatException
*/
public function loadChunk(int $chunkX, int $chunkZ) : ?Chunk;
/**
* @return string
*/
public function getName() : string;
/**
* @return int
*/
public function getTime() : int;
/**
* @param int $value
* @return void
*/
public function setTime(int $value);
/**
* @return int
*/
public function getSeed() : int;
/**
* @param int $value
* @return void
*/
public function setSeed(int $value);
/**
* @return Vector3
*/
public function getSpawn() : Vector3;
/**
* @param Vector3 $pos
* @return void
*/
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
* @return void
*/
public function setDifficulty(int $difficulty);
/**
* Performs garbage collection in the level provider, such as cleaning up regions in Region-based worlds.
*
* @return void
*/
public function doGarbageCollection();
/**
* Performs cleanups necessary when the level provider is closed and no longer needed.
*
* @return void
*/
public function close();

View File

@ -31,6 +31,10 @@ use function strtolower;
use function trim;
abstract class LevelProviderManager{
/**
* @var string[]
* @phpstan-var array<string, class-string<LevelProvider>>
*/
protected static $providers = [];
public static function init() : void{
@ -41,8 +45,9 @@ abstract class LevelProviderManager{
}
/**
* @param string $class
* @phpstan-param class-string<LevelProvider> $class
*
* @return void
* @throws \InvalidArgumentException
*/
public static function addProvider(string $class){
@ -65,13 +70,12 @@ abstract class LevelProviderManager{
/**
* Returns a LevelProvider class for this path, or null
*
* @param string $path
*
* @return string|null
* @phpstan-return class-string<LevelProvider>|null
*/
public static function getProvider(string $path){
foreach(self::$providers as $provider){
/** @var $provider LevelProvider */
/** @phpstan-var class-string<LevelProvider> $provider */
if($provider::isValid($path)){
return $provider;
}
@ -83,9 +87,8 @@ abstract class LevelProviderManager{
/**
* Returns a LevelProvider by name, or null if not found
*
* @param string $name
*
* @return string|null
* @phpstan-return class-string<LevelProvider>|null
*/
public static function getProviderByName(string $name){
return self::$providers[trim(strtolower($name))] ?? null;

View File

@ -45,6 +45,7 @@ use pocketmine\utils\Binary;
use pocketmine\utils\BinaryStream;
use function array_values;
use function chr;
use function count;
use function defined;
use function explode;
use function extension_loaded;
@ -101,7 +102,7 @@ class LevelDB extends BaseLevelProvider{
/** @var \LevelDB */
protected $db;
private static function checkForLevelDBExtension(){
private static function checkForLevelDBExtension() : void{
if(!extension_loaded('leveldb')){
throw new LevelException("The leveldb PHP extension is required to use this world format");
}
@ -125,8 +126,12 @@ class LevelDB extends BaseLevelProvider{
}
protected function loadLevelData() : void{
$rawLevelData = file_get_contents($this->getPath() . "level.dat");
if($rawLevelData === false or strlen($rawLevelData) <= 8){
throw new LevelException("Truncated level.dat");
}
$nbt = new LittleEndianNBTStream();
$levelData = $nbt->read(substr(file_get_contents($this->getPath() . "level.dat"), 8));
$levelData = $nbt->read(substr($rawLevelData, 8));
if($levelData instanceof CompoundTag){
$this->levelData = $levelData;
}else{
@ -247,7 +252,6 @@ class LevelDB extends BaseLevelProvider{
$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"])){
@ -292,10 +296,6 @@ class LevelDB extends BaseLevelProvider{
}
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return Chunk|null
* @throws UnsupportedChunkFormatException
*/
protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk{
@ -516,10 +516,9 @@ class LevelDB extends BaseLevelProvider{
/**
* @param CompoundTag[] $targets
* @param string $index
*/
private function writeTags(array $targets, string $index){
if(!empty($targets)){
private function writeTags(array $targets, string $index) : void{
if(count($targets) > 0){
$nbt = new LittleEndianNBTStream();
$this->db->put($index, $nbt->write($targets));
}else{
@ -527,9 +526,6 @@ class LevelDB extends BaseLevelProvider{
}
}
/**
* @return \LevelDB
*/
public function getDatabase() : \LevelDB{
return $this->db;
}

View File

@ -21,10 +21,8 @@
declare(strict_types=1);
namespace pocketmine\level\format\io\region;
class CorruptedRegionException extends RegionException{
}

View File

@ -67,11 +67,6 @@ class McRegion extends BaseLevelProvider{
/** @var RegionLoader[] */
protected $regions = [];
/**
* @param Chunk $chunk
*
* @return string
*/
protected function nbtSerialize(Chunk $chunk) : string{
$nbt = new CompoundTag("Level", []);
$nbt->setInt("xPos", $chunk->getX());
@ -127,9 +122,6 @@ class McRegion extends BaseLevelProvider{
}
/**
* @param string $data
*
* @return Chunk
* @throws CorruptedChunkException
*/
protected function nbtDeserialize(string $data) : Chunk{
@ -206,9 +198,6 @@ class McRegion extends BaseLevelProvider{
}
/**
* @param string $context
* @param ListTag $list
*
* @return CompoundTag[]
* @throws CorruptedChunkException
*/
@ -236,7 +225,6 @@ class McRegion extends BaseLevelProvider{
/**
* Returns the storage version as per Minecraft PC world formats.
* @return int
*/
public static function getPcWorldFormatVersion() : int{
return 19132; //mcregion
@ -251,7 +239,7 @@ class McRegion extends BaseLevelProvider{
$isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/"));
if($isValid){
$files = array_filter(scandir($path . "/region/", SCANDIR_SORT_NONE), function($file){
$files = array_filter(scandir($path . "/region/", SCANDIR_SORT_NONE), function(string $file) : bool{
return substr($file, strrpos($file, ".") + 1, 2) === "mc"; //region file
});
@ -329,10 +317,10 @@ class McRegion extends BaseLevelProvider{
}
/**
* @param int $chunkX
* @param int $chunkZ
* @param int &$regionX
* @param int &$regionZ
* @param int $regionX reference parameter
* @param int $regionZ reference parameter
*
* @return void
*/
public static function getRegionIndex(int $chunkX, int $chunkZ, &$regionX, &$regionZ){
$regionX = $chunkX >> 5;
@ -340,9 +328,6 @@ class McRegion extends BaseLevelProvider{
}
/**
* @param int $regionX
* @param int $regionZ
*
* @return RegionLoader|null
*/
protected function getRegion(int $regionX, int $regionZ){
@ -351,19 +336,13 @@ class McRegion extends BaseLevelProvider{
/**
* Returns the path to a specific region file based on its X/Z coordinates
*
* @param int $regionX
* @param int $regionZ
*
* @return string
*/
protected function pathToRegion(int $regionX, int $regionZ) : string{
return $this->path . "region/r.$regionX.$regionZ." . static::REGION_FILE_EXTENSION;
}
/**
* @param int $regionX
* @param int $regionZ
* @return void
*/
protected function loadRegion(int $regionX, int $regionZ){
if(!isset($this->regions[$index = Level::chunkHash($regionX, $regionZ)])){
@ -398,11 +377,6 @@ class McRegion extends BaseLevelProvider{
}
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return Chunk|null
*
* @throws CorruptedChunkException
*/
protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk{

View File

@ -21,10 +21,8 @@
declare(strict_types=1);
namespace pocketmine\level\format\io\region;
class RegionException extends \RuntimeException{
}

View File

@ -62,6 +62,7 @@ class RegionLoader{
private const FIRST_SECTOR = 2; //location table occupies 0 and 1
/** @var int */
public static $COMPRESSION_LEVEL = 7;
/** @var int */
@ -86,6 +87,7 @@ class RegionLoader{
}
/**
* @return void
* @throws CorruptedRegionException
*/
public function open(){
@ -120,10 +122,6 @@ class RegionLoader{
}
/**
* @param int $x
* @param int $z
*
* @return null|string
* @throws \InvalidArgumentException if invalid coordinates are given
* @throws CorruptedChunkException if chunk corruption is detected
*/
@ -172,10 +170,6 @@ class RegionLoader{
}
/**
* @param int $x
* @param int $z
*
* @return bool
* @throws \InvalidArgumentException
*/
public function chunkExists(int $x, int $z) : bool{
@ -183,10 +177,7 @@ class RegionLoader{
}
/**
* @param int $x
* @param int $z
* @param string $chunkData
*
* @return void
* @throws ChunkException
* @throws \InvalidArgumentException
*/
@ -216,9 +207,7 @@ class RegionLoader{
}
/**
* @param int $x
* @param int $z
*
* @return void
* @throws \InvalidArgumentException
*/
public function removeChunk(int $x, int $z){
@ -228,10 +217,6 @@ class RegionLoader{
}
/**
* @param int $x
* @param int $z
*
* @return int
* @throws \InvalidArgumentException
*/
protected static function getChunkOffset(int $x, int $z) : int{
@ -242,9 +227,8 @@ class RegionLoader{
}
/**
* @param int $offset
* @param int &$x
* @param int &$z
* @param int $x reference parameter
* @param int $z reference parameter
*/
protected static function getChunkCoords(int $offset, ?int &$x, ?int &$z) : void{
$x = $offset & 0x1f;
@ -254,7 +238,7 @@ class RegionLoader{
/**
* Writes the region header and closes the file
*
* @param bool $writeHeader
* @return void
*/
public function close(bool $writeHeader = true){
if(is_resource($this->filePointer)){
@ -267,6 +251,7 @@ class RegionLoader{
}
/**
* @return void
* @throws CorruptedRegionException
*/
protected function loadLocationTable(){
@ -328,7 +313,7 @@ class RegionLoader{
}
}
private function writeLocationTable(){
private function writeLocationTable() : void{
$write = [];
for($i = 0; $i < 1024; ++$i){
@ -341,6 +326,11 @@ class RegionLoader{
fwrite($this->filePointer, pack("N*", ...$write), 4096 * 2);
}
/**
* @param int $index
*
* @return void
*/
protected function writeLocationIndex($index){
fseek($this->filePointer, $index << 2);
fwrite($this->filePointer, Binary::writeInt(($this->locationTable[$index]->getFirstSector() << 8) | $this->locationTable[$index]->getSectorCount()), 4);
@ -348,6 +338,9 @@ class RegionLoader{
fwrite($this->filePointer, Binary::writeInt($this->locationTable[$index]->getTimestamp()), 4);
}
/**
* @return void
*/
protected function createBlank(){
fseek($this->filePointer, 0);
ftruncate($this->filePointer, 8192); // this fills the file with the null byte

View File

@ -35,10 +35,6 @@ class RegionLocationTableEntry{
private $timestamp;
/**
* @param int $firstSector
* @param int $sectorCount
* @param int $timestamp
*
* @throws \InvalidArgumentException
*/
public function __construct(int $firstSector, int $sectorCount, int $timestamp){
@ -53,16 +49,10 @@ class RegionLocationTableEntry{
$this->timestamp = $timestamp;
}
/**
* @return int
*/
public function getFirstSector() : int{
return $this->firstSector;
}
/**
* @return int
*/
public function getLastSector() : int{
return $this->firstSector + $this->sectorCount - 1;
}
@ -75,23 +65,14 @@ class RegionLocationTableEntry{
return range($this->getFirstSector(), $this->getLastSector());
}
/**
* @return int
*/
public function getSectorCount() : int{
return $this->sectorCount;
}
/**
* @return int
*/
public function getTimestamp() : int{
return $this->timestamp;
}
/**
* @return bool
*/
public function isNull() : bool{
return $this->firstSector === 0 or $this->sectorCount === 0;
}

View File

@ -44,13 +44,19 @@ class Flat extends Generator{
private $chunk;
/** @var Populator[] */
private $populators = [];
/** @var int[][] */
/**
* @var int[][]
* @phpstan-var array<int, array{0: int, 1: int}>
*/
private $structure;
/** @var int */
private $floorLevel;
/** @var int */
private $biome;
/** @var mixed[] */
/**
* @var mixed[]
* @phpstan-var array<string, mixed>
*/
private $options;
/** @var string */
private $preset;
@ -64,7 +70,8 @@ class Flat extends Generator{
}
/**
* @param array $options
* @param mixed[] $options
* @phpstan-param array<string, mixed> $options
*
* @throws InvalidGeneratorOptionsException
*/
@ -96,9 +103,9 @@ class Flat extends Generator{
}
/**
* @param string $layers
*
* @return int[][]
* @phpstan-return array<int, array{0: int, 1: int}>
*
* @throws InvalidGeneratorOptionsException
*/
public static function parseLayers(string $layers) : array{
@ -127,9 +134,9 @@ class Flat extends Generator{
protected function parsePreset() : void{
$preset = explode(";", $this->preset);
$blocks = (string) ($preset[1] ?? "");
$blocks = $preset[1] ?? "";
$this->biome = (int) ($preset[2] ?? 1);
$options = (string) ($preset[3] ?? "");
$options = $preset[3] ?? "";
$this->structure = self::parseLayers($blocks);
$this->floorLevel = count($this->structure);

View File

@ -36,10 +36,6 @@ abstract class Generator{
/**
* Converts a string level seed into an integer for use by the generator.
*
* @param string $seed
*
* @return int|null
*/
public static function convertSeed(string $seed) : ?int{
if($seed === ""){ //empty seed should cause a random seed to be selected - can't use 0 here because 0 is a valid seed
@ -59,13 +55,13 @@ abstract class Generator{
protected $random;
/**
* @param array $settings
*
* @throws InvalidGeneratorOptionsException
*
* @param mixed[] $settings
* @phpstan-param array<string, mixed> $settings
*/
abstract public function __construct(array $settings = []);
public function init(ChunkManager $level, Random $random) : void{
$this->level = $level;
$this->random = $random;
@ -75,6 +71,10 @@ abstract class Generator{
abstract public function populateChunk(int $chunkX, int $chunkZ) : void;
/**
* @return mixed[]
* @phpstan-return array<string, mixed>
*/
abstract public function getSettings() : array;
abstract public function getName() : string;

View File

@ -30,7 +30,10 @@ use function is_subclass_of;
use function strtolower;
final class GeneratorManager{
/** @var string[] name => classname mapping */
/**
* @var string[] name => classname mapping
* @phpstan-var array<string, class-string<Generator>>
*/
private static $list = [];
/**
@ -48,6 +51,7 @@ final class GeneratorManager{
* @param string $class Fully qualified name of class that extends \pocketmine\level\generator\Generator
* @param string $name Alias for this generator type that can be written in configs
* @param bool $overwrite Whether to force overwriting any existing registered generator with the same name
* @phpstan-param class-string<Generator> $class
*/
public static function addGenerator(string $class, string $name, bool $overwrite = false) : void{
if(!is_subclass_of($class, Generator::class)){
@ -73,10 +77,11 @@ final class GeneratorManager{
/**
* Returns a class name of a registered Generator matching the given name.
*
* @param string $name
* @param bool $throwOnMissing @deprecated this is for backwards compatibility only
*
* @return string|Generator Name of class that extends Generator (not an actual Generator object)
* @return string Name of class that extends Generator
* @phpstan-return class-string<Generator>
*
* @throws \InvalidArgumentException if the generator type isn't registered
*/
public static function getGenerator(string $name, bool $throwOnMissing = false){
@ -94,8 +99,7 @@ final class GeneratorManager{
* Returns the registered name of the given Generator class.
*
* @param string $class Fully qualified name of class that extends \pocketmine\level\generator\Generator
*
* @return string
* @phpstan-param class-string<Generator> $class
*/
public static function getGeneratorName(string $class) : string{
foreach(self::$list as $name => $c){

View File

@ -34,12 +34,21 @@ use function unserialize;
class GeneratorRegisterTask extends AsyncTask{
/** @var string */
public $generatorClass;
/** @var string */
public $settings;
/** @var int */
public $seed;
/** @var int */
public $levelId;
/** @var int */
public $worldHeight = Level::Y_MAX;
/**
* @param mixed[] $generatorSettings
* @phpstan-param array<string, mixed> $generatorSettings
*/
public function __construct(Level $level, string $generatorClass, array $generatorSettings = []){
$this->generatorClass = $generatorClass;
$this->settings = serialize($generatorSettings);

View File

@ -28,6 +28,7 @@ use pocketmine\scheduler\AsyncTask;
class GeneratorUnregisterTask extends AsyncTask{
/** @var int */
public $levelId;
public function __construct(Level $level){

View File

@ -31,18 +31,31 @@ use pocketmine\Server;
class PopulationTask extends AsyncTask{
/** @var bool */
public $state;
/** @var int */
public $levelId;
/** @var string */
public $chunk;
/** @var string */
public $chunk0;
/** @var string */
public $chunk1;
/** @var string */
public $chunk2;
/** @var string */
public $chunk3;
//center chunk
/** @var string */
public $chunk5;
/** @var string */
public $chunk6;
/** @var string */
public $chunk7;
/** @var string */
public $chunk8;
public function __construct(Level $level, Chunk $chunk){
@ -89,48 +102,26 @@ class PopulationTask extends AsyncTask{
}
foreach($chunks as $c){
if($c !== null){
$manager->setChunk($c->getX(), $c->getZ(), $c);
if(!$c->isGenerated()){
$generator->generateChunk($c->getX(), $c->getZ());
$c = $manager->getChunk($c->getX(), $c->getZ());
$c->setGenerated();
}
$manager->setChunk($c->getX(), $c->getZ(), $c);
if(!$c->isGenerated()){
$generator->generateChunk($c->getX(), $c->getZ());
$c->setGenerated();
}
}
$generator->populateChunk($chunk->getX(), $chunk->getZ());
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
$chunk->recalculateHeightMap();
$chunk->populateSkyLight();
$chunk->setLightPopulated();
$chunk->setPopulated();
$this->chunk = $chunk->fastSerialize();
$manager->setChunk($chunk->getX(), $chunk->getZ(), null);
foreach($chunks as $i => $c){
if($c !== null){
$c = $chunks[$i] = $manager->getChunk($c->getX(), $c->getZ());
if(!$c->hasChanged()){
$chunks[$i] = null;
}
}else{
//This way non-changed chunks are not set
$chunks[$i] = null;
}
$this->{"chunk$i"} = $c->hasChanged() ? $c->fastSerialize() : null;
}
$manager->cleanChunks();
for($i = 0; $i < 9; ++$i){
if($i === 4){
continue;
}
$this->{"chunk$i"} = $chunks[$i] !== null ? $chunks[$i]->fastSerialize() : null;
}
}
public function onCompletion(Server $server){

View File

@ -34,7 +34,10 @@ abstract class BiomeSelector{
/** @var Simplex */
private $rainfall;
/** @var Biome[]|\SplFixedArray */
/**
* @var Biome[]|\SplFixedArray
* @phpstan-var \SplFixedArray<Biome>
*/
private $map = null;
public function __construct(Random $random){
@ -45,13 +48,13 @@ abstract class BiomeSelector{
/**
* Lookup function called by recalculate() to determine the biome to use for this temperature and rainfall.
*
* @param float $temperature
* @param float $rainfall
*
* @return int biome ID 0-255
*/
abstract protected function lookup(float $temperature, float $rainfall) : int;
/**
* @return void
*/
public function recalculate(){
$this->map = new \SplFixedArray(64 * 64);
@ -66,20 +69,29 @@ abstract class BiomeSelector{
}
}
/**
* @param float $x
* @param float $z
*
* @return float
*/
public function getTemperature($x, $z){
return ($this->temperature->noise2D($x, $z, true) + 1) / 2;
}
/**
* @param float $x
* @param float $z
*
* @return float
*/
public function getRainfall($x, $z){
return ($this->rainfall->noise2D($x, $z, true) + 1) / 2;
}
/**
* TODO: not sure on types here
* @param int|float $x
* @param int|float $z
*
* @return Biome
* @param int $x
* @param int $z
*/
public function pickBiome($x, $z) : Biome{
$temperature = (int) ($this->getTemperature($x, $z) * 63);

View File

@ -53,7 +53,8 @@ class Nether extends Generator{
private $noiseBase;
/**
* @param array $options
* @param mixed[] $options
* @phpstan-param array<string, mixed> $options
*
* @throws InvalidGeneratorOptionsException
*/

View File

@ -26,35 +26,79 @@ declare(strict_types=1);
*/
namespace pocketmine\level\generator\noise;
use function array_fill;
use function assert;
abstract class Noise{
/** @var int[] */
protected $perm = [];
/** @var float */
protected $offsetX = 0;
/** @var float */
protected $offsetY = 0;
/** @var float */
protected $offsetZ = 0;
/** @var int */
protected $octaves = 8;
/** @var float */
protected $persistence;
/** @var float */
protected $expansion;
/**
* @param float $x
*/
public static function floor($x) : int{
return $x >= 0 ? (int) $x : (int) ($x - 1);
}
/**
* @param float $x
*
* @return float
*/
public static function fade($x){
return $x * $x * $x * ($x * ($x * 6 - 15) + 10);
}
/**
* @param float $x
* @param float $y
* @param float $z
*
* @return float
*/
public static function lerp($x, $y, $z){
return $y + $x * ($z - $y);
}
/**
* @param float $x
* @param float $x1
* @param float $x2
* @param float $q0
* @param float $q1
*
* @return float
*/
public static function linearLerp($x, $x1, $x2, $q0, $q1){
return (($x2 - $x) / ($x2 - $x1)) * $q0 + (($x - $x1) / ($x2 - $x1)) * $q1;
}
/**
* @param float $x
* @param float $y
* @param float $q00
* @param float $q01
* @param float $q10
* @param float $q11
* @param float $x1
* @param float $x2
* @param float $y1
* @param float $y2
*
* @return float
*/
public static function bilinearLerp($x, $y, $q00, $q01, $q10, $q11, $x1, $x2, $y1, $y2){
$dx1 = (($x2 - $x) / ($x2 - $x1));
$dx2 = (($x - $x1) / ($x2 - $x1));
@ -66,6 +110,27 @@ abstract class Noise{
);
}
/**
* @param float $x
* @param float $y
* @param float $z
* @param float $q000
* @param float $q001
* @param float $q010
* @param float $q011
* @param float $q100
* @param float $q101
* @param float $q110
* @param float $q111
* @param float $x1
* @param float $x2
* @param float $y1
* @param float $y2
* @param float $z1
* @param float $z2
*
* @return float
*/
public static function trilinearLerp($x, $y, $z, $q000, $q001, $q010, $q011, $q100, $q101, $q110, $q111, $x1, $x2, $y1, $y2, $z1, $z2){
$dx1 = (($x2 - $x) / ($x2 - $x1));
$dx2 = (($x - $x1) / ($x2 - $x1));
@ -87,6 +152,14 @@ abstract class Noise{
);
}
/**
* @param int $hash
* @param float $x
* @param float $y
* @param float $z
*
* @return float
*/
public static function grad($hash, $x, $y, $z){
$hash &= 15;
$u = $hash < 8 ? $x : $y;
@ -95,10 +168,30 @@ abstract class Noise{
return (($hash & 1) === 0 ? $u : -$u) + (($hash & 2) === 0 ? $v : -$v);
}
/**
* @param float $x
* @param float $z
*
* @return float
*/
abstract public function getNoise2D($x, $z);
/**
* @param float $x
* @param float $y
* @param float $z
*
* @return float
*/
abstract public function getNoise3D($x, $y, $z);
/**
* @param float $x
* @param float $z
* @param bool $normalized
*
* @return float
*/
public function noise2D($x, $z, $normalized = false){
$result = 0;
$amp = 1;
@ -122,6 +215,14 @@ abstract class Noise{
return $result;
}
/**
* @param float $x
* @param float $y
* @param float $z
* @param bool $normalized
*
* @return float
*/
public function noise3D($x, $y, $z, $normalized = false){
$result = 0;
$amp = 1;
@ -146,15 +247,9 @@ abstract class Noise{
return $result;
}
/**
* @param int $xSize
* @param int $samplingRate
* @param int $x
* @param int $y
* @param int $z
*
* @return \SplFixedArray
* @return \SplFixedArray|float[]
* @phpstan-return \SplFixedArray<float>
*/
public function getFastNoise1D(int $xSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
if($samplingRate === 0){
@ -181,14 +276,8 @@ abstract class Noise{
}
/**
* @param int $xSize
* @param int $zSize
* @param int $samplingRate
* @param int $x
* @param int $y
* @param int $z
*
* @return \SplFixedArray
* @return \SplFixedArray|float[][]
* @phpstan-return \SplFixedArray<\SplFixedArray<float>>
*/
public function getFastNoise2D(int $xSize, int $zSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
assert($samplingRate !== 0, new \InvalidArgumentException("samplingRate cannot be 0"));
@ -227,17 +316,7 @@ abstract class Noise{
}
/**
* @param int $xSize
* @param int $ySize
* @param int $zSize
* @param int $xSamplingRate
* @param int $ySamplingRate
* @param int $zSamplingRate
* @param int $x
* @param int $y
* @param int $z
*
* @return array
* @return float[][][]
*/
public function getFastNoise3D(int $xSize, int $ySize, int $zSize, int $xSamplingRate, int $ySamplingRate, int $zSamplingRate, int $x, int $y, int $z) : array{
@ -297,6 +376,13 @@ abstract class Noise{
return $noiseArray;
}
/**
* @param float $x
* @param float $y
* @param float $z
*
* @return void
*/
public function setOffset($x, $y, $z){
$this->offsetX = $x;
$this->offsetY = $y;

View File

@ -26,13 +26,18 @@ namespace pocketmine\level\generator\noise;
use pocketmine\utils\Random;
class Perlin extends Noise{
/** @var int[][] */
public static $grad3 = [
[1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0],
[1, 0, 1], [-1, 0, 1], [1, 0, -1], [-1, 0, -1],
[0, 1, 1], [0, -1, 1], [0, 1, -1], [0, -1, -1]
];
/**
* @param int $octaves
* @param float $persistence
* @param float $expansion
*/
public function __construct(Random $random, $octaves, $persistence, $expansion = 1){
$this->octaves = $octaves;
$this->persistence = $persistence;
@ -144,6 +149,12 @@ class Perlin extends Noise{
*/
}
/**
* @param float $x
* @param float $y
*
* @return float
*/
public function getNoise2D($x, $y){
return $this->getNoise3D($x, $y, 0);
}

View File

@ -34,18 +34,31 @@ use function sqrt;
* http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
*/
class Simplex extends Perlin{
/** @var float */
protected static $SQRT_3;
/** @var float */
protected static $SQRT_5;
/** @var float */
protected static $F2;
/** @var float */
protected static $G2;
/** @var float */
protected static $G22;
/** @var float */
protected static $F3;
/** @var float */
protected static $G3;
/** @var float */
protected static $F4;
/** @var float */
protected static $G4;
/** @var float */
protected static $G42;
/** @var float */
protected static $G43;
/** @var float */
protected static $G44;
/** @var int[][] */
protected static $grad4 = [[0, 1, 1, 1], [0, 1, 1, -1], [0, 1, -1, 1], [0, 1, -1, -1],
[0, -1, 1, 1], [0, -1, 1, -1], [0, -1, -1, 1], [0, -1, -1, -1],
[1, 0, 1, 1], [1, 0, 1, -1], [1, 0, -1, 1], [1, 0, -1, -1],
@ -54,6 +67,8 @@ class Simplex extends Perlin{
[-1, 1, 0, 1], [-1, 1, 0, -1], [-1, -1, 0, 1], [-1, -1, 0, -1],
[1, 1, 1, 0], [1, 1, -1, 0], [1, -1, 1, 0], [1, -1, -1, 0],
[-1, 1, 1, 0], [-1, 1, -1, 0], [-1, -1, 1, 0], [-1, -1, -1, 0]];
/** @var int[][] */
protected static $simplex = [
[0, 1, 2, 3], [0, 1, 3, 2], [0, 0, 0, 0], [0, 2, 3, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 2, 3, 0],
[0, 2, 1, 3], [0, 0, 0, 0], [0, 3, 1, 2], [0, 3, 2, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 3, 2, 0],
@ -63,9 +78,15 @@ class Simplex extends Perlin{
[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0],
[2, 0, 1, 3], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [3, 0, 1, 2], [3, 0, 2, 1], [0, 0, 0, 0], [3, 1, 2, 0],
[2, 1, 0, 3], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [3, 1, 0, 2], [0, 0, 0, 0], [3, 2, 0, 1], [3, 2, 1, 0]];
/** @var float */
protected $offsetW;
/**
* @param int $octaves
* @param float $persistence
* @param float $expansion
*/
public function __construct(Random $random, $octaves, $persistence, $expansion = 1){
parent::__construct($random, $octaves, $persistence, $expansion);
$this->offsetW = $random->nextFloat() * 256;
@ -83,14 +104,38 @@ class Simplex extends Perlin{
self::$G44 = self::$G4 * 4.0 - 1.0;
}
/**
* @param int[] $g
* @param float $x
* @param float $y
*
* @return float
*/
protected static function dot2D($g, $x, $y){
return $g[0] * $x + $g[1] * $y;
}
/**
* @param int[] $g
* @param float $x
* @param float $y
* @param float $z
*
* @return float
*/
protected static function dot3D($g, $x, $y, $z){
return $g[0] * $x + $g[1] * $y + $g[2] * $z;
}
/**
* @param int[] $g
* @param float $x
* @param float $y
* @param float $z
* @param float $w
*
* @return float
*/
protected static function dot4D($g, $x, $y, $z, $w){
return $g[0] * $x + $g[1] * $y + $g[2] * $z + $g[3] * $w;
}
@ -219,6 +264,12 @@ class Simplex extends Perlin{
return 32.0 * $n;
}
/**
* @param float $x
* @param float $y
*
* @return float
*/
public function getNoise2D($x, $y){
$x += $this->offsetX;
$y += $this->offsetY;

View File

@ -55,11 +55,14 @@ class Normal extends Generator{
/** @var BiomeSelector */
private $selector;
/** @var float[][]|null */
private static $GAUSSIAN_KERNEL = null;
/** @var int */
private static $SMOOTH_SIZE = 2;
/**
* @param array $options
* @param mixed[] $options
* @phpstan-param array<string, mixed> $options
*
* @throws InvalidGeneratorOptionsException
*/

View File

@ -26,60 +26,19 @@ namespace pocketmine\level\generator\object;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;
/**
* @deprecated
*/
class BigTree extends Tree{
private $trunkHeightMultiplier = 0.618;
private $trunkHeight;
private $leafAmount = 1;
private $leafDistanceLimit = 5;
private $widthScale = 1;
private $branchSlope = 0.381;
private $totalHeight = 6;
private $leavesHeight = 3;
protected $radiusIncrease = 0;
private $addLeavesVines = false;
private $addLogVines = false;
private $addCocoaPlants = false;
public function canPlaceObject(ChunkManager $level, int $x, int $y, int $z, Random $random) : bool{
return false;
}
/**
* @return void
*/
public function placeObject(ChunkManager $level, int $x, int $y, int $z, Random $random){
/*$this->trunkHeight = (int) ($this->totalHeight * $this->trunkHeightMultiplier);
$leaves = $this->getLeafGroupPoints($level, $pos);
foreach($leaves as $leafGroup){
$groupX = $leafGroup->getBlockX();
$groupY = $leafGroup->getBlockY();
$groupZ = $leafGroup->getBlockZ();
for($yy = $groupY; $yy < $groupY + $this->leafDistanceLimit; ++$yy){
$this->generateGroupLayer($level, $groupX, $yy, $groupZ, $this->getLeafGroupLayerSize($yy - $groupY));
}
}
final BlockIterator trunk = new BlockIterator(new Point(w, x, y - 1, z), new Point(w, x, y + trunkHeight, z));
while (trunk.hasNext()) {
trunk.next().setMaterial(VanillaMaterials.LOG, logMetadata);
}
generateBranches(w, x, y, z, leaves);
$level->setBlock($x, $pos->y - 1, $z, 3, 0);
$this->totalHeight += $random->nextRange(0, 2);
$this->leavesHeight += mt_rand(0, 1);
for($yy = ($this->totalHeight - $this->leavesHeight); $yy < ($this->totalHeight + 1); ++$yy){
$yRadius = ($yy - $this->totalHeight);
$xzRadius = (int) (($this->radiusIncrease + 1) - $yRadius / 2);
for($xx = -$xzRadius; $xx < ($xzRadius + 1); ++$xx){
for($zz = -$xzRadius; $zz < ($xzRadius + 1); ++$zz){
if((abs($xx) != $xzRadius or abs($zz) != $xzRadius) and $yRadius != 0){
$level->setBlock($pos->x + $xx, $pos->y + $yy, $pos->z + $zz, 18, $this->type);
}
}
}
}
for($yy = 0; $yy < ($this->totalHeight - 1); ++$yy){
$level->setBlock($x, $pos->y + $yy, $z, 17, $this->type);
}
*/
}
}

View File

@ -30,6 +30,7 @@ use pocketmine\utils\Random;
class BirchTree extends Tree{
/** @var bool */
protected $superBirch = false;
public function __construct(bool $superBirch = false){
@ -39,6 +40,9 @@ class BirchTree extends Tree{
$this->superBirch = $superBirch;
}
/**
* @return void
*/
public function placeObject(ChunkManager $level, int $x, int $y, int $z, Random $random){
$this->treeHeight = $random->nextBoundedInt(3) + 5;
if($this->superBirch){

View File

@ -36,6 +36,9 @@ class OakTree extends Tree{
$this->type = Wood::OAK;
}
/**
* @return void
*/
public function placeObject(ChunkManager $level, int $x, int $y, int $z, Random $random){
$this->treeHeight = $random->nextBoundedInt(3) + 4;
parent::placeObject($level, $x, $y, $z, $random);

View File

@ -49,6 +49,9 @@ class Ore{
return $level->getBlockIdAt($x, $y, $z) === Block::STONE;
}
/**
* @return void
*/
public function placeObject(ChunkManager $level, int $x, int $y, int $z){
$clusterSize = $this->type->clusterSize;
$angle = $this->random->nextFloat() * M_PI;
@ -72,24 +75,24 @@ class Ore{
$endY = (int) ($seedY + $size);
$endZ = (int) ($seedZ + $size);
for($x = $startX; $x <= $endX; ++$x){
$sizeX = ($x + 0.5 - $seedX) / $size;
for($xx = $startX; $xx <= $endX; ++$xx){
$sizeX = ($xx + 0.5 - $seedX) / $size;
$sizeX *= $sizeX;
if($sizeX < 1){
for($y = $startY; $y <= $endY; ++$y){
$sizeY = ($y + 0.5 - $seedY) / $size;
for($yy = $startY; $yy <= $endY; ++$yy){
$sizeY = ($yy + 0.5 - $seedY) / $size;
$sizeY *= $sizeY;
if($y > 0 and ($sizeX + $sizeY) < 1){
for($z = $startZ; $z <= $endZ; ++$z){
$sizeZ = ($z + 0.5 - $seedZ) / $size;
if($yy > 0 and ($sizeX + $sizeY) < 1){
for($zz = $startZ; $zz <= $endZ; ++$zz){
$sizeZ = ($zz + 0.5 - $seedZ) / $size;
$sizeZ *= $sizeZ;
if(($sizeX + $sizeY + $sizeZ) < 1 and $level->getBlockIdAt($x, $y, $z) === Block::STONE){
$level->setBlockIdAt($x, $y, $z, $this->type->material->getId());
if(($sizeX + $sizeY + $sizeZ) < 1 and $level->getBlockIdAt($xx, $yy, $zz) === Block::STONE){
$level->setBlockIdAt($xx, $yy, $zz, $this->type->material->getId());
if($this->type->material->getDamage() !== 0){
$level->setBlockDataAt($x, $y, $z, $this->type->material->getDamage());
$level->setBlockDataAt($xx, $yy, $zz, $this->type->material->getDamage());
}
}
}

View File

@ -29,7 +29,9 @@ use pocketmine\math\Vector3;
use pocketmine\utils\Random;
class Pond{
/** @var Random */
private $random;
/** @var Block */
public $type;
public function __construct(Random $random, Block $type){
@ -41,6 +43,9 @@ class Pond{
return false;
}
/**
* @return void
*/
public function placeObject(ChunkManager $level, Vector3 $pos){
}

View File

@ -26,7 +26,6 @@ declare(strict_types=1);
*/
namespace pocketmine\level\generator\object;
abstract class PopulatorObject{
}

View File

@ -39,6 +39,9 @@ class SpruceTree extends Tree{
$this->treeHeight = 10;
}
/**
* @return void
*/
public function placeObject(ChunkManager $level, int $x, int $y, int $z, Random $random){
$this->treeHeight = $random->nextBoundedInt(4) + 6;

View File

@ -31,6 +31,9 @@ use function count;
class TallGrass{
/**
* @return void
*/
public static function growGrass(ChunkManager $level, Vector3 $pos, Random $random, int $count = 15, int $radius = 10){
$arr = [
[Block::DANDELION, 0],

View File

@ -31,6 +31,7 @@ use pocketmine\utils\Random;
use function abs;
abstract class Tree{
/** @var bool[] */
public $overridable = [
Block::AIR => true,
Block::SAPLING => true,
@ -39,11 +40,18 @@ abstract class Tree{
Block::LEAVES2 => true
];
/** @var int */
public $type = 0;
/** @var int */
public $trunkBlock = Block::LOG;
/** @var int */
public $leafBlock = Block::LEAVES;
/** @var int */
public $treeHeight = 7;
/**
* @return void
*/
public static function growTree(ChunkManager $level, int $x, int $y, int $z, Random $random, int $type = 0){
switch($type){
case Sapling::SPRUCE:
@ -76,7 +84,6 @@ abstract class Tree{
}
}
public function canPlaceObject(ChunkManager $level, int $x, int $y, int $z, Random $random) : bool{
$radiusToCheck = 0;
for($yy = 0; $yy < $this->treeHeight + 3; ++$yy){
@ -95,6 +102,9 @@ abstract class Tree{
return true;
}
/**
* @return void
*/
public function placeObject(ChunkManager $level, int $x, int $y, int $z, Random $random){
$this->placeTrunk($level, $x, $y, $z, $random, $this->treeHeight - 1);
@ -118,6 +128,9 @@ abstract class Tree{
}
}
/**
* @return void
*/
protected function placeTrunk(ChunkManager $level, int $x, int $y, int $z, Random $random, int $trunkHeight){
// The base dirt block
$level->setBlockIdAt($x, $y - 1, $z, Block::DIRT);

View File

@ -47,12 +47,13 @@ class GroundCover extends Populator{
}
$column = $chunk->getBlockIdColumn($x, $z);
for($y = 127; $y > 0; --$y){
if($column[$y] !== "\x00" and !BlockFactory::get(ord($column[$y]))->isTransparent()){
$startY = 127;
for(; $startY > 0; --$startY){
if($column[$startY] !== "\x00" and !BlockFactory::get(ord($column[$startY]))->isTransparent()){
break;
}
}
$startY = min(127, $y + $diffY);
$startY = min(127, $startY + $diffY);
$endY = $startY - count($cover);
for($y = $startY; $y > $endY and $y >= 0; --$y){
$b = $cover[$startY - $y];

View File

@ -48,6 +48,8 @@ class Ore extends Populator{
/**
* @param OreType[] $types
*
* @return void
*/
public function setOreTypes(array $types){
$this->oreTypes = $types;

View File

@ -30,8 +30,11 @@ use pocketmine\math\Vector3;
use pocketmine\utils\Random;
class Pond extends Populator{
/** @var int */
private $waterOdd = 4;
/** @var int */
private $lavaOdd = 4;
/** @var int */
private $lavaSurfaceOdd = 4;
public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){
@ -46,14 +49,23 @@ class Pond extends Populator{
}
}
/**
* @return void
*/
public function setWaterOdd(int $waterOdd){
$this->waterOdd = $waterOdd;
}
/**
* @return void
*/
public function setLavaOdd(int $lavaOdd){
$this->lavaOdd = $lavaOdd;
}
/**
* @return void
*/
public function setLavaSurfaceOdd(int $lavaSurfaceOdd){
$this->lavaSurfaceOdd = $lavaSurfaceOdd;
}

View File

@ -32,11 +32,6 @@ use pocketmine\utils\Random;
abstract class Populator{
/**
* @param ChunkManager $level
* @param int $chunkX
* @param int $chunkZ
* @param Random $random
*
* @return mixed
*/
abstract public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random);

View File

@ -30,13 +30,25 @@ use pocketmine\utils\Random;
class TallGrass extends Populator{
/** @var ChunkManager */
private $level;
/** @var int */
private $randomAmount = 1;
/** @var int */
private $baseAmount = 0;
/**
* @param int $amount
*
* @return void
*/
public function setRandomAmount($amount){
$this->randomAmount = $amount;
}
/**
* @param int $amount
*
* @return void
*/
public function setBaseAmount($amount){
$this->baseAmount = $amount;
}
@ -65,10 +77,10 @@ class TallGrass extends Populator{
for($y = 127; $y >= 0; --$y){
$b = $this->level->getBlockIdAt($x, $y, $z);
if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::LEAVES2 and $b !== Block::SNOW_LAYER){
break;
return $y + 1;
}
}
return $y === 0 ? -1 : ++$y;
return -1;
}
}

View File

@ -32,19 +32,35 @@ use pocketmine\utils\Random;
class Tree extends Populator{
/** @var ChunkManager */
private $level;
/** @var int */
private $randomAmount = 1;
/** @var int */
private $baseAmount = 0;
/** @var int */
private $type;
/**
* @param int $type
*/
public function __construct($type = Sapling::OAK){
$this->type = $type;
}
/**
* @param int $amount
*
* @return void
*/
public function setRandomAmount($amount){
$this->randomAmount = $amount;
}
/**
* @param int $amount
*
* @return void
*/
public function setBaseAmount($amount){
$this->baseAmount = $amount;
}
@ -64,15 +80,15 @@ class Tree extends Populator{
}
private function getHighestWorkableBlock(int $x, int $z) : int{
for($y = 127; $y > 0; --$y){
for($y = 127; $y >= 0; --$y){
$b = $this->level->getBlockIdAt($x, $y, $z);
if($b === Block::DIRT or $b === Block::GRASS){
break;
return $y + 1;
}elseif($b !== Block::AIR and $b !== Block::SNOW_LAYER){
return -1;
}
}
return ++$y;
return -1;
}
}

View File

@ -31,7 +31,9 @@ use pocketmine\Server;
class LightPopulationTask extends AsyncTask{
/** @var int */
public $levelId;
/** @var string */
public $chunk;
public function __construct(Level $level, Chunk $chunk){

View File

@ -59,8 +59,14 @@ abstract class LightUpdate{
abstract protected function getLight(int $x, int $y, int $z) : int;
/**
* @return void
*/
abstract protected function setLight(int $x, int $y, int $z, int $level);
/**
* @return void
*/
public function setAndUpdateLight(int $x, int $y, int $z, int $newLevel){
$this->updateNodes[Level::blockHash($x, $y, $z)] = [$x, $y, $z, $newLevel];
}
@ -84,6 +90,9 @@ abstract class LightUpdate{
}
}
/**
* @return void
*/
public function execute(){
$this->prepareNodes();
@ -137,6 +146,9 @@ abstract class LightUpdate{
}
}
/**
* @return void
*/
protected function computeRemoveLight(int $x, int $y, int $z, int $oldAdjacentLevel){
$current = $this->getLight($x, $y, $z);
@ -157,6 +169,9 @@ abstract class LightUpdate{
}
}
/**
* @return void
*/
protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel){
$current = $this->getLight($x, $y, $z);
$potentialLight = $newAdjacentLevel - BlockFactory::$lightFilter[$this->subChunkHandler->currentSubChunk->getBlockId($x & 0x0f, $y & 0x0f, $z & 0x0f)];

View File

@ -39,16 +39,15 @@ use function str_repeat;
class FloatingTextParticle extends Particle{
//TODO: HACK!
/** @var string */
protected $text;
/** @var string */
protected $title;
protected $entityId;
/** @var int|null */
protected $entityId = null;
/** @var bool */
protected $invisible = false;
/**
* @param Vector3 $pos
* @param string $text
* @param string $title
*/
public function __construct(Vector3 $pos, string $text, string $title = ""){
parent::__construct($pos->x, $pos->y, $pos->z);
$this->text = $text;

View File

@ -29,7 +29,7 @@ use pocketmine\network\mcpe\protocol\DataPacket;
abstract class Particle extends Vector3{
public const TYPE_BUBBLE = 1;
//2 same as 1
public const TYPE_BUBBLE_MANUAL = 2;
public const TYPE_CRITICAL = 3;
public const TYPE_BLOCK_FORCE_FIELD = 4;
public const TYPE_SMOKE = 5;
@ -40,56 +40,61 @@ abstract class Particle extends Vector3{
public const TYPE_LARGE_SMOKE = 10;
public const TYPE_REDSTONE = 11;
public const TYPE_RISING_RED_DUST = 12;
//62 same as 12
public const TYPE_ITEM_BREAK = 13;
public const TYPE_SNOWBALL_POOF = 14;
public const TYPE_HUGE_EXPLODE = 15;
//60 same as 15
public const TYPE_HUGE_EXPLODE_SEED = 16;
public const TYPE_MOB_FLAME = 17;
public const TYPE_HEART = 18;
public const TYPE_TERRAIN = 19;
public const TYPE_SUSPENDED_TOWN = 20, TYPE_TOWN_AURA = 20;
//61 same as 20
public const TYPE_PORTAL = 21;
//22 same as 21
public const TYPE_SPLASH = 23, TYPE_WATER_SPLASH = 23;
//24 same as 23
public const TYPE_WATER_SPLASH_MANUAL = 24;
public const TYPE_WATER_WAKE = 25;
public const TYPE_DRIP_WATER = 26;
public const TYPE_DRIP_LAVA = 27;
public const TYPE_FALLING_DUST = 28, TYPE_DUST = 28;
public const TYPE_MOB_SPELL = 29;
public const TYPE_MOB_SPELL_AMBIENT = 30;
public const TYPE_MOB_SPELL_INSTANTANEOUS = 31;
public const TYPE_INK = 32;
public const TYPE_SLIME = 33;
public const TYPE_RAIN_SPLASH = 34;
public const TYPE_VILLAGER_ANGRY = 35;
//59 same as 35
public const TYPE_VILLAGER_HAPPY = 36;
public const TYPE_ENCHANTMENT_TABLE = 37;
public const TYPE_TRACKING_EMITTER = 38;
public const TYPE_NOTE = 39;
public const TYPE_WITCH_SPELL = 40;
public const TYPE_CARROT = 41;
//42 unknown
public const TYPE_END_ROD = 43;
//58 same as 43
public const TYPE_DRAGONS_BREATH = 44;
public const TYPE_SPIT = 45;
public const TYPE_TOTEM = 46;
public const TYPE_FOOD = 47;
public const TYPE_FIREWORKS_STARTER = 48;
public const TYPE_FIREWORKS_SPARK = 49;
public const TYPE_FIREWORKS_OVERLAY = 50;
public const TYPE_BALLOON_GAS = 51;
public const TYPE_COLORED_FLAME = 52;
public const TYPE_SPARKLER = 53;
public const TYPE_CONDUIT = 54;
public const TYPE_BUBBLE_COLUMN_UP = 55;
public const TYPE_BUBBLE_COLUMN_DOWN = 56;
public const TYPE_SNEEZE = 57;
public const TYPE_DRIP_HONEY = 28;
public const TYPE_FALLING_DUST = 29, TYPE_DUST = 29;
public const TYPE_MOB_SPELL = 30;
public const TYPE_MOB_SPELL_AMBIENT = 31;
public const TYPE_MOB_SPELL_INSTANTANEOUS = 32;
public const TYPE_INK = 33;
public const TYPE_SLIME = 34;
public const TYPE_RAIN_SPLASH = 35;
public const TYPE_VILLAGER_ANGRY = 36;
public const TYPE_VILLAGER_HAPPY = 37;
public const TYPE_ENCHANTMENT_TABLE = 38;
public const TYPE_TRACKING_EMITTER = 39;
public const TYPE_NOTE = 40;
public const TYPE_WITCH_SPELL = 41;
public const TYPE_CARROT = 42;
public const TYPE_MOB_APPEARANCE = 43;
public const TYPE_END_ROD = 44;
public const TYPE_DRAGONS_BREATH = 45;
public const TYPE_SPIT = 46;
public const TYPE_TOTEM = 47;
public const TYPE_FOOD = 48;
public const TYPE_FIREWORKS_STARTER = 49;
public const TYPE_FIREWORKS_SPARK = 50;
public const TYPE_FIREWORKS_OVERLAY = 51;
public const TYPE_BALLOON_GAS = 52;
public const TYPE_COLORED_FLAME = 53;
public const TYPE_SPARKLER = 54;
public const TYPE_CONDUIT = 55;
public const TYPE_BUBBLE_COLUMN_UP = 56;
public const TYPE_BUBBLE_COLUMN_DOWN = 57;
public const TYPE_SNEEZE = 58;
public const TYPE_SHULKER_BULLET = 59;
public const TYPE_BLEACH = 60;
public const TYPE_DRAGON_DESTROY_BLOCK = 61;
public const TYPE_MYCELIUM_DUST = 62;
public const TYPE_FALLING_RED_DUST = 63;
public const TYPE_CAMPFIRE_SMOKE = 64;
public const TYPE_TALL_CAMPFIRE_SMOKE = 65;
public const TYPE_DRAGON_BREATH_FIRE = 66;
public const TYPE_DRAGON_BREATH_TRAIL = 67;
/**
* @return DataPacket|DataPacket[]