diff --git a/src/world/generator/object/AcaciaTree.php b/src/world/generator/object/AcaciaTree.php new file mode 100644 index 000000000..75e58a9b3 --- /dev/null +++ b/src/world/generator/object/AcaciaTree.php @@ -0,0 +1,132 @@ +nextRange(0, 2) + $random->nextRange(0, 2); + } + + protected function placeTrunk(int $x, int $y, int $z, Random $random, int $trunkHeight, BlockTransaction $transaction) : void{ + // The base dirt block + $transaction->addBlockAt($x, $y - 1, $z, VanillaBlocks::DIRT()); + + $firstBranchHeight = $trunkHeight - 1 - $random->nextRange(0, 3); + + for($yy = 0; $yy <= $firstBranchHeight; ++$yy){ + $transaction->addBlockAt($x, $y + $yy, $z, $this->trunkBlock); + } + + $mainBranchFacing = Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)]; + + //this branch may grow a second trunk if the diagonal length is less than the max length + $this->mainBranchTip = $this->placeBranch( + $transaction, + new Vector3($x, $y + $firstBranchHeight, $z), + $mainBranchFacing, + $random->nextRange(1, 3), + $trunkHeight - $firstBranchHeight + ); + + $secondBranchFacing = Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)]; + if($secondBranchFacing !== $mainBranchFacing){ + $secondBranchLength = $random->nextRange(1, 3); + $this->secondBranchTip = $this->placeBranch( + $transaction, + new Vector3($x, $y + ($firstBranchHeight - $random->nextRange(0, 1)), $z), + $secondBranchFacing, + $secondBranchLength, + $secondBranchLength //the secondary branch may not form a second trunk + ); + } + } + + protected function placeBranch(BlockTransaction $transaction, Vector3 $start, int $branchFacing, int $maxDiagonal, int $length) : Vector3{ + $diagonalPlaced = 0; + + $nextBlockPos = $start; + for($yy = 0; $yy < $length; $yy++){ + $nextBlockPos = $nextBlockPos->up(); + if($diagonalPlaced < $maxDiagonal){ + $nextBlockPos = $nextBlockPos->getSide($branchFacing); + $diagonalPlaced++; + } + $transaction->addBlock($nextBlockPos, $this->trunkBlock); + } + + return $nextBlockPos; + } + + protected function placeCanopyLayer(BlockTransaction $transaction, Vector3 $center, int $radius, int $maxTaxicabDistance) : void{ + $centerX = $center->getFloorX(); + $centerY = $center->getFloorY(); + $centerZ = $center->getFloorZ(); + + for($x = $centerX - $radius; $x <= $centerX + $radius; ++$x){ + for($z = $centerZ - $radius; $z <= $centerZ + $radius; ++$z){ + if( + abs($x - $centerX) + abs($z - $centerZ) <= $maxTaxicabDistance && + $transaction->fetchBlockAt($x, $centerY, $z)->canBeReplaced() + ){ + $transaction->addBlockAt($x, $centerY, $z, $this->leafBlock); + } + } + } + } + + protected function placeCanopy(int $x, int $y, int $z, Random $random, BlockTransaction $transaction) : void{ + $mainBranchTip = $this->mainBranchTip; + if($mainBranchTip !== null){ + $this->placeCanopyLayer($transaction, $mainBranchTip, radius: 3, maxTaxicabDistance: 5); + $this->placeCanopyLayer($transaction, $mainBranchTip->up(), radius: 2, maxTaxicabDistance: 2); + } + $secondBranchTip = $this->secondBranchTip; + if($secondBranchTip !== null){ + $this->placeCanopyLayer($transaction, $secondBranchTip, radius: 2, maxTaxicabDistance: 3); + $this->placeCanopyLayer($transaction, $secondBranchTip->up(), radius: 1, maxTaxicabDistance: 2); + } + } +} diff --git a/src/world/generator/object/TreeFactory.php b/src/world/generator/object/TreeFactory.php index ecab73c79..1d95a77b1 100644 --- a/src/world/generator/object/TreeFactory.php +++ b/src/world/generator/object/TreeFactory.php @@ -49,6 +49,8 @@ final class TreeFactory{ }else{*/ //} + }elseif($type->equals(TreeType::ACACIA())){ + return new AcaciaTree(); } return null; }