Compare commits

...

2 Commits

Author SHA1 Message Date
15ffab659c Release 3.28.0 2022-02-08 20:09:52 +00:00
ca76a928c1 Protocol changes for 1.18.10 2022-02-08 20:06:46 +00:00
28 changed files with 916 additions and 156 deletions

10
changelogs/3.28.md Normal file
View File

@ -0,0 +1,10 @@
**For Minecraft: Bedrock Edition 1.18.10**
### 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.28.0
- Added support for Minecraft: Bedrock Edition 1.18.10.

View File

@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
const _VERSION_INFO_INCLUDED = true;
const NAME = "PocketMine-MP";
const BASE_VERSION = "3.27.1";
const IS_DEVELOPMENT_BUILD = true;
const BASE_VERSION = "3.28.0";
const IS_DEVELOPMENT_BUILD = false;
const BUILD_CHANNEL = "pm3";

View File

@ -61,7 +61,7 @@ class ChunkRequestTask extends AsyncTask{
public function onRun(){
$chunk = Chunk::fastDeserialize($this->chunk);
$pk = LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $chunk->getSubChunkSendCount() + 4, $chunk->networkSerialize($this->tiles));
$pk = LevelChunkPacket::create($this->chunkX, $this->chunkZ, $chunk->getSubChunkSendCount() + 4, false, null, $chunk->networkSerialize($this->tiles));
$batch = new BatchPacket();
$batch->addPacket($pk);

View File

@ -56,6 +56,7 @@ use pocketmine\network\mcpe\protocol\ClientCacheMissResponsePacket;
use pocketmine\network\mcpe\protocol\ClientCacheStatusPacket;
use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket;
use pocketmine\network\mcpe\protocol\CodeBuilderPacket;
use pocketmine\network\mcpe\protocol\CodeBuilderSourcePacket;
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\CommandOutputPacket;
use pocketmine\network\mcpe\protocol\CommandRequestPacket;
@ -128,6 +129,7 @@ use pocketmine\network\mcpe\protocol\PlayerHotbarPacket;
use pocketmine\network\mcpe\protocol\PlayerInputPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\PlayerStartItemCooldownPacket;
use pocketmine\network\mcpe\protocol\PlaySoundPacket;
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
use pocketmine\network\mcpe\protocol\PositionTrackingDBClientRequestPacket;
@ -146,6 +148,7 @@ use pocketmine\network\mcpe\protocol\ResourcePacksInfoPacket;
use pocketmine\network\mcpe\protocol\ResourcePackStackPacket;
use pocketmine\network\mcpe\protocol\RespawnPacket;
use pocketmine\network\mcpe\protocol\ScriptCustomEventPacket;
use pocketmine\network\mcpe\protocol\ScriptMessagePacket;
use pocketmine\network\mcpe\protocol\ServerSettingsRequestPacket;
use pocketmine\network\mcpe\protocol\ServerSettingsResponsePacket;
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
@ -881,4 +884,16 @@ abstract class NetworkSession{
public function handleSubChunkRequest(SubChunkRequestPacket $packet) : bool{
return false;
}
public function handlePlayerStartItemCooldown(PlayerStartItemCooldownPacket $packet) : bool{
return false;
}
public function handleScriptMessage(ScriptMessagePacket $packet) : bool{
return false;
}
public function handleCodeBuilderSource(CodeBuilderSourcePacket $packet) : bool{
return false;
}
}

View File

@ -46,6 +46,8 @@ class BossEventPacket extends DataPacket{
public const TYPE_UNKNOWN_6 = 6;
/* S2C: Not implemented :( Intended to alter bar appearance, but these currently produce no effect on client-side whatsoever. */
public const TYPE_TEXTURE = 7;
/* C2S: Client asking the server to resend all boss data. */
public const TYPE_QUERY = 8;
/** @var int */
public $bossEid;
@ -71,6 +73,7 @@ class BossEventPacket extends DataPacket{
switch($this->eventType){
case self::TYPE_REGISTER_PLAYER:
case self::TYPE_UNREGISTER_PLAYER:
case self::TYPE_QUERY:
$this->playerEid = $this->getEntityUniqueId();
break;
/** @noinspection PhpMissingBreakStatementInspection */
@ -101,6 +104,7 @@ class BossEventPacket extends DataPacket{
switch($this->eventType){
case self::TYPE_REGISTER_PLAYER:
case self::TYPE_UNREGISTER_PLAYER:
case self::TYPE_QUERY:
$this->putEntityUniqueId($this->playerEid);
break;
/** @noinspection PhpMissingBreakStatementInspection */

View File

@ -0,0 +1,67 @@
<?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;
use pocketmine\network\mcpe\NetworkSession;
class CodeBuilderSourcePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::CODE_BUILDER_SOURCE_PACKET;
private int $operation;
private int $category;
private string $value;
/**
* @generate-create-func
*/
public static function create(int $operation, int $category, string $value) : self{
$result = new self;
$result->operation = $operation;
$result->category = $category;
$result->value = $value;
return $result;
}
public function getOperation() : int{ return $this->operation; }
public function getCategory() : int{ return $this->category; }
public function getValue() : string{ return $this->value; }
protected function decodePayload() : void{
$this->operation = $this->getByte();
$this->category = $this->getByte();
$this->value = $this->getString();
}
protected function encodePayload() : void{
$this->putByte($this->operation);
$this->putByte($this->category);
$this->putString($this->value);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleCodeBuilderSource($this);
}
}

View File

@ -23,53 +23,43 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use function count;
use const PHP_INT_MAX;
class LevelChunkPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::LEVEL_CHUNK_PACKET;
/** @var int */
private $chunkX;
/** @var int */
private $chunkZ;
/** @var int */
private $subChunkCount;
/** @var bool */
private $cacheEnabled;
/** @var int[] */
private $usedBlobHashes = [];
/** @var string */
private $extraPayload;
/**
* Client will request all subchunks as needed up to the top of the world
*/
private const CLIENT_REQUEST_FULL_COLUMN_FAKE_COUNT = 0xff_ff_ff_ff;
/**
* Client will request subchunks as needed up to the height written in the packet, and assume that anything above
* that height is air (wtf mojang ...)
*/
private const CLIENT_REQUEST_TRUNCATED_COLUMN_FAKE_COUNT = 0xff_ff_ff_fe;
public static function withoutCache(int $chunkX, int $chunkZ, int $subChunkCount, string $payload) : self{
$result = new self;
$result->chunkX = $chunkX;
$result->chunkZ = $chunkZ;
$result->subChunkCount = $subChunkCount;
$result->extraPayload = $payload;
$result->cacheEnabled = false;
return $result;
}
private int $chunkX;
private int $chunkZ;
private int $subChunkCount;
private bool $clientSubChunkRequestsEnabled;
/** @var int[]|null */
private ?array $usedBlobHashes = null;
private string $extraPayload;
/**
* @generate-create-func
* @param int[] $usedBlobHashes
*/
public static function withCache(int $chunkX, int $chunkZ, int $subChunkCount, array $usedBlobHashes, string $extraPayload) : self{
(static function(int ...$hashes) : void{})(...$usedBlobHashes);
public static function create(int $chunkX, int $chunkZ, int $subChunkCount, bool $clientSubChunkRequestsEnabled, ?array $usedBlobHashes, string $extraPayload) : self{
$result = new self;
$result->chunkX = $chunkX;
$result->chunkZ = $chunkZ;
$result->subChunkCount = $subChunkCount;
$result->extraPayload = $extraPayload;
$result->cacheEnabled = true;
$result->clientSubChunkRequestsEnabled = $clientSubChunkRequestsEnabled;
$result->usedBlobHashes = $usedBlobHashes;
$result->extraPayload = $extraPayload;
return $result;
}
@ -85,14 +75,18 @@ class LevelChunkPacket extends DataPacket/* implements ClientboundPacket*/{
return $this->subChunkCount;
}
public function isClientSubChunkRequestEnabled() : bool{
return $this->clientSubChunkRequestsEnabled;
}
public function isCacheEnabled() : bool{
return $this->cacheEnabled;
return $this->usedBlobHashes !== null;
}
/**
* @return int[]
* @return int[]|null
*/
public function getUsedBlobHashes() : array{
public function getUsedBlobHashes() : ?array{
return $this->usedBlobHashes;
}
@ -103,9 +97,22 @@ class LevelChunkPacket extends DataPacket/* implements ClientboundPacket*/{
protected function decodePayload() : void{
$this->chunkX = $this->getVarInt();
$this->chunkZ = $this->getVarInt();
$this->subChunkCount = $this->getUnsignedVarInt();
$this->cacheEnabled = $this->getBool();
if($this->cacheEnabled){
$subChunkCountButNotReally = $this->getUnsignedVarInt();
if($subChunkCountButNotReally === self::CLIENT_REQUEST_FULL_COLUMN_FAKE_COUNT){
$this->clientSubChunkRequestsEnabled = true;
$this->subChunkCount = PHP_INT_MAX;
}elseif($subChunkCountButNotReally === self::CLIENT_REQUEST_TRUNCATED_COLUMN_FAKE_COUNT){
$this->clientSubChunkRequestsEnabled = true;
$this->subChunkCount = $this->getLShort();
}else{
$this->clientSubChunkRequestsEnabled = false;
$this->subChunkCount = $subChunkCountButNotReally;
}
$cacheEnabled = $this->getBool();
if($cacheEnabled){
$this->usedBlobHashes = [];
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->usedBlobHashes[] = $this->getLLong();
}
@ -116,11 +123,23 @@ class LevelChunkPacket extends DataPacket/* implements ClientboundPacket*/{
protected function encodePayload() : void{
$this->putVarInt($this->chunkX);
$this->putVarInt($this->chunkZ);
$this->putUnsignedVarInt($this->subChunkCount);
$this->putBool($this->cacheEnabled);
if($this->cacheEnabled){
$this->putUnsignedVarInt(count($this->usedBlobHashes));
foreach($this->usedBlobHashes as $hash){
if($this->clientSubChunkRequestsEnabled){
if($this->subChunkCount === PHP_INT_MAX){
$this->putUnsignedVarInt(self::CLIENT_REQUEST_FULL_COLUMN_FAKE_COUNT);
}else{
$this->putUnsignedVarInt(self::CLIENT_REQUEST_TRUNCATED_COLUMN_FAKE_COUNT);
$this->putLShort($this->subChunkCount);
}
}else{
$this->putUnsignedVarInt($this->subChunkCount);
}
$this->putBool($this->usedBlobHashes !== null);
if($this->usedBlobHashes !== null){
$usedBlobHashes = $this->usedBlobHashes;
$this->putUnsignedVarInt(count($usedBlobHashes));
foreach($usedBlobHashes as $hash){
$this->putLLong($hash);
}
}

View File

@ -206,6 +206,9 @@ class PacketPool{
static::registerPacket(new PhotoInfoRequestPacket());
static::registerPacket(new SubChunkPacket());
static::registerPacket(new SubChunkRequestPacket());
static::registerPacket(new PlayerStartItemCooldownPacket());
static::registerPacket(new ScriptMessagePacket());
static::registerPacket(new CodeBuilderSourcePacket());
}
/**

View File

@ -0,0 +1,61 @@
<?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;
use pocketmine\network\mcpe\NetworkSession;
class PlayerStartItemCooldownPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::PLAYER_START_ITEM_COOLDOWN_PACKET;
private string $itemCategory;
private int $cooldownTicks;
/**
* @generate-create-func
*/
public static function create(string $itemCategory, int $cooldownTicks) : self{
$result = new self;
$result->itemCategory = $itemCategory;
$result->cooldownTicks = $cooldownTicks;
return $result;
}
public function getItemCategory() : string{ return $this->itemCategory; }
public function getCooldownTicks() : int{ return $this->cooldownTicks; }
protected function decodePayload() : void{
$this->itemCategory = $this->getString();
$this->cooldownTicks = $this->getVarInt();
}
protected function encodePayload() : void{
$this->putString($this->itemCategory);
$this->putVarInt($this->cooldownTicks);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handlePlayerStartItemCooldown($this);
}
}

View File

@ -37,11 +37,11 @@ interface ProtocolInfo{
*/
/** Actual Minecraft: PE protocol version */
public const CURRENT_PROTOCOL = 475;
public const CURRENT_PROTOCOL = 486;
/** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */
public const MINECRAFT_VERSION = 'v1.18.0';
public const MINECRAFT_VERSION = 'v1.18.11';
/** Version number sent to clients in ping responses. */
public const MINECRAFT_VERSION_NETWORK = '1.18.0';
public const MINECRAFT_VERSION_NETWORK = '1.18.11';
public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02;
@ -218,5 +218,8 @@ interface ProtocolInfo{
public const PHOTO_INFO_REQUEST_PACKET = 0xad;
public const SUB_CHUNK_PACKET = 0xae;
public const SUB_CHUNK_REQUEST_PACKET = 0xaf;
public const PLAYER_START_ITEM_COOLDOWN_PACKET = 0xb0;
public const SCRIPT_MESSAGE_PACKET = 0xb1;
public const CODE_BUILDER_SOURCE_PACKET = 0xb2;
}

View File

@ -0,0 +1,61 @@
<?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;
use pocketmine\network\mcpe\NetworkSession;
class ScriptMessagePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SCRIPT_MESSAGE_PACKET;
private string $messageId;
private string $value;
/**
* @generate-create-func
*/
public static function create(string $messageId, string $value) : self{
$result = new self;
$result->messageId = $messageId;
$result->value = $value;
return $result;
}
public function getMessageId() : string{ return $this->messageId; }
public function getValue() : string{ return $this->value; }
protected function decodePayload() : void{
$this->messageId = $this->getString();
$this->value = $this->getString();
}
protected function encodePayload() : void{
$this->putString($this->messageId);
$this->putString($this->value);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleScriptMessage($this);
}
}

View File

@ -23,93 +23,70 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\SubChunkPacketHeightMapInfo;
use pocketmine\network\mcpe\protocol\types\SubChunkPacketHeightMapType;
use pocketmine\network\mcpe\protocol\types\SubChunkPacketEntryWithCache as EntryWithBlobHash;
use pocketmine\network\mcpe\protocol\types\SubChunkPacketEntryWithCacheList as ListWithBlobHashes;
use pocketmine\network\mcpe\protocol\types\SubChunkPacketEntryWithoutCache as EntryWithoutBlobHash;
use pocketmine\network\mcpe\protocol\types\SubChunkPacketEntryWithoutCacheList as ListWithoutBlobHashes;
use pocketmine\network\mcpe\protocol\types\SubChunkPosition;
use function count;
class SubChunkPacket extends DataPacket{
class SubChunkPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::SUB_CHUNK_PACKET;
private int $dimension;
private int $subChunkX;
private int $subChunkY;
private int $subChunkZ;
private string $data;
private int $requestResult;
private ?SubChunkPacketHeightMapInfo $heightMapData = null;
private ?int $usedBlobHash = null;
private SubChunkPosition $baseSubChunkPosition;
private ListWithBlobHashes|ListWithoutBlobHashes $entries;
public static function create(int $dimension, int $subChunkX, int $subChunkY, int $subChunkZ, string $data, int $requestResult, ?SubChunkPacketHeightMapInfo $heightMapData, ?int $usedBlobHash) : self{
/**
* @generate-create-func
*/
public static function create(int $dimension, SubChunkPosition $baseSubChunkPosition, ListWithBlobHashes|ListWithoutBlobHashes $entries) : self{
$result = new self;
$result->dimension = $dimension;
$result->subChunkX = $subChunkX;
$result->subChunkY = $subChunkY;
$result->subChunkZ = $subChunkZ;
$result->data = $data;
$result->requestResult = $requestResult;
$result->heightMapData = $heightMapData;
$result->usedBlobHash = $usedBlobHash;
$result->baseSubChunkPosition = $baseSubChunkPosition;
$result->entries = $entries;
return $result;
}
public function isCacheEnabled() : bool{ return $this->entries instanceof ListWithBlobHashes; }
public function getDimension() : int{ return $this->dimension; }
public function getSubChunkX() : int{ return $this->subChunkX; }
public function getBaseSubChunkPosition() : SubChunkPosition{ return $this->baseSubChunkPosition; }
public function getSubChunkY() : int{ return $this->subChunkY; }
public function getSubChunkZ() : int{ return $this->subChunkZ; }
public function getData() : string{ return $this->data; }
public function getRequestResult() : int{ return $this->requestResult; }
public function getHeightMapData() : ?SubChunkPacketHeightMapInfo{ return $this->heightMapData; }
public function getUsedBlobHash() : ?int{ return $this->usedBlobHash; }
public function getEntries() : ListWithBlobHashes|ListWithoutBlobHashes{ return $this->entries; }
protected function decodePayload() : void{
$cacheEnabled = $this->getBool();
$this->dimension = $this->getVarInt();
$this->subChunkX = $this->getVarInt();
$this->subChunkY = $this->getVarInt();
$this->subChunkZ = $this->getVarInt();
$this->data = $this->getString();
$this->requestResult = $this->getVarInt();
$heightMapDataType = $this->getByte();
$this->heightMapData = match($heightMapDataType){
SubChunkPacketHeightMapType::NO_DATA => null,
SubChunkPacketHeightMapType::DATA => SubChunkPacketHeightMapInfo::read($this),
SubChunkPacketHeightMapType::ALL_TOO_HIGH => SubChunkPacketHeightMapInfo::allTooHigh(),
SubChunkPacketHeightMapType::ALL_TOO_LOW => SubChunkPacketHeightMapInfo::allTooLow(),
default => throw new \UnexpectedValueException("Unknown heightmap data type $heightMapDataType")
};
$this->usedBlobHash = $this->getBool() ? $this->getLLong() : null;
$this->baseSubChunkPosition = SubChunkPosition::read($this);
$count = $this->getLInt();
if($cacheEnabled){
$entries = [];
for($i = 0; $i < $count; $i++){
$entries[] = EntryWithBlobHash::read($this);
}
$this->entries = new ListWithBlobHashes($entries);
}else{
$entries = [];
for($i = 0; $i < $count; $i++){
$entries[] = EntryWithoutBlobHash::read($this);
}
$this->entries = new ListWithoutBlobHashes($entries);
}
}
protected function encodePayload() : void{
$this->putBool($this->entries instanceof ListWithBlobHashes);
$this->putVarInt($this->dimension);
$this->putVarInt($this->subChunkX);
$this->putVarInt($this->subChunkY);
$this->putVarInt($this->subChunkZ);
$this->putString($this->data);
$this->putVarInt($this->requestResult);
if($this->heightMapData === null){
$this->putByte(SubChunkPacketHeightMapType::NO_DATA);
}elseif($this->heightMapData->isAllTooLow()){
$this->putByte(SubChunkPacketHeightMapType::ALL_TOO_LOW);
}elseif($this->heightMapData->isAllTooHigh()){
$this->putByte(SubChunkPacketHeightMapType::ALL_TOO_HIGH);
}else{
$heightMapData = $this->heightMapData; //avoid PHPStan purity issue
$this->putByte(SubChunkPacketHeightMapType::DATA);
$heightMapData->write($this);
}
$usedBlobHash = $this->usedBlobHash;
$this->putBool($usedBlobHash !== null);
if($usedBlobHash !== null){
$this->putLLong($usedBlobHash);
$this->baseSubChunkPosition->write($this);
$this->putLInt(count($this->entries->getEntries()));
foreach($this->entries->getEntries() as $entry){
$entry->write($this);
}
}

View File

@ -23,47 +23,63 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\SubChunkPosition;
use pocketmine\network\mcpe\protocol\types\SubChunkPositionOffset;
use function count;
class SubChunkRequestPacket extends DataPacket/* implements ServerboundPacket*/{
public const NETWORK_ID = ProtocolInfo::SUB_CHUNK_REQUEST_PACKET;
private int $dimension;
private int $subChunkX;
private int $subChunkY;
private int $subChunkZ;
private SubChunkPosition $basePosition;
/**
* @var SubChunkPositionOffset[]
* @phpstan-var list<SubChunkPositionOffset>
*/
private array $entries;
public static function create(int $dimension, int $subChunkX, int $subChunkY, int $subChunkZ) : self{
/**
* @generate-create-func
* @param SubChunkPositionOffset[] $entries
* @phpstan-param list<SubChunkPositionOffset> $entries
*/
public static function create(int $dimension, SubChunkPosition $basePosition, array $entries) : self{
$result = new self;
$result->dimension = $dimension;
$result->subChunkX = $subChunkX;
$result->subChunkY = $subChunkY;
$result->subChunkZ = $subChunkZ;
$result->basePosition = $basePosition;
$result->entries = $entries;
return $result;
}
public function getDimension() : int{ return $this->dimension; }
public function getSubChunkX() : int{ return $this->subChunkX; }
public function getBasePosition() : SubChunkPosition{ return $this->basePosition; }
public function getSubChunkY() : int{ return $this->subChunkY; }
public function getSubChunkZ() : int{ return $this->subChunkZ; }
/**
* @return SubChunkPositionOffset[]
* @phpstan-return list<SubChunkPositionOffset>
*/
public function getEntries() : array{ return $this->entries; }
protected function decodePayload() : void{
$this->dimension = $this->getVarInt();
$this->subChunkX = $this->getVarInt();
$this->subChunkY = $this->getVarInt();
$this->subChunkZ = $this->getVarInt();
$this->basePosition = SubChunkPosition::read($this);
$this->entries = [];
for($i = 0, $count = $this->getLInt(); $i < $count; $i++){
$this->entries[] = SubChunkPositionOffset::read($this);
}
}
protected function encodePayload() : void{
$this->putVarInt($this->dimension);
$this->putVarInt($this->subChunkX);
$this->putVarInt($this->subChunkY);
$this->putVarInt($this->subChunkZ);
$this->basePosition->write($this);
$this->putLInt(count($this->entries));
foreach($this->entries as $entry){
$entry->write($this);
}
}
public function handle(NetworkSession $handler) : bool{

View File

@ -0,0 +1,91 @@
<?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 SubChunkPacketEntryCommon{
public function __construct(
private SubChunkPositionOffset $offset,
private int $requestResult,
private string $terrainData,
private ?SubChunkPacketHeightMapInfo $heightMap
){}
public function getOffset() : SubChunkPositionOffset{ return $this->offset; }
public function getRequestResult() : int{ return $this->requestResult; }
public function getTerrainData() : string{ return $this->terrainData; }
/** @return SubChunkPacketHeightMapInfo|null */
public function getHeightMap() : ?SubChunkPacketHeightMapInfo{ return $this->heightMap; }
public static function read(NetworkBinaryStream $in, bool $cacheEnabled) : self{
$offset = SubChunkPositionOffset::read($in);
$requestResult = $in->getByte();
$data = !$cacheEnabled || $requestResult !== SubChunkRequestResult::SUCCESS_ALL_AIR ? $in->getString() : "";
$heightMapDataType = $in->getByte();
$heightMapData = match ($heightMapDataType) {
SubChunkPacketHeightMapType::NO_DATA => null,
SubChunkPacketHeightMapType::DATA => SubChunkPacketHeightMapInfo::read($in),
SubChunkPacketHeightMapType::ALL_TOO_HIGH => SubChunkPacketHeightMapInfo::allTooHigh(),
SubChunkPacketHeightMapType::ALL_TOO_LOW => SubChunkPacketHeightMapInfo::allTooLow(),
default => throw new \UnexpectedValueException("Unknown heightmap data type $heightMapDataType")
};
return new self(
$offset,
$requestResult,
$data,
$heightMapData
);
}
public function write(NetworkBinaryStream $out, bool $cacheEnabled) : void{
$this->offset->write($out);
$out->putByte($this->requestResult);
if(!$cacheEnabled || $this->requestResult !== SubChunkRequestResult::SUCCESS_ALL_AIR){
$out->putString($this->terrainData);
}
if($this->heightMap === null){
$out->putByte(SubChunkPacketHeightMapType::NO_DATA);
}elseif($this->heightMap->isAllTooLow()){
$out->putByte(SubChunkPacketHeightMapType::ALL_TOO_LOW);
}elseif($this->heightMap->isAllTooHigh()){
$out->putByte(SubChunkPacketHeightMapType::ALL_TOO_HIGH);
}else{
$heightMapData = $this->heightMap; //avoid PHPStan purity issue
$out->putByte(SubChunkPacketHeightMapType::DATA);
$heightMapData->write($out);
}
}
}

View File

@ -0,0 +1,50 @@
<?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 SubChunkPacketEntryWithCache{
public function __construct(
private SubChunkPacketEntryCommon $base,
private int $usedBlobHash
){}
public function getBase() : SubChunkPacketEntryCommon{ return $this->base; }
public function getUsedBlobHash() : int{ return $this->usedBlobHash; }
public static function read(NetworkBinaryStream $in) : self{
$base = SubChunkPacketEntryCommon::read($in, true);
$usedBlobHash = $in->getLLong();
return new self($base, $usedBlobHash);
}
public function write(NetworkBinaryStream $out) : void{
$this->base->write($out, true);
$out->putLLong($this->usedBlobHash);
}
}

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 SubChunkPacketEntryWithCacheList{
/**
* @param SubChunkPacketEntryWithCache[] $entries
*/
public function __construct(
private array $entries
){}
/**
* @return SubChunkPacketEntryWithCache[]
*/
public function getEntries() : array{ return $this->entries; }
}

View File

@ -0,0 +1,43 @@
<?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 SubChunkPacketEntryWithoutCache{
public function __construct(
private SubChunkPacketEntryCommon $base
){}
public function getBase() : SubChunkPacketEntryCommon{ return $this->base; }
public static function read(NetworkBinaryStream $in) : self{
return new self(SubChunkPacketEntryCommon::read($in, false));
}
public function write(NetworkBinaryStream $out) : void{
$this->base->write($out, false);
}
}

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 SubChunkPacketEntryWithoutCacheList{
/**
* @param SubChunkPacketEntryWithoutCache[] $entries
*/
public function __construct(
private array $entries
){}
/**
* @return SubChunkPacketEntryWithoutCache[]
*/
public function getEntries() : array{ return $this->entries; }
}

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\types;
use pocketmine\network\mcpe\NetworkBinaryStream;
final class SubChunkPosition{
public function __construct(
private int $x,
private int $y,
private int $z,
){}
public function getX() : int{ return $this->x; }
public function getY() : int{ return $this->y; }
public function getZ() : int{ return $this->z; }
public static function read(NetworkBinaryStream $in) : self{
$x = $in->getVarInt();
$y = $in->getVarInt();
$z = $in->getVarInt();
return new self($x, $y, $z);
}
public function write(NetworkBinaryStream $out) : void{
$out->putVarInt($this->x);
$out->putVarInt($this->y);
$out->putVarInt($this->z);
}
}

View File

@ -0,0 +1,66 @@
<?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\utils\Binary;
final class SubChunkPositionOffset{
public function __construct(
private int $xOffset,
private int $yOffset,
private int $zOffset,
){
self::clampOffset($this->xOffset);
self::clampOffset($this->yOffset);
self::clampOffset($this->zOffset);
}
private static function clampOffset(int $v) : void{
if($v < -128 || $v > 127){
throw new \InvalidArgumentException("Offsets must be within the range of a byte (-128 ... 127)");
}
}
public function getXOffset() : int{ return $this->xOffset; }
public function getYOffset() : int{ return $this->yOffset; }
public function getZOffset() : int{ return $this->zOffset; }
public static function read(NetworkBinaryStream $in) : self{
$xOffset = Binary::signByte($in->getByte());
$yOffset = Binary::signByte($in->getByte());
$zOffset = Binary::signByte($in->getByte());
return new self($xOffset, $yOffset, $zOffset);
}
public function write(NetworkBinaryStream $out) : void{
$out->putByte($this->xOffset);
$out->putByte($this->yOffset);
$out->putByte($this->zOffset);
}
}

View File

@ -31,4 +31,5 @@ final class SubChunkRequestResult{
public const WRONG_DIMENSION = 3;
public const NULL_PLAYER = 4;
public const Y_INDEX_OUT_OF_BOUNDS = 5;
public const SUCCESS_ALL_AIR = 6;
}

View File

@ -0,0 +1,48 @@
<?php
/*
* This file is part of BedrockProtocol.
* Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/BedrockProtocol>
*
* BedrockProtocol 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.
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* Repair and/or remove enchantments from an item in a grindstone.
*/
final class GrindstoneStackRequestAction extends ItemStackRequestAction{
public static function getTypeId() : int{
return ItemStackRequestActionType::CRAFTING_GRINDSTONE;
}
public function __construct(
private int $recipeId,
private int $repairCost
){}
public function getRecipeId() : int{ return $this->recipeId; }
/** WARNING: This may be negative */
public function getRepairCost() : int{ return $this->repairCost; }
public static function read(NetworkBinaryStream $in) : self{
$recipeId = $in->readGenericTypeNetworkId();
$repairCost = $in->getVarInt(); //WHY!!!!
return new self($recipeId, $repairCost);
}
public function write(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->recipeId);
$out->putVarInt($this->repairCost);
}
}

View File

@ -69,6 +69,8 @@ final class ItemStackRequest{
case DestroyStackRequestAction::getTypeId(): return DestroyStackRequestAction::read($in);
case CraftingConsumeInputStackRequestAction::getTypeId(): return CraftingConsumeInputStackRequestAction::read($in);
case CraftingMarkSecondaryResultStackRequestAction::getTypeId(): return CraftingMarkSecondaryResultStackRequestAction::read($in);
case PlaceIntoBundleStackRequestAction::getTypeId(): return PlaceIntoBundleStackRequestAction::read($in);
case TakeFromBundleStackRequestAction::getTypeId(): return TakeFromBundleStackRequestAction::read($in);
case LabTableCombineStackRequestAction::getTypeId(): return LabTableCombineStackRequestAction::read($in);
case BeaconPaymentStackRequestAction::getTypeId(): return BeaconPaymentStackRequestAction::read($in);
case MineBlockStackRequestAction::getTypeId(): return MineBlockStackRequestAction::read($in);
@ -76,6 +78,8 @@ final class ItemStackRequest{
case CraftRecipeAutoStackRequestAction::getTypeId(): return CraftRecipeAutoStackRequestAction::read($in);
case CreativeCreateStackRequestAction::getTypeId(): return CreativeCreateStackRequestAction::read($in);
case CraftRecipeOptionalStackRequestAction::getTypeId(): return CraftRecipeOptionalStackRequestAction::read($in);
case GrindstoneStackRequestAction::getTypeId(): return GrindstoneStackRequestAction::read($in);
case LoomStackRequestAction::getTypeId(): return LoomStackRequestAction::read($in);
case DeprecatedCraftingNonImplementedStackRequestAction::getTypeId(): return DeprecatedCraftingNonImplementedStackRequestAction::read($in);
case DeprecatedCraftingResultsStackRequestAction::getTypeId(): return DeprecatedCraftingResultsStackRequestAction::read($in);
}

View File

@ -1,23 +1,14 @@
<?php
/*
* This file is part of BedrockProtocol.
* Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/BedrockProtocol>
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* BedrockProtocol 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);
@ -36,13 +27,17 @@ final class ItemStackRequestActionType{
public const DESTROY = 4;
public const CRAFTING_CONSUME_INPUT = 5;
public const CRAFTING_MARK_SECONDARY_RESULT_SLOT = 6;
public const LAB_TABLE_COMBINE = 7;
public const BEACON_PAYMENT = 8;
public const MINE_BLOCK = 9;
public const CRAFTING_RECIPE = 10;
public const CRAFTING_RECIPE_AUTO = 11; //recipe book?
public const CREATIVE_CREATE = 12;
public const CRAFTING_RECIPE_OPTIONAL = 13; //anvil/cartography table rename
public const CRAFTING_NON_IMPLEMENTED_DEPRECATED_ASK_TY_LAING = 14;
public const CRAFTING_RESULTS_DEPRECATED_ASK_TY_LAING = 15; //no idea what this is for
public const PLACE_INTO_BUNDLE = 7;
public const TAKE_FROM_BUNDLE = 8;
public const LAB_TABLE_COMBINE = 9;
public const BEACON_PAYMENT = 10;
public const MINE_BLOCK = 11;
public const CRAFTING_RECIPE = 12;
public const CRAFTING_RECIPE_AUTO = 13; //recipe book?
public const CREATIVE_CREATE = 14;
public const CRAFTING_RECIPE_OPTIONAL = 15; //anvil/cartography table rename
public const CRAFTING_GRINDSTONE = 16;
public const CRAFTING_LOOM = 17;
public const CRAFTING_NON_IMPLEMENTED_DEPRECATED_ASK_TY_LAING = 18;
public const CRAFTING_RESULTS_DEPRECATED_ASK_TY_LAING = 19; //no idea what this is for
}

View File

@ -0,0 +1,41 @@
<?php
/*
* This file is part of BedrockProtocol.
* Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/BedrockProtocol>
*
* BedrockProtocol 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.
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* Apply a pattern to a banner using a loom.
*/
final class LoomStackRequestAction extends ItemStackRequestAction{
public static function getTypeId() : int{
return ItemStackRequestActionType::CRAFTING_LOOM;
}
public function __construct(
private string $patternId
){}
public function getPatternId() : string{ return $this->patternId; }
public static function read(NetworkBinaryStream $in) : self{
return new self($in->getString());
}
public function write(NetworkBinaryStream $out) : void{
$out->putString($this->patternId);
}
}

View File

@ -0,0 +1,26 @@
<?php
/*
* This file is part of BedrockProtocol.
* Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/BedrockProtocol>
*
* BedrockProtocol 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.
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
/**
* Insert an item into a bundle.
*/
final class PlaceIntoBundleStackRequestAction extends ItemStackRequestAction{
use TakeOrPlaceStackRequestActionTrait;
public static function getTypeId() : int{
return ItemStackRequestActionType::PLACE_INTO_BUNDLE;
}
}

View File

@ -0,0 +1,26 @@
<?php
/*
* This file is part of BedrockProtocol.
* Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/BedrockProtocol>
*
* BedrockProtocol 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.
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
/**
* Take an item out of a bundle.
*/
final class TakeFromBundleStackRequestAction extends ItemStackRequestAction{
use TakeOrPlaceStackRequestActionTrait;
public static function getTypeId() : int{
return ItemStackRequestActionType::TAKE_FROM_BUNDLE;
}
}