mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-10 13:35:29 +00:00
start making network compressors dynamic
this will facilitate future multi version support where compression types are different between versions
This commit is contained in:
parent
fe258740e3
commit
d9e4783b24
@ -48,7 +48,7 @@ use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\TreeRoot;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchTask;
|
||||
use pocketmine\network\mcpe\compression\Zlib as ZlibNetworkCompression;
|
||||
use pocketmine\network\mcpe\compression\ZlibCompressor as ZlibNetworkCompression;
|
||||
use pocketmine\network\mcpe\encryption\NetworkCipher;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||
@ -912,17 +912,18 @@ class Server{
|
||||
|
||||
$this->asyncPool = new AsyncPool($poolSize, max(-1, (int) $this->getProperty("memory.async-worker-hard-limit", 256)), $this->autoloader, $this->logger);
|
||||
|
||||
$netCompressionThreshold = -1;
|
||||
if($this->getProperty("network.batch-threshold", 256) >= 0){
|
||||
ZlibNetworkCompression::$THRESHOLD = (int) $this->getProperty("network.batch-threshold", 256);
|
||||
}else{
|
||||
ZlibNetworkCompression::$THRESHOLD = -1;
|
||||
$netCompressionThreshold = (int) $this->getProperty("network.batch-threshold", 256);
|
||||
}
|
||||
|
||||
ZlibNetworkCompression::$LEVEL = $this->getProperty("network.compression-level", 7);
|
||||
if(ZlibNetworkCompression::$LEVEL < 1 or ZlibNetworkCompression::$LEVEL > 9){
|
||||
$this->logger->warning("Invalid network compression level " . ZlibNetworkCompression::$LEVEL . " set, setting to default 7");
|
||||
ZlibNetworkCompression::$LEVEL = 7;
|
||||
$netCompressionLevel = $this->getProperty("network.compression-level", 7);
|
||||
if($netCompressionLevel < 1 or $netCompressionLevel > 9){
|
||||
$this->logger->warning("Invalid network compression level $netCompressionLevel set, setting to default 7");
|
||||
$netCompressionLevel = 7;
|
||||
}
|
||||
ZlibNetworkCompression::setInstance(new ZlibNetworkCompression($netCompressionLevel, $netCompressionThreshold, ZlibNetworkCompression::DEFAULT_MAX_DECOMPRESSION_SIZE));
|
||||
|
||||
$this->networkCompressionAsync = (bool) $this->getProperty("network.async-compression", true);
|
||||
|
||||
NetworkCipher::$ENABLED = (bool) $this->getProperty("network.enable-encryption", true);
|
||||
@ -1251,7 +1252,7 @@ class Server{
|
||||
|
||||
$stream = PacketBatch::fromPackets(...$ev->getPackets());
|
||||
|
||||
if(ZlibNetworkCompression::$THRESHOLD < 0 or strlen($stream->getBuffer()) < ZlibNetworkCompression::$THRESHOLD){
|
||||
if(!ZlibNetworkCompression::getInstance()->willCompress($stream->getBuffer())){
|
||||
foreach($recipients as $target){
|
||||
foreach($ev->getPackets() as $pk){
|
||||
$target->addToSendBuffer($pk);
|
||||
@ -1274,19 +1275,18 @@ class Server{
|
||||
try{
|
||||
Timings::$playerNetworkSendCompressTimer->startTiming();
|
||||
|
||||
$compressionLevel = ZlibNetworkCompression::$LEVEL;
|
||||
$compressor = ZlibNetworkCompression::getInstance();
|
||||
$buffer = $stream->getBuffer();
|
||||
if(ZlibNetworkCompression::$THRESHOLD < 0 or strlen($buffer) < ZlibNetworkCompression::$THRESHOLD){
|
||||
$compressionLevel = 0; //Do not compress packets under the threshold
|
||||
if(!$compressor->willCompress($buffer)){
|
||||
$forceSync = true;
|
||||
}
|
||||
|
||||
$promise = new CompressBatchPromise();
|
||||
if(!$forceSync and $this->networkCompressionAsync){
|
||||
$task = new CompressBatchTask($buffer, $compressionLevel, $promise);
|
||||
$task = new CompressBatchTask($buffer, $promise, $compressor);
|
||||
$this->asyncPool->submitTask($task);
|
||||
}else{
|
||||
$promise->resolve(ZlibNetworkCompression::compress($buffer, $compressionLevel));
|
||||
$promise->resolve($compressor->compress($buffer));
|
||||
}
|
||||
|
||||
return $promise;
|
||||
|
@ -25,7 +25,7 @@ namespace pocketmine\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
||||
use pocketmine\network\mcpe\compression\Zlib;
|
||||
use pocketmine\network\mcpe\compression\ZlibCompressor;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||
@ -165,7 +165,7 @@ class CraftingManager{
|
||||
}
|
||||
|
||||
$this->craftingDataCache = new CompressBatchPromise();
|
||||
$this->craftingDataCache->resolve(Zlib::compress(PacketBatch::fromPackets($pk)->getBuffer()));
|
||||
$this->craftingDataCache->resolve(ZlibCompressor::getInstance()->compress(PacketBatch::fromPackets($pk)->getBuffer()));
|
||||
|
||||
Timings::$craftingDataCacheRebuildTimer->stopTiming();
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -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
|
||||
|
@ -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{
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
77
src/network/mcpe/compression/ZlibCompressor.php
Normal file
77
src/network/mcpe/compression/ZlibCompressor.php
Normal 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);
|
||||
}
|
||||
}
|
@ -70,6 +70,11 @@ parameters:
|
||||
count: 1
|
||||
path: ../../../src/network/mcpe/protocol/types/entity/EntityMetadataCollection.php
|
||||
|
||||
-
|
||||
message: "#^Class pocketmine\\\\network\\\\mcpe\\\\compression\\\\ZlibCompressor constructor invoked with 0 parameters, 3 required\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/network/mcpe/compression/ZlibCompressor.php
|
||||
|
||||
-
|
||||
message: "#^Strict comparison using \\!\\=\\= between string and false will always evaluate to true\\.$#"
|
||||
count: 1
|
||||
|
Loading…
x
Reference in New Issue
Block a user