mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-21 08:17:34 +00:00
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:
parent
e5149756a8
commit
1f9400f901
@ -75,6 +75,12 @@ class BlockFactory{
|
||||
*/
|
||||
private $fullList;
|
||||
|
||||
/**
|
||||
* @var \SplFixedArray|int[]
|
||||
* @phpstan-var \SplFixedArray<int>
|
||||
*/
|
||||
private \SplFixedArray $mappedStateIds;
|
||||
|
||||
/**
|
||||
* @var \SplFixedArray|int[]
|
||||
* @phpstan-var \SplFixedArray<int>
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user