Clean up entity/tile data loading from world providers

This commit is contained in:
Dylan K. Taylor
2021-08-29 23:11:18 +01:00
parent 533b0d0724
commit 994a2c9eb9
12 changed files with 106 additions and 76 deletions

View File

@ -0,0 +1,48 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\format\io;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\world\format\Chunk;
final class ChunkData{
/**
* @param CompoundTag[] $entityNBT
* @param CompoundTag[] $tileNBT
*/
public function __construct(
private Chunk $chunk,
private array $entityNBT,
private array $tileNBT
){}
public function getChunk() : Chunk{ return $this->chunk; }
/** @return CompoundTag[] */
public function getEntityNBT() : array{ return $this->entityNBT; }
/** @return CompoundTag[] */
public function getTileNBT() : array{ return $this->tileNBT; }
}

View File

@ -143,7 +143,7 @@ final class FastChunkSerializer{
$heightMap = new HeightArray(array_values($unpackedHeightMap));
}
$chunk = new Chunk($subChunks, null, null, $biomeIds, $heightMap);
$chunk = new Chunk($subChunks, $biomeIds, $heightMap);
$chunk->setPopulated($terrainPopulated);
$chunk->setLightPopulated($lightPopulated);
$chunk->clearDirtyFlags();

View File

@ -149,7 +149,7 @@ class FormatConverter{
$thisRound = $start;
foreach($this->oldProvider->getAllChunks(true, $this->logger) as $coords => $chunk){
[$chunkX, $chunkZ] = $coords;
$chunk->setDirty();
$chunk->getChunk()->setDirty();
$new->saveChunk($chunkX, $chunkZ, $chunk);
$counter++;
if(($counter % $this->chunksPerProgressUpdate) === 0){

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\world\format\io;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\exception\CorruptedChunkException;
interface WorldProvider{
@ -44,7 +43,7 @@ interface WorldProvider{
*
* @throws CorruptedChunkException
*/
public function loadChunk(int $chunkX, int $chunkZ) : ?Chunk;
public function loadChunk(int $chunkX, int $chunkZ) : ?ChunkData;
/**
* Performs garbage collection in the world provider, such as cleaning up regions in Region-based worlds.
@ -64,8 +63,8 @@ interface WorldProvider{
/**
* Returns a generator which yields all the chunks in this world.
*
* @return \Generator|Chunk[]
* @phpstan-return \Generator<array{int, int}, Chunk, void, void>
* @return \Generator|ChunkData[]
* @phpstan-return \Generator<array{int, int}, ChunkData, void, void>
* @throws CorruptedChunkException
*/
public function getAllChunks(bool $skipCorrupted = false, ?\Logger $logger = null) : \Generator;

View File

@ -23,11 +23,9 @@ declare(strict_types=1);
namespace pocketmine\world\format\io;
use pocketmine\world\format\Chunk;
interface WritableWorldProvider extends WorldProvider{
/**
* Saves a chunk (usually to disk).
*/
public function saveChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void;
public function saveChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void;
}

View File

@ -36,6 +36,7 @@ use pocketmine\utils\BinaryStream;
use pocketmine\world\format\BiomeArray;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\BaseWorldProvider;
use pocketmine\world\format\io\ChunkData;
use pocketmine\world\format\io\ChunkUtils;
use pocketmine\world\format\io\data\BedrockWorldData;
use pocketmine\world\format\io\exception\CorruptedChunkException;
@ -232,7 +233,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
/**
* @throws CorruptedChunkException
*/
public function loadChunk(int $chunkX, int $chunkZ) : ?Chunk{
public function loadChunk(int $chunkX, int $chunkZ) : ?ChunkData{
$index = LevelDB::chunkIndex($chunkX, $chunkZ);
$chunkVersionRaw = $this->db->get($index . self::TAG_VERSION);
@ -405,8 +406,6 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$chunk = new Chunk(
$subChunks,
$entities,
$tiles,
$biomeArray
);
@ -423,16 +422,17 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$chunk->setDirty(); //trigger rewriting chunk to disk if it was converted from an older format
}
return $chunk;
return new ChunkData($chunk, $entities, $tiles);
}
public function saveChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
public function saveChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void{
$idMap = LegacyBlockIdToStringIdMap::getInstance();
$index = LevelDB::chunkIndex($chunkX, $chunkZ);
$write = new \LevelDBWriteBatch();
$write->put($index . self::TAG_VERSION, chr(self::CURRENT_LEVEL_CHUNK_VERSION));
$chunk = $chunkData->getChunk();
if($chunk->getDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN)){
$subChunks = $chunk->getSubChunks();
foreach($subChunks as $y => $subChunk){
@ -474,8 +474,8 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
//TODO: use this properly
$write->put($index . self::TAG_STATE_FINALISATION, chr($chunk->isPopulated() ? self::FINALISATION_DONE : self::FINALISATION_NEEDS_POPULATION));
$this->writeTags($chunk->getNBTtiles(), $index . self::TAG_BLOCK_ENTITY, $write);
$this->writeTags($chunk->getNBTentities(), $index . self::TAG_ENTITY, $write);
$this->writeTags($chunkData->getTileNBT(), $index . self::TAG_BLOCK_ENTITY, $write);
$this->writeTags($chunkData->getEntityNBT(), $index . self::TAG_ENTITY, $write);
$write->delete($index . self::TAG_DATA_2D_LEGACY);
$write->delete($index . self::TAG_LEGACY_TERRAIN);

View File

@ -31,6 +31,7 @@ use pocketmine\nbt\tag\IntArrayTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\world\format\BiomeArray;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\ChunkData;
use pocketmine\world\format\io\ChunkUtils;
use pocketmine\world\format\io\exception\CorruptedChunkException;
use pocketmine\world\format\SubChunk;
@ -49,7 +50,7 @@ trait LegacyAnvilChunkTrait{
/**
* @throws CorruptedChunkException
*/
protected function deserializeChunk(string $data) : Chunk{
protected function deserializeChunk(string $data) : ChunkData{
$decompressed = @zlib_decode($data);
if($decompressed === false){
throw new CorruptedChunkException("Failed to decompress chunk NBT");
@ -89,12 +90,14 @@ trait LegacyAnvilChunkTrait{
$result = new Chunk(
$subChunks,
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
$biomeArray
);
$result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0);
return $result;
return new ChunkData(
$result,
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
);
}
abstract protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk;

View File

@ -33,6 +33,7 @@ use pocketmine\nbt\tag\IntArrayTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\world\format\BiomeArray;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\ChunkData;
use pocketmine\world\format\io\ChunkUtils;
use pocketmine\world\format\io\exception\CorruptedChunkException;
use pocketmine\world\format\io\SubChunkConverter;
@ -43,7 +44,7 @@ class McRegion extends RegionWorldProvider{
/**
* @throws CorruptedChunkException
*/
protected function deserializeChunk(string $data) : Chunk{
protected function deserializeChunk(string $data) : ChunkData{
$decompressed = @zlib_decode($data);
if($decompressed === false){
throw new CorruptedChunkException("Failed to decompress chunk NBT");
@ -81,14 +82,13 @@ class McRegion extends RegionWorldProvider{
$biomeIds = $makeBiomeArray($biomesTag->getValue());
}
$result = new Chunk(
$subChunks,
$result = new Chunk($subChunks, $biomeIds);
$result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0);
return new ChunkData(
$result,
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
$biomeIds
);
$result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0);
return $result;
}
protected static function getRegionFileExtension() : string{

View File

@ -27,8 +27,8 @@ use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteArrayTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\BaseWorldProvider;
use pocketmine\world\format\io\ChunkData;
use pocketmine\world\format\io\data\JavaWorldData;
use pocketmine\world\format\io\exception\CorruptedChunkException;
use pocketmine\world\format\io\WorldData;
@ -146,7 +146,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
/**
* @throws CorruptedChunkException
*/
abstract protected function deserializeChunk(string $data) : Chunk;
abstract protected function deserializeChunk(string $data) : ChunkData;
/**
* @return CompoundTag[]
@ -185,7 +185,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
/**
* @throws CorruptedChunkException
*/
public function loadChunk(int $chunkX, int $chunkZ) : ?Chunk{
public function loadChunk(int $chunkX, int $chunkZ) : ?ChunkData{
$regionX = $regionZ = null;
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
assert(is_int($regionX) and is_int($regionZ));

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\world\format\io\region;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\ChunkData;
use pocketmine\world\format\io\data\JavaWorldData;
use pocketmine\world\format\io\WritableWorldProvider;
use pocketmine\world\WorldCreationOptions;
@ -51,10 +51,10 @@ abstract class WritableRegionWorldProvider extends RegionWorldProvider implement
JavaWorldData::generate($path, $name, $options, static::getPcWorldFormatVersion());
}
abstract protected function serializeChunk(Chunk $chunk) : string;
abstract protected function serializeChunk(ChunkData $chunk) : string;
public function saveChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
public function saveChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void{
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
$this->loadRegion($regionX, $regionZ)->writeChunk($chunkX & 0x1f, $chunkZ & 0x1f, $this->serializeChunk($chunk));
$this->loadRegion($regionX, $regionZ)->writeChunk($chunkX & 0x1f, $chunkZ & 0x1f, $this->serializeChunk($chunkData));
}
}