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