faces[Facing::SOUTH]) ? BlockLegacyMetadata::VINE_FLAG_SOUTH : 0) | (isset($this->faces[Facing::WEST]) ? BlockLegacyMetadata::VINE_FLAG_WEST : 0) | (isset($this->faces[Facing::NORTH]) ? BlockLegacyMetadata::VINE_FLAG_NORTH : 0) | (isset($this->faces[Facing::EAST]) ? BlockLegacyMetadata::VINE_FLAG_EAST : 0); } public function readStateFromData(int $id, int $stateMeta) : void{ $this->setFaceFromMeta($stateMeta, BlockLegacyMetadata::VINE_FLAG_SOUTH, Facing::SOUTH); $this->setFaceFromMeta($stateMeta, BlockLegacyMetadata::VINE_FLAG_WEST, Facing::WEST); $this->setFaceFromMeta($stateMeta, BlockLegacyMetadata::VINE_FLAG_NORTH, Facing::NORTH); $this->setFaceFromMeta($stateMeta, BlockLegacyMetadata::VINE_FLAG_EAST, Facing::EAST); } public function getStateBitmask() : int{ return 0b1111; } private function setFaceFromMeta(int $meta, int $flag, int $face) : void{ if(($meta & $flag) !== 0){ $this->faces[$face] = true; }else{ unset($this->faces[$face]); } } public function hasEntityCollision() : bool{ return true; } public function canClimb() : bool{ return true; } public function canBeReplaced() : bool{ return true; } public function onEntityInside(Entity $entity) : void{ $entity->resetFallDistance(); } protected function recalculateBoundingBox() : ?AxisAlignedBB{ switch(count($this->faces)){ case 0: return AxisAlignedBB::one()->trim(Facing::DOWN, 15 / 16); case 1: return AxisAlignedBB::one()->trim(Facing::opposite(array_keys($this->faces)[0]), 15 / 16); default: return AxisAlignedBB::one(); } } protected function recalculateCollisionBoxes() : array{ return []; } public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if(!$blockClicked->isSolid() or Facing::axis($face) === Facing::AXIS_Y){ return false; } $this->faces = $blockReplace instanceof Vine ? $blockReplace->faces : []; $this->faces[Facing::opposite($face)] = true; return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player); } public function onNearbyBlockChange() : void{ $changed = false; $up = $this->getSide(Facing::UP); //check which faces have corresponding vines in the block above $supportedFaces = $up instanceof Vine ? array_intersect_key($this->faces, $up->faces) : []; foreach($this->faces as $face => $bool){ if(!isset($supportedFaces[$face]) and !$this->getSide($face)->isSolid()){ unset($this->faces[$face]); $changed = true; } } if($changed){ if(empty($this->faces)){ $this->world->useBreakOn($this); }else{ $this->world->setBlock($this, $this); } } } public function ticksRandomly() : bool{ return true; } public function onRandomTick() : void{ //TODO: vine growth } public function getDrops(Item $item) : array{ if($item->getBlockToolType() & BlockToolType::TYPE_SHEARS){ return $this->getDropsForCompatibleTool($item); } return []; } public function getFlameEncouragement() : int{ return 15; } public function getFlammability() : int{ return 100; } }