From eaab4b35d284260faea7e6cee37c29eedfe131c1 Mon Sep 17 00:00:00 2001 From: ShockedPlot7560 Date: Sat, 22 Mar 2025 23:00:15 +0100 Subject: [PATCH] add unit testing on MaterialRepairRecipe --- src/block/utils/AnvilHelper.php | 5 +- .../AnvilCraftingManagerDataFiller.php | 12 ++ src/crafting/MaterialRepairRecipe.php | 2 +- .../transaction/AnvilTransaction.php | 6 +- .../mcpe/handler/ItemStackRequestExecutor.php | 2 +- tests/phpunit/crafting/AnvilCraftTest.php | 104 ++++++++++++++++++ 6 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 tests/phpunit/crafting/AnvilCraftTest.php diff --git a/src/block/utils/AnvilHelper.php b/src/block/utils/AnvilHelper.php index 957c9da3f..97d8204b8 100644 --- a/src/block/utils/AnvilHelper.php +++ b/src/block/utils/AnvilHelper.php @@ -25,7 +25,6 @@ namespace pocketmine\block\utils; use pocketmine\crafting\AnvilCraftResult; use pocketmine\item\Item; -use pocketmine\player\Player; use pocketmine\Server; final class AnvilHelper{ @@ -36,7 +35,7 @@ final class AnvilHelper{ * * Returns null if the operation can't do anything. */ - public static function calculateResult(Player $player, Item $base, Item $material, ?string $customName = null) : ?AnvilCraftResult{ + public static function calculateResult(Item $base, Item $material, ?string $customName, bool $isCreative) : ?AnvilCraftResult{ $recipe = Server::getInstance()->getCraftingManager()->matchAnvilRecipe($base, $material); if($recipe === null){ @@ -58,7 +57,7 @@ final class AnvilHelper{ $result = new AnvilCraftResult($xpCost, $resultItem, $result->getSacrificeResult()); } - if($result === null || $result->getXpCost() <= 0 || ($result->getXpCost() > self::COST_LIMIT && !$player->isCreative())){ + if($result === null || $result->getXpCost() <= 0 || ($result->getXpCost() > self::COST_LIMIT && !$isCreative)){ return null; } diff --git a/src/crafting/AnvilCraftingManagerDataFiller.php b/src/crafting/AnvilCraftingManagerDataFiller.php index d226c7a7f..ee7abb7ea 100644 --- a/src/crafting/AnvilCraftingManagerDataFiller.php +++ b/src/crafting/AnvilCraftingManagerDataFiller.php @@ -23,9 +23,11 @@ declare(strict_types=1); namespace pocketmine\crafting; +use pocketmine\item\Durable; use pocketmine\item\ToolTier; use pocketmine\item\VanillaArmorMaterials; use pocketmine\item\VanillaItems; +use pocketmine\world\format\io\GlobalItemDataHandlers; final class AnvilCraftingManagerDataFiller{ public static function fillData(CraftingManager $manager) : CraftingManager{ @@ -62,6 +64,16 @@ final class AnvilCraftingManagerDataFiller{ } } + foreach(VanillaItems::getAll() as $item){ + if($item instanceof Durable){ + $itemId = GlobalItemDataHandlers::getSerializer()->serializeType($item)->getName(); + $manager->registerAnvilRecipe(new ItemCombineRecipe( + new MetaWildcardRecipeIngredient($itemId), + new MetaWildcardRecipeIngredient($itemId) + )); + } + } + return $manager; } } diff --git a/src/crafting/MaterialRepairRecipe.php b/src/crafting/MaterialRepairRecipe.php index 77d45c9ad..66f332fb5 100644 --- a/src/crafting/MaterialRepairRecipe.php +++ b/src/crafting/MaterialRepairRecipe.php @@ -59,7 +59,7 @@ class MaterialRepairRecipe implements AnvilRecipe{ return new AnvilCraftResult( $numberRepair, (clone $input)->setDamage(max(0, $damage)), - (clone $material)->pop($numberRepair) + (clone $material)->setCount($material->getCount() - $numberRepair) ); } } diff --git a/src/inventory/transaction/AnvilTransaction.php b/src/inventory/transaction/AnvilTransaction.php index 90aa6c1f4..cb7f1f5bd 100644 --- a/src/inventory/transaction/AnvilTransaction.php +++ b/src/inventory/transaction/AnvilTransaction.php @@ -46,7 +46,7 @@ class AnvilTransaction extends InventoryTransaction{ Player $source, private readonly AnvilCraftResult $expectedResult, private readonly ?string $customName - ) { + ){ parent::__construct($source); } @@ -62,8 +62,8 @@ class AnvilTransaction extends InventoryTransaction{ } } - private function validateInputs(Item $base, Item $material, Item $expectedOutput) : ?int { - $calculAttempt = AnvilHelper::calculateResult($this->source, $base, $material, $this->customName); + private function validateInputs(Item $base, Item $material, Item $expectedOutput) : ?int{ + $calculAttempt = AnvilHelper::calculateResult($base, $material, $this->customName, $this->source->isCreative()); if($calculAttempt === null){ return null; } diff --git a/src/network/mcpe/handler/ItemStackRequestExecutor.php b/src/network/mcpe/handler/ItemStackRequestExecutor.php index 9701ec9e5..61576d2e1 100644 --- a/src/network/mcpe/handler/ItemStackRequestExecutor.php +++ b/src/network/mcpe/handler/ItemStackRequestExecutor.php @@ -355,7 +355,7 @@ class ItemStackRequestExecutor{ }elseif($action instanceof CraftRecipeOptionalStackRequestAction){ $window = $this->player->getCurrentWindow(); if($window instanceof AnvilInventory){ - $result = AnvilHelper::calculateResult($this->player, $window->getInput(), $window->getMaterial(), $this->request->getFilterStrings()[0] ?? null); + $result = AnvilHelper::calculateResult($window->getInput(), $window->getMaterial(), $this->request->getFilterStrings()[0] ?? null, $this->player->isCreative()); if($result !== null){ $this->specialTransaction = new AnvilTransaction($this->player, $result, $this->request->getFilterStrings()[0] ?? null); $this->setNextCreatedItem($result->getOutput()); diff --git a/tests/phpunit/crafting/AnvilCraftTest.php b/tests/phpunit/crafting/AnvilCraftTest.php new file mode 100644 index 000000000..b35bfb352 --- /dev/null +++ b/tests/phpunit/crafting/AnvilCraftTest.php @@ -0,0 +1,104 @@ + [ + VanillaItems::DIAMOND_PICKAXE(), + VanillaItems::DIAMOND(), + null + ]; + + yield "Repair one damage" => [ + VanillaItems::DIAMOND_PICKAXE()->setDamage(1), + VanillaItems::DIAMOND(), + new AnvilCraftResult(1, VanillaItems::DIAMOND_PICKAXE(), null) + ]; + + yield "Repair one damage with more materials than expected" => [ + VanillaItems::DIAMOND_PICKAXE()->setDamage(1), + VanillaItems::DIAMOND()->setCount(2), + new AnvilCraftResult(1, VanillaItems::DIAMOND_PICKAXE(), VanillaItems::DIAMOND()) + ]; + + $diamondPickaxeQuarter = (int) floor(VanillaItems::DIAMOND_PICKAXE()->getMaxDurability() / 4); + yield "Repair one quarter" => [ + VanillaItems::DIAMOND_PICKAXE()->setDamage($diamondPickaxeQuarter), + VanillaItems::DIAMOND()->setCount(1), + new AnvilCraftResult(1, VanillaItems::DIAMOND_PICKAXE(), null) + ]; + + yield "Repair one quarter plus 1" => [ + VanillaItems::DIAMOND_PICKAXE()->setDamage($diamondPickaxeQuarter + 1), + VanillaItems::DIAMOND()->setCount(1), + new AnvilCraftResult(1, VanillaItems::DIAMOND_PICKAXE()->setDamage(1), null) + ]; + + yield "Repair more than one quarter" => [ + VanillaItems::DIAMOND_PICKAXE()->setDamage($diamondPickaxeQuarter * 2), + VanillaItems::DIAMOND()->setCount(2), + new AnvilCraftResult(2, VanillaItems::DIAMOND_PICKAXE(), null) + ]; + + yield "Repair more than one quarter with more materials than expected" => [ + VanillaItems::DIAMOND_PICKAXE()->setDamage($diamondPickaxeQuarter * 2), + VanillaItems::DIAMOND()->setCount(3), + new AnvilCraftResult(2, VanillaItems::DIAMOND_PICKAXE(), VanillaItems::DIAMOND()->setCount(1)) + ]; + } + + /** + * @dataProvider materialRepairRecipe + */ + public function testMaterialRepairRecipe(Item $base, Item $material, ?AnvilCraftResult $expected) : void{ + $recipe = new MaterialRepairRecipe( + new ExactRecipeIngredient((clone $base)->setCount(1)), + new ExactRecipeIngredient((clone $material)->setCount(1)) + ); + $result = $recipe->getResultFor($base, $material); + if($expected === null){ + self::assertNull($result, "Recipe did not match expected result"); + return; + }else{ + self::assertNotNull($result, "Recipe did not match expected result"); + } + self::assertEquals($expected->getXpCost(), $result->getXpCost(), "XP cost did not match expected result"); + self::assertTrue($expected->getOutput()->equalsExact($result->getOutput()), "Recipe output did not match expected result"); + $sacrificeResult = $expected->getSacrificeResult(); + if($sacrificeResult !== null){ + $resultExpected = $result->getSacrificeResult(); + self::assertNotNull($resultExpected, "Recipe sacrifice result did not match expected result"); + self::assertTrue($sacrificeResult->equalsExact($resultExpected), "Recipe sacrifice result did not match expected result"); + }else{ + self::assertNull($result->getSacrificeResult(), "Recipe sacrifice result did not match expected result"); + } + } +}