PocketMine-MP 5.21.2 git-a6534ecbbbcf369264567d27e5ed70f7f5be9816
Loading...
Searching...
No Matches
Campfire.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;
25
27use pocketmine\block\tile\Campfire as TileCampfire;
28use pocketmine\block\utils\HorizontalFacingTrait;
29use pocketmine\block\utils\LightableTrait;
30use pocketmine\block\utils\SupportType;
32use pocketmine\crafting\FurnaceType;
58use function count;
59use function min;
60use function mt_rand;
61
62class Campfire extends Transparent{
63 use HorizontalFacingTrait{
64 HorizontalFacingTrait::describeBlockOnlyState as encodeFacingState;
65 }
66 use LightableTrait{
67 LightableTrait::describeBlockOnlyState as encodeLitState;
68 }
69
70 private const UPDATE_INTERVAL_TICKS = 10;
71
72 protected CampfireInventory $inventory;
73
78 protected array $cookingTimes = [];
79
80 protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
81 $this->encodeFacingState($w);
82 $this->encodeLitState($w);
83 }
84
85 public function readStateFromWorld() : Block{
86 parent::readStateFromWorld();
87 $tile = $this->position->getWorld()->getTile($this->position);
88 if($tile instanceof TileCampfire){
89 $this->inventory = $tile->getInventory();
90 $this->cookingTimes = $tile->getCookingTimes();
91 }else{
92 $this->inventory = new CampfireInventory($this->position);
93 }
94
95 return $this;
96 }
97
98 public function writeStateToWorld() : void{
99 parent::writeStateToWorld();
100 $tile = $this->position->getWorld()->getTile($this->position);
101 if($tile instanceof TileCampfire){
102 $tile->setCookingTimes($this->cookingTimes);
103 }
104 }
105
106 public function hasEntityCollision() : bool{
107 return true;
108 }
109
110 public function getLightLevel() : int{
111 return $this->lit ? 15 : 0;
112 }
113
114 public function isAffectedBySilkTouch() : bool{
115 return true;
116 }
117
118 public function getDropsForCompatibleTool(Item $item) : array{
119 return [
120 VanillaItems::CHARCOAL()->setCount(2)
121 ];
122 }
123
124 public function getSupportType(int $facing) : SupportType{
125 return SupportType::NONE;
126 }
127
128 protected function recalculateCollisionBoxes() : array{
129 return [AxisAlignedBB::one()->trim(Facing::UP, 9 / 16)];
130 }
131
132 public function getInventory() : CampfireInventory{
133 return $this->inventory;
134 }
135
136 protected function getFurnaceType() : FurnaceType{
137 return FurnaceType::CAMPFIRE;
138 }
139
140 protected function getEntityCollisionDamage() : int{
141 return 1;
142 }
143
147 public function setCookingTime(int $slot, int $time) : void{
148 if($slot < 0 || $slot > 3){
149 throw new \InvalidArgumentException("Slot must be in range 0-3");
150 }
151 if($time < 0 || $time > $this->getFurnaceType()->getCookDurationTicks()){
152 throw new \InvalidArgumentException("CookingTime must be in range 0-" . $this->getFurnaceType()->getCookDurationTicks());
153 }
154 $this->cookingTimes[$slot] = $time;
155 }
156
160 public function getCookingTime(int $slot) : int{
161 return $this->cookingTimes[$slot] ?? 0;
162 }
163
164 public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
165 if($this->getSide(Facing::DOWN) instanceof Campfire){
166 return false;
167 }
168 if($player !== null){
169 $this->facing = $player->getHorizontalFacing();
170 }
171 $this->lit = true;
172 return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
173 }
174
175 public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
176 if(!$this->lit){
177 if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE){
178 $item->pop();
179 $this->ignite();
180 $this->position->getWorld()->addSound($this->position, new BlazeShootSound());
181 return true;
182 }elseif($item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
183 if($item instanceof Durable){
184 $item->applyDamage(1);
185 }
186 $this->ignite();
187 return true;
188 }
189 }elseif($item instanceof Shovel){
190 $item->applyDamage(1);
191 $this->extinguish();
192 return true;
193 }
194
195 if($this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($this->getFurnaceType())->match($item) !== null){
196 $ingredient = clone $item;
197 $ingredient->setCount(1);
198 if(count($this->inventory->addItem($ingredient)) === 0){
199 $item->pop();
200 $this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
201 return true;
202 }
203 }
204 return false;
205 }
206
207 public function onNearbyBlockChange() : void{
208 if($this->lit && $this->getSide(Facing::UP)->getTypeId() === BlockTypeIds::WATER){
209 $this->extinguish();
210 //TODO: Waterlogging
211 }
212 }
213
214 public function onEntityInside(Entity $entity) : bool{
215 if(!$this->lit){
216 if($entity->isOnFire()){
217 $this->ignite();
218 return false;
219 }
220 }elseif($entity instanceof Living){
221 $entity->attack(new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, $this->getEntityCollisionDamage()));
222 }
223 return true;
224 }
225
226 public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
227 if($this->lit && $projectile instanceof SplashPotion && $projectile->getPotionType() === PotionType::WATER){
228 $this->extinguish();
229 }
230 }
231
232 public function onScheduledUpdate() : void{
233 if($this->lit){
234 $items = $this->inventory->getContents();
235 $furnaceType = $this->getFurnaceType();
236 $maxCookDuration = $furnaceType->getCookDurationTicks();
237 foreach($items as $slot => $item){
238 $this->setCookingTime($slot, min($maxCookDuration, $this->getCookingTime($slot) + self::UPDATE_INTERVAL_TICKS));
239 if($this->getCookingTime($slot) >= $maxCookDuration){
240 $result =
241 ($recipe = $this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($furnaceType)->match($item)) instanceof FurnaceRecipe ?
242 $recipe->getResult() :
243 VanillaItems::AIR();
244
245 $ev = new CampfireCookEvent($this, $slot, $item, $result);
246 $ev->call();
247
248 if ($ev->isCancelled()){
249 continue;
250 }
251
252 $this->inventory->setItem($slot, VanillaItems::AIR());
253 $this->setCookingTime($slot, 0);
254 $this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $ev->getResult());
255 }
256 }
257 if(count($items) > 0){
258 $this->position->getWorld()->setBlock($this->position, $this);
259 }
260 if(mt_rand(1, 6) === 1){
261 $this->position->getWorld()->addSound($this->position, $furnaceType->getCookSound());
262 }
263 $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS);
264 }
265 }
266
267 private function extinguish() : void{
268 $this->position->getWorld()->addSound($this->position, new FireExtinguishSound());
269 $this->position->getWorld()->setBlock($this->position, $this->setLit(false));
270 }
271
272 private function ignite() : void{
273 $this->position->getWorld()->addSound($this->position, new FlintSteelSound());
274 $this->position->getWorld()->setBlock($this->position, $this->setLit(true));
275 $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS);
276 }
277}
place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player=null)
Definition Campfire.php:164
describeBlockOnlyState(RuntimeDataDescriber $w)
Definition Campfire.php:80
onProjectileHit(Projectile $projectile, RayTraceResult $hitResult)
Definition Campfire.php:226
getSupportType(int $facing)
Definition Campfire.php:124
setCookingTime(int $slot, int $time)
Definition Campfire.php:147
getDropsForCompatibleTool(Item $item)
Definition Campfire.php:118
onEntityInside(Entity $entity)
Definition Campfire.php:214
onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player=null, array &$returnedItems=[])
Definition Campfire.php:175