Compare commits

..

3 Commits

Author SHA1 Message Date
7f1b2a0ee5 Release 3.23.0 2021-09-22 00:29:24 +01:00
27324a3aeb Protocol changes for 1.17.30 2021-09-22 00:26:39 +01:00
33b5da3749 3.22.6 is next 2021-09-10 17:09:51 +01:00
27 changed files with 827 additions and 41 deletions

11
changelogs/3.23.md Normal file
View File

@ -0,0 +1,11 @@
**For Minecraft: Bedrock Edition 1.17.30**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 3.23.0
- Added support for Minecraft: Bedrock Edition 1.17.30.
- Removed compatibility with earlier versions.

View File

@ -1976,17 +1976,19 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
base64_decode($packet->clientData["CapeData"] ?? "", true)
),
base64_decode($packet->clientData["SkinGeometryData"] ?? "", true),
base64_decode($packet->clientData["SkinGeometryDataEngineVersion"], true),
base64_decode($packet->clientData["SkinAnimationData"] ?? "", true),
$packet->clientData["PremiumSkin"] ?? false,
$packet->clientData["PersonaSkin"] ?? false,
$packet->clientData["CapeOnClassicSkin"] ?? false,
$packet->clientData["CapeId"] ?? "",
null,
$packet->clientData["ArmSize"] ?? SkinData::ARM_SIZE_WIDE,
$packet->clientData["SkinColor"] ?? "",
$personaPieces,
$pieceTintColors,
true
true,
$packet->clientData["PremiumSkin"] ?? false,
$packet->clientData["PersonaSkin"] ?? false,
$packet->clientData["CapeOnClassicSkin"] ?? false,
true, //assume this is true? there's no field for it ...
);
try{

View File

@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
const _VERSION_INFO_INCLUDED = true;
const NAME = "PocketMine-MP";
const BASE_VERSION = "3.22.5";
const BASE_VERSION = "3.23.0";
const IS_DEVELOPMENT_BUILD = false;
const BUILD_NUMBER = 0;
const BUILD_CHANNEL = "stable";

View File

@ -105,10 +105,8 @@ class NetworkBinaryStream extends BinaryStream{
}
$capeData = $this->getSkinImage();
$geometryData = $this->getString();
$geometryDataVersion = $this->getString();
$animationData = $this->getString();
$premium = $this->getBool();
$persona = $this->getBool();
$capeOnClassic = $this->getBool();
$capeId = $this->getString();
$fullSkinId = $this->getString();
$armSize = $this->getString();
@ -137,8 +135,12 @@ class NetworkBinaryStream extends BinaryStream{
$colors
);
}
$premium = $this->getBool();
$persona = $this->getBool();
$capeOnClassic = $this->getBool();
$isPrimaryUser = $this->getBool();
return new SkinData($skinId, $skinPlayFabId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId, $fullSkinId, $armSize, $skinColor, $personaPieces, $pieceTintColors);
return new SkinData($skinId, $skinPlayFabId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $geometryDataVersion, $animationData, $capeId, $fullSkinId, $armSize, $skinColor, $personaPieces, $pieceTintColors, true, $premium, $persona, $capeOnClassic, $isPrimaryUser);
}
/**
@ -158,10 +160,8 @@ class NetworkBinaryStream extends BinaryStream{
}
$this->putSkinImage($skin->getCapeImage());
$this->putString($skin->getGeometryData());
$this->putString($skin->getGeometryDataEngineVersion());
$this->putString($skin->getAnimationData());
$this->putBool($skin->isPremium());
$this->putBool($skin->isPersona());
$this->putBool($skin->isPersonaCapeOnClassic());
$this->putString($skin->getCapeId());
$this->putString($skin->getFullSkinId());
$this->putString($skin->getArmSize());
@ -182,6 +182,10 @@ class NetworkBinaryStream extends BinaryStream{
$this->putString($color);
}
}
$this->putBool($skin->isPremium());
$this->putBool($skin->isPersona());
$this->putBool($skin->isPersonaCapeOnClassic());
$this->putBool($skin->isPrimaryUser());
}
private function getSkinImage() : SkinImage{

View File

@ -66,11 +66,13 @@ use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
use pocketmine\network\mcpe\protocol\CorrectPlayerMovePredictionPacket;
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\CreatePhotoPacket;
use pocketmine\network\mcpe\protocol\CreativeContentPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DebugInfoPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\EducationSettingsPacket;
use pocketmine\network\mcpe\protocol\EduUriResourcePacket;
use pocketmine\network\mcpe\protocol\EmoteListPacket;
use pocketmine\network\mcpe\protocol\EmotePacket;
use pocketmine\network\mcpe\protocol\EventPacket;
@ -114,6 +116,7 @@ use pocketmine\network\mcpe\protocol\NpcDialoguePacket;
use pocketmine\network\mcpe\protocol\NpcRequestPacket;
use pocketmine\network\mcpe\protocol\OnScreenTextureAnimationPacket;
use pocketmine\network\mcpe\protocol\PacketViolationWarningPacket;
use pocketmine\network\mcpe\protocol\PhotoInfoRequestPacket;
use pocketmine\network\mcpe\protocol\PhotoTransferPacket;
use pocketmine\network\mcpe\protocol\PlayerActionPacket;
use pocketmine\network\mcpe\protocol\PlayerArmorDamagePacket;
@ -187,6 +190,7 @@ use pocketmine\network\mcpe\protocol\UpdateBlockSyncedPacket;
use pocketmine\network\mcpe\protocol\UpdateEquipPacket;
use pocketmine\network\mcpe\protocol\UpdatePlayerGameTypePacket;
use pocketmine\network\mcpe\protocol\UpdateSoftEnumPacket;
use pocketmine\network\mcpe\protocol\UpdateSubChunkBlocksPacket;
use pocketmine\network\mcpe\protocol\UpdateTradePacket;
abstract class NetworkSession{
@ -851,4 +855,20 @@ abstract class NetworkSession{
public function handleNpcDialogue(NpcDialoguePacket $packet) : bool{
return false;
}
public function handleEduUriResource(EduUriResourcePacket $packet) : bool{
return false;
}
public function handleCreatePhoto(CreatePhotoPacket $packet) : bool{
return false;
}
public function handleUpdateSubChunkBlocks(UpdateSubChunkBlocksPacket $packet) : bool{
return false;
}
public function handlePhotoInfoRequest(PhotoInfoRequestPacket $packet) : bool{
return false;
}
}

View File

@ -34,15 +34,19 @@ class ActorPickRequestPacket extends DataPacket{
public $entityUniqueId;
/** @var int */
public $hotbarSlot;
/** @var bool */
public $addUserData;
protected function decodePayload(){
$this->entityUniqueId = $this->getLLong();
$this->hotbarSlot = $this->getByte();
$this->addUserData = $this->getBool();
}
protected function encodePayload(){
$this->putLLong($this->entityUniqueId);
$this->putByte($this->hotbarSlot);
$this->putBool($this->addUserData);
}
public function handle(NetworkSession $session) : bool{

View File

@ -36,11 +36,14 @@ class AddVolumeEntityPacket extends DataPacket{
private $entityNetId;
/** @var CompoundTag */
private $data;
/** @var string */
private $engineVersion;
public static function create(int $entityNetId, CompoundTag $data) : self{
public static function create(int $entityNetId, CompoundTag $data, string $engineVersion) : self{
$result = new self;
$result->entityNetId = $entityNetId;
$result->data = $data;
$result->engineVersion = $engineVersion;
return $result;
}
@ -48,14 +51,18 @@ class AddVolumeEntityPacket extends DataPacket{
public function getData() : CompoundTag{ return $this->data; }
public function getEngineVersion() : string{ return $this->engineVersion; }
protected function decodePayload() : void{
$this->entityNetId = $this->getUnsignedVarInt();
$this->data = $this->getNbtCompoundRoot();
$this->engineVersion = $this->getString();
}
protected function encodePayload() : void{
$this->putUnsignedVarInt($this->entityNetId);
$this->put((new NetworkLittleEndianNBTStream())->write($this->data));
$this->putString($this->engineVersion);
}
public function handle(NetworkSession $handler) : bool{

View File

@ -37,6 +37,8 @@ class AnimateEntityPacket extends DataPacket/* implements ClientboundPacket*/{
private $nextState;
/** @var string */
private $stopExpression;
/** @var int */
private $stopExpressionVersion;
/** @var string */
private $controller;
/** @var float */
@ -51,11 +53,12 @@ class AnimateEntityPacket extends DataPacket/* implements ClientboundPacket*/{
* @param int[] $actorRuntimeIds
* @phpstan-param list<int> $actorRuntimeIds
*/
public static function create(string $animation, string $nextState, string $stopExpression, string $controller, float $blendOutTime, array $actorRuntimeIds) : self{
public static function create(string $animation, string $nextState, string $stopExpression, int $stopExpressionVersion, string $controller, float $blendOutTime, array $actorRuntimeIds) : self{
$result = new self;
$result->animation = $animation;
$result->nextState = $nextState;
$result->stopExpression = $stopExpression;
$result->stopExpressionVersion = $stopExpressionVersion;
$result->controller = $controller;
$result->blendOutTime = $blendOutTime;
$result->actorRuntimeIds = $actorRuntimeIds;
@ -68,6 +71,8 @@ class AnimateEntityPacket extends DataPacket/* implements ClientboundPacket*/{
public function getStopExpression() : string{ return $this->stopExpression; }
public function getStopExpressionVersion() : int{ return $this->stopExpressionVersion; }
public function getController() : string{ return $this->controller; }
public function getBlendOutTime() : float{ return $this->blendOutTime; }
@ -82,6 +87,7 @@ class AnimateEntityPacket extends DataPacket/* implements ClientboundPacket*/{
$this->animation = $this->getString();
$this->nextState = $this->getString();
$this->stopExpression = $this->getString();
$this->stopExpressionVersion = $this->getLInt();
$this->controller = $this->getString();
$this->blendOutTime = $this->getLFloat();
$this->actorRuntimeIds = [];
@ -94,6 +100,7 @@ class AnimateEntityPacket extends DataPacket/* implements ClientboundPacket*/{
$this->putString($this->animation);
$this->putString($this->nextState);
$this->putString($this->stopExpression);
$this->putLInt($this->stopExpressionVersion);
$this->putString($this->controller);
$this->putLFloat($this->blendOutTime);
$this->putUnsignedVarInt(count($this->actorRuntimeIds));

View File

@ -32,6 +32,8 @@ use pocketmine\item\ItemFactory;
use pocketmine\network\mcpe\convert\ItemTranslator;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\MaterialReducerRecipe;
use pocketmine\network\mcpe\protocol\types\MaterialReducerRecipeOutput;
use pocketmine\network\mcpe\protocol\types\PotionContainerChangeRecipe;
use pocketmine\network\mcpe\protocol\types\PotionTypeRecipe;
#ifndef COMPILE
@ -58,6 +60,8 @@ class CraftingDataPacket extends DataPacket{
public $potionTypeRecipes = [];
/** @var PotionContainerChangeRecipe[] */
public $potionContainerRecipes = [];
/** @var MaterialReducerRecipe[] */
public $materialReducerRecipes = [];
/** @var bool */
public $cleanRecipes = false;
@ -169,6 +173,17 @@ class CraftingDataPacket extends DataPacket{
[$output, ] = ItemTranslator::getInstance()->fromNetworkId($outputIdNet, 0);
$this->potionContainerRecipes[] = new PotionContainerChangeRecipe($input, $ingredient, $output);
}
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$inputIdAndData = $this->getVarInt();
[$inputId, $inputMeta] = [$inputIdAndData >> 16, $inputIdAndData & 0x7fff];
$outputs = [];
for($j = 0, $outputCount = $this->getUnsignedVarInt(); $j < $outputCount; ++$j){
$outputItemId = $this->getVarInt();
$outputItemCount = $this->getVarInt();
$outputs[] = new MaterialReducerRecipeOutput($outputItemId, $outputItemCount);
}
$this->materialReducerRecipes[] = new MaterialReducerRecipe($inputId, $inputMeta, $outputs);
}
$this->cleanRecipes = $this->getBool();
}
@ -301,6 +316,15 @@ class CraftingDataPacket extends DataPacket{
$this->putVarInt($recipe->getIngredientItemId());
$this->putVarInt($recipe->getOutputItemId());
}
$this->putUnsignedVarInt(count($this->materialReducerRecipes));
foreach($this->materialReducerRecipes as $recipe){
$this->putVarInt(($recipe->getInputItemId() << 16) | $recipe->getInputItemMeta());
$this->putUnsignedVarInt(count($recipe->getOutputs()));
foreach($recipe->getOutputs() as $output){
$this->putVarInt($output->getItemId());
$this->putVarInt($output->getCount());
}
}
$this->putBool($this->cleanRecipes);
}

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;
class CreatePhotoPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::CREATE_PHOTO_PACKET;
private int $entityUniqueId;
private string $photoName;
private string $photoItemName;
public static function create(int $actorUniqueId, string $photoName, string $photoItemName) : self{
$result = new self;
$result->entityUniqueId = $actorUniqueId;
$result->photoName = $photoName;
$result->photoItemName = $photoItemName;
return $result;
}
/**
* TODO: rename this to getEntityUniqueId() on PM4 (shit architecture, thanks shoghi)
*/
public function getEntityUniqueIdField() : int{ return $this->entityUniqueId; }
public function getPhotoName() : string{ return $this->photoName; }
public function getPhotoItemName() : string{ return $this->photoItemName; }
protected function decodePayload() : void{
$this->entityUniqueId = $this->getLLong(); //why be consistent mojang ?????
$this->photoName = $this->getString();
$this->photoItemName = $this->getString();
}
protected function encodePayload() : void{
$this->putLLong($this->entityUniqueId);
$this->putString($this->photoName);
$this->putString($this->photoItemName);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleCreatePhoto($this);
}
}

View File

@ -0,0 +1,55 @@
<?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\EducationUriResource;
class EduUriResourcePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::EDU_URI_RESOURCE_PACKET;
private EducationUriResource $resource;
public static function create(EducationUriResource $resource) : self{
$result = new self;
$result->resource = $resource;
return $result;
}
public function getResource() : EducationUriResource{ return $this->resource; }
protected function decodePayload() : void{
$this->resource = EducationUriResource::read($this);
}
protected function encodePayload() : void{
$this->resource->write($this);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleEduUriResource($this);
}
}

View File

@ -26,6 +26,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\EducationSettingsAgentCapabilities;
use pocketmine\network\mcpe\protocol\types\EducationSettingsExternalLinkSettings;
class EducationSettingsPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::EDUCATION_SETTINGS_PACKET;
@ -36,18 +38,44 @@ class EducationSettingsPacket extends DataPacket{
private $codeBuilderTitle;
/** @var bool */
private $canResizeCodeBuilder;
/** @var bool */
private $disableLegacyTitleBar;
/** @var string */
private $postProcessFilter;
/** @var string */
private $screenshotBorderResourcePath;
/** @var EducationSettingsAgentCapabilities|null */
private $agentCapabilities;
/** @var string|null */
private $codeBuilderOverrideUri;
/** @var bool */
private $hasQuiz;
/** @var EducationSettingsExternalLinkSettings|null */
private $linkSettings;
public static function create(string $codeBuilderDefaultUri, string $codeBuilderTitle, bool $canResizeCodeBuilder, ?string $codeBuilderOverrideUri, bool $hasQuiz) : self{
public static function create(
string $codeBuilderDefaultUri,
string $codeBuilderTitle,
bool $canResizeCodeBuilder,
bool $disableLegacyTitleBar,
string $postProcessFilter,
string $screenshotBorderResourcePath,
?EducationSettingsAgentCapabilities $agentCapabilities,
?string $codeBuilderOverrideUri,
bool $hasQuiz,
?EducationSettingsExternalLinkSettings $linkSettings
) : self{
$result = new self;
$result->codeBuilderDefaultUri = $codeBuilderDefaultUri;
$result->codeBuilderTitle = $codeBuilderTitle;
$result->canResizeCodeBuilder = $canResizeCodeBuilder;
$result->disableLegacyTitleBar = $disableLegacyTitleBar;
$result->postProcessFilter = $postProcessFilter;
$result->screenshotBorderResourcePath = $screenshotBorderResourcePath;
$result->agentCapabilities = $agentCapabilities;
$result->codeBuilderOverrideUri = $codeBuilderOverrideUri;
$result->hasQuiz = $hasQuiz;
$result->linkSettings = $linkSettings;
return $result;
}
@ -63,6 +91,14 @@ class EducationSettingsPacket extends DataPacket{
return $this->canResizeCodeBuilder;
}
public function disableLegacyTitleBar() : bool{ return $this->disableLegacyTitleBar; }
public function getPostProcessFilter() : string{ return $this->postProcessFilter; }
public function getScreenshotBorderResourcePath() : string{ return $this->screenshotBorderResourcePath; }
public function getAgentCapabilities() : ?EducationSettingsAgentCapabilities{ return $this->agentCapabilities; }
public function getCodeBuilderOverrideUri() : ?string{
return $this->codeBuilderOverrideUri;
}
@ -71,27 +107,49 @@ class EducationSettingsPacket extends DataPacket{
return $this->hasQuiz;
}
public function getLinkSettings() : ?EducationSettingsExternalLinkSettings{ return $this->linkSettings; }
protected function decodePayload() : void{
$this->codeBuilderDefaultUri = $this->getString();
$this->codeBuilderTitle = $this->getString();
$this->canResizeCodeBuilder = $this->getBool();
$this->disableLegacyTitleBar = $this->getBool();
$this->postProcessFilter = $this->getString();
$this->screenshotBorderResourcePath = $this->getString();
$this->agentCapabilities = $this->getBool() ? EducationSettingsAgentCapabilities::read($this) : null;
if($this->getBool()){
$this->codeBuilderOverrideUri = $this->getString();
}else{
$this->codeBuilderOverrideUri = null;
}
$this->hasQuiz = $this->getBool();
$this->linkSettings = $this->getBool() ? EducationSettingsExternalLinkSettings::read($this) : null;
}
protected function encodePayload() : void{
$this->putString($this->codeBuilderDefaultUri);
$this->putString($this->codeBuilderTitle);
$this->putBool($this->canResizeCodeBuilder);
$this->putBool($this->disableLegacyTitleBar);
$this->putString($this->postProcessFilter);
$this->putString($this->screenshotBorderResourcePath);
if($this->agentCapabilities !== null){
$this->putBool(true);
$this->agentCapabilities->write($this);
}else{
$this->putBool(false);
}
$this->putBool($this->codeBuilderOverrideUri !== null);
if($this->codeBuilderOverrideUri !== null){
$this->putString($this->codeBuilderOverrideUri);
}
$this->putBool($this->hasQuiz);
if($this->linkSettings !== null){
$this->putBool(true);
$this->linkSettings->write($this);
}else{
$this->putBool(false);
}
}
public function handle(NetworkSession $handler) : bool{

View File

@ -34,15 +34,19 @@ class HurtArmorPacket extends DataPacket{
public $cause;
/** @var int */
public $health;
/** @var int */
public $armorSlotFlags;
protected function decodePayload(){
$this->cause = $this->getVarInt();
$this->health = $this->getVarInt();
$this->armorSlotFlags = $this->getUnsignedVarLong();
}
protected function encodePayload(){
$this->putVarInt($this->cause);
$this->putVarInt($this->health);
$this->putUnsignedVarLong($this->armorSlotFlags);
}
public function handle(NetworkSession $session) : bool{

View File

@ -200,6 +200,10 @@ class PacketPool{
static::registerPacket(new RemoveVolumeEntityPacket());
static::registerPacket(new SimulationTypePacket());
static::registerPacket(new NpcDialoguePacket());
static::registerPacket(new EduUriResourcePacket());
static::registerPacket(new CreatePhotoPacket());
static::registerPacket(new UpdateSubChunkBlocksPacket());
static::registerPacket(new PhotoInfoRequestPacket());
}
/**

View File

@ -0,0 +1,52 @@
<?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 PhotoInfoRequestPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::PHOTO_INFO_REQUEST_PACKET;
private int $photoId;
public static function create(int $photoId) : self{
$result = new self;
$result->photoId = $photoId;
return $result;
}
protected function decodePayload() : void{
$this->photoId = $this->getEntityUniqueId();
}
protected function encodePayload() : void{
$this->putEntityUniqueId($this->photoId);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handlePhotoInfoRequest($this);
}
}

View File

@ -36,17 +36,33 @@ class PhotoTransferPacket extends DataPacket{
public $photoData;
/** @var string */
public $bookId; //photos are stored in a sibling directory to the games folder (screenshots/(some UUID)/bookID/example.png)
/** @var int */
public $type;
/** @var int */
public $sourceType;
/** @var int */
public $ownerEntityUniqueId;
/** @var string */
public $newPhotoName; //???
protected function decodePayload(){
$this->photoName = $this->getString();
$this->photoData = $this->getString();
$this->bookId = $this->getString();
$this->type = $this->getByte();
$this->sourceType = $this->getByte();
$this->ownerEntityUniqueId = $this->getLLong(); //...............
$this->newPhotoName = $this->getString();
}
protected function encodePayload(){
$this->putString($this->photoName);
$this->putString($this->photoData);
$this->putString($this->bookId);
$this->putByte($this->type);
$this->putByte($this->sourceType);
$this->putLLong($this->ownerEntityUniqueId);
$this->putString($this->newPhotoName);
}
public function handle(NetworkSession $session) : bool{

View File

@ -37,11 +37,11 @@ interface ProtocolInfo{
*/
/** Actual Minecraft: PE protocol version */
public const CURRENT_PROTOCOL = 448;
public const CURRENT_PROTOCOL = 465;
/** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */
public const MINECRAFT_VERSION = 'v1.17.10';
public const MINECRAFT_VERSION = 'v1.17.30';
/** Version number sent to clients in ping responses. */
public const MINECRAFT_VERSION_NETWORK = '1.17.10';
public const MINECRAFT_VERSION_NETWORK = '1.17.30';
public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02;
@ -212,5 +212,9 @@ interface ProtocolInfo{
public const REMOVE_VOLUME_ENTITY_PACKET = 0xa7;
public const SIMULATION_TYPE_PACKET = 0xa8;
public const NPC_DIALOGUE_PACKET = 0xa9;
public const EDU_URI_RESOURCE_PACKET = 0xaa;
public const CREATE_PHOTO_PACKET = 0xab;
public const UPDATE_SUB_CHUNK_BLOCKS_PACKET = 0xac;
public const PHOTO_INFO_REQUEST_PACKET = 0xad;
}

View File

@ -30,6 +30,7 @@ use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\BlockPaletteEntry;
use pocketmine\network\mcpe\protocol\types\EducationEditionOffer;
use pocketmine\network\mcpe\protocol\types\EducationUriResource;
use pocketmine\network\mcpe\protocol\types\Experiments;
use pocketmine\network\mcpe\protocol\types\GameRuleType;
use pocketmine\network\mcpe\protocol\types\GeneratorType;
@ -143,6 +144,8 @@ class StartGamePacket extends DataPacket{
public $limitedWorldLength = 0;
/** @var bool */
public $isNewNether = true;
/** @var EducationUriResource|null */
public $eduSharedUriResource = null;
/** @var bool|null */
public $experimentalGameplayOverride = null;
@ -227,6 +230,7 @@ class StartGamePacket extends DataPacket{
$this->limitedWorldWidth = $this->getLInt();
$this->limitedWorldLength = $this->getLInt();
$this->isNewNether = $this->getBool();
$this->eduSharedUriResource = EducationUriResource::read($this);
if($this->getBool()){
$this->experimentalGameplayOverride = $this->getBool();
}else{
@ -311,6 +315,7 @@ class StartGamePacket extends DataPacket{
$this->putLInt($this->limitedWorldWidth);
$this->putLInt($this->limitedWorldLength);
$this->putBool($this->isNewNether);
($this->eduSharedUriResource ?? new EducationUriResource("", ""))->write($this);
$this->putBool($this->experimentalGameplayOverride !== null);
if($this->experimentalGameplayOverride !== null){
$this->putBool($this->experimentalGameplayOverride);

View File

@ -0,0 +1,97 @@
<?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\UpdateSubChunkBlocksPacketEntry;
use function count;
class UpdateSubChunkBlocksPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::UPDATE_SUB_CHUNK_BLOCKS_PACKET;
private int $subChunkX;
private int $subChunkY;
private int $subChunkZ;
/** @var UpdateSubChunkBlocksPacketEntry[] */
private array $layer0Updates;
/** @var UpdateSubChunkBlocksPacketEntry[] */
private array $layer1Updates;
/**
* @param UpdateSubChunkBlocksPacketEntry[] $layer0
* @param UpdateSubChunkBlocksPacketEntry[] $layer1
*/
public static function create(int $subChunkX, int $subChunkY, int $subChunkZ, array $layer0, array $layer1) : self{
$result = new self;
$result->subChunkX = $subChunkX;
$result->subChunkY = $subChunkY;
$result->subChunkZ = $subChunkZ;
$result->layer0Updates = $layer0;
$result->layer1Updates = $layer1;
return $result;
}
public function getSubChunkX() : int{ return $this->subChunkX; }
public function getSubChunkY() : int{ return $this->subChunkY; }
public function getSubChunkZ() : int{ return $this->subChunkZ; }
/** @return UpdateSubChunkBlocksPacketEntry[] */
public function getLayer0Updates() : array{ return $this->layer0Updates; }
/** @return UpdateSubChunkBlocksPacketEntry[] */
public function getLayer1Updates() : array{ return $this->layer1Updates; }
protected function decodePayload() : void{
$this->subChunkX = $this->subChunkY = $this->subChunkZ = 0;
$this->getBlockPosition($this->subChunkX, $this->subChunkY, $this->subChunkZ);
$this->layer0Updates = [];
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->layer0Updates[] = UpdateSubChunkBlocksPacketEntry::read($this);
}
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->layer1Updates[] = UpdateSubChunkBlocksPacketEntry::read($this);
}
}
protected function encodePayload() : void{
$this->putBlockPosition($this->subChunkX, $this->subChunkY, $this->subChunkZ);
$this->putUnsignedVarInt(count($this->layer0Updates));
foreach($this->layer0Updates as $update){
$update->write($this);
}
$this->putUnsignedVarInt(count($this->layer1Updates));
foreach($this->layer1Updates as $update){
$update->write($this);
}
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleUpdateSubChunkBlocks($this);
}
}

View File

@ -0,0 +1,51 @@
<?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\network\mcpe\NetworkBinaryStream;
final class EducationSettingsAgentCapabilities{
private ?bool $canModifyBlocks;
public function __construct(?bool $canModifyBlocks){
$this->canModifyBlocks = $canModifyBlocks;
}
public function getCanModifyBlocks() : ?bool{ return $this->canModifyBlocks; }
public static function read(NetworkBinaryStream $in) : self{
$canModifyBlocks = $in->getBool() ? $in->getBool() : null;
return new self($canModifyBlocks);
}
public function write(NetworkBinaryStream $out) : void{
if($this->canModifyBlocks !== null){
$out->putBool(true);
$out->putBool($this->canModifyBlocks);
}else{
$out->putBool(false);
}
}
}

View File

@ -0,0 +1,52 @@
<?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\network\mcpe\NetworkBinaryStream;
final class EducationSettingsExternalLinkSettings{
private string $displayName;
private string $url;
public function __construct(string $url, string $displayName){
$this->displayName = $displayName;
$this->url = $url;
}
public function getUrl() : string{ return $this->url; }
public function getDisplayName() : string{ return $this->displayName; }
public static function read(NetworkBinaryStream $in) : self{
$url = $in->getString();
$displayName = $in->getString();
return new self($displayName, $url);
}
public function write(NetworkBinaryStream $out) : void{
$out->putString($this->url);
$out->putString($this->displayName);
}
}

View File

@ -0,0 +1,51 @@
<?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\network\mcpe\NetworkBinaryStream;
final class EducationUriResource{
private string $buttonName;
private string $linkUri;
public function __construct(string $buttonName, string $linkUri){
$this->buttonName = $buttonName;
$this->linkUri = $linkUri;
}
public function getButtonName() : string{ return $this->buttonName; }
public function getLinkUri() : string{ return $this->linkUri; }
public static function read(NetworkBinaryStream $in) : self{
$buttonName = $in->getString();
$linkUri = $in->getString();
return new self($buttonName, $linkUri);
}
public function write(NetworkBinaryStream $out) : void{
$out->putString($this->buttonName);
$out->putString($this->linkUri);
}
}

View File

@ -0,0 +1,52 @@
<?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;
final class MaterialReducerRecipe{
private int $inputItemId;
private int $inputItemMeta;
/**
* @var MaterialReducerRecipeOutput[]
* @phpstan-var list<MaterialReducerRecipeOutput>
*/
private array $outputs;
/**
* @param MaterialReducerRecipeOutput[] $outputs
* @phpstan-param list<MaterialReducerRecipeOutput> $outputs
*/
public function __construct(int $inputItemId, int $inputItemMeta, array $outputs){
$this->inputItemId = $inputItemId;
$this->inputItemMeta = $inputItemMeta;
$this->outputs = $outputs;
}
public function getInputItemId() : int{ return $this->inputItemId; }
public function getInputItemMeta() : int{ return $this->inputItemMeta; }
/** @return MaterialReducerRecipeOutput[] */
public function getOutputs() : array{ return $this->outputs; }
}

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\types;
final class MaterialReducerRecipeOutput{
private int $itemId;
private int $count;
public function __construct(int $itemId, int $count){
$this->itemId = $itemId;
$this->count = $count;
}
public function getItemId() : int{ return $this->itemId; }
public function getCount() : int{ return $this->count; }
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\utils\UUID;
class SkinData{
@ -44,14 +45,9 @@ class SkinData{
private $capeImage;
/** @var string */
private $geometryData;
private string $geometryDataEngineVersion;
/** @var string */
private $animationData;
/** @var bool */
private $persona;
/** @var bool */
private $premium;
/** @var bool */
private $personaCapeOnClassic;
/** @var string */
private $capeId;
/** @var string */
@ -66,13 +62,21 @@ class SkinData{
private $pieceTintColors;
/** @var bool */
private $isVerified;
/** @var bool */
private $persona;
/** @var bool */
private $premium;
/** @var bool */
private $personaCapeOnClassic;
/** @var bool */
private $isPrimaryUser;
/**
* @param SkinAnimation[] $animations
* @param PersonaSkinPiece[] $personaPieces
* @param PersonaPieceTintColor[] $pieceTintColors
*/
public function __construct(string $skinId, string $playFabId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = "", ?string $fullSkinId = null, string $armSize = self::ARM_SIZE_WIDE, string $skinColor = "", array $personaPieces = [], array $pieceTintColors = [], bool $isVerified = true){
public function __construct(string $skinId, string $playFabId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $geometryDataEngineVersion = ProtocolInfo::MINECRAFT_VERSION_NETWORK, string $animationData = "", string $capeId = "", ?string $fullSkinId = null, string $armSize = self::ARM_SIZE_WIDE, string $skinColor = "", array $personaPieces = [], array $pieceTintColors = [], bool $isVerified = true, bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, bool $isPrimaryUser = true){
$this->skinId = $skinId;
$this->playFabId = $playFabId;
$this->resourcePatch = $resourcePatch;
@ -80,10 +84,8 @@ class SkinData{
$this->animations = $animations;
$this->capeImage = $capeImage ?? new SkinImage(0, 0, "");
$this->geometryData = $geometryData;
$this->geometryDataEngineVersion = $geometryDataEngineVersion;
$this->animationData = $animationData;
$this->premium = $premium;
$this->persona = $persona;
$this->personaCapeOnClassic = $personaCapeOnClassic;
$this->capeId = $capeId;
//this has to be unique or the client will do stupid things
$this->fullSkinId = $fullSkinId ?? UUID::fromRandom()->toString();
@ -92,6 +94,10 @@ class SkinData{
$this->personaPieces = $personaPieces;
$this->pieceTintColors = $pieceTintColors;
$this->isVerified = $isVerified;
$this->premium = $premium;
$this->persona = $persona;
$this->personaCapeOnClassic = $personaCapeOnClassic;
$this->isPrimaryUser = $isPrimaryUser;
}
public function getSkinId() : string{
@ -123,22 +129,12 @@ class SkinData{
return $this->geometryData;
}
public function getGeometryDataEngineVersion() : string{ return $this->geometryDataEngineVersion; }
public function getAnimationData() : string{
return $this->animationData;
}
public function isPersona() : bool{
return $this->persona;
}
public function isPremium() : bool{
return $this->premium;
}
public function isPersonaCapeOnClassic() : bool{
return $this->personaCapeOnClassic;
}
public function getCapeId() : string{
return $this->capeId;
}
@ -169,6 +165,20 @@ class SkinData{
return $this->pieceTintColors;
}
public function isPersona() : bool{
return $this->persona;
}
public function isPremium() : bool{
return $this->premium;
}
public function isPersonaCapeOnClassic() : bool{
return $this->personaCapeOnClassic;
}
public function isPrimaryUser() : bool{ return $this->isPrimaryUser; }
public function isVerified() : bool{
return $this->isVerified;
}

View File

@ -0,0 +1,88 @@
<?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\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
final class UpdateSubChunkBlocksPacketEntry{
private int $x;
private int $y;
private int $z;
private int $blockRuntimeId;
private int $flags;
//These two fields are useless 99.9% of the time; they are here to allow this packet to provide UpdateBlockSyncedPacket functionality.
private int $syncedUpdateEntityUniqueId;
private int $syncedUpdateType;
public function __construct(int $x, int $y, int $z, int $blockRuntimeId, int $flags, int $syncedUpdateEntityUniqueId, int $syncedUpdateType){
$this->x = $x;
$this->y = $y;
$this->z = $z;
$this->blockRuntimeId = $blockRuntimeId;
$this->flags = $flags;
$this->syncedUpdateEntityUniqueId = $syncedUpdateEntityUniqueId;
$this->syncedUpdateType = $syncedUpdateType;
}
public static function simple(int $x, int $y, int $z, int $blockRuntimeId) : self{
return new self($x, $y, $z, $blockRuntimeId, UpdateBlockPacket::FLAG_NETWORK, 0, 0);
}
public function getX() : int{ return $this->x; }
public function getY() : int{ return $this->y; }
public function getZ() : int{ return $this->z; }
public function getBlockRuntimeId() : int{ return $this->blockRuntimeId; }
public function getFlags() : int{ return $this->flags; }
public function getSyncedUpdateEntityUniqueId() : int{ return $this->syncedUpdateEntityUniqueId; }
public function getSyncedUpdateType() : int{ return $this->syncedUpdateType; }
public static function read(NetworkBinaryStream $in) : self{
$x = $y = $z = 0;
$in->getBlockPosition($x, $y, $z);
$blockRuntimeId = $in->getUnsignedVarInt();
$updateFlags = $in->getUnsignedVarInt();
$syncedUpdateEntityUniqueId = $in->getUnsignedVarLong(); //this can't use the standard method because it's unsigned as opposed to the usual signed... !!!!!!
$syncedUpdateType = $in->getUnsignedVarInt(); //this isn't even consistent with UpdateBlockSyncedPacket?!
return new self($x, $y, $z, $blockRuntimeId, $updateFlags, $syncedUpdateEntityUniqueId, $syncedUpdateType);
}
public function write(NetworkBinaryStream $out) : void{
$out->putBlockPosition($this->x, $this->y, $this->z);
$out->putUnsignedVarInt($this->blockRuntimeId);
$out->putUnsignedVarInt($this->flags);
$out->putUnsignedVarLong($this->syncedUpdateEntityUniqueId);
$out->putUnsignedVarInt($this->syncedUpdateType);
}
}