From 9744bd70733aa2fd7181242d9baadde0de0ec686 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 17 Feb 2025 15:35:18 +0000 Subject: [PATCH] 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); } /**