From 9744bd70733aa2fd7181242d9baadde0de0ec686 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 17 Feb 2025 15:35:18 +0000 Subject: [PATCH 1/2] CraftingManager: make a less dumb hash function fixes #4415 --- src/crafting/CraftingManager.php | 48 +++++++++++++------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/src/crafting/CraftingManager.php b/src/crafting/CraftingManager.php index 895eeaccc..93d6e1838 100644 --- a/src/crafting/CraftingManager.php +++ b/src/crafting/CraftingManager.php @@ -29,8 +29,12 @@ use pocketmine\nbt\TreeRoot; use pocketmine\utils\BinaryStream; use pocketmine\utils\DestructorCallbackTrait; use pocketmine\utils\ObjectSet; +use function array_shift; +use function count; +use function implode; +use function ksort; use function spl_object_id; -use function usort; +use const SORT_STRING; class CraftingManager{ use DestructorCallbackTrait; @@ -100,6 +104,7 @@ class CraftingManager{ /** * Function used to arrange Shapeless Recipe ingredient lists into a consistent order. + * @deprecated */ public static function sort(Item $i1, Item $i2) : int{ //Use spaceship operator to compare each property, then try the next one if they are equivalent. @@ -108,45 +113,30 @@ class CraftingManager{ return $retval; } - /** - * @param Item[] $items - * - * @return Item[] - * @phpstan-return list - */ - private static function pack(array $items) : array{ - $result = []; + private static function hashOutput(Item $output) : string{ + $write = new BinaryStream(); + $write->putVarInt($output->getStateId()); + $write->put((new LittleEndianNbtSerializer())->write(new TreeRoot($output->getNamedTag()))); - foreach($items as $item){ - foreach($result as $otherItem){ - if($item->canStackWith($otherItem)){ - $otherItem->setCount($otherItem->getCount() + $item->getCount()); - continue 2; - } - } - - //No matching item found - $result[] = clone $item; - } - - return $result; + return $write->getBuffer(); } /** * @param Item[] $outputs */ private static function hashOutputs(array $outputs) : string{ - $outputs = self::pack($outputs); - usort($outputs, [self::class, "sort"]); - $result = new BinaryStream(); + if(count($outputs) === 1){ + return self::hashOutput(array_shift($outputs)); + } + $unique = []; foreach($outputs as $o){ //count is not written because the outputs might be from multiple repetitions of a single recipe //this reduces the accuracy of the hash, but it won't matter in most cases. - $result->putVarInt($o->getStateId()); - $result->put((new LittleEndianNbtSerializer())->write(new TreeRoot($o->getNamedTag()))); + $hash = self::hashOutput($o); + $unique[$hash] = $hash; } - - return $result->getBuffer(); + ksort($unique, SORT_STRING); + return implode("", $unique); } /** From 77be5f8e25cb0a9f0fb7fcd79183ff63e65d4e05 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 17 Feb 2025 17:51:39 +0000 Subject: [PATCH 2/2] Update PHPStan --- composer.json | 2 +- composer.lock | 36 +++++++++++----------- src/Server.php | 2 +- src/utils/Utils.php | 2 +- tests/phpstan/configs/actual-problems.neon | 32 +------------------ tests/phpstan/configs/phpstan-bugs.neon | 6 ---- 6 files changed, 22 insertions(+), 58 deletions(-) diff --git a/composer.json b/composer.json index f8d060bcd..ac35fef77 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "symfony/filesystem": "~6.4.0" }, "require-dev": { - "phpstan/phpstan": "2.1.4", + "phpstan/phpstan": "2.1.5", "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 cc7f1f716..e5c60aa7d 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": "af7547291a131bfac6d7087957601325", + "content-hash": "dcf1176890f95cb24670e69c8c8f1216", "packages": [ { "name": "adhocore/json-comment", @@ -1150,16 +1150,16 @@ "packages-dev": [ { "name": "myclabs/deep-copy", - "version": "1.12.1", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", "shasum": "" }, "require": { @@ -1198,7 +1198,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" }, "funding": [ { @@ -1206,7 +1206,7 @@ "type": "tidelift" } ], - "time": "2024-11-08T17:47:46+00:00" + "time": "2025-02-12T12:17:51+00:00" }, { "name": "nikic/php-parser", @@ -1386,16 +1386,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.4", + "version": "2.1.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a" + "reference": "451b17f9665481ee502adc39be987cb71067ece2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f99e18eb775dbaf6460c95fa0b65312da9c746a", - "reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/451b17f9665481ee502adc39be987cb71067ece2", + "reference": "451b17f9665481ee502adc39be987cb71067ece2", "shasum": "" }, "require": { @@ -1440,7 +1440,7 @@ "type": "github" } ], - "time": "2025-02-10T08:25:21+00:00" + "time": "2025-02-13T12:49:56+00:00" }, { "name": "phpstan/phpstan-phpunit", @@ -1864,16 +1864,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.44", + "version": "10.5.45", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1381c62769be4bb88fa4c5aec1366c7c66ca4f36" + "reference": "bd68a781d8e30348bc297449f5234b3458267ae8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1381c62769be4bb88fa4c5aec1366c7c66ca4f36", - "reference": "1381c62769be4bb88fa4c5aec1366c7c66ca4f36", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8", + "reference": "bd68a781d8e30348bc297449f5234b3458267ae8", "shasum": "" }, "require": { @@ -1945,7 +1945,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.44" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45" }, "funding": [ { @@ -1961,7 +1961,7 @@ "type": "tidelift" } ], - "time": "2025-01-31T07:00:38+00:00" + "time": "2025-02-06T16:08:12+00:00" }, { "name": "sebastian/cli-parser", diff --git a/src/Server.php b/src/Server.php index 252964a91..679a0ef0b 100644 --- a/src/Server.php +++ b/src/Server.php @@ -699,7 +699,7 @@ class Server{ public function removeOp(string $name) : void{ $lowercaseName = strtolower($name); - foreach($this->operators->getAll() as $operatorName => $_){ + foreach(Utils::promoteKeys($this->operators->getAll()) as $operatorName => $_){ $operatorName = (string) $operatorName; if($lowercaseName === strtolower($operatorName)){ $this->operators->remove($operatorName); diff --git a/src/utils/Utils.php b/src/utils/Utils.php index 46cd49ec4..2a9dd65da 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -587,7 +587,7 @@ final class Utils{ * @phpstan-param \Closure(TMemberType) : void $validator */ public static function validateArrayValueType(array $array, \Closure $validator) : void{ - foreach($array as $k => $v){ + foreach(Utils::promoteKeys($array) as $k => $v){ try{ $validator($v); }catch(\TypeError $e){ diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index ef9828b37..73b7a65c1 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -48,12 +48,6 @@ parameters: count: 1 path: ../../../src/VersionInfo.php - - - message: '#^Method pocketmine\\VersionInfo\:\:GIT_HASH\(\) should return string but returns mixed\.$#' - identifier: return.type - count: 1 - path: ../../../src/VersionInfo.php - - message: '#^Static property pocketmine\\VersionInfo\:\:\$gitHash \(string\|null\) does not accept mixed\.$#' identifier: assign.propertyType @@ -918,24 +912,6 @@ parameters: count: 1 path: ../../../src/plugin/PluginDescription.php - - - message: '#^Parameter \#1 \$haystack of function stripos expects string, mixed given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/plugin/PluginDescription.php - - - - message: '#^Parameter \#2 \$subject of function preg_match expects string, mixed given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/plugin/PluginDescription.php - - - - message: '#^Parameter \#3 \$subject of function str_replace expects array\\|string, mixed given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/plugin/PluginDescription.php - - message: '#^Property pocketmine\\plugin\\PluginDescription\:\:\$authors \(array\\) does not accept list\\.$#' identifier: assign.propertyType @@ -966,12 +942,6 @@ parameters: count: 1 path: ../../../src/resourcepacks/ZippedResourcePack.php - - - message: '#^Method pocketmine\\resourcepacks\\ZippedResourcePack\:\:getSha256\(\) should return string but returns string\|false\.$#' - identifier: return.type - count: 1 - path: ../../../src/resourcepacks/ZippedResourcePack.php - - message: '#^Property pocketmine\\resourcepacks\\ZippedResourcePack\:\:\$fileResource \(resource\) does not accept resource\|false\.$#' identifier: assign.propertyType @@ -1009,7 +979,7 @@ parameters: path: ../../../src/utils/Config.php - - message: '#^Parameter \#1 \$config of static method pocketmine\\utils\\Config\:\:writeProperties\(\) expects array\, array\ given\.$#' + message: '#^Parameter \#1 \$config of static method pocketmine\\utils\\Config\:\:writeProperties\(\) expects array\, array\ given\.$#' identifier: argument.type count: 1 path: ../../../src/utils/Config.php diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 9ab125763..aeb3fae29 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -114,12 +114,6 @@ parameters: count: 1 path: ../../../src/crash/CrashDump.php - - - message: '#^Call to function assert\(\) with false and ''unknown hit type'' will always evaluate to false\.$#' - identifier: function.impossibleType - count: 1 - path: ../../../src/entity/projectile/Projectile.php - - message: '#^Property pocketmine\\item\\WritableBookBase\:\:\$pages \(list\\) does not accept non\-empty\-array\\.$#' identifier: assign.propertyType