Split some block variants into their own classes where behaviour differs

This commit is contained in:
Dylan K. Taylor 2018-09-28 16:21:03 +01:00
parent e038c4295d
commit 2600cf5977
14 changed files with 200 additions and 102 deletions

View File

@ -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.
*

View File

@ -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);
}
}

View File

@ -0,0 +1,41 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Hoe;
use pocketmine\item\Item;
use pocketmine\Player;
class CoarseDirt extends Dirt{
public function onActivate(Item $item, Player $player = null) : bool{
if($item instanceof Hoe){
$item->applyDamage(1);
$this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT));
return true;
}
return false;
}
}

View File

@ -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));
}
return true;
}

View File

@ -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{

View File

@ -0,0 +1,51 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
class DoubleTallGrass extends DoublePlant{
public function canBeReplaced() : bool{
return true;
}
public function getToolType() : int{
return BlockToolType::TYPE_SHEARS;
}
public function getToolHarvestLevel() : int{
return 1;
}
public function getDrops(Item $item) : array{
if($this->top and !$this->isCompatibleWithTool($item) and mt_rand(0, 7) === 0){
return [
ItemFactory::get(Item::SEEDS)
];
}
return parent::getDrops($item);
}
}

View File

@ -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;
}

View File

@ -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 :(
}
}

View File

@ -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 :(
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
class SmoothStone extends Stone{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::COBBLESTONE)
];
}
}

View File

@ -47,14 +47,4 @@ class Stone extends Solid{
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getDropsForCompatibleTool(Item $item) : array{
if($this->variant === self::NORMAL){
return [
ItemFactory::get(Item::COBBLESTONE)
];
}
return parent::getDropsForCompatibleTool($item);
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);