blockLayers = $blocks; self::assignData($this->skyLight, $skyLight, 2048, "\xff"); self::assignData($this->blockLight, $blockLight, 2048); } public function isEmpty(bool $checkLight = true) : bool{ foreach($this->blockLayers as $layer){ $palette = $layer->getPalette(); foreach($palette as $p){ if(($p >> 4) !== BlockLegacyIds::AIR){ return false; } } } return (!$checkLight or ( substr_count($this->skyLight, "\xff") === 2048 and $this->blockLight === ZERO_NIBBLE_ARRAY ) ); } public function getFullBlock(int $x, int $y, int $z) : int{ if(empty($this->blockLayers)){ return BlockLegacyIds::AIR << 4; } return $this->blockLayers[0]->get($x, $y, $z); } public function setFullBlock(int $x, int $y, int $z, int $block) : void{ if(empty($this->blockLayers)){ $this->blockLayers[] = new PalettedBlockArray(BlockLegacyIds::AIR << 4); } $this->blockLayers[0]->set($x, $y, $z, $block); } /** * @return PalettedBlockArray[] */ public function getBlockLayers() : array{ return $this->blockLayers; } public function getBlockLight(int $x, int $y, int $z) : int{ return (ord($this->blockLight{($x << 7) | ($z << 3) | ($y >> 1)}) >> (($y & 1) << 2)) & 0xf; } public function setBlockLight(int $x, int $y, int $z, int $level) : bool{ $i = ($x << 7) | ($z << 3) | ($y >> 1); $shift = ($y & 1) << 2; $byte = ord($this->blockLight{$i}); $this->blockLight{$i} = chr(($byte & ~(0xf << $shift)) | (($level & 0xf) << $shift)); return true; } public function getBlockSkyLight(int $x, int $y, int $z) : int{ return (ord($this->skyLight{($x << 7) | ($z << 3) | ($y >> 1)}) >> (($y & 1) << 2)) & 0xf; } public function setBlockSkyLight(int $x, int $y, int $z, int $level) : bool{ $i = ($x << 7) | ($z << 3) | ($y >> 1); $shift = ($y & 1) << 2; $byte = ord($this->skyLight{$i}); $this->skyLight{$i} = chr(($byte & ~(0xf << $shift)) | (($level & 0xf) << $shift)); return true; } public function getHighestBlockAt(int $x, int $z) : int{ if(empty($this->blockLayers)){ return -1; } for($y = 15; $y >= 0; --$y){ if(($this->blockLayers[0]->get($x, $y, $z) >> 4) !== BlockLegacyIds::AIR){ return $y; } } return -1; //highest block not in this subchunk } public function getBlockSkyLightArray() : string{ assert(strlen($this->skyLight) === 2048, "Wrong length of skylight array, expecting 2048 bytes, got " . strlen($this->skyLight)); return $this->skyLight; } public function setBlockSkyLightArray(string $data) : void{ assert(strlen($data) === 2048, "Wrong length of skylight array, expecting 2048 bytes, got " . strlen($data)); $this->skyLight = $data; } public function getBlockLightArray() : string{ assert(strlen($this->blockLight) === 2048, "Wrong length of light array, expecting 2048 bytes, got " . strlen($this->blockLight)); return $this->blockLight; } public function setBlockLightArray(string $data) : void{ assert(strlen($data) === 2048, "Wrong length of light array, expecting 2048 bytes, got " . strlen($data)); $this->blockLight = $data; } public function __debugInfo(){ return []; } public function collectGarbage() : void{ foreach($this->blockLayers as $k => $layer){ $layer->collectGarbage(); foreach($layer->getPalette() as $p){ if(($p >> 4) !== BlockLegacyIds::AIR){ continue 2; } } unset($this->blockLayers[$k]); } $this->blockLayers = array_values($this->blockLayers); /* * This strange looking code is designed to exploit PHP's copy-on-write behaviour. Assigning will copy a * reference to the const instead of duplicating the whole string. The string will only be duplicated when * modified, which is perfect for this purpose. */ if($this->skyLight === ZERO_NIBBLE_ARRAY){ $this->skyLight = ZERO_NIBBLE_ARRAY; } if($this->blockLight === ZERO_NIBBLE_ARRAY){ $this->blockLight = ZERO_NIBBLE_ARRAY; } } }