Deglobalize ItemTypeDictionary usage, at least for the protocol

while this is a bit hacky outside of the protocol namespace, it makes it much easier to use the protocol library for alternative purposes, such as for a client or MITM proxy.
It also removes all but one remaining core dependency of the protocol library, making it very close to being able to be separated from the server core entirely.
This commit is contained in:
Dylan K. Taylor 2021-07-14 14:26:32 +01:00
parent 0c2917f2aa
commit 1ad38d499c
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
12 changed files with 108 additions and 36 deletions

View File

@ -25,9 +25,11 @@ namespace pocketmine\network\mcpe;
use pocketmine\network\mcpe\compression\CompressBatchPromise; use pocketmine\network\mcpe\compression\CompressBatchPromise;
use pocketmine\network\mcpe\compression\Compressor; use pocketmine\network\mcpe\compression\Compressor;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\LevelChunkPacket; use pocketmine\network\mcpe\protocol\LevelChunkPacket;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch; use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\network\mcpe\serializer\ChunkSerializer; use pocketmine\network\mcpe\serializer\ChunkSerializer;
use pocketmine\scheduler\AsyncTask; use pocketmine\scheduler\AsyncTask;
use pocketmine\world\format\Chunk; use pocketmine\world\format\Chunk;
@ -68,8 +70,9 @@ class ChunkRequestTask extends AsyncTask{
public function onRun() : void{ public function onRun() : void{
$chunk = FastChunkSerializer::deserialize($this->chunk); $chunk = FastChunkSerializer::deserialize($this->chunk);
$subCount = ChunkSerializer::getSubChunkCount($chunk); $subCount = ChunkSerializer::getSubChunkCount($chunk);
$payload = ChunkSerializer::serialize($chunk, RuntimeBlockMapping::getInstance(), $this->tiles); $encoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$this->setResult($this->compressor->compress(PacketBatch::fromPackets(LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $subCount, $payload))->getBuffer())); $payload = ChunkSerializer::serialize($chunk, RuntimeBlockMapping::getInstance(), $encoderContext, $this->tiles);
$this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $subCount, $payload))->getBuffer()));
} }
public function onError() : void{ public function onError() : void{

View File

@ -42,6 +42,7 @@ use pocketmine\network\mcpe\cache\ChunkCache;
use pocketmine\network\mcpe\compression\CompressBatchPromise; use pocketmine\network\mcpe\compression\CompressBatchPromise;
use pocketmine\network\mcpe\compression\Compressor; use pocketmine\network\mcpe\compression\Compressor;
use pocketmine\network\mcpe\compression\DecompressionException; use pocketmine\network\mcpe\compression\DecompressionException;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\convert\SkinAdapterSingleton; use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
use pocketmine\network\mcpe\convert\TypeConverter; use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\encryption\DecryptionException; use pocketmine\network\mcpe\encryption\DecryptionException;
@ -74,6 +75,7 @@ use pocketmine\network\mcpe\protocol\PlayStatusPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket; use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch; use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\network\mcpe\protocol\ServerboundPacket; use pocketmine\network\mcpe\protocol\ServerboundPacket;
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket; use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
use pocketmine\network\mcpe\protocol\SetActorDataPacket; use pocketmine\network\mcpe\protocol\SetActorDataPacket;
@ -158,6 +160,7 @@ class NetworkSession{
private bool $forceAsyncCompression = true; private bool $forceAsyncCompression = true;
private PacketPool $packetPool; private PacketPool $packetPool;
private PacketSerializerContext $packetSerializerContext;
private ?InventoryManager $invManager = null; private ?InventoryManager $invManager = null;
@ -185,6 +188,9 @@ class NetworkSession{
$this->compressor = $compressor; $this->compressor = $compressor;
$this->packetPool = $packetPool; $this->packetPool = $packetPool;
//TODO: allow this to be injected
$this->packetSerializerContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$this->disposeHooks = new ObjectSet(); $this->disposeHooks = new ObjectSet();
$this->connectTime = time(); $this->connectTime = time();
@ -335,7 +341,7 @@ class NetworkSession{
} }
try{ try{
foreach($stream->getPackets($this->packetPool, 500) as [$packet, $buffer]){ foreach($stream->getPackets($this->packetPool, $this->packetSerializerContext, 500) as [$packet, $buffer]){
try{ try{
$this->handleDataPacket($packet, $buffer); $this->handleDataPacket($packet, $buffer);
}catch(PacketHandlingException $e){ }catch(PacketHandlingException $e){
@ -361,7 +367,7 @@ class NetworkSession{
$timings->startTiming(); $timings->startTiming();
try{ try{
$stream = new PacketSerializer($buffer); $stream = PacketSerializer::decoder($buffer, 0, $this->packetSerializerContext);
try{ try{
$packet->decode($stream); $packet->decode($stream);
}catch(PacketDecodeException $e){ }catch(PacketDecodeException $e){
@ -430,7 +436,7 @@ class NetworkSession{
}elseif($this->forceAsyncCompression){ }elseif($this->forceAsyncCompression){
$syncMode = false; $syncMode = false;
} }
$promise = $this->server->prepareBatch(PacketBatch::fromPackets(...$this->sendBuffer), $this->compressor, $syncMode); $promise = $this->server->prepareBatch(PacketBatch::fromPackets($this->packetSerializerContext, ...$this->sendBuffer), $this->compressor, $syncMode);
$this->sendBuffer = []; $this->sendBuffer = [];
$this->queueCompressedNoBufferFlush($promise, $immediate); $this->queueCompressedNoBufferFlush($promise, $immediate);
} }

View File

@ -24,7 +24,9 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe; namespace pocketmine\network\mcpe;
use pocketmine\network\mcpe\compression\Compressor; use pocketmine\network\mcpe\compression\Compressor;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch; use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\Server; use pocketmine\Server;
use function spl_object_id; use function spl_object_id;
@ -38,7 +40,8 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
} }
public function broadcastPackets(array $recipients, array $packets) : void{ public function broadcastPackets(array $recipients, array $packets) : void{
$stream = PacketBatch::fromPackets(...$packets); //TODO: we should be using session-specific serializer contexts for this
$stream = PacketBatch::fromPackets(new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()), ...$packets);
/** @var Compressor[] $compressors */ /** @var Compressor[] $compressors */
$compressors = []; $compressors = [];

View File

@ -29,6 +29,7 @@ use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer; use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\SingletonTrait; use pocketmine\utils\SingletonTrait;
use Webmozart\PathUtil\Path; use Webmozart\PathUtil\Path;
@ -52,7 +53,7 @@ final class RuntimeBlockMapping{
if($canonicalBlockStatesFile === false){ if($canonicalBlockStatesFile === false){
throw new AssumptionFailedError("Missing required resource file"); throw new AssumptionFailedError("Missing required resource file");
} }
$stream = new PacketSerializer($canonicalBlockStatesFile); $stream = PacketSerializer::decoder($canonicalBlockStatesFile, 0, new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()));
$list = []; $list = [];
while(!$stream->feof()){ while(!$stream->feof()){
$list[] = $stream->getNbtCompoundRoot(); $list[] = $stream->getNbtCompoundRoot();
@ -66,7 +67,7 @@ final class RuntimeBlockMapping{
$legacyIdMap = LegacyBlockIdToStringIdMap::getInstance(); $legacyIdMap = LegacyBlockIdToStringIdMap::getInstance();
/** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */ /** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */
$legacyStateMap = []; $legacyStateMap = [];
$legacyStateMapReader = new PacketSerializer(file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "r12_to_current_block_map.bin"))); $legacyStateMapReader = PacketSerializer::decoder(file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "r12_to_current_block_map.bin")), 0, new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()));
$nbtReader = new NetworkNbtSerializer(); $nbtReader = new NetworkNbtSerializer();
while(!$legacyStateMapReader->feof()){ while(!$legacyStateMapReader->feof()){
$id = $legacyStateMapReader->getString(); $id = $legacyStateMapReader->getString();

View File

@ -42,8 +42,8 @@ class PacketBatch{
* @phpstan-return \Generator<int, array{Packet, string}, void, void> * @phpstan-return \Generator<int, array{Packet, string}, void, void>
* @throws PacketDecodeException * @throws PacketDecodeException
*/ */
public function getPackets(PacketPool $packetPool, int $max) : \Generator{ public function getPackets(PacketPool $packetPool, PacketSerializerContext $decoderContext, int $max) : \Generator{
$serializer = new PacketSerializer($this->buffer); $serializer = PacketSerializer::decoder($this->buffer, 0, $decoderContext);
for($c = 0; $c < $max and !$serializer->feof(); ++$c){ for($c = 0; $c < $max and !$serializer->feof(); ++$c){
try{ try{
$buffer = $serializer->getString(); $buffer = $serializer->getString();
@ -64,10 +64,10 @@ class PacketBatch{
* *
* @return PacketBatch * @return PacketBatch
*/ */
public static function fromPackets(Packet ...$packets) : self{ public static function fromPackets(PacketSerializerContext $context, Packet ...$packets) : self{
$serializer = new PacketSerializer(); $serializer = PacketSerializer::encoder($context);
foreach($packets as $packet){ foreach($packets as $packet){
$subSerializer = new PacketSerializer(); $subSerializer = PacketSerializer::encoder($context);
$packet->encode($subSerializer); $packet->encode($subSerializer);
$serializer->putString($subSerializer->getBuffer()); $serializer->putString($subSerializer->getBuffer());
} }

View File

@ -30,7 +30,6 @@ use pocketmine\nbt\LittleEndianNbtSerializer;
use pocketmine\nbt\NbtDataException; use pocketmine\nbt\NbtDataException;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\TreeRoot; use pocketmine\nbt\TreeRoot;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\protocol\PacketDecodeException; use pocketmine\network\mcpe\protocol\PacketDecodeException;
use pocketmine\network\mcpe\protocol\types\BoolGameRule; use pocketmine\network\mcpe\protocol\types\BoolGameRule;
use pocketmine\network\mcpe\protocol\types\command\CommandOriginData; use pocketmine\network\mcpe\protocol\types\command\CommandOriginData;
@ -71,10 +70,20 @@ use function substr;
class PacketSerializer extends BinaryStream{ class PacketSerializer extends BinaryStream{
private int $shieldItemRuntimeId; private int $shieldItemRuntimeId;
private PacketSerializerContext $context;
public function __construct(string $buffer = "", int $offset = 0){ protected function __construct(PacketSerializerContext $context, string $buffer = "", int $offset = 0){
parent::__construct($buffer, $offset); parent::__construct($buffer, $offset);
$this->shieldItemRuntimeId = GlobalItemTypeDictionary::getInstance()->getDictionary()->fromStringId("minecraft:shield"); $this->context = $context;
$this->shieldItemRuntimeId = $context->getItemDictionary()->fromStringId("minecraft:shield");
}
public static function encoder(PacketSerializerContext $context) : self{
return new self($context);
}
public static function decoder(string $buffer, int $offset, PacketSerializerContext $context) : self{
return new self($context, $buffer, $offset);
} }
/** /**
@ -248,9 +257,8 @@ class PacketSerializer extends BinaryStream{
$readExtraCrapInTheMiddle($this); $readExtraCrapInTheMiddle($this);
$blockRuntimeId = $this->getVarInt(); $blockRuntimeId = $this->getVarInt();
$extraData = new PacketSerializer($this->getString()); $extraData = self::decoder($this->getString(), 0, $this->context);
$shieldItemRuntimeId = $this->shieldItemRuntimeId; return (static function() use ($extraData, $id, $meta, $count, $blockRuntimeId) : ItemStack{
return (static function() use ($extraData, $id, $meta, $count, $blockRuntimeId, $shieldItemRuntimeId) : ItemStack{
$nbtLen = $extraData->getLShort(); $nbtLen = $extraData->getLShort();
/** @var CompoundTag|null $compound */ /** @var CompoundTag|null $compound */
@ -283,7 +291,7 @@ class PacketSerializer extends BinaryStream{
} }
$shieldBlockingTick = null; $shieldBlockingTick = null;
if($id === $shieldItemRuntimeId){ if($id === $extraData->shieldItemRuntimeId){
$shieldBlockingTick = $extraData->getLLong(); $shieldBlockingTick = $extraData->getLLong();
} }
@ -312,9 +320,9 @@ class PacketSerializer extends BinaryStream{
$writeExtraCrapInTheMiddle($this); $writeExtraCrapInTheMiddle($this);
$this->putVarInt($item->getBlockRuntimeId()); $this->putVarInt($item->getBlockRuntimeId());
$shieldItemRuntimeId = $this->shieldItemRuntimeId; $context = $this->context;
$this->putString((static function() use ($item, $shieldItemRuntimeId) : string{ $this->putString((static function() use ($item, $context) : string{
$extraData = new PacketSerializer(); $extraData = PacketSerializer::encoder($context);
$nbt = $item->getNbt(); $nbt = $item->getNbt();
if($nbt !== null){ if($nbt !== null){
@ -337,7 +345,7 @@ class PacketSerializer extends BinaryStream{
} }
$blockingTick = $item->getShieldBlockingTick(); $blockingTick = $item->getShieldBlockingTick();
if($item->getId() === $shieldItemRuntimeId){ if($item->getId() === $extraData->shieldItemRuntimeId){
$extraData->putLLong($blockingTick ?? 0); $extraData->putLLong($blockingTick ?? 0);
} }
return $extraData->getBuffer(); return $extraData->getBuffer();

View File

@ -0,0 +1,39 @@
<?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\protocol\serializer;
/**
* Contains information for a packet serializer specific to a given game session needed for packet encoding and decoding,
* such as a dictionary of item runtime IDs to their internal string IDs.
*/
final class PacketSerializerContext{
private ItemTypeDictionary $itemDictionary;
public function __construct(ItemTypeDictionary $itemDictionary){
$this->itemDictionary = $itemDictionary;
}
public function getItemDictionary() : ItemTypeDictionary{ return $this->itemDictionary; }
}

View File

@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\serializer;
use pocketmine\block\tile\Spawnable; use pocketmine\block\tile\Spawnable;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\BinaryStream; use pocketmine\utils\BinaryStream;
use pocketmine\world\format\Chunk; use pocketmine\world\format\Chunk;
@ -52,8 +53,8 @@ final class ChunkSerializer{
return 0; return 0;
} }
public static function serialize(Chunk $chunk, RuntimeBlockMapping $blockMapper, ?string $tiles = null) : string{ public static function serialize(Chunk $chunk, RuntimeBlockMapping $blockMapper, PacketSerializerContext $encoderContext, ?string $tiles = null) : string{
$stream = new PacketSerializer(); $stream = PacketSerializer::encoder($encoderContext);
$subChunkCount = self::getSubChunkCount($chunk); $subChunkCount = self::getSubChunkCount($chunk);
for($y = 0; $y < $subChunkCount; ++$y){ for($y = 0; $y < $subChunkCount; ++$y){
$layers = $chunk->getSubChunk($y)->getBlockLayers(); $layers = $chunk->getSubChunk($y)->getBlockLayers();

View File

@ -591,7 +591,7 @@ parameters:
path: ../../../src/network/mcpe/auth/ProcessLoginTask.php path: ../../../src/network/mcpe/auth/ProcessLoginTask.php
- -
message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\serializer\\\\PacketSerializer constructor expects string, string\\|false given\\.$#" message: "#^Parameter \\#1 \\$buffer of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\serializer\\\\PacketSerializer\\:\\:decoder\\(\\) expects string, string\\|false given\\.$#"
count: 1 count: 1
path: ../../../src/network/mcpe/convert/RuntimeBlockMapping.php path: ../../../src/network/mcpe/convert/RuntimeBlockMapping.php

View File

@ -24,7 +24,9 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol; namespace pocketmine\network\mcpe\protocol;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
class DataPacketTest extends TestCase{ class DataPacketTest extends TestCase{
@ -32,11 +34,13 @@ class DataPacketTest extends TestCase{
$pk = new TestPacket(); $pk = new TestPacket();
$pk->senderSubId = 3; $pk->senderSubId = 3;
$pk->recipientSubId = 2; $pk->recipientSubId = 2;
$serializer = new PacketSerializer();
$context = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$serializer = PacketSerializer::encoder($context);
$pk->encode($serializer); $pk->encode($serializer);
$pk2 = new TestPacket(); $pk2 = new TestPacket();
$pk2->decode(new PacketSerializer($serializer->getBuffer())); $pk2->decode(PacketSerializer::decoder($serializer->getBuffer(), 0, $context));
self::assertSame($pk2->senderSubId, 3); self::assertSame($pk2->senderSubId, 3);
self::assertSame($pk2->recipientSubId, 2); self::assertSame($pk2->recipientSubId, 2);
} }

View File

@ -24,18 +24,21 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol; namespace pocketmine\network\mcpe\protocol;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use function strlen; use function strlen;
class LoginPacketTest extends TestCase{ class LoginPacketTest extends TestCase{
public function testInvalidChainDataJsonHandling() : void{ public function testInvalidChainDataJsonHandling() : void{
$stream = new PacketSerializer(); $context = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$stream = PacketSerializer::encoder($context);
$stream->putUnsignedVarInt(ProtocolInfo::LOGIN_PACKET); $stream->putUnsignedVarInt(ProtocolInfo::LOGIN_PACKET);
$payload = '{"chain":[]'; //intentionally malformed $payload = '{"chain":[]'; //intentionally malformed
$stream->putInt(ProtocolInfo::CURRENT_PROTOCOL); $stream->putInt(ProtocolInfo::CURRENT_PROTOCOL);
$stream2 = new PacketSerializer(); $stream2 = PacketSerializer::encoder($context);
$stream2->putLInt(strlen($payload)); $stream2->putLInt(strlen($payload));
$stream2->put($payload); $stream2->put($payload);
$stream->putString($stream2->getBuffer()); $stream->putString($stream2->getBuffer());
@ -43,6 +46,6 @@ class LoginPacketTest extends TestCase{
$pk = PacketPool::getInstance()->getPacket($stream->getBuffer()); $pk = PacketPool::getInstance()->getPacket($stream->getBuffer());
$this->expectException(PacketDecodeException::class); $this->expectException(PacketDecodeException::class);
$pk->decode(new PacketSerializer($stream->getBuffer())); //bang $pk->decode(PacketSerializer::decoder($stream->getBuffer(), 0, $context)); //bang
} }
} }

View File

@ -24,9 +24,11 @@ declare(strict_types=1);
namespace pocketmine\mcpe\protocol\serializer; namespace pocketmine\mcpe\protocol\serializer;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\protocol\PacketDecodeException; use pocketmine\network\mcpe\protocol\PacketDecodeException;
use pocketmine\network\mcpe\protocol\PacketPool; use pocketmine\network\mcpe\protocol\PacketPool;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch; use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\network\mcpe\protocol\TestPacket; use pocketmine\network\mcpe\protocol\TestPacket;
use function array_fill; use function array_fill;
@ -34,21 +36,23 @@ class PacketBatchTest extends TestCase{
public function testDecodeTooBig() : void{ public function testDecodeTooBig() : void{
$limit = 10; $limit = 10;
$write = PacketBatch::fromPackets(...array_fill(0, $limit + 1, new TestPacket())); $decoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$write = PacketBatch::fromPackets($decoderContext, ...array_fill(0, $limit + 1, new TestPacket()));
$read = new PacketBatch($write->getBuffer()); $read = new PacketBatch($write->getBuffer());
$this->expectException(PacketDecodeException::class); $this->expectException(PacketDecodeException::class);
$readCount = 0; $readCount = 0;
foreach($read->getPackets(PacketPool::getInstance(), $limit) as $packet){ foreach($read->getPackets(PacketPool::getInstance(), $decoderContext, $limit) as $packet){
$readCount++; $readCount++;
} }
} }
public function testDecodeAtLimit() : void{ public function testDecodeAtLimit() : void{
$limit = 10; $limit = 10;
$write = PacketBatch::fromPackets(...array_fill(0, $limit, new TestPacket())); $decoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$write = PacketBatch::fromPackets($decoderContext, ...array_fill(0, $limit, new TestPacket()));
$read = new PacketBatch($write->getBuffer()); $read = new PacketBatch($write->getBuffer());
$readCount = 0; $readCount = 0;
foreach($read->getPackets(PacketPool::getInstance(), $limit) as $packet){ foreach($read->getPackets(PacketPool::getInstance(), $decoderContext, $limit) as $packet){
$readCount++; $readCount++;
} }
self::assertSame($limit, $readCount); self::assertSame($limit, $readCount);