From 60f5c7ccefa2aba8e172902e5097eee61d2d37a7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 18 May 2017 12:19:27 +0100 Subject: [PATCH] Async chunk compression and serialization is now non-optional --- src/pocketmine/Player.php | 13 +++------- src/pocketmine/level/Level.php | 26 ++----------------- .../level/format/io/BaseLevelProvider.php | 15 +++-------- .../level/format/io/ChunkRequestTask.php | 16 ++++++++++-- .../level/format/io/LevelProvider.php | 5 ++-- src/pocketmine/resources/pocketmine.yml | 2 -- 6 files changed, 25 insertions(+), 52 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 10cc7b3ff..f164817fe 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -112,6 +112,7 @@ use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\AdventureSettingsPacket; use pocketmine\network\mcpe\protocol\AnimatePacket; use pocketmine\network\mcpe\protocol\AvailableCommandsPacket; +use pocketmine\network\mcpe\protocol\BatchPacket; use pocketmine\network\mcpe\protocol\BlockEntityDataPacket; use pocketmine\network\mcpe\protocol\BlockEventPacket; use pocketmine\network\mcpe\protocol\BlockPickRequestPacket; @@ -803,7 +804,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return $this->spawnPosition instanceof WeakPosition and $this->spawnPosition->isValid(); } - public function sendChunk($x, $z, $payload){ + public function sendChunk(int $x, int $z, BatchPacket $payload){ if($this->connected === false){ return; } @@ -811,15 +812,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->usedChunks[Level::chunkHash($x, $z)] = true; $this->chunkLoadCount++; - if($payload instanceof DataPacket){ - $this->dataPacket($payload); - }else{ - $pk = new FullChunkDataPacket(); - $pk->chunkX = $x; - $pk->chunkZ = $z; - $pk->data = $payload; - $this->batchDataPacket($pk); - } + $this->dataPacket($payload); if($this->spawned){ foreach($this->level->getChunkEntities($x, $z) as $entity){ diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 1f9aea008..845362a06 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -2409,13 +2409,13 @@ class Level implements ChunkManager, Metadatable{ } } - public function chunkRequestCallback(int $x, int $z, string $payload){ + public function chunkRequestCallback(int $x, int $z, BatchPacket $payload){ $this->timings->syncChunkSendTimer->startTiming(); $index = Level::chunkHash($x, $z); if(!isset($this->chunkCache[$index]) and $this->cacheChunks and $this->server->getMemoryManager()->canUseChunkCache()){ - $this->chunkCache[$index] = Level::getChunkCacheFromData($x, $z, $payload); + $this->chunkCache[$index] = $payload; $this->sendChunkFromCache($x, $z); $this->timings->syncChunkSendTimer->stopTiming(); return; @@ -2886,28 +2886,6 @@ class Level implements ChunkManager, Metadatable{ } } - /** - * @param int $chunkX - * @param int $chunkZ - * @param string $payload - * - * @return DataPacket - */ - public static function getChunkCacheFromData($chunkX, $chunkZ, $payload){ - $pk = new FullChunkDataPacket(); - $pk->chunkX = $chunkX; - $pk->chunkZ = $chunkZ; - $pk->data = $payload; - $pk->encode(); - - $batch = new BatchPacket(); - $batch->payload = zlib_encode(Binary::writeUnsignedVarInt(strlen($pk->getBuffer())) . $pk->getBuffer(), ZLIB_ENCODING_DEFLATE, Server::getInstance()->networkCompressionLevel); - - $batch->encode(); - $batch->isEncoded = true; - return $batch; - } - public function setMetadata($metadataKey, MetadataValue $metadataValue){ $this->server->getLevelMetadata()->setMetadata($this, $metadataKey, $metadataValue); } diff --git a/src/pocketmine/level/format/io/BaseLevelProvider.php b/src/pocketmine/level/format/io/BaseLevelProvider.php index 461f89ff2..979677a8e 100644 --- a/src/pocketmine/level/format/io/BaseLevelProvider.php +++ b/src/pocketmine/level/format/io/BaseLevelProvider.php @@ -33,6 +33,7 @@ use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\LongTag; use pocketmine\nbt\tag\StringTag; +use pocketmine\scheduler\AsyncTask; abstract class BaseLevelProvider implements LevelProvider{ /** @var Level */ @@ -41,8 +42,6 @@ abstract class BaseLevelProvider implements LevelProvider{ protected $path; /** @var CompoundTag */ protected $levelData; - /** @var bool */ - protected $asyncChunkRequest = false; public function __construct(Level $level, string $path){ $this->level = $level; @@ -66,7 +65,6 @@ abstract class BaseLevelProvider implements LevelProvider{ if(!isset($this->levelData->generatorOptions)){ $this->levelData->generatorOptions = new StringTag("generatorOptions", ""); } - $this->asyncChunkRequest = (bool) $this->level->getServer()->getProperty("chunk-sending.async-chunk-request", false); } public function getPath() : string{ @@ -131,19 +129,12 @@ abstract class BaseLevelProvider implements LevelProvider{ file_put_contents($this->getPath() . "level.dat", $buffer); } - public function requestChunkTask(int $x, int $z){ + public function requestChunkTask(int $x, int $z) : AsyncTask{ $chunk = $this->getChunk($x, $z, false); if(!($chunk instanceof Chunk)){ throw new ChunkException("Invalid Chunk sent"); } - if($this->asyncChunkRequest){ - return new ChunkRequestTask($this->level, $chunk); - } - - //non-async, call the callback directly with serialized data - $this->getLevel()->chunkRequestCallback($x, $z, $chunk->networkSerialize()); - - return null; + return new ChunkRequestTask($this->level, $chunk); } } diff --git a/src/pocketmine/level/format/io/ChunkRequestTask.php b/src/pocketmine/level/format/io/ChunkRequestTask.php index 6d6685cf2..71204441b 100644 --- a/src/pocketmine/level/format/io/ChunkRequestTask.php +++ b/src/pocketmine/level/format/io/ChunkRequestTask.php @@ -24,6 +24,8 @@ namespace pocketmine\level\format\io; use pocketmine\level\format\Chunk; use pocketmine\level\Level; use pocketmine\nbt\NBT; +use pocketmine\network\mcpe\protocol\BatchPacket; +use pocketmine\network\mcpe\protocol\FullChunkDataPacket; use pocketmine\scheduler\AsyncTask; use pocketmine\Server; use pocketmine\tile\Spawnable; @@ -38,8 +40,11 @@ class ChunkRequestTask extends AsyncTask{ protected $tiles; + protected $compressionLevel; + public function __construct(Level $level, Chunk $chunk){ $this->levelId = $level->getId(); + $this->compressionLevel = $level->getServer()->networkCompressionLevel; $this->chunk = $chunk->fastSerialize(); $this->chunkX = $chunk->getX(); @@ -61,9 +66,16 @@ class ChunkRequestTask extends AsyncTask{ public function onRun(){ $chunk = Chunk::fastDeserialize($this->chunk); - $ordered = $chunk->networkSerialize() . $this->tiles; + $pk = new FullChunkDataPacket(); + $pk->chunkX = $this->chunkX; + $pk->chunkZ = $this->chunkZ; + $pk->data = $chunk->networkSerialize() . $this->tiles; - $this->setResult($ordered, false); + $batch = new BatchPacket(); + $batch->addPacket($pk); + $batch->compress($this->compressionLevel); + + $this->setResult($batch); } public function onCompletion(Server $server){ diff --git a/src/pocketmine/level/format/io/LevelProvider.php b/src/pocketmine/level/format/io/LevelProvider.php index 0b31dfd31..9c4aea06c 100644 --- a/src/pocketmine/level/format/io/LevelProvider.php +++ b/src/pocketmine/level/format/io/LevelProvider.php @@ -26,6 +26,7 @@ namespace pocketmine\level\format\io; use pocketmine\level\format\Chunk; use pocketmine\level\Level; use pocketmine\math\Vector3; +use pocketmine\scheduler\AsyncTask; interface LevelProvider{ @@ -166,9 +167,9 @@ interface LevelProvider{ * @param int $x * @param int $z * - * @return \pocketmine\scheduler\AsyncTask|null + * @return AsyncTask */ - public function requestChunkTask(int $x, int $z); + public function requestChunkTask(int $x, int $z) : AsyncTask; /** * @return string diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index 5fa080618..3431823ea 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -122,8 +122,6 @@ chunk-sending: #Save a serialized copy of the chunk in memory for faster sending #Useful in mostly-static worlds where lots of players join at the same time cache-chunks: false - #Use AsyncTasks for serializing chunks for sending. - async-chunk-request: false chunk-ticking: #Max amount of chunks processed each tick