From 3a42c21cc18ca5e603e68269edc0ad65de70540e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 24 Apr 2020 21:28:27 +0100 Subject: [PATCH] wrap up block_id_map in a class --- .../bedrock/LegacyBlockIdToStringIdMap.php | 69 +++++++++++++++++++ .../mcpe/convert/RuntimeBlockMapping.php | 9 ++- src/world/format/io/leveldb/LevelDB.php | 19 ++--- 3 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 src/data/bedrock/LegacyBlockIdToStringIdMap.php diff --git a/src/data/bedrock/LegacyBlockIdToStringIdMap.php b/src/data/bedrock/LegacyBlockIdToStringIdMap.php new file mode 100644 index 000000000..de012d850 --- /dev/null +++ b/src/data/bedrock/LegacyBlockIdToStringIdMap.php @@ -0,0 +1,69 @@ + + */ + private $legacyToString = []; + /** + * @var int[] + * @phpstan-var array + */ + private $stringToLegacy = []; + + public function __construct(){ + $stringToLegacyId = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . 'vanilla/block_id_map.json'), true); + if(!is_array($stringToLegacyId)){ + throw new AssumptionFailedError("Invalid format of block_id_map"); + } + foreach($stringToLegacyId as $stringId => $legacyId){ + if(!is_string($stringId) or !is_int($legacyId)){ + throw new AssumptionFailedError("Block ID map should have string keys and int values"); + } + $this->legacyToString[$legacyId] = $stringId; + $this->stringToLegacy[$stringId] = $legacyId; + } + } + + public function legacyToString(int $legacy) : ?string{ + return $this->legacyToString[$legacy] ?? null; + } + + public function stringToLegacy(string $string) : ?int{ + return $this->stringToLegacy[$string] ?? null; + } +} \ No newline at end of file diff --git a/src/network/mcpe/convert/RuntimeBlockMapping.php b/src/network/mcpe/convert/RuntimeBlockMapping.php index dd1378daf..570878def 100644 --- a/src/network/mcpe/convert/RuntimeBlockMapping.php +++ b/src/network/mcpe/convert/RuntimeBlockMapping.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\convert; use pocketmine\block\BlockLegacyIds; +use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap; use pocketmine\nbt\NBT; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\ListTag; @@ -31,7 +32,6 @@ use pocketmine\network\mcpe\protocol\types\CacheableNbt; use pocketmine\network\mcpe\serializer\NetworkNbtSerializer; use function file_get_contents; use function getmypid; -use function json_decode; use function mt_rand; use function mt_srand; use function shuffle; @@ -77,7 +77,7 @@ final class RuntimeBlockMapping{ } private function setupLegacyMappings() : void{ - $legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true); + $legacyIdMap = LegacyBlockIdToStringIdMap::getInstance(); $legacyStateMap = (new NetworkNbtSerializer())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.nbt"))->getTag(); if(!($legacyStateMap instanceof ListTag) or $legacyStateMap->getTagType() !== NBT::TAG_Compound){ throw new \RuntimeException("Invalid legacy states mapping table, expected TAG_List root"); @@ -93,7 +93,10 @@ final class RuntimeBlockMapping{ /** @var CompoundTag $pair */ foreach($legacyStateMap as $pair){ $oldState = $pair->getCompoundTag("old"); - $id = $legacyIdMap[$oldState->getString("name")]; + $id = $legacyIdMap->stringToLegacy($oldState->getString("name")); + if($id === null){ + throw new \RuntimeException("State does not have a legacy ID"); + } $data = $oldState->getShort("val"); if($data > 15){ //we can't handle metadata with more than 4 bits diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index a765dd03f..7bd49dac7 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\world\format\io\leveldb; use pocketmine\block\BlockLegacyIds; +use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap; use pocketmine\nbt\LittleEndianNbtSerializer; use pocketmine\nbt\NbtDataException; use pocketmine\nbt\tag\CompoundTag; @@ -45,7 +46,6 @@ use pocketmine\world\format\io\WritableWorldProvider; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\format\SubChunk; use pocketmine\world\generator\Generator; -use function array_flip; use function array_map; use function array_values; use function chr; @@ -53,9 +53,7 @@ use function count; use function defined; use function extension_loaded; use function file_exists; -use function file_get_contents; use function is_dir; -use function json_decode; use function mkdir; use function ord; use function str_repeat; @@ -153,11 +151,6 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ } protected function deserializePaletted(BinaryStream $stream) : PalettedBlockArray{ - static $stringToLegacyId = null; - if($stringToLegacyId === null){ - $stringToLegacyId = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . 'vanilla/block_id_map.json'), true); - } - $bitsPerBlock = $stream->getByte() >> 1; try{ @@ -167,12 +160,13 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ } $nbt = new LittleEndianNbtSerializer(); $palette = []; + $idMap = LegacyBlockIdToStringIdMap::getInstance(); for($i = 0, $paletteSize = $stream->getLInt(); $i < $paletteSize; ++$i){ $offset = $stream->getOffset(); $tag = $nbt->read($stream->getBuffer(), $offset)->mustGetCompoundTag(); $stream->setOffset($offset); - $id = $stringToLegacyId[$tag->getString("name")] ?? BlockLegacyIds::INFO_UPDATE; + $id = $idMap->stringToLegacy($tag->getString("name")) ?? BlockLegacyIds::INFO_UPDATE; $data = $tag->getShort("val"); $palette[] = ($id << 4) | $data; } @@ -419,10 +413,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ } protected function writeChunk(Chunk $chunk) : void{ - static $idMap = null; - if($idMap === null){ - $idMap = array_flip(json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . 'vanilla/block_id_map.json'), true)); - } + $idMap = LegacyBlockIdToStringIdMap::getInstance(); $index = LevelDB::chunkIndex($chunk->getX(), $chunk->getZ()); $write = new \LevelDBWriteBatch(); @@ -449,7 +440,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $tags = []; foreach($palette as $p){ $tags[] = new TreeRoot(CompoundTag::create() - ->setString("name", $idMap[$p >> 4] ?? "minecraft:info_update") + ->setString("name", $idMap->legacyToString($p >> 4) ?? "minecraft:info_update") ->setInt("oldid", $p >> 4) //PM only (debugging), vanilla doesn't have this ->setShort("val", $p & 0xf)); }