From 6f3851be80b148d83f696f38f0fe16088877fda6 Mon Sep 17 00:00:00 2001 From: "Dylan T." Date: Sun, 6 Apr 2025 04:52:15 +0100 Subject: [PATCH 01/10] 5.27.1 (#6670) --- changelogs/5.27.md | 6 ++++++ composer.json | 2 +- composer.lock | 18 +++++++++--------- src/VersionInfo.php | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/changelogs/5.27.md b/changelogs/5.27.md index f3923d466..07bc8c26e 100644 --- a/changelogs/5.27.md +++ b/changelogs/5.27.md @@ -16,3 +16,9 @@ If you're upgrading from 5.25.x directly to 5.27.0, please also read the followi ## General - Aded support for Minecraft: Bedrock Edition 1.21.70. - Removed support for earlier versions. + +# 5.27.1 +Released 6th April 2025. + +## Fixes +- Updated RakLib to get ping timestamp handling fixes. diff --git a/composer.json b/composer.json index 8da46090b..77e32e3da 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "pocketmine/log": "^0.4.0", "pocketmine/math": "~1.0.0", "pocketmine/nbt": "~1.1.0", - "pocketmine/raklib": "~1.1.0", + "pocketmine/raklib": "~1.1.2", "pocketmine/raklib-ipc": "~1.0.0", "pocketmine/snooze": "^0.5.0", "ramsey/uuid": "~4.7.0", diff --git a/composer.lock b/composer.lock index 405a92414..16dcb5e3d 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": "28b4de9a23a293646dbad2707cdfd9e0", + "content-hash": "8d3061c5cc77e5b1dfa1fcf77f5146c6", "packages": [ { "name": "adhocore/json-comment", @@ -618,16 +618,16 @@ }, { "name": "pocketmine/raklib", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/pmmp/RakLib.git", - "reference": "be2783be516bf6e2872ff5c81fb9048596617b97" + "reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/RakLib/zipball/be2783be516bf6e2872ff5c81fb9048596617b97", - "reference": "be2783be516bf6e2872ff5c81fb9048596617b97", + "url": "https://api.github.com/repos/pmmp/RakLib/zipball/4145a31cd812fe8931c3c9c691fcd2ded2f47e7f", + "reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f", "shasum": "" }, "require": { @@ -639,8 +639,8 @@ "pocketmine/log": "^0.3.0 || ^0.4.0" }, "require-dev": { - "phpstan/phpstan": "1.10.1", - "phpstan/phpstan-strict-rules": "^1.0" + "phpstan/phpstan": "2.1.0", + "phpstan/phpstan-strict-rules": "^2.0" }, "type": "library", "autoload": { @@ -655,9 +655,9 @@ "description": "A RakNet server implementation written in PHP", "support": { "issues": "https://github.com/pmmp/RakLib/issues", - "source": "https://github.com/pmmp/RakLib/tree/1.1.1" + "source": "https://github.com/pmmp/RakLib/tree/1.1.2" }, - "time": "2024-03-04T14:02:14+00:00" + "time": "2025-04-06T03:38:21+00:00" }, { "name": "pocketmine/raklib-ipc", diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 0f776dc1d..249a27176 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.27.1"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; /** From d3f6c22996de69c215b87d51d21514761462e979 Mon Sep 17 00:00:00 2001 From: "pmmp-admin-bot[bot]" <188621379+pmmp-admin-bot[bot]@users.noreply.github.com> Date: Sun, 6 Apr 2025 03:53:08 +0000 Subject: [PATCH 02/10] 5.27.2 is next Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/14288755593 --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 249a27176..44238dba3 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.27.1"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "5.27.2"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; /** From 835c383d4e126df6f38000e3217ad6a325b7a1f7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 6 Apr 2025 19:59:02 +0100 Subject: [PATCH 03/10] Update Composer dependencies --- composer.json | 2 +- composer.lock | 50 ++++++++++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/composer.json b/composer.json index 77e32e3da..87086f456 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "symfony/filesystem": "~6.4.0" }, "require-dev": { - "phpstan/phpstan": "2.1.8", + "phpstan/phpstan": "2.1.11", "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 16dcb5e3d..23f312317 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": "8d3061c5cc77e5b1dfa1fcf77f5146c6", + "content-hash": "818c679a25da8e6b466bc454ad48dec3", "packages": [ { "name": "adhocore/json-comment", @@ -471,16 +471,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.24.1", + "version": "2.24.2", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "8f48cbe1fb5835a8bb573bed00ef04c65c26c7e5" + "reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/8f48cbe1fb5835a8bb573bed00ef04c65c26c7e5", - "reference": "8f48cbe1fb5835a8bb573bed00ef04c65c26c7e5", + "url": "https://api.github.com/repos/pmmp/Language/zipball/2a00c44c52bce98e7a43aa31517df78cbb2ba23b", + "reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b", "shasum": "" }, "type": "library", @@ -488,9 +488,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.24.1" + "source": "https://github.com/pmmp/Language/tree/2.24.2" }, - "time": "2025-03-16T19:04:15+00:00" + "time": "2025-04-03T01:23:27+00:00" }, { "name": "pocketmine/log", @@ -742,16 +742,16 @@ }, { "name": "ramsey/collection", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109" + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109", - "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109", + "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", "shasum": "" }, "require": { @@ -812,9 +812,9 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/2.1.0" + "source": "https://github.com/ramsey/collection/tree/2.1.1" }, - "time": "2025-03-02T04:48:29+00:00" + "time": "2025-03-22T05:38:12+00:00" }, { "name": "ramsey/uuid", @@ -1373,16 +1373,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.8", + "version": "2.1.11", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "f9adff3b87c03b12cc7e46a30a524648e497758f" + "reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f9adff3b87c03b12cc7e46a30a524648e497758f", - "reference": "f9adff3b87c03b12cc7e46a30a524648e497758f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8ca5f79a8f63c49b2359065832a654e1ec70ac30", + "reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30", "shasum": "" }, "require": { @@ -1427,20 +1427,20 @@ "type": "github" } ], - "time": "2025-03-09T09:30:48+00:00" + "time": "2025-03-24T13:45:00+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "2.0.4", + "version": "2.0.6", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "d09e152f403c843998d7a52b5d87040c937525dd" + "reference": "6b92469f8a7995e626da3aa487099617b8dfa260" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d09e152f403c843998d7a52b5d87040c937525dd", - "reference": "d09e152f403c843998d7a52b5d87040c937525dd", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6b92469f8a7995e626da3aa487099617b8dfa260", + "reference": "6b92469f8a7995e626da3aa487099617b8dfa260", "shasum": "" }, "require": { @@ -1451,7 +1451,9 @@ "phpunit/phpunit": "<7.0" }, "require-dev": { + "nikic/php-parser": "^5", "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9.6" }, @@ -1476,9 +1478,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.4" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.6" }, - "time": "2025-01-22T13:07:38+00:00" + "time": "2025-03-26T12:47:06+00:00" }, { "name": "phpstan/phpstan-strict-rules", From f661443ec79d44bbe850e18b58bc0d670dfe093a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 15 Apr 2025 16:48:13 +0100 Subject: [PATCH 04/10] Update Ubuntu base image for GitHub Actions --- .github/workflows/build-docker-image.yml | 2 +- .github/workflows/draft-release-pr-check.yml | 4 ++-- .github/workflows/draft-release.yml | 6 +++--- .github/workflows/main-php-matrix.yml | 2 +- .github/workflows/main.yml | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 6199ad7a9..83d568878 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -8,7 +8,7 @@ on: jobs: build: name: Update Docker Hub images - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Set up Docker Buildx diff --git a/.github/workflows/draft-release-pr-check.yml b/.github/workflows/draft-release-pr-check.yml index 131c0dde2..303f61ccf 100644 --- a/.github/workflows/draft-release-pr-check.yml +++ b/.github/workflows/draft-release-pr-check.yml @@ -24,7 +24,7 @@ permissions: jobs: check-intent: name: Check release trigger - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 outputs: valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }} @@ -43,7 +43,7 @@ jobs: #don't do these checks if this isn't a release - we don't want to generate unnecessary failed statuses if: needs.check-intent.outputs.valid == 'true' - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index d2e9eb0d0..02cdeec6f 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -23,7 +23,7 @@ env: jobs: skip: name: Check whether to ignore this tag - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 outputs: skip: ${{ steps.exists.outputs.exists == 'true' }} @@ -54,7 +54,7 @@ jobs: needs: [check] if: needs.check.outputs.valid == 'true' && github.ref_type != 'tag' #can't do post-commit for a tag - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Generate access token @@ -79,7 +79,7 @@ jobs: needs: [check] if: needs.check.outputs.valid == 'true' || github.ref_type == 'tag' #ignore validity check for tags - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/main-php-matrix.yml b/.github/workflows/main-php-matrix.yml index e26f7c318..015a33188 100644 --- a/.github/workflows/main-php-matrix.yml +++ b/.github/workflows/main-php-matrix.yml @@ -15,7 +15,7 @@ on: type: number image: description: 'Runner image to use' - default: 'ubuntu-20.04' + default: 'ubuntu-22.04' type: string jobs: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 571868747..051a3a790 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: codestyle: name: Code Style checks - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false @@ -40,7 +40,7 @@ jobs: shellcheck: name: ShellCheck - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false From 028815490ee69885bd5c9d2b1ef620ca8f0df4b7 Mon Sep 17 00:00:00 2001 From: zSALLAZAR <59490940+zSALLAZAR@users.noreply.github.com> Date: Fri, 18 Apr 2025 11:19:46 +0200 Subject: [PATCH 05/10] Add EntityExtinguishEvent (#6671) --- src/block/Water.php | 3 +- src/block/WaterCauldron.php | 3 +- src/entity/Entity.php | 10 ++-- src/event/entity/EntityExtinguishEvent.php | 53 ++++++++++++++++++++++ src/player/Player.php | 3 +- 5 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 src/event/entity/EntityExtinguishEvent.php diff --git a/src/block/Water.php b/src/block/Water.php index b711ab5a1..44759783a 100644 --- a/src/block/Water.php +++ b/src/block/Water.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\entity\Entity; +use pocketmine\event\entity\EntityExtinguishEvent; use pocketmine\world\sound\BucketEmptyWaterSound; use pocketmine\world\sound\BucketFillWaterSound; use pocketmine\world\sound\Sound; @@ -53,7 +54,7 @@ class Water extends Liquid{ public function onEntityInside(Entity $entity) : bool{ $entity->resetFallDistance(); if($entity->isOnFire()){ - $entity->extinguish(); + $entity->extinguish(EntityExtinguishEvent::CAUSE_WATER); } return true; } diff --git a/src/block/WaterCauldron.php b/src/block/WaterCauldron.php index e470aa6cb..8129f2960 100644 --- a/src/block/WaterCauldron.php +++ b/src/block/WaterCauldron.php @@ -27,6 +27,7 @@ use pocketmine\block\tile\Cauldron as TileCauldron; use pocketmine\block\utils\DyeColor; use pocketmine\color\Color; use pocketmine\entity\Entity; +use pocketmine\event\entity\EntityExtinguishEvent; use pocketmine\item\Armor; use pocketmine\item\Banner; use pocketmine\item\Dye; @@ -183,7 +184,7 @@ final class WaterCauldron extends FillableCauldron{ public function onEntityInside(Entity $entity) : bool{ if($entity->isOnFire()){ - $entity->extinguish(); + $entity->extinguish(EntityExtinguishEvent::CAUSE_WATER_CAULDRON); //TODO: particles $this->position->getWorld()->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::ENTITY_EXTINGUISH_USE_AMOUNT)); diff --git a/src/entity/Entity.php b/src/entity/Entity.php index e24c6067c..1637e0755 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -31,6 +31,7 @@ use pocketmine\block\Water; use pocketmine\entity\animation\Animation; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDespawnEvent; +use pocketmine\event\entity\EntityExtinguishEvent; use pocketmine\event\entity\EntityMotionEvent; use pocketmine\event\entity\EntityRegainHealthEvent; use pocketmine\event\entity\EntitySpawnEvent; @@ -709,7 +710,10 @@ abstract class Entity{ } } - public function extinguish() : void{ + public function extinguish(int $cause = EntityExtinguishEvent::CAUSE_CUSTOM) : void{ + $ev = new EntityExtinguishEvent($this, $cause); + $ev->call(); + $this->fireTicks = 0; $this->networkPropertiesDirty = true; } @@ -720,7 +724,7 @@ abstract class Entity{ protected function doOnFireTick(int $tickDiff = 1) : bool{ if($this->isFireProof() && $this->isOnFire()){ - $this->extinguish(); + $this->extinguish(EntityExtinguishEvent::CAUSE_FIRE_PROOF); return false; } @@ -731,7 +735,7 @@ abstract class Entity{ } if(!$this->isOnFire()){ - $this->extinguish(); + $this->extinguish(EntityExtinguishEvent::CAUSE_TICKING); }else{ return true; } diff --git a/src/event/entity/EntityExtinguishEvent.php b/src/event/entity/EntityExtinguishEvent.php new file mode 100644 index 000000000..b39d12231 --- /dev/null +++ b/src/event/entity/EntityExtinguishEvent.php @@ -0,0 +1,53 @@ + + */ +class EntityExtinguishEvent extends EntityEvent{ + public const CAUSE_CUSTOM = 0; + public const CAUSE_WATER = 1; + public const CAUSE_WATER_CAULDRON = 2; + public const CAUSE_RESPAWN = 3; + public const CAUSE_FIRE_PROOF = 4; + public const CAUSE_TICKING = 5; + public const CAUSE_RAIN = 6; + public const CAUSE_POWDER_SNOW = 7; + + public function __construct( + Entity $entity, + private int $cause + ){ + $this->entity = $entity; + } + + public function getCause() : int{ + return $this->cause; + } +} diff --git a/src/player/Player.php b/src/player/Player.php index 1c67b7182..3c494b980 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -45,6 +45,7 @@ use pocketmine\entity\projectile\Arrow; use pocketmine\entity\Skin; use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageEvent; +use pocketmine\event\entity\EntityExtinguishEvent; use pocketmine\event\inventory\InventoryCloseEvent; use pocketmine\event\inventory\InventoryOpenEvent; use pocketmine\event\player\PlayerBedEnterEvent; @@ -2546,7 +2547,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->setSneaking(false); $this->setFlying(false); - $this->extinguish(); + $this->extinguish(EntityExtinguishEvent::CAUSE_RESPAWN); $this->setAirSupplyTicks($this->getMaxAirSupplyTicks()); $this->deadTicks = 0; $this->noDamageTicks = 60; From 2548422973a4b6f4417f9fe9b0e02164991ad583 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 20 Apr 2025 16:44:23 +0100 Subject: [PATCH 06/10] AvailableEnchantmentRegistry: reject non-string tags fixes https://crash.pmmp.io/view/12627328 --- src/item/enchantment/AvailableEnchantmentRegistry.php | 3 +++ src/utils/Utils.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/item/enchantment/AvailableEnchantmentRegistry.php b/src/item/enchantment/AvailableEnchantmentRegistry.php index eed7bff52..2d8dafa4b 100644 --- a/src/item/enchantment/AvailableEnchantmentRegistry.php +++ b/src/item/enchantment/AvailableEnchantmentRegistry.php @@ -28,6 +28,7 @@ use pocketmine\item\enchantment\ItemEnchantmentTags as Tags; use pocketmine\item\enchantment\VanillaEnchantments as Enchantments; use pocketmine\item\Item; use pocketmine\utils\SingletonTrait; +use pocketmine\utils\Utils; use function array_filter; use function array_values; use function count; @@ -129,6 +130,7 @@ final class AvailableEnchantmentRegistry{ if(!$this->isRegistered($enchantment)){ throw new \LogicException("Cannot set primary item tags for non-registered enchantment"); } + Utils::validateArrayValueType($tags, fn(string $v) => 1); $this->primaryItemTags[spl_object_id($enchantment)] = array_values($tags); } @@ -152,6 +154,7 @@ final class AvailableEnchantmentRegistry{ if(!$this->isRegistered($enchantment)){ throw new \LogicException("Cannot set secondary item tags for non-registered enchantment"); } + Utils::validateArrayValueType($tags, fn(string $v) => 1); $this->secondaryItemTags[spl_object_id($enchantment)] = array_values($tags); } diff --git a/src/utils/Utils.php b/src/utils/Utils.php index 046296cf4..800bd0183 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -584,7 +584,7 @@ final class Utils{ /** * @phpstan-template TMemberType * @phpstan-param array $array - * @phpstan-param \Closure(TMemberType) : void $validator + * @phpstan-param \Closure(TMemberType) : mixed $validator */ public static function validateArrayValueType(array $array, \Closure $validator) : void{ foreach(Utils::promoteKeys($array) as $k => $v){ From 4a5c1e75407f9cf8b37795210fc0957f9a37059a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 20 Apr 2025 16:57:44 +0100 Subject: [PATCH 07/10] Entity: truncate fire ticks instead of throwing exceptions as written in the comments, it's not reasonable to propagate this limitation, since it ultimately comes from a shortfall in the Mojang save format, not a limitation of PM's capability. It's also not obvious how this would be propagated to the likes of setOnFire(), as this would translate into a max time of 1638 seconds, a value no one is going to remember. There's a case to be made for truncating this on save rather than on initial set, but this is at least better than having Fire Aspect level 1000 cause crashes and whatever other gameplay logic that would have to work around this stupid limitation. --- src/entity/Entity.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index e24c6067c..97cdc19de 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -60,6 +60,7 @@ use pocketmine\player\Player; use pocketmine\Server; use pocketmine\timings\Timings; use pocketmine\timings\TimingsHandler; +use pocketmine\utils\Limits; use pocketmine\utils\Utils; use pocketmine\VersionInfo; use pocketmine\world\format\Chunk; @@ -700,9 +701,16 @@ abstract class Entity{ * @throws \InvalidArgumentException */ public function setFireTicks(int $fireTicks) : void{ - if($fireTicks < 0 || $fireTicks > 0x7fff){ - throw new \InvalidArgumentException("Fire ticks must be in range 0 ... " . 0x7fff . ", got $fireTicks"); + if($fireTicks < 0){ + throw new \InvalidArgumentException("Fire ticks cannot be negative"); } + + //Since the max value is not externally obvious or intuitive, many plugins use this without being aware that + //reasonably large values are not accepted. We even have such usages within PM itself. It doesn't make sense + //to force all those calls to be aware of this limitation, as it's not a functional limit but a limitation of + //the Mojang save format. Truncating this to the max acceptable value is the next best thing we can do. + $fireTicks = min($fireTicks, Limits::INT16_MAX); + if(!$this->isFireProof()){ $this->fireTicks = $fireTicks; $this->networkPropertiesDirty = true; From 1ea5c060fdd23023857cdc7f874a6562d117a72d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 20 Apr 2025 18:16:54 +0100 Subject: [PATCH 08/10] bruh --- src/entity/Entity.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index 97cdc19de..6681558ad 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -77,6 +77,7 @@ use function floatval; use function floor; use function fmod; use function get_class; +use function min; use function sin; use function spl_object_id; use const M_PI_2; From ad6f7dfedb31a299d6d9c30961a76acf1f888f65 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 20 Apr 2025 19:48:28 +0100 Subject: [PATCH 09/10] World: verify saveability of blocks, entities and tiles at entry points I want to do the same for items, but items are going to be a pain in the ass. For items there are multiple possible entry points and all of them will need to be checked: - dropped items - inventory contents - lecterns - item frames I don't see a good way to deal with all these. We can't check for registration in the constructor because we need to fully construct the item in order to register it. Blocks are also a potential issue in other areas, but setBlock() is definitely the biggest offender. --- src/block/tile/TileFactory.php | 7 +++++++ .../convert/BlockObjectToStateSerializer.php | 4 ++++ src/entity/EntityFactory.php | 7 +++++++ src/world/World.php | 17 +++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/src/block/tile/TileFactory.php b/src/block/tile/TileFactory.php index 515dd8c63..26e0af6a5 100644 --- a/src/block/tile/TileFactory.php +++ b/src/block/tile/TileFactory.php @@ -114,6 +114,13 @@ final class TileFactory{ $this->saveNames[$className] = reset($saveNames); } + /** + * @phpstan-param class-string $class + */ + public function isRegistered(string $class) : bool{ + return isset($this->saveNames[$class]); + } + /** * @internal * @throws SavedDataLoadingException diff --git a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php index 367d38449..45784d409 100644 --- a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php +++ b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php @@ -225,6 +225,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{ return $this->cache[$stateId] ??= $this->serializeBlock(RuntimeBlockStateRegistry::getInstance()->fromStateId($stateId)); } + public function isRegistered(Block $block) : bool{ + return isset($this->serializers[$block->getTypeId()]); + } + /** * @phpstan-template TBlockType of Block * @phpstan-param TBlockType $block diff --git a/src/entity/EntityFactory.php b/src/entity/EntityFactory.php index 03d9c03e6..970fd986f 100644 --- a/src/entity/EntityFactory.php +++ b/src/entity/EntityFactory.php @@ -219,6 +219,13 @@ final class EntityFactory{ $this->saveNames[$className] = reset($saveNames); } + /** + * @phpstan-param class-string $class + */ + public function isRegistered(string $class) : bool{ + return isset($this->saveNames[$class]); + } + /** * Creates an entity from data stored on a chunk. * diff --git a/src/world/World.php b/src/world/World.php index 3a7d0c538..afd01c628 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2047,6 +2047,15 @@ class World implements ChunkManager{ throw new WorldException("Cannot set a block in un-generated terrain"); } + //TODO: this computes state ID twice (we do it again in writeStateToWorld()). Not great for performance :( + $stateId = $block->getStateId(); + if(!$this->blockStateRegistry->hasStateId($stateId)){ + throw new \LogicException("Block state ID not known to RuntimeBlockStateRegistry (probably not registered)"); + } + if(!GlobalBlockStateHandlers::getSerializer()->isRegistered($block)){ + throw new \LogicException("Block not registered with GlobalBlockStateHandlers serializer"); + } + $this->timings->setBlock->startTiming(); $this->unlockChunk($chunkX, $chunkZ, null); @@ -2769,6 +2778,11 @@ class World implements ChunkManager{ throw new AssumptionFailedError("Found two different entities sharing entity ID " . $entity->getId()); } } + if(!EntityFactory::getInstance()->isRegistered($entity::class)){ + //canSaveWithChunk is mutable, so that means it could be toggled after adding the entity and cause a crash + //later on. Better we just force all entities to have a save ID, even if it might not be needed. + throw new \LogicException("Entity " . $entity::class . " is not registered for a save ID in EntityFactory"); + } $pos = $entity->getPosition()->asVector3(); $this->entitiesByChunk[World::chunkHash($pos->getFloorX() >> Chunk::COORD_BIT_SIZE, $pos->getFloorZ() >> Chunk::COORD_BIT_SIZE)][$entity->getId()] = $entity; $this->entityLastKnownPositions[$entity->getId()] = $pos; @@ -2870,6 +2884,9 @@ class World implements ChunkManager{ if(!$this->isInWorld($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ())){ throw new \InvalidArgumentException("Tile position is outside the world bounds"); } + if(!TileFactory::getInstance()->isRegistered($tile::class)){ + throw new \LogicException("Tile " . $tile::class . " is not registered for a save ID in TileFactory"); + } $chunkX = $pos->getFloorX() >> Chunk::COORD_BIT_SIZE; $chunkZ = $pos->getFloorZ() >> Chunk::COORD_BIT_SIZE; From fe70b3188138e3262adad6e96d3f4cadd6b6c144 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 26 Apr 2025 22:11:03 +0100 Subject: [PATCH 10/10] Fix crash when a player is added to the world --- src/world/World.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/World.php b/src/world/World.php index afd01c628..7ffe8e00b 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2778,7 +2778,7 @@ class World implements ChunkManager{ throw new AssumptionFailedError("Found two different entities sharing entity ID " . $entity->getId()); } } - if(!EntityFactory::getInstance()->isRegistered($entity::class)){ + if(!EntityFactory::getInstance()->isRegistered($entity::class) && !$entity instanceof Player){ //canSaveWithChunk is mutable, so that means it could be toggled after adding the entity and cause a crash //later on. Better we just force all entities to have a save ID, even if it might not be needed. throw new \LogicException("Entity " . $entity::class . " is not registered for a save ID in EntityFactory");