PocketMine-MP 5.23.3 git-976fc63567edab7a6fb6aeae739f43cf9fe57de4
Loading...
Searching...
No Matches
block/Bamboo.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
26use pocketmine\block\utils\StaticSupportTrait;
27use pocketmine\block\utils\SupportType;
30use pocketmine\item\Bamboo as ItemBamboo;
39use function count;
40use function gmp_add;
41use function gmp_and;
42use function gmp_intval;
43use function gmp_mul;
44use function gmp_xor;
45use function min;
46use function mt_rand;
47use const PHP_INT_MAX;
48
49class Bamboo extends Transparent{
50 use StaticSupportTrait;
51
52 public const NO_LEAVES = 0;
53 public const SMALL_LEAVES = 1;
54 public const LARGE_LEAVES = 2;
55
56 protected bool $thick = false; //age in PC, but this is 0/1
57 protected bool $ready = false;
58 protected int $leafSize = self::NO_LEAVES;
59
60 protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
61 $w->boundedIntAuto(self::NO_LEAVES, self::LARGE_LEAVES, $this->leafSize);
62 $w->bool($this->thick);
63 $w->bool($this->ready);
64 }
65
66 public function isThick() : bool{ return $this->thick; }
67
69 public function setThick(bool $thick) : self{
70 $this->thick = $thick;
71 return $this;
72 }
73
74 public function isReady() : bool{ return $this->ready; }
75
77 public function setReady(bool $ready) : self{
78 $this->ready = $ready;
79 return $this;
80 }
81
82 public function getLeafSize() : int{ return $this->leafSize; }
83
85 public function setLeafSize(int $leafSize) : self{
86 $this->leafSize = $leafSize;
87 return $this;
88 }
89
90 protected function recalculateCollisionBoxes() : array{
91 //this places the BB at the northwest corner, not the center
92 $inset = 1 - (($this->thick ? 3 : 2) / 16);
93 return [AxisAlignedBB::one()->trim(Facing::SOUTH, $inset)->trim(Facing::EAST, $inset)];
94 }
95
96 public function getSupportType(int $facing) : SupportType{
97 return SupportType::NONE;
98 }
99
100 private static function getOffsetSeed(int $x, int $y, int $z) : int{
101 $p1 = gmp_mul($z, 0x6ebfff5);
102 $p2 = gmp_mul($x, 0x2fc20f);
103 $p3 = $y;
104
105 $xord = gmp_xor(gmp_xor($p1, $p2), $p3);
106
107 $fullResult = gmp_mul(gmp_add(gmp_mul($xord, 0x285b825), 0xb), $xord);
108 return gmp_intval(gmp_and($fullResult, 0xffffffff));
109 }
110
111 private static function getMaxHeight(int $x, int $z) : int{
112 return 12 + (self::getOffsetSeed($x, 0, $z) % 5);
113 }
114
115 public function getModelPositionOffset() : ?Vector3{
116 $seed = self::getOffsetSeed($this->position->getFloorX(), 0, $this->position->getFloorZ());
117 $retX = (($seed % 12) + 1) / 16;
118 $retZ = ((($seed >> 8) % 12) + 1) / 16;
119 return new Vector3($retX, 0, $retZ);
120 }
121
122 private function canBeSupportedAt(Block $block) : bool{
123 $supportBlock = $block->getSide(Facing::DOWN);
124 return
125 $supportBlock->hasSameTypeId($this) ||
126 $supportBlock->getTypeId() === BlockTypeIds::GRAVEL ||
127 $supportBlock->hasTypeTag(BlockTypeTags::DIRT) ||
128 $supportBlock->hasTypeTag(BlockTypeTags::MUD) ||
129 $supportBlock->hasTypeTag(BlockTypeTags::SAND);
130 }
131
132 private function seekToTop() : Bamboo{
133 $world = $this->position->getWorld();
134 $top = $this;
135 while(($next = $world->getBlock($top->position->up())) instanceof Bamboo && $next->hasSameTypeId($this)){
136 $top = $next;
137 }
138 return $top;
139 }
140
141 public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
142 if($item instanceof Fertilizer){
143 $top = $this->seekToTop();
144 if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2), $player)){
145 $item->pop();
146 return true;
147 }
148 }elseif($item instanceof ItemBamboo){
149 if($this->seekToTop()->grow(PHP_INT_MAX, 1, $player)){
150 $item->pop();
151 return true;
152 }
153 }
154 return false;
155 }
156
157 private function grow(int $maxHeight, int $growAmount, ?Player $player) : bool{
158 $world = $this->position->getWorld();
159 if(!$world->getBlock($this->position->up())->canBeReplaced()){
160 return false;
161 }
162
163 $height = 1;
164 while($world->getBlock($this->position->subtract(0, $height, 0))->hasSameTypeId($this)){
165 if(++$height >= $maxHeight){
166 return false;
167 }
168 }
169
170 $newHeight = $height + $growAmount;
171
172 $stemBlock = (clone $this)->setReady(false)->setLeafSize(self::NO_LEAVES);
173 if($newHeight >= 4 && !$stemBlock->thick){ //don't change it to false if height is less, because it might have been chopped
174 $stemBlock = $stemBlock->setThick(true);
175 }
176 $smallLeavesBlock = (clone $stemBlock)->setLeafSize(self::SMALL_LEAVES);
177 $bigLeavesBlock = (clone $stemBlock)->setLeafSize(self::LARGE_LEAVES);
178
179 $newBlocks = [];
180 if($newHeight === 2){
181 $newBlocks[] = $smallLeavesBlock;
182 }elseif($newHeight === 3){
183 $newBlocks[] = $smallLeavesBlock;
184 $newBlocks[] = $smallLeavesBlock;
185 }elseif($newHeight === 4){
186 $newBlocks[] = $bigLeavesBlock;
187 $newBlocks[] = $smallLeavesBlock;
188 $newBlocks[] = $stemBlock;
189 $newBlocks[] = $stemBlock;
190 }elseif($newHeight > 4){
191 $newBlocks[] = $bigLeavesBlock;
192 $newBlocks[] = $bigLeavesBlock;
193 $newBlocks[] = $smallLeavesBlock;
194 for($i = 0, $max = min($growAmount, $newHeight - count($newBlocks)); $i < $max; ++$i){
195 $newBlocks[] = $stemBlock; //to replace the bottom blocks that currently have leaves
196 }
197 }
198
199 $tx = new BlockTransaction($world);
200 foreach($newBlocks as $idx => $newBlock){
201 $tx->addBlock($this->position->subtract(0, $idx - $growAmount, 0), $newBlock);
202 }
203
204 $ev = new StructureGrowEvent($this, $tx, $player);
205 $ev->call();
206 if($ev->isCancelled()){
207 return false;
208 }
209
210 return $tx->apply();
211 }
212
213 public function ticksRandomly() : bool{
214 return true;
215 }
216
217 public function onRandomTick() : void{
218 $world = $this->position->getWorld();
219 if($this->ready){
220 $this->ready = false;
221 if($world->getFullLight($this->position) < 9 || !$this->grow(self::getMaxHeight($this->position->getFloorX(), $this->position->getFloorZ()), 1, null)){
222 $world->setBlock($this->position, $this);
223 }
224 }elseif($world->getBlock($this->position->up())->canBeReplaced()){
225 $this->ready = true;
226 $world->setBlock($this->position, $this);
227 }
228 }
229
230 public function asItem() : Item{
231 return VanillaItems::BAMBOO();
232 }
233}
describeBlockOnlyState(RuntimeDataDescriber $w)
onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player=null, array &$returnedItems=[])
setLeafSize(int $leafSize)
getSupportType(int $facing)
hasSameTypeId(Block $other)
Definition Block.php:187
pop(int $count=1)
Definition Item.php:430