mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-22 11:24:02 +00:00
LevelDB: log more stuff, stop bailing on recoverable errors
This commit is contained in:
parent
f29e2f7110
commit
5fcf5e0c40
@ -24,7 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\data\bedrock\block\upgrade;
|
namespace pocketmine\data\bedrock\block\upgrade;
|
||||||
|
|
||||||
use pocketmine\data\bedrock\block\BlockStateData;
|
use pocketmine\data\bedrock\block\BlockStateData;
|
||||||
use pocketmine\data\bedrock\block\BlockTypeNames;
|
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
|
|
||||||
final class BlockDataUpgrader{
|
final class BlockDataUpgrader{
|
||||||
@ -34,25 +34,30 @@ final class BlockDataUpgrader{
|
|||||||
private BlockStateUpgrader $blockStateUpgrader
|
private BlockStateUpgrader $blockStateUpgrader
|
||||||
){}
|
){}
|
||||||
|
|
||||||
public function upgradeIntIdMeta(int $id, int $meta) : ?BlockStateData{
|
/**
|
||||||
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
|
public function upgradeIntIdMeta(int $id, int $meta) : BlockStateData{
|
||||||
return $this->blockIdMetaUpgrader->fromIntIdMeta($id, $meta);
|
return $this->blockIdMetaUpgrader->fromIntIdMeta($id, $meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function upgradeStringIdMeta(string $id, int $meta) : ?BlockStateData{
|
/**
|
||||||
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
|
public function upgradeStringIdMeta(string $id, int $meta) : BlockStateData{
|
||||||
return $this->blockIdMetaUpgrader->fromStringIdMeta($id, $meta);
|
return $this->blockIdMetaUpgrader->fromStringIdMeta($id, $meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function upgradeBlockStateNbt(CompoundTag $tag) : ?BlockStateData{
|
/**
|
||||||
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
|
public function upgradeBlockStateNbt(CompoundTag $tag) : BlockStateData{
|
||||||
if($tag->getTag("name") !== null && $tag->getTag("val") !== null){
|
if($tag->getTag("name") !== null && $tag->getTag("val") !== null){
|
||||||
//Legacy (pre-1.13) blockstate - upgrade it to a version we understand
|
//Legacy (pre-1.13) blockstate - upgrade it to a version we understand
|
||||||
$id = $tag->getString("name");
|
$id = $tag->getString("name");
|
||||||
$data = $tag->getShort("val");
|
$data = $tag->getShort("val");
|
||||||
|
|
||||||
$blockStateData = $this->upgradeStringIdMeta($id, $data);
|
$blockStateData = $this->upgradeStringIdMeta($id, $data);
|
||||||
if($blockStateData === null){
|
|
||||||
//unknown block, invalid ID
|
|
||||||
$blockStateData = BlockStateData::current(BlockTypeNames::INFO_UPDATE, []);
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
//Modern (post-1.13) blockstate
|
//Modern (post-1.13) blockstate
|
||||||
$blockStateData = BlockStateData::fromNbt($tag);
|
$blockStateData = BlockStateData::fromNbt($tag);
|
||||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\data\bedrock\block\upgrade;
|
namespace pocketmine\data\bedrock\block\upgrade;
|
||||||
|
|
||||||
use pocketmine\data\bedrock\block\BlockStateData;
|
use pocketmine\data\bedrock\block\BlockStateData;
|
||||||
|
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
|
||||||
use pocketmine\nbt\LittleEndianNbtSerializer;
|
use pocketmine\nbt\LittleEndianNbtSerializer;
|
||||||
use pocketmine\utils\BinaryDataException;
|
use pocketmine\utils\BinaryDataException;
|
||||||
use pocketmine\utils\BinaryStream;
|
use pocketmine\utils\BinaryStream;
|
||||||
@ -41,14 +42,22 @@ final class BlockIdMetaUpgrader{
|
|||||||
private LegacyBlockIdToStringIdMap $legacyNumericIdMap
|
private LegacyBlockIdToStringIdMap $legacyNumericIdMap
|
||||||
){}
|
){}
|
||||||
|
|
||||||
public function fromStringIdMeta(string $id, int $meta) : ?BlockStateData{
|
/**
|
||||||
return $this->mappingTable[$id][$meta] ?? $this->mappingTable[$id][0] ?? null;
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
|
public function fromStringIdMeta(string $id, int $meta) : BlockStateData{
|
||||||
|
return $this->mappingTable[$id][$meta] ??
|
||||||
|
$this->mappingTable[$id][0] ??
|
||||||
|
throw new BlockStateDeserializeException("Unknown legacy block string ID $id");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fromIntIdMeta(int $id, int $meta) : ?BlockStateData{
|
/**
|
||||||
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
|
public function fromIntIdMeta(int $id, int $meta) : BlockStateData{
|
||||||
$stringId = $this->legacyNumericIdMap->legacyToString($id);
|
$stringId = $this->legacyNumericIdMap->legacyToString($id);
|
||||||
if($stringId === null){
|
if($stringId === null){
|
||||||
return null;
|
throw new BlockStateDeserializeException("Unknown legacy block numeric ID $id");
|
||||||
}
|
}
|
||||||
return $this->fromStringIdMeta($stringId, $meta);
|
return $this->fromStringIdMeta($stringId, $meta);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ use pocketmine\data\bedrock\BiomeIds;
|
|||||||
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
|
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
|
||||||
use pocketmine\nbt\LittleEndianNbtSerializer;
|
use pocketmine\nbt\LittleEndianNbtSerializer;
|
||||||
use pocketmine\nbt\NbtDataException;
|
use pocketmine\nbt\NbtDataException;
|
||||||
use pocketmine\nbt\NbtException;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
use pocketmine\nbt\TreeRoot;
|
use pocketmine\nbt\TreeRoot;
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
@ -144,7 +143,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
/**
|
/**
|
||||||
* @throws CorruptedChunkException
|
* @throws CorruptedChunkException
|
||||||
*/
|
*/
|
||||||
protected function deserializeBlockPalette(BinaryStream $stream) : PalettedBlockArray{
|
protected function deserializeBlockPalette(BinaryStream $stream, \Logger $logger) : PalettedBlockArray{
|
||||||
$bitsPerBlock = $stream->getByte() >> 1;
|
$bitsPerBlock = $stream->getByte() >> 1;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
@ -160,25 +159,28 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
for($i = 0; $i < $paletteSize; ++$i){
|
for($i = 0; $i < $paletteSize; ++$i){
|
||||||
try{
|
try{
|
||||||
$offset = $stream->getOffset();
|
$offset = $stream->getOffset();
|
||||||
|
|
||||||
$blockStateNbt = $nbt->read($stream->getBuffer(), $offset)->mustGetCompoundTag();
|
$blockStateNbt = $nbt->read($stream->getBuffer(), $offset)->mustGetCompoundTag();
|
||||||
$blockStateData = $this->blockDataUpgrader->upgradeBlockStateNbt($blockStateNbt);
|
|
||||||
if($blockStateData === null){
|
|
||||||
//upgrading blockstates should always succeed, regardless of whether they've been implemented or not
|
|
||||||
throw new BlockStateDeserializeException("Invalid or improperly mapped legacy blockstate: " . $blockStateNbt->toString());
|
|
||||||
}
|
|
||||||
$stream->setOffset($offset);
|
$stream->setOffset($offset);
|
||||||
|
}catch(NbtDataException $e){
|
||||||
try{
|
//NBT borked, unrecoverable
|
||||||
$palette[] = $this->blockStateDeserializer->deserialize($blockStateData);
|
|
||||||
}catch(BlockStateDeserializeException){
|
|
||||||
//TODO: remember data for unknown states so we can implement them later
|
|
||||||
//TODO: log this
|
|
||||||
$palette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
|
|
||||||
}
|
|
||||||
}catch(NbtException | BlockStateDeserializeException $e){
|
|
||||||
throw new CorruptedChunkException("Invalid blockstate NBT at offset $i in paletted storage: " . $e->getMessage(), 0, $e);
|
throw new CorruptedChunkException("Invalid blockstate NBT at offset $i in paletted storage: " . $e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: remember data for unknown states so we can implement them later
|
||||||
|
try{
|
||||||
|
$blockStateData = $this->blockDataUpgrader->upgradeBlockStateNbt($blockStateNbt);
|
||||||
|
}catch(BlockStateDeserializeException $e){
|
||||||
|
//while not ideal, this is not a fatal error
|
||||||
|
$logger->error("Failed to upgrade blockstate: " . $e->getMessage() . " offset $i in palette, blockstate NBT: " . $blockStateNbt->toString());
|
||||||
|
$palette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
$palette[] = $this->blockStateDeserializer->deserialize($blockStateData);
|
||||||
|
}catch(BlockStateDeserializeException $e){
|
||||||
|
$logger->error("Failed to deserialize blockstate: " . $e->getMessage() . " offset $i in palette, blockstate NBT: " . $blockStateNbt->toString());
|
||||||
|
$palette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: exceptions
|
//TODO: exceptions
|
||||||
@ -253,7 +255,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
* @return PalettedBlockArray[]
|
* @return PalettedBlockArray[]
|
||||||
* @phpstan-return array<int, PalettedBlockArray>
|
* @phpstan-return array<int, PalettedBlockArray>
|
||||||
*/
|
*/
|
||||||
private static function deserialize3dBiomes(BinaryStream $stream, int $chunkVersion) : array{
|
private static function deserialize3dBiomes(BinaryStream $stream, int $chunkVersion, \Logger $logger) : array{
|
||||||
$previous = null;
|
$previous = null;
|
||||||
$result = [];
|
$result = [];
|
||||||
$nextIndex = Chunk::MIN_SUBCHUNK_INDEX;
|
$nextIndex = Chunk::MIN_SUBCHUNK_INDEX;
|
||||||
@ -279,7 +281,8 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!$stream->feof()){
|
if(!$stream->feof()){
|
||||||
throw new CorruptedChunkException("3D biomes data contains extra unread data");
|
//maybe bad output produced by a third-party conversion tool like Chunker
|
||||||
|
$logger->error("Unexpected trailing data after 3D biomes data");
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@ -314,7 +317,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
/**
|
/**
|
||||||
* @return PalettedBlockArray[]
|
* @return PalettedBlockArray[]
|
||||||
*/
|
*/
|
||||||
protected function deserializeLegacyExtraData(string $index, int $chunkVersion) : array{
|
protected function deserializeLegacyExtraData(string $index, int $chunkVersion, \Logger $logger) : array{
|
||||||
if(($extraRawData = $this->db->get($index . ChunkDataKey::LEGACY_BLOCK_EXTRA_DATA)) === false || $extraRawData === ""){
|
if(($extraRawData = $this->db->get($index . ChunkDataKey::LEGACY_BLOCK_EXTRA_DATA)) === false || $extraRawData === ""){
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -335,12 +338,15 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
|
|
||||||
$blockId = $value & 0xff;
|
$blockId = $value & 0xff;
|
||||||
$blockData = ($value >> 8) & 0xf;
|
$blockData = ($value >> 8) & 0xf;
|
||||||
$blockStateData = $this->blockDataUpgrader->upgradeIntIdMeta($blockId, $blockData);
|
try{
|
||||||
if($blockStateData === null){
|
$blockStateData = $this->blockDataUpgrader->upgradeIntIdMeta($blockId, $blockData);
|
||||||
|
}catch(BlockStateDeserializeException $e){
|
||||||
//TODO: we could preserve this in case it's supported in the future, but this was historically only
|
//TODO: we could preserve this in case it's supported in the future, but this was historically only
|
||||||
//used for grass anyway, so we probably don't need to care
|
//used for grass anyway, so we probably don't need to care
|
||||||
|
$logger->error("Failed to upgrade legacy extra block: " . $e->getMessage() . " ($blockId:$blockData)");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
//assume this won't throw
|
||||||
$blockStateId = $this->blockStateDeserializer->deserialize($blockStateData);
|
$blockStateId = $this->blockStateDeserializer->deserialize($blockStateData);
|
||||||
|
|
||||||
if(!isset($extraDataLayers[$ySub])){
|
if(!isset($extraDataLayers[$ySub])){
|
||||||
@ -372,8 +378,8 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
* @phpstan-return array<int, SubChunk>
|
* @phpstan-return array<int, SubChunk>
|
||||||
* @throws CorruptedWorldException
|
* @throws CorruptedWorldException
|
||||||
*/
|
*/
|
||||||
private function deserializeLegacyTerrainData(string $index, int $chunkVersion) : array{
|
private function deserializeLegacyTerrainData(string $index, int $chunkVersion, \Logger $logger) : array{
|
||||||
$convertedLegacyExtraData = $this->deserializeLegacyExtraData($index, $chunkVersion);
|
$convertedLegacyExtraData = $this->deserializeLegacyExtraData($index, $chunkVersion, $logger);
|
||||||
|
|
||||||
$legacyTerrain = $this->db->get($index . ChunkDataKey::LEGACY_TERRAIN);
|
$legacyTerrain = $this->db->get($index . ChunkDataKey::LEGACY_TERRAIN);
|
||||||
if($legacyTerrain === false){
|
if($legacyTerrain === false){
|
||||||
@ -396,6 +402,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
}catch(BinaryDataException $e){
|
}catch(BinaryDataException $e){
|
||||||
throw new CorruptedChunkException($e->getMessage(), 0, $e);
|
throw new CorruptedChunkException($e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
if(!$binaryStream->feof()){
|
||||||
|
$logger->error("Unexpected trailing data in legacy terrain data");
|
||||||
|
}
|
||||||
|
|
||||||
$subChunks = [];
|
$subChunks = [];
|
||||||
for($yy = 0; $yy < 8; ++$yy){
|
for($yy = 0; $yy < 8; ++$yy){
|
||||||
@ -419,18 +428,25 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
/**
|
/**
|
||||||
* Deserializes a subchunk stored in the legacy non-paletted format used from 1.0 until 1.2.13.
|
* Deserializes a subchunk stored in the legacy non-paletted format used from 1.0 until 1.2.13.
|
||||||
*/
|
*/
|
||||||
private function deserializeNonPalettedSubChunkData(BinaryStream $binaryStream, int $chunkVersion, ?PalettedBlockArray $convertedLegacyExtraData, PalettedBlockArray $biomePalette) : SubChunk{
|
private function deserializeNonPalettedSubChunkData(BinaryStream $binaryStream, int $chunkVersion, ?PalettedBlockArray $convertedLegacyExtraData, PalettedBlockArray $biomePalette, \Logger $logger) : SubChunk{
|
||||||
try{
|
try{
|
||||||
$blocks = $binaryStream->get(4096);
|
$blocks = $binaryStream->get(4096);
|
||||||
$blockData = $binaryStream->get(2048);
|
$blockData = $binaryStream->get(2048);
|
||||||
|
|
||||||
if($chunkVersion < ChunkVersion::v1_1_0){
|
|
||||||
$binaryStream->get(4096); //legacy light info, discard it
|
|
||||||
}
|
|
||||||
}catch(BinaryDataException $e){
|
}catch(BinaryDataException $e){
|
||||||
throw new CorruptedChunkException($e->getMessage(), 0, $e);
|
throw new CorruptedChunkException($e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($chunkVersion < ChunkVersion::v1_1_0){
|
||||||
|
try{
|
||||||
|
$binaryStream->get(4096); //legacy light info, discard it
|
||||||
|
if(!$binaryStream->feof()){
|
||||||
|
$logger->error("Unexpected trailing data in legacy subchunk data");
|
||||||
|
}
|
||||||
|
}catch(BinaryDataException $e){
|
||||||
|
$logger->error("Failed to read legacy subchunk light info: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$storages = [$this->palettizeLegacySubChunkXZY($blocks, $blockData)];
|
$storages = [$this->palettizeLegacySubChunkXZY($blocks, $blockData)];
|
||||||
if($convertedLegacyExtraData !== null){
|
if($convertedLegacyExtraData !== null){
|
||||||
$storages[] = $convertedLegacyExtraData;
|
$storages[] = $convertedLegacyExtraData;
|
||||||
@ -445,7 +461,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
* @see ChunkDataKey::SUBCHUNK
|
* @see ChunkDataKey::SUBCHUNK
|
||||||
* @throws CorruptedChunkException
|
* @throws CorruptedChunkException
|
||||||
*/
|
*/
|
||||||
private function deserializeSubChunkData(BinaryStream $binaryStream, int $chunkVersion, int $subChunkVersion, ?PalettedBlockArray $convertedLegacyExtraData, PalettedBlockArray $biomePalette) : SubChunk{
|
private function deserializeSubChunkData(BinaryStream $binaryStream, int $chunkVersion, int $subChunkVersion, ?PalettedBlockArray $convertedLegacyExtraData, PalettedBlockArray $biomePalette, \Logger $logger) : SubChunk{
|
||||||
switch($subChunkVersion){
|
switch($subChunkVersion){
|
||||||
case SubChunkVersion::CLASSIC:
|
case SubChunkVersion::CLASSIC:
|
||||||
case SubChunkVersion::CLASSIC_BUG_2: //these are all identical to version 0, but vanilla respects these so we should also
|
case SubChunkVersion::CLASSIC_BUG_2: //these are all identical to version 0, but vanilla respects these so we should also
|
||||||
@ -454,9 +470,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
case SubChunkVersion::CLASSIC_BUG_5:
|
case SubChunkVersion::CLASSIC_BUG_5:
|
||||||
case SubChunkVersion::CLASSIC_BUG_6:
|
case SubChunkVersion::CLASSIC_BUG_6:
|
||||||
case SubChunkVersion::CLASSIC_BUG_7:
|
case SubChunkVersion::CLASSIC_BUG_7:
|
||||||
return $this->deserializeNonPalettedSubChunkData($binaryStream, $chunkVersion, $convertedLegacyExtraData, $biomePalette);
|
return $this->deserializeNonPalettedSubChunkData($binaryStream, $chunkVersion, $convertedLegacyExtraData, $biomePalette, $logger);
|
||||||
case SubChunkVersion::PALETTED_SINGLE:
|
case SubChunkVersion::PALETTED_SINGLE:
|
||||||
$storages = [$this->deserializeBlockPalette($binaryStream)];
|
$storages = [$this->deserializeBlockPalette($binaryStream, $logger)];
|
||||||
if($convertedLegacyExtraData !== null){
|
if($convertedLegacyExtraData !== null){
|
||||||
$storages[] = $convertedLegacyExtraData;
|
$storages[] = $convertedLegacyExtraData;
|
||||||
}
|
}
|
||||||
@ -473,11 +489,11 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
|
|
||||||
$storages = [];
|
$storages = [];
|
||||||
for($k = 0; $k < $storageCount; ++$k){
|
for($k = 0; $k < $storageCount; ++$k){
|
||||||
$storages[] = $this->deserializeBlockPalette($binaryStream);
|
$storages[] = $this->deserializeBlockPalette($binaryStream, $logger);
|
||||||
}
|
}
|
||||||
return new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, $storages, $biomePalette);
|
return new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, $storages, $biomePalette);
|
||||||
default:
|
default:
|
||||||
//TODO: set chunks read-only so the version on disk doesn't get overwritten
|
//this should never happen - an unsupported chunk appearing in a supported world is a sign of corruption
|
||||||
throw new CorruptedChunkException("don't know how to decode LevelDB subchunk format version $subChunkVersion");
|
throw new CorruptedChunkException("don't know how to decode LevelDB subchunk format version $subChunkVersion");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,7 +515,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
* @return SubChunk[]
|
* @return SubChunk[]
|
||||||
* @phpstan-return array<int, SubChunk>
|
* @phpstan-return array<int, SubChunk>
|
||||||
*/
|
*/
|
||||||
private function deserializeAllSubChunkData(string $index, int $chunkVersion, bool &$hasBeenUpgraded, array $convertedLegacyExtraData, array $biomeArrays) : array{
|
private function deserializeAllSubChunkData(string $index, int $chunkVersion, bool &$hasBeenUpgraded, array $convertedLegacyExtraData, array $biomeArrays, \Logger $logger) : array{
|
||||||
$subChunks = [];
|
$subChunks = [];
|
||||||
|
|
||||||
$subChunkKeyOffset = self::hasOffsetCavesAndCliffsSubChunks($chunkVersion) ? self::CAVES_CLIFFS_EXPERIMENTAL_SUBCHUNK_KEY_OFFSET : 0;
|
$subChunkKeyOffset = self::hasOffsetCavesAndCliffsSubChunks($chunkVersion) ? self::CAVES_CLIFFS_EXPERIMENTAL_SUBCHUNK_KEY_OFFSET : 0;
|
||||||
@ -518,7 +534,14 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
$hasBeenUpgraded = true;
|
$hasBeenUpgraded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$subChunks[$y] = $this->deserializeSubChunkData($binaryStream, $chunkVersion, $subChunkVersion, $convertedLegacyExtraData[$y] ?? null, $biomeArrays[$y]);
|
$subChunks[$y] = $this->deserializeSubChunkData(
|
||||||
|
$binaryStream,
|
||||||
|
$chunkVersion,
|
||||||
|
$subChunkVersion,
|
||||||
|
$convertedLegacyExtraData[$y] ?? null,
|
||||||
|
$biomeArrays[$y],
|
||||||
|
new \PrefixedLogger($logger, "Subchunk y=$y v$subChunkVersion")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $subChunks;
|
return $subChunks;
|
||||||
@ -530,7 +553,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
* @return PalettedBlockArray[]
|
* @return PalettedBlockArray[]
|
||||||
* @phpstan-return array<int, PalettedBlockArray>
|
* @phpstan-return array<int, PalettedBlockArray>
|
||||||
*/
|
*/
|
||||||
private function deserializeBiomeData(string $index, int $chunkVersion) : array{
|
private function deserializeBiomeData(string $index, int $chunkVersion, \Logger $logger) : array{
|
||||||
$biomeArrays = [];
|
$biomeArrays = [];
|
||||||
if(($maps2d = $this->db->get($index . ChunkDataKey::HEIGHTMAP_AND_2D_BIOMES)) !== false){
|
if(($maps2d = $this->db->get($index . ChunkDataKey::HEIGHTMAP_AND_2D_BIOMES)) !== false){
|
||||||
$binaryStream = new BinaryStream($maps2d);
|
$binaryStream = new BinaryStream($maps2d);
|
||||||
@ -538,6 +561,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
try{
|
try{
|
||||||
$binaryStream->get(512); //heightmap, discard it
|
$binaryStream->get(512); //heightmap, discard it
|
||||||
$biomes3d = ChunkUtils::extrapolate3DBiomes($binaryStream->get(256)); //never throws
|
$biomes3d = ChunkUtils::extrapolate3DBiomes($binaryStream->get(256)); //never throws
|
||||||
|
if(!$binaryStream->feof()){
|
||||||
|
$logger->error("Unexpected trailing data after 2D biome data");
|
||||||
|
}
|
||||||
}catch(BinaryDataException $e){
|
}catch(BinaryDataException $e){
|
||||||
throw new CorruptedChunkException($e->getMessage(), 0, $e);
|
throw new CorruptedChunkException($e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
@ -549,11 +575,12 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
|
|
||||||
try{
|
try{
|
||||||
$binaryStream->get(512);
|
$binaryStream->get(512);
|
||||||
$biomeArrays = self::deserialize3dBiomes($binaryStream, $chunkVersion);
|
$biomeArrays = self::deserialize3dBiomes($binaryStream, $chunkVersion, $logger);
|
||||||
}catch(BinaryDataException $e){
|
}catch(BinaryDataException $e){
|
||||||
throw new CorruptedChunkException($e->getMessage(), 0, $e);
|
throw new CorruptedChunkException($e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
$logger->error("Missing biome data, using default ocean biome");
|
||||||
for($i = Chunk::MIN_SUBCHUNK_INDEX; $i <= Chunk::MAX_SUBCHUNK_INDEX; ++$i){
|
for($i = Chunk::MIN_SUBCHUNK_INDEX; $i <= Chunk::MAX_SUBCHUNK_INDEX; ++$i){
|
||||||
$biomeArrays[$i] = new PalettedBlockArray(BiomeIds::OCEAN); //polyfill
|
$biomeArrays[$i] = new PalettedBlockArray(BiomeIds::OCEAN); //polyfill
|
||||||
}
|
}
|
||||||
@ -574,6 +601,8 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$logger = new \PrefixedLogger($this->logger, "Loading chunk x=$chunkX z=$chunkZ v$chunkVersion");
|
||||||
|
|
||||||
$hasBeenUpgraded = $chunkVersion < self::CURRENT_LEVEL_CHUNK_VERSION;
|
$hasBeenUpgraded = $chunkVersion < self::CURRENT_LEVEL_CHUNK_VERSION;
|
||||||
|
|
||||||
switch($chunkVersion){
|
switch($chunkVersion){
|
||||||
@ -617,14 +646,14 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
case ChunkVersion::v1_1_0:
|
case ChunkVersion::v1_1_0:
|
||||||
//TODO: check beds
|
//TODO: check beds
|
||||||
case ChunkVersion::v1_0_0:
|
case ChunkVersion::v1_0_0:
|
||||||
$convertedLegacyExtraData = $this->deserializeLegacyExtraData($index, $chunkVersion);
|
$convertedLegacyExtraData = $this->deserializeLegacyExtraData($index, $chunkVersion, $logger);
|
||||||
$biomeArrays = $this->deserializeBiomeData($index, $chunkVersion);
|
$biomeArrays = $this->deserializeBiomeData($index, $chunkVersion, $logger);
|
||||||
$subChunks = $this->deserializeAllSubChunkData($index, $chunkVersion, $hasBeenUpgraded, $convertedLegacyExtraData, $biomeArrays);
|
$subChunks = $this->deserializeAllSubChunkData($index, $chunkVersion, $hasBeenUpgraded, $convertedLegacyExtraData, $biomeArrays, $logger);
|
||||||
break;
|
break;
|
||||||
case ChunkVersion::v0_9_5:
|
case ChunkVersion::v0_9_5:
|
||||||
case ChunkVersion::v0_9_2:
|
case ChunkVersion::v0_9_2:
|
||||||
case ChunkVersion::v0_9_0:
|
case ChunkVersion::v0_9_0:
|
||||||
$subChunks = $this->deserializeLegacyTerrainData($index, $chunkVersion);
|
$subChunks = $this->deserializeLegacyTerrainData($index, $chunkVersion, $logger);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new CorruptedChunkException("don't know how to decode chunk format version $chunkVersion");
|
throw new CorruptedChunkException("don't know how to decode chunk format version $chunkVersion");
|
||||||
@ -668,6 +697,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
);
|
);
|
||||||
|
|
||||||
if($hasBeenUpgraded){
|
if($hasBeenUpgraded){
|
||||||
|
$logger->debug("Flagging chunk as dirty due to upgraded data");
|
||||||
$chunk->setTerrainDirty(); //trigger rewriting chunk to disk if it was converted from an older format
|
$chunk->setTerrainDirty(); //trigger rewriting chunk to disk if it was converted from an older format
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user