40    use StaticSupportTrait {
 
   44    public const MAX_AGE = 15;
 
   46    private function seekToBottom() : 
Position{
 
   47        $world = $this->position->getWorld();
 
   48        $bottom = $this->position;
 
   49        while(($next = $world->getBlock($bottom->down()))->hasSameTypeId($this)){
 
   50            $bottom = $next->position;
 
   55    private function grow(
Position $pos, ?
Player $player = 
null) : 
bool{
 
   58        for($y = 1; $y < 3; ++$y){
 
   59            if(!$world->isInWorld($pos->x, $pos->y + $y, $pos->z)){
 
   62            $b = $world->getBlockAt($pos->x, $pos->y + $y, $pos->z);
 
   63            if($b->getTypeId() === BlockTypeIds::AIR){
 
   64                if(BlockEventHelper::grow($b, VanillaBlocks::SUGARCANE(), $player)){
 
   69            }elseif(!$b->hasSameTypeId($this)){
 
   74        $world->setBlock($pos, $this);
 
   80            if($this->grow($this->seekToBottom(), $player)){
 
 
   90    private function canBeSupportedAt(Block $block) : bool{
 
   91        $supportBlock = $block->getSide(Facing::DOWN);
 
   92        return $supportBlock->hasSameTypeId($this) ||
 
   93            $supportBlock->hasTypeTag(BlockTypeTags::MUD) ||
 
   94            $supportBlock->hasTypeTag(BlockTypeTags::DIRT) ||
 
   95            $supportBlock->hasTypeTag(BlockTypeTags::SAND);
 
  103        $down = $this->getSide(
Facing::DOWN);
 
  104        if(!$down->hasSameTypeId($this)){
 
  105            if(!$this->hasNearbyWater($down)){
 
  106                $this->position->getWorld()->useBreakOn($this->position, createParticles: true);
 
  110            if($this->age === self::MAX_AGE){
 
  111                $this->grow($this->position);
 
  114                $this->position->getWorld()->setBlock($this->position, $this);
 
 
  120        $down = $blockReplace->getSide(
Facing::DOWN);
 
  121        if($down->hasSameTypeId($this)){
 
  122            return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
 
  126        foreach(Facing::HORIZONTAL as $side){
 
  127            $sideBlock = $down->getSide($side);
 
  128            if($sideBlock instanceof Water || $sideBlock instanceof FrostedIce){
 
  129                return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
 
 
  136    private function hasNearbyWater(Block $down) : bool{
 
  137        foreach($down->getHorizontalSides() as $sideBlock){
 
  138            $blockId = $sideBlock->getTypeId();
 
  139            if($blockId === BlockTypeIds::WATER || $blockId === BlockTypeIds::FROSTED_ICE){
 
  147        $down = $this->getSide(
Facing::DOWN);
 
  148        if(!$down->hasSameTypeId($this) && !$this->hasNearbyWater($down)){
 
  149            $this->position->getWorld()->useBreakOn($this->position, createParticles: true);
 
  151            $this->onSupportBlockChange();
 
 
 
place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player=null)