PocketMine-MP 5.33.2 git-1133d49c924b4358c79d44eeb97dcbf56cb4d1eb
Loading...
Searching...
No Matches
tile/Furnace.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
26use pocketmine\block\Furnace as BlockFurnace;
29use pocketmine\crafting\FurnaceType;
41use function array_map;
42use function max;
43
44abstract class Furnace extends Spawnable implements ContainerTile, Nameable{
45 use NameableTrait;
47
48 public const TAG_BURN_TIME = "BurnTime";
49 public const TAG_COOK_TIME = "CookTime";
50 public const TAG_MAX_TIME = "MaxTime";
51
52 protected Inventory $inventory;
53 private int $remainingFuelTime = 0;
54 private int $cookTime = 0;
55 private int $maxFuelTime = 0;
56
57 public function __construct(World $world, Vector3 $pos){
58 parent::__construct($world, $pos);
59 $this->inventory = new SimpleInventory(3);
60 $this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(
61 static function(Inventory $unused) use ($world, $pos) : void{
62 $world->scheduleDelayedBlockUpdate($pos, 1);
63 })
64 );
65 }
66
67 public function readSaveData(CompoundTag $nbt) : void{
68 $this->remainingFuelTime = max(0, $nbt->getShort(self::TAG_BURN_TIME, $this->remainingFuelTime));
69
70 $this->cookTime = $nbt->getShort(self::TAG_COOK_TIME, $this->cookTime);
71 if($this->remainingFuelTime === 0){
72 $this->cookTime = 0;
73 }
74
75 $this->maxFuelTime = $nbt->getShort(self::TAG_MAX_TIME, $this->maxFuelTime);
76 if($this->maxFuelTime === 0){
77 $this->maxFuelTime = $this->remainingFuelTime;
78 }
79
80 $this->loadName($nbt);
81 $this->loadItems($nbt);
82
83 if($this->remainingFuelTime > 0){
84 $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1);
85 }
86 }
87
88 protected function writeSaveData(CompoundTag $nbt) : void{
89 $nbt->setShort(self::TAG_BURN_TIME, $this->remainingFuelTime);
90 $nbt->setShort(self::TAG_COOK_TIME, $this->cookTime);
91 $nbt->setShort(self::TAG_MAX_TIME, $this->maxFuelTime);
92 $this->saveName($nbt);
93 $this->saveItems($nbt);
94 }
95
96 public function getDefaultName() : string{
97 return "Furnace";
98 }
99
100 public function close() : void{
101 if(!$this->closed){
102 $this->inventory->removeAllWindows();
103
104 parent::close();
105 }
106 }
107
108 public function getInventory() : Inventory{
109 return $this->inventory;
110 }
111
112 public function getRealInventory() : Inventory{
113 return $this->getInventory();
114 }
115
116 protected function checkFuel(Item $fuel) : void{
117 $ev = new FurnaceBurnEvent($this, $fuel, $fuel->getFuelTime());
118 $ev->call();
119 if($ev->isCancelled()){
120 return;
121 }
122
123 $this->maxFuelTime = $this->remainingFuelTime = $ev->getBurnTime();
124 $this->onStartSmelting();
125
126 if($this->remainingFuelTime > 0 && $ev->isBurning()){
127 $this->inventory->setItem(FurnaceInventoryWindow::SLOT_FUEL, $fuel->getFuelResidue());
128 }
129 }
130
131 protected function onStartSmelting() : void{
132 $block = $this->getBlock();
133 if($block instanceof BlockFurnace && !$block->isLit()){
134 $block->setLit(true);
135 $this->position->getWorld()->setBlock($block->getPosition(), $block);
136 }
137 }
138
139 protected function onStopSmelting() : void{
140 $block = $this->getBlock();
141 if($block instanceof BlockFurnace && $block->isLit()){
142 $block->setLit(false);
143 $this->position->getWorld()->setBlock($block->getPosition(), $block);
144 }
145 }
146
147 abstract public function getFurnaceType() : FurnaceType;
148
149 public function onUpdate() : bool{
150 //TODO: move this to Block
151 if($this->closed){
152 return false;
153 }
154
155 $this->timings->startTiming();
156
157 $prevCookTime = $this->cookTime;
158 $prevRemainingFuelTime = $this->remainingFuelTime;
159 $prevMaxFuelTime = $this->maxFuelTime;
160
161 $ret = false;
162
163 $fuel = $this->inventory->getItem(FurnaceInventoryWindow::SLOT_FUEL);
164 $raw = $this->inventory->getItem(FurnaceInventoryWindow::SLOT_INPUT);
165 $product = $this->inventory->getItem(FurnaceInventoryWindow::SLOT_RESULT);
166
167 $furnaceType = $this->getFurnaceType();
168 $smelt = $this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($furnaceType)->match($raw);
169 $canSmelt = ($smelt instanceof FurnaceRecipe && $raw->getCount() > 0 && (($smelt->getResult()->canStackWith($product) && $product->getCount() < $product->getMaxStackSize()) || $product->isNull()));
170
171 if($this->remainingFuelTime <= 0 && $canSmelt && $fuel->getFuelTime() > 0 && $fuel->getCount() > 0){
172 $this->checkFuel($fuel);
173 }
174
175 if($this->remainingFuelTime > 0){
176 --$this->remainingFuelTime;
177
178 if($smelt instanceof FurnaceRecipe && $canSmelt){
179 ++$this->cookTime;
180
181 if($this->cookTime >= $furnaceType->getCookDurationTicks()){
182 $product = $smelt->getResult()->setCount($product->getCount() + 1);
183
184 $ev = new FurnaceSmeltEvent($this, $raw, $product);
185 $ev->call();
186
187 if(!$ev->isCancelled()){
188 $this->inventory->setItem(FurnaceInventoryWindow::SLOT_RESULT, $ev->getResult());
189 $raw->pop();
190 $this->inventory->setItem(FurnaceInventoryWindow::SLOT_INPUT, $raw);
191 }
192
193 $this->cookTime -= $furnaceType->getCookDurationTicks();
194 }
195 }elseif($this->remainingFuelTime <= 0){
196 $this->remainingFuelTime = $this->cookTime = $this->maxFuelTime = 0;
197 }else{
198 $this->cookTime = 0;
199 }
200 $ret = true;
201 }else{
202 $this->onStopSmelting();
203 $this->remainingFuelTime = $this->cookTime = $this->maxFuelTime = 0;
204 }
205
206 $viewers = array_map(fn(Player $p) => $p->getNetworkSession()->getInvManager(), $this->inventory->getViewers());
207 foreach($viewers as $v){
208 if($v === null){
209 continue;
210 }
211 if($prevCookTime !== $this->cookTime){
212 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_SMELT_PROGRESS, $this->cookTime);
213 }
214 if($prevRemainingFuelTime !== $this->remainingFuelTime){
215 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_REMAINING_FUEL_TIME, $this->remainingFuelTime);
216 }
217 if($prevMaxFuelTime !== $this->maxFuelTime){
218 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_MAX_FUEL_TIME, $this->maxFuelTime);
219 }
220 }
221
222 $this->timings->stopTiming();
223
224 return $ret;
225 }
226}
writeSaveData(CompoundTag $nbt)
setShort(string $name, int $value)
scheduleDelayedBlockUpdate(Vector3 $pos, int $delay)
Definition World.php:1467