From 54f746fc111bbdb9b2eff422f5734bf245175bab Mon Sep 17 00:00:00 2001 From: ShockedPlot7560 Date: Sat, 10 Aug 2024 23:16:54 +0200 Subject: [PATCH] finalize anvil transaction --- src/block/utils/AnvilHelper.php | 6 ++- .../transaction/AnvilTransaction.php | 53 +++++++++++++++++-- .../mcpe/handler/ItemStackRequestExecutor.php | 2 +- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/block/utils/AnvilHelper.php b/src/block/utils/AnvilHelper.php index 816d86d37..ed8a1bfd5 100644 --- a/src/block/utils/AnvilHelper.php +++ b/src/block/utils/AnvilHelper.php @@ -168,8 +168,10 @@ class AnvilHelper{ $item->clearCustomName(); } }else{ - $resultCost += self::COST_RENAME; - $item->setCustomName($customName); + if($item->getCustomName() !== $customName){ + $resultCost += self::COST_RENAME; + $item->setCustomName($customName); + } } return $resultCost; diff --git a/src/inventory/transaction/AnvilTransaction.php b/src/inventory/transaction/AnvilTransaction.php index fd4512ebf..7301df982 100644 --- a/src/inventory/transaction/AnvilTransaction.php +++ b/src/inventory/transaction/AnvilTransaction.php @@ -23,19 +23,43 @@ declare(strict_types=1); namespace pocketmine\inventory\transaction; +use pocketmine\block\utils\AnvilHelper; use pocketmine\block\utils\AnvilResult; use pocketmine\item\Item; +use pocketmine\item\VanillaItems; use pocketmine\player\Player; use function count; class AnvilTransaction extends InventoryTransaction{ public function __construct( Player $source, - private AnvilResult $anvilResult + private readonly AnvilResult $expectedResult, + private readonly ?string $customName ) { parent::__construct($source); } + private function validateFiniteResources(int $xpSpent) : void{ + $expectedXpCost = $this->expectedResult->getRepairCost(); + if($xpSpent !== $expectedXpCost){ + throw new TransactionValidationException("Expected the amount of xp spent to be $expectedXpCost, but received $xpSpent"); + } + + $xpLevel = $this->source->getXpManager()->getXpLevel(); + if($xpLevel < $expectedXpCost){ + throw new TransactionValidationException("Player's XP level $xpLevel is less than the required XP level $expectedXpCost"); + } + } + + private function validateInputs(Item $base, Item $material, Item $expectedOutput) : ?AnvilResult { + $calculAttempt = AnvilHelper::calculateResult($this->source, $base, $material, $this->customName); + if($calculAttempt->getResult() === null || !$calculAttempt->getResult()->equalsExact($expectedOutput)){ + return null; + } + + return $calculAttempt; + } + public function validate() : void{ if(count($this->actions) < 1){ throw new TransactionValidationException("Transaction must have at least one action to be executable"); @@ -47,14 +71,37 @@ class AnvilTransaction extends InventoryTransaction{ $outputs = []; $this->matchItems($outputs, $inputs); - //TODO + if(($outputCount = count($outputs)) !== 1){ + throw new TransactionValidationException("Expected 1 output item, but received $outputCount"); + } + $outputItem = $outputs[0]; + + if(($inputCount = count($inputs)) < 1){ + throw new TransactionValidationException("Expected at least 1 input item, but received $inputCount"); + } + if($inputCount > 2){ + throw new TransactionValidationException("Expected at most 2 input items, but received $inputCount"); + } + + if(count($inputs) < 2){ + $attempt = $this->validateInputs($inputs[0], VanillaItems::AIR(), $outputItem) ?? + throw new TransactionValidationException("Inputs do not match expected result"); + }else{ + $attempt = $this->validateInputs($inputs[0], $inputs[1], $outputItem) ?? + $this->validateInputs($inputs[1], $inputs[0], $outputItem) ?? + throw new TransactionValidationException("Inputs do not match expected result"); + } + + if($this->source->hasFiniteResources()){ + $this->validateFiniteResources($attempt->getRepairCost()); + } } public function execute() : void{ parent::execute(); if($this->source->hasFiniteResources()){ - $this->source->getXpManager()->subtractXpLevels($this->anvilResult->getRepairCost()); + $this->source->getXpManager()->subtractXpLevels($this->expectedResult->getRepairCost()); } } } diff --git a/src/network/mcpe/handler/ItemStackRequestExecutor.php b/src/network/mcpe/handler/ItemStackRequestExecutor.php index 4cd76ec72..ccecf3b4a 100644 --- a/src/network/mcpe/handler/ItemStackRequestExecutor.php +++ b/src/network/mcpe/handler/ItemStackRequestExecutor.php @@ -356,7 +356,7 @@ class ItemStackRequestExecutor{ if($window instanceof AnvilInventory){ $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->specialTransaction = new AnvilTransaction($this->player, $result, $this->request->getFilterStrings()[0] ?? null); $this->setNextCreatedItem($result->getResult()); } }