Replace hardcoded block metadata shifts and masks with constants

we might want to make these bigger than 4 bits in the future.
This commit is contained in:
Dylan K. Taylor 2021-06-16 12:48:09 +01:00
parent c22f793521
commit 61c59be299
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
9 changed files with 37 additions and 29 deletions

View File

@ -48,6 +48,8 @@ use function dechex;
use const PHP_INT_MAX; use const PHP_INT_MAX;
class Block{ class Block{
public const INTERNAL_METADATA_BITS = 4;
public const INTERNAL_METADATA_MASK = ~(~0 << self::INTERNAL_METADATA_BITS);
protected BlockIdentifier $idInfo; protected BlockIdentifier $idInfo;
protected string $fallbackName; protected string $fallbackName;
@ -90,7 +92,7 @@ class Block{
* @internal * @internal
*/ */
public function getFullId() : int{ public function getFullId() : int{
return ($this->getId() << 4) | $this->getMeta(); return ($this->getId() << self::INTERNAL_METADATA_BITS) | $this->getMeta();
} }
public function asItem() : Item{ public function asItem() : Item{

View File

@ -895,7 +895,7 @@ class BlockFactory{
throw new \InvalidArgumentException("Block registration " . get_class($block) . " has states which conflict with other blocks"); throw new \InvalidArgumentException("Block registration " . get_class($block) . " has states which conflict with other blocks");
} }
$index = ($id << 4) | $m; $index = ($id << Block::INTERNAL_METADATA_BITS) | $m;
$v = clone $block; $v = clone $block;
try{ try{
@ -915,7 +915,7 @@ class BlockFactory{
} }
public function remap(int $id, int $meta, Block $block) : void{ public function remap(int $id, int $meta, Block $block) : void{
$index = ($id << 4) | $meta; $index = ($id << Block::INTERNAL_METADATA_BITS) | $meta;
if($this->isRegistered($id, $meta)){ if($this->isRegistered($id, $meta)){
$existing = $this->fullList[$index]; $existing = $this->fullList[$index];
if($existing !== null && $existing->getFullId() === $index){ if($existing !== null && $existing->getFullId() === $index){
@ -924,7 +924,7 @@ class BlockFactory{
//if it's not a match, this was already remapped for some reason; remapping overwrites are OK //if it's not a match, this was already remapped for some reason; remapping overwrites are OK
} }
} }
$this->fillStaticArrays(($id << 4) | $meta, $block); $this->fillStaticArrays(($id << Block::INTERNAL_METADATA_BITS) | $meta, $block);
} }
private function fillStaticArrays(int $index, Block $block) : void{ private function fillStaticArrays(int $index, Block $block) : void{
@ -943,14 +943,14 @@ class BlockFactory{
* Deserializes a block from the provided legacy ID and legacy meta. * Deserializes a block from the provided legacy ID and legacy meta.
*/ */
public function get(int $id, int $meta) : Block{ public function get(int $id, int $meta) : Block{
if($meta < 0 or $meta > 0xf){ if($meta < 0 or $meta > (1 << Block::INTERNAL_METADATA_BITS)){
throw new \InvalidArgumentException("Block meta value $meta is out of bounds"); throw new \InvalidArgumentException("Block meta value $meta is out of bounds");
} }
/** @var Block|null $block */ /** @var Block|null $block */
$block = null; $block = null;
try{ try{
$index = ($id << 4) | $meta; $index = ($id << Block::INTERNAL_METADATA_BITS) | $meta;
if($this->fullList[$index] !== null){ if($this->fullList[$index] !== null){
$block = clone $this->fullList[$index]; $block = clone $this->fullList[$index];
} }
@ -966,14 +966,14 @@ class BlockFactory{
} }
public function fromFullBlock(int $fullState) : Block{ public function fromFullBlock(int $fullState) : Block{
return $this->get($fullState >> 4, $fullState & 0xf); return $this->get($fullState >> Block::INTERNAL_METADATA_BITS, $fullState & Block::INTERNAL_METADATA_MASK);
} }
/** /**
* Returns whether a specified block state is already registered in the block factory. * Returns whether a specified block state is already registered in the block factory.
*/ */
public function isRegistered(int $id, int $meta = 0) : bool{ public function isRegistered(int $id, int $meta = 0) : bool{
$b = $this->fullList[($id << 4) | $meta]; $b = $this->fullList[($id << Block::INTERNAL_METADATA_BITS) | $meta];
return $b !== null and !($b instanceof UnknownBlock); return $b !== null and !($b instanceof UnknownBlock);
} }

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\convert; namespace pocketmine\network\mcpe\convert;
use pocketmine\block\Block;
use pocketmine\block\BlockLegacyIds; use pocketmine\block\BlockLegacyIds;
use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap; use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
@ -110,7 +111,7 @@ final class RuntimeBlockMapping{
} }
public function toRuntimeId(int $internalStateId) : int{ public function toRuntimeId(int $internalStateId) : int{
return $this->legacyToRuntimeMap[$internalStateId] ?? $this->legacyToRuntimeMap[BlockLegacyIds::INFO_UPDATE << 4]; return $this->legacyToRuntimeMap[$internalStateId] ?? $this->legacyToRuntimeMap[BlockLegacyIds::INFO_UPDATE << Block::INTERNAL_METADATA_BITS];
} }
public function fromRuntimeId(int $runtimeId) : int{ public function fromRuntimeId(int $runtimeId) : int{
@ -118,8 +119,8 @@ final class RuntimeBlockMapping{
} }
private function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{ private function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{
$this->legacyToRuntimeMap[($legacyId << 4) | $legacyMeta] = $staticRuntimeId; $this->legacyToRuntimeMap[($legacyId << Block::INTERNAL_METADATA_BITS) | $legacyMeta] = $staticRuntimeId;
$this->runtimeToLegacyMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta; $this->runtimeToLegacyMap[$staticRuntimeId] = ($legacyId << Block::INTERNAL_METADATA_BITS) | $legacyMeta;
} }
/** /**

View File

@ -26,6 +26,7 @@ declare(strict_types=1);
namespace pocketmine\world\format; namespace pocketmine\world\format;
use pocketmine\block\Block;
use pocketmine\block\BlockLegacyIds; use pocketmine\block\BlockLegacyIds;
use pocketmine\block\tile\Tile; use pocketmine\block\tile\Tile;
use pocketmine\data\bedrock\BiomeIds; use pocketmine\data\bedrock\BiomeIds;
@ -86,7 +87,7 @@ class Chunk{
$this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS); $this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS);
foreach($this->subChunks as $y => $null){ foreach($this->subChunks as $y => $null){
$this->subChunks[$y] = $subChunks[$y] ?? new SubChunk(BlockLegacyIds::AIR << 4, []); $this->subChunks[$y] = $subChunks[$y] ?? new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, []);
} }
$val = ($this->subChunks->getSize() * 16); $val = ($this->subChunks->getSize() * 16);
@ -366,7 +367,7 @@ class Chunk{
throw new \InvalidArgumentException("Invalid subchunk Y coordinate $y"); throw new \InvalidArgumentException("Invalid subchunk Y coordinate $y");
} }
$this->subChunks[$y] = $subChunk ?? new SubChunk(BlockLegacyIds::AIR << 4, []); $this->subChunks[$y] = $subChunk ?? new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, []);
$this->setDirtyFlag(self::DIRTY_FLAG_TERRAIN, true); $this->setDirtyFlag(self::DIRTY_FLAG_TERRAIN, true);
} }

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\world\format\io\leveldb; namespace pocketmine\world\format\io\leveldb;
use pocketmine\block\Block;
use pocketmine\block\BlockLegacyIds; use pocketmine\block\BlockLegacyIds;
use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap; use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap;
use pocketmine\nbt\LittleEndianNbtSerializer; use pocketmine\nbt\LittleEndianNbtSerializer;
@ -176,7 +177,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
//we really need a proper state fixer, but this is a pressing issue. //we really need a proper state fixer, but this is a pressing issue.
$data = 0; $data = 0;
} }
$palette[] = ($id << 4) | $data; $palette[] = ($id << Block::INTERNAL_METADATA_BITS) | $data;
} }
//TODO: exceptions //TODO: exceptions
@ -219,9 +220,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$blockId = $value & 0xff; $blockId = $value & 0xff;
$blockData = ($value >> 8) & 0xf; $blockData = ($value >> 8) & 0xf;
if(!isset($extraDataLayers[$ySub])){ if(!isset($extraDataLayers[$ySub])){
$extraDataLayers[$ySub] = new PalettedBlockArray(BlockLegacyIds::AIR << 4); $extraDataLayers[$ySub] = new PalettedBlockArray(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS);
} }
$extraDataLayers[$ySub]->set($x, $y, $z, ($blockId << 4) | $blockData); $extraDataLayers[$ySub]->set($x, $y, $z, ($blockId << Block::INTERNAL_METADATA_BITS) | $blockData);
} }
return $extraDataLayers; return $extraDataLayers;
@ -301,14 +302,14 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$storages[] = $convertedLegacyExtraData[$y]; $storages[] = $convertedLegacyExtraData[$y];
} }
$subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << 4, $storages); $subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, $storages);
break; break;
case 1: //paletted v1, has a single blockstorage case 1: //paletted v1, has a single blockstorage
$storages = [$this->deserializePaletted($binaryStream)]; $storages = [$this->deserializePaletted($binaryStream)];
if(isset($convertedLegacyExtraData[$y])){ if(isset($convertedLegacyExtraData[$y])){
$storages[] = $convertedLegacyExtraData[$y]; $storages[] = $convertedLegacyExtraData[$y];
} }
$subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << 4, $storages); $subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, $storages);
break; break;
case 8: case 8:
//legacy extradata layers intentionally ignored because they aren't supposed to exist in v8 //legacy extradata layers intentionally ignored because they aren't supposed to exist in v8
@ -319,7 +320,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
for($k = 0; $k < $storageCount; ++$k){ for($k = 0; $k < $storageCount; ++$k){
$storages[] = $this->deserializePaletted($binaryStream); $storages[] = $this->deserializePaletted($binaryStream);
} }
$subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << 4, $storages); $subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, $storages);
} }
break; break;
default: default:
@ -362,7 +363,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
if(isset($convertedLegacyExtraData[$yy])){ if(isset($convertedLegacyExtraData[$yy])){
$storages[] = $convertedLegacyExtraData[$yy]; $storages[] = $convertedLegacyExtraData[$yy];
} }
$subChunks[$yy] = new SubChunk(BlockLegacyIds::AIR << 4, $storages); $subChunks[$yy] = new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, $storages);
} }
try{ try{
@ -446,9 +447,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$tags = []; $tags = [];
foreach($palette as $p){ foreach($palette as $p){
$tags[] = new TreeRoot(CompoundTag::create() $tags[] = new TreeRoot(CompoundTag::create()
->setString("name", $idMap->legacyToString($p >> 4) ?? "minecraft:info_update") ->setString("name", $idMap->legacyToString($p >> Block::INTERNAL_METADATA_BITS) ?? "minecraft:info_update")
->setInt("oldid", $p >> 4) //PM only (debugging), vanilla doesn't have this ->setInt("oldid", $p >> Block::INTERNAL_METADATA_BITS) //PM only (debugging), vanilla doesn't have this
->setShort("val", $p & 0xf)); ->setShort("val", $p & Block::INTERNAL_METADATA_MASK));
} }
$subStream->put((new LittleEndianNbtSerializer())->writeMultiple($tags)); $subStream->put((new LittleEndianNbtSerializer())->writeMultiple($tags));

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\world\format\io\region; namespace pocketmine\world\format\io\region;
use pocketmine\block\Block;
use pocketmine\block\BlockLegacyIds; use pocketmine\block\BlockLegacyIds;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\world\format\io\SubChunkConverter; use pocketmine\world\format\io\SubChunkConverter;
@ -32,7 +33,7 @@ class Anvil extends RegionWorldProvider{
use LegacyAnvilChunkTrait; use LegacyAnvilChunkTrait;
protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{ protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
return new SubChunk(BlockLegacyIds::AIR << 4, [SubChunkConverter::convertSubChunkYZX( return new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, [SubChunkConverter::convertSubChunkYZX(
self::readFixedSizeByteArray($subChunk, "Blocks", 4096), self::readFixedSizeByteArray($subChunk, "Blocks", 4096),
self::readFixedSizeByteArray($subChunk, "Data", 2048) self::readFixedSizeByteArray($subChunk, "Data", 2048)
)]); )]);

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\world\format\io\region; namespace pocketmine\world\format\io\region;
use pocketmine\block\Block;
use pocketmine\block\BlockLegacyIds; use pocketmine\block\BlockLegacyIds;
use pocketmine\nbt\BigEndianNbtSerializer; use pocketmine\nbt\BigEndianNbtSerializer;
use pocketmine\nbt\NbtDataException; use pocketmine\nbt\NbtDataException;
@ -63,7 +64,7 @@ class McRegion extends RegionWorldProvider{
$fullData = self::readFixedSizeByteArray($chunk, "Data", 16384); $fullData = self::readFixedSizeByteArray($chunk, "Data", 16384);
for($y = 0; $y < 8; ++$y){ for($y = 0; $y < 8; ++$y){
$subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << 4, [SubChunkConverter::convertSubChunkFromLegacyColumn($fullIds, $fullData, $y)]); $subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, [SubChunkConverter::convertSubChunkFromLegacyColumn($fullIds, $fullData, $y)]);
} }
$makeBiomeArray = function(string $biomeIds) : BiomeArray{ $makeBiomeArray = function(string $biomeIds) : BiomeArray{

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\world\format\io\region; namespace pocketmine\world\format\io\region;
use pocketmine\block\Block;
use pocketmine\block\BlockLegacyIds; use pocketmine\block\BlockLegacyIds;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\world\format\io\SubChunkConverter; use pocketmine\world\format\io\SubChunkConverter;
@ -36,7 +37,7 @@ class PMAnvil extends RegionWorldProvider{
use LegacyAnvilChunkTrait; use LegacyAnvilChunkTrait;
protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{ protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
return new SubChunk(BlockLegacyIds::AIR << 4, [SubChunkConverter::convertSubChunkXZY( return new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, [SubChunkConverter::convertSubChunkXZY(
self::readFixedSizeByteArray($subChunk, "Blocks", 4096), self::readFixedSizeByteArray($subChunk, "Blocks", 4096),
self::readFixedSizeByteArray($subChunk, "Data", 2048) self::readFixedSizeByteArray($subChunk, "Data", 2048)
)]); )]);

View File

@ -36,14 +36,14 @@ $new = array_map(
); );
foreach($old as $k => $name){ foreach($old as $k => $name){
if(!isset($new[$k])){ if(!isset($new[$k])){
echo "Removed state for $name (" . ($k >> 4) . ":" . ($k & 0xf) . ")\n"; echo "Removed state for $name (" . ($k >> \pocketmine\block\Block::INTERNAL_METADATA_BITS) . ":" . ($k & \pocketmine\block\Block::INTERNAL_METADATA_MASK) . ")\n";
} }
} }
foreach($new as $k => $name){ foreach($new as $k => $name){
if(!isset($old[$k])){ if(!isset($old[$k])){
echo "Added state for $name (" . ($k >> 4) . ":" . ($k & 0xf) . ")\n"; echo "Added state for $name (" . ($k >> \pocketmine\block\Block::INTERNAL_METADATA_BITS) . ":" . ($k & \pocketmine\block\Block::INTERNAL_METADATA_MASK) . ")\n";
}elseif($old[$k] !== $name){ }elseif($old[$k] !== $name){
echo "Name changed (" . ($k >> 4) . ":" . ($k & 0xf) . "): " . $old[$k] . " -> " . $name . "\n"; echo "Name changed (" . ($k >> \pocketmine\block\Block::INTERNAL_METADATA_BITS) . ":" . ($k & \pocketmine\block\Block::INTERNAL_METADATA_MASK) . "): " . $old[$k] . " -> " . $name . "\n";
} }
} }
file_put_contents(__DIR__ . '/block_factory_consistency_check.json', json_encode( file_put_contents(__DIR__ . '/block_factory_consistency_check.json', json_encode(