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