PocketMine-MP 5.23.3 git-f7687af337d001ddbcc47b8e773f014a33faa662
Loading...
Searching...
No Matches
EnchantingTransaction.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\inventory\transaction;
25
33use function count;
34use function min;
35
37
38 private ?Item $inputItem = null;
39 private ?Item $outputItem = null;
40
41 public function __construct(
42 Player $source,
43 private readonly EnchantingOption $option,
44 private readonly int $cost
45 ){
46 parent::__construct($source);
47 }
48
49 private function validateOutput() : void{
50 if($this->inputItem === null || $this->outputItem === null){
51 throw new AssumptionFailedError("Expected that inputItem and outputItem are not null before validating output");
52 }
53
54 $enchantedInput = EnchantingHelper::enchantItem($this->inputItem, $this->option->getEnchantments());
55 if(!$this->outputItem->equalsExact($enchantedInput)){
56 throw new TransactionValidationException("Invalid output item");
57 }
58 }
59
60 private function validateFiniteResources(int $lapisSpent) : void{
61 if($lapisSpent !== $this->cost){
62 throw new TransactionValidationException("Expected the amount of lapis lazuli spent to be $this->cost, but received $lapisSpent");
63 }
64
65 $xpLevel = $this->source->getXpManager()->getXpLevel();
66 $requiredXpLevel = $this->option->getRequiredXpLevel();
67
68 if($xpLevel < $requiredXpLevel){
69 throw new TransactionValidationException("Player's XP level $xpLevel is less than the required XP level $requiredXpLevel");
70 }
71 //XP level cost is intentionally not checked here, as the required level may be lower than the cost, allowing
72 //the option to be used with less XP than the cost - in this case, as much XP as possible will be deducted.
73 }
74
75 public function validate() : void{
76 if(count($this->actions) < 1){
77 throw new TransactionValidationException("Transaction must have at least one action to be executable");
78 }
79
81 $inputs = [];
83 $outputs = [];
84 $this->matchItems($outputs, $inputs);
85
86 $lapisSpent = 0;
87 foreach($inputs as $input){
88 if($input->getTypeId() === ItemTypeIds::LAPIS_LAZULI){
89 $lapisSpent = $input->getCount();
90 }else{
91 if($this->inputItem !== null){
92 throw new TransactionValidationException("Received more than 1 items to enchant");
93 }
94 $this->inputItem = $input;
95 }
96 }
97
98 if($this->inputItem === null){
99 throw new TransactionValidationException("No item to enchant received");
100 }
101
102 if(($outputCount = count($outputs)) !== 1){
103 throw new TransactionValidationException("Expected 1 output item, but received $outputCount");
104 }
105 $this->outputItem = $outputs[0];
106
107 $this->validateOutput();
108
109 if($this->source->hasFiniteResources()){
110 $this->validateFiniteResources($lapisSpent);
111 }
112 }
113
114 public function execute() : void{
115 parent::execute();
116
117 if($this->source->hasFiniteResources()){
118 //If the required XP level is less than the XP cost, the option can be selected with less XP than the cost.
119 //In this case, as much XP as possible will be taken.
120 $this->source->getXpManager()->subtractXpLevels(min($this->cost, $this->source->getXpManager()->getXpLevel()));
121 }
122 $this->source->regenerateEnchantmentSeed();
123 }
124
125 protected function callExecuteEvent() : bool{
126 if($this->inputItem === null || $this->outputItem === null){
127 throw new AssumptionFailedError("Expected that inputItem and outputItem are not null before executing the event");
128 }
129
130 $event = new PlayerItemEnchantEvent($this->source, $this, $this->option, $this->inputItem, $this->outputItem, $this->cost);
131 $event->call();
132 return !$event->isCancelled();
133 }
134}