mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-13 01:09:44 +00:00
now we always decode, because it's not safe to assume that we can just grab the rest of the bytes in the packet.
318 lines
9.9 KiB
PHP
318 lines
9.9 KiB
PHP
<?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;
|
|
|
|
#include <rules/DataPacket.h>
|
|
|
|
use pocketmine\math\Vector3;
|
|
use pocketmine\nbt\tag\ListTag;
|
|
use pocketmine\network\mcpe\protocol\serializer\NetworkBinaryStream;
|
|
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
|
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
|
use function count;
|
|
use function file_get_contents;
|
|
use function json_decode;
|
|
use const pocketmine\RESOURCE_PATH;
|
|
|
|
class StartGamePacket extends DataPacket implements ClientboundPacket{
|
|
public const NETWORK_ID = ProtocolInfo::START_GAME_PACKET;
|
|
|
|
/** @var string|null */
|
|
private static $itemTableCache = null;
|
|
|
|
/** @var int */
|
|
public $entityUniqueId;
|
|
/** @var int */
|
|
public $entityRuntimeId;
|
|
/** @var int */
|
|
public $playerGamemode;
|
|
|
|
/** @var Vector3 */
|
|
public $playerPosition;
|
|
|
|
/** @var float */
|
|
public $pitch;
|
|
/** @var float */
|
|
public $yaw;
|
|
|
|
/** @var int */
|
|
public $seed;
|
|
/** @var int */
|
|
public $dimension;
|
|
/** @var int */
|
|
public $generator = 1; //default infinite - 0 old, 1 infinite, 2 flat
|
|
/** @var int */
|
|
public $worldGamemode;
|
|
/** @var int */
|
|
public $difficulty;
|
|
/** @var int */
|
|
public $spawnX;
|
|
/** @var int */
|
|
public $spawnY;
|
|
/** @var int */
|
|
public $spawnZ;
|
|
/** @var bool */
|
|
public $hasAchievementsDisabled = true;
|
|
/** @var int */
|
|
public $time = -1;
|
|
/** @var int */
|
|
public $eduEditionOffer = 0;
|
|
/** @var bool */
|
|
public $hasEduFeaturesEnabled = false;
|
|
/** @var float */
|
|
public $rainLevel;
|
|
/** @var float */
|
|
public $lightningLevel;
|
|
/** @var bool */
|
|
public $hasConfirmedPlatformLockedContent = false;
|
|
/** @var bool */
|
|
public $isMultiplayerGame = true;
|
|
/** @var bool */
|
|
public $hasLANBroadcast = true;
|
|
/** @var int */
|
|
public $xboxLiveBroadcastMode = 0; //TODO: find values
|
|
/** @var int */
|
|
public $platformBroadcastMode = 0;
|
|
/** @var bool */
|
|
public $commandsEnabled;
|
|
/** @var bool */
|
|
public $isTexturePacksRequired = true;
|
|
/**
|
|
* @var mixed[][]
|
|
* @phpstan-var array<string, array{0: int, 1: bool|int|float}>
|
|
*/
|
|
public $gameRules = [ //TODO: implement this
|
|
"naturalregeneration" => [1, false] //Hack for client side regeneration
|
|
];
|
|
/** @var bool */
|
|
public $hasBonusChestEnabled = false;
|
|
/** @var bool */
|
|
public $hasStartWithMapEnabled = false;
|
|
/** @var int */
|
|
public $defaultPlayerPermission = PlayerPermissions::MEMBER; //TODO
|
|
|
|
/** @var int */
|
|
public $serverChunkTickRadius = 4; //TODO (leave as default for now)
|
|
|
|
/** @var bool */
|
|
public $hasLockedBehaviorPack = false;
|
|
/** @var bool */
|
|
public $hasLockedResourcePack = false;
|
|
/** @var bool */
|
|
public $isFromLockedWorldTemplate = false;
|
|
/** @var bool */
|
|
public $useMsaGamertagsOnly = false;
|
|
/** @var bool */
|
|
public $isFromWorldTemplate = false;
|
|
/** @var bool */
|
|
public $isWorldTemplateOptionLocked = false;
|
|
/** @var bool */
|
|
public $onlySpawnV1Villagers = false;
|
|
|
|
/** @var string */
|
|
public $vanillaVersion = ProtocolInfo::MINECRAFT_VERSION_NETWORK;
|
|
/** @var string */
|
|
public $levelId = ""; //base64 string, usually the same as world folder name in vanilla
|
|
/** @var string */
|
|
public $worldName;
|
|
/** @var string */
|
|
public $premiumWorldTemplateId = "";
|
|
/** @var bool */
|
|
public $isTrial = false;
|
|
/** @var bool */
|
|
public $isMovementServerAuthoritative = false;
|
|
/** @var int */
|
|
public $currentTick = 0; //only used if isTrial is true
|
|
/** @var int */
|
|
public $enchantmentSeed = 0;
|
|
/** @var string */
|
|
public $multiplayerCorrelationId = ""; //TODO: this should be filled with a UUID of some sort
|
|
|
|
/**
|
|
* @var CacheableNbt
|
|
* @phpstan-var CacheableNbt<\pocketmine\nbt\tag\ListTag>
|
|
*/
|
|
public $blockTable;
|
|
/**
|
|
* @var int[]|null string (name) => int16 (legacyID)
|
|
* @phpstan-var array<string, int>|null
|
|
*/
|
|
public $itemTable = null;
|
|
|
|
protected function decodePayload(NetworkBinaryStream $in) : void{
|
|
$this->entityUniqueId = $in->getEntityUniqueId();
|
|
$this->entityRuntimeId = $in->getEntityRuntimeId();
|
|
$this->playerGamemode = $in->getVarInt();
|
|
|
|
$this->playerPosition = $in->getVector3();
|
|
|
|
$this->pitch = $in->getLFloat();
|
|
$this->yaw = $in->getLFloat();
|
|
|
|
//Level settings
|
|
$this->seed = $in->getVarInt();
|
|
$this->dimension = $in->getVarInt();
|
|
$this->generator = $in->getVarInt();
|
|
$this->worldGamemode = $in->getVarInt();
|
|
$this->difficulty = $in->getVarInt();
|
|
$in->getBlockPosition($this->spawnX, $this->spawnY, $this->spawnZ);
|
|
$this->hasAchievementsDisabled = $in->getBool();
|
|
$this->time = $in->getVarInt();
|
|
$this->eduEditionOffer = $in->getVarInt();
|
|
$this->hasEduFeaturesEnabled = $in->getBool();
|
|
$this->rainLevel = $in->getLFloat();
|
|
$this->lightningLevel = $in->getLFloat();
|
|
$this->hasConfirmedPlatformLockedContent = $in->getBool();
|
|
$this->isMultiplayerGame = $in->getBool();
|
|
$this->hasLANBroadcast = $in->getBool();
|
|
$this->xboxLiveBroadcastMode = $in->getVarInt();
|
|
$this->platformBroadcastMode = $in->getVarInt();
|
|
$this->commandsEnabled = $in->getBool();
|
|
$this->isTexturePacksRequired = $in->getBool();
|
|
$this->gameRules = $in->getGameRules();
|
|
$this->hasBonusChestEnabled = $in->getBool();
|
|
$this->hasStartWithMapEnabled = $in->getBool();
|
|
$this->defaultPlayerPermission = $in->getVarInt();
|
|
$this->serverChunkTickRadius = $in->getLInt();
|
|
$this->hasLockedBehaviorPack = $in->getBool();
|
|
$this->hasLockedResourcePack = $in->getBool();
|
|
$this->isFromLockedWorldTemplate = $in->getBool();
|
|
$this->useMsaGamertagsOnly = $in->getBool();
|
|
$this->isFromWorldTemplate = $in->getBool();
|
|
$this->isWorldTemplateOptionLocked = $in->getBool();
|
|
$this->onlySpawnV1Villagers = $in->getBool();
|
|
|
|
$this->vanillaVersion = $in->getString();
|
|
$this->levelId = $in->getString();
|
|
$this->worldName = $in->getString();
|
|
$this->premiumWorldTemplateId = $in->getString();
|
|
$this->isTrial = $in->getBool();
|
|
$this->isMovementServerAuthoritative = $in->getBool();
|
|
$this->currentTick = $in->getLLong();
|
|
|
|
$this->enchantmentSeed = $in->getVarInt();
|
|
|
|
$blockTable = $in->getNbtRoot()->getTag();
|
|
if(!($blockTable instanceof ListTag)){
|
|
throw new \UnexpectedValueException("Wrong block table root NBT tag type");
|
|
}
|
|
$this->blockTable = new CacheableNbt($blockTable);
|
|
|
|
$this->itemTable = [];
|
|
for($i = 0, $count = $in->getUnsignedVarInt(); $i < $count; ++$i){
|
|
$id = $in->getString();
|
|
$legacyId = $in->getSignedLShort();
|
|
|
|
$this->itemTable[$id] = $legacyId;
|
|
}
|
|
|
|
$this->multiplayerCorrelationId = $in->getString();
|
|
}
|
|
|
|
protected function encodePayload(NetworkBinaryStream $out) : void{
|
|
$out->putEntityUniqueId($this->entityUniqueId);
|
|
$out->putEntityRuntimeId($this->entityRuntimeId);
|
|
$out->putVarInt($this->playerGamemode);
|
|
|
|
$out->putVector3($this->playerPosition);
|
|
|
|
$out->putLFloat($this->pitch);
|
|
$out->putLFloat($this->yaw);
|
|
|
|
//Level settings
|
|
$out->putVarInt($this->seed);
|
|
$out->putVarInt($this->dimension);
|
|
$out->putVarInt($this->generator);
|
|
$out->putVarInt($this->worldGamemode);
|
|
$out->putVarInt($this->difficulty);
|
|
$out->putBlockPosition($this->spawnX, $this->spawnY, $this->spawnZ);
|
|
$out->putBool($this->hasAchievementsDisabled);
|
|
$out->putVarInt($this->time);
|
|
$out->putVarInt($this->eduEditionOffer);
|
|
$out->putBool($this->hasEduFeaturesEnabled);
|
|
$out->putLFloat($this->rainLevel);
|
|
$out->putLFloat($this->lightningLevel);
|
|
$out->putBool($this->hasConfirmedPlatformLockedContent);
|
|
$out->putBool($this->isMultiplayerGame);
|
|
$out->putBool($this->hasLANBroadcast);
|
|
$out->putVarInt($this->xboxLiveBroadcastMode);
|
|
$out->putVarInt($this->platformBroadcastMode);
|
|
$out->putBool($this->commandsEnabled);
|
|
$out->putBool($this->isTexturePacksRequired);
|
|
$out->putGameRules($this->gameRules);
|
|
$out->putBool($this->hasBonusChestEnabled);
|
|
$out->putBool($this->hasStartWithMapEnabled);
|
|
$out->putVarInt($this->defaultPlayerPermission);
|
|
$out->putLInt($this->serverChunkTickRadius);
|
|
$out->putBool($this->hasLockedBehaviorPack);
|
|
$out->putBool($this->hasLockedResourcePack);
|
|
$out->putBool($this->isFromLockedWorldTemplate);
|
|
$out->putBool($this->useMsaGamertagsOnly);
|
|
$out->putBool($this->isFromWorldTemplate);
|
|
$out->putBool($this->isWorldTemplateOptionLocked);
|
|
$out->putBool($this->onlySpawnV1Villagers);
|
|
|
|
$out->putString($this->vanillaVersion);
|
|
$out->putString($this->levelId);
|
|
$out->putString($this->worldName);
|
|
$out->putString($this->premiumWorldTemplateId);
|
|
$out->putBool($this->isTrial);
|
|
$out->putBool($this->isMovementServerAuthoritative);
|
|
$out->putLLong($this->currentTick);
|
|
|
|
$out->putVarInt($this->enchantmentSeed);
|
|
|
|
$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));
|
|
}
|
|
$out->put(self::$itemTableCache);
|
|
}else{
|
|
$out->put(self::serializeItemTable($this->itemTable));
|
|
}
|
|
|
|
$out->putString($this->multiplayerCorrelationId);
|
|
}
|
|
|
|
/**
|
|
* @param int[] $table
|
|
* @phpstan-param array<string, int> $table
|
|
*/
|
|
private static function serializeItemTable(array $table) : string{
|
|
$stream = new NetworkBinaryStream();
|
|
$stream->putUnsignedVarInt(count($table));
|
|
foreach($table as $name => $legacyId){
|
|
$stream->putString($name);
|
|
$stream->putLShort($legacyId);
|
|
}
|
|
return $stream->getBuffer();
|
|
}
|
|
|
|
public function handle(PacketHandlerInterface $handler) : bool{
|
|
return $handler->handleStartGame($this);
|
|
}
|
|
}
|