burnTime > 0){ $this->scheduleUpdate(); } } protected function readSaveData(CompoundTag $nbt) : void{ $this->burnTime = max(0, $nbt->getShort(self::TAG_BURN_TIME, 0, true)); $this->cookTime = $nbt->getShort(self::TAG_COOK_TIME, 0, true); if($this->burnTime === 0){ $this->cookTime = 0; } $this->maxTime = $nbt->getShort(self::TAG_MAX_TIME, 0, true); if($this->maxTime === 0){ $this->maxTime = $this->burnTime; } $this->loadName($nbt); $this->inventory = new FurnaceInventory($this); $this->loadItems($nbt); $this->inventory->setEventProcessor(new class($this) implements InventoryEventProcessor{ /** @var Furnace */ private $furnace; public function __construct(Furnace $furnace){ $this->furnace = $furnace; } public function onSlotChange(Inventory $inventory, int $slot, Item $oldItem, Item $newItem) : ?Item{ $this->furnace->scheduleUpdate(); return $newItem; } }); } protected function writeSaveData(CompoundTag $nbt) : void{ $nbt->setShort(self::TAG_BURN_TIME, $this->burnTime); $nbt->setShort(self::TAG_COOK_TIME, $this->cookTime); $nbt->setShort(self::TAG_MAX_TIME, $this->maxTime); $this->saveName($nbt); $this->saveItems($nbt); } /** * @return string */ public function getDefaultName() : string{ return "Furnace"; } public function close() : void{ if(!$this->closed){ $this->inventory->removeAllViewers(true); $this->inventory = null; parent::close(); } } /** * @return FurnaceInventory */ public function getInventory(){ return $this->inventory; } /** * @return FurnaceInventory */ public function getRealInventory(){ return $this->getInventory(); } protected function checkFuel(Item $fuel){ $ev = new FurnaceBurnEvent($this, $fuel, $fuel->getFuelTime()); $ev->call(); if($ev->isCancelled()){ return; } $this->maxTime = $this->burnTime = $ev->getBurnTime(); if($this->getBlock()->getId() === Block::FURNACE){ $this->getLevel()->setBlock($this, BlockFactory::get(Block::BURNING_FURNACE, $this->getBlock()->getDamage()), true); } if($this->burnTime > 0 and $ev->isBurning()){ $fuel->pop(); $this->inventory->setFuel($fuel); } } protected function getFuelTicksLeft() : int{ return $this->maxTime > 0 ? (int) ceil($this->burnTime / $this->maxTime * 200) : 0; } public function onUpdate() : bool{ if($this->closed){ return false; } $this->timings->startTiming(); $prevCookTime = $this->cookTime; $prevFuelTicksLeft = $this->getFuelTicksLeft(); $ret = false; $fuel = $this->inventory->getFuel(); $raw = $this->inventory->getSmelting(); $product = $this->inventory->getResult(); $smelt = $this->server->getCraftingManager()->matchFurnaceRecipe($raw); $canSmelt = ($smelt instanceof FurnaceRecipe and $raw->getCount() > 0 and (($smelt->getResult()->equals($product) and $product->getCount() < $product->getMaxStackSize()) or $product->isNull())); if($this->burnTime <= 0 and $canSmelt and $fuel->getFuelTime() > 0 and $fuel->getCount() > 0){ $this->checkFuel($fuel); } if($this->burnTime > 0){ --$this->burnTime; if($smelt instanceof FurnaceRecipe and $canSmelt){ ++$this->cookTime; if($this->cookTime >= 200){ //10 seconds $product = ItemFactory::get($smelt->getResult()->getId(), $smelt->getResult()->getDamage(), $product->getCount() + 1); $ev = new FurnaceSmeltEvent($this, $raw, $product); $ev->call(); if(!$ev->isCancelled()){ $this->inventory->setResult($ev->getResult()); $raw->pop(); $this->inventory->setSmelting($raw); } $this->cookTime -= 200; } }elseif($this->burnTime <= 0){ $this->burnTime = $this->cookTime = $this->maxTime = 0; }else{ $this->cookTime = 0; } $ret = true; }else{ if($this->getBlock()->getId() === Block::BURNING_FURNACE){ $this->getLevel()->setBlock($this, BlockFactory::get(Block::FURNACE, $this->getBlock()->getDamage()), true); } $this->burnTime = $this->cookTime = $this->maxTime = 0; } /** @var ContainerSetDataPacket[] $packets */ $packets = []; if($prevCookTime !== $this->cookTime){ $pk = new ContainerSetDataPacket(); $pk->property = ContainerSetDataPacket::PROPERTY_FURNACE_TICK_COUNT; $pk->value = $this->cookTime; $packets[] = $pk; } $fuelTicksLeft = $this->getFuelTicksLeft(); if($prevFuelTicksLeft !== $fuelTicksLeft){ $pk = new ContainerSetDataPacket(); $pk->property = ContainerSetDataPacket::PROPERTY_FURNACE_LIT_TIME; $pk->value = $fuelTicksLeft; $packets[] = $pk; } if(!empty($packets)){ foreach($this->getInventory()->getViewers() as $player){ $windowId = $player->getWindowId($this->getInventory()); if($windowId > 0){ foreach($packets as $pk){ $pk->windowId = $windowId; $player->dataPacket(clone $pk); } } } } $this->timings->stopTiming(); return $ret; } protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ $nbt->setShort(self::TAG_BURN_TIME, $this->burnTime); $nbt->setShort(self::TAG_COOK_TIME, $this->cookTime); $this->addNameSpawnData($nbt); } }