From b4cb09fe5e8f93bb98c7192f252867af0966508a Mon Sep 17 00:00:00 2001 From: ShockedPlot7560 Date: Sat, 22 Mar 2025 20:21:56 +0100 Subject: [PATCH] continue refactoring, not finished, not tested This is a bump from my workspace --- src/block/utils/AnvilHelper.php | 9 +++-- src/crafting/AnvilCraftResult.php | 35 ++++++++++++++++--- src/crafting/AnvilRecipe.php | 2 -- src/crafting/CraftingManager.php | 1 + .../CraftingManagerFromDataHelper.php | 12 +++---- src/crafting/ItemCombineRecipe.php | 28 ++++----------- src/crafting/MaterialRepairRecipe.php | 24 ++++++------- .../transaction/AnvilTransaction.php | 8 ++--- src/item/ToolTier.php | 2 +- .../mcpe/handler/ItemStackRequestExecutor.php | 2 +- 10 files changed, 67 insertions(+), 56 deletions(-) diff --git a/src/block/utils/AnvilHelper.php b/src/block/utils/AnvilHelper.php index 9bf5c3fa8b..b35c824c96 100644 --- a/src/block/utils/AnvilHelper.php +++ b/src/block/utils/AnvilHelper.php @@ -39,20 +39,23 @@ final class AnvilHelper{ public static function calculateResult(Player $player, Item $base, Item $material, ?string $customName = null) : ?AnvilCraftResult { $recipe = Server::getInstance()->getCraftingManager()->matchAnvilRecipe($base, $material); + if($recipe === null){ + return null; + } $result = $recipe->getResultFor($base, $material); if($result !== null){ - $resultItem = $result->getResult(); + $resultItem = $result->getOutput(); $xpCost = $result->getXpCost(); if(($customName === null || $customName === "") && $resultItem->hasCustomName()){ $xpCost++; $resultItem->clearCustomName(); - }elseif($resultItem->getCustomName() !== $customName){ + }elseif($customName !== null && $resultItem->getCustomName() !== $customName){ $xpCost++; $resultItem->setCustomName($customName); } - $result = new AnvilCraftResult($xpCost, $resultItem); + $result = new AnvilCraftResult($xpCost, $resultItem, $result->getSacrificeResult()); } if($result === null || $result->getXpCost() <= 0 || ($result->getXpCost() > self::COST_LIMIT && !$player->isCreative())){ diff --git a/src/crafting/AnvilCraftResult.php b/src/crafting/AnvilCraftResult.php index 02a8e12e3f..a9e0e620b8 100644 --- a/src/crafting/AnvilCraftResult.php +++ b/src/crafting/AnvilCraftResult.php @@ -25,17 +25,44 @@ namespace pocketmine\crafting; use pocketmine\item\Item; +/** + * This class is here to hold the result of an anvil crafting process. + */ class AnvilCraftResult{ + /** + * @param int $xpCost + * @param Item $output + * @param Item|null $sacrificeResult If the given item is considered as null (count <= 0), the value will be set to null. + */ public function __construct( private int $xpCost, - private Item $result, - ){} + private Item $output, + private ?Item $sacrificeResult + ){ + if($this->sacrificeResult !== null && $this->sacrificeResult->isNull()){ + $this->sacrificeResult = null; + } + } + /** + * Represent the amount of experience points required to craft the output item. + */ public function getXpCost() : int{ return $this->xpCost; } - public function getResult() : Item{ - return $this->result; + /** + * Represent the item given as output of the crafting process. + */ + public function getOutput() : Item{ + return $this->output; + } + + /** + * This result has to be null if the sacrifice slot need to be emptied. + * If not null, it represent the item that will be left in the sacrifice slot after the crafting process. + */ + public function getSacrificeResult() : ?Item{ + return $this->sacrificeResult; } } diff --git a/src/crafting/AnvilRecipe.php b/src/crafting/AnvilRecipe.php index ae38cd4d79..6da3e90f4b 100644 --- a/src/crafting/AnvilRecipe.php +++ b/src/crafting/AnvilRecipe.php @@ -26,7 +26,5 @@ namespace pocketmine\crafting; use pocketmine\item\Item; interface AnvilRecipe{ - public function getXpCost() : int; - public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult; } diff --git a/src/crafting/CraftingManager.php b/src/crafting/CraftingManager.php index 185630b62d..b8e595886d 100644 --- a/src/crafting/CraftingManager.php +++ b/src/crafting/CraftingManager.php @@ -34,6 +34,7 @@ use function count; use function implode; use function ksort; use function spl_object_id; +use function var_dump; use const SORT_STRING; class CraftingManager{ diff --git a/src/crafting/CraftingManagerFromDataHelper.php b/src/crafting/CraftingManagerFromDataHelper.php index 4561333f6e..b55fd92efb 100644 --- a/src/crafting/CraftingManagerFromDataHelper.php +++ b/src/crafting/CraftingManagerFromDataHelper.php @@ -31,8 +31,10 @@ use pocketmine\crafting\json\RecipeIngredientData; use pocketmine\crafting\json\ShapedRecipeData; use pocketmine\crafting\json\ShapelessRecipeData; use pocketmine\data\bedrock\block\BlockStateData; +use pocketmine\data\bedrock\block\BlockTypeNames; use pocketmine\data\bedrock\item\BlockItemIdMap; use pocketmine\data\bedrock\item\ItemTypeDeserializeException; +use pocketmine\data\bedrock\item\ItemTypeNames; use pocketmine\data\bedrock\item\SavedItemData; use pocketmine\data\bedrock\item\SavedItemStackData; use pocketmine\data\SavedDataLoadingException; @@ -335,15 +337,13 @@ final class CraftingManagerFromDataHelper{ } $result->registerAnvilRecipe(new MaterialRepairRecipe( - new ExactRecipeIngredient(VanillaItems::DIAMOND_PICKAXE()), - new ExactRecipeIngredient(VanillaItems::DIAMOND()), - VanillaItems::DIAMOND_PICKAXE() + new MetaWildcardRecipeIngredient(ItemTypeNames::DIAMOND_PICKAXE), + new ExactRecipeIngredient(VanillaItems::DIAMOND()) )); $result->registerAnvilRecipe(new ItemCombineRecipe( - new ExactRecipeIngredient(VanillaItems::DIAMOND_PICKAXE()), - new ExactRecipeIngredient(VanillaItems::DIAMOND_PICKAXE()), - VanillaItems::DIAMOND_PICKAXE() + new MetaWildcardRecipeIngredient(ItemTypeNames::DIAMOND_PICKAXE), + new MetaWildcardRecipeIngredient(ItemTypeNames::DIAMOND_PICKAXE) )); //TODO: smithing diff --git a/src/crafting/ItemCombineRecipe.php b/src/crafting/ItemCombineRecipe.php index 5c49900b1f..2c90eaed47 100644 --- a/src/crafting/ItemCombineRecipe.php +++ b/src/crafting/ItemCombineRecipe.php @@ -40,8 +40,7 @@ use function min; class ItemCombineRecipe implements AnvilRecipe{ public function __construct( private RecipeIngredient $input, - private RecipeIngredient $material, - private Item $result + private RecipeIngredient $material ){ } public function getInput() : RecipeIngredient{ @@ -52,22 +51,14 @@ class ItemCombineRecipe implements AnvilRecipe{ return $this->material; } - public function getResult() : Item{ - return clone $this->result; - } - - public function getXpCost() : int{ - return 2; - } - public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult{ - if($input->equals($this->input->getItem()) && $material->equals($this->material->getItem())){ - $result = $this->getResult(); + if($this->input->accepts($input) && $this->material->accepts($material)){ + $result = (clone $input); $xpCost = 0; - if($input instanceof Durable && $material instanceof Durable){ - $damage = $input->getDamage(); + if($result instanceof Durable && $material instanceof Durable){ + $damage = $result->getDamage(); if($damage !== 0){ - $baseMaxDurability = $input->getMaxDurability(); + $baseMaxDurability = $result->getMaxDurability(); $baseDurability = $baseMaxDurability - $damage; $materialDurability = $material->getMaxDurability() - $material->getDamage(); $addDurability = (int) ($baseMaxDurability * 12 / 100); @@ -78,11 +69,6 @@ class ItemCombineRecipe implements AnvilRecipe{ $xpCost = 2; } - // setting base enchantments to result - foreach($input->getEnchantments() as $enchantment){ - $result->addEnchantment($enchantment); - } - // combining enchantments foreach($material->getEnchantments() as $instance){ $enchantment = $instance->getType(); @@ -131,7 +117,7 @@ class ItemCombineRecipe implements AnvilRecipe{ ); } - return new AnvilCraftResult($xpCost, $result); + return new AnvilCraftResult($xpCost, $result, null); } return null; diff --git a/src/crafting/MaterialRepairRecipe.php b/src/crafting/MaterialRepairRecipe.php index 8f5af1d28b..72edbe5690 100644 --- a/src/crafting/MaterialRepairRecipe.php +++ b/src/crafting/MaterialRepairRecipe.php @@ -23,11 +23,14 @@ declare(strict_types=1); namespace pocketmine\crafting; +use pocketmine\item\Durable; use pocketmine\item\Item; +use pocketmine\item\Tool; use function ceil; use function floor; use function max; use function min; +use function var_dump; /** * Represent a recipe that repair an item with a material in an anvil. @@ -35,8 +38,7 @@ use function min; class MaterialRepairRecipe implements AnvilRecipe{ public function __construct( private RecipeIngredient $input, - private RecipeIngredient $material, - private Item $result + private RecipeIngredient $material ){ } public function getInput() : RecipeIngredient{ @@ -47,16 +49,8 @@ class MaterialRepairRecipe implements AnvilRecipe{ return $this->material; } - public function getResult() : Item{ - return clone $this->result; - } - - public function getXpCost() : int{ - return 1; - } - - public function getResultFor(Item $input, Item $material) : ?Item{ - if($this->input->accepts($input) && $this->material->accepts($material)){ + public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult{ + if($this->input->accepts($input) && $this->material->accepts($material) && $input instanceof Durable){ $damage = $input->getDamage(); if($damage !== 0){ $quarter = min($damage, (int) floor($input->getMaxDurability() / 4)); @@ -65,7 +59,11 @@ class MaterialRepairRecipe implements AnvilRecipe{ // TODO: remove the material $damage -= $quarter * $numberRepair; } - return $this->getResult()->setDamage(max(0, $damage)); + return new AnvilCraftResult( + $numberRepair, + (clone $input)->setDamage(max(0, $damage)), + $material->pop($numberRepair) + ); } } diff --git a/src/inventory/transaction/AnvilTransaction.php b/src/inventory/transaction/AnvilTransaction.php index 556cf78b6e..90aa6c1f48 100644 --- a/src/inventory/transaction/AnvilTransaction.php +++ b/src/inventory/transaction/AnvilTransaction.php @@ -67,7 +67,7 @@ class AnvilTransaction extends InventoryTransaction{ if($calculAttempt === null){ return null; } - $result = $calculAttempt->getResult(); + $result = $calculAttempt->getOutput(); if(!$result->equalsExact($expectedOutput)){ return null; } @@ -119,7 +119,7 @@ class AnvilTransaction extends InventoryTransaction{ parent::execute(); if($this->source->hasFiniteResources()){ - $this->source->getXpManager()->subtractXpLevels($this->expectedResult->getRepairCost()); + $this->source->getXpManager()->subtractXpLevels($this->expectedResult->getXpCost()); } $inventory = $this->source->getCurrentWindow(); @@ -148,9 +148,7 @@ class AnvilTransaction extends InventoryTransaction{ throw new AssumptionFailedError("Expected that baseItem are not null before executing the event"); } - $ev = new PlayerUseAnvilEvent($this->source, $this->baseItem, $this->materialItem, $this->expectedResult->getResult() ?? throw new \AssertionError( - "Expected that the expected result is not null" - ), $this->customName, $this->expectedResult->getXpCost()); + $ev = new PlayerUseAnvilEvent($this->source, $this->baseItem, $this->materialItem, $this->expectedResult->getOutput(), $this->customName, $this->expectedResult->getXpCost()); $ev->call(); return !$ev->isCancelled(); } diff --git a/src/item/ToolTier.php b/src/item/ToolTier.php index eed69f0db7..8469bc7e5f 100644 --- a/src/item/ToolTier.php +++ b/src/item/ToolTier.php @@ -36,7 +36,7 @@ use pocketmine\utils\LegacyEnumShimTrait; * @method static ToolTier STONE() * @method static ToolTier WOOD() * - * @phpstan-type TMetadata array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int[]} + * @phpstan-type TMetadata array{0: int, 1: int, 2: int, 3: int, 4: int} */ enum ToolTier{ use LegacyEnumShimTrait; diff --git a/src/network/mcpe/handler/ItemStackRequestExecutor.php b/src/network/mcpe/handler/ItemStackRequestExecutor.php index b57aab31b5..9701ec9e5d 100644 --- a/src/network/mcpe/handler/ItemStackRequestExecutor.php +++ b/src/network/mcpe/handler/ItemStackRequestExecutor.php @@ -358,7 +358,7 @@ class ItemStackRequestExecutor{ $result = AnvilHelper::calculateResult($this->player, $window->getInput(), $window->getMaterial(), $this->request->getFilterStrings()[0] ?? null); if($result !== null){ $this->specialTransaction = new AnvilTransaction($this->player, $result, $this->request->getFilterStrings()[0] ?? null); - $this->setNextCreatedItem($result->getResult()); + $this->setNextCreatedItem($result->getOutput()); } } }elseif($action instanceof CraftingConsumeInputStackRequestAction){