wrap up block_id_map in a class

This commit is contained in:
Dylan K. Taylor 2020-04-24 21:28:27 +01:00
parent 1df345ba6f
commit 3a42c21cc1
3 changed files with 80 additions and 17 deletions

View File

@ -0,0 +1,69 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\SingletonTrait;
use function file_get_contents;
use function is_array;
use function is_int;
use function is_string;
use function json_decode;
final class LegacyBlockIdToStringIdMap{
use SingletonTrait;
/**
* @var string[]
* @phpstan-var array<int, string>
*/
private $legacyToString = [];
/**
* @var int[]
* @phpstan-var array<string, int>
*/
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;
}
}

View File

@ -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<TAG_Compound> 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

View File

@ -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));
}