diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index fd252f789..38e26f6b7 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -75,6 +75,12 @@ class BlockFactory{ */ private $fullList; + /** + * @var \SplFixedArray|int[] + * @phpstan-var \SplFixedArray + */ + private \SplFixedArray $mappedStateIds; + /** * @var \SplFixedArray|int[] * @phpstan-var \SplFixedArray @@ -98,6 +104,7 @@ class BlockFactory{ public function __construct(){ $this->fullList = new \SplFixedArray(1024 << Block::INTERNAL_METADATA_BITS); + $this->mappedStateIds = new \SplFixedArray(1024 << Block::INTERNAL_METADATA_BITS); $this->light = \SplFixedArray::fromArray(array_fill(0, 1024 << Block::INTERNAL_METADATA_BITS, 0)); $this->lightFilter = \SplFixedArray::fromArray(array_fill(0, 1024 << Block::INTERNAL_METADATA_BITS, 1)); @@ -948,6 +955,7 @@ class BlockFactory{ private function fillStaticArrays(int $index, Block $block) : void{ $this->fullList[$index] = $block; + $this->mappedStateIds[$index] = $block->getFullId(); $this->light[$index] = $block->getLightLevel(); $this->lightFilter[$index] = min(15, $block->getLightFilter() + 1); //opacity plus 1 standard light filter $this->blocksDirectSkyLight[$index] = $block->blocksDirectSkyLight(); @@ -997,4 +1005,12 @@ class BlockFactory{ public function getAllKnownStates() : array{ return array_filter($this->fullList->toArray(), function(?Block $v) : bool{ return $v !== null; }); } + + /** + * Returns the ID of the state mapped to the given state ID. + * Used to correct invalid blockstates found in loaded chunks. + */ + public function getMappedStateId(int $fullState) : int{ + return $this->mappedStateIds[$fullState] ?? $fullState; + } } diff --git a/src/world/World.php b/src/world/World.php index 9549980eb..37236de22 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2466,6 +2466,27 @@ class World implements ChunkManager{ private function initChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void{ $logger = new \PrefixedLogger($this->logger, "Loading chunk $chunkX $chunkZ"); + + $this->timings->syncChunkLoadFixInvalidBlocks->startTiming(); + $blockFactory = BlockFactory::getInstance(); + $invalidBlocks = 0; + foreach($chunkData->getChunk()->getSubChunks() as $subChunk){ + foreach($subChunk->getBlockLayers() as $blockLayer){ + foreach($blockLayer->getPalette() as $blockStateId){ + $mappedStateId = $blockFactory->getMappedStateId($blockStateId); + if($mappedStateId !== $blockStateId){ + $blockLayer->replaceAll($blockStateId, $mappedStateId); + $invalidBlocks++; + } + } + } + } + if($invalidBlocks > 0){ + $logger->debug("Fixed $invalidBlocks invalid blockstates"); + $chunkData->getChunk()->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_BLOCKS, true); + } + $this->timings->syncChunkLoadFixInvalidBlocks->stopTiming(); + if(count($chunkData->getEntityNBT()) !== 0){ $this->timings->syncChunkLoadEntities->startTiming(); $entityFactory = EntityFactory::getInstance(); diff --git a/src/world/WorldTimings.php b/src/world/WorldTimings.php index ac060e9a3..874a5f5fd 100644 --- a/src/world/WorldTimings.php +++ b/src/world/WorldTimings.php @@ -45,6 +45,7 @@ class WorldTimings{ public TimingsHandler $syncChunkLoad; public TimingsHandler $syncChunkLoadData; + public TimingsHandler $syncChunkLoadFixInvalidBlocks; public TimingsHandler $syncChunkLoadEntities; public TimingsHandler $syncChunkLoadTileEntities; public TimingsHandler $syncChunkSave; @@ -69,6 +70,7 @@ class WorldTimings{ $this->syncChunkLoad = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load", Timings::$worldLoad); $this->syncChunkLoadData = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Data"); + $this->syncChunkLoadFixInvalidBlocks = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Fix Invalid Blocks"); $this->syncChunkLoadEntities = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Entities"); $this->syncChunkLoadTileEntities = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - TileEntities"); $this->syncChunkSave = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Save", Timings::$worldSave);