48 public const TAG_BURN_TIME =
"BurnTime";
49 public const TAG_COOK_TIME =
"CookTime";
50 public const TAG_MAX_TIME =
"MaxTime";
53 private int $remainingFuelTime = 0;
54 private int $cookTime = 0;
55 private int $maxFuelTime = 0;
58 parent::__construct($world, $pos);
60 $this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(
61 static function(
Inventory $unused) use ($world, $pos) :
void{
67 public function readSaveData(
CompoundTag $nbt) :
void{
68 $this->remainingFuelTime = max(0, $nbt->getShort(self::TAG_BURN_TIME, $this->remainingFuelTime));
70 $this->cookTime = $nbt->getShort(self::TAG_COOK_TIME, $this->cookTime);
71 if($this->remainingFuelTime === 0){
75 $this->maxFuelTime = $nbt->getShort(self::TAG_MAX_TIME, $this->maxFuelTime);
76 if($this->maxFuelTime === 0){
77 $this->maxFuelTime = $this->remainingFuelTime;
80 $this->loadName($nbt);
81 $this->loadItems($nbt);
83 if($this->remainingFuelTime > 0){
84 $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1);
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);
96 public function getDefaultName() : string{
100 public function close() : void{
102 $this->inventory->removeAllWindows();
108 public function getInventory() : Inventory{
109 return $this->inventory;
112 public function getRealInventory() : Inventory{
113 return $this->getInventory();
116 protected function checkFuel(Item $fuel) : void{
117 $ev = new FurnaceBurnEvent($this, $fuel, $fuel->getFuelTime());
119 if($ev->isCancelled()){
123 $this->maxFuelTime = $this->remainingFuelTime = $ev->getBurnTime();
124 $this->onStartSmelting();
126 if($this->remainingFuelTime > 0 && $ev->isBurning()){
127 $this->inventory->setItem(FurnaceInventoryWindow::SLOT_FUEL, $fuel->getFuelResidue());
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);
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);
147 abstract public function getFurnaceType() : FurnaceType;
149 public function onUpdate() : bool{
155 $this->timings->startTiming();
157 $prevCookTime = $this->cookTime;
158 $prevRemainingFuelTime = $this->remainingFuelTime;
159 $prevMaxFuelTime = $this->maxFuelTime;
163 $fuel = $this->inventory->getItem(FurnaceInventoryWindow::SLOT_FUEL);
164 $raw = $this->inventory->getItem(FurnaceInventoryWindow::SLOT_INPUT);
165 $product = $this->inventory->getItem(FurnaceInventoryWindow::SLOT_RESULT);
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()));
171 if($this->remainingFuelTime <= 0 && $canSmelt && $fuel->getFuelTime() > 0 && $fuel->getCount() > 0){
172 $this->checkFuel($fuel);
175 if($this->remainingFuelTime > 0){
176 --$this->remainingFuelTime;
178 if($smelt instanceof FurnaceRecipe && $canSmelt){
181 if($this->cookTime >= $furnaceType->getCookDurationTicks()){
182 $product = $smelt->getResult()->setCount($product->getCount() + 1);
184 $ev =
new FurnaceSmeltEvent($this, $raw, $product);
187 if(!$ev->isCancelled()){
188 $this->inventory->setItem(FurnaceInventoryWindow::SLOT_RESULT, $ev->getResult());
190 $this->inventory->setItem(FurnaceInventoryWindow::SLOT_INPUT, $raw);
193 $this->cookTime -= $furnaceType->getCookDurationTicks();
195 }elseif($this->remainingFuelTime <= 0){
196 $this->remainingFuelTime = $this->cookTime = $this->maxFuelTime = 0;
202 $this->onStopSmelting();
203 $this->remainingFuelTime = $this->cookTime = $this->maxFuelTime = 0;
206 $viewers = array_map(fn(Player $p) => $p->getNetworkSession()->getInvManager(), $this->inventory->getViewers());
207 foreach($viewers as $v){
211 if($prevCookTime !== $this->cookTime){
212 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_SMELT_PROGRESS, $this->cookTime);
214 if($prevRemainingFuelTime !== $this->remainingFuelTime){
215 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_REMAINING_FUEL_TIME, $this->remainingFuelTime);
217 if($prevMaxFuelTime !== $this->maxFuelTime){
218 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_MAX_FUEL_TIME, $this->maxFuelTime);
222 $this->timings->stopTiming();