mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-22 00:33:59 +00:00
Chunk: Drop dirty flags for tiles and entities
instead, just ungate this and allow the provider to decide what to do. Any chunk that contains entities or tiles is already always considered dirty, so the only thing the flags are good for is flagging chunks that previously had tiles and/or entities but no longer do. In those cases, it's just removing keys from LevelDB anyway, so it's already very cheap. Avoiding these redundant deletions is not worth the extra complexity and fragility of relying on flags to track this stuff.
This commit is contained in:
parent
4b06e19d28
commit
0289b45202
@ -1126,15 +1126,13 @@ class World implements ChunkManager{
|
||||
$this->timings->syncChunkSave->startTiming();
|
||||
try{
|
||||
foreach($this->chunks as $chunkHash => $chunk){
|
||||
if($chunk->isDirty()){
|
||||
self::getXZ($chunkHash, $chunkX, $chunkZ);
|
||||
$this->provider->saveChunk($chunkX, $chunkZ, new ChunkData(
|
||||
$chunk,
|
||||
array_map(fn(Entity $e) => $e->saveNBT(), $chunk->getSavableEntities()),
|
||||
array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()),
|
||||
));
|
||||
$chunk->clearDirtyFlags();
|
||||
}
|
||||
self::getXZ($chunkHash, $chunkX, $chunkZ);
|
||||
$this->provider->saveChunk($chunkX, $chunkZ, new ChunkData(
|
||||
$chunk,
|
||||
array_map(fn(Entity $e) => $e->saveNBT(), $chunk->getSavableEntities()),
|
||||
array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()),
|
||||
));
|
||||
$chunk->clearTerrainDirtyFlags();
|
||||
}
|
||||
}finally{
|
||||
$this->timings->syncChunkSave->stopTiming();
|
||||
@ -2186,7 +2184,7 @@ class World implements ChunkManager{
|
||||
|
||||
unset($this->blockCache[$chunkHash]);
|
||||
unset($this->changedBlocks[$chunkHash]);
|
||||
$chunk->setDirty();
|
||||
$chunk->setTerrainDirty();
|
||||
|
||||
if(!$this->isChunkInUse($chunkX, $chunkZ)){
|
||||
$this->unloadChunkRequest($chunkX, $chunkZ);
|
||||
@ -2494,7 +2492,6 @@ class World implements ChunkManager{
|
||||
//here, because entities currently add themselves to the world
|
||||
}
|
||||
|
||||
$this->getChunk($chunkX, $chunkZ)?->setDirtyFlag(Chunk::DIRTY_FLAG_ENTITIES, true);
|
||||
$this->timings->syncChunkLoadEntities->stopTiming();
|
||||
}
|
||||
|
||||
@ -2518,7 +2515,6 @@ class World implements ChunkManager{
|
||||
}
|
||||
}
|
||||
|
||||
$this->getChunk($chunkX, $chunkZ)?->setDirtyFlag(Chunk::DIRTY_FLAG_TILES, true);
|
||||
$this->timings->syncChunkLoadTileEntities->stopTiming();
|
||||
}
|
||||
}
|
||||
@ -2565,7 +2561,7 @@ class World implements ChunkManager{
|
||||
return false;
|
||||
}
|
||||
|
||||
if($trySave and $this->getAutoSave() and $chunk->isDirty()){
|
||||
if($trySave and $this->getAutoSave()){
|
||||
$this->timings->syncChunkSave->startTiming();
|
||||
try{
|
||||
$this->provider->saveChunk($x, $z, new ChunkData(
|
||||
|
@ -35,18 +35,15 @@ use pocketmine\player\Player;
|
||||
use function array_fill;
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function count;
|
||||
|
||||
class Chunk{
|
||||
public const DIRTY_FLAG_TERRAIN = 1 << 0;
|
||||
public const DIRTY_FLAG_ENTITIES = 1 << 1;
|
||||
public const DIRTY_FLAG_TILES = 1 << 2;
|
||||
public const DIRTY_FLAG_BIOMES = 1 << 3;
|
||||
|
||||
public const MAX_SUBCHUNKS = 16;
|
||||
|
||||
/** @var int */
|
||||
private $dirtyFlags = 0;
|
||||
private $terrainDirtyFlags = 0;
|
||||
|
||||
/** @var bool|null */
|
||||
protected $lightPopulated = false;
|
||||
@ -111,7 +108,7 @@ class Chunk{
|
||||
*/
|
||||
public function setFullBlock(int $x, int $y, int $z, int $block) : void{
|
||||
$this->getSubChunk($y >> 4)->setFullBlock($x, $y & 0xf, $z, $block);
|
||||
$this->dirtyFlags |= self::DIRTY_FLAG_TERRAIN;
|
||||
$this->terrainDirtyFlags |= self::DIRTY_FLAG_TERRAIN;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,7 +171,7 @@ class Chunk{
|
||||
*/
|
||||
public function setBiomeId(int $x, int $z, int $biomeId) : void{
|
||||
$this->biomeIds->set($x, $z, $biomeId);
|
||||
$this->dirtyFlags |= self::DIRTY_FLAG_BIOMES;
|
||||
$this->terrainDirtyFlags |= self::DIRTY_FLAG_BIOMES;
|
||||
}
|
||||
|
||||
public function isLightPopulated() : ?bool{
|
||||
@ -191,7 +188,7 @@ class Chunk{
|
||||
|
||||
public function setPopulated(bool $value = true) : void{
|
||||
$this->terrainPopulated = $value;
|
||||
$this->dirtyFlags |= self::DIRTY_FLAG_TERRAIN;
|
||||
$this->terrainDirtyFlags |= self::DIRTY_FLAG_TERRAIN;
|
||||
}
|
||||
|
||||
public function addEntity(Entity $entity) : void{
|
||||
@ -199,16 +196,10 @@ class Chunk{
|
||||
throw new \InvalidArgumentException("Attempted to add a garbage closed Entity to a chunk");
|
||||
}
|
||||
$this->entities[$entity->getId()] = $entity;
|
||||
if(!($entity instanceof Player)){
|
||||
$this->dirtyFlags |= self::DIRTY_FLAG_ENTITIES;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeEntity(Entity $entity) : void{
|
||||
unset($this->entities[$entity->getId()]);
|
||||
if(!($entity instanceof Player)){
|
||||
$this->dirtyFlags |= self::DIRTY_FLAG_ENTITIES;
|
||||
}
|
||||
}
|
||||
|
||||
public function addTile(Tile $tile) : void{
|
||||
@ -221,13 +212,11 @@ class Chunk{
|
||||
throw new \InvalidArgumentException("Another tile is already at this location");
|
||||
}
|
||||
$this->tiles[$index] = $tile;
|
||||
$this->dirtyFlags |= self::DIRTY_FLAG_TILES;
|
||||
}
|
||||
|
||||
public function removeTile(Tile $tile) : void{
|
||||
$pos = $tile->getPosition();
|
||||
unset($this->tiles[Chunk::blockHash($pos->x, $pos->y, $pos->z)]);
|
||||
$this->dirtyFlags |= self::DIRTY_FLAG_TILES;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -298,32 +287,32 @@ class Chunk{
|
||||
$this->heightMap = new HeightArray($values);
|
||||
}
|
||||
|
||||
public function isDirty() : bool{
|
||||
return $this->dirtyFlags !== 0 or count($this->tiles) > 0 or count($this->getSavableEntities()) > 0;
|
||||
public function isTerrainDirty() : bool{
|
||||
return $this->terrainDirtyFlags !== 0;
|
||||
}
|
||||
|
||||
public function getDirtyFlag(int $flag) : bool{
|
||||
return ($this->dirtyFlags & $flag) !== 0;
|
||||
public function getTerrainDirtyFlag(int $flag) : bool{
|
||||
return ($this->terrainDirtyFlags & $flag) !== 0;
|
||||
}
|
||||
|
||||
public function getDirtyFlags() : int{
|
||||
return $this->dirtyFlags;
|
||||
public function getTerrainDirtyFlags() : int{
|
||||
return $this->terrainDirtyFlags;
|
||||
}
|
||||
|
||||
public function setDirtyFlag(int $flag, bool $value) : void{
|
||||
public function setTerrainDirtyFlag(int $flag, bool $value) : void{
|
||||
if($value){
|
||||
$this->dirtyFlags |= $flag;
|
||||
$this->terrainDirtyFlags |= $flag;
|
||||
}else{
|
||||
$this->dirtyFlags &= ~$flag;
|
||||
$this->terrainDirtyFlags &= ~$flag;
|
||||
}
|
||||
}
|
||||
|
||||
public function setDirty() : void{
|
||||
$this->dirtyFlags = ~0;
|
||||
public function setTerrainDirty() : void{
|
||||
$this->terrainDirtyFlags = ~0;
|
||||
}
|
||||
|
||||
public function clearDirtyFlags() : void{
|
||||
$this->dirtyFlags = 0;
|
||||
public function clearTerrainDirtyFlags() : void{
|
||||
$this->terrainDirtyFlags = 0;
|
||||
}
|
||||
|
||||
public function getSubChunk(int $y) : SubChunk{
|
||||
@ -342,7 +331,7 @@ class Chunk{
|
||||
}
|
||||
|
||||
$this->subChunks[$y] = $subChunk ?? new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, []);
|
||||
$this->setDirtyFlag(self::DIRTY_FLAG_TERRAIN, true);
|
||||
$this->setTerrainDirtyFlag(self::DIRTY_FLAG_TERRAIN, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,7 +146,7 @@ final class FastChunkSerializer{
|
||||
$chunk = new Chunk($subChunks, $biomeIds, $heightMap);
|
||||
$chunk->setPopulated($terrainPopulated);
|
||||
$chunk->setLightPopulated($lightPopulated);
|
||||
$chunk->clearDirtyFlags();
|
||||
$chunk->clearTerrainDirtyFlags();
|
||||
|
||||
return $chunk;
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ class FormatConverter{
|
||||
$thisRound = $start;
|
||||
foreach($this->oldProvider->getAllChunks(true, $this->logger) as $coords => $chunk){
|
||||
[$chunkX, $chunkZ] = $coords;
|
||||
$chunk->getChunk()->setDirty();
|
||||
$chunk->getChunk()->setTerrainDirty();
|
||||
$new->saveChunk($chunkX, $chunkZ, $chunk);
|
||||
$counter++;
|
||||
if(($counter % $this->chunksPerProgressUpdate) === 0){
|
||||
|
@ -419,7 +419,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
||||
$chunk->setPopulated();
|
||||
}
|
||||
if($hasBeenUpgraded){
|
||||
$chunk->setDirty(); //trigger rewriting chunk to disk if it was converted from an older format
|
||||
$chunk->setTerrainDirty(); //trigger rewriting chunk to disk if it was converted from an older format
|
||||
}
|
||||
|
||||
return new ChunkData($chunk, $entities, $tiles);
|
||||
@ -433,7 +433,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
||||
$write->put($index . self::TAG_VERSION, chr(self::CURRENT_LEVEL_CHUNK_VERSION));
|
||||
|
||||
$chunk = $chunkData->getChunk();
|
||||
if($chunk->getDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN)){
|
||||
if($chunk->getTerrainDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN)){
|
||||
$subChunks = $chunk->getSubChunks();
|
||||
foreach($subChunks as $y => $subChunk){
|
||||
$key = $index . self::TAG_SUBCHUNK_PREFIX . chr($y);
|
||||
@ -467,7 +467,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
||||
}
|
||||
}
|
||||
|
||||
if($chunk->getDirtyFlag(Chunk::DIRTY_FLAG_BIOMES)){
|
||||
if($chunk->getTerrainDirtyFlag(Chunk::DIRTY_FLAG_BIOMES)){
|
||||
$write->put($index . self::TAG_DATA_2D, str_repeat("\x00", 512) . $chunk->getBiomeIdArray());
|
||||
}
|
||||
|
||||
|
@ -106,8 +106,8 @@ class PopulationTask extends AsyncTask{
|
||||
if($chunk === null){
|
||||
$generator->generateChunk($manager, $this->chunkX, $this->chunkZ);
|
||||
$chunk = $manager->getChunk($this->chunkX, $this->chunkZ);
|
||||
$chunk->setDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN, true);
|
||||
$chunk->setDirtyFlag(Chunk::DIRTY_FLAG_BIOMES, true);
|
||||
$chunk->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN, true);
|
||||
$chunk->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_BIOMES, true);
|
||||
}
|
||||
|
||||
foreach($chunks as $i => $c){
|
||||
@ -117,8 +117,8 @@ class PopulationTask extends AsyncTask{
|
||||
if($c === null){
|
||||
$generator->generateChunk($manager, $cX, $cZ);
|
||||
$chunks[$i] = $manager->getChunk($cX, $cZ);
|
||||
$chunks[$i]->setDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN, true);
|
||||
$chunks[$i]->setDirtyFlag(Chunk::DIRTY_FLAG_BIOMES, true);
|
||||
$chunks[$i]->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN, true);
|
||||
$chunks[$i]->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_BIOMES, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +129,7 @@ class PopulationTask extends AsyncTask{
|
||||
$this->chunk = FastChunkSerializer::serializeWithoutLight($chunk);
|
||||
|
||||
foreach($chunks as $i => $c){
|
||||
$this->{"chunk$i"} = $c->isDirty() ? FastChunkSerializer::serializeWithoutLight($c) : null;
|
||||
$this->{"chunk$i"} = $c->isTerrainDirty() ? FastChunkSerializer::serializeWithoutLight($c) : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user