id = $id; $this->meta = $meta; $this->fallbackName = $name; $this->itemId = $itemId; } /** * @return string */ public function getName() : string{ return $this->fallbackName; } /** * @return int */ final public function getId() : int{ return $this->id; } /** * Returns the ID of the item form of the block. * Used for drops for blocks (some blocks such as doors have a different item ID). * * @return int */ public function getItemId() : int{ return $this->itemId ?? $this->getId(); } /** * @return int */ final public function getDamage() : int{ return $this->meta; } /** * @param int $meta */ final public function setDamage(int $meta){ if($meta < 0 or $meta > 0xf){ throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta"); } $this->meta = $meta; } /** * Bitmask to use to remove superfluous information from block meta when getting its item form or name. * This defaults to -1 (don't remove any data). Used to remove rotation data and bitflags from block drops. * * If your block should not have any meta value when it's dropped as an item, override this to return 0 in * descendent classes. * * @return int */ public function getVariantBitmask() : int{ return -1; } /** * Places the Block, using block space and block target, and side. Returns if the block has been placed. * * @param Item $item * @param Block $blockReplace * @param Block $blockClicked * @param int $face * @param Vector3 $facePos * @param Player|null $player * * @return bool */ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{ return $this->getLevel()->setBlock($this, $this, true, true); } /** * Returns if the block can be broken with an specific Item * * @param Item $item * * @return bool */ public function isBreakable(Item $item) : bool{ return true; } /** * Do the actions needed so the block is broken with the Item * * @param Item $item * @param Player|null $player * * @return bool */ public function onBreak(Item $item, Player $player = null) : bool{ return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true); } /** * Fires a block update on the Block * * @param int $type * * @return bool|int */ public function onUpdate(int $type){ return false; } /** * Do actions when activated by Item. Returns if it has done anything * * @param Item $item * @param Player|null $player * * @return bool */ public function onActivate(Item $item, Player $player = null) : bool{ return false; } /** * Returns a base value used to compute block break times. * @return float */ public function getHardness() : float{ return 10; } /** * @deprecated * @return float */ public function getResistance() : float{ return $this->getBlastResistance(); } /** * Returns the block's resistance to explosions. Usually 5x hardness. * @return float */ public function getBlastResistance() : float{ return $this->getHardness() * 5; } /** * @return int */ public function getToolType() : int{ return Tool::TYPE_NONE; } /** * @return float */ public function getFrictionFactor() : float{ return 0.6; } /** * @return int 0-15 */ public function getLightLevel() : int{ return 0; } /** * Returns the amount of light this block will filter out when light passes through this block. * This value is used in light spread calculation. * * @return int 0-15 */ public function getLightFilter() : int{ return 15; } /** * Returns whether this block will diffuse sky light passing through it vertically. * Diffusion means that full-strength sky light passing through this block will not be reduced, but will start being filtered below the block. * Examples of this behaviour include leaves and cobwebs. * * Light-diffusing blocks are included by the heightmap. * * @return bool */ public function diffusesSkyLight() : bool{ return false; } /** * Returns whether random block updates will be done on this block. * * @return bool */ public function ticksRandomly() : bool{ return false; } /** * AKA: Block->isPlaceable * @return bool */ public function canBePlaced() : bool{ return true; } /** * @param Block|null $with * * @return bool */ public function canBeReplaced(Block $with = null) : bool{ return false; } /** * @return bool */ public function isTransparent() : bool{ return false; } public function isSolid() : bool{ return true; } /** * AKA: Block->isFlowable * @return bool */ public function canBeFlowedInto() : bool{ return false; } public function hasEntityCollision() : bool{ return false; } public function canPassThrough() : bool{ return false; } /** * Returns whether entities can climb up this block. * @return bool */ public function canClimb() : bool{ return false; } public function addVelocityToEntity(Entity $entity, Vector3 $vector){ } /** * Sets the block position to a new Position object * * @param Position $v */ final public function position(Position $v){ $this->x = (int) $v->x; $this->y = (int) $v->y; $this->z = (int) $v->z; $this->level = $v->level; $this->boundingBox = null; } /** * Returns an array of Item objects to be dropped * * @param Item $item * * @return Item[] */ public function getDrops(Item $item) : array{ return [ ItemFactory::get($this->getItemId(), $this->getDamage() & $this->getVariantBitmask(), 1) ]; } /** * Returns the seconds that this block takes to be broken using an specific Item * * @param Item $item * * @return float */ public function getBreakTime(Item $item) : float{ $base = $this->getHardness() * 1.5; if($this->canBeBrokenWith($item)){ if($this->getToolType() === Tool::TYPE_SHEARS and $item->isShears()){ $base /= 15; }elseif( ($this->getToolType() === Tool::TYPE_PICKAXE and ($tier = $item->isPickaxe()) !== false) or ($this->getToolType() === Tool::TYPE_AXE and ($tier = $item->isAxe()) !== false) or ($this->getToolType() === Tool::TYPE_SHOVEL and ($tier = $item->isShovel()) !== false) ){ switch($tier){ case Tool::TIER_WOODEN: $base /= 2; break; case Tool::TIER_STONE: $base /= 4; break; case Tool::TIER_IRON: $base /= 6; break; case Tool::TIER_DIAMOND: $base /= 8; break; case Tool::TIER_GOLD: $base /= 12; break; } } }else{ $base *= 3.33; } if($item->isSword()){ $base *= 0.5; } return $base; } public function canBeBrokenWith(Item $item) : bool{ return $this->getHardness() !== -1; } /** * Returns the time in ticks which the block will fuel a furnace for. * @return int */ public function getFuelTime() : int{ return 0; } /** * Returns the Block on the side $side, works like Vector3::side() * * @param int $side * @param int $step * * @return Block */ public function getSide($side, $step = 1){ if($this->isValid()){ return $this->getLevel()->getBlock(Vector3::getSide($side, $step)); } return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step))); } /** * @return string */ public function __toString(){ return "Block[" . $this->getName() . "] (" . $this->getId() . ":" . $this->getDamage() . ")"; } /** * Checks for collision against an AxisAlignedBB * * @param AxisAlignedBB $bb * * @return bool */ public function collidesWithBB(AxisAlignedBB $bb) : bool{ $bb2 = $this->getBoundingBox(); return $bb2 !== null and $bb->intersectsWith($bb2); } /** * @param Entity $entity */ public function onEntityCollide(Entity $entity){ } /** * @return AxisAlignedBB|null */ public function getBoundingBox(){ if($this->boundingBox === null){ $this->boundingBox = $this->recalculateBoundingBox(); } return $this->boundingBox; } /** * @return AxisAlignedBB|null */ protected function recalculateBoundingBox(){ return new AxisAlignedBB( $this->x, $this->y, $this->z, $this->x + 1, $this->y + 1, $this->z + 1 ); } /** * @param Vector3 $pos1 * @param Vector3 $pos2 * * @return MovingObjectPosition|null */ public function calculateIntercept(Vector3 $pos1, Vector3 $pos2){ $bb = $this->getBoundingBox(); if($bb === null){ return null; } $v1 = $pos1->getIntermediateWithXValue($pos2, $bb->minX); $v2 = $pos1->getIntermediateWithXValue($pos2, $bb->maxX); $v3 = $pos1->getIntermediateWithYValue($pos2, $bb->minY); $v4 = $pos1->getIntermediateWithYValue($pos2, $bb->maxY); $v5 = $pos1->getIntermediateWithZValue($pos2, $bb->minZ); $v6 = $pos1->getIntermediateWithZValue($pos2, $bb->maxZ); if($v1 !== null and !$bb->isVectorInYZ($v1)){ $v1 = null; } if($v2 !== null and !$bb->isVectorInYZ($v2)){ $v2 = null; } if($v3 !== null and !$bb->isVectorInXZ($v3)){ $v3 = null; } if($v4 !== null and !$bb->isVectorInXZ($v4)){ $v4 = null; } if($v5 !== null and !$bb->isVectorInXY($v5)){ $v5 = null; } if($v6 !== null and !$bb->isVectorInXY($v6)){ $v6 = null; } $vector = $v1; if($v2 !== null and ($vector === null or $pos1->distanceSquared($v2) < $pos1->distanceSquared($vector))){ $vector = $v2; } if($v3 !== null and ($vector === null or $pos1->distanceSquared($v3) < $pos1->distanceSquared($vector))){ $vector = $v3; } if($v4 !== null and ($vector === null or $pos1->distanceSquared($v4) < $pos1->distanceSquared($vector))){ $vector = $v4; } if($v5 !== null and ($vector === null or $pos1->distanceSquared($v5) < $pos1->distanceSquared($vector))){ $vector = $v5; } if($v6 !== null and ($vector === null or $pos1->distanceSquared($v6) < $pos1->distanceSquared($vector))){ $vector = $v6; } if($vector === null){ return null; } $f = -1; if($vector === $v1){ $f = 4; }elseif($vector === $v2){ $f = 5; }elseif($vector === $v3){ $f = 0; }elseif($vector === $v4){ $f = 1; }elseif($vector === $v5){ $f = 2; }elseif($vector === $v6){ $f = 3; } return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z)); } public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){ if($this->getLevel() instanceof Level){ $this->getLevel()->getBlockMetadata()->setMetadata($this, $metadataKey, $newMetadataValue); } } public function getMetadata(string $metadataKey){ if($this->getLevel() instanceof Level){ return $this->getLevel()->getBlockMetadata()->getMetadata($this, $metadataKey); } return null; } public function hasMetadata(string $metadataKey) : bool{ if($this->getLevel() instanceof Level){ return $this->getLevel()->getBlockMetadata()->hasMetadata($this, $metadataKey); } return false; } public function removeMetadata(string $metadataKey, Plugin $owningPlugin){ if($this->getLevel() instanceof Level){ $this->getLevel()->getBlockMetadata()->removeMetadata($this, $metadataKey, $owningPlugin); } } }