mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-01 23:59:53 +00:00
WorldProvider subsystem no longer depends on Chunk
Instead, it provides the data needed to construct the chunk, which doesn't require the provider to be aware of anywhere near as much logic.
This commit is contained in:
parent
d57954dff0
commit
a49842278a
@ -1400,10 +1400,11 @@ class World implements ChunkManager{
|
|||||||
foreach($this->chunks as $chunkHash => $chunk){
|
foreach($this->chunks as $chunkHash => $chunk){
|
||||||
self::getXZ($chunkHash, $chunkX, $chunkZ);
|
self::getXZ($chunkHash, $chunkX, $chunkZ);
|
||||||
$this->provider->saveChunk($chunkX, $chunkZ, new ChunkData(
|
$this->provider->saveChunk($chunkX, $chunkZ, new ChunkData(
|
||||||
$chunk,
|
$chunk->getSubChunks(),
|
||||||
|
$chunk->isPopulated(),
|
||||||
array_map(fn(Entity $e) => $e->saveNBT(), array_filter($this->getChunkEntities($chunkX, $chunkZ), fn(Entity $e) => $e->canSaveWithChunk())),
|
array_map(fn(Entity $e) => $e->saveNBT(), array_filter($this->getChunkEntities($chunkX, $chunkZ), fn(Entity $e) => $e->canSaveWithChunk())),
|
||||||
array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()),
|
array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()),
|
||||||
));
|
), $chunk->getTerrainDirtyFlags());
|
||||||
$chunk->clearTerrainDirtyFlags();
|
$chunk->clearTerrainDirtyFlags();
|
||||||
}
|
}
|
||||||
}finally{
|
}finally{
|
||||||
@ -2717,7 +2718,8 @@ class World implements ChunkManager{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$chunk = $loadedChunkData->getData()->getChunk();
|
$chunkData = $loadedChunkData->getData();
|
||||||
|
$chunk = new Chunk($chunkData->getSubChunks(), $chunkData->isPopulated());
|
||||||
if(!$loadedChunkData->isUpgraded()){
|
if(!$loadedChunkData->isUpgraded()){
|
||||||
$chunk->clearTerrainDirtyFlags();
|
$chunk->clearTerrainDirtyFlags();
|
||||||
}else{
|
}else{
|
||||||
@ -2726,7 +2728,7 @@ class World implements ChunkManager{
|
|||||||
$this->chunks[$chunkHash] = $chunk;
|
$this->chunks[$chunkHash] = $chunk;
|
||||||
unset($this->blockCache[$chunkHash]);
|
unset($this->blockCache[$chunkHash]);
|
||||||
|
|
||||||
$this->initChunk($x, $z, $loadedChunkData->getData());
|
$this->initChunk($x, $z, $chunkData);
|
||||||
|
|
||||||
(new ChunkLoadEvent($this, $x, $z, $this->chunks[$chunkHash], false))->call();
|
(new ChunkLoadEvent($this, $x, $z, $this->chunks[$chunkHash], false))->call();
|
||||||
|
|
||||||
@ -2853,10 +2855,11 @@ class World implements ChunkManager{
|
|||||||
$this->timings->syncChunkSave->startTiming();
|
$this->timings->syncChunkSave->startTiming();
|
||||||
try{
|
try{
|
||||||
$this->provider->saveChunk($x, $z, new ChunkData(
|
$this->provider->saveChunk($x, $z, new ChunkData(
|
||||||
$chunk,
|
$chunk->getSubChunks(),
|
||||||
|
$chunk->isPopulated(),
|
||||||
array_map(fn(Entity $e) => $e->saveNBT(), array_filter($this->getChunkEntities($x, $z), fn(Entity $e) => $e->canSaveWithChunk())),
|
array_map(fn(Entity $e) => $e->saveNBT(), array_filter($this->getChunkEntities($x, $z), fn(Entity $e) => $e->canSaveWithChunk())),
|
||||||
array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()),
|
array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()),
|
||||||
));
|
), $chunk->getTerrainDirtyFlags());
|
||||||
}finally{
|
}finally{
|
||||||
$this->timings->syncChunkSave->stopTiming();
|
$this->timings->syncChunkSave->stopTiming();
|
||||||
}
|
}
|
||||||
|
@ -24,21 +24,28 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\world\format\io;
|
namespace pocketmine\world\format\io;
|
||||||
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
use pocketmine\world\format\Chunk;
|
use pocketmine\world\format\SubChunk;
|
||||||
|
|
||||||
final class ChunkData{
|
final class ChunkData{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param SubChunk[] $subChunks
|
||||||
* @param CompoundTag[] $entityNBT
|
* @param CompoundTag[] $entityNBT
|
||||||
* @param CompoundTag[] $tileNBT
|
* @param CompoundTag[] $tileNBT
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private Chunk $chunk,
|
private array $subChunks,
|
||||||
|
private bool $populated,
|
||||||
private array $entityNBT,
|
private array $entityNBT,
|
||||||
private array $tileNBT
|
private array $tileNBT
|
||||||
){}
|
){}
|
||||||
|
|
||||||
public function getChunk() : Chunk{ return $this->chunk; }
|
/**
|
||||||
|
* @return SubChunk[]
|
||||||
|
*/
|
||||||
|
public function getSubChunks() : array{ return $this->subChunks; }
|
||||||
|
|
||||||
|
public function isPopulated() : bool{ return $this->populated; }
|
||||||
|
|
||||||
/** @return CompoundTag[] */
|
/** @return CompoundTag[] */
|
||||||
public function getEntityNBT() : array{ return $this->entityNBT; }
|
public function getEntityNBT() : array{ return $this->entityNBT; }
|
||||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\world\format\io;
|
namespace pocketmine\world\format\io;
|
||||||
|
|
||||||
use pocketmine\utils\Filesystem;
|
use pocketmine\utils\Filesystem;
|
||||||
|
use pocketmine\world\format\Chunk;
|
||||||
use pocketmine\world\generator\GeneratorManager;
|
use pocketmine\world\generator\GeneratorManager;
|
||||||
use pocketmine\world\generator\normal\Normal;
|
use pocketmine\world\generator\normal\Normal;
|
||||||
use pocketmine\world\WorldCreationOptions;
|
use pocketmine\world\WorldCreationOptions;
|
||||||
@ -142,9 +143,7 @@ class FormatConverter{
|
|||||||
$thisRound = $start;
|
$thisRound = $start;
|
||||||
foreach($this->oldProvider->getAllChunks(true, $this->logger) as $coords => $loadedChunkData){
|
foreach($this->oldProvider->getAllChunks(true, $this->logger) as $coords => $loadedChunkData){
|
||||||
[$chunkX, $chunkZ] = $coords;
|
[$chunkX, $chunkZ] = $coords;
|
||||||
$chunkData = $loadedChunkData->getData();
|
$new->saveChunk($chunkX, $chunkZ, $loadedChunkData->getData(), ~0);
|
||||||
$chunkData->getChunk()->setTerrainDirty();
|
|
||||||
$new->saveChunk($chunkX, $chunkZ, $chunkData);
|
|
||||||
$counter++;
|
$counter++;
|
||||||
if(($counter % $this->chunksPerProgressUpdate) === 0){
|
if(($counter % $this->chunksPerProgressUpdate) === 0){
|
||||||
$time = microtime(true);
|
$time = microtime(true);
|
||||||
|
@ -27,5 +27,5 @@ interface WritableWorldProvider extends WorldProvider{
|
|||||||
/**
|
/**
|
||||||
* Saves a chunk (usually to disk).
|
* Saves a chunk (usually to disk).
|
||||||
*/
|
*/
|
||||||
public function saveChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void;
|
public function saveChunk(int $chunkX, int $chunkZ, ChunkData $chunkData, int $dirtyFlags) : void;
|
||||||
}
|
}
|
||||||
|
@ -290,12 +290,15 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function serialize3dBiomes(BinaryStream $stream, Chunk $chunk) : void{
|
/**
|
||||||
|
* @param SubChunk[] $subChunks
|
||||||
|
*/
|
||||||
|
private static function serialize3dBiomes(BinaryStream $stream, array $subChunks) : void{
|
||||||
//TODO: the server-side min/max may not coincide with the world storage min/max - we may need additional logic to handle this
|
//TODO: the server-side min/max may not coincide with the world storage min/max - we may need additional logic to handle this
|
||||||
for($y = Chunk::MIN_SUBCHUNK_INDEX; $y <= Chunk::MAX_SUBCHUNK_INDEX; $y++){
|
for($y = Chunk::MIN_SUBCHUNK_INDEX; $y <= Chunk::MAX_SUBCHUNK_INDEX; $y++){
|
||||||
//TODO: is it worth trying to use the previous palette if it's the same as the current one? vanilla supports
|
//TODO: is it worth trying to use the previous palette if it's the same as the current one? vanilla supports
|
||||||
//this, but it's not clear if it's worth the effort to implement.
|
//this, but it's not clear if it's worth the effort to implement.
|
||||||
self::serializeBiomePalette($stream, $chunk->getSubChunk($y)->getBiomeArray());
|
self::serializeBiomePalette($stream, $subChunks[$y]->getBiomeArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,13 +699,13 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
//TODO: tile ticks, biome states (?)
|
//TODO: tile ticks, biome states (?)
|
||||||
|
|
||||||
return new LoadedChunkData(
|
return new LoadedChunkData(
|
||||||
data: new ChunkData(new Chunk($subChunks, $terrainPopulated), $entities, $tiles),
|
data: new ChunkData($subChunks, $terrainPopulated, $entities, $tiles),
|
||||||
upgraded: $hasBeenUpgraded,
|
upgraded: $hasBeenUpgraded,
|
||||||
fixerFlags: LoadedChunkData::FIXER_FLAG_ALL //TODO: fill this by version rather than just setting all flags
|
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{
|
public function saveChunk(int $chunkX, int $chunkZ, ChunkData $chunkData, int $dirtyFlags) : void{
|
||||||
$index = LevelDB::chunkIndex($chunkX, $chunkZ);
|
$index = LevelDB::chunkIndex($chunkX, $chunkZ);
|
||||||
|
|
||||||
$write = new \LevelDBWriteBatch();
|
$write = new \LevelDBWriteBatch();
|
||||||
@ -710,10 +713,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
$write->put($index . ChunkDataKey::NEW_VERSION, chr(self::CURRENT_LEVEL_CHUNK_VERSION));
|
$write->put($index . ChunkDataKey::NEW_VERSION, chr(self::CURRENT_LEVEL_CHUNK_VERSION));
|
||||||
$write->put($index . ChunkDataKey::PM_DATA_VERSION, Binary::writeLLong(VersionInfo::WORLD_DATA_VERSION));
|
$write->put($index . ChunkDataKey::PM_DATA_VERSION, Binary::writeLLong(VersionInfo::WORLD_DATA_VERSION));
|
||||||
|
|
||||||
$chunk = $chunkData->getChunk();
|
$subChunks = $chunkData->getSubChunks();
|
||||||
|
|
||||||
if($chunk->getTerrainDirtyFlag(Chunk::DIRTY_FLAG_BLOCKS)){
|
if(($dirtyFlags & Chunk::DIRTY_FLAG_BLOCKS) !== 0){
|
||||||
$subChunks = $chunk->getSubChunks();
|
|
||||||
|
|
||||||
foreach($subChunks as $y => $subChunk){
|
foreach($subChunks as $y => $subChunk){
|
||||||
$key = $index . ChunkDataKey::SUBCHUNK . chr($y);
|
$key = $index . ChunkDataKey::SUBCHUNK . chr($y);
|
||||||
@ -734,16 +736,16 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($chunk->getTerrainDirtyFlag(Chunk::DIRTY_FLAG_BIOMES)){
|
if(($dirtyFlags & Chunk::DIRTY_FLAG_BIOMES) !== 0){
|
||||||
$write->delete($index . ChunkDataKey::HEIGHTMAP_AND_2D_BIOMES);
|
$write->delete($index . ChunkDataKey::HEIGHTMAP_AND_2D_BIOMES);
|
||||||
$stream = new BinaryStream();
|
$stream = new BinaryStream();
|
||||||
$stream->put(str_repeat("\x00", 512)); //fake heightmap
|
$stream->put(str_repeat("\x00", 512)); //fake heightmap
|
||||||
self::serialize3dBiomes($stream, $chunk);
|
self::serialize3dBiomes($stream, $subChunks);
|
||||||
$write->put($index . ChunkDataKey::HEIGHTMAP_AND_3D_BIOMES, $stream->getBuffer());
|
$write->put($index . ChunkDataKey::HEIGHTMAP_AND_3D_BIOMES, $stream->getBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: use this properly
|
//TODO: use this properly
|
||||||
$write->put($index . ChunkDataKey::FINALIZATION, chr($chunk->isPopulated() ? self::FINALISATION_DONE : self::FINALISATION_NEEDS_POPULATION));
|
$write->put($index . ChunkDataKey::FINALIZATION, chr($chunkData->isPopulated() ? self::FINALISATION_DONE : self::FINALISATION_NEEDS_POPULATION));
|
||||||
|
|
||||||
$this->writeTags($chunkData->getTileNBT(), $index . ChunkDataKey::BLOCK_ENTITIES, $write);
|
$this->writeTags($chunkData->getTileNBT(), $index . ChunkDataKey::BLOCK_ENTITIES, $write);
|
||||||
$this->writeTags($chunkData->getEntityNBT(), $index . ChunkDataKey::ENTITIES, $write);
|
$this->writeTags($chunkData->getEntityNBT(), $index . ChunkDataKey::ENTITIES, $write);
|
||||||
|
@ -102,10 +102,8 @@ trait LegacyAnvilChunkTrait{
|
|||||||
|
|
||||||
return new LoadedChunkData(
|
return new LoadedChunkData(
|
||||||
data: new ChunkData(
|
data: new ChunkData(
|
||||||
new Chunk(
|
|
||||||
$subChunks,
|
$subChunks,
|
||||||
$chunk->getByte("TerrainPopulated", 0) !== 0
|
$chunk->getByte("TerrainPopulated", 0) !== 0,
|
||||||
),
|
|
||||||
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
|
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
|
||||||
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
|
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
|
||||||
),
|
),
|
||||||
|
@ -101,10 +101,8 @@ class McRegion extends RegionWorldProvider{
|
|||||||
|
|
||||||
return new LoadedChunkData(
|
return new LoadedChunkData(
|
||||||
data: new ChunkData(
|
data: new ChunkData(
|
||||||
new Chunk(
|
|
||||||
$subChunks,
|
$subChunks,
|
||||||
$chunk->getByte("TerrainPopulated", 0) !== 0
|
$chunk->getByte("TerrainPopulated", 0) !== 0,
|
||||||
),
|
|
||||||
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
|
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
|
||||||
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
|
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],
|
||||||
),
|
),
|
||||||
|
@ -53,7 +53,7 @@ abstract class WritableRegionWorldProvider extends RegionWorldProvider implement
|
|||||||
|
|
||||||
abstract protected function serializeChunk(ChunkData $chunk) : string;
|
abstract protected function serializeChunk(ChunkData $chunk) : string;
|
||||||
|
|
||||||
public function saveChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void{
|
public function saveChunk(int $chunkX, int $chunkZ, ChunkData $chunkData, int $dirtyFlags) : void{
|
||||||
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
|
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
|
||||||
$this->loadRegion($regionX, $regionZ)->writeChunk($chunkX & 0x1f, $chunkZ & 0x1f, $this->serializeChunk($chunkData));
|
$this->loadRegion($regionX, $regionZ)->writeChunk($chunkX & 0x1f, $chunkZ & 0x1f, $this->serializeChunk($chunkData));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user