start making network compressors dynamic

this will facilitate future multi version support where compression types are different between versions
This commit is contained in:
Dylan K. Taylor
2020-04-28 14:47:01 +01:00
parent fe258740e3
commit d9e4783b24
8 changed files with 110 additions and 87 deletions

View File

@@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe;
use pocketmine\network\mcpe\compression\CompressBatchPromise;
use pocketmine\network\mcpe\compression\Zlib;
use pocketmine\network\mcpe\compression\ZlibCompressor;
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\serializer\ChunkSerializer;
@@ -43,8 +43,8 @@ class ChunkRequestTask extends AsyncTask{
/** @var int */
protected $chunkZ;
/** @var int */
protected $compressionLevel;
/** @var ZlibCompressor */
protected $compressor;
/** @var string */
private $tiles = "";
@@ -53,7 +53,7 @@ class ChunkRequestTask extends AsyncTask{
* @phpstan-param (\Closure() : void)|null $onError
*/
public function __construct(int $chunkX, int $chunkZ, Chunk $chunk, CompressBatchPromise $promise, ?\Closure $onError = null){
$this->compressionLevel = Zlib::$LEVEL;
$this->compressor = ZlibCompressor::getInstance(); //TODO: this should be injectable
$this->chunk = FastChunkSerializer::serializeWithoutLight($chunk);
$this->chunkX = $chunkX;
@@ -68,7 +68,7 @@ class ChunkRequestTask extends AsyncTask{
$chunk = FastChunkSerializer::deserialize($this->chunk);
$subCount = ChunkSerializer::getSubChunkCount($chunk);
$payload = ChunkSerializer::serialize($chunk, $this->tiles);
$this->setResult(Zlib::compress(PacketBatch::fromPackets(LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $subCount, $payload))->getBuffer(), $this->compressionLevel));
$this->setResult($this->compressor->compress(PacketBatch::fromPackets(LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $subCount, $payload))->getBuffer()));
}
public function onError() : void{

View File

@@ -36,7 +36,7 @@ use pocketmine\math\Vector3;
use pocketmine\network\BadPacketException;
use pocketmine\network\mcpe\compression\CompressBatchPromise;
use pocketmine\network\mcpe\compression\DecompressionException;
use pocketmine\network\mcpe\compression\Zlib;
use pocketmine\network\mcpe\compression\ZlibCompressor;
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\encryption\DecryptionException;
@@ -283,7 +283,7 @@ class NetworkSession{
Timings::$playerNetworkReceiveDecompressTimer->startTiming();
try{
$stream = new PacketBatch(Zlib::decompress($payload));
$stream = new PacketBatch(ZlibCompressor::getInstance()->decompress($payload)); //TODO: make this dynamic
}catch(DecompressionException $e){
$this->logger->debug("Failed to decompress packet: " . base64_encode($payload));
//TODO: this isn't incompatible game version if we already established protocol version

View File

@@ -29,19 +29,19 @@ class CompressBatchTask extends AsyncTask{
private const TLS_KEY_PROMISE = "promise";
/** @var int */
private $level;
/** @var string */
private $data;
/** @var ZlibCompressor */
private $compressor;
public function __construct(string $data, int $compressionLevel, CompressBatchPromise $promise){
public function __construct(string $data, CompressBatchPromise $promise, ZlibCompressor $compressor){
$this->data = $data;
$this->level = $compressionLevel;
$this->compressor = $compressor;
$this->storeLocal(self::TLS_KEY_PROMISE, $promise);
}
public function onRun() : void{
$this->setResult(Zlib::compress($this->data, $this->level));
$this->setResult($this->compressor->compress($this->data));
}
public function onCompletion() : void{

View File

@@ -1,59 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\compression;
use function zlib_decode;
use function zlib_encode;
use const ZLIB_ENCODING_DEFLATE;
final class Zlib{
/** @var int */
public static $LEVEL = 7;
/** @var int */
public static $THRESHOLD = 256;
private function __construct(){
}
/**
* @param int $maxDecodedLength default 2MB
*
* @throws DecompressionException
*/
public static function decompress(string $payload, int $maxDecodedLength = 1024 * 1024 * 2) : string{
$result = @zlib_decode($payload, $maxDecodedLength);
if($result === false){
throw new DecompressionException("Failed to decompress data");
}
return $result;
}
/**
* @param int $compressionLevel
*/
public static function compress(string $payload, ?int $compressionLevel = null) : string{
return zlib_encode($payload, ZLIB_ENCODING_DEFLATE, $compressionLevel ?? self::$LEVEL);
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\compression;
use pocketmine\utils\SingletonTrait;
use function strlen;
use function zlib_decode;
use function zlib_encode;
use const ZLIB_ENCODING_DEFLATE;
final class ZlibCompressor{
use SingletonTrait;
public const DEFAULT_LEVEL = 7;
public const DEFAULT_THRESHOLD = 256;
public const DEFAULT_MAX_DECOMPRESSION_SIZE = 2 * 1024 * 1024;
/**
* @see SingletonTrait::make()
*/
private static function make() : self{
return new self(self::DEFAULT_LEVEL, self::DEFAULT_THRESHOLD, self::DEFAULT_MAX_DECOMPRESSION_SIZE);
}
/** @var int */
private $level;
/** @var int */
private $threshold;
/** @var int */
private $maxDecompressionSize;
public function __construct(int $level, int $minCompressionSize, int $maxDecompressionSize){
$this->level = $level;
$this->threshold = $minCompressionSize;
$this->maxDecompressionSize = $maxDecompressionSize;
}
public function willCompress(string $data) : bool{
return $this->threshold > -1 and strlen($data) >= $this->threshold;
}
/**
* @throws DecompressionException
*/
public function decompress(string $payload) : string{
$result = @zlib_decode($payload, $this->maxDecompressionSize);
if($result === false){
throw new DecompressionException("Failed to decompress data");
}
return $result;
}
public function compress(string $payload) : string{
return zlib_encode($payload, ZLIB_ENCODING_DEFLATE, $this->willCompress($payload) ? $this->level : 0);
}
}