diff --git a/changelogs/4.18.md b/changelogs/4.18.md index 435784fb0..890f00d6d 100644 --- a/changelogs/4.18.md +++ b/changelogs/4.18.md @@ -97,3 +97,15 @@ Released 29th March 2023. ## Fixes - Fixed players being unable to join due to the appearance of a new `x5t` field in the JWT header of Xbox Live authentication tokens. - Fixed items' durability appearing to reset when moving them around in the inventory. + +# 4.18.3 +Released 5th April 2023. + +## Fixes +- Fixed Average Players not being shown on timings reports when custom player classes are used. +- Fixed incorrect tick violation calculation in timings reports. +- Fixed not being able to add or remove items from the offhand slot. +- Fixed creative inventory item count corruption when taking items (some players would see 64x items in the creative inventory after rejoining or changing gamemode). +- Fixed not being able to drop items directly from the creative inventory on mobile. +- Fixed `DataPacketReceiveEvent` not being called for packets sent by `EntityEventBroadcaster`. +- `CreativeInventory::getItem()` and `CreativeInventory::getAll()` now return cloned itemstacks, to prevent accidental modification of the creative inventory. diff --git a/composer.json b/composer.json index 1bc3c5370..1eb2eb866 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ "webmozart/path-util": "^2.3" }, "require-dev": { - "phpstan/phpstan": "1.10.7", + "phpstan/phpstan": "1.10.11", "phpstan/phpstan-phpunit": "^1.1.0", "phpstan/phpstan-strict-rules": "^1.2.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index 8d914bb31..17a18e11e 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": "7c779ace575b5ef662eb5a6b0f173418", + "content-hash": "6cd5185a409af08d842a5e41ba3b877b", "packages": [ { "name": "adhocore/json-comment", @@ -1884,16 +1884,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.7", + "version": "1.10.11", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975" + "reference": "8aa62e6ea8b58ffb650e02940e55a788cbc3fe21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b10ceb526d9607903c5b2673f1fc8775dbe48975", - "reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8aa62e6ea8b58ffb650e02940e55a788cbc3fe21", + "reference": "8aa62e6ea8b58ffb650e02940e55a788cbc3fe21", "shasum": "" }, "require": { @@ -1942,7 +1942,7 @@ "type": "tidelift" } ], - "time": "2023-03-16T15:24:20+00:00" + "time": "2023-04-04T19:17:42+00:00" }, { "name": "phpstan/phpstan-phpunit", @@ -1998,16 +1998,16 @@ }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "b7dd96a5503919a43b3cd06a2dced9d4252492f2" + "reference": "b21c03d4f6f3a446e4311155f4be9d65048218e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/b7dd96a5503919a43b3cd06a2dced9d4252492f2", - "reference": "b7dd96a5503919a43b3cd06a2dced9d4252492f2", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/b21c03d4f6f3a446e4311155f4be9d65048218e6", + "reference": "b21c03d4f6f3a446e4311155f4be9d65048218e6", "shasum": "" }, "require": { @@ -2041,9 +2041,9 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.0" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.1" }, - "time": "2023-02-21T10:17:10+00:00" + "time": "2023-03-29T14:47:40+00:00" }, { "name": "phpunit/php-code-coverage", @@ -2365,16 +2365,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.5", + "version": "9.6.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5" + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86e761949019ae83f49240b2f2123fb5ab3b2fc5", - "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115", + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115", "shasum": "" }, "require": { @@ -2447,7 +2447,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.5" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6" }, "funding": [ { @@ -2463,7 +2464,7 @@ "type": "tidelift" } ], - "time": "2023-03-09T06:34:10+00:00" + "time": "2023-03-27T11:43:46+00:00" }, { "name": "sebastian/cli-parser", diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 0ac681340..61ec22aec 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,7 +31,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.18.3"; + public const BASE_VERSION = "4.18.4"; public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; diff --git a/src/inventory/CreativeInventory.php b/src/inventory/CreativeInventory.php index 25d3152a4..7d6754f8c 100644 --- a/src/inventory/CreativeInventory.php +++ b/src/inventory/CreativeInventory.php @@ -27,6 +27,7 @@ use pocketmine\item\Durable; use pocketmine\item\Item; use pocketmine\utils\Filesystem; use pocketmine\utils\SingletonTrait; +use pocketmine\utils\Utils; use Symfony\Component\Filesystem\Path; use function json_decode; @@ -60,11 +61,11 @@ final class CreativeInventory{ * @return Item[] */ public function getAll() : array{ - return $this->creative; + return Utils::cloneObjectArray($this->creative); } public function getItem(int $index) : ?Item{ - return $this->creative[$index] ?? null; + return isset($this->creative[$index]) ? clone $this->creative[$index] : null; } public function getItemIndex(Item $item) : int{ diff --git a/src/network/mcpe/NetworkBroadcastUtils.php b/src/network/mcpe/NetworkBroadcastUtils.php index 8d04d35c5..76ae98738 100644 --- a/src/network/mcpe/NetworkBroadcastUtils.php +++ b/src/network/mcpe/NetworkBroadcastUtils.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace pocketmine\network\mcpe; -use pocketmine\event\server\DataPacketSendEvent; use pocketmine\network\mcpe\protocol\ClientboundPacket; use pocketmine\player\Player; use pocketmine\timings\Timings; @@ -57,13 +56,6 @@ final class NetworkBroadcastUtils{ return false; } - $ev = new DataPacketSendEvent($sessions, $packets); - $ev->call(); - if($ev->isCancelled()){ - return false; - } - $sessions = $ev->getTargets(); - /** @var PacketBroadcaster[] $uniqueBroadcasters */ $uniqueBroadcasters = []; /** @var NetworkSession[][] $broadcasterTargets */ diff --git a/src/network/mcpe/StandardPacketBroadcaster.php b/src/network/mcpe/StandardPacketBroadcaster.php index 1ed0f16ae..da9fa5101 100644 --- a/src/network/mcpe/StandardPacketBroadcaster.php +++ b/src/network/mcpe/StandardPacketBroadcaster.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe; +use pocketmine\event\server\DataPacketSendEvent; use pocketmine\network\mcpe\protocol\serializer\PacketBatch; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext; @@ -41,6 +42,15 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{ ){} public function broadcastPackets(array $recipients, array $packets) : void{ + //TODO: this shouldn't really be called here, since the broadcaster might be replaced by an alternative + //implementation that doesn't fire events + $ev = new DataPacketSendEvent($recipients, $packets); + $ev->call(); + if($ev->isCancelled()){ + return; + } + $packets = $ev->getPackets(); + $compressors = []; /** @var NetworkSession[][] $targetsByCompressor */ diff --git a/src/network/mcpe/handler/ItemStackRequestExecutor.php b/src/network/mcpe/handler/ItemStackRequestExecutor.php index 840a23cc1..81d820c2b 100644 --- a/src/network/mcpe/handler/ItemStackRequestExecutor.php +++ b/src/network/mcpe/handler/ItemStackRequestExecutor.php @@ -147,6 +147,11 @@ class ItemStackRequestExecutor{ * @throws ItemStackRequestProcessException */ protected function removeItemFromSlot(ItemStackRequestSlotInfo $slotInfo, int $count) : Item{ + if($slotInfo->getContainerId() === ContainerUIIds::CREATED_OUTPUT && $slotInfo->getSlotId() === UIInventorySlotOffset::CREATED_ITEM_OUTPUT){ + //special case for the "created item" output slot + //TODO: do we need to send a response for this slot info? + return $this->takeCreatedItem($count); + } $this->requestSlotInfos[] = $slotInfo; [$inventory, $slot] = $this->getBuilderInventoryAndSlot($slotInfo); if($count < 1){ @@ -188,6 +193,13 @@ class ItemStackRequestExecutor{ $inventory->setItem($slot, $newItem); } + protected function dropItem(Item $item, int $count) : void{ + if($count < 1){ + throw new ItemStackRequestProcessException("Cannot drop less than 1 of an item"); + } + $this->builder->addAction(new DropItemAction((clone $item)->setCount($count))); + } + /** * @throws ItemStackRequestProcessException */ @@ -254,7 +266,7 @@ class ItemStackRequestExecutor{ /** * @throws ItemStackRequestProcessException */ - protected function takeCreatedItem(ItemStackRequestSlotInfo $destination, int $count) : void{ + protected function takeCreatedItem(int $count) : Item{ if($count < 1){ //this should be impossible at the protocol level, but in case of buggy core code this will prevent exploits throw new ItemStackRequestProcessException("Cannot take less than 1 created item"); @@ -272,10 +284,12 @@ class ItemStackRequestExecutor{ } $this->createdItemsTakenCount += $count; - $this->addItemToSlot($destination, $createdItem, $count); + $createdItem = clone $createdItem; + $createdItem->setCount($count); if(!$this->createdItemFromCreativeInventory && $this->createdItemsTakenCount >= $createdItem->getCount()){ $this->setNextCreatedItem(null); } + return $createdItem; } /** @@ -299,14 +313,7 @@ class ItemStackRequestExecutor{ $action instanceof TakeStackRequestAction || $action instanceof PlaceStackRequestAction ){ - $source = $action->getSource(); - $destination = $action->getDestination(); - - if($source->getContainerId() === ContainerUIIds::CREATED_OUTPUT && $source->getSlotId() === UIInventorySlotOffset::CREATED_ITEM_OUTPUT){ - $this->takeCreatedItem($destination, $action->getCount()); - }else{ - $this->transferItems($source, $destination, $action->getCount()); - } + $this->transferItems($action->getSource(), $action->getDestination(), $action->getCount()); }elseif($action instanceof SwapStackRequestAction){ $this->requestSlotInfos[] = $action->getSlot1(); $this->requestSlotInfos[] = $action->getSlot2();