38 public function __construct(
41 private readonly
Block $decorBlock,
43 private readonly
bool $hasVines,
44 private readonly
bool $huge
46 parent::__construct($stemBlock, $hatBlock, $treeHeight);
49 public function canPlaceObject(
ChunkManager $world,
int $x,
int $y,
int $z,
Random $random) :
bool{
53 protected function placeTrunk(
int $x,
int $y,
int $z,
Random $random,
int $trunkHeight,
BlockTransaction $transaction) :
void{
54 $i = $this->huge ? 1 : 0;
56 for($j = -$i; $j <= $i; ++$j){
57 for($k = -$i; $k <= $i; ++$k){
58 $isCorner = $this->huge && abs($j) === $i && abs($k) === $i;
60 for($l = 0; $l < $trunkHeight; ++$l){
65 if((!$isCorner || $random->
nextFloat() < 0.1) && $this->canOverride($transaction->
fetchBlockAt($blockX, $blockY, $blockZ))){
66 $transaction->
addBlockAt($blockX, $blockY, $blockZ, $this->trunkBlock);
73 protected function placeCanopy(
int $x,
int $y,
int $z,
Random $random,
BlockTransaction $transaction) :
void{
74 $isCrimson = $this->hasVines;
75 $i = min($random->nextBoundedInt(1 + (
int) ($this->treeHeight / 3)) + 5, $this->treeHeight);
76 $j = $this->treeHeight - $i;
78 for($k = $j; $k <= $this->treeHeight; ++$k){
79 $l = $k < $this->treeHeight - $random->nextBoundedInt(3) ? 2 : 1;
81 if($i > 8 && $k < $j + 4){
89 for($i1 = -$l; $i1 <= $l; ++$i1){
90 for($j1 = -$l; $j1 <= $l; ++$j1){
91 $isEdgeX = $i1 === -$l || $i1 === $l;
92 $isEdgeZ = $j1 === -$l || $j1 === $l;
93 $isInner = !$isEdgeX && !$isEdgeZ && $k !== $this->treeHeight;
94 $isCorner = $isEdgeX && $isEdgeZ;
95 $isLowerSection = $k < $j + 3;
101 if($this->canOverride($transaction->
fetchBlockAt($blockX, $blockY, $blockZ))){
104 $this->placeHatDropBlock($blockX, $blockY, $blockZ, $random, $transaction, $isCrimson);
107 $this->placeHatBlock($blockX, $blockY, $blockZ, $random, $transaction, 0.1, 0.2, $isCrimson ? 0.1 : 0.0);
109 $this->placeHatBlock($blockX, $blockY, $blockZ, $random, $transaction, 0.01, 0.7, $isCrimson ? 0.083 : 0.0);
111 $this->placeHatBlock($blockX, $blockY, $blockZ, $random, $transaction, 0.0005, 0.98, $isCrimson ? 0.07 : 0.0);
119 protected function placeHatBlock(
int $x,
int $y,
int $z,
Random $random,
BlockTransaction $transaction,
float $decorChance,
float $hatChance,
float $vineChance) :
void{
121 $transaction->
addBlockAt($x, $y, $z, $this->decorBlock);
122 }elseif($random->
nextFloat() < $hatChance){
123 $transaction->
addBlockAt($x, $y, $z, $this->leafBlock);
125 $this->tryPlaceWeepingVines($x, $y, $z, $random, $transaction);
130 protected function placeHatDropBlock(
int $x,
int $y,
int $z,
Random $random,
BlockTransaction $transaction,
bool $isCrimson) :
void{
131 $blockBelow = $transaction->
fetchBlockAt($x, $y - 1, $z);
132 if($blockBelow->getTypeId() === $this->leafBlock->getTypeId()){
133 $transaction->
addBlockAt($x, $y, $z, $this->leafBlock);
135 $transaction->
addBlockAt($x, $y, $z, $this->leafBlock);
136 if($isCrimson && $random->nextBoundedInt(11) === 0){
137 $this->tryPlaceWeepingVines($x, $y, $z, $random, $transaction);
142 protected function tryPlaceWeepingVines(
int $x,
int $y,
int $z,
Random $random,
BlockTransaction $transaction) :
void{
145 if($this->canOverride($transaction->
fetchBlockAt($x, $currentY, $z))){
146 $i = $random->nextBoundedInt(5) + 1;
147 if($random->nextBoundedInt(7) === 0){
151 $maxAge = NetherVines::MAX_AGE;
154 for($v = 0; $v < $i; ++$v){
155 $vy = $currentY - $v;
160 if($this->canOverride($transaction->
fetchBlockAt($x, $vy, $z))){
161 $vineAge = min($maxAge, $startAge + $v);
162 $transaction->
addBlockAt($x, $vy, $z, VanillaBlocks::WEEPING_VINES()->setAge($vineAge));
170 protected function canOverride(
Block $block) :
bool{
174 protected function generateTrunkHeight(
Random $random) :
int{
175 return $this->treeHeight;