mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-10 05:34:54 +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)]);
|
return isset($this->chunkLock[World::chunkHash($chunkX, $chunkZ)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
|
||||||
* @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{
|
|
||||||
$chunkHash = World::chunkHash($chunkX, $chunkZ);
|
$chunkHash = World::chunkHash($chunkX, $chunkZ);
|
||||||
$oldChunk = $this->loadChunk($chunkX, $chunkZ);
|
$oldChunk = $this->loadChunk($chunkX, $chunkZ);
|
||||||
if($oldChunk !== null and $oldChunk !== $chunk){
|
if($oldChunk !== null and $oldChunk !== $chunk){
|
||||||
if($deleteTiles){
|
$deletedTiles = 0;
|
||||||
foreach($oldChunk->getTiles() as $tile){
|
$transferredTiles = 0;
|
||||||
$tile->close();
|
foreach($oldChunk->getTiles() as $oldTile){
|
||||||
}
|
$tilePosition = $oldTile->getPosition();
|
||||||
}else{
|
$localX = $tilePosition->getFloorX() & Chunk::COORD_MASK;
|
||||||
foreach($oldChunk->getTiles() as $tile){
|
$localY = $tilePosition->getFloorY();
|
||||||
$chunk->addTile($tile);
|
$localZ = $tilePosition->getFloorZ() & Chunk::COORD_MASK;
|
||||||
$oldChunk->removeTile($tile);
|
|
||||||
|
$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;
|
$this->chunks[$chunkHash] = $chunk;
|
||||||
@ -2830,11 +2843,11 @@ class World implements ChunkManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$oldChunk = $this->loadChunk($x, $z);
|
$oldChunk = $this->loadChunk($x, $z);
|
||||||
$this->setChunk($x, $z, $chunk, false);
|
$this->setChunk($x, $z, $chunk);
|
||||||
|
|
||||||
foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){
|
foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){
|
||||||
World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk);
|
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()){
|
if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user