From c6a28d8df0e67251182d21e75127370da29e2683 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 15 Sep 2025 17:34:35 +0100 Subject: [PATCH 1/6] InventoryManager: fixed window sending getting stuck on client rejecting window opening closes #6778 honestly, we could just stop checking the window ID entirely, considering the need for delaying and waiting for window close acks, it seems useless at this point... --- src/network/mcpe/InventoryManager.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/network/mcpe/InventoryManager.php b/src/network/mcpe/InventoryManager.php index 19bd94fce..01368ec0a 100644 --- a/src/network/mcpe/InventoryManager.php +++ b/src/network/mcpe/InventoryManager.php @@ -64,6 +64,7 @@ use pocketmine\network\mcpe\protocol\types\inventory\WindowTypes; use pocketmine\network\PacketHandlingException; use pocketmine\player\Player; use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Binary; use pocketmine\utils\ObjectSet; use function array_fill_keys; use function array_keys; @@ -419,6 +420,15 @@ class InventoryManager{ } public function onClientRemoveWindow(int $id) : void{ + if(Binary::signByte($id) === ContainerIds::NONE){ //TODO: REMOVE signByte() once BedrockProtocol + ext-encoding are implemented + //TODO: HACK! Since 1.21.100 (and probably earlier), the client will send -1 to close windows that it can't + //view for some reason, e.g. if the chat window was already open. This is pretty awkward, since it means + //that we can only assume it refers to the most recently sent window, and if we don't handle it, + //InventoryManager will never get the green light to send subsequent windows, which breaks inventory UIs. + //Fortunately, we already wait for close acks anyway, so the window ID is technically useless...? + $this->session->getLogger()->debug("Client rejected opening of a window, assuming it was $this->lastInventoryNetworkId"); + $id = $this->lastInventoryNetworkId; + } if($id === $this->lastInventoryNetworkId){ if(isset($this->networkIdToInventoryMap[$id]) && $id !== $this->pendingCloseWindowId){ $this->remove($id); From e7ad3c25fa0200d201284ea23d3781d5cd266a87 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 15 Sep 2025 18:02:10 +0100 Subject: [PATCH 2/6] InGamePacketHandler: ignore CREATIVE_PLAYER_DESTROY_BLOCK fixes #6757 we get PREDICT_DESTROY_BLOCK anyway, so it's not needed --- src/network/mcpe/handler/InGamePacketHandler.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 6aae60745..8b8e0e69f 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -717,7 +717,8 @@ class InGamePacketHandler extends PacketHandler{ case PlayerAction::INTERACT_BLOCK: //TODO: ignored (for now) break; case PlayerAction::CREATIVE_PLAYER_DESTROY_BLOCK: - //TODO: do we need to handle this? + //in server auth block breaking, we get PREDICT_DESTROY_BLOCK anyway, so this action is redundant + break; case PlayerAction::PREDICT_DESTROY_BLOCK: self::validateFacing($face); if(!$this->player->breakBlock($pos)){ From b237cacfc9466a1197058803ed405447f71a9521 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 15 Sep 2025 19:36:29 +0100 Subject: [PATCH 3/6] InGamePacketHandler: don't resync blocks if the client predicted an interact fail if the prediction was a fail, we can assume that the client didn't do anything visual on its end, which avoids the need to resend blocks. This fixes block lag when towering as discussed in #6803. The more general issue in #6803 remains unresolved (that the server's block resyncing may overwrite additional client side predictions if it places a block before the server's resync for the initial placement arrives), but that's more complicated to fix and I'm not convinced on the correct method to resolve it yet. In any case, this change nets a decent improvement for everyone, regardless. --- src/network/mcpe/handler/InGamePacketHandler.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 8b8e0e69f..18b3f110f 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -89,6 +89,7 @@ use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds; use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\NetworkInventoryAction; use pocketmine\network\mcpe\protocol\types\inventory\NormalTransactionData; +use pocketmine\network\mcpe\protocol\types\inventory\PredictedResult; use pocketmine\network\mcpe\protocol\types\inventory\ReleaseItemTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\ItemStackRequest; use pocketmine\network\mcpe\protocol\types\inventory\stackresponse\ItemStackResponse; @@ -498,11 +499,13 @@ class InGamePacketHandler extends PacketHandler{ $blockPos = $data->getBlockPosition(); $vBlockPos = new Vector3($blockPos->getX(), $blockPos->getY(), $blockPos->getZ()); $this->player->interactBlock($vBlockPos, $data->getFace(), $clickPos); - //always sync this in case plugins caused a different result than the client expected - //we *could* try to enhance detection of plugin-altered behaviour, but this would require propagating - //more information up the stack. For now I think this is good enough. - //if only the client would tell us what blocks it thinks changed... - $this->syncBlocksNearby($vBlockPos, $data->getFace()); + if($data->getClientInteractPrediction() === PredictedResult::SUCCESS){ + //always sync this in case plugins caused a different result than the client expected + //we *could* try to enhance detection of plugin-altered behaviour, but this would require propagating + //more information up the stack. For now I think this is good enough. + //if only the client would tell us what blocks it thinks changed... + $this->syncBlocksNearby($vBlockPos, $data->getFace()); + } return true; case UseItemTransactionData::ACTION_CLICK_AIR: if($this->player->isUsingItem()){ From a056af16173cd178d8c4240422a8371fd945759c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 15 Sep 2025 22:41:02 +0100 Subject: [PATCH 4/6] Update composer dev dependencies --- build/generate-block-serializer-consts.php | 6 +++ composer.json | 2 +- composer.lock | 40 +++++++++---------- .../block/upgrade/BlockStateUpgrader.php | 4 ++ tests/phpstan/configs/actual-problems.neon | 12 ++++++ tests/phpstan/configs/phpstan-bugs.neon | 12 ------ .../configs/spl-fixed-array-sucks.neon | 23 +++++++++++ .../utils/CloningRegistryTraitTest.php | 2 +- tools/blockstate-upgrade-schema-utils.php | 3 ++ 9 files changed, 70 insertions(+), 34 deletions(-) diff --git a/build/generate-block-serializer-consts.php b/build/generate-block-serializer-consts.php index 875729fcf..6dab2ceb2 100644 --- a/build/generate-block-serializer-consts.php +++ b/build/generate-block-serializer-consts.php @@ -29,6 +29,9 @@ use pocketmine\data\bedrock\block\BlockStateStringValues; use pocketmine\data\bedrock\block\BlockTypeNames; use pocketmine\errorhandler\ErrorToExceptionHandler; use pocketmine\nbt\NbtException; +use pocketmine\nbt\tag\ByteTag; +use pocketmine\nbt\tag\IntTag; +use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\convert\BlockStateDictionary; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Utils; @@ -78,6 +81,9 @@ function generateBlockPaletteReport(array $states) : BlockPaletteReport{ $name = $stateData->getName(); $result->seenTypes[$name] = $name; foreach(Utils::stringifyKeys($stateData->getStates()) as $k => $v){ + if(!$v instanceof ByteTag && !$v instanceof IntTag && !$v instanceof StringTag){ + throw new AssumptionFailedError("Assumed all state tags should be TAG_Byte, TAG_Int or TAG_String, but found $k ($v) on block $name"); + } $result->seenStateValues[$k][$v->getValue()] = $v->getValue(); asort($result->seenStateValues[$k]); } diff --git a/composer.json b/composer.json index 17271955e..bef8b1250 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "symfony/filesystem": "~6.4.0" }, "require-dev": { - "phpstan/phpstan": "2.1.17", + "phpstan/phpstan": "2.1.25", "phpstan/phpstan-phpunit": "^2.0.0", "phpstan/phpstan-strict-rules": "^2.0.0", "phpunit/phpunit": "^10.5.24" diff --git a/composer.lock b/composer.lock index 31cad5d9e..be22909f1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "27fee330bdcb6ea2373c57cdfb3bc22f", + "content-hash": "008c888b5812dda09a0ec6e425453153", "packages": [ { "name": "adhocore/json-comment", @@ -1204,16 +1204,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.17", + "version": "2.1.25", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053" + "reference": "4087d28bd252895874e174d65e26b2c202ed893a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053", - "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/4087d28bd252895874e174d65e26b2c202ed893a", + "reference": "4087d28bd252895874e174d65e26b2c202ed893a", "shasum": "" }, "require": { @@ -1258,25 +1258,25 @@ "type": "github" } ], - "time": "2025-05-21T20:55:28+00:00" + "time": "2025-09-12T14:26:42+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "2.0.6", + "version": "2.0.7", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "6b92469f8a7995e626da3aa487099617b8dfa260" + "reference": "9a9b161baee88a5f5c58d816943cff354ff233dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6b92469f8a7995e626da3aa487099617b8dfa260", - "reference": "6b92469f8a7995e626da3aa487099617b8dfa260", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/9a9b161baee88a5f5c58d816943cff354ff233dc", + "reference": "9a9b161baee88a5f5c58d816943cff354ff233dc", "shasum": "" }, "require": { "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.0.4" + "phpstan/phpstan": "^2.1.18" }, "conflict": { "phpunit/phpunit": "<7.0" @@ -1309,9 +1309,9 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.6" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.7" }, - "time": "2025-03-26T12:47:06+00:00" + "time": "2025-07-13T11:31:46+00:00" }, { "name": "phpstan/phpstan-strict-rules", @@ -1684,16 +1684,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.54", + "version": "10.5.55", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b1dbbaaf96106b76d500b9d3db51f9b01f6a3589" + "reference": "4b2d546b336876bd9562f24641b08a25335b06b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b1dbbaaf96106b76d500b9d3db51f9b01f6a3589", - "reference": "b1dbbaaf96106b76d500b9d3db51f9b01f6a3589", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4b2d546b336876bd9562f24641b08a25335b06b6", + "reference": "4b2d546b336876bd9562f24641b08a25335b06b6", "shasum": "" }, "require": { @@ -1714,7 +1714,7 @@ "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.3", + "sebastian/comparator": "^5.0.4", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", "sebastian/exporter": "^5.1.2", @@ -1765,7 +1765,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.54" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.55" }, "funding": [ { @@ -1789,7 +1789,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T06:19:38+00:00" + "time": "2025-09-14T06:19:20+00:00" }, { "name": "sebastian/cli-parser", diff --git a/src/data/bedrock/block/upgrade/BlockStateUpgrader.php b/src/data/bedrock/block/upgrade/BlockStateUpgrader.php index a3e72807e..acfd0c503 100644 --- a/src/data/bedrock/block/upgrade/BlockStateUpgrader.php +++ b/src/data/bedrock/block/upgrade/BlockStateUpgrader.php @@ -278,6 +278,10 @@ final class BlockStateUpgrader{ private function applyPropertyFlattened(BlockStateUpgradeSchemaFlattenInfo $flattenInfo, string $oldName, array $states) : array{ $flattenedValue = $states[$flattenInfo->flattenedProperty] ?? null; $expectedType = $flattenInfo->flattenedPropertyType; + if($expectedType === null){ + //TODO: we can't make this non-nullable in a patch release + throw new AssumptionFailedError("We never give this null"); + } if(!$flattenedValue instanceof $expectedType){ //flattened property is not of the expected type, so this transformation is not applicable return [$oldName, $states]; diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 570303843..76cebf283 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -948,6 +948,12 @@ parameters: count: 1 path: ../../../src/plugin/PluginDescription.php + - + message: '#^Property pocketmine\\plugin\\PluginDescription\:\:\$srcNamespacePrefix \(string\) does not accept mixed\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/plugin/PluginDescription.php + - message: '#^Cannot call method addChild\(\) on pocketmine\\permission\\Permission\|null\.$#' identifier: method.nonObject @@ -990,6 +996,12 @@ parameters: count: 1 path: ../../../src/scheduler/TaskScheduler.php + - + message: '#^Possibly invalid array key type mixed\.$#' + identifier: offsetAccess.invalidOffset + count: 1 + path: ../../../src/thread/ThreadManager.php + - message: '#^Cannot access offset string on mixed\.$#' identifier: offsetAccess.nonOffsetAccessible diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index a80050020..65064ab6c 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -192,18 +192,6 @@ parameters: count: 1 path: ../../../src/network/mcpe/cache/CraftingDataCache.php - - - message: '#^Method pocketmine\\network\\mcpe\\compression\\ZlibCompressor\:\:getNetworkId\(\) never returns 1 so it can be removed from the return type\.$#' - identifier: return.unusedType - count: 1 - path: ../../../src/network/mcpe/compression/ZlibCompressor.php - - - - message: '#^Method pocketmine\\network\\mcpe\\compression\\ZlibCompressor\:\:getNetworkId\(\) never returns 255 so it can be removed from the return type\.$#' - identifier: return.unusedType - count: 1 - path: ../../../src/network/mcpe/compression/ZlibCompressor.php - - message: '#^Parameter \#1 \$states of class pocketmine\\network\\mcpe\\convert\\BlockStateDictionary constructor expects list\, array\, pocketmine\\network\\mcpe\\convert\\BlockStateDictionaryEntry\> given\.$#' identifier: argument.type diff --git a/tests/phpstan/configs/spl-fixed-array-sucks.neon b/tests/phpstan/configs/spl-fixed-array-sucks.neon index 05524fb8c..9c5ab915f 100644 --- a/tests/phpstan/configs/spl-fixed-array-sucks.neon +++ b/tests/phpstan/configs/spl-fixed-array-sucks.neon @@ -30,3 +30,26 @@ parameters: count: 4 path: ../../../src/world/generator/noise/Noise.php + - + message: '#^Parameter \$q00 of static method pocketmine\\world\\generator\\noise\\Noise\:\:bilinearLerp\(\) expects float, float\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/world/generator/noise/Noise.php + + - + message: '#^Parameter \$q01 of static method pocketmine\\world\\generator\\noise\\Noise\:\:bilinearLerp\(\) expects float, float\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/world/generator/noise/Noise.php + + - + message: '#^Parameter \$q10 of static method pocketmine\\world\\generator\\noise\\Noise\:\:bilinearLerp\(\) expects float, float\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/world/generator/noise/Noise.php + + - + message: '#^Parameter \$q11 of static method pocketmine\\world\\generator\\noise\\Noise\:\:bilinearLerp\(\) expects float, float\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/world/generator/noise/Noise.php diff --git a/tests/phpunit/utils/CloningRegistryTraitTest.php b/tests/phpunit/utils/CloningRegistryTraitTest.php index e3b53ecb5..3a1e6a5e0 100644 --- a/tests/phpunit/utils/CloningRegistryTraitTest.php +++ b/tests/phpunit/utils/CloningRegistryTraitTest.php @@ -47,7 +47,7 @@ final class CloningRegistryTraitTest extends TestCase{ public function testGetAllClone() : void{ $list1 = TestCloningRegistry::getAll(); $list2 = TestCloningRegistry::getAll(); - foreach(Utils::promoteKeys($list1) as $k => $member){ + foreach(Utils::stringifyKeys($list1) as $k => $member){ self::assertNotSame($member, $list2[$k], "VanillaBlocks ought to clone its members"); } } diff --git a/tools/blockstate-upgrade-schema-utils.php b/tools/blockstate-upgrade-schema-utils.php index 7c34b7728..80a79bd89 100644 --- a/tools/blockstate-upgrade-schema-utils.php +++ b/tools/blockstate-upgrade-schema-utils.php @@ -354,6 +354,9 @@ function processStateGroup(string $oldName, array $upgradeTable, BlockStateUpgra * @param string[] $strings */ function findCommonPrefix(array $strings) : string{ + if(count($strings) === 0){ + return ""; + } sort($strings, SORT_STRING); $first = $strings[array_key_first($strings)]; From 1e797b989725bf0b2211f3fd381023ff157f573b Mon Sep 17 00:00:00 2001 From: "Dylan T." Date: Mon, 15 Sep 2025 23:53:05 +0100 Subject: [PATCH 5/6] Prepare 5.33.2 release (#6804) --- changelogs/5.33.md | 12 ++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/changelogs/5.33.md b/changelogs/5.33.md index fe2e15a07..65ff6620d 100644 --- a/changelogs/5.33.md +++ b/changelogs/5.33.md @@ -133,3 +133,15 @@ Released 31st August 2025. ## Fixes - Fixed banners placed in prior versions getting their tiles deleted (due to missing `Type` tags). + +# 5.33.2 +Released 16th September 2025. + +## General +- PHP 8.4 has now been added to the test matrix. + +## Fixes +- Fixed PHP 8.4 deprecation notice in `AsyncGeneratorExecutor`. +- Fixed inventory windows breaking if a window is sent while the player has the chat window open (e.g. quickly pressing E followed by / could trigger this). +- Fixed `BlockBreakEvent` being called twice in creative if cancelled. +- Reduced block lag when towering and other situations where the placed block might intersect with the player's AABB. Block lag may still appear on higher latency clients - this is still being worked on. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 855e78aaa..5f457cfc1 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "5.33.2"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; /** From 40a1a29f0dac93c1afb887177dd36bf757492c70 Mon Sep 17 00:00:00 2001 From: "pmmp-admin-bot[bot]" <188621379+pmmp-admin-bot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:54:12 +0000 Subject: [PATCH 6/6] 5.33.3 is next Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/17748879758 --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 5f457cfc1..944d6d84f 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "5.33.2"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "5.33.3"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; /**