From ff915b829cebf2965403642468404909322dc80e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 24 Apr 2020 20:50:56 +0100 Subject: [PATCH] StartGamePacket: remove hardcoded cache, move to RuntimeBlockMapping --- .../mcpe/convert/RuntimeBlockMapping.php | 14 +++++ .../mcpe/handler/PreSpawnPacketHandler.php | 3 + src/network/mcpe/protocol/StartGamePacket.php | 25 +++----- .../mcpe/protocol/types/CacheableNbt.php | 60 +++++++++++++++++++ 4 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 src/network/mcpe/protocol/types/CacheableNbt.php diff --git a/src/network/mcpe/convert/RuntimeBlockMapping.php b/src/network/mcpe/convert/RuntimeBlockMapping.php index fc5b4fee3..dd1378daf 100644 --- a/src/network/mcpe/convert/RuntimeBlockMapping.php +++ b/src/network/mcpe/convert/RuntimeBlockMapping.php @@ -27,6 +27,7 @@ use pocketmine\block\BlockLegacyIds; use pocketmine\nbt\NBT; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\ListTag; +use pocketmine\network\mcpe\protocol\types\CacheableNbt; use pocketmine\network\mcpe\serializer\NetworkNbtSerializer; use function file_get_contents; use function getmypid; @@ -56,6 +57,11 @@ final class RuntimeBlockMapping{ private $runtimeToLegacyMap = []; /** @var CompoundTag[]|null */ private $bedrockKnownStates = null; + /** + * @var CacheableNbt|null + * @phpstan-var CacheableNbt<\pocketmine\nbt\tag\ListTag>|null + */ + private $startGamePaletteCache = null; private function __construct(){ $tag = (new NetworkNbtSerializer())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/required_block_states.nbt"))->getTag(); @@ -146,6 +152,7 @@ final class RuntimeBlockMapping{ private function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{ $this->legacyToRuntimeMap[($legacyId << 4) | $legacyMeta] = $staticRuntimeId; $this->runtimeToLegacyMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta; + $this->startGamePaletteCache = null; } /** @@ -154,4 +161,11 @@ final class RuntimeBlockMapping{ public function getBedrockKnownStates() : array{ return $this->bedrockKnownStates; } + + /** + * @phpstan-return CacheableNbt<\pocketmine\nbt\tag\ListTag> + */ + public function getStartGamePaletteCache() : ?CacheableNbt{ + return $this->startGamePaletteCache ?? new CacheableNbt(new ListTag($this->bedrockKnownStates)); + } } diff --git a/src/network/mcpe/handler/PreSpawnPacketHandler.php b/src/network/mcpe/handler/PreSpawnPacketHandler.php index 435d297b5..13cccb07c 100644 --- a/src/network/mcpe/handler/PreSpawnPacketHandler.php +++ b/src/network/mcpe/handler/PreSpawnPacketHandler.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\handler; +use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket; use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket; @@ -77,6 +78,8 @@ class PreSpawnPacketHandler extends PacketHandler{ $pk->commandsEnabled = true; $pk->levelId = ""; $pk->worldName = $this->server->getMotd(); + $pk->blockTable = RuntimeBlockMapping::getInstance()->getStartGamePaletteCache(); + $this->session->sendDataPacket($pk); $this->session->sendDataPacket(new AvailableActorIdentifiersPacket()); diff --git a/src/network/mcpe/protocol/StartGamePacket.php b/src/network/mcpe/protocol/StartGamePacket.php index ce1a8b8de..241afa12d 100644 --- a/src/network/mcpe/protocol/StartGamePacket.php +++ b/src/network/mcpe/protocol/StartGamePacket.php @@ -27,9 +27,8 @@ namespace pocketmine\network\mcpe\protocol; use pocketmine\math\Vector3; use pocketmine\nbt\tag\ListTag; -use pocketmine\nbt\TreeRoot; +use pocketmine\network\mcpe\protocol\types\CacheableNbt; use pocketmine\network\mcpe\protocol\types\PlayerPermissions; -use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\serializer\NetworkBinaryStream; use pocketmine\network\mcpe\serializer\NetworkNbtSerializer; use function count; @@ -40,8 +39,6 @@ use const pocketmine\RESOURCE_PATH; class StartGamePacket extends DataPacket implements ClientboundPacket{ public const NETWORK_ID = ProtocolInfo::START_GAME_PACKET; - /** @var string|null */ - private static $blockTableCache = null; /** @var string|null */ private static $itemTableCache = null; @@ -153,8 +150,11 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ /** @var string */ public $multiplayerCorrelationId = ""; //TODO: this should be filled with a UUID of some sort - /** @var ListTag|null */ - public $blockTable = null; + /** + * @var CacheableNbt + * @phpstan-var CacheableNbt<\pocketmine\nbt\tag\ListTag> + */ + public $blockTable; /** * @var int[]|null string (name) => int16 (legacyID) * @phpstan-var array|null @@ -220,7 +220,7 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ if(!($blockTable instanceof ListTag)){ throw new \UnexpectedValueException("Wrong block table root NBT tag type"); } - $this->blockTable = $blockTable; + $this->blockTable = new CacheableNbt($blockTable); $this->itemTable = []; for($i = 0, $count = $in->getUnsignedVarInt(); $i < $count; ++$i){ @@ -286,15 +286,8 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ $out->putVarInt($this->enchantmentSeed); - if($this->blockTable === null){ - if(self::$blockTableCache === null){ - //this is a really nasty hack, but it'll do for now - self::$blockTableCache = (new NetworkNbtSerializer())->write(new TreeRoot(new ListTag(RuntimeBlockMapping::getInstance()->getBedrockKnownStates()))); - } - $out->put(self::$blockTableCache); - }else{ - $out->put((new NetworkNbtSerializer())->write(new TreeRoot($this->blockTable))); - } + $out->put($this->blockTable->getEncodedNbt()); + if($this->itemTable === null){ if(self::$itemTableCache === null){ self::$itemTableCache = self::serializeItemTable(json_decode(file_get_contents(RESOURCE_PATH . '/vanilla/item_id_map.json'), true)); diff --git a/src/network/mcpe/protocol/types/CacheableNbt.php b/src/network/mcpe/protocol/types/CacheableNbt.php new file mode 100644 index 000000000..43439500e --- /dev/null +++ b/src/network/mcpe/protocol/types/CacheableNbt.php @@ -0,0 +1,60 @@ +root = $nbtRoot; + } + + /** + * @phpstan-return TTagType + */ + public function getRoot() : Tag{ + return $this->root; + } + + public function getEncodedNbt() : string{ + return $this->encodedNbt ?? ($this->encodedNbt = (new NetworkNbtSerializer())->write(new TreeRoot($this->root))); + } +}