diff --git a/src/world/format/io/BaseWorldProvider.php b/src/world/format/io/BaseWorldProvider.php index dc9f296fb..cd1cc9b5f 100644 --- a/src/world/format/io/BaseWorldProvider.php +++ b/src/world/format/io/BaseWorldProvider.php @@ -23,8 +23,7 @@ declare(strict_types=1); namespace pocketmine\world\format\io; -use pocketmine\data\bedrock\block\BlockStateData; -use pocketmine\data\bedrock\block\BlockTypeNames; +use pocketmine\data\bedrock\block\BlockStateDeserializeException; use pocketmine\world\format\io\exception\CorruptedWorldException; use pocketmine\world\format\io\exception\UnsupportedWorldFormatException; use pocketmine\world\format\PalettedBlockArray; @@ -62,10 +61,16 @@ abstract class BaseWorldProvider implements WorldProvider{ $newStateData = $blockDataUpgrader->upgradeIntIdMeta($legacyIdMeta >> 4, $legacyIdMeta & 0xf); if($newStateData === null){ //TODO: remember data for unknown states so we can implement them later - $newStateData = new BlockStateData(BlockTypeNames::INFO_UPDATE, [], BlockStateData::CURRENT_VERSION); + $newStateData = GlobalBlockStateHandlers::getUnknownBlockStateData(); } - $newPalette[$k] = $blockStateDeserializer->deserialize($newStateData); + try{ + $newPalette[$k] = $blockStateDeserializer->deserialize($newStateData); + }catch(BlockStateDeserializeException){ + //TODO: this needs to be logged + //TODO: maybe we can remember unknown states for later saving instead of discarding them and destroying maps... + $newPalette[$k] = $blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData()); + } } //TODO: this is sub-optimal since it reallocates the offset table multiple times diff --git a/src/world/format/io/GlobalBlockStateHandlers.php b/src/world/format/io/GlobalBlockStateHandlers.php index 2ba979a66..195b9337a 100644 --- a/src/world/format/io/GlobalBlockStateHandlers.php +++ b/src/world/format/io/GlobalBlockStateHandlers.php @@ -26,6 +26,7 @@ namespace pocketmine\world\format\io; use pocketmine\data\bedrock\block\BlockStateData; use pocketmine\data\bedrock\block\BlockStateDeserializer; use pocketmine\data\bedrock\block\BlockStateSerializer; +use pocketmine\data\bedrock\block\BlockTypeNames; use pocketmine\data\bedrock\block\CachingBlockStateDeserializer; use pocketmine\data\bedrock\block\CachingBlockStateSerializer; use pocketmine\data\bedrock\block\convert\BlockObjectToBlockStateSerializer; @@ -54,6 +55,8 @@ final class GlobalBlockStateHandlers{ private static ?BlockDataUpgrader $blockDataUpgrader = null; + private static ?BlockStateData $unknownBlockStateData = null; + public static function getDeserializer() : BlockStateDeserializer{ return self::$blockStateDeserializer ??= new CachingBlockStateDeserializer(new BlockStateToBlockObjectDeserializer()); } @@ -83,4 +86,8 @@ final class GlobalBlockStateHandlers{ return self::$blockDataUpgrader; } + + public static function getUnknownBlockStateData() : BlockStateData{ + return self::$unknownBlockStateData ??= new BlockStateData(BlockTypeNames::INFO_UPDATE, [], BlockStateData::CURRENT_VERSION); + } } diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index 92e2fa853..4d8794e31 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -26,9 +26,7 @@ namespace pocketmine\world\format\io\leveldb; use pocketmine\block\Block; use pocketmine\block\BlockTypeIds; use pocketmine\data\bedrock\BiomeIds; -use pocketmine\data\bedrock\block\BlockStateData; use pocketmine\data\bedrock\block\BlockStateDeserializeException; -use pocketmine\data\bedrock\block\BlockTypeNames; use pocketmine\nbt\LittleEndianNbtSerializer; use pocketmine\nbt\NbtDataException; use pocketmine\nbt\NbtException; @@ -178,9 +176,8 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $palette[] = $blockStateDeserializer->deserialize($blockStateData); }catch(BlockStateDeserializeException){ //TODO: remember data for unknown states so we can implement them later - //TODO: this is slow; we need to cache this //TODO: log this - $palette[] = $blockStateDeserializer->deserialize(new BlockStateData(BlockTypeNames::INFO_UPDATE, [], BlockStateData::CURRENT_VERSION)); + $palette[] = $blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData()); } }catch(NbtException | BlockStateDeserializeException $e){ throw new CorruptedChunkException("Invalid blockstate NBT at offset $i in paletted storage: " . $e->getMessage(), 0, $e);