WorldProvider: allow loadChunk() to return additional information about the loaded chunk data

this will be needed for dealing with #5733. I don't plan to fix that before 5.0, but we need to make the appropriate BC breaks now, before release.
This commit is contained in:
Dylan K. Taylor 2023-05-29 17:03:39 +01:00
parent f5a1a0c9cb
commit c10be0f346
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
8 changed files with 91 additions and 30 deletions

View File

@ -2702,25 +2702,25 @@ class World implements ChunkManager{
$this->timings->syncChunkLoadData->startTiming();
$chunk = null;
$loadedChunkData = null;
try{
$chunk = $this->provider->loadChunk($x, $z);
$loadedChunkData = $this->provider->loadChunk($x, $z);
}catch(CorruptedChunkException $e){
$this->logger->critical("Failed to load chunk x=$x z=$z: " . $e->getMessage());
}
$this->timings->syncChunkLoadData->stopTiming();
if($chunk === null){
if($loadedChunkData === null){
$this->timings->syncChunkLoad->stopTiming();
return null;
}
$this->chunks[$chunkHash] = $chunk->getChunk();
$this->chunks[$chunkHash] = $loadedChunkData->getData()->getChunk();
unset($this->blockCache[$chunkHash]);
$this->initChunk($x, $z, $chunk);
$this->initChunk($x, $z, $loadedChunkData->getData());
(new ChunkLoadEvent($this, $x, $z, $this->chunks[$chunkHash], false))->call();

View File

@ -140,10 +140,11 @@ class FormatConverter{
$start = microtime(true);
$thisRound = $start;
foreach($this->oldProvider->getAllChunks(true, $this->logger) as $coords => $chunk){
foreach($this->oldProvider->getAllChunks(true, $this->logger) as $coords => $loadedChunkData){
[$chunkX, $chunkZ] = $coords;
$chunk->getChunk()->setTerrainDirty();
$new->saveChunk($chunkX, $chunkZ, $chunk);
$chunkData = $loadedChunkData->getData();
$chunkData->getChunk()->setTerrainDirty();
$new->saveChunk($chunkX, $chunkZ, $chunkData);
$counter++;
if(($counter % $this->chunksPerProgressUpdate) === 0){
$time = microtime(true);

View File

@ -0,0 +1,45 @@
<?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;
/**
* Encapsulates information returned when loading a chunk. This includes more information than saving a chunk, since the
* data might have been upgraded or need post-processing.
*/
final class LoadedChunkData{
public const FIXER_FLAG_NONE = 0;
public const FIXER_FLAG_ALL = ~0;
public function __construct(
private ChunkData $data,
private bool $upgraded,
private int $fixerFlags
){}
public function getData() : ChunkData{ return $this->data; }
public function isUpgraded() : bool{ return $this->upgraded; }
public function getFixerFlags() : int{ return $this->fixerFlags; }
}

View File

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

View File

@ -44,6 +44,7 @@ use pocketmine\world\format\io\exception\CorruptedChunkException;
use pocketmine\world\format\io\exception\CorruptedWorldException;
use pocketmine\world\format\io\exception\UnsupportedWorldFormatException;
use pocketmine\world\format\io\GlobalBlockStateHandlers;
use pocketmine\world\format\io\LoadedChunkData;
use pocketmine\world\format\io\WorldData;
use pocketmine\world\format\io\WritableWorldProvider;
use pocketmine\world\format\PalettedBlockArray;
@ -593,7 +594,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
/**
* @throws CorruptedChunkException
*/
public function loadChunk(int $chunkX, int $chunkZ) : ?ChunkData{
public function loadChunk(int $chunkX, int $chunkZ) : ?LoadedChunkData{
$index = LevelDB::chunkIndex($chunkX, $chunkZ);
$chunkVersion = $this->readVersion($chunkX, $chunkZ);
@ -704,7 +705,11 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$chunk->setTerrainDirty(); //trigger rewriting chunk to disk if it was converted from an older format
}
return new ChunkData($chunk, $entities, $tiles);
return new LoadedChunkData(
data: new ChunkData($chunk, $entities, $tiles),
upgraded: $hasBeenUpgraded,
fixerFlags: LoadedChunkData::FIXER_FLAG_ALL //TODO: fill this by version rather than just setting all flags
);
}
public function saveChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void{

View File

@ -36,6 +36,7 @@ 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\LoadedChunkData;
use pocketmine\world\format\PalettedBlockArray;
use pocketmine\world\format\SubChunk;
use function strlen;
@ -54,7 +55,7 @@ trait LegacyAnvilChunkTrait{
/**
* @throws CorruptedChunkException
*/
protected function deserializeChunk(string $data) : ?ChunkData{
protected function deserializeChunk(string $data) : ?LoadedChunkData{
$decompressed = @zlib_decode($data);
if($decompressed === false){
throw new CorruptedChunkException("Failed to decompress chunk NBT");
@ -99,13 +100,17 @@ trait LegacyAnvilChunkTrait{
}
}
return new ChunkData(
new Chunk(
$subChunks,
$chunk->getByte("TerrainPopulated", 0) !== 0
return new LoadedChunkData(
data: new ChunkData(
new Chunk(
$subChunks,
$chunk->getByte("TerrainPopulated", 0) !== 0
),
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
),
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
upgraded: true,
fixerFlags: LoadedChunkData::FIXER_FLAG_ALL
);
}

View File

@ -37,6 +37,7 @@ 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\LoadedChunkData;
use pocketmine\world\format\PalettedBlockArray;
use pocketmine\world\format\SubChunk;
use function strlen;
@ -46,7 +47,7 @@ class McRegion extends RegionWorldProvider{
/**
* @throws CorruptedChunkException
*/
protected function deserializeChunk(string $data) : ?ChunkData{
protected function deserializeChunk(string $data) : ?LoadedChunkData{
$decompressed = @zlib_decode($data);
if($decompressed === false){
throw new CorruptedChunkException("Failed to decompress chunk NBT");
@ -98,13 +99,17 @@ class McRegion extends RegionWorldProvider{
}
}
return new ChunkData(
new Chunk(
$subChunks,
$chunk->getByte("TerrainPopulated", 0) !== 0
return new LoadedChunkData(
data: new ChunkData(
new Chunk(
$subChunks,
$chunk->getByte("TerrainPopulated", 0) !== 0
),
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
),
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
upgraded: true,
fixerFlags: LoadedChunkData::FIXER_FLAG_ALL
);
}

View File

@ -28,9 +28,9 @@ use pocketmine\nbt\tag\ByteArrayTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
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\LoadedChunkData;
use pocketmine\world\format\io\WorldData;
use Symfony\Component\Filesystem\Path;
use function assert;
@ -147,7 +147,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
/**
* @throws CorruptedChunkException
*/
abstract protected function deserializeChunk(string $data) : ?ChunkData;
abstract protected function deserializeChunk(string $data) : ?LoadedChunkData;
/**
* @return CompoundTag[]
@ -189,7 +189,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
/**
* @throws CorruptedChunkException
*/
public function loadChunk(int $chunkX, int $chunkZ) : ?ChunkData{
public function loadChunk(int $chunkX, int $chunkZ) : ?LoadedChunkData{
$regionX = $regionZ = null;
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
assert(is_int($regionX) && is_int($regionZ));