47 public const TAG_BURN_TIME =
"BurnTime";
48 public const TAG_COOK_TIME =
"CookTime";
49 public const TAG_MAX_TIME =
"MaxTime";
52 private int $remainingFuelTime = 0;
53 private int $cookTime = 0;
54 private int $maxFuelTime = 0;
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{
66 public function readSaveData(
CompoundTag $nbt) :
void{
67 $this->remainingFuelTime = max(0, $nbt->getShort(self::TAG_BURN_TIME, $this->remainingFuelTime));
69 $this->cookTime = $nbt->getShort(self::TAG_COOK_TIME, $this->cookTime);
70 if($this->remainingFuelTime === 0){
74 $this->maxFuelTime = $nbt->getShort(self::TAG_MAX_TIME, $this->maxFuelTime);
75 if($this->maxFuelTime === 0){
76 $this->maxFuelTime = $this->remainingFuelTime;
79 $this->loadName($nbt);
80 $this->loadItems($nbt);
82 if($this->remainingFuelTime > 0){
83 $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1);
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);
95 public function getDefaultName() : string{
99 public function close() : void{
101 $this->inventory->removeAllViewers();
107 public function getInventory() : FurnaceInventory{
108 return $this->inventory;
111 public function getRealInventory() : FurnaceInventory{
112 return $this->getInventory();
115 protected function checkFuel(Item $fuel) : void{
116 $ev = new FurnaceBurnEvent($this, $fuel, $fuel->getFuelTime());
118 if($ev->isCancelled()){
122 $this->maxFuelTime = $this->remainingFuelTime = $ev->getBurnTime();
123 $this->onStartSmelting();
125 if($this->remainingFuelTime > 0 && $ev->isBurning()){
126 $this->inventory->setFuel($fuel->getFuelResidue());
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);
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);
146 abstract public function getFurnaceType() : FurnaceType;
148 public function onUpdate() : bool{
154 $this->timings->startTiming();
156 $prevCookTime = $this->cookTime;
157 $prevRemainingFuelTime = $this->remainingFuelTime;
158 $prevMaxFuelTime = $this->maxFuelTime;
162 $fuel = $this->inventory->getFuel();
163 $raw = $this->inventory->getSmelting();
164 $product = $this->inventory->getResult();
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()));
170 if($this->remainingFuelTime <= 0 && $canSmelt && $fuel->getFuelTime() > 0 && $fuel->getCount() > 0){
171 $this->checkFuel($fuel);
174 if($this->remainingFuelTime > 0){
175 --$this->remainingFuelTime;
177 if($smelt instanceof FurnaceRecipe && $canSmelt){
180 if($this->cookTime >= $furnaceType->getCookDurationTicks()){
181 $product = $smelt->getResult()->setCount($product->getCount() + 1);
183 $ev =
new FurnaceSmeltEvent($this, $raw, $product);
186 if(!$ev->isCancelled()){
187 $this->inventory->setResult($ev->getResult());
189 $this->inventory->setSmelting($raw);
192 $this->cookTime -= $furnaceType->getCookDurationTicks();
194 }elseif($this->remainingFuelTime <= 0){
195 $this->remainingFuelTime = $this->cookTime = $this->maxFuelTime = 0;
201 $this->onStopSmelting();
202 $this->remainingFuelTime = $this->cookTime = $this->maxFuelTime = 0;
205 $viewers = array_map(fn(Player $p) => $p->getNetworkSession()->getInvManager(), $this->inventory->getViewers());
206 foreach($viewers as $v){
210 if($prevCookTime !== $this->cookTime){
211 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_SMELT_PROGRESS, $this->cookTime);
213 if($prevRemainingFuelTime !== $this->remainingFuelTime){
214 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_REMAINING_FUEL_TIME, $this->remainingFuelTime);
216 if($prevMaxFuelTime !== $this->maxFuelTime){
217 $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_MAX_FUEL_TIME, $this->maxFuelTime);
221 $this->timings->stopTiming();