Skip to content

Commit

Permalink
1.21.50 support
Browse files Browse the repository at this point in the history
  • Loading branch information
AkmalFairuz committed Dec 3, 2024
1 parent 78663f9 commit 6951fd8
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 21 deletions.
48 changes: 30 additions & 18 deletions src/PlayerAuthInputPacket.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use pocketmine\math\Vector2;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\serializer\BitSet;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
use pocketmine\network\mcpe\protocol\types\InputMode;
use pocketmine\network\mcpe\protocol\types\InteractionMode;
Expand All @@ -39,7 +40,7 @@ class PlayerAuthInputPacket extends DataPacket implements ServerboundPacket{
private float $headYaw;
private float $moveVecX;
private float $moveVecZ;
private int $inputFlags;
private BitSet $inputFlags;
private int $inputMode;
private int $playMode;
private int $interactionMode;
Expand All @@ -54,6 +55,7 @@ class PlayerAuthInputPacket extends DataPacket implements ServerboundPacket{
private float $analogMoveVecX;
private float $analogMoveVecZ;
private Vector3 $cameraOrientation;
private Vector2 $rawMove;

/**
* @param int $inputFlags @see PlayerAuthInputFlags
Expand All @@ -70,7 +72,7 @@ public static function create(
float $headYaw,
float $moveVecX,
float $moveVecZ,
int $inputFlags,
BitSet $inputFlags,
int $inputMode,
int $playMode,
int $interactionMode,
Expand All @@ -84,6 +86,7 @@ public static function create(
float $analogMoveVecX,
float $analogMoveVecZ,
Vector3 $cameraOrientation,
Vector2 $rawMove
) : self{
$result = new self;
$result->position = $position->asVector3();
Expand All @@ -93,19 +96,13 @@ public static function create(
$result->moveVecX = $moveVecX;
$result->moveVecZ = $moveVecZ;

$result->inputFlags = $inputFlags & ~((1 << PlayerAuthInputFlags::PERFORM_ITEM_STACK_REQUEST) | (1 << PlayerAuthInputFlags::PERFORM_ITEM_INTERACTION) | (1 << PlayerAuthInputFlags::PERFORM_BLOCK_ACTIONS));
if($itemStackRequest !== null){
$result->inputFlags |= 1 << PlayerAuthInputFlags::PERFORM_ITEM_STACK_REQUEST;
}
if($itemInteractionData !== null){
$result->inputFlags |= 1 << PlayerAuthInputFlags::PERFORM_ITEM_INTERACTION;
}
if($blockActions !== null){
$result->inputFlags |= 1 << PlayerAuthInputFlags::PERFORM_BLOCK_ACTIONS;
}
if($vehicleInfo !== null){
$result->inputFlags |= 1 << PlayerAuthInputFlags::IN_CLIENT_PREDICTED_VEHICLE;
if($inputFlags->getLength() !== 65){
throw new \InvalidArgumentException("Input flags must be 65 bits long");
}
$inputFlags->set(PlayerAuthInputFlags::PERFORM_ITEM_STACK_REQUEST, $itemStackRequest !== null);
$inputFlags->set(PlayerAuthInputFlags::PERFORM_ITEM_INTERACTION, $itemInteractionData !== null);
$inputFlags->set(PlayerAuthInputFlags::PERFORM_BLOCK_ACTIONS, $blockActions !== null);
$inputFlags->set(PlayerAuthInputFlags::IN_CLIENT_PREDICTED_VEHICLE, $vehicleInfo !== null);

$result->inputMode = $inputMode;
$result->playMode = $playMode;
Expand All @@ -120,6 +117,7 @@ public static function create(
$result->analogMoveVecX = $analogMoveVecX;
$result->analogMoveVecZ = $analogMoveVecZ;
$result->cameraOrientation = $cameraOrientation;
$result->rawMove = $rawMove;
return $result;
}

Expand Down Expand Up @@ -150,7 +148,7 @@ public function getMoveVecZ() : float{
/**
* @see PlayerAuthInputFlags
*/
public function getInputFlags() : int{
public function getInputFlags() : BitSet{
return $this->inputFlags;
}

Expand Down Expand Up @@ -215,7 +213,7 @@ public function getCameraOrientation(): Vector3 {
}

public function hasFlag(int $flag) : bool{
return ($this->inputFlags & (1 << $flag)) !== 0;
return $this->inputFlags->get($flag);
}

protected function decodePayload(PacketSerializer $in) : void{
Expand All @@ -225,7 +223,11 @@ protected function decodePayload(PacketSerializer $in) : void{
$this->moveVecX = $in->getLFloat();
$this->moveVecZ = $in->getLFloat();
$this->headYaw = $in->getLFloat();
$this->inputFlags = $in->getUnsignedVarLong();
if($in->getProtocol() >= ProtocolInfo::PROTOCOL_766){
$this->inputFlags = BitSet::read($in, 65);
}else{
$this->inputFlags = BitSet::readFromUnsignedVarLong($in, 65);
}
$this->inputMode = $in->getUnsignedVarInt();
$this->playMode = $in->getUnsignedVarInt();
if($in->getProtocol() >= ProtocolInfo::PROTOCOL_527){
Expand Down Expand Up @@ -270,6 +272,9 @@ protected function decodePayload(PacketSerializer $in) : void{
}
if($in->getProtocol() >= ProtocolInfo::PROTOCOL_748){
$this->cameraOrientation = $in->getVector3();
if($in->getProtocol() >= ProtocolInfo::PROTOCOL_766){
$this->rawMove = $in->getVector2();
}
}
}

Expand All @@ -280,7 +285,11 @@ protected function encodePayload(PacketSerializer $out) : void{
$out->putLFloat($this->moveVecX);
$out->putLFloat($this->moveVecZ);
$out->putLFloat($this->headYaw);
$out->putUnsignedVarLong($this->inputFlags);
if($out->getProtocol() >= ProtocolInfo::PROTOCOL_766){
$this->inputFlags->write($out);
}else{
$this->inputFlags->writeAsUnsignedVarLong($out);
}
$out->putUnsignedVarInt($this->inputMode);
$out->putUnsignedVarInt($this->playMode);
if($out->getProtocol() >= ProtocolInfo::PROTOCOL_527){
Expand Down Expand Up @@ -319,6 +328,9 @@ protected function encodePayload(PacketSerializer $out) : void{
}
if($out->getProtocol() >= ProtocolInfo::PROTOCOL_748){
$out->putVector3($this->cameraOrientation);
if($out->getProtocol() >= ProtocolInfo::PROTOCOL_766){
$out->putVector2($this->rawMove);
}
}
}

Expand Down
8 changes: 5 additions & 3 deletions src/ProtocolInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ private function __construct(){
*/

/** Actual Minecraft: PE protocol version */
public const CURRENT_PROTOCOL = 748;
public const CURRENT_PROTOCOL = 766;
/** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */
public const MINECRAFT_VERSION = 'v1.21.40';
public const MINECRAFT_VERSION = 'v1.21.50';
/** Version number sent to clients in ping responses. */
public const MINECRAFT_VERSION_NETWORK = '1.21.40';
public const MINECRAFT_VERSION_NETWORK = '1.21.50';

public const BASE_VERSION = '1.18.0';

public const PROTOCOL_766 = 766; // 1.21.50
public const PROTOCOL_748 = 748; // 1.21.40
public const PROTOCOL_729 = 729; // 1.21.30
public const PROTOCOL_712 = 712; // 1.21.20
Expand Down Expand Up @@ -69,6 +70,7 @@ private function __construct(){
public const PROTOCOL_475 = 475; // v1.18.0

public const COMPATIBLE_PROTOCOL = [
self::PROTOCOL_766,
self::PROTOCOL_748,
self::PROTOCOL_729,
self::PROTOCOL_712,
Expand Down
15 changes: 15 additions & 0 deletions src/ResourcePacksInfoPacket.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
use pocketmine\network\mcpe\protocol\types\resourcepacks\BehaviorPackInfoEntry;
use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackInfoEntry;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use function count;

class ResourcePacksInfoPacket extends DataPacket implements ClientboundPacket{
Expand All @@ -30,6 +32,9 @@ class ResourcePacksInfoPacket extends DataPacket implements ClientboundPacket{
public bool $hasAddons = false;
public bool $hasScripts = false; //if true, causes disconnect for any platform that doesn't support scripts yet
public bool $forceServerPacks = false;
public UuidInterface $worldTemplateId;
public string $worldTemplateVersion;

/**
* @var string[]
* @phpstan-var array<string, string>
Expand All @@ -52,6 +57,8 @@ public static function create(array $resourcePackEntries, array $behaviorPackEnt
$result->hasScripts = $hasScripts;
$result->forceServerPacks = $forceServerPacks;
$result->cdnUrls = $cdnUrls;
$result->worldTemplateId = Uuid::fromString("");
$result->worldTemplateVersion = "";
return $result;
}

Expand All @@ -61,6 +68,10 @@ protected function decodePayload(PacketSerializer $in) : void{
$this->hasAddons = $in->getBool();
}
$this->hasScripts = $in->getBool();
if($in->getProtocol() >= ProtocolInfo::PROTOCOL_766){
$this->worldTemplateId = $in->getUuid();
$this->worldTemplateVersion = $in->getString();
}
if($in->getProtocol() < ProtocolInfo::PROTOCOL_729) {
$this->forceServerPacks = $in->getBool();
}
Expand Down Expand Up @@ -92,6 +103,10 @@ protected function encodePayload(PacketSerializer $out) : void{
$out->putBool($this->hasAddons);
}
$out->putBool($this->hasScripts);
if($out->getProtocol() >= ProtocolInfo::PROTOCOL_766){
$out->putUuid($this->worldTemplateId);
$out->putString($this->worldTemplateVersion);
}
if($out->getProtocol() < ProtocolInfo::PROTOCOL_729) {
$out->putBool($this->forceServerPacks);
}
Expand Down
166 changes: 166 additions & 0 deletions src/serializer/BitSet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<?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\serializer;

use pocketmine\utils\BinaryDataException;
use function array_pad;
use function array_values;
use function chr;
use function count;
use function intdiv;
use function min;
use function ord;

class BitSet{
private const INT_BITS = PHP_INT_SIZE * 8;
private const SHIFT = 7;

/**
* @param int[] $parts
*/
public function __construct(
private readonly int $length,
private array $parts = []
){
$expectedPartsCount = intdiv($length + self::INT_BITS - 1, self::INT_BITS);
$partsCount = count($parts);

if($partsCount > $expectedPartsCount){
throw new \InvalidArgumentException("Too many parts");
}elseif($partsCount < $expectedPartsCount){
$parts = array_pad($parts, $expectedPartsCount, 0);
}

$this->parts = array_values($parts);
}

public function get(int $index) : bool{
[$partIndex, $bitIndex] = $this->getPartIndex($index);

return ($this->parts[$partIndex] & (1 << $bitIndex)) !== 0;
}

public function set(int $index, bool $value) : void{
[$partIndex, $bitIndex] = $this->getPartIndex($index);

if($value){
$this->parts[$partIndex] |= 1 << $bitIndex;
}else{
$this->parts[$partIndex] &= ~(1 << $bitIndex);
}
}

/**
* Returns the part index and the bit index within that part for a given bit index.
*
* @return array{int, int}
*/
private function getPartIndex(int $index) : array{
if($index < 0 or $index >= $this->length){
throw new \InvalidArgumentException("Index out of bounds");
}

return [
intdiv($index, self::INT_BITS),
$index % self::INT_BITS
];
}

public static function read(PacketSerializer $in, int $length) : self{
$result = [0];

$currentIndex = 0;
$currentShift = 0;

for($i = 0; $i < $length; $i += self::SHIFT){
$b = ord($in->get(1));
$bits = $b & 0x7f;

$result[$currentIndex] |= $bits << $currentShift; //extra bits will be discarded
$nextShift = $currentShift + self::SHIFT;
if($nextShift >= self::INT_BITS){
$nextShift -= self::INT_BITS;
$rightShift = self::SHIFT - $nextShift;
$result[++$currentIndex] = $bits >> $rightShift;
}
$currentShift = $nextShift;

if(($b & 0x80) === 0){
return new self($length, $result);
}
}

throw new BinaryDataException("Didn't terminate after reading $length bits");
}

public static function readFromUnsignedVarLong(PacketSerializer $in, int $minimum): self{
$flags = $in->getUnsignedVarLong();
$length = 63; // assume
$parts = [];
for($i = 0; $i < $length; $i++){
$parts[] = ($flags >> $i) & 1;
}
if($length < $minimum){
for($i = $length; $i < $minimum; $i++){
$parts[] = 0;
}
}
return new self($length, $parts);
}

public function write(PacketSerializer $out) : void{
$buf = "";

$parts = $this->parts;
$length = $this->length;

$currentIndex = 0;
$currentShift = 0;

for($i = 0; $i < $length; $i += self::SHIFT){
$bits = $parts[$currentIndex] >> $currentShift;
$nextShift = $currentShift + self::SHIFT;
if($nextShift >= self::INT_BITS){
$nextShift -= self::INT_BITS;
$bits |= $parts[++$currentIndex] << (self::SHIFT - $nextShift);
}
$currentShift = $nextShift;

$last = $i + self::SHIFT >= $length;
$bits |= $last ? 0 : 0x80;

$buf .= chr($bits);
if($last){
break;
}
}

$out->put($buf);
}

public function writeAsUnsignedVarLong(PacketSerializer $out): void{
$flags = 0;
$max = 63; // assume
for($i = 0; $i < min($max, $this->length); $i++){
$flags |= ($this->get($i) ? 1 : 0) << $i;
}

$out->putUnsignedVarLong($flags);
}

public function getLength() : int{
return $this->length;
}
}
Loading

0 comments on commit 6951fd8

Please sign in to comment.