From 1bb9b3d3ab56536efc71e453737f240248ca86ad Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 3 Mar 2019 16:22:44 +0000 Subject: [PATCH] Discard light information from disk storage this makes world conversion faster and offers the opportunity to correct age-old lighting bugs. --- src/pocketmine/level/Level.php | 2 +- .../level/format/io/leveldb/LevelDB.php | 50 +++++-------------- .../level/format/io/region/Anvil.php | 10 ++-- .../io/region/LegacyAnvilChunkTrait.php | 9 ++-- .../level/format/io/region/McRegion.php | 42 +++------------- .../level/format/io/region/PMAnvil.php | 9 ++-- 6 files changed, 33 insertions(+), 89 deletions(-) diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 201ed48b5..f5c51f9c1 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -2663,7 +2663,7 @@ class Level implements ChunkManager, Metadatable{ (new ChunkLoadEvent($this, $chunk, !$chunk->isGenerated()))->call(); - if(!$chunk->isLightPopulated() and $chunk->isPopulated() and $this->getServer()->getProperty("chunk-ticking.light-updates", false)){ + if($chunk->isPopulated() and $this->getServer()->getProperty("chunk-ticking.light-updates", false)){ $this->getServer()->getAsyncPool()->submitTask(new LightPopulationTask($this, $chunk)); } diff --git a/src/pocketmine/level/format/io/leveldb/LevelDB.php b/src/pocketmine/level/format/io/leveldb/LevelDB.php index cd91e59fc..e6a60d4d6 100644 --- a/src/pocketmine/level/format/io/leveldb/LevelDB.php +++ b/src/pocketmine/level/format/io/leveldb/LevelDB.php @@ -46,7 +46,7 @@ use function file_exists; use function is_dir; use function mkdir; use function ord; -use function pack; +use function str_repeat; use function strlen; use function substr; use function unpack; @@ -146,14 +146,9 @@ class LevelDB extends BaseLevelProvider{ /** @var SubChunk[] $subChunks */ $subChunks = []; - /** @var int[] $heightMap */ - $heightMap = []; /** @var string $biomeIds */ $biomeIds = ""; - /** @var bool $lightPopulated */ - $lightPopulated = true; - $chunkVersion = ord($this->db->get($index . self::TAG_VERSION)); $binaryStream = new BinaryStream(); @@ -179,20 +174,15 @@ class LevelDB extends BaseLevelProvider{ try{ $blocks = $binaryStream->get(4096); $blockData = $binaryStream->get(2048); + if($chunkVersion < 4){ - $blockSkyLight = $binaryStream->get(2048); - $blockLight = $binaryStream->get(2048); - }else{ - //Mojang didn't bother changing the subchunk version when they stopped saving sky light -_- - $blockSkyLight = ""; - $blockLight = ""; - $lightPopulated = false; + $binaryStream->get(4096); //legacy light info, discard it } }catch(BinaryDataException $e){ throw new CorruptedChunkException($e->getMessage(), 0, $e); } - $subChunks[$y] = new SubChunk($blocks, $blockData, $blockSkyLight, $blockLight); + $subChunks[$y] = new SubChunk($blocks, $blockData); break; default: //TODO: set chunks read-only so the version on disk doesn't get overwritten @@ -204,7 +194,7 @@ class LevelDB extends BaseLevelProvider{ $binaryStream->setBuffer($maps2d); try{ - $heightMap = array_values(unpack("v*", $binaryStream->get(512))); + $binaryStream->get(512); //heightmap, discard it $biomeIds = $binaryStream->get(256); }catch(BinaryDataException $e){ throw new CorruptedChunkException($e->getMessage(), 0, $e); @@ -220,8 +210,7 @@ class LevelDB extends BaseLevelProvider{ try{ $fullIds = $binaryStream->get(32768); $fullData = $binaryStream->get(16384); - $fullSkyLight = $binaryStream->get(16384); - $fullBlockLight = $binaryStream->get(16384); + $binaryStream->get(32768); //legacy light info, discard it }catch(BinaryDataException $e){ throw new CorruptedChunkException($e->getMessage(), 0, $e); } @@ -239,23 +228,12 @@ class LevelDB extends BaseLevelProvider{ $data .= substr($fullData, $subOffset, 8); $subOffset += 64; } - $skyLight = ""; - $subOffset = ($yy << 3); - for($i = 0; $i < 256; ++$i){ - $skyLight .= substr($fullSkyLight, $subOffset, 8); - $subOffset += 64; - } - $blockLight = ""; - $subOffset = ($yy << 3); - for($i = 0; $i < 256; ++$i){ - $blockLight .= substr($fullBlockLight, $subOffset, 8); - $subOffset += 64; - } - $subChunks[$yy] = new SubChunk($ids, $data, $skyLight, $blockLight); + + $subChunks[$yy] = new SubChunk($ids, $data); } try{ - $heightMap = array_values(unpack("C*", $binaryStream->get(256))); + $binaryStream->get(256); //heightmap, discard it $biomeIds = ChunkUtils::convertBiomeColors(array_values(unpack("N*", $binaryStream->get(1024)))); }catch(BinaryDataException $e){ throw new CorruptedChunkException($e->getMessage(), 0, $e); @@ -307,15 +285,13 @@ class LevelDB extends BaseLevelProvider{ $subChunks, $entities, $tiles, - $biomeIds, - $heightMap + $biomeIds ); //TODO: tile ticks, biome states (?) - $chunk->setGenerated(true); - $chunk->setPopulated(true); - $chunk->setLightPopulated($lightPopulated); + $chunk->setGenerated(); + $chunk->setPopulated(); return $chunk; } @@ -338,7 +314,7 @@ class LevelDB extends BaseLevelProvider{ } } - $this->db->put($index . self::TAG_DATA_2D, pack("v*", ...$chunk->getHeightMapArray()) . $chunk->getBiomeIdArray()); + $this->db->put($index . self::TAG_DATA_2D, str_repeat("\x00", 512) . $chunk->getBiomeIdArray()); //TODO: use this properly $this->db->put($index . self::TAG_STATE_FINALISATION, chr(self::FINALISATION_DONE)); diff --git a/src/pocketmine/level/format/io/region/Anvil.php b/src/pocketmine/level/format/io/region/Anvil.php index b5fc66718..998b41840 100644 --- a/src/pocketmine/level/format/io/region/Anvil.php +++ b/src/pocketmine/level/format/io/region/Anvil.php @@ -27,6 +27,7 @@ use pocketmine\level\format\io\ChunkUtils; use pocketmine\level\format\SubChunk; use pocketmine\nbt\tag\ByteArrayTag; use pocketmine\nbt\tag\CompoundTag; +use function str_repeat; class Anvil extends RegionLevelProvider{ use LegacyAnvilChunkTrait; @@ -35,17 +36,16 @@ class Anvil extends RegionLevelProvider{ return new CompoundTag("", [ new ByteArrayTag("Blocks", ChunkUtils::reorderByteArray($subChunk->getBlockIdArray())), //Generic in-memory chunks are currently always XZY new ByteArrayTag("Data", ChunkUtils::reorderNibbleArray($subChunk->getBlockDataArray())), - new ByteArrayTag("SkyLight", ChunkUtils::reorderNibbleArray($subChunk->getBlockSkyLightArray(), "\xff")), - new ByteArrayTag("BlockLight", ChunkUtils::reorderNibbleArray($subChunk->getBlockLightArray())) + new ByteArrayTag("SkyLight", str_repeat("\x00", 2048)), + new ByteArrayTag("BlockLight", str_repeat("\x00", 2048)) ]); } protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{ return new SubChunk( ChunkUtils::reorderByteArray($subChunk->getByteArray("Blocks")), - ChunkUtils::reorderNibbleArray($subChunk->getByteArray("Data")), - ChunkUtils::reorderNibbleArray($subChunk->getByteArray("SkyLight"), "\xff"), - ChunkUtils::reorderNibbleArray($subChunk->getByteArray("BlockLight")) + ChunkUtils::reorderNibbleArray($subChunk->getByteArray("Data")) + //ignore legacy light information ); } diff --git a/src/pocketmine/level/format/io/region/LegacyAnvilChunkTrait.php b/src/pocketmine/level/format/io/region/LegacyAnvilChunkTrait.php index e10e6eb28..fc2ac45d0 100644 --- a/src/pocketmine/level/format/io/region/LegacyAnvilChunkTrait.php +++ b/src/pocketmine/level/format/io/region/LegacyAnvilChunkTrait.php @@ -33,6 +33,7 @@ use pocketmine\nbt\NbtDataException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntArrayTag; use pocketmine\nbt\tag\ListTag; +use function array_fill; /** * Trait containing I/O methods for handling legacy Anvil-style chunks. @@ -56,7 +57,7 @@ trait LegacyAnvilChunkTrait{ $nbt->setLong("LastUpdate", 0); //TODO $nbt->setLong("InhabitedTime", 0); //TODO $nbt->setByte("TerrainPopulated", $chunk->isPopulated() ? 1 : 0); - $nbt->setByte("LightPopulated", $chunk->isLightPopulated() ? 1 : 0); + $nbt->setByte("LightPopulated", 0); $subChunks = []; foreach($chunk->getSubChunks() as $y => $subChunk){ @@ -71,7 +72,7 @@ trait LegacyAnvilChunkTrait{ $nbt->setTag(new ListTag("Sections", $subChunks, NBT::TAG_Compound)); $nbt->setByteArray("Biomes", $chunk->getBiomeIdArray()); - $nbt->setIntArray("HeightMap", $chunk->getHeightMapArray()); + $nbt->setIntArray("HeightMap", array_fill(0, 256, 0)); $nbt->setTag(new ListTag("Entities", $chunk->getNBTentities(), NBT::TAG_Compound)); $nbt->setTag(new ListTag("TileEntities", $chunk->getNBTtiles(), NBT::TAG_Compound)); @@ -123,10 +124,8 @@ trait LegacyAnvilChunkTrait{ $subChunks, $chunk->hasTag("Entities", ListTag::class) ? $chunk->getListTag("Entities")->getValue() : [], $chunk->hasTag("TileEntities", ListTag::class) ? $chunk->getListTag("TileEntities")->getValue() : [], - $biomeIds, - $chunk->getIntArray("HeightMap", []) + $biomeIds ); - $result->setLightPopulated($chunk->getByte("LightPopulated", 0) !== 0); $result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0); $result->setGenerated(); return $result; diff --git a/src/pocketmine/level/format/io/region/McRegion.php b/src/pocketmine/level/format/io/region/McRegion.php index b4047ce96..11aef6279 100644 --- a/src/pocketmine/level/format/io/region/McRegion.php +++ b/src/pocketmine/level/format/io/region/McRegion.php @@ -34,11 +34,8 @@ use pocketmine\nbt\tag\ByteArrayTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntArrayTag; use pocketmine\nbt\tag\ListTag; -use function array_values; -use function pack; use function str_repeat; use function substr; -use function unpack; class McRegion extends RegionLevelProvider{ @@ -54,12 +51,10 @@ class McRegion extends RegionLevelProvider{ $nbt->setLong("LastUpdate", 0); //TODO $nbt->setByte("TerrainPopulated", $chunk->isPopulated() ? 1 : 0); - $nbt->setByte("LightPopulated", $chunk->isLightPopulated() ? 1 : 0); + $nbt->setByte("LightPopulated", 0); $ids = ""; $data = ""; - $skyLight = ""; - $blockLight = ""; $subChunks = $chunk->getSubChunks(); for($x = 0; $x < 16; ++$x){ for($z = 0; $z < 16; ++$z){ @@ -67,19 +62,17 @@ class McRegion extends RegionLevelProvider{ $subChunk = $subChunks[$y]; $ids .= substr($subChunk->getBlockIdArray(), ($x << 8) | ($z << 4), 16); $data .= substr($subChunk->getBlockDataArray(), ($x << 7) | ($z << 3), 8); - $skyLight .= substr($subChunk->getBlockSkyLightArray(), ($x << 7) | ($z << 3), 8); - $blockLight .= substr($subChunk->getBlockLightArray(), ($x << 7) | ($z << 3), 8); } } } $nbt->setByteArray("Blocks", $ids); $nbt->setByteArray("Data", $data); - $nbt->setByteArray("SkyLight", $skyLight); - $nbt->setByteArray("BlockLight", $blockLight); + $nbt->setByteArray("SkyLight", str_repeat("\x00", 16384)); + $nbt->setByteArray("BlockLight", str_repeat("\x00", 16384)); $nbt->setByteArray("Biomes", $chunk->getBiomeIdArray()); //doesn't exist in regular McRegion, this is here for PocketMine-MP only - $nbt->setByteArray("HeightMap", pack("C*", ...$chunk->getHeightMapArray())); //this is ByteArray in McRegion, but IntArray in Anvil (due to raised build height) + $nbt->setByteArray("HeightMap", str_repeat("\x00", 256)); //this is ByteArray in McRegion, but IntArray in Anvil (due to raised build height) $nbt->setTag(new ListTag("Entities", $chunk->getNBTentities(), NBT::TAG_Compound)); $nbt->setTag(new ListTag("TileEntities", $chunk->getNBTtiles(), NBT::TAG_Compound)); @@ -110,8 +103,6 @@ class McRegion extends RegionLevelProvider{ $subChunks = []; $fullIds = $chunk->hasTag("Blocks", ByteArrayTag::class) ? $chunk->getByteArray("Blocks") : str_repeat("\x00", 32768); $fullData = $chunk->hasTag("Data", ByteArrayTag::class) ? $chunk->getByteArray("Data") : str_repeat("\x00", 16384); - $fullSkyLight = $chunk->hasTag("SkyLight", ByteArrayTag::class) ? $chunk->getByteArray("SkyLight") : str_repeat("\xff", 16384); - $fullBlockLight = $chunk->hasTag("BlockLight", ByteArrayTag::class) ? $chunk->getByteArray("BlockLight") : str_repeat("\x00", 16384); for($y = 0; $y < 8; ++$y){ $offset = ($y << 4); @@ -126,19 +117,7 @@ class McRegion extends RegionLevelProvider{ $data .= substr($fullData, $offset, 8); $offset += 64; } - $skyLight = ""; - $offset = ($y << 3); - for($i = 0; $i < 256; ++$i){ - $skyLight .= substr($fullSkyLight, $offset, 8); - $offset += 64; - } - $blockLight = ""; - $offset = ($y << 3); - for($i = 0; $i < 256; ++$i){ - $blockLight .= substr($fullBlockLight, $offset, 8); - $offset += 64; - } - $subChunks[$y] = new SubChunk($ids, $data, $skyLight, $blockLight); + $subChunks[$y] = new SubChunk($ids, $data); } if($chunk->hasTag("BiomeColors", IntArrayTag::class)){ @@ -149,23 +128,14 @@ class McRegion extends RegionLevelProvider{ $biomeIds = ""; } - $heightMap = []; - if($chunk->hasTag("HeightMap", ByteArrayTag::class)){ - $heightMap = array_values(unpack("C*", $chunk->getByteArray("HeightMap"))); - }elseif($chunk->hasTag("HeightMap", IntArrayTag::class)){ - $heightMap = $chunk->getIntArray("HeightMap"); #blameshoghicp - } - $result = new Chunk( $chunk->getInt("xPos"), $chunk->getInt("zPos"), $subChunks, $chunk->hasTag("Entities", ListTag::class) ? $chunk->getListTag("Entities")->getValue() : [], $chunk->hasTag("TileEntities", ListTag::class) ? $chunk->getListTag("TileEntities")->getValue() : [], - $biomeIds, - $heightMap + $biomeIds ); - $result->setLightPopulated($chunk->getByte("LightPopulated", 0) !== 0); $result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0); $result->setGenerated(true); return $result; diff --git a/src/pocketmine/level/format/io/region/PMAnvil.php b/src/pocketmine/level/format/io/region/PMAnvil.php index 84ab25ac7..566a5b82e 100644 --- a/src/pocketmine/level/format/io/region/PMAnvil.php +++ b/src/pocketmine/level/format/io/region/PMAnvil.php @@ -26,6 +26,7 @@ namespace pocketmine\level\format\io\region; use pocketmine\level\format\SubChunk; use pocketmine\nbt\tag\ByteArrayTag; use pocketmine\nbt\tag\CompoundTag; +use function str_repeat; /** * This format is exactly the same as the PC Anvil format, with the only difference being that the stored data order @@ -38,17 +39,15 @@ class PMAnvil extends RegionLevelProvider{ return new CompoundTag("", [ new ByteArrayTag("Blocks", $subChunk->getBlockIdArray()), new ByteArrayTag("Data", $subChunk->getBlockDataArray()), - new ByteArrayTag("SkyLight", $subChunk->getBlockSkyLightArray()), - new ByteArrayTag("BlockLight", $subChunk->getBlockLightArray()) + new ByteArrayTag("SkyLight", str_repeat("\x00", 2048)), + new ByteArrayTag("BlockLight", str_repeat("\x00", 2048)) ]); } protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{ return new SubChunk( $subChunk->getByteArray("Blocks"), - $subChunk->getByteArray("Data"), - $subChunk->getByteArray("SkyLight"), - $subChunk->getByteArray("BlockLight") + $subChunk->getByteArray("Data") ); }