diff --git a/src/pocketmine/block/BlockFactory.php b/src/pocketmine/block/BlockFactory.php index 7fc4af2ae..b105d4315 100644 --- a/src/pocketmine/block/BlockFactory.php +++ b/src/pocketmine/block/BlockFactory.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\Color; +use pocketmine\block\utils\PillarRotationTrait; use pocketmine\block\utils\WoodType; use pocketmine\item\Item; use pocketmine\level\Position; @@ -45,7 +46,7 @@ class BlockFactory{ public static $blastResistance = null; /** @var \SplFixedArray|int[] */ - public static $stateMasks = null; + private static $stateMasks = null; /** @var int[] */ public static $staticRuntimeIdMap = []; @@ -68,12 +69,12 @@ class BlockFactory{ self::$diffusesSkyLight = \SplFixedArray::fromArray(array_fill(0, 512, false)); self::$blastResistance = \SplFixedArray::fromArray(array_fill(0, 512, 0)); - self::$stateMasks = \SplFixedArray::fromArray(array_fill(0, 512, 0)); + self::$stateMasks = new \SplFixedArray(512); self::registerBlock(new Air()); - //TODO: give smooth stone its own class (different drops) - self::registerBlock(new Stone(Block::STONE, Stone::NORMAL, "Stone")); + self::registerBlock(new SmoothStone(Block::STONE, Stone::NORMAL, "Stone")); + self::registerBlock(new Stone(Block::STONE, Stone::GRANITE, "Granite")); self::registerBlock(new Stone(Block::STONE, Stone::POLISHED_GRANITE, "Polished Granite")); self::registerBlock(new Stone(Block::STONE, Stone::DIORITE, "Diorite")); @@ -83,9 +84,8 @@ class BlockFactory{ self::registerBlock(new Grass()); - //TODO: split these into separate classes self::registerBlock(new Dirt(Block::DIRT, Dirt::NORMAL, "Dirt")); - self::registerBlock(new Dirt(Block::DIRT, Dirt::COARSE, "Coarse Dirt")); + self::registerBlock(new CoarseDirt(Block::DIRT, Dirt::COARSE, "Coarse Dirt")); self::registerBlock(new Cobblestone()); @@ -355,11 +355,17 @@ class BlockFactory{ //TODO: HOPPER_BLOCK self::registerBlock(new Quartz(Block::QUARTZ_BLOCK, Quartz::NORMAL, "Quartz Block")); - self::registerBlock(new Quartz(Block::QUARTZ_BLOCK, Quartz::CHISELED, "Chiseled Quartz Block")); - self::registerBlock(new Quartz(Block::QUARTZ_BLOCK, Quartz::PILLAR, "Quartz Pillar")); + self::registerBlock(new class(Block::QUARTZ_BLOCK, Quartz::CHISELED, "Chiseled Quartz Block") extends Quartz{ + use PillarRotationTrait; + }); + self::registerBlock(new class(Block::QUARTZ_BLOCK, Quartz::PILLAR, "Quartz Pillar") extends Quartz{ + use PillarRotationTrait; + }); - self::registerBlock(new Purpur(Block::PURPUR_BLOCK, Purpur::NORMAL, "Purpur Block")); - self::registerBlock(new Purpur(Block::PURPUR_BLOCK, Purpur::PILLAR, "Purpur Pillar")); + self::registerBlock(new Purpur(Block::PURPUR_BLOCK, 0, "Purpur Block")); + self::registerBlock(new class(Block::PURPUR_BLOCK, 2, "Purpur Pillar") extends Purpur{ + use PillarRotationTrait; + }); self::registerBlock(new QuartzStairs()); @@ -382,9 +388,8 @@ class BlockFactory{ self::registerBlock(new DoublePlant(Block::DOUBLE_PLANT, 0, "Sunflower")); self::registerBlock(new DoublePlant(Block::DOUBLE_PLANT, 1, "Lilac")); - //TODO: double tallgrass and large fern have different behaviour than the others, so they should get their own classes - self::registerBlock(new DoublePlant(Block::DOUBLE_PLANT, 2, "Double Tallgrass")); - self::registerBlock(new DoublePlant(Block::DOUBLE_PLANT, 3, "Large Fern")); + self::registerBlock(new DoubleTallGrass(Block::DOUBLE_PLANT, 2, "Double Tallgrass")); + self::registerBlock(new DoubleTallGrass(Block::DOUBLE_PLANT, 3, "Large Fern")); self::registerBlock(new DoublePlant(Block::DOUBLE_PLANT, 4, "Rose Bush")); self::registerBlock(new DoublePlant(Block::DOUBLE_PLANT, 5, "Peony")); @@ -478,6 +483,10 @@ class BlockFactory{ throw new \RuntimeException("Trying to overwrite an already registered block"); } + if(self::$stateMasks[$id] !== null and self::$stateMasks[$id] !== $block->getStateBitmask()){ + throw new \InvalidArgumentException("Blocks with the same ID must have the same state bitmask"); + } + self::$fullList[($id << 4) | $variant] = clone $block; if($variant === 0){ //TODO: allow these to differ for different variants @@ -499,13 +508,9 @@ class BlockFactory{ throw new \InvalidArgumentException("Block meta value $meta is out of bounds"); } - if(self::$stateMasks[$id] === null){ - $variant = 0; - $state = $meta; - }else{ - $variant = $meta & ~self::$stateMasks[$id]; - $state = $meta & self::$stateMasks[$id]; - } + $stateMask = self::getStateMask($id); + $variant = $meta & ~$stateMask; + $state = $meta & $stateMask; $index = ($id << 4) | $variant; @@ -553,6 +558,10 @@ class BlockFactory{ self::$stateMasks[$id] = $block->getStateBitmask(); } + public static function getStateMask(int $id) : int{ + return self::$stateMasks[$id] ?? 0; + } + /** * Returns whether a specified block ID is already registered in the block factory. * diff --git a/src/pocketmine/block/BoneBlock.php b/src/pocketmine/block/BoneBlock.php index f632cfcc2..b8a183a1c 100644 --- a/src/pocketmine/block/BoneBlock.php +++ b/src/pocketmine/block/BoneBlock.php @@ -24,11 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\PillarRotationTrait; -use pocketmine\item\Item; use pocketmine\item\TieredTool; -use pocketmine\math\Facing; -use pocketmine\math\Vector3; -use pocketmine\Player; class BoneBlock extends Solid{ use PillarRotationTrait; @@ -54,9 +50,4 @@ class BoneBlock extends Solid{ public function getToolHarvestLevel() : int{ return TieredTool::TIER_WOODEN; } - - public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - $this->axis = Facing::axis($face); - return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player); - } } diff --git a/src/pocketmine/block/CoarseDirt.php b/src/pocketmine/block/CoarseDirt.php new file mode 100644 index 000000000..2f3a3eb25 --- /dev/null +++ b/src/pocketmine/block/CoarseDirt.php @@ -0,0 +1,41 @@ +applyDamage(1); + $this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT)); + return true; + } + + return false; + } +} diff --git a/src/pocketmine/block/Dirt.php b/src/pocketmine/block/Dirt.php index 2bc32e343..e810b0ab5 100644 --- a/src/pocketmine/block/Dirt.php +++ b/src/pocketmine/block/Dirt.php @@ -42,11 +42,7 @@ class Dirt extends Solid{ public function onActivate(Item $item, Player $player = null) : bool{ if($item instanceof Hoe){ $item->applyDamage(1); - if($this->variant === self::COARSE){ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT)); - }else{ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND)); - } + $this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND)); return true; } diff --git a/src/pocketmine/block/DoublePlant.php b/src/pocketmine/block/DoublePlant.php index fb4266c17..f9ab9bf4e 100644 --- a/src/pocketmine/block/DoublePlant.php +++ b/src/pocketmine/block/DoublePlant.php @@ -47,10 +47,6 @@ class DoublePlant extends Flowable{ return 0b1000; } - public function canBeReplaced() : bool{ - return $this->variant === 2 or $this->variant === 3; //grass or fern - } - public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $id = $blockReplace->getSide(Facing::DOWN)->getId(); if(($id === Block::GRASS or $id === Block::DIRT) and $blockReplace->getSide(Facing::UP)->canBeReplaced()){ @@ -85,28 +81,8 @@ class DoublePlant extends Flowable{ } } - public function getToolType() : int{ - return ($this->variant === 2 or $this->variant === 3) ? BlockToolType::TYPE_SHEARS : BlockToolType::TYPE_NONE; - } - - public function getToolHarvestLevel() : int{ - return ($this->variant === 2 or $this->variant === 3) ? 1 : 0; //only grass or fern require shears - } - public function getDrops(Item $item) : array{ - if($this->top){ - if($this->isCompatibleWithTool($item)){ - return parent::getDrops($item); - } - - if(mt_rand(0, 24) === 0){ - return [ - ItemFactory::get(Item::SEEDS) - ]; - } - } - - return []; + return $this->top ? parent::getDrops($item) : []; } public function getAffectedBlocks() : array{ diff --git a/src/pocketmine/block/DoubleTallGrass.php b/src/pocketmine/block/DoubleTallGrass.php new file mode 100644 index 000000000..374d8136a --- /dev/null +++ b/src/pocketmine/block/DoubleTallGrass.php @@ -0,0 +1,51 @@ +top and !$this->isCompatibleWithTool($item) and mt_rand(0, 7) === 0){ + return [ + ItemFactory::get(Item::SEEDS) + ]; + } + return parent::getDrops($item); + } +} diff --git a/src/pocketmine/block/HayBale.php b/src/pocketmine/block/HayBale.php index e39f20003..e1bb4e19b 100644 --- a/src/pocketmine/block/HayBale.php +++ b/src/pocketmine/block/HayBale.php @@ -24,10 +24,6 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\PillarRotationTrait; -use pocketmine\item\Item; -use pocketmine\math\Facing; -use pocketmine\math\Vector3; -use pocketmine\Player; class HayBale extends Solid{ use PillarRotationTrait; @@ -46,11 +42,6 @@ class HayBale extends Solid{ return 0.5; } - public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - $this->axis = Facing::axis($face); - return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player); - } - public function getFlameEncouragement() : int{ return 60; } diff --git a/src/pocketmine/block/Purpur.php b/src/pocketmine/block/Purpur.php index a2e3c49f6..5c6687aed 100644 --- a/src/pocketmine/block/Purpur.php +++ b/src/pocketmine/block/Purpur.php @@ -23,7 +23,17 @@ declare(strict_types=1); namespace pocketmine\block; -class Purpur extends Quartz{ +use pocketmine\item\TieredTool; + +class Purpur extends Solid{ + + public function getToolType() : int{ + return BlockToolType::TYPE_PICKAXE; + } + + public function getToolHarvestLevel() : int{ + return TieredTool::TIER_WOODEN; + } public function getHardness() : float{ return 1.5; @@ -32,4 +42,8 @@ class Purpur extends Quartz{ public function getBlastResistance() : float{ return 30; } + + public function getStateBitmask() : int{ + return 0b1100; //HACK: needs to be consistent for blocks with the same ID :( + } } diff --git a/src/pocketmine/block/Quartz.php b/src/pocketmine/block/Quartz.php index eb66aaff9..7c5e3c4e5 100644 --- a/src/pocketmine/block/Quartz.php +++ b/src/pocketmine/block/Quartz.php @@ -23,15 +23,9 @@ declare(strict_types=1); namespace pocketmine\block; -use pocketmine\block\utils\PillarRotationTrait; -use pocketmine\item\Item; use pocketmine\item\TieredTool; -use pocketmine\math\Facing; -use pocketmine\math\Vector3; -use pocketmine\Player; class Quartz extends Solid{ - use PillarRotationTrait; public const NORMAL = 0; public const CHISELED = 1; @@ -41,13 +35,6 @@ class Quartz extends Solid{ return 0.8; } - public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - if($this->variant !== self::NORMAL){ - $this->axis = Facing::axis($face); - } - return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player); - } - public function getToolType() : int{ return BlockToolType::TYPE_PICKAXE; } @@ -55,4 +42,8 @@ class Quartz extends Solid{ public function getToolHarvestLevel() : int{ return TieredTool::TIER_WOODEN; } + + public function getStateBitmask() : int{ + return 0b1100; //HACK: needs to be consistent for blocks with the same ID :( + } } diff --git a/src/pocketmine/block/SmoothStone.php b/src/pocketmine/block/SmoothStone.php new file mode 100644 index 000000000..764ee79a9 --- /dev/null +++ b/src/pocketmine/block/SmoothStone.php @@ -0,0 +1,36 @@ +variant === self::NORMAL){ - return [ - ItemFactory::get(Item::COBBLESTONE) - ]; - } - - return parent::getDropsForCompatibleTool($item); - } } diff --git a/src/pocketmine/block/Wood.php b/src/pocketmine/block/Wood.php index 9f66ef318..43e0eec29 100644 --- a/src/pocketmine/block/Wood.php +++ b/src/pocketmine/block/Wood.php @@ -24,10 +24,6 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\PillarRotationTrait; -use pocketmine\item\Item; -use pocketmine\math\Facing; -use pocketmine\math\Vector3; -use pocketmine\Player; class Wood extends Solid{ use PillarRotationTrait; @@ -41,11 +37,6 @@ class Wood extends Solid{ return 2; } - public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - $this->axis = Facing::axis($face); - return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player); - } - public function getToolType() : int{ return BlockToolType::TYPE_AXE; } diff --git a/src/pocketmine/block/utils/PillarRotationTrait.php b/src/pocketmine/block/utils/PillarRotationTrait.php index a7531e77f..156fae1ee 100644 --- a/src/pocketmine/block/utils/PillarRotationTrait.php +++ b/src/pocketmine/block/utils/PillarRotationTrait.php @@ -24,7 +24,10 @@ declare(strict_types=1); namespace pocketmine\block\utils; use pocketmine\block\Block; +use pocketmine\item\Item; use pocketmine\math\Facing; +use pocketmine\math\Vector3; +use pocketmine\Player; trait PillarRotationTrait{ @@ -73,4 +76,22 @@ trait PillarRotationTrait{ ]; return $bits[$this->axis] << 2; } + + /** + * @see Block::place() + * + * @param Item $item + * @param Block $blockReplace + * @param Block $blockClicked + * @param int $face + * @param Vector3 $clickVector + * @param Player|null $player + * + * @return bool + */ + public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ + $this->axis = Facing::axis($face); + /** @see Block::place() */ + return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player); + } } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 2ab1cc9a6..cf05d1971 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -986,7 +986,7 @@ class Level implements ChunkManager, Metadatable{ $blockId = $subChunk->getBlockId($x, $y, $z); $meta = $subChunk->getBlockData($x, $y, $z); - if($this->randomTickBlocks[($blockId << 4) | ($meta & ~BlockFactory::$stateMasks[$blockId])]){ + if($this->randomTickBlocks[($blockId << 4) | ($meta & ~BlockFactory::getStateMask($blockId))]){ /** @var Block $block */ $block = BlockFactory::get($blockId, $meta);