LevelDB: Added conversion of legacy extradata -> 4D subchunk block layers

This commit is contained in:
Dylan K. Taylor 2019-05-17 17:15:45 +01:00
parent f7a9da4e92
commit 0f398bbe66

View File

@ -183,6 +183,47 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
return PalettedBlockArray::fromData($bitsPerBlock, $words, $palette); return PalettedBlockArray::fromData($bitsPerBlock, $words, $palette);
} }
protected static function deserializeExtraDataKey(int $chunkVersion, int $key, ?int &$x, ?int &$y, ?int &$z) : void{
if($chunkVersion >= 3){
$x = ($key >> 12) & 0xf;
$z = ($key >> 8) & 0xf;
$y = $key & 0xff;
}else{ //pre-1.0, 7 bits were used because the build height limit was lower
$x = ($key >> 11) & 0xf;
$z = ($key >> 7) & 0xf;
$y = $key & 0x7f;
}
}
protected function deserializeLegacyExtraData(string $index, int $chunkVersion) : array{
if(($extraRawData = $this->db->get($index . self::TAG_BLOCK_EXTRA_DATA)) === false or $extraRawData === ""){
return [];
}
/** @var PalettedBlockArray[] $extraDataLayers */
$extraDataLayers = [];
$binaryStream = new BinaryStream($extraRawData);
$count = $binaryStream->getLInt();
for($i = 0; $i < $count; ++$i){
$key = $binaryStream->getLInt();
$value = $binaryStream->getLShort();
self::deserializeExtraDataKey($chunkVersion, $key, $x, $fullY, $z);
$ySub = ($fullY >> 4) & 0xf;
$y = $key & 0xf;
$blockId = $value & 0xff;
$blockData = ($value >> 8) & 0xf;
if(!isset($extraDataLayers[$ySub])){
$extraDataLayers[$ySub] = new PalettedBlockArray(BlockLegacyIds::AIR << 4);
}
$extraDataLayers[$ySub]->set($x, $y, $z, ($blockId << 4) | $blockData);
}
return $extraDataLayers;
}
/** /**
* @param int $chunkX * @param int $chunkX
* @param int $chunkZ * @param int $chunkZ
@ -216,6 +257,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
case 4: //MCPE 1.1 case 4: //MCPE 1.1
//TODO: check beds //TODO: check beds
case 3: //MCPE 1.0 case 3: //MCPE 1.0
/** @var PalettedBlockArray[] $convertedLegacyExtraData */
$convertedLegacyExtraData = $this->deserializeLegacyExtraData($index, $chunkVersion);
for($y = 0; $y < Chunk::MAX_SUBCHUNKS; ++$y){ for($y = 0; $y < Chunk::MAX_SUBCHUNKS; ++$y){
if(($data = $this->db->get($index . self::TAG_SUBCHUNK_PREFIX . chr($y))) === false){ if(($data = $this->db->get($index . self::TAG_SUBCHUNK_PREFIX . chr($y))) === false){
continue; continue;
@ -250,17 +294,31 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
throw new CorruptedChunkException($e->getMessage(), 0, $e); throw new CorruptedChunkException($e->getMessage(), 0, $e);
} }
$subChunks[$y] = new SubChunk([SubChunkConverter::convertSubChunkXZY($blocks, $blockData)]); $storages = [SubChunkConverter::convertSubChunkXZY($blocks, $blockData)];
if(isset($convertedLegacyExtraData[$y])){
$storages[] = $convertedLegacyExtraData[$y];
}
$subChunks[$y] = new SubChunk($storages);
break; break;
case 1: //paletted v1, has a single blockstorage case 1: //paletted v1, has a single blockstorage
$subChunks[$y] = new SubChunk([$this->deserializePaletted($binaryStream)]); $storages = [$this->deserializePaletted($binaryStream)];
if(isset($convertedLegacyExtraData[$y])){
$storages[] = $convertedLegacyExtraData[$y];
}
$subChunks[$y] = new SubChunk($storages);
break; break;
case 8: case 8:
//legacy extradata layers intentionally ignored because they aren't supposed to exist in v8
$storageCount = $binaryStream->getByte();
if($storageCount > 0){
$storages = []; $storages = [];
for($k = 0, $storageCount = $binaryStream->getByte(); $k < $storageCount; ++$k){
for($k = 0; $k < $storageCount; ++$k){
$storages[] = $this->deserializePaletted($binaryStream); $storages[] = $this->deserializePaletted($binaryStream);
} }
$subChunks[$y] = new SubChunk($storages); $subChunks[$y] = new SubChunk($storages);
}
break; break;
default: default:
//TODO: set chunks read-only so the version on disk doesn't get overwritten //TODO: set chunks read-only so the version on disk doesn't get overwritten
@ -280,6 +338,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
} }
break; break;
case 2: // < MCPE 1.0 case 2: // < MCPE 1.0
/** @var PalettedBlockArray[] $extraDataLayers */
$convertedLegacyExtraData = $this->deserializeLegacyExtraData($index, $chunkVersion);
$legacyTerrain = $this->db->get($index . self::TAG_LEGACY_TERRAIN); $legacyTerrain = $this->db->get($index . self::TAG_LEGACY_TERRAIN);
if($legacyTerrain === false){ if($legacyTerrain === false){
throw new CorruptedChunkException("Missing expected LEGACY_TERRAIN tag for format version $chunkVersion"); throw new CorruptedChunkException("Missing expected LEGACY_TERRAIN tag for format version $chunkVersion");
@ -294,7 +355,11 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
} }
for($yy = 0; $yy < 8; ++$yy){ for($yy = 0; $yy < 8; ++$yy){
$subChunks[$yy] = new SubChunk([SubChunkConverter::convertSubChunkFromLegacyColumn($fullIds, $fullData, $yy)]); $storages = [SubChunkConverter::convertSubChunkFromLegacyColumn($fullIds, $fullData, $yy)];
if(isset($convertedLegacyExtraData[$yy])){
$storages[] = $convertedLegacyExtraData[$yy];
}
$subChunks[$yy] = new SubChunk($storages);
} }
try{ try{
@ -331,19 +396,6 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
} }
} }
//TODO: extra data should be converted into blockstorage layers (first they need to be implemented!)
/*
$extraData = [];
if(($extraRawData = $this->db->get($index . self::TAG_BLOCK_EXTRA_DATA)) !== false and $extraRawData !== ""){
$binaryStream->setBuffer($extraRawData, 0);
$count = $binaryStream->getLInt();
for($i = 0; $i < $count; ++$i){
$key = $binaryStream->getLInt();
$value = $binaryStream->getLShort();
$extraData[$key] = $value;
}
}*/
$chunk = new Chunk( $chunk = new Chunk(
$chunkX, $chunkX,
$chunkZ, $chunkZ,