PocketMine-MP 5.16.1 git-585aee9386a787c95e73dd0a05ffca8329606b68
GlowLichen.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\utils\SupportType;
37use function array_key_first;
38use function count;
39use function shuffle;
40
41class GlowLichen extends Transparent{
42
44 protected array $faces = [];
45
46 protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
47 $w->facingFlags($this->faces);
48 }
49
51 public function getFaces() : array{ return $this->faces; }
52
53 public function hasFace(int $face) : bool{
54 return isset($this->faces[$face]);
55 }
56
61 public function setFaces(array $faces) : self{
62 $uniqueFaces = [];
63 foreach($faces as $face){
64 Facing::validate($face);
65 $uniqueFaces[$face] = $face;
66 }
67 $this->faces = $uniqueFaces;
68 return $this;
69 }
70
72 public function setFace(int $face, bool $value) : self{
73 Facing::validate($face);
74 if($value){
75 $this->faces[$face] = $face;
76 }else{
77 unset($this->faces[$face]);
78 }
79 return $this;
80 }
81
82 public function getLightLevel() : int{
83 return 7;
84 }
85
86 public function isSolid() : bool{
87 return false;
88 }
89
93 protected function recalculateCollisionBoxes() : array{
94 return [];
95 }
96
97 public function getSupportType(int $facing) : SupportType{
98 return SupportType::NONE;
99 }
100
101 public function canBeReplaced() : bool{
102 return true;
103 }
104
105 public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
106 $this->faces = $blockReplace instanceof GlowLichen ? $blockReplace->faces : [];
107 $availableFaces = $this->getAvailableFaces();
108
109 if(count($availableFaces) === 0){
110 return false;
111 }
112
113 $opposite = Facing::opposite($face);
114 $placedFace = isset($availableFaces[$opposite]) ? $opposite : array_key_first($availableFaces);
115 $this->faces[$placedFace] = $placedFace;
116
117 return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
118 }
119
120 public function onNearbyBlockChange() : void{
121 $changed = false;
122
123 foreach($this->faces as $face){
124 if($this->getAdjacentSupportType($face) !== SupportType::FULL){
125 unset($this->faces[$face]);
126 $changed = true;
127 }
128 }
129
130 if($changed){
131 $world = $this->position->getWorld();
132 if(count($this->faces) === 0){
133 $world->useBreakOn($this->position);
134 }else{
135 $world->setBlock($this->position, $this);
136 }
137 }
138 }
139
140 private function getSpreadBlock(Block $replace, int $spreadFace) : ?Block{
141 if($replace instanceof self && $replace->hasSameTypeId($this)){
142 if($replace->hasFace($spreadFace)){
143 return null;
144 }
145 $result = $replace;
146 }elseif($replace->getTypeId() === BlockTypeIds::AIR){
147 $result = VanillaBlocks::GLOW_LICHEN();
148 }else{
149 //TODO: if this is a water block, generate a waterlogged block
150 return null;
151 }
152 return $result->setFace($spreadFace, true);
153 }
154
155 private function spread(World $world, Vector3 $replacePos, int $spreadFace) : bool{
156 $supportBlock = $world->getBlock($replacePos->getSide($spreadFace));
157 $supportFace = Facing::opposite($spreadFace);
158
159 if($supportBlock->getSupportType($supportFace) !== SupportType::FULL){
160 return false;
161 }
162
163 $replacedBlock = $supportBlock->getSide($supportFace);
164 $replacementBlock = $this->getSpreadBlock($replacedBlock, Facing::opposite($supportFace));
165 if($replacementBlock === null){
166 return false;
167 }
168
169 return BlockEventHelper::spread($replacedBlock, $replacementBlock, $this);
170 }
171
175 private static function getShuffledSpreadFaces(int $sourceFace) : \Generator{
176 $skipAxis = Facing::axis($sourceFace);
177
178 $faces = Facing::ALL;
179 shuffle($faces);
180 foreach($faces as $spreadFace){
181 if(Facing::axis($spreadFace) !== $skipAxis){
182 yield $spreadFace;
183 }
184 }
185 }
186
187 private function spreadAroundSupport(int $sourceFace) : bool{
188 $world = $this->position->getWorld();
189
190 $supportPos = $this->position->getSide($sourceFace);
191 foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
192 $replacePos = $supportPos->getSide($spreadFace);
193 if($this->spread($world, $replacePos, Facing::opposite($spreadFace))){
194 return true;
195 }
196 }
197
198 return false;
199 }
200
201 private function spreadAdjacentToSupport(int $sourceFace) : bool{
202 $world = $this->position->getWorld();
203
204 foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
205 $replacePos = $this->position->getSide($spreadFace);
206 if($this->spread($world, $replacePos, $sourceFace)){
207 return true;
208 }
209 }
210 return false;
211 }
212
213 private function spreadWithinSelf(int $sourceFace) : bool{
214 foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
215 if(!$this->hasFace($spreadFace) && $this->spread($this->position->getWorld(), $this->position, $spreadFace)){
216 return true;
217 }
218 }
219
220 return false;
221 }
222
223 public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
224 if($item instanceof Fertilizer && count($this->faces) > 0){
225 $shuffledFaces = $this->faces;
226 shuffle($shuffledFaces);
227
228 $spreadMethods = [
229 $this->spreadAroundSupport(...),
230 $this->spreadAdjacentToSupport(...),
231 $this->spreadWithinSelf(...),
232 ];
233 shuffle($spreadMethods);
234
235 foreach($shuffledFaces as $sourceFace){
236 foreach($spreadMethods as $spreadMethod){
237 if($spreadMethod($sourceFace)){
238 $item->pop();
239 break 2;
240 }
241 }
242 }
243
244 return true;
245 }
246 return false;
247 }
248
249 public function getDrops(Item $item) : array{
250 if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0){
251 return $this->getDropsForCompatibleTool($item);
252 }
253
254 return [];
255 }
256
257 public function getFlameEncouragement() : int{
258 return 15;
259 }
260
261 public function getFlammability() : int{
262 return 100;
263 }
264
268 private function getAvailableFaces() : array{
269 $faces = [];
270 foreach(Facing::ALL as $face){
271 if(!$this->hasFace($face) && $this->getAdjacentSupportType($face) === SupportType::FULL){
272 $faces[$face] = $face;
273 }
274 }
275 return $faces;
276 }
277}
describeBlockOnlyState(RuntimeDataDescriber $w)
Definition: GlowLichen.php:46
place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player=null)
Definition: GlowLichen.php:105
setFace(int $face, bool $value)
Definition: GlowLichen.php:72
onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player=null, array &$returnedItems=[])
Definition: GlowLichen.php:223
pop(int $count=1)
Definition: Item.php:430