27 public const COORD_BIT_SIZE = 4;
28 public const COORD_MASK = ~(~0 << self::COORD_BIT_SIZE);
29 public const EDGE_LENGTH = 1 << self::COORD_BIT_SIZE;
35 private int $emptyBlockId,
36 private ?PalettedBlockArray $blockLayer0,
37 private ?PalettedBlockArray $blockLayer1,
38 private PalettedBlockArray $biomes,
39 private ?LightArray $skyLight =
null,
40 private ?LightArray $blockLight =
null
49 $this->collectGarbage();
58 return $this->blockLayer0 === null && $this->blockLayer1 === null;
67 public function getBlockStateId(
int $x,
int $y,
int $z) : int{
68 return $this->blockLayer0?->get($x, $y, $z) ?? $this->emptyBlockId;
71 public function setBlockStateId(
int $x,
int $y,
int $z,
int $block) : void{
72 if($this->blockLayer0 === null){
73 $this->blockLayer0 =
new PalettedBlockArray($this->emptyBlockId);
75 $this->blockLayer0->set($x, $y, $z, $block);
78 public function getBlockLayer0() : ?PalettedBlockArray{
79 return $this->blockLayer0;
82 public function getBlockLayer1() : ?PalettedBlockArray{
83 return $this->blockLayer1;
92 if($this->blockLayer0 !==
null){
93 $layers[] = $this->blockLayer0;
95 if($this->blockLayer1 !==
null){
96 $layers[] = $this->blockLayer1;
101 public function getHighestBlockAt(
int $x,
int $z) : ?int{
102 if($this->blockLayer0 === null){
105 for($y = self::EDGE_LENGTH - 1; $y >= 0; --$y){
106 if($this->blockLayer0->get($x, $y, $z) !== $this->emptyBlockId){
114 public function getBiomeArray() : PalettedBlockArray{ return $this->biomes; }
116 public function getBlockSkyLightArray() : LightArray{
117 return $this->skyLight ??= LightArray::fill(0);
120 public function setBlockSkyLightArray(LightArray $data) : void{
121 $this->skyLight = $data;
124 public function getBlockLightArray() : LightArray{
125 return $this->blockLight ??= LightArray::fill(0);
128 public function setBlockLightArray(LightArray $data) : void{
129 $this->blockLight = $data;
139 private static function gcBlockPalette(?PalettedBlockArray $layer,
int $emptyBlockId) : ?PalettedBlockArray{
143 $layer->collectGarbage();
144 return $layer->getBitsPerBlock() === 0 && $layer->get(0, 0, 0) === $emptyBlockId ?
null : $layer;
147 public function collectGarbage() : void{
148 $this->blockLayer0 = self::gcBlockPalette($this->blockLayer0, $this->emptyBlockId);
149 $this->blockLayer1 = self::gcBlockPalette($this->blockLayer1, $this->emptyBlockId);
150 if($this->blockLayer0 ===
null && $this->blockLayer1 !==
null){
151 $this->blockLayer0 = $this->blockLayer1;
152 $this->blockLayer1 =
null;
154 $this->biomes->collectGarbage();
156 if($this->skyLight !==
null && $this->skyLight->isUniform(0)){
157 $this->skyLight =
null;
159 if($this->blockLight !==
null && $this->blockLight->isUniform(0)){
160 $this->blockLight =
null;
164 public function __clone(){
165 $this->blockLayer0 = $this->blockLayer0 !==
null ? clone $this->blockLayer0 :
null;
166 $this->blockLayer1 = $this->blockLayer1 !==
null ? clone $this->blockLayer1 :
null;
167 $this->biomes = clone $this->biomes;
169 if($this->skyLight !==
null){
170 $this->skyLight = clone $this->skyLight;
172 if($this->blockLight !==
null){
173 $this->blockLight = clone $this->blockLight;