PocketMine-MP 5.17.1 git-df4ada81e5d74a14046f27cf44a37dcee69d657e
tile/BrewingStand.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\block\tile;
25
40use function array_map;
41use function count;
42
43class BrewingStand extends Spawnable implements Container, Nameable{
44 use NameableTrait {
45 addAdditionalSpawnData as addNameSpawnData;
46 }
48
49 public const BREW_TIME_TICKS = 400; // Brew time in ticks
50
51 private const TAG_BREW_TIME = "BrewTime"; //TAG_Short
52 private const TAG_BREW_TIME_PE = "CookTime"; //TAG_Short
53 private const TAG_MAX_FUEL_TIME = "FuelTotal"; //TAG_Short
54 private const TAG_REMAINING_FUEL_TIME = "Fuel"; //TAG_Byte
55 private const TAG_REMAINING_FUEL_TIME_PE = "FuelAmount"; //TAG_Short
56
57 private BrewingStandInventory $inventory;
58
59 private int $brewTime = 0;
60 private int $maxFuelTime = 0;
61 private int $remainingFuelTime = 0;
62
63 public function __construct(World $world, Vector3 $pos){
64 parent::__construct($world, $pos);
65 $this->inventory = new BrewingStandInventory($this->position);
66 $this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(static function(Inventory $unused) use ($world, $pos) : void{
67 $world->scheduleDelayedBlockUpdate($pos, 1);
68 }));
69 }
70
71 public function readSaveData(CompoundTag $nbt) : void{
72 $this->loadName($nbt);
73 $this->loadItems($nbt);
74
75 $this->brewTime = $nbt->getShort(self::TAG_BREW_TIME, $nbt->getShort(self::TAG_BREW_TIME_PE, 0));
76 $this->maxFuelTime = $nbt->getShort(self::TAG_MAX_FUEL_TIME, 0);
77 $this->remainingFuelTime = $nbt->getByte(self::TAG_REMAINING_FUEL_TIME, $nbt->getShort(self::TAG_REMAINING_FUEL_TIME_PE, 0));
78 if($this->maxFuelTime === 0){
79 $this->maxFuelTime = $this->remainingFuelTime;
80 }
81 if($this->remainingFuelTime === 0){
82 $this->maxFuelTime = $this->remainingFuelTime = $this->brewTime = 0;
83 }
84 }
85
86 protected function writeSaveData(CompoundTag $nbt) : void{
87 $this->saveName($nbt);
88 $this->saveItems($nbt);
89
90 $nbt->setShort(self::TAG_BREW_TIME_PE, $this->brewTime);
91 $nbt->setShort(self::TAG_MAX_FUEL_TIME, $this->maxFuelTime);
92 $nbt->setShort(self::TAG_REMAINING_FUEL_TIME_PE, $this->remainingFuelTime);
93 }
94
95 protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
96 $this->addNameSpawnData($nbt);
97
98 $nbt->setShort(self::TAG_BREW_TIME_PE, $this->brewTime);
99 $nbt->setShort(self::TAG_MAX_FUEL_TIME, $this->maxFuelTime);
100 $nbt->setShort(self::TAG_REMAINING_FUEL_TIME_PE, $this->remainingFuelTime);
101 }
102
103 public function getDefaultName() : string{
104 return "Brewing Stand";
105 }
106
107 public function close() : void{
108 if(!$this->closed){
109 $this->inventory->removeAllViewers();
110
111 parent::close();
112 }
113 }
114
115 public function getInventory() : BrewingStandInventory{
116 return $this->inventory;
117 }
118
119 public function getRealInventory() : BrewingStandInventory{
120 return $this->inventory;
121 }
122
123 private function checkFuel(Item $item) : void{
124 $ev = new BrewingFuelUseEvent($this);
125 if(!$item->equals(VanillaItems::BLAZE_POWDER(), true, false)){
126 $ev->cancel();
127 }
128
129 $ev->call();
130 if($ev->isCancelled()){
131 return;
132 }
133
134 $item->pop();
135 $this->inventory->setItem(BrewingStandInventory::SLOT_FUEL, $item);
136
137 $this->maxFuelTime = $this->remainingFuelTime = $ev->getFuelTime();
138 }
139
144 private function getBrewableRecipes() : array{
145 $ingredient = $this->inventory->getItem(BrewingStandInventory::SLOT_INGREDIENT);
146 if($ingredient->isNull()){
147 return [];
148 }
149
150 $recipes = [];
151 $craftingManager = $this->position->getWorld()->getServer()->getCraftingManager();
152 foreach([BrewingStandInventory::SLOT_BOTTLE_LEFT, BrewingStandInventory::SLOT_BOTTLE_MIDDLE, BrewingStandInventory::SLOT_BOTTLE_RIGHT] as $slot){
153 $input = $this->inventory->getItem($slot);
154 if($input->isNull()){
155 continue;
156 }
157
158 if(($recipe = $craftingManager->matchBrewingRecipe($input, $ingredient)) !== null){
159 $recipes[$slot] = $recipe;
160 }
161 }
162
163 return $recipes;
164 }
165
166 public function onUpdate() : bool{
167 if($this->closed){
168 return false;
169 }
170
171 $this->timings->startTiming();
172
173 $prevBrewTime = $this->brewTime;
174 $prevRemainingFuelTime = $this->remainingFuelTime;
175 $prevMaxFuelTime = $this->maxFuelTime;
176
177 $ret = false;
178
179 $fuel = $this->inventory->getItem(BrewingStandInventory::SLOT_FUEL);
180 $ingredient = $this->inventory->getItem(BrewingStandInventory::SLOT_INGREDIENT);
181
182 $recipes = $this->getBrewableRecipes();
183 $canBrew = count($recipes) !== 0;
184
185 if($this->remainingFuelTime <= 0 && $canBrew){
186 $this->checkFuel($fuel);
187 }
188
189 if($this->remainingFuelTime > 0){
190 if($canBrew){
191 if($this->brewTime === 0){
192 $this->brewTime = self::BREW_TIME_TICKS;
193 --$this->remainingFuelTime;
194 }
195
196 --$this->brewTime;
197
198 if($this->brewTime <= 0){
199 $anythingBrewed = false;
200 foreach($recipes as $slot => $recipe){
201 $input = $this->inventory->getItem($slot);
202 $output = $recipe->getResultFor($input);
203 if($output === null){
204 continue;
205 }
206
207 $ev = new BrewItemEvent($this, $slot, $input, $output, $recipe);
208 $ev->call();
209 if($ev->isCancelled()){
210 continue;
211 }
212
213 $this->inventory->setItem($slot, $ev->getResult());
214 $anythingBrewed = true;
215 }
216
217 if($anythingBrewed){
218 $this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new PotionFinishBrewingSound());
219 }
220
221 $ingredient->pop();
222 $this->inventory->setItem(BrewingStandInventory::SLOT_INGREDIENT, $ingredient);
223
224 $this->brewTime = 0;
225 }else{
226 $ret = true;
227 }
228 }else{
229 $this->brewTime = 0;
230 }
231 }else{
232 $this->brewTime = $this->remainingFuelTime = $this->maxFuelTime = 0;
233 }
234
235 $viewers = array_map(fn(Player $p) => $p->getNetworkSession()->getInvManager(), $this->inventory->getViewers());
236 foreach($viewers as $v){
237 if($v === null){
238 continue;
239 }
240 if($prevBrewTime !== $this->brewTime){
241 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_BREWING_STAND_BREW_TIME, $this->brewTime);
242 }
243 if($prevRemainingFuelTime !== $this->remainingFuelTime){
244 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_BREWING_STAND_FUEL_AMOUNT, $this->remainingFuelTime);
245 }
246 if($prevMaxFuelTime !== $this->maxFuelTime){
247 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_BREWING_STAND_FUEL_TOTAL, $this->maxFuelTime);
248 }
249 }
250
251 $this->timings->stopTiming();
252
253 return $ret;
254 }
255}
setShort(string $name, int $value)
scheduleDelayedBlockUpdate(Vector3 $pos, int $delay)
Definition: World.php:1452