World: automatically remap invalid blockstates on chunk load

this fixes a wide range of blocks with invalid blockstates becoming update! blocks on the client.

The most common occurrence of this was air with nonzero metadata left behind by world editors which set blockIDs but not block metadata. This caused large ghost structures of update! blocks to appear from nowhere.

The performance impact of this is very minimal (20 microseconds per chunk load in timings, compared to average 660 microseconds to load tiles).
This commit is contained in:
Dylan K. Taylor
2021-11-27 01:12:30 +00:00
parent e5149756a8
commit 1f9400f901
3 changed files with 39 additions and 0 deletions

View File

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