mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-08 12:48:32 +00:00
NetworkSession: add support for discarding repeated packets before they're decoded
this dramatically reduces the server workload dealing with spammy packets like right-click interactions trigger. It also solves the problem of players getting kicked for right-clicking for too long.
This commit is contained in:
parent
56da492e48
commit
14b70c04ad
@ -58,6 +58,7 @@ use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
|
|||||||
use pocketmine\network\mcpe\protocol\ClientboundCloseFormPacket;
|
use pocketmine\network\mcpe\protocol\ClientboundCloseFormPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||||
use pocketmine\network\mcpe\protocol\DisconnectPacket;
|
use pocketmine\network\mcpe\protocol\DisconnectPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
|
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
|
||||||
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
|
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
|
||||||
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
|
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
|
||||||
@ -109,6 +110,7 @@ use pocketmine\promise\PromiseResolver;
|
|||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
use pocketmine\timings\Timings;
|
use pocketmine\timings\Timings;
|
||||||
use pocketmine\utils\AssumptionFailedError;
|
use pocketmine\utils\AssumptionFailedError;
|
||||||
|
use pocketmine\utils\Binary;
|
||||||
use pocketmine\utils\BinaryDataException;
|
use pocketmine\utils\BinaryDataException;
|
||||||
use pocketmine\utils\BinaryStream;
|
use pocketmine\utils\BinaryStream;
|
||||||
use pocketmine\utils\ObjectSet;
|
use pocketmine\utils\ObjectSet;
|
||||||
@ -194,6 +196,17 @@ class NetworkSession{
|
|||||||
*/
|
*/
|
||||||
private ObjectSet $disposeHooks;
|
private ObjectSet $disposeHooks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
* @phpstan-var array<int, string>
|
||||||
|
*/
|
||||||
|
private array $repeatedPacketFilters = [];
|
||||||
|
/**
|
||||||
|
* @var int[]
|
||||||
|
* @phpstan-var array<int, int>
|
||||||
|
*/
|
||||||
|
private array $repeatedPacketFilterStats = [];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private Server $server,
|
private Server $server,
|
||||||
private NetworkSessionManager $manager,
|
private NetworkSessionManager $manager,
|
||||||
@ -221,6 +234,8 @@ class NetworkSession{
|
|||||||
$this->onSessionStartSuccess(...)
|
$this->onSessionStartSuccess(...)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$this->addRepeatedPacketFilter(InventoryTransactionPacket::NETWORK_ID);
|
||||||
|
|
||||||
$this->manager->add($this);
|
$this->manager->add($this);
|
||||||
$this->logger->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_network_session_open()));
|
$this->logger->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_network_session_open()));
|
||||||
}
|
}
|
||||||
@ -350,6 +365,44 @@ class NetworkSession{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addRepeatedPacketFilter(int $packetId) : void{
|
||||||
|
$this->repeatedPacketFilters[$packetId] = "";
|
||||||
|
$this->repeatedPacketFilterStats[$packetId] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeRepeatedPacketFilter(int $packetId) : void{
|
||||||
|
unset($this->repeatedPacketFilters[$packetId]);
|
||||||
|
unset($this->repeatedPacketFilterStats[$packetId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the stats for repeated packet filters, indexed by packet ID.
|
||||||
|
* The value is the number of times a packet was dropped due to being repeated.
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
* @phpstan-return array<int, int>
|
||||||
|
*/
|
||||||
|
public function getRepeatedPacketFilterStats() : array{
|
||||||
|
return $this->repeatedPacketFilterStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkRepeatedPacketFilter(string $buffer) : bool{
|
||||||
|
//TODO: would be great if we didn't repeat reading the ID inside PacketPool
|
||||||
|
$dummy = 0;
|
||||||
|
$packetId = Binary::readUnsignedVarInt($buffer, $dummy);
|
||||||
|
|
||||||
|
if(isset($this->repeatedPacketFilters[$packetId])){
|
||||||
|
if($buffer === $this->repeatedPacketFilters[$packetId]){
|
||||||
|
$this->repeatedPacketFilterStats[$packetId]++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->repeatedPacketFilters[$packetId] = $buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws PacketHandlingException
|
* @throws PacketHandlingException
|
||||||
*/
|
*/
|
||||||
@ -403,6 +456,10 @@ class NetworkSession{
|
|||||||
try{
|
try{
|
||||||
$stream = new BinaryStream($decompressed);
|
$stream = new BinaryStream($decompressed);
|
||||||
foreach(PacketBatch::decodeRaw($stream) as $buffer){
|
foreach(PacketBatch::decodeRaw($stream) as $buffer){
|
||||||
|
if($this->checkRepeatedPacketFilter($buffer)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$this->gamePacketLimiter->decrement();
|
$this->gamePacketLimiter->decrement();
|
||||||
$packet = $this->packetPool->getPacket($buffer);
|
$packet = $this->packetPool->getPacket($buffer);
|
||||||
if($packet === null){
|
if($packet === null){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user