mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-22 16:51:42 +00:00
World: Intelligently perform automatic transfer or deletion of tiles in setChunk(), depending on the context
tiles may be deleted in the following circumstances: 1) the target block in the new chunk doesn't expect a tile 2) the target block in the new chunk expects a different type of tile (responsibility of the plugin developer to create the new tile) 3) there's already a tile in the target chunk which conflicts with the old one In all other cases, the tile will be transferred. This resolves a large number of unintentional bugs caused by world editors replacing chunks without setting the deleteTilesAndEntities parameter to false (even the core itself does it). closes #4520
This commit is contained in:
parent
c66790b6a6
commit
eb75df6f8e
@ -2124,23 +2124,36 @@ class World implements ChunkManager{
|
||||
return isset($this->chunkLock[World::chunkHash($chunkX, $chunkZ)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $deleteTiles Whether to delete tiles on the old chunk, or transfer them to the new one
|
||||
*/
|
||||
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk, bool $deleteTiles = true) : void{
|
||||
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
|
||||
$chunkHash = World::chunkHash($chunkX, $chunkZ);
|
||||
$oldChunk = $this->loadChunk($chunkX, $chunkZ);
|
||||
if($oldChunk !== null and $oldChunk !== $chunk){
|
||||
if($deleteTiles){
|
||||
foreach($oldChunk->getTiles() as $tile){
|
||||
$tile->close();
|
||||
}
|
||||
}else{
|
||||
foreach($oldChunk->getTiles() as $tile){
|
||||
$chunk->addTile($tile);
|
||||
$oldChunk->removeTile($tile);
|
||||
$deletedTiles = 0;
|
||||
$transferredTiles = 0;
|
||||
foreach($oldChunk->getTiles() as $oldTile){
|
||||
$tilePosition = $oldTile->getPosition();
|
||||
$localX = $tilePosition->getFloorX() & Chunk::COORD_MASK;
|
||||
$localY = $tilePosition->getFloorY();
|
||||
$localZ = $tilePosition->getFloorZ() & Chunk::COORD_MASK;
|
||||
|
||||
$newBlock = BlockFactory::getInstance()->fromFullBlock($chunk->getFullBlock($localX, $localY, $localZ));
|
||||
$expectedTileClass = $newBlock->getIdInfo()->getTileClass();
|
||||
if(
|
||||
$expectedTileClass === null || //new block doesn't expect a tile
|
||||
!($oldTile instanceof $expectedTileClass) || //new block expects a different tile
|
||||
(($newTile = $chunk->getTile($localX, $localY, $localZ)) !== null && $newTile !== $oldTile) //new chunk already has a different tile
|
||||
){
|
||||
$oldTile->close();
|
||||
$deletedTiles++;
|
||||
}else{
|
||||
$transferredTiles++;
|
||||
$chunk->addTile($oldTile);
|
||||
$oldChunk->removeTile($oldTile);
|
||||
}
|
||||
}
|
||||
if($deletedTiles > 0 || $transferredTiles > 0){
|
||||
$this->logger->debug("Replacement of chunk $chunkX $chunkZ caused deletion of $deletedTiles obsolete/conflicted tiles, and transfer of $transferredTiles");
|
||||
}
|
||||
}
|
||||
|
||||
$this->chunks[$chunkHash] = $chunk;
|
||||
@ -2830,11 +2843,11 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
$oldChunk = $this->loadChunk($x, $z);
|
||||
$this->setChunk($x, $z, $chunk, false);
|
||||
$this->setChunk($x, $z, $chunk);
|
||||
|
||||
foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){
|
||||
World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk);
|
||||
$this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk, false);
|
||||
$this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk);
|
||||
}
|
||||
|
||||
if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){
|
||||
|
Loading…
x
Reference in New Issue
Block a user