blocks{($x << 11) | ($z << 7) | $y}); } public function setBlockId($x, $y, $z, $id){ $this->blocks{($x << 11) | ($z << 7) | $y} = chr($id); $this->hasChanged = true; } public function getBlockData($x, $y, $z){ $m = ord($this->data{($x << 10) | ($z << 6) | ($y >> 1)}); if(($y & 1) === 0){ return $m & 0x0F; }else{ return $m >> 4; } } public function setBlockData($x, $y, $z, $data){ $i = ($x << 10) | ($z << 6) | ($y >> 1); $old_m = ord($this->data{$i}); if(($y & 1) === 0){ $this->data{$i} = chr(($old_m & 0xf0) | ($data & 0x0f)); }else{ $this->data{$i} = chr((($data & 0x0f) << 4) | ($old_m & 0x0f)); } $this->hasChanged = true; } public function getFullBlock($x, $y, $z){ $i = ($x << 11) | ($z << 7) | $y; if(($y & 1) === 0){ return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) & 0x0F); }else{ return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) >> 4); } } public function getBlock($x, $y, $z, &$blockId, &$meta = null){ $full = $this->getFullBlock($x, $y, $z); $blockId = $full >> 4; $meta = $full & 0x0f; } public function setBlock($x, $y, $z, $blockId = null, $meta = null){ $i = ($x << 11) | ($z << 7) | $y; $changed = false; if($blockId !== null){ $blockId = chr($blockId); if($this->blocks{$i} !== $blockId){ $this->blocks{$i} = $blockId; $changed = true; } } if($meta !== null){ $i >>= 1; $old_m = ord($this->data{$i}); if(($y & 1) === 0){ $this->data{$i} = chr(($old_m & 0xf0) | ($meta & 0x0f)); if(($old_m & 0x0f) !== $meta){ $changed = true; } }else{ $this->data{$i} = chr((($meta & 0x0f) << 4) | ($old_m & 0x0f)); if((($old_m & 0xf0) >> 4) !== $meta){ $changed = true; } } } if($changed){ $this->hasChanged = true; } return $changed; } public function getBlockSkyLight($x, $y, $z){ $sl = ord($this->skyLight{($x << 10) | ($z << 6) | ($y >> 1)}); if(($y & 1) === 0){ return $sl & 0x0F; }else{ return $sl >> 4; } } public function setBlockSkyLight($x, $y, $z, $level){ $i = ($x << 10) | ($z << 6) | ($y >> 1); $old_sl = ord($this->skyLight{$i}); if(($y & 1) === 0){ $this->skyLight{$i} = chr(($old_sl & 0xf0) | ($level & 0x0f)); }else{ $this->skyLight{$i} = chr((($level & 0x0f) << 4) | ($old_sl & 0x0f)); } $this->hasChanged = true; } public function getBlockLight($x, $y, $z){ $l = ord($this->blockLight{($x << 10) | ($z << 6) | ($y >> 1)}); if(($y & 1) === 0){ return $l & 0x0F; }else{ return $l >> 4; } } public function setBlockLight($x, $y, $z, $level){ $i = ($x << 10) | ($z << 6) | ($y >> 1); $old_l = ord($this->blockLight{$i}); if(($y & 1) === 0){ $this->blockLight{$i} = chr(($old_l & 0xf0) | ($level & 0x0f)); }else{ $this->blockLight{$i} = chr((($level & 0x0f) << 4) | ($old_l & 0x0f)); } $this->hasChanged = true; } public function getBlockIdColumn($x, $z){ return substr($this->blocks, ($x << 11) + ($z << 7), 128); } public function getBlockDataColumn($x, $z){ return substr($this->data, ($x << 10) + ($z << 6), 64); } public function getBlockSkyLightColumn($x, $z){ return substr($this->skyLight, ($x << 10) + ($z << 6), 64); } public function getBlockLightColumn($x, $z){ return substr($this->blockLight, ($x << 10) + ($z << 6), 64); } /** * @return bool */ public function isPopulated(){ return $this->isPopulated; } /** * @param int $value */ public function setPopulated($value = 1){ $this->isPopulated = (bool) $value; } /** * @return bool */ public function isGenerated(){ return $this->isGenerated; } /** * @param int $value */ public function setGenerated($value = 1){ $this->isGenerated = (bool) $value; } /** * @param string $data * @param LevelProvider $provider * * @return Chunk */ public static function fromBinary($data, LevelProvider $provider = null){ try{ $chunkX = Binary::readLInt(substr($data, 0, 4)); $chunkZ = Binary::readLInt(substr($data, 4, 4)); $chunkData = substr($data, 8, -1); $flags = ord(substr($data, -1)); $entities = null; $tiles = null; if($provider instanceof LevelDB){ $nbt = new NBT(NBT::LITTLE_ENDIAN); $entityData = $provider->getDatabase()->get(substr($data, 0, 8) . "\x32"); if($entityData !== false and strlen($entityData) > 0){ $nbt->read($entityData); $entities = $nbt->getData(); if(!is_array($entities)){ $entities = [$entities]; } } $tileData = $provider->getDatabase()->get(substr($data, 0, 8) . "\x31"); if($tileData !== false and strlen($tileData) > 0){ $nbt->read($tileData); $tiles = $nbt->getData(); if(!is_array($tiles)){ $tiles = [$tiles]; } } } $chunk = new Chunk($provider instanceof LevelProvider ? $provider : LevelDB::class, $chunkX, $chunkZ, $chunkData, $entities, $tiles); if($flags & 0x01){ $chunk->setGenerated(); } if($flags & 0x02){ $chunk->setPopulated(); } return $chunk; }catch(\Exception $e){ echo $e; return null; } } public function toBinary($saveExtra = false){ $chunkIndex = LevelDB::chunkIndex($this->getX(), $this->getZ()); $provider = $this->getProvider(); if($saveExtra and $provider instanceof LevelDB){ $nbt = new NBT(NBT::LITTLE_ENDIAN); $entities = []; foreach($this->getEntities() as $entity){ if(!($entity instanceof Player) and !$entity->closed){ $entity->saveNBT(); $nbt->setData($entity->namedtag); $entities[] = $nbt->write(); } } if(count($entities) > 0){ $provider->getDatabase()->put($chunkIndex . "\x32", implode($entities)); }else{ $provider->getDatabase()->delete($chunkIndex . "\x32"); } $tiles = []; foreach($this->getTiles() as $tile){ $tile->saveNBT(); $nbt->setData($tile->namedtag); $tiles[] = $nbt->write(); } if(count($tiles) > 0){ $provider->getDatabase()->put($chunkIndex . "\x31", implode($tiles)); }else{ $provider->getDatabase()->delete($chunkIndex . "\x31"); } } $biomeColors = pack("N*", ...$this->getBiomeColorArray()); return $chunkIndex . $this->getBlockIdArray() . $this->getBlockDataArray() . $this->getBlockSkyLightArray() . $this->getBlockLightArray() . $this->getBiomeIdArray() . $biomeColors . chr( ($this->isPopulated() ? 0x02 : 0) | ($this->isGenerated() ? 0x01 : 0) ); } }