From 8744032ab6e19baf4e902e61b39fb7b2f8f73f44 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 29 May 2023 18:26:23 +0100 Subject: [PATCH] Fixed empty block handling after blockstate ID XOR change --- src/block/Block.php | 5 +++++ src/world/format/Chunk.php | 7 +++---- src/world/format/io/leveldb/LevelDB.php | 15 +++++++-------- src/world/format/io/region/Anvil.php | 3 +-- .../format/io/region/LegacyAnvilChunkTrait.php | 3 +-- src/world/format/io/region/McRegion.php | 5 ++--- src/world/format/io/region/PMAnvil.php | 3 +-- tests/phpunit/block/BlockTest.php | 5 +++++ 8 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/block/Block.php b/src/block/Block.php index 29990bd1c..21781d170 100644 --- a/src/block/Block.php +++ b/src/block/Block.php @@ -58,6 +58,11 @@ class Block{ public const INTERNAL_STATE_DATA_BITS = 8; public const INTERNAL_STATE_DATA_MASK = ~(~0 << self::INTERNAL_STATE_DATA_BITS); + /** + * @internal + */ + public const EMPTY_STATE_ID = (BlockTypeIds::AIR << self::INTERNAL_STATE_DATA_BITS) | (BlockTypeIds::AIR & self::INTERNAL_STATE_DATA_MASK); + protected BlockIdentifier $idInfo; protected string $fallbackName; protected BlockTypeInfo $typeInfo; diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index 1f94ad9d0..e4c877dc9 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -27,7 +27,6 @@ declare(strict_types=1); namespace pocketmine\world\format; use pocketmine\block\Block; -use pocketmine\block\BlockTypeIds; use pocketmine\block\tile\Tile; use pocketmine\data\bedrock\BiomeIds; use function array_map; @@ -71,7 +70,7 @@ class Chunk{ foreach($this->subChunks as $y => $null){ //TODO: we should probably require all subchunks to be provided here - $this->subChunks[$y] = $subChunks[$y + self::MIN_SUBCHUNK_INDEX] ?? new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, [], new PalettedBlockArray(BiomeIds::OCEAN)); + $this->subChunks[$y] = $subChunks[$y + self::MIN_SUBCHUNK_INDEX] ?? new SubChunk(Block::EMPTY_STATE_ID, [], new PalettedBlockArray(BiomeIds::OCEAN)); } $val = (self::MAX_SUBCHUNK_INDEX + 1) * SubChunk::EDGE_LENGTH; @@ -293,8 +292,8 @@ class Chunk{ throw new \InvalidArgumentException("Invalid subchunk Y coordinate $y"); } - $this->subChunks[$y - self::MIN_SUBCHUNK_INDEX] = $subChunk ?? new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, [], new PalettedBlockArray(BiomeIds::OCEAN)); - $this->setTerrainDirtyFlag(self::DIRTY_FLAG_BLOCKS, true); + $this->subChunks[$y - self::MIN_SUBCHUNK_INDEX] = $subChunk ?? new SubChunk(Block::EMPTY_STATE_ID, [], new PalettedBlockArray(BiomeIds::OCEAN)); + $this->terrainDirtyFlags |= self::DIRTY_FLAG_BLOCKS; } /** diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index c0ae51673..a42d8d53e 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine\world\format\io\leveldb; use pocketmine\block\Block; -use pocketmine\block\BlockTypeIds; use pocketmine\data\bedrock\BiomeIds; use pocketmine\data\bedrock\block\BlockStateDeserializeException; use pocketmine\nbt\LittleEndianNbtSerializer; @@ -355,7 +354,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $blockStateId = $this->blockStateDeserializer->deserialize($blockStateData); if(!isset($extraDataLayers[$ySub])){ - $extraDataLayers[$ySub] = new PalettedBlockArray(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS); + $extraDataLayers[$ySub] = new PalettedBlockArray(Block::EMPTY_STATE_ID); } $extraDataLayers[$ySub]->set($x, $y, $z, $blockStateId); } @@ -417,13 +416,13 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ if(isset($convertedLegacyExtraData[$yy])){ $storages[] = $convertedLegacyExtraData[$yy]; } - $subChunks[$yy] = new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, $storages, clone $biomes3d); + $subChunks[$yy] = new SubChunk(Block::EMPTY_STATE_ID, $storages, clone $biomes3d); } //make sure extrapolated biomes get filled in correctly for($yy = Chunk::MIN_SUBCHUNK_INDEX; $yy <= Chunk::MAX_SUBCHUNK_INDEX; ++$yy){ if(!isset($subChunks[$yy])){ - $subChunks[$yy] = new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, [], clone $biomes3d); + $subChunks[$yy] = new SubChunk(Block::EMPTY_STATE_ID, [], clone $biomes3d); } } @@ -457,7 +456,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $storages[] = $convertedLegacyExtraData; } - return new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, $storages, $biomePalette); + return new SubChunk(Block::EMPTY_STATE_ID, $storages, $biomePalette); } /** @@ -481,7 +480,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ if($convertedLegacyExtraData !== null){ $storages[] = $convertedLegacyExtraData; } - return new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, $storages, $biomePalette); + return new SubChunk(Block::EMPTY_STATE_ID, $storages, $biomePalette); case SubChunkVersion::PALETTED_MULTI: case SubChunkVersion::PALETTED_MULTI_WITH_OFFSET: //legacy extradata layers intentionally ignored because they aren't supposed to exist in v8 @@ -496,7 +495,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ for($k = 0; $k < $storageCount; ++$k){ $storages[] = $this->deserializeBlockPalette($binaryStream, $logger); } - return new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, $storages, $biomePalette); + return new SubChunk(Block::EMPTY_STATE_ID, $storages, $biomePalette); default: //this should never happen - an unsupported chunk appearing in a supported world is a sign of corruption throw new CorruptedChunkException("don't know how to decode LevelDB subchunk format version $subChunkVersion"); @@ -526,7 +525,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $subChunkKeyOffset = self::hasOffsetCavesAndCliffsSubChunks($chunkVersion) ? self::CAVES_CLIFFS_EXPERIMENTAL_SUBCHUNK_KEY_OFFSET : 0; for($y = Chunk::MIN_SUBCHUNK_INDEX; $y <= Chunk::MAX_SUBCHUNK_INDEX; ++$y){ if(($data = $this->db->get($index . ChunkDataKey::SUBCHUNK . chr($y + $subChunkKeyOffset))) === false){ - $subChunks[$y] = new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, [], $biomeArrays[$y]); + $subChunks[$y] = new SubChunk(Block::EMPTY_STATE_ID, [], $biomeArrays[$y]); continue; } diff --git a/src/world/format/io/region/Anvil.php b/src/world/format/io/region/Anvil.php index c1b6b9671..abefc9f25 100644 --- a/src/world/format/io/region/Anvil.php +++ b/src/world/format/io/region/Anvil.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine\world\format\io\region; use pocketmine\block\Block; -use pocketmine\block\BlockTypeIds; use pocketmine\nbt\tag\CompoundTag; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\format\SubChunk; @@ -33,7 +32,7 @@ class Anvil extends RegionWorldProvider{ use LegacyAnvilChunkTrait; protected function deserializeSubChunk(CompoundTag $subChunk, PalettedBlockArray $biomes3d) : SubChunk{ - return new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, [$this->palettizeLegacySubChunkYZX( + return new SubChunk(Block::EMPTY_STATE_ID, [$this->palettizeLegacySubChunkYZX( self::readFixedSizeByteArray($subChunk, "Blocks", 4096), self::readFixedSizeByteArray($subChunk, "Data", 2048) )], $biomes3d); diff --git a/src/world/format/io/region/LegacyAnvilChunkTrait.php b/src/world/format/io/region/LegacyAnvilChunkTrait.php index ffb7b585a..ba97d43b5 100644 --- a/src/world/format/io/region/LegacyAnvilChunkTrait.php +++ b/src/world/format/io/region/LegacyAnvilChunkTrait.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine\world\format\io\region; use pocketmine\block\Block; -use pocketmine\block\BlockTypeIds; use pocketmine\data\bedrock\BiomeIds; use pocketmine\nbt\BigEndianNbtSerializer; use pocketmine\nbt\NbtDataException; @@ -96,7 +95,7 @@ trait LegacyAnvilChunkTrait{ } for($y = Chunk::MIN_SUBCHUNK_INDEX; $y <= Chunk::MAX_SUBCHUNK_INDEX; ++$y){ if(!isset($subChunks[$y])){ - $subChunks[$y] = new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, [], clone $biomes3d); + $subChunks[$y] = new SubChunk(Block::EMPTY_STATE_ID, [], clone $biomes3d); } } diff --git a/src/world/format/io/region/McRegion.php b/src/world/format/io/region/McRegion.php index b596e33af..878c84df4 100644 --- a/src/world/format/io/region/McRegion.php +++ b/src/world/format/io/region/McRegion.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine\world\format\io\region; use pocketmine\block\Block; -use pocketmine\block\BlockTypeIds; use pocketmine\data\bedrock\BiomeIds; use pocketmine\nbt\BigEndianNbtSerializer; use pocketmine\nbt\NbtDataException; @@ -91,11 +90,11 @@ class McRegion extends RegionWorldProvider{ $fullData = self::readFixedSizeByteArray($chunk, "Data", 16384); for($y = 0; $y < 8; ++$y){ - $subChunks[$y] = new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, [$this->palettizeLegacySubChunkFromColumn($fullIds, $fullData, $y)], clone $biomes3d); + $subChunks[$y] = new SubChunk(Block::EMPTY_STATE_ID, [$this->palettizeLegacySubChunkFromColumn($fullIds, $fullData, $y)], clone $biomes3d); } for($y = Chunk::MIN_SUBCHUNK_INDEX; $y <= Chunk::MAX_SUBCHUNK_INDEX; ++$y){ if(!isset($subChunks[$y])){ - $subChunks[$y] = new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, [], clone $biomes3d); + $subChunks[$y] = new SubChunk(Block::EMPTY_STATE_ID, [], clone $biomes3d); } } diff --git a/src/world/format/io/region/PMAnvil.php b/src/world/format/io/region/PMAnvil.php index 8d31f73bc..41dc0fa80 100644 --- a/src/world/format/io/region/PMAnvil.php +++ b/src/world/format/io/region/PMAnvil.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine\world\format\io\region; use pocketmine\block\Block; -use pocketmine\block\BlockTypeIds; use pocketmine\nbt\tag\CompoundTag; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\format\SubChunk; @@ -37,7 +36,7 @@ class PMAnvil extends RegionWorldProvider{ use LegacyAnvilChunkTrait; protected function deserializeSubChunk(CompoundTag $subChunk, PalettedBlockArray $biomes3d) : SubChunk{ - return new SubChunk(BlockTypeIds::AIR << Block::INTERNAL_STATE_DATA_BITS, [$this->palettizeLegacySubChunkXZY( + return new SubChunk(Block::EMPTY_STATE_ID, [$this->palettizeLegacySubChunkXZY( self::readFixedSizeByteArray($subChunk, "Blocks", 4096), self::readFixedSizeByteArray($subChunk, "Data", 2048) )], $biomes3d); diff --git a/tests/phpunit/block/BlockTest.php b/tests/phpunit/block/BlockTest.php index 81f1c3516..711b7e51a 100644 --- a/tests/phpunit/block/BlockTest.php +++ b/tests/phpunit/block/BlockTest.php @@ -119,4 +119,9 @@ class BlockTest extends TestCase{ self::assertSame($name, $states[$k]->getName()); } } + + public function testEmptyStateId() : void{ + $block = $this->blockFactory->fromStateId(Block::EMPTY_STATE_ID); + self::assertInstanceOf(Air::class, $block); + } }