diff --git a/src/block/tile/FlowerPot.php b/src/block/tile/FlowerPot.php index 499101bb1..2b39731ed 100644 --- a/src/block/tile/FlowerPot.php +++ b/src/block/tile/FlowerPot.php @@ -46,11 +46,13 @@ class FlowerPot extends Spawnable{ public function readSaveData(CompoundTag $nbt) : void{ $blockStateData = null; + + $blockDataUpgrader = GlobalBlockStateHandlers::getUpgrader(); if(($itemIdTag = $nbt->getTag(self::TAG_ITEM)) instanceof ShortTag && ($itemMetaTag = $nbt->getTag(self::TAG_ITEM_DATA)) instanceof IntTag){ - $blockStateData = GlobalBlockStateHandlers::getLegacyBlockStateMapper()->fromIntIdMeta($itemIdTag->getValue(), $itemMetaTag->getValue()); + $blockStateData = $blockDataUpgrader->upgradeIntIdMeta($itemIdTag->getValue(), $itemMetaTag->getValue()); }elseif(($plantBlockTag = $nbt->getCompoundTag(self::TAG_PLANT_BLOCK)) !== null){ try{ - $blockStateData = GlobalBlockStateHandlers::nbtToBlockStateData($plantBlockTag); + $blockStateData = $blockDataUpgrader->upgradeBlockStateNbt($plantBlockTag); }catch(BlockStateDeserializeException $e){ throw new SavedDataLoadingException("Error loading " . self::TAG_PLANT_BLOCK . " tag for flower pot: " . $e->getMessage(), 0, $e); } diff --git a/src/data/bedrock/block/UpgradingBlockStateDeserializer.php b/src/data/bedrock/block/UpgradingBlockStateDeserializer.php deleted file mode 100644 index 273669b46..000000000 --- a/src/data/bedrock/block/UpgradingBlockStateDeserializer.php +++ /dev/null @@ -1,40 +0,0 @@ -realDeserializer->deserialize($this->blockStateUpgrader->upgrade($stateData)); - } - - public function getRealDeserializer() : BlockStateDeserializer{ return $this->realDeserializer; } -} diff --git a/src/entity/object/FallingBlock.php b/src/entity/object/FallingBlock.php index 5642889b9..22f198167 100644 --- a/src/entity/object/FallingBlock.php +++ b/src/entity/object/FallingBlock.php @@ -65,12 +65,9 @@ class FallingBlock extends Entity{ public static function parseBlockNBT(BlockFactory $factory, CompoundTag $nbt) : Block{ //TODO: 1.8+ save format + $blockDataUpgrader = GlobalBlockStateHandlers::getUpgrader(); if(($fallingBlockTag = $nbt->getCompoundTag(self::TAG_FALLING_BLOCK)) !== null){ - try{ - $blockStateData = GlobalBlockStateHandlers::nbtToBlockStateData($fallingBlockTag); - }catch(BlockStateDeserializeException $e){ - throw new SavedDataLoadingException($e->getMessage(), 0, $e); - } + $blockStateData = $blockDataUpgrader->upgradeBlockStateNbt($fallingBlockTag); }else{ if(($tileIdTag = $nbt->getTag("TileID")) instanceof IntTag){ $blockId = $tileIdTag->getValue(); @@ -81,10 +78,10 @@ class FallingBlock extends Entity{ } $damage = $nbt->getByte("Data", 0); - $blockStateData = GlobalBlockStateHandlers::getLegacyBlockStateMapper()->fromIntIdMeta($blockId, $damage); - if($blockStateData === null){ - throw new SavedDataLoadingException("Invalid legacy falling block"); - } + $blockStateData = $blockDataUpgrader->upgradeIntIdMeta($blockId, $damage); + } + if($blockStateData === null){ + throw new SavedDataLoadingException("Invalid legacy falling block"); } try{ diff --git a/src/world/format/io/BaseWorldProvider.php b/src/world/format/io/BaseWorldProvider.php index 17c6a6ac7..23d1ba269 100644 --- a/src/world/format/io/BaseWorldProvider.php +++ b/src/world/format/io/BaseWorldProvider.php @@ -56,11 +56,11 @@ abstract class BaseWorldProvider implements WorldProvider{ //TODO: this should be dependency-injected so it can be replaced, but that would break BC //also, we want it to be lazy-loaded ... - $legacyBlockStateMapper = GlobalBlockStateHandlers::getLegacyBlockStateMapper(); + $blockDataUpgrader = GlobalBlockStateHandlers::getUpgrader(); $blockStateDeserializer = GlobalBlockStateHandlers::getDeserializer(); $newPalette = []; foreach($palette as $k => $legacyIdMeta){ - $newStateData = $legacyBlockStateMapper->fromIntIdMeta($legacyIdMeta >> 4, $legacyIdMeta & 0xf); + $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, CompoundTag::create(), BlockStateData::CURRENT_VERSION); diff --git a/src/world/format/io/GlobalBlockStateHandlers.php b/src/world/format/io/GlobalBlockStateHandlers.php index 3f49336fd..42e4b9c26 100644 --- a/src/world/format/io/GlobalBlockStateHandlers.php +++ b/src/world/format/io/GlobalBlockStateHandlers.php @@ -26,18 +26,16 @@ 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; use pocketmine\data\bedrock\block\convert\BlockStateToBlockObjectDeserializer; +use pocketmine\data\bedrock\block\upgrade\BlockDataUpgrader; use pocketmine\data\bedrock\block\upgrade\BlockStateUpgrader; use pocketmine\data\bedrock\block\upgrade\BlockStateUpgradeSchemaUtils; -use pocketmine\data\bedrock\block\upgrade\LegacyBlockStateMapper; -use pocketmine\data\bedrock\block\UpgradingBlockStateDeserializer; use pocketmine\data\bedrock\block\upgrade\LegacyBlockIdToStringIdMap; +use pocketmine\data\bedrock\block\upgrade\LegacyBlockStateMapper; use pocketmine\errorhandler\ErrorToExceptionHandler; -use pocketmine\nbt\tag\CompoundTag; use Webmozart\PathUtil\Path; use function file_get_contents; use const pocketmine\BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH; @@ -54,50 +52,29 @@ final class GlobalBlockStateHandlers{ private static ?BlockStateDeserializer $blockStateDeserializer; - private static ?LegacyBlockStateMapper $legacyBlockStateMapper; + private static ?BlockDataUpgrader $blockDataUpgrader; public static function getDeserializer() : BlockStateDeserializer{ - return self::$blockStateDeserializer ??= new CachingBlockStateDeserializer( - new UpgradingBlockStateDeserializer( - new BlockStateUpgrader(BlockStateUpgradeSchemaUtils::loadSchemas( - Path::join(BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH, 'nbt_upgrade_schema'), - BlockStateData::CURRENT_VERSION - )), - new BlockStateToBlockObjectDeserializer() - ) - ); + return self::$blockStateDeserializer ??= new CachingBlockStateDeserializer(new BlockStateToBlockObjectDeserializer()); } public static function getSerializer() : BlockStateSerializer{ return self::$blockStateSerializer ??= new CachingBlockStateSerializer(new BlockObjectToBlockStateSerializer()); } - public static function getLegacyBlockStateMapper() : LegacyBlockStateMapper{ - return self::$legacyBlockStateMapper ??= LegacyBlockStateMapper::loadFromString( - ErrorToExceptionHandler::trapAndRemoveFalse(fn() => file_get_contents(Path::join( - BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH, - '1.12.0_to_1.18.10_blockstate_map.bin' - ))), - LegacyBlockIdToStringIdMap::getInstance() + public static function getUpgrader() : BlockDataUpgrader{ + return self::$blockDataUpgrader ??= new BlockDataUpgrader( + LegacyBlockStateMapper::loadFromString( + ErrorToExceptionHandler::trapAndRemoveFalse(fn() => file_get_contents(Path::join( + BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH, + '1.12.0_to_1.18.10_blockstate_map.bin' + ))), + LegacyBlockIdToStringIdMap::getInstance() + ), + new BlockStateUpgrader(BlockStateUpgradeSchemaUtils::loadSchemas( + Path::join(BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH, 'nbt_upgrade_schema'), + BlockStateData::CURRENT_VERSION + )) ); } - - public static function nbtToBlockStateData(CompoundTag $tag) : BlockStateData{ - if($tag->getTag("name") !== null && $tag->getTag("val") !== null){ - //Legacy (pre-1.13) blockstate - upgrade it to a version we understand - $id = $tag->getString("name"); - $data = $tag->getShort("val"); - - $blockStateData = GlobalBlockStateHandlers::getLegacyBlockStateMapper()->fromStringIdMeta($id, $data); - if($blockStateData === null){ - //unknown block, invalid ID - $blockStateData = new BlockStateData(BlockTypeNames::INFO_UPDATE, CompoundTag::create(), BlockStateData::CURRENT_VERSION); - } - }else{ - //Modern (post-1.13) blockstate - $blockStateData = BlockStateData::fromNbt($tag); - } - - return $blockStateData; - } } diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index 0814655fb..263311413 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -160,12 +160,18 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $paletteSize = $bitsPerBlock === 0 ? 1 : $stream->getLInt(); + $blockDataUpgrader = GlobalBlockStateHandlers::getUpgrader(); $blockStateDeserializer = GlobalBlockStateHandlers::getDeserializer(); for($i = 0; $i < $paletteSize; ++$i){ try{ $offset = $stream->getOffset(); - $blockStateData = GlobalBlockStateHandlers::nbtToBlockStateData($nbt->read($stream->getBuffer(), $offset)->mustGetCompoundTag()); + $blockStateNbt = $nbt->read($stream->getBuffer(), $offset)->mustGetCompoundTag(); + $blockStateData = $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); try{ @@ -210,7 +216,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $binaryStream = new BinaryStream($extraRawData); $count = $binaryStream->getLInt(); - $legacyMapper = GlobalBlockStateHandlers::getLegacyBlockStateMapper(); + $blockDataUpgrader = GlobalBlockStateHandlers::getUpgrader(); $blockStateDeserializer = GlobalBlockStateHandlers::getDeserializer(); for($i = 0; $i < $count; ++$i){ $key = $binaryStream->getLInt(); @@ -223,7 +229,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $blockId = $value & 0xff; $blockData = ($value >> 8) & 0xf; - $blockStateData = $legacyMapper->fromIntIdMeta($blockId, $blockData); + $blockStateData = $blockDataUpgrader->upgradeIntIdMeta($blockId, $blockData); if($blockStateData === null){ //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