diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index a0b9e651a..9e02c6ea0 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -81,10 +81,7 @@ class Chunk{ /** @var Entity[] */ protected $entities = []; - /** - * @var \SplFixedArray|int[] - * @phpstan-var \SplFixedArray - */ + /** @var HeightArray */ protected $heightMap; /** @var BiomeArray */ @@ -100,9 +97,8 @@ class Chunk{ * @param SubChunk[] $subChunks * @param CompoundTag[] $entities * @param CompoundTag[] $tiles - * @param int[] $heightMap */ - public function __construct(int $chunkX, int $chunkZ, array $subChunks = [], ?array $entities = null, ?array $tiles = null, ?BiomeArray $biomeIds = null, array $heightMap = []){ + public function __construct(int $chunkX, int $chunkZ, array $subChunks = [], ?array $entities = null, ?array $tiles = null, ?BiomeArray $biomeIds = null, ?HeightArray $heightMap = null){ $this->x = $chunkX; $this->z = $chunkZ; @@ -112,14 +108,8 @@ class Chunk{ $this->subChunks[$y] = $subChunks[$y] ?? new SubChunk(BlockLegacyIds::AIR << 4, []); } - if(count($heightMap) === 256){ - $this->heightMap = \SplFixedArray::fromArray($heightMap); - }else{ - assert(count($heightMap) === 0, "Wrong HeightMap value count, expected 256, got " . count($heightMap)); - $val = ($this->subChunks->getSize() * 16); - $this->heightMap = \SplFixedArray::fromArray(array_fill(0, 256, $val)); - } - + $val = ($this->subChunks->getSize() * 16); + $this->heightMap = $heightMap ?? new HeightArray(array_fill(0, 256, $val)); $this->biomeIds = $biomeIds ?? new BiomeArray(str_repeat("\x00", 256)); $this->NBTtiles = $tiles; @@ -258,7 +248,7 @@ class Chunk{ * @param int $z 0-15 */ public function getHeightMap(int $x, int $z) : int{ - return $this->heightMap[($z << 4) | $x]; + return $this->heightMap->get($x, $z); } /** @@ -268,7 +258,7 @@ class Chunk{ * @param int $z 0-15 */ public function setHeightMap(int $x, int $z, int $value) : void{ - $this->heightMap[($z << 4) | $x] = $value; + $this->heightMap->set($x, $z, $value); } /** @@ -552,18 +542,14 @@ class Chunk{ * @return int[] */ public function getHeightMapArray() : array{ - return $this->heightMap->toArray(); + return $this->heightMap->getValues(); } /** * @param int[] $values - * @throws \InvalidArgumentException */ public function setHeightMapArray(array $values) : void{ - if(count($values) !== 256){ - throw new \InvalidArgumentException("Expected exactly 256 values"); - } - $this->heightMap = \SplFixedArray::fromArray($values); + $this->heightMap = new HeightArray($values); } public function isDirty() : bool{ diff --git a/src/world/format/HeightArray.php b/src/world/format/HeightArray.php new file mode 100644 index 000000000..3025d6f62 --- /dev/null +++ b/src/world/format/HeightArray.php @@ -0,0 +1,73 @@ + + */ + private $array; + + /** + * @param int[] $values ZZZZXXXX key bit order + * @phpstan-param list $values + */ + public function __construct(array $values){ + if(count($values) !== 256){ + throw new \InvalidArgumentException("Expected exactly 256 values"); + } + $this->array = \SplFixedArray::fromArray($values); + } + + private static function idx(int $x, int $z) : int{ + if($x < 0 or $x >= 16 or $z < 0 or $z >= 16){ + throw new \InvalidArgumentException("x and z must be in the range 0-15"); + } + return ($z << 4) | $x; + } + + public function get(int $x, int $z) : int{ + return $this->array[self::idx($x, $z)]; + } + + public function set(int $x, int $z, int $height) : void{ + $this->array[self::idx($x, $z)] = $height; + } + + /** + * @return int[] ZZZZXXXX key bit order + * @phpstan-return list + */ + public function getValues() : array{ + return $this->array->toArray(); + } + + public function __clone(){ + $this->array = clone $this->array; + } +} diff --git a/src/world/format/io/FastChunkSerializer.php b/src/world/format/io/FastChunkSerializer.php index e41776d32..242caebb8 100644 --- a/src/world/format/io/FastChunkSerializer.php +++ b/src/world/format/io/FastChunkSerializer.php @@ -27,6 +27,7 @@ use pocketmine\block\BlockLegacyIds; use pocketmine\utils\BinaryStream; use pocketmine\world\format\BiomeArray; use pocketmine\world\format\Chunk; +use pocketmine\world\format\HeightArray; use pocketmine\world\format\LightArray; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\format\SubChunk; @@ -120,7 +121,7 @@ final class FastChunkSerializer{ $subChunks = []; $biomeIds = null; - $heightMap = []; + $heightMap = null; if($terrainGenerated){ $count = $stream->getByte(); for($subCount = 0; $subCount < $count; ++$subCount){ @@ -142,7 +143,7 @@ final class FastChunkSerializer{ $biomeIds = new BiomeArray($stream->get(256)); if($lightPopulated){ - $heightMap = array_values(unpack("S*", $stream->get(512))); + $heightMap = new HeightArray(array_values(unpack("S*", $stream->get(512)))); } }