From d04991feb69793b918938d66541ebbd7d9772650 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Jun 2018 11:25:45 +0100 Subject: [PATCH] Level: Avoid chunk sending bugs caused by duplicate chunks with wrong coordinates If the same chunk is set into multiple different places in the world, the chunk's position is no longer able to be relied on, because it will have the position of the last place it was set. This results in chunks not getting sent correctly when the same chunk is set in multiple places. This avoids the bug by using known valid coordinates (using chunk hashes) to establish the real coordinates, and also adds an assert to notify developers should they unintentionally set a duplicate chunk by mistake. --- src/pocketmine/level/Level.php | 3 ++- src/pocketmine/level/format/io/ChunkRequestTask.php | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 01a57634a..a7284afaa 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -2487,8 +2487,9 @@ class Level implements ChunkManager, Metadatable{ if(!($chunk instanceof Chunk)){ throw new ChunkException("Invalid Chunk sent"); } + assert($chunk->getX() === $x and $chunk->getZ() === $z, "Chunk coordinate mismatch: expected $x $z, but chunk has coordinates " . $chunk->getX() . " " . $chunk->getZ() . ", did you forget to clone a chunk before setting?"); - $this->server->getAsyncPool()->submitTask(new ChunkRequestTask($this, $chunk)); + $this->server->getAsyncPool()->submitTask(new ChunkRequestTask($this, $x, $z, $chunk)); $this->timings->syncChunkSendPrepareTimer->stopTiming(); } diff --git a/src/pocketmine/level/format/io/ChunkRequestTask.php b/src/pocketmine/level/format/io/ChunkRequestTask.php index 3effbd0e0..834e5d61f 100644 --- a/src/pocketmine/level/format/io/ChunkRequestTask.php +++ b/src/pocketmine/level/format/io/ChunkRequestTask.php @@ -43,13 +43,13 @@ class ChunkRequestTask extends AsyncTask{ protected $compressionLevel; - public function __construct(Level $level, Chunk $chunk){ + public function __construct(Level $level, int $chunkX, int $chunkZ, Chunk $chunk){ $this->levelId = $level->getId(); $this->compressionLevel = $level->getServer()->networkCompressionLevel; $this->chunk = $chunk->fastSerialize(); - $this->chunkX = $chunk->getX(); - $this->chunkZ = $chunk->getZ(); + $this->chunkX = $chunkX; + $this->chunkZ = $chunkZ; //TODO: serialize tiles with chunks $tiles = "";