Merge branch 'mcpe-1.6' into release/3.2

This commit is contained in:
Dylan K. Taylor 2018-08-29 16:23:53 +01:00
commit 888dba704b
18 changed files with 333 additions and 54 deletions

View File

@ -197,9 +197,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
*/
protected $sessionAdapter;
/** @var int */
protected $protocol = -1;
/** @var string */
protected $ip;
/** @var int */
@ -1849,8 +1846,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return false;
}
$this->protocol = $packet->protocol;
if($packet->protocol !== ProtocolInfo::CURRENT_PROTOCOL){
if($packet->protocol < ProtocolInfo::CURRENT_PROTOCOL){
$this->sendPlayStatus(PlayStatusPacket::LOGIN_FAILED_CLIENT, true);
@ -1933,7 +1928,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public function sendPlayStatus(int $status, bool $immediate = false){
$pk = new PlayStatusPacket();
$pk->status = $status;
$pk->protocol = $this->protocol;
$this->sendDataPacket($pk, false, $immediate);
}
@ -2041,7 +2035,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
case ResourcePackClientResponsePacket::STATUS_SEND_PACKS:
$manager = $this->server->getResourcePackManager();
foreach($packet->packIds as $uuid){
$pack = $manager->getPackById($uuid);
$pack = $manager->getPackById(substr($uuid, 0, strpos($uuid, "_"))); //dirty hack for mojang's dirty hack for versions
if(!($pack instanceof ResourcePack)){
//Client requested a resource pack but we don't have it available on the server
$this->close("", "disconnectionScreen.resourcePack", true);

View File

@ -421,8 +421,8 @@ class BlockFactory{
public static function registerStaticRuntimeIdMappings() : void{
/** @var mixed[] $runtimeIdMap */
$runtimeIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true);
foreach($runtimeIdMap as $obj){
self::registerMapping($obj["runtimeID"], $obj["id"], $obj["data"]);
foreach($runtimeIdMap as $k => $obj){
self::registerMapping($k, $obj["id"], $obj["data"]);
}
}

View File

@ -79,6 +79,7 @@ use pocketmine\network\mcpe\protocol\ModalFormResponsePacket;
use pocketmine\network\mcpe\protocol\MoveEntityAbsolutePacket;
use pocketmine\network\mcpe\protocol\MoveEntityDeltaPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
use pocketmine\network\mcpe\protocol\NpcRequestPacket;
use pocketmine\network\mcpe\protocol\PhotoTransferPacket;
use pocketmine\network\mcpe\protocol\PlaySoundPacket;
@ -115,6 +116,7 @@ use pocketmine\network\mcpe\protocol\SetLastHurtByPacket;
use pocketmine\network\mcpe\protocol\SetLocalPlayerAsInitializedPacket;
use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
use pocketmine\network\mcpe\protocol\SetScorePacket;
use pocketmine\network\mcpe\protocol\SetScoreboardIdentityPacket;
use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket;
use pocketmine\network\mcpe\protocol\SetTimePacket;
use pocketmine\network\mcpe\protocol\SetTitlePacket;
@ -134,6 +136,7 @@ use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockSyncedPacket;
use pocketmine\network\mcpe\protocol\UpdateEquipPacket;
use pocketmine\network\mcpe\protocol\UpdateSoftEnumPacket;
use pocketmine\network\mcpe\protocol\UpdateTradePacket;
use pocketmine\network\mcpe\protocol\WSConnectPacket;
@ -585,7 +588,19 @@ abstract class NetworkSession{
return false;
}
public function handleSetScoreboardIdentity(SetScoreboardIdentityPacket $packet) : bool{
return false;
}
public function handleSetLocalPlayerAsInitialized(SetLocalPlayerAsInitializedPacket $packet) : bool{
return false;
}
public function handleUpdateSoftEnum(UpdateSoftEnumPacket $packet) : bool{
return false;
}
public function handleNetworkStackLatency(NetworkStackLatencyPacket $packet) : bool{
return false;
}
}

View File

@ -46,7 +46,7 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
* Sometimes this gets changed when the MCPE-layer protocol gets broken to the point where old and new can't
* communicate. It's important that we check this to avoid catastrophes.
*/
private const MCPE_RAKNET_PROTOCOL_VERSION = 8;
private const MCPE_RAKNET_PROTOCOL_VERSION = 9;
/** @var Server */
private $server;

View File

@ -75,6 +75,9 @@ class AddPlayerPacket extends DataPacket{
/** @var EntityLink[] */
public $links = [];
/** @var string */
public $deviceId = ""; //TODO: fill player's device ID (???)
protected function decodePayload(){
$this->uuid = $this->getUUID();
$this->username = $this->getString();
@ -103,6 +106,8 @@ class AddPlayerPacket extends DataPacket{
for($i = 0; $i < $linkCount; ++$i){
$this->links[$i] = $this->getEntityLink();
}
$this->deviceId = $this->getString();
}
protected function encodePayload(){
@ -133,6 +138,8 @@ class AddPlayerPacket extends DataPacket{
foreach($this->links as $link){
$this->putEntityLink($link);
}
$this->putString($this->deviceId);
}
public function handle(NetworkSession $session) : bool{

View File

@ -103,6 +103,13 @@ class AvailableCommandsPacket extends DataPacket{
*/
public $commandData = [];
/**
* @var CommandEnum[]
* List of dynamic command enums, also referred to as "soft" enums. These can by dynamically updated mid-game
* without resending this packet.
*/
public $softEnums = [];
protected function decodePayload(){
for($i = 0, $this->enumValuesCount = $this->getUnsignedVarInt(); $i < $this->enumValuesCount; ++$i){
$this->enumValues[] = $this->getString();
@ -119,6 +126,10 @@ class AvailableCommandsPacket extends DataPacket{
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->commandData[] = $this->getCommandData();
}
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->softEnums[] = $this->getSoftEnum();
}
}
protected function getEnum() : CommandEnum{
@ -133,6 +144,18 @@ class AvailableCommandsPacket extends DataPacket{
return $retval;
}
protected function getSoftEnum() : CommandEnum{
$retval = new CommandEnum();
$retval->enumName = $this->getString();
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
//Get the enum value from the initial pile of mess
$retval->enumValues[] = $this->getString();
}
return $retval;
}
protected function putEnum(CommandEnum $enum){
$this->putString($enum->enumName);
@ -147,6 +170,15 @@ class AvailableCommandsPacket extends DataPacket{
}
}
protected function putSoftEnum(CommandEnum $enum) : void{
$this->putString($enum->enumName);
$this->putUnsignedVarInt(count($enum->enumValues));
foreach($enum->enumValues as $value){
$this->putString($value);
}
}
protected function getEnumValueIndex() : int{
if($this->enumValuesCount < 256){
return $this->getByte();
@ -185,13 +217,17 @@ class AvailableCommandsPacket extends DataPacket{
if($parameter->paramType & self::ARG_FLAG_ENUM){
$index = ($parameter->paramType & 0xffff);
$parameter->enum = $this->enums[$index] ?? null;
assert($parameter->enum !== null, "expected enum at $index, but got none");
}elseif(($parameter->paramType & self::ARG_FLAG_VALID) === 0){ //postfix (guessing)
if($parameter->enum === null){
throw new \UnexpectedValueException("expected enum at $index, but got none");
}
}elseif($parameter->paramType & self::ARG_FLAG_POSTFIX){
$index = ($parameter->paramType & 0xffff);
$parameter->postfix = $this->postfixes[$index] ?? null;
assert($parameter->postfix !== null, "expected postfix at $index, but got none");
if($parameter->postfix === null){
throw new \UnexpectedValueException("expected postfix at $index, but got none");
}
}elseif(($parameter->paramType & self::ARG_FLAG_VALID) === 0){
throw new \UnexpectedValueException("Invalid parameter type 0x" . dechex($parameter->paramType));
}
$retval->overloads[$overloadIndex][$paramIndex] = $parameter;
@ -227,7 +263,7 @@ class AvailableCommandsPacket extends DataPacket{
if($key === false){
throw new \InvalidStateException("Postfix '$parameter->postfix' not in postfixes array");
}
$type = $parameter->paramType << 24 | $key;
$type = self::ARG_FLAG_POSTFIX | $key;
}else{
$type = $parameter->paramType;
}
@ -266,13 +302,12 @@ class AvailableCommandsPacket extends DataPacket{
case self::ARG_TYPE_COMMAND:
return "command";
}
}elseif($argtype !== 0){
//guessed
$baseType = $argtype >> 24;
$typeName = $this->argTypeToString(self::ARG_FLAG_VALID | $baseType);
}elseif($argtype & self::ARG_FLAG_POSTFIX){
$postfix = $this->postfixes[$argtype & 0xffff];
return $typeName . " (postfix $postfix)";
return "int (postfix $postfix)";
}else{
throw new \UnexpectedValueException("Unknown arg type 0x" . dechex($argtype));
}
return "unknown ($argtype)";
@ -334,6 +369,11 @@ class AvailableCommandsPacket extends DataPacket{
foreach($this->commandData as $data){
$this->putCommandData($data);
}
$this->putUnsignedVarInt(count($this->softEnums));
foreach($this->softEnums as $enum){
$this->putSoftEnum($enum);
}
}
public function handle(NetworkSession $session) : bool{

View File

@ -74,10 +74,6 @@ abstract class DataPacket extends NetworkBinaryStream{
protected function decodeHeader(){
$pid = $this->getUnsignedVarInt();
assert($pid === static::NETWORK_ID);
$this->senderSubId = $this->getByte();
$this->recipientSubId = $this->getByte();
assert($this->senderSubId === 0 and $this->recipientSubId === 0, "Got unexpected non-zero split-screen bytes (byte1: $this->senderSubId, byte2: $this->recipientSubId");
}
/**
@ -96,9 +92,6 @@ abstract class DataPacket extends NetworkBinaryStream{
protected function encodeHeader(){
$this->putUnsignedVarInt(static::NETWORK_ID);
$this->putByte($this->senderSubId);
$this->putByte($this->recipientSubId);
}
/**

View File

@ -79,13 +79,6 @@ class LoginPacket extends DataPacket{
protected function decodePayload(){
$this->protocol = $this->getInt();
if($this->protocol !== ProtocolInfo::CURRENT_PROTOCOL){
if($this->protocol > 0xffff){ //guess MCPE <= 1.1
$this->offset -= 6;
$this->protocol = $this->getInt();
}
}
try{
$this->decodeConnectionRequest();
}catch(\Throwable $e){

View File

@ -0,0 +1,47 @@
<?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\network\mcpe\NetworkSession;
class NetworkStackLatencyPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::NETWORK_STACK_LATENCY_PACKET;
/** @var int */
public $timestamp;
protected function decodePayload(){
$this->timestamp = $this->getLLong();
}
protected function encodePayload(){
$this->putLLong($this->timestamp);
}
public function handle(NetworkSession $session) : bool{
return $session->handleNetworkStackLatency($this);
}
}

View File

@ -142,7 +142,10 @@ class PacketPool{
static::registerPacket(new LabTablePacket());
static::registerPacket(new UpdateBlockSyncedPacket());
static::registerPacket(new MoveEntityDeltaPacket());
static::registerPacket(new SetScoreboardIdentityPacket());
static::registerPacket(new SetLocalPlayerAsInitializedPacket());
static::registerPacket(new UpdateSoftEnumPacket());
static::registerPacket(new NetworkStackLatencyPacket());
static::registerPacket(new BatchPacket());
}

View File

@ -43,12 +43,6 @@ class PlayStatusPacket extends DataPacket{
/** @var int */
public $status;
/**
* @var int
* Used to determine how to write the packet when we disconnect incompatible clients.
*/
public $protocol = ProtocolInfo::CURRENT_PROTOCOL;
protected function decodePayload(){
$this->status = $this->getInt();
}
@ -57,14 +51,6 @@ class PlayStatusPacket extends DataPacket{
return true;
}
protected function encodeHeader(){
if($this->protocol < 130){ //MCPE <= 1.1
$this->putByte(static::NETWORK_ID);
}else{
parent::encodeHeader();
}
}
protected function encodePayload(){
$this->putInt($this->status);
}

View File

@ -39,15 +39,15 @@ interface ProtocolInfo{
/**
* Actual Minecraft: PE protocol version
*/
public const CURRENT_PROTOCOL = 274;
public const CURRENT_PROTOCOL = 282;
/**
* Current Minecraft PE version reported by the server. This is usually the earliest currently supported version.
*/
public const MINECRAFT_VERSION = 'v1.5.0';
public const MINECRAFT_VERSION = 'v1.6.0.8 beta';
/**
* Version number sent to clients in ping responses.
*/
public const MINECRAFT_VERSION_NETWORK = '1.5.0';
public const MINECRAFT_VERSION_NETWORK = '1.6.0.8';
public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02;
@ -160,6 +160,9 @@ interface ProtocolInfo{
public const LAB_TABLE_PACKET = 0x6d;
public const UPDATE_BLOCK_SYNCED_PACKET = 0x6e;
public const MOVE_ENTITY_DELTA_PACKET = 0x6f;
public const SET_LOCAL_PLAYER_AS_INITIALIZED_PACKET = 0x70;
public const SET_SCOREBOARD_IDENTITY_PACKET = 0x70;
public const SET_LOCAL_PLAYER_AS_INITIALIZED_PACKET = 0x71;
public const UPDATE_SOFT_ENUM_PACKET = 0x72;
public const NETWORK_STACK_LATENCY_PACKET = 0x73;
}

View File

@ -70,6 +70,7 @@ class ResourcePacksInfoPacket extends DataPacket{
$this->putLLong($entry->getPackSize());
$this->putString(""); //TODO: encryption key
$this->putString(""); //TODO: subpack name
$this->putString(""); //TODO: content identity
}
$this->putLShort(count($this->resourcePackEntries));
foreach($this->resourcePackEntries as $entry){
@ -78,6 +79,7 @@ class ResourcePacksInfoPacket extends DataPacket{
$this->putLLong($entry->getPackSize());
$this->putString(""); //TODO: encryption key
$this->putString(""); //TODO: subpack name
$this->putString(""); //TODO: content identity
}
}

View File

@ -0,0 +1,69 @@
<?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\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ScoreboardIdentityPacketEntry;
class SetScoreboardIdentityPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SET_SCOREBOARD_IDENTITY_PACKET;
public const TYPE_REGISTER_IDENTITY = 0;
public const TYPE_CLEAR_IDENTITY = 1;
/** @var int */
public $type;
/** @var ScoreboardIdentityPacketEntry[] */
public $entries = [];
protected function decodePayload(){
$this->type = $this->getByte();
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$entry = new ScoreboardIdentityPacketEntry();
$entry->scoreboardId = $this->getVarLong();
if($this->type === self::TYPE_REGISTER_IDENTITY){
$entry->uuid = $this->getUUID();
}
$this->entries[] = $entry;
}
}
protected function encodePayload(){
$this->putByte($this->type);
$this->putUnsignedVarInt(count($this->entries));
foreach($this->entries as $entry){
$this->putVarLong($entry->scoreboardId);
if($this->type === self::TYPE_REGISTER_IDENTITY){
$this->putUUID($entry->uuid);
}
}
}
public function handle(NetworkSession $session) : bool{
return $session->handleSetScoreboardIdentity($this);
}
}

View File

@ -27,12 +27,16 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
class StartGamePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::START_GAME_PACKET;
/** @var string|null */
private static $runtimeIdTable;
/** @var int */
public $entityUniqueId;
/** @var int */
@ -125,6 +129,8 @@ class StartGamePacket extends DataPacket{
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
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
@ -175,6 +181,14 @@ class StartGamePacket extends DataPacket{
$this->currentTick = $this->getLLong();
$this->enchantmentSeed = $this->getVarInt();
$count = $this->getUnsignedVarInt();
for($i = 0; $i < $count; ++$i){
$this->getString();
$this->getLShort();
}
$this->multiplayerCorrelationId = $this->getString();
}
protected function encodePayload(){
@ -226,6 +240,21 @@ class StartGamePacket extends DataPacket{
$this->putLLong($this->currentTick);
$this->putVarInt($this->enchantmentSeed);
if(self::$runtimeIdTable === null){
//this is a really nasty hack, but it'll do for now
$stream = new NetworkBinaryStream();
$data = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true);
$stream->putUnsignedVarInt(count($data));
foreach($data as $v){
$stream->putString($v["name"]);
$stream->putLShort($v["data"]);
}
self::$runtimeIdTable = $stream->buffer;
}
$this->put(self::$runtimeIdTable);
$this->putString($this->multiplayerCorrelationId);
}
public function handle(NetworkSession $session) : bool{

View File

@ -0,0 +1,64 @@
<?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\network\mcpe\NetworkSession;
class UpdateSoftEnumPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::UPDATE_SOFT_ENUM_PACKET;
public const TYPE_ADD = 0;
public const TYPE_REMOVE = 1;
public const TYPE_SET = 2;
/** @var string */
public $enumName;
/** @var string[] */
public $values = [];
/** @var int */
public $type;
protected function decodePayload(){
$this->enumName = $this->getString();
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->values[] = $this->getString();
}
$this->type = $this->getByte();
}
protected function encodePayload(){
$this->putString($this->enumName);
$this->putUnsignedVarInt(count($this->values));
foreach($this->values as $v){
$this->putString($v);
}
$this->putByte($this->type);
}
public function handle(NetworkSession $session) : bool{
return $session->handleUpdateSoftEnum($this);
}
}

View File

@ -0,0 +1,34 @@
<?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\types;
use pocketmine\utils\UUID;
class ScoreboardIdentityPacketEntry{
/** @var int */
public $scoreboardId;
/** @var UUID|null */
public $uuid;
}

File diff suppressed because one or more lines are too long