Nuke Block->meta, split into variant and state properties, lots of cleanup

This is a major change to the way block metadata is handled within the PM core. This separates variant metadata (which really ought to be part of the ID) from state metadata, and in a couple of cases flattens separate states of blocks together.

The result of this is that invalid variants can be much more easily detected, and additionally state handling is much cleaner since meta is only needed at the serialize layer instead of throughout the code.
This commit is contained in:
Dylan K. Taylor 2018-09-21 19:28:10 +01:00
parent a55ab54ddb
commit 56d9943b0d
178 changed files with 2012 additions and 2120 deletions

View File

@ -2448,6 +2448,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public function handleItemFrameDropItem(ItemFrameDropItemPacket $packet) : bool{
$tile = $this->level->getTileAt($packet->x, $packet->y, $packet->z);
if($tile instanceof ItemFrame){
//TODO: use facing blockstate property instead of damage value
$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $tile->getBlock(), null, 5 - $tile->getBlock()->getDamage(), PlayerInteractEvent::LEFT_CLICK_BLOCK);
if($this->isSpectator() or $this->level->checkSpawnProtection($this, $tile)){
$ev->setCancelled();

View File

@ -34,8 +34,8 @@ class Air extends Transparent{
protected $id = self::AIR;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -28,6 +28,7 @@ use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Bearing;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -37,10 +38,19 @@ class Anvil extends Fallable{
public const TYPE_SLIGHTLY_DAMAGED = 4;
public const TYPE_VERY_DAMAGED = 8;
protected $id = self::ANVIL;
/** @var int */
protected $facing = Facing::NORTH;
public function __construct(int $meta = 0){
$this->setDamage($meta);
protected function writeStateToMeta() : int{
return Bearing::fromFacing($this->facing);
}
public function readStateFromMeta(int $meta) : void{
$this->facing = Bearing::toFacing($meta);
}
public function getStateBitmask() : int{
return 0b11;
}
public function isTransparent() : bool{
@ -55,19 +65,6 @@ class Anvil extends Fallable{
return 6000;
}
public function getVariantBitmask() : int{
return 0x0c;
}
public function getName() : string{
static $names = [
self::TYPE_NORMAL => "Anvil",
self::TYPE_SLIGHTLY_DAMAGED => "Slightly Damaged Anvil",
self::TYPE_VERY_DAMAGED => "Very Damaged Anvil"
];
return $names[$this->getVariant()] ?? "Anvil";
}
public function getToolType() : int{
return BlockToolType::TYPE_PICKAXE;
}
@ -79,7 +76,7 @@ class Anvil extends Fallable{
public function recalculateBoundingBox() : ?AxisAlignedBB{
$inset = 0.125;
if($this->meta & 0x01){ //east/west
if(Facing::axis($this->facing) === Facing::AXIS_X){
return new AxisAlignedBB(0, 0, $inset, 1, 1, 1 - $inset);
}else{
return new AxisAlignedBB($inset, 0, 0, 1 - $inset, 1, 1);
@ -95,8 +92,9 @@ class Anvil extends Fallable{
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
$direction = $player !== null ? Bearing::rotate($player->getDirection(), 1) : 0;
$this->meta = $this->getVariant() | $direction;
if($player !== null){
$this->facing = Bearing::toFacing(Bearing::rotate($player->getDirection(), 1));
}
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -37,13 +37,6 @@ abstract class BaseRail extends Flowable{
public const ASCENDING_NORTH = 4;
public const ASCENDING_SOUTH = 5;
private const ASCENDING_SIDES = [
self::ASCENDING_NORTH => Facing::NORTH,
self::ASCENDING_EAST => Facing::EAST,
self::ASCENDING_SOUTH => Facing::SOUTH,
self::ASCENDING_WEST => Facing::WEST
];
protected const FLAG_ASCEND = 1 << 24; //used to indicate direction-up
protected const CONNECTIONS = [
@ -76,8 +69,28 @@ abstract class BaseRail extends Flowable{
]
];
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int[] */
protected $connections = [];
public function __construct(){
}
protected function writeStateToMeta() : int{
if(empty($this->connections)){
return self::STRAIGHT_NORTH_SOUTH;
}
return $this->getMetaForState($this->connections);
}
public function readStateFromMeta(int $meta) : void{
//on invalid states, this will return an empty array, allowing this rail to transform into any other state
//TODO: should this throw instead?
$this->connections = $this->getConnectionsFromMeta($meta);
}
public function getStateBitmask() : int{
return 0b111;
}
public function getHardness() : float{
@ -121,9 +134,11 @@ abstract class BaseRail extends Flowable{
/**
* Returns the connection directions of this rail (depending on the current block state)
*
* @param int $meta
*
* @return int[]
*/
abstract protected function getConnectionsForState() : array;
abstract protected function getConnectionsFromMeta(int $meta) : array;
/**
* Returns all the directions this rail is already connected in.
@ -135,7 +150,7 @@ abstract class BaseRail extends Flowable{
$connections = [];
/** @var int $connection */
foreach($this->getConnectionsForState() as $connection){
foreach($this->connections as $connection){
$other = $this->getSide($connection & ~self::FLAG_ASCEND);
$otherConnection = Facing::opposite($connection & ~self::FLAG_ASCEND);
@ -149,7 +164,7 @@ abstract class BaseRail extends Flowable{
if(
$other instanceof BaseRail and
in_array($otherConnection, $other->getConnectionsForState(), true)
in_array($otherConnection, $other->connections, true)
){
$connections[] = $connection;
}
@ -248,20 +263,20 @@ abstract class BaseRail extends Flowable{
throw new \InvalidArgumentException("Expected exactly 2 connections, got " . count($connections));
}
$this->meta = $this->getMetaForState($connections);
$this->connections = $connections;
$this->level->setBlock($this, $this, false, false); //avoid recursion
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->isTransparent() or (
isset(self::ASCENDING_SIDES[$this->meta & 0x07]) and
$this->getSide(self::ASCENDING_SIDES[$this->meta & 0x07])->isTransparent()
)){
$this->getLevel()->useBreakOn($this);
if($this->getSide(Facing::DOWN)->isTransparent()){
$this->level->useBreakOn($this);
}else{
foreach($this->connections as $connection){
if(($connection & self::FLAG_ASCEND) !== 0 and $this->getSide($connection & ~self::FLAG_ASCEND)->isTransparent()){
$this->level->useBreakOn($this);
break;
}
}
}
}
public function getVariantBitmask() : int{
return 0;
}
}

View File

@ -37,15 +37,38 @@ use pocketmine\tile\Tile;
use pocketmine\utils\TextFormat;
class Bed extends Transparent{
public const BITFLAG_OCCUPIED = 0x04;
public const BITFLAG_HEAD = 0x08;
private const BITFLAG_OCCUPIED = 0x04;
private const BITFLAG_HEAD = 0x08;
protected $id = self::BED_BLOCK;
protected $itemId = Item::BED;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $facing = Facing::NORTH;
/** @var bool */
protected $occupied = false;
/** @var bool */
protected $head = false;
public function __construct(){
}
protected function writeStateToMeta() : int{
return Bearing::fromFacing($this->facing) |
($this->occupied ? self::BITFLAG_OCCUPIED : 0) |
($this->head ? self::BITFLAG_HEAD : 0);
}
public function readStateFromMeta(int $meta) : void{
$this->facing = Bearing::toFacing($meta & 0x03);
$this->occupied = ($meta & self::BITFLAG_OCCUPIED) !== 0;
$this->head = ($meta & self::BITFLAG_HEAD) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function getHardness() : float{
@ -61,51 +84,39 @@ class Bed extends Transparent{
}
public function isHeadPart() : bool{
return ($this->meta & self::BITFLAG_HEAD) !== 0;
return $this->head;
}
/**
* @return bool
*/
public function isOccupied() : bool{
return ($this->meta & self::BITFLAG_OCCUPIED) !== 0;
return $this->occupied;
}
public function setOccupied(bool $occupied = true){
if($occupied){
$this->meta |= self::BITFLAG_OCCUPIED;
}else{
$this->meta &= ~self::BITFLAG_OCCUPIED;
}
$this->occupied = $occupied;
$this->level->setBlock($this, $this, false, false);
$this->getLevel()->setBlock($this, $this, false, false);
if(($other = $this->getOtherHalf()) !== null and $other->isOccupied() !== $occupied){
$other->setOccupied($occupied);
if(($other = $this->getOtherHalf()) !== null){
$other->occupied = $occupied;
$this->level->setBlock($other, $other, false, false);
}
}
/**
* @param int $meta
* @param bool $isHead
*
* @return int
*/
public static function getOtherHalfSide(int $meta, bool $isHead = false) : int{
$side = Bearing::toFacing($meta & 0x03);
if($isHead){
$side = Facing::opposite($side);
}
return $side;
private function getOtherHalfSide() : int{
return $this->head ? Facing::opposite($this->facing) : $this->facing;
}
/**
* @return Bed|null
*/
public function getOtherHalf() : ?Bed{
$other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart()));
if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){
$other = $this->getSide($this->getOtherHalfSide());
if($other instanceof Bed and $other->head !== $this->head and $other->facing === $this->facing){
return $other;
}
@ -152,11 +163,14 @@ class Bed extends Transparent{
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
$down = $this->getSide(Facing::DOWN);
if(!$down->isTransparent()){
$this->meta = $player instanceof Player ? $player->getDirection() : 0;
$next = $this->getSide(self::getOtherHalfSide($this->meta));
$this->facing = $player !== null ? Bearing::toFacing($player->getDirection()) : Facing::NORTH;
$next = $this->getSide($this->getOtherHalfSide());
if($next->canBeReplaced() and !$next->getSide(Facing::DOWN)->isTransparent()){
parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $this->meta | self::BITFLAG_HEAD), true, true);
$nextState = clone $this;
$nextState->head = true;
$this->getLevel()->setBlock($next, $nextState, true, true);
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player));
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player));

View File

@ -29,8 +29,8 @@ class Bedrock extends Solid{
protected $id = self::BEDROCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -30,16 +30,12 @@ class Beetroot extends Crops{
protected $id = self::BEETROOT_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getName() : string{
return "Beetroot Block";
}
public function getDropsForCompatibleTool(Item $item) : array{
if($this->meta >= 0x07){
if($this->age >= 7){
return [
ItemFactory::get(Item::BEETROOT),
ItemFactory::get(Item::BEETROOT_SEEDS, 0, mt_rand(0, 3))

View File

@ -60,7 +60,7 @@ class Block extends Position implements BlockIds, Metadatable{
/** @var int */
protected $id;
/** @var int */
protected $meta = 0;
protected $variant = 0;
/** @var string|null */
protected $fallbackName;
/** @var int|null */
@ -74,14 +74,18 @@ class Block extends Position implements BlockIds, Metadatable{
protected $collisionBoxes = null;
/**
* @param int $id The block type's ID, 0-255
* @param int $meta Meta value of the block type
* @param string|null $name English name of the block type (TODO: implement translations)
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
* @param int $id The block type's ID, 0-255
* @param int $variant Meta value of the block type
* @param string|null $name English name of the block type (TODO: implement translations)
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
*/
public function __construct(int $id, int $meta = 0, string $name = null, int $itemId = null){
public function __construct(int $id, int $variant = 0, string $name = null, int $itemId = null){
$this->id = $id;
$this->meta = $meta;
if(($variant & $this->getStateBitmask()) !== 0){
throw new \InvalidArgumentException("Variant 0x" . dechex($variant) . " collides with state bitmask 0x" . dechex($this->getStateBitmask()));
}
$this->variant = $variant;
$this->fallbackName = $name;
$this->itemId = $itemId;
}
@ -122,30 +126,26 @@ class Block extends Position implements BlockIds, Metadatable{
* @return int
*/
public function getDamage() : int{
return $this->meta;
$stateMeta = $this->writeStateToMeta();
assert(($stateMeta & ~$this->getStateBitmask()) === 0);
return $this->variant | $stateMeta;
}
protected function writeStateToMeta() : int{
return 0;
}
public function readStateFromMeta(int $meta) : void{
//NOOP
}
/**
* @param int $meta
*/
public function setDamage(int $meta) : void{
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.
* Returns a bitmask used to extract state bits from block metadata.
*
* @return int
*/
public function getVariantBitmask() : int{
return -1;
public function getStateBitmask() : int{
return 0;
}
/**
@ -153,10 +153,9 @@ class Block extends Position implements BlockIds, Metadatable{
* @return int
*/
public function getVariant() : int{
return $this->meta & $this->getVariantBitmask();
return $this->variant;
}
/**
* AKA: Block->isPlaceable
* @return bool

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\Color;
use pocketmine\block\utils\WoodType;
use pocketmine\item\Item;
use pocketmine\level\Position;
@ -32,6 +34,8 @@ use pocketmine\level\Position;
class BlockFactory{
/** @var \SplFixedArray<Block> */
private static $fullList = null;
/** @var \SplFixedArray|\Closure[] */
private static $getInterceptors = null;
/** @var \SplFixedArray<int> */
public static $lightFilter = null;
@ -40,6 +44,9 @@ class BlockFactory{
/** @var \SplFixedArray<float> */
public static $blastResistance = null;
/** @var \SplFixedArray|int[] */
public static $stateMasks = null;
/** @var int[] */
public static $staticRuntimeIdMap = [];
@ -55,56 +62,138 @@ class BlockFactory{
*/
public static function init() : void{
self::$fullList = new \SplFixedArray(4096);
self::$getInterceptors = new \SplFixedArray(4096);
self::$lightFilter = \SplFixedArray::fromArray(array_fill(0, 256, 1));
self::$diffusesSkyLight = \SplFixedArray::fromArray(array_fill(0, 256, false));
self::$blastResistance = \SplFixedArray::fromArray(array_fill(0, 256, 0));
self::$stateMasks = \SplFixedArray::fromArray(array_fill(0, 256, 0));
self::registerBlock(new Air());
self::registerBlock(new Stone());
//TODO: give smooth stone its own class (different drops)
self::registerBlock(new Stone(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"));
self::registerBlock(new Stone(Block::STONE, Stone::POLISHED_DIORITE, "Polished Diorite"));
self::registerBlock(new Stone(Block::STONE, Stone::ANDESITE, "Andesite"));
self::registerBlock(new Stone(Block::STONE, Stone::POLISHED_ANDESITE, "Polished Andesite"));
self::registerBlock(new Grass());
self::registerBlock(new Dirt());
//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 Cobblestone());
self::registerBlock(new Planks());
self::registerBlock(new Sapling());
foreach(WoodType::ALL as $type){
self::registerBlock(new Planks(Block::PLANKS, $type, WoodType::NAMES[$type] . " Planks"));
self::registerBlock(new Sapling(Block::SAPLING, $type, WoodType::NAMES[$type] . " Sapling"));
self::registerBlock(new WoodenFence(Block::FENCE, $type, WoodType::NAMES[$type] . " Fence"));
}
foreach(WoodType::ALL as $type){
//TODO: find a better way to deal with this split
self::registerBlock(new Wood($type >= 4 ? Block::WOOD2 : Block::WOOD, $type & 0x03, WoodType::NAMES[$type] . " Wood"));
self::registerBlock(new Leaves($type >= 4 ? Block::LEAVES2 : Block::LEAVES, $type & 0x03, $type, WoodType::NAMES[$type] . " Leaves"));
}
self::registerBlock(new Bedrock());
self::registerBlock(new Water());
self::registerBlock(new StillWater());
self::registerBlock(new Lava());
self::registerBlock(new StillLava());
self::registerBlock(new Sand());
self::registerBlock(new Sand(Block::SAND, 0, "Sand"));
self::registerBlock(new Sand(Block::SAND, 1, "Red Sand"));
self::registerBlock(new Gravel());
self::registerBlock(new GoldOre());
self::registerBlock(new IronOre());
self::registerBlock(new CoalOre());
self::registerBlock(new Wood());
self::registerBlock(new Leaves());
self::registerBlock(new Sponge());
self::registerBlock(new Glass());
self::registerBlock(new Glass(Block::GLASS, 0, "Glass"));
self::registerBlock(new LapisOre());
self::registerBlock(new Lapis());
//TODO: DISPENSER
self::registerBlock(new Sandstone());
static $sandstoneTypes = [
Sandstone::NORMAL => "",
Sandstone::CHISELED => "Chiseled ",
Sandstone::SMOOTH => "Smooth "
];
foreach($sandstoneTypes as $variant => $prefix){
self::registerBlock(new Sandstone(Block::SANDSTONE, $variant, $prefix . "Sandstone"));
self::registerBlock(new Sandstone(Block::RED_SANDSTONE, $variant, $prefix . "Red Sandstone"));
}
self::registerBlock(new NoteBlock());
self::registerBlock(new Bed());
self::registerBlock(new PoweredRail());
self::registerBlock(new DetectorRail());
//TODO: STICKY_PISTON
self::registerBlock(new Cobweb());
self::registerBlock(new TallGrass());
self::registerBlock(new TallGrass(Block::TALL_GRASS, 0, "Fern"));
self::registerBlock(new TallGrass(Block::TALL_GRASS, 1, "Tall Grass"));
self::registerBlock(new TallGrass(Block::TALL_GRASS, 2, "Fern"));
self::registerBlock(new TallGrass(Block::TALL_GRASS, 3, "Fern"));
self::registerBlock(new DeadBush());
//TODO: PISTON
//TODO: PISTONARMCOLLISION
self::registerBlock(new Wool());
foreach(Color::ALL as $color){
self::registerBlock(new Wool(Block::WOOL, $color, Color::NAMES[$color] . " Wool"));
self::registerBlock(new HardenedClay(Block::STAINED_CLAY, $color, Color::NAMES[$color] . " Stained Clay"));
self::registerBlock(new Glass(Block::STAINED_GLASS, $color, Color::NAMES[$color] . " Stained Glass"));
self::registerBlock(new GlassPane(Block::STAINED_GLASS_PANE, $color, Color::NAMES[$color] . " Stained Glass Pane"));
self::registerBlock(new Carpet(Block::CARPET, $color, Color::NAMES[$color] . " Carpet"));
self::registerBlock(new Concrete(Block::CONCRETE, $color, Color::NAMES[$color] . " Concrete"));
self::registerBlock(new ConcretePowder(Block::CONCRETE_POWDER, $color, Color::NAMES[$color] . " Concrete Powder"));
}
self::registerBlock(new Dandelion());
self::registerBlock(new Flower());
self::registerBlock(new Flower(Block::RED_FLOWER, Flower::TYPE_POPPY, "Poppy"));
self::registerBlock(new Flower(Block::RED_FLOWER, Flower::TYPE_BLUE_ORCHID, "Blue Orchid"));
self::registerBlock(new Flower(Block::RED_FLOWER, Flower::TYPE_ALLIUM, "Allium"));
self::registerBlock(new Flower(Block::RED_FLOWER, Flower::TYPE_AZURE_BLUET, "Azure Bluet"));
self::registerBlock(new Flower(Block::RED_FLOWER, Flower::TYPE_RED_TULIP, "Red Tulip"));
self::registerBlock(new Flower(Block::RED_FLOWER, Flower::TYPE_ORANGE_TULIP, "Orange Tulip"));
self::registerBlock(new Flower(Block::RED_FLOWER, Flower::TYPE_WHITE_TULIP, "White Tulip"));
self::registerBlock(new Flower(Block::RED_FLOWER, Flower::TYPE_PINK_TULIP, "Pink Tulip"));
self::registerBlock(new Flower(Block::RED_FLOWER, Flower::TYPE_OXEYE_DAISY, "Oxeye Daisy"));
self::registerBlock(new BrownMushroom());
self::registerBlock(new RedMushroom());
self::registerBlock(new Gold());
self::registerBlock(new Iron());
self::registerBlock(new DoubleStoneSlab());
self::registerBlock(new StoneSlab());
/** @var Slab[] $slabTypes */
$slabTypes = [
new StoneSlab(Block::STONE_SLAB, Block::DOUBLE_STONE_SLAB, 0, "Stone"),
new StoneSlab(Block::STONE_SLAB, Block::DOUBLE_STONE_SLAB, 1, "Sandstone"),
new StoneSlab(Block::STONE_SLAB, Block::DOUBLE_STONE_SLAB, 2, "Fake Wooden"),
new StoneSlab(Block::STONE_SLAB, Block::DOUBLE_STONE_SLAB, 3, "Cobblestone"),
new StoneSlab(Block::STONE_SLAB, Block::DOUBLE_STONE_SLAB, 4, "Brick"),
new StoneSlab(Block::STONE_SLAB, Block::DOUBLE_STONE_SLAB, 5, "Stone Brick"),
new StoneSlab(Block::STONE_SLAB, Block::DOUBLE_STONE_SLAB, 6, "Quartz"),
new StoneSlab(Block::STONE_SLAB, Block::DOUBLE_STONE_SLAB, 7, "Nether Brick"),
new StoneSlab(Block::STONE_SLAB2, Block::DOUBLE_STONE_SLAB2, 0, "Red Sandstone"),
new StoneSlab(Block::STONE_SLAB2, Block::DOUBLE_STONE_SLAB2, 1, "Purpur")
];
foreach(WoodType::ALL as $woodType){
$slabTypes[] = new WoodenSlab($woodType);
}
foreach($slabTypes as $type){
self::registerBlock($type);
self::registerBlock(new DoubleSlab($type->getDoubleSlabId(), $type->getId(), $type->getVariant()));
}
self::registerBlock(new Bricks());
self::registerBlock(new TNT());
self::registerBlock(new Bookshelf());
@ -121,8 +210,16 @@ class BlockFactory{
self::registerBlock(new CraftingTable());
self::registerBlock(new Wheat());
self::registerBlock(new Farmland());
self::registerBlock(new Furnace());
self::registerBlock(new BurningFurnace());
self::addGetInterceptor(Block::BURNING_FURNACE, 0, function() : Block{
$block = self::get(Block::FURNACE);
if($block instanceof Furnace){
$block->setLit();
}
return $block;
});
self::registerBlock(new SignPost());
self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door", Item::OAK_DOOR));
self::registerBlock(new Ladder());
@ -134,9 +231,23 @@ class BlockFactory{
self::registerBlock(new IronDoor());
self::registerBlock(new WoodenPressurePlate());
self::registerBlock(new RedstoneOre());
self::registerBlock(new GlowingRedstoneOre());
self::registerBlock(new RedstoneTorchUnlit());
self::addGetInterceptor(Block::GLOWING_REDSTONE_ORE, 0, function() : Block{
$block = self::get(Block::REDSTONE_ORE);
if($block instanceof RedstoneOre){
$block->setLit();
}
return $block;
});
self::registerBlock(new RedstoneTorch());
self::addGetInterceptor(Block::UNLIT_REDSTONE_TORCH, 0, function() : Block{
$block = self::get(Block::REDSTONE_TORCH);
if($block instanceof RedstoneTorch){
$block->setLit(false); //default state is lit
}
return $block;
});
self::registerBlock(new StoneButton());
self::registerBlock(new SnowLayer());
self::registerBlock(new Ice());
@ -145,7 +256,7 @@ class BlockFactory{
self::registerBlock(new Clay());
self::registerBlock(new Sugarcane());
//TODO: JUKEBOX
self::registerBlock(new WoodenFence());
self::registerBlock(new Pumpkin());
self::registerBlock(new Netherrack());
self::registerBlock(new SoulSand());
@ -158,11 +269,16 @@ class BlockFactory{
//TODO: INVISIBLEBEDROCK
self::registerBlock(new Trapdoor());
//TODO: MONSTER_EGG
self::registerBlock(new StoneBricks());
self::registerBlock(new StoneBricks(Block::STONE_BRICKS, StoneBricks::NORMAL, "Stone Bricks"));
self::registerBlock(new StoneBricks(Block::STONE_BRICKS, StoneBricks::MOSSY, "Mossy Stone Bricks"));
self::registerBlock(new StoneBricks(Block::STONE_BRICKS, StoneBricks::CRACKED, "Cracked Stone Bricks"));
self::registerBlock(new StoneBricks(Block::STONE_BRICKS, StoneBricks::CHISELED, "Chiseled Stone Bricks"));
self::registerBlock(new BrownMushroomBlock());
self::registerBlock(new RedMushroomBlock());
self::registerBlock(new IronBars());
self::registerBlock(new GlassPane());
self::registerBlock(new GlassPane(Block::GLASS_PANE, 0, "Glass Pane"));
self::registerBlock(new Melon());
self::registerBlock(new PumpkinStem());
self::registerBlock(new MelonStem());
@ -184,7 +300,14 @@ class BlockFactory{
self::registerBlock(new EndStone());
//TODO: DRAGON_EGG
self::registerBlock(new RedstoneLamp());
self::registerBlock(new LitRedstoneLamp());
self::addGetInterceptor(Block::LIT_REDSTONE_LAMP, 0, function() : Block{
$block = self::get(Block::REDSTONE_LAMP);
if($block instanceof RedstoneLamp){
$block->setLit();
}
return $block;
});
//TODO: DROPPER
self::registerBlock(new ActivatorRail());
self::registerBlock(new CocoaBlock());
@ -199,50 +322,76 @@ class BlockFactory{
self::registerBlock(new WoodenStairs(Block::JUNGLE_STAIRS, 0, "Jungle Stairs"));
//TODO: COMMAND_BLOCK
//TODO: BEACON
self::registerBlock(new CobblestoneWall());
self::registerBlock(new CobblestoneWall(Block::COBBLESTONE_WALL, CobblestoneWall::NONE_MOSSY_WALL, "Cobblestone Wall"));
self::registerBlock(new CobblestoneWall(Block::COBBLESTONE_WALL, CobblestoneWall::MOSSY_WALL, "Mossy Cobblestone Wall"));
self::registerBlock(new FlowerPot());
self::registerBlock(new Carrot());
self::registerBlock(new Potato());
self::registerBlock(new WoodenButton());
self::registerBlock(new Skull());
self::registerBlock(new Anvil());
self::registerBlock(new Anvil(Block::ANVIL, Anvil::TYPE_NORMAL, "Anvil"));
self::registerBlock(new Anvil(Block::ANVIL, Anvil::TYPE_SLIGHTLY_DAMAGED, "Slightly Damaged Anvil"));
self::registerBlock(new Anvil(Block::ANVIL, Anvil::TYPE_VERY_DAMAGED, "Very Damaged Anvil"));
self::registerBlock(new TrappedChest());
self::registerBlock(new WeightedPressurePlateLight());
self::registerBlock(new WeightedPressurePlateHeavy());
//TODO: COMPARATOR_BLOCK
//TODO: POWERED_COMPARATOR
self::registerBlock(new DaylightSensor());
self::addGetInterceptor(Block::DAYLIGHT_SENSOR_INVERTED, 0, function() : Block{
$block = self::get(Block::DAYLIGHT_SENSOR);
if($block instanceof DaylightSensor){
$block->setInverted();
}
return $block;
});
self::registerBlock(new Redstone());
self::registerBlock(new NetherQuartzOre());
//TODO: HOPPER_BLOCK
self::registerBlock(new Quartz());
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 Purpur(Block::PURPUR_BLOCK, Purpur::NORMAL, "Purpur Block"));
self::registerBlock(new Purpur(Block::PURPUR_BLOCK, Purpur::PILLAR, "Purpur Pillar"));
self::registerBlock(new QuartzStairs());
self::registerBlock(new DoubleWoodenSlab());
self::registerBlock(new WoodenSlab());
self::registerBlock(new StainedClay());
self::registerBlock(new StainedGlassPane());
self::registerBlock(new Leaves2());
self::registerBlock(new Wood2());
self::registerBlock(new WoodenStairs(Block::ACACIA_STAIRS, 0, "Acacia Stairs"));
self::registerBlock(new WoodenStairs(Block::DARK_OAK_STAIRS, 0, "Dark Oak Stairs"));
//TODO: SLIME
self::registerBlock(new IronTrapdoor());
self::registerBlock(new Prismarine());
self::registerBlock(new Prismarine(Block::PRISMARINE, Prismarine::NORMAL, "Prismarine"));
self::registerBlock(new Prismarine(Block::PRISMARINE, Prismarine::DARK, "Dark Prismarine"));
self::registerBlock(new Prismarine(Block::PRISMARINE, Prismarine::BRICKS, "Prismarine Bricks"));
self::registerBlock(new SeaLantern());
self::registerBlock(new HayBale());
self::registerBlock(new Carpet());
self::registerBlock(new HardenedClay());
self::registerBlock(new HardenedClay(Block::HARDENED_CLAY, 0, "Hardened Clay"));
self::registerBlock(new Coal());
self::registerBlock(new PackedIce());
self::registerBlock(new DoublePlant());
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 DoublePlant(Block::DOUBLE_PLANT, 4, "Rose Bush"));
self::registerBlock(new DoublePlant(Block::DOUBLE_PLANT, 5, "Peony"));
self::registerBlock(new StandingBanner());
self::registerBlock(new WallBanner());
//TODO: DAYLIGHT_DETECTOR_INVERTED
self::registerBlock(new RedSandstone());
self::registerBlock(new RedSandstoneStairs());
self::registerBlock(new DoubleStoneSlab2());
self::registerBlock(new StoneSlab2());
self::registerBlock(new FenceGate(Block::SPRUCE_FENCE_GATE, 0, "Spruce Fence Gate"));
self::registerBlock(new FenceGate(Block::BIRCH_FENCE_GATE, 0, "Birch Fence Gate"));
self::registerBlock(new FenceGate(Block::JUNGLE_FENCE_GATE, 0, "Jungle Fence Gate"));
@ -259,7 +408,6 @@ class BlockFactory{
self::registerBlock(new GrassPath());
self::registerBlock(new ItemFrame());
//TODO: CHORUS_FLOWER
self::registerBlock(new Purpur());
self::registerBlock(new PurpurStairs());
@ -292,11 +440,8 @@ class BlockFactory{
self::registerBlock(new GlazedTerracotta(Block::GREEN_GLAZED_TERRACOTTA, 0, "Green Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::RED_GLAZED_TERRACOTTA, 0, "Red Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::BLACK_GLAZED_TERRACOTTA, 0, "Black Glazed Terracotta"));
self::registerBlock(new Concrete());
self::registerBlock(new ConcretePowder());
//TODO: CHORUS_PLANT
self::registerBlock(new StainedGlass());
self::registerBlock(new Podzol());
self::registerBlock(new Beetroot());
@ -327,20 +472,17 @@ class BlockFactory{
*/
public static function registerBlock(Block $block, bool $override = false) : void{
$id = $block->getId();
$variant = $block->getVariant();
if(!$override and self::isRegistered($id)){
if(!$override and self::isRegistered($id, $variant)){
throw new \RuntimeException("Trying to overwrite an already registered block");
}
for($meta = 0; $meta < 16; ++$meta){
$variant = clone $block;
$variant->setDamage($meta);
self::$fullList[($id << 4) | $meta] = $variant;
self::$fullList[($id << 4) | $variant] = clone $block;
if($variant === 0){
//TODO: allow these to differ for different variants
self::fillStaticArrays($id, $block);
}
self::$lightFilter[$id] = min(15, $block->getLightFilter() + 1); //opacity plus 1 standard light filter
self::$diffusesSkyLight[$id] = $block->diffusesSkyLight();
self::$blastResistance[$id] = $block->getBlastResistance();
}
/**
@ -357,16 +499,34 @@ 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];
}
$index = ($id << 4) | $variant;
/** @var Block|null $block */
$block = null;
try{
if(self::$fullList[($id << 4) | $meta] !== null){
$block = clone self::$fullList[($id << 4) | $meta];
}else{
$block = new UnknownBlock($id, $meta);
if(self::$getInterceptors[$index] !== null){
$block = (self::$getInterceptors[$index])();
}elseif(self::$fullList[$index] !== null){
$block = clone self::$fullList[$index];
}
}catch(\RuntimeException $e){
throw new \InvalidArgumentException("Block ID $id is out of bounds");
}
if($block !== null){
$block->readStateFromMeta($state);
}else{
$block = new UnknownBlock($id, $meta);
}
if($pos !== null){
$block->x = $pos->getFloorX();
$block->y = $pos->getFloorY();
@ -377,22 +537,32 @@ class BlockFactory{
return $block;
}
/**
* @internal
* @return \SplFixedArray
*/
public static function getBlockStatesArray() : \SplFixedArray{
return self::$fullList;
public static function addGetInterceptor(int $id, int $variant, \Closure $interceptor) : void{
$block = $interceptor();
if(!($block instanceof Block)){
throw new \InvalidArgumentException("Interceptor must return an instance of " . Block::class);
}
self::$getInterceptors[($id << 4) | $variant] = $interceptor;
self::fillStaticArrays($id, $block);
}
private static function fillStaticArrays(int $id, Block $block) : void{
self::$lightFilter[$id] = min(15, $block->getLightFilter() + 1); //opacity plus 1 standard light filter
self::$diffusesSkyLight[$id] = $block->diffusesSkyLight();
self::$blastResistance[$id] = $block->getBlastResistance();
self::$stateMasks[$id] = $block->getStateBitmask();
}
/**
* Returns whether a specified block ID is already registered in the block factory.
*
* @param int $id
* @param int $variant
*
* @return bool
*/
public static function isRegistered(int $id) : bool{
$b = self::$fullList[$id << 4];
public static function isRegistered(int $id, int $variant = 0) : bool{
$b = self::$fullList[($id << 4) | $variant];
return $b !== null and !($b instanceof UnknownBlock);
}

View File

@ -23,18 +23,20 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\PillarRotationHelper;
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;
protected $id = Block::BONE_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{
@ -54,11 +56,7 @@ class BoneBlock extends Solid{
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
$this->axis = Facing::axis($face);
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function getVariantBitmask() : int{
return 0x03;
}
}

View File

@ -30,8 +30,8 @@ class Bookshelf extends Solid{
protected $id = self::BOOKSHELF;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -32,8 +32,29 @@ class BrewingStand extends Transparent{
protected $itemId = Item::BREWING_STAND;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var bool */
protected $eastSlot = false;
/** @var bool */
protected $northwestSlot = false;
/** @var bool */
protected $southwestSlot = false;
public function __construct(){
}
protected function writeStateToMeta() : int{
return ($this->eastSlot ? 0x01 : 0) | ($this->southwestSlot ? 0x02 : 0) | ($this->northwestSlot ? 0x04 : 0);
}
public function readStateFromMeta(int $meta) : void{
$this->eastSlot = ($meta & 0x01) !== 0;
$this->southwestSlot = ($meta & 0x02) !== 0;
$this->northwestSlot = ($meta & 0x04) !== 0;
}
public function getStateBitmask() : int{
return 0b111;
}
public function getName() : string{
@ -52,9 +73,5 @@ class BrewingStand extends Transparent{
return TieredTool::TIER_WOODEN;
}
public function getVariantBitmask() : int{
return 0;
}
//TODO
}

View File

@ -29,8 +29,8 @@ class BrickStairs extends Stair{
protected $id = self::BRICK_STAIRS;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -29,8 +29,8 @@ class Bricks extends Solid{
protected $id = self::BRICK_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -1,96 +0,0 @@
<?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\TieredTool;
use pocketmine\math\Bearing;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\Furnace as TileFurnace;
use pocketmine\tile\Tile;
class BurningFurnace extends Solid{
protected $id = self::BURNING_FURNACE;
protected $itemId = self::FURNACE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getName() : string{
return "Burning Furnace";
}
public function getHardness() : float{
return 3.5;
}
public function getToolType() : int{
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getLightLevel() : int{
return 13;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if($player !== null){
$this->meta = Bearing::toFacing(Bearing::opposite($player->getDirection()));
}
if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));
return true;
}
return false;
}
public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){
$furnace = $this->getLevel()->getTile($this);
if(!($furnace instanceof TileFurnace)){
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
}
if(!$furnace->canOpenWith($item->getCustomName())){
return true;
}
$player->addWindow($furnace->getInventory());
}
return true;
}
public function getVariantBitmask() : int{
return 0;
}
}

View File

@ -24,22 +24,38 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\Player;
abstract class Button extends Flowable{
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $facing = Facing::DOWN;
/** @var bool */
protected $powered = false;
public function __construct(){
}
public function getVariantBitmask() : int{
return 0;
protected function writeStateToMeta() : int{
return $this->facing | ($this->powered ? 0x08 : 0);
}
public function readStateFromMeta(int $meta) : void{
//TODO: in PC it's (6 - facing) for every meta except 0 (down)
$this->facing = $meta & 0x07;
$this->powered = ($meta & 0x08) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
//TODO: check valid target block
$this->meta = $face;
$this->facing = $face;
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}

View File

@ -38,8 +38,23 @@ class Cactus extends Transparent{
protected $id = self::CACTUS;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $age = 0;
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->age;
}
public function readStateFromMeta(int $meta) : void{
$this->age = $meta;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function getHardness() : float{
@ -85,7 +100,7 @@ class Cactus extends Transparent{
public function onRandomTick() : void{
if($this->getSide(Facing::DOWN)->getId() !== self::CACTUS){
if($this->meta === 0x0f){
if($this->age === 15){
for($y = 1; $y < 3; ++$y){
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
if($b->getId() === self::AIR){
@ -95,10 +110,10 @@ class Cactus extends Transparent{
}
}
}
$this->meta = 0;
$this->age = 0;
$this->getLevel()->setBlock($this, $this);
}else{
++$this->meta;
++$this->age;
$this->getLevel()->setBlock($this, $this);
}
}
@ -118,8 +133,4 @@ class Cactus extends Transparent{
return false;
}
public function getVariantBitmask() : int{
return 0;
}
}

View File

@ -38,8 +38,23 @@ class Cake extends Transparent implements FoodSource{
protected $itemId = Item::CAKE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $bites = 0;
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->bites;
}
public function readStateFromMeta(int $meta) : void{
$this->bites = $meta;
}
public function getStateBitmask() : int{
return 0b111;
}
public function getHardness() : float{
@ -51,7 +66,7 @@ class Cake extends Transparent implements FoodSource{
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$f = $this->getDamage() * 0.125; //1 slice width
$f = $this->bites * 0.125; //1 slice width
return new AxisAlignedBB(
0.0625 + $f,
@ -112,8 +127,8 @@ class Cake extends Transparent implements FoodSource{
*/
public function getResidue(){
$clone = clone $this;
$clone->meta++;
if($clone->meta > 0x06){
$clone->bites++;
if($clone->bites > 6){
$clone = BlockFactory::get(Block::AIR);
}
return $clone;

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
@ -32,12 +31,6 @@ use pocketmine\Player;
class Carpet extends Flowable{
protected $id = self::CARPET;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getHardness() : float{
return 0.1;
}
@ -46,10 +39,6 @@ class Carpet extends Flowable{
return true;
}
public function getName() : string{
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Carpet";
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(0, 0, 0, 1, 0.0625, 1);
}

View File

@ -30,17 +30,13 @@ class Carrot extends Crops{
protected $id = self::CARROT_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getName() : string{
return "Carrot Block";
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::CARROT, 0, $this->meta >= 0x07 ? mt_rand(1, 4) : 1)
ItemFactory::get(Item::CARROT, 0, $this->age >= 7 ? mt_rand(1, 4) : 1)
];
}

View File

@ -36,8 +36,23 @@ class Chest extends Transparent{
protected $id = self::CHEST;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $facing = Facing::NORTH;
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->facing;
}
public function readStateFromMeta(int $meta) : void{
$this->facing = $meta;
}
public function getStateBitmask() : int{
return 0b111;
}
public function getHardness() : float{
@ -60,7 +75,7 @@ class Chest extends Transparent{
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
$chest = null;
if($player !== null){
$this->meta = Bearing::toFacing(Bearing::opposite($player->getDirection()));
$this->facing = Bearing::toFacing(Bearing::opposite($player->getDirection()));
}
foreach([
@ -68,7 +83,7 @@ class Chest extends Transparent{
Bearing::toFacing(Bearing::rotate($player->getDirection(), 1))
] as $side){
$c = $this->getSide($side);
if($c->getId() === $this->id and $c->getDamage() === $this->meta){
if($c instanceof Chest and $c->getId() === $this->getId() and $c->facing === $this->facing){
$tile = $this->getLevel()->getTile($c);
if($tile instanceof TileChest and !$tile->isPaired()){
$chest = $tile;
@ -116,10 +131,6 @@ class Chest extends Transparent{
return true;
}
public function getVariantBitmask() : int{
return 0;
}
public function getFuelTime() : int{
return 300;
}

View File

@ -30,8 +30,8 @@ class Clay extends Solid{
protected $id = self::CLAY_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -29,8 +29,8 @@ class Coal extends Solid{
protected $id = self::COAL_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -31,8 +31,8 @@ class CoalOre extends Solid{
protected $id = self::COAL_ORE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -29,8 +29,8 @@ class Cobblestone extends Solid{
protected $id = self::COBBLESTONE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getToolType() : int{

View File

@ -29,8 +29,8 @@ class CobblestoneStairs extends Stair{
protected $id = self::COBBLESTONE_STAIRS;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -31,12 +31,6 @@ class CobblestoneWall extends Transparent{
public const NONE_MOSSY_WALL = 0;
public const MOSSY_WALL = 1;
protected $id = self::COBBLESTONE_WALL;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getToolType() : int{
return BlockToolType::TYPE_PICKAXE;
}
@ -49,14 +43,6 @@ class CobblestoneWall extends Transparent{
return 2;
}
public function getName() : string{
if($this->meta === 0x01){
return "Mossy Cobblestone Wall";
}
return "Cobblestone Wall";
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
//walls don't have any special collision boxes like fences do

View File

@ -31,8 +31,8 @@ class Cobweb extends Flowable{
protected $id = self::COBWEB;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function hasEntityCollision() : bool{

View File

@ -23,12 +23,38 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Bearing;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\Player;
class CocoaBlock extends Transparent{
protected $id = self::COCOA_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $facing = Facing::NORTH;
/** @var int */
protected $age = 0;
public function __construct(){
}
protected function writeStateToMeta() : int{
return Bearing::fromFacing(Facing::opposite($this->facing)) | ($this->age << 2);
}
public function readStateFromMeta(int $meta) : void{
$this->facing = Facing::opposite(Bearing::toFacing($meta & 0x03));
$this->age = $meta >> 2;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function getName() : string{

View File

@ -23,21 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\item\TieredTool;
class Concrete extends Solid{
protected $id = Block::CONCRETE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getName() : string{
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Concrete";
}
public function getHardness() : float{
return 1.8;
}

View File

@ -23,21 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\math\Facing;
class ConcretePowder extends Fallable{
protected $id = self::CONCRETE_POWDER;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getName() : string{
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Concrete Powder";
}
public function getHardness() : float{
return 0.5;
}
@ -70,7 +59,7 @@ class ConcretePowder extends Fallable{
continue;
}
if($this->getSide($i) instanceof Water){
return BlockFactory::get(Block::CONCRETE, $this->meta);
return BlockFactory::get(Block::CONCRETE, $this->variant);
}
}

View File

@ -31,8 +31,8 @@ class CraftingTable extends Solid{
protected $id = self::CRAFTING_TABLE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -31,6 +31,24 @@ use pocketmine\Player;
use pocketmine\Server;
abstract class Crops extends Flowable{
/** @var int */
protected $age = 0;
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->age;
}
public function readStateFromMeta(int $meta) : void{
$this->age = $meta;
}
public function getStateBitmask() : int{
return 0b111;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if($blockReplace->getSide(Facing::DOWN)->getId() === Block::FARMLAND){
@ -44,9 +62,9 @@ abstract class Crops extends Flowable{
public function onActivate(Item $item, Player $player = null) : bool{
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
$block = clone $this;
$block->meta += mt_rand(2, 5);
if($block->meta > 7){
$block->meta = 7;
$block->age += mt_rand(2, 5);
if($block->age > 7){
$block->age = 7;
}
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
@ -75,9 +93,9 @@ abstract class Crops extends Flowable{
public function onRandomTick() : void{
if(mt_rand(0, 2) === 1){
if($this->meta < 0x07){
if($this->age < 7){
$block = clone $this;
++$block->meta;
++$block->age;
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
if(!$ev->isCancelled()){

View File

@ -32,8 +32,8 @@ class Dandelion extends Flowable{
protected $id = self::DANDELION;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -25,10 +25,40 @@ namespace pocketmine\block;
class DaylightSensor extends Transparent{
protected $id = self::DAYLIGHT_SENSOR;
protected $itemId = self::DAYLIGHT_SENSOR;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $power = 0;
/** @var bool */
protected $inverted = false;
public function __construct(){
}
public function getId() : int{
return $this->inverted ? self::DAYLIGHT_SENSOR_INVERTED : self::DAYLIGHT_SENSOR;
}
protected function writeStateToMeta() : int{
return $this->power;
}
public function readStateFromMeta(int $meta) : void{
$this->power = $meta;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function isInverted() : bool{
return $this->inverted;
}
public function setInverted(bool $inverted = true) : void{
$this->inverted = $inverted;
}
public function getName() : string{

View File

@ -33,8 +33,8 @@ class DeadBush extends Flowable{
protected $id = self::DEAD_BUSH;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -29,8 +29,8 @@ class Diamond extends Solid{
protected $id = self::DIAMOND_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -31,8 +31,8 @@ class DiamondOre extends Solid{
protected $id = self::DIAMOND_ORE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -28,12 +28,8 @@ use pocketmine\item\Item;
use pocketmine\Player;
class Dirt extends Solid{
protected $id = self::DIRT;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public const NORMAL = 0;
public const COARSE = 1;
public function getHardness() : float{
return 0.5;
@ -43,17 +39,10 @@ class Dirt extends Solid{
return BlockToolType::TYPE_SHOVEL;
}
public function getName() : string{
if($this->meta === 1){
return "Coarse Dirt";
}
return "Dirt";
}
public function onActivate(Item $item, Player $player = null) : bool{
if($item instanceof Hoe){
$item->applyDamage(1);
if($this->meta === 1){
if($this->variant === self::COARSE){
$this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT), true);
}else{
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);

View File

@ -33,41 +33,72 @@ use pocketmine\Player;
abstract class Door extends Transparent{
/** @var int */
protected $facing = Facing::NORTH;
/** @var bool */
protected $top = false;
/** @var bool */
protected $hingeRight = false;
/** @var bool */
protected $open = false;
/** @var bool */
protected $powered = false;
protected function writeStateToMeta() : int{
if($this->top){
return 0x08 | ($this->hingeRight ? 0x01 : 0) | ($this->powered ? 0x02 : 0);
}
return Bearing::rotate(Bearing::fromFacing($this->facing), 1) | ($this->open ? 0x04 : 0);
}
public function readStateFromMeta(int $meta) : void{
$this->top = $meta & 0x08;
if($this->top){
$this->hingeRight = ($meta & 0x01) !== 0;
$this->powered = ($meta & 0x02) !== 0;
}else{
$this->facing = Bearing::toFacing(Bearing::rotate($meta & 0x03, -1));
$this->open = ($meta & 0x04) !== 0;
}
}
public function getStateBitmask() : int{
return 0b1111;
}
/**
* Copies door properties from the other half of the door, since metadata is split between the two halves.
* TODO: the blockstate should be updated directly on creation so these properties can be detected in advance.
*/
private function updateStateFromOtherHalf() : void{
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
if($other instanceof Door and $other->getId() === $this->getId()){
if($this->top){
$this->facing = $other->facing;
$this->open = $other->open;
}else{
$this->hingeRight = $other->hingeRight;
$this->powered = $other->powered;
}
}
}
public function isSolid() : bool{
return false;
}
private function getFullDamage(){
$damage = $this->getDamage();
$isUp = ($damage & 0x08) > 0;
if($isUp){
$down = $this->getSide(Facing::DOWN)->getDamage();
$up = $damage;
}else{
$down = $damage;
$up = $this->getSide(Facing::UP)->getDamage();
}
$isRight = ($up & 0x01) > 0;
return $down & 0x07 | ($isUp ? 8 : 0) | ($isRight ? 0x10 : 0);
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$f = 0.1875;
$damage = $this->getFullDamage();
$this->updateStateFromOtherHalf();
$bb = new AxisAlignedBB(0, 0, 0, 1, 2, 1);
$j = $damage & 0x03;
$isOpen = (($damage & 0x04) > 0);
$isRight = (($damage & 0x10) > 0);
if($j === 0){
if($isOpen){
if(!$isRight){
if($this->facing === Facing::EAST){
if($this->open){
if(!$this->hingeRight){
$bb->setBounds(0, 0, 0, 1, 1, $f);
}else{
$bb->setBounds(0, 0, 1 - $f, 1, 1, 1);
@ -75,9 +106,9 @@ abstract class Door extends Transparent{
}else{
$bb->setBounds(0, 0, 0, $f, 1, 1);
}
}elseif($j === 1){
if($isOpen){
if(!$isRight){
}elseif($this->facing === Facing::SOUTH){
if($this->open){
if(!$this->hingeRight){
$bb->setBounds(1 - $f, 0, 0, 1, 1, 1);
}else{
$bb->setBounds(0, 0, 0, $f, 1, 1);
@ -85,9 +116,9 @@ abstract class Door extends Transparent{
}else{
$bb->setBounds(0, 0, 0, 1, 1, $f);
}
}elseif($j === 2){
if($isOpen){
if(!$isRight){
}elseif($this->facing === Facing::WEST){
if($this->open){
if(!$this->hingeRight){
$bb->setBounds(0, 0, 1 - $f, 1, 1, 1);
}else{
$bb->setBounds(0, 0, 0, 1, 1, $f);
@ -95,9 +126,9 @@ abstract class Door extends Transparent{
}else{
$bb->setBounds(1 - $f, 0, 0, 1, 1, 1);
}
}elseif($j === 3){
if($isOpen){
if(!$isRight){
}elseif($this->facing === Facing::NORTH){
if($this->open){
if(!$this->hingeRight){
$bb->setBounds(0, 0, 0, $f, 1, 1);
}else{
$bb->setBounds(1 - $f, 0, 0, 1, 1, 1);
@ -127,21 +158,22 @@ abstract class Door extends Transparent{
return false;
}
//door faces this way when opened (unless it's right, in which case it's the opposite)
$direction = $player !== null ? Bearing::rotate($player->getDirection(), 1) : Bearing::NORTH;
$facing = Bearing::toFacing($direction);
$next = $this->getSide(Facing::opposite($facing));
$next2 = $this->getSide($facing);
$metaUp = 0x08;
if($next->getId() === $this->getId() or (!$next2->isTransparent() and $next->isTransparent())){ //Door hinge
$metaUp |= 0x01;
if($player !== null){
$this->facing = Bearing::toFacing($player->getDirection());
}
$this->setDamage($direction);
$next = $this->getSide(Facing::rotate($this->facing, Facing::AXIS_Y, false));
$next2 = $this->getSide(Facing::rotate($this->facing, Facing::AXIS_Y, true));
if($next->getId() === $this->getId() or (!$next2->isTransparent() and $next->isTransparent())){ //Door hinge
$this->hingeRight = true;
}
$topHalf = clone $this;
$topHalf->top = true;
parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
$this->getLevel()->setBlock($blockUp, BlockFactory::get($this->getId(), $metaUp), true); //Top
$this->level->setBlock($blockUp, $topHalf, true); //Top
return true;
}
@ -149,31 +181,23 @@ abstract class Door extends Transparent{
}
public function onActivate(Item $item, Player $player = null) : bool{
if(($this->getDamage() & 0x08) === 0x08){ //Top
$down = $this->getSide(Facing::DOWN);
if($down->getId() === $this->getId()){
$meta = $down->getDamage() ^ 0x04;
$this->level->setBlock($down, BlockFactory::get($this->getId(), $meta), true);
$this->level->addSound(new DoorSound($this));
return true;
}
$this->updateStateFromOtherHalf();
$this->open = !$this->open;
return false;
}else{
$this->meta ^= 0x04;
$this->level->setBlock($this, $this, true);
$this->level->addSound(new DoorSound($this));
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
if($other instanceof Door and $this->getId() === $other->getId()){
$other->open = $this->open;
$this->level->setBlock($other, $other, true, true);
}
$this->level->setBlock($this, $this, true, true);
$this->level->addSound(new DoorSound($this));
return true;
}
public function getVariantBitmask() : int{
return 0;
}
public function getDropsForCompatibleTool(Item $item) : array{
if(($this->meta & 0x08) === 0){ //bottom half only
if(!$this->top){ //bottom half only
return parent::getDropsForCompatibleTool($item);
}
@ -185,18 +209,10 @@ abstract class Door extends Transparent{
}
public function getAffectedBlocks() : array{
if(($this->getDamage() & 0x08) === 0x08){
$down = $this->getSide(Facing::DOWN);
if($down->getId() === $this->getId()){
return [$this, $down];
}
}else{
$up = $this->getSide(Facing::UP);
if($up->getId() === $this->getId()){
return [$this, $up];
}
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
if($other->getId() === $this->getId()){
return [$this, $other];
}
return parent::getAffectedBlocks();
}
}

View File

@ -30,35 +30,34 @@ use pocketmine\math\Vector3;
use pocketmine\Player;
class DoublePlant extends Flowable{
public const BITFLAG_TOP = 0x08;
private const BITFLAG_TOP = 0x08;
protected $id = self::DOUBLE_PLANT;
/** @var bool */
protected $top = false;
public function __construct(int $meta = 0){
$this->setDamage($meta);
protected function writeStateToMeta() : int{
return ($this->top ? self::BITFLAG_TOP : 0);
}
public function readStateFromMeta(int $meta) : void{
$this->top = ($meta & self::BITFLAG_TOP) !== 0;
}
public function getStateBitmask() : int{
return 0b1000;
}
public function canBeReplaced() : bool{
return $this->meta === 2 or $this->meta === 3; //grass or fern
}
public function getName() : string{
static $names = [
0 => "Sunflower",
1 => "Lilac",
2 => "Double Tallgrass",
3 => "Large Fern",
4 => "Rose Bush",
5 => "Peony"
];
return $names[$this->getVariant()] ?? "";
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()){
$this->getLevel()->setBlock($blockReplace, $this, false, false);
$this->getLevel()->setBlock($blockReplace->getSide(Facing::UP), BlockFactory::get($this->id, $this->meta | self::BITFLAG_TOP), false, false);
$top = clone $this;
$top->top = true;
$this->getLevel()->setBlock($blockReplace->getSide(Facing::UP), $top, false, false);
return true;
}
@ -71,39 +70,32 @@ class DoublePlant extends Flowable{
* @return bool
*/
public function isValidHalfPlant() : bool{
if($this->meta & self::BITFLAG_TOP){
$other = $this->getSide(Facing::DOWN);
}else{
$other = $this->getSide(Facing::UP);
}
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
return (
$other instanceof DoublePlant and
$other->getId() === $this->getId() and
$other->getVariant() === $this->getVariant() and
($other->getDamage() & self::BITFLAG_TOP) !== ($this->getDamage() & self::BITFLAG_TOP)
$other->getVariant() === $this->variant and
$other->top !== $this->top
);
}
public function onNearbyBlockChange() : void{
if(!$this->isValidHalfPlant() or (($this->meta & self::BITFLAG_TOP) === 0 and $this->getSide(Facing::DOWN)->isTransparent())){
if(!$this->isValidHalfPlant() or (!$this->top and $this->getSide(Facing::DOWN)->isTransparent())){
$this->getLevel()->useBreakOn($this);
}
}
public function getVariantBitmask() : int{
return 0x07;
}
public function getToolType() : int{
return ($this->meta === 2 or $this->meta === 3) ? BlockToolType::TYPE_SHEARS : BlockToolType::TYPE_NONE;
return ($this->variant === 2 or $this->variant === 3) ? BlockToolType::TYPE_SHEARS : BlockToolType::TYPE_NONE;
}
public function getToolHarvestLevel() : int{
return ($this->meta === 2 or $this->meta === 3) ? 1 : 0; //only grass or fern require shears
return ($this->variant === 2 or $this->variant === 3) ? 1 : 0; //only grass or fern require shears
}
public function getDrops(Item $item) : array{
if($this->meta & self::BITFLAG_TOP){
if($this->top){
if($this->isCompatibleWithTool($item)){
return parent::getDrops($item);
}
@ -120,7 +112,7 @@ class DoublePlant extends Flowable{
public function getAffectedBlocks() : array{
if($this->isValidHalfPlant()){
return [$this, $this->getSide(($this->meta & self::BITFLAG_TOP) !== 0 ? Facing::DOWN : Facing::UP)];
return [$this, $this->getSide($this->top ? Facing::DOWN : Facing::UP)];
}
return parent::getAffectedBlocks();

View File

@ -26,21 +26,46 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
abstract class DoubleSlab extends Solid{
class DoubleSlab extends Solid{
/** @var int */
protected $singleId;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(int $id, int $singleId, int $variant = 0){
parent::__construct($id, $variant);
$this->singleId = $singleId;
}
abstract public function getSlabId() : int;
protected function getSingle() : Block{
return BlockFactory::get($this->singleId, $this->variant);
}
public function getHardness() : float{
return $this->getSingle()->getHardness();
}
public function getToolType() : int{
return $this->getSingle()->getToolType();
}
public function getToolHarvestLevel() : int{
return $this->getSingle()->getToolHarvestLevel();
}
public function getFlameEncouragement() : int{
return $this->getSingle()->getFlameEncouragement();
}
public function getFlammability() : int{
return $this->getSingle()->getFlammability();
}
public function getName() : string{
return "Double " . BlockFactory::get($this->getSlabId(), $this->getVariant())->getName();
return "Double " . $this->getSingle()->getName();
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get($this->getSlabId(), $this->getVariant(), 2)
ItemFactory::get($this->singleId, $this->variant, 2)
];
}

View File

@ -1,47 +0,0 @@
<?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\TieredTool;
class DoubleStoneSlab extends DoubleSlab{
protected $id = self::DOUBLE_STONE_SLAB;
public function getSlabId() : int{
return self::STONE_SLAB;
}
public function getHardness() : float{
return 2;
}
public function getToolType() : int{
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
}

View File

@ -1,33 +0,0 @@
<?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;
class DoubleStoneSlab2 extends DoubleStoneSlab{
protected $id = self::DOUBLE_STONE_SLAB2;
public function getSlabId() : int{
return self::STONE_SLAB2;
}
}

View File

@ -1,49 +0,0 @@
<?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;
class DoubleWoodenSlab extends DoubleSlab{
protected $id = self::DOUBLE_WOODEN_SLAB;
public function getSlabId() : int{
return self::WOODEN_SLAB;
}
public function getHardness() : float{
return 2;
}
public function getToolType() : int{
return BlockToolType::TYPE_AXE;
}
public function getFlameEncouragement() : int{
return 5;
}
public function getFlammability() : int{
return 20;
}
}

View File

@ -29,8 +29,8 @@ class Emerald extends Solid{
protected $id = self::EMERALD_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -31,8 +31,8 @@ class EmeraldOre extends Solid{
protected $id = self::EMERALD_ORE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -35,8 +35,8 @@ class EnchantingTable extends Transparent{
protected $id = self::ENCHANTING_TABLE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{

View File

@ -25,13 +25,35 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Bearing;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\Player;
class EndPortalFrame extends Solid{
protected $id = self::END_PORTAL_FRAME;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $facing = Facing::NORTH;
/** @var bool */
protected $eye = false;
public function __construct(){
}
protected function writeStateToMeta() : int{
return Bearing::fromFacing($this->facing) | ($this->eye ? 0x04 : 0);
}
public function readStateFromMeta(int $meta) : void{
$this->facing = Bearing::toFacing($meta & 0x03);
$this->eye = ($meta & 0x04) !== 0;
}
public function getStateBitmask() : int{
return 0b111;
}
public function getLightLevel() : int{
@ -55,14 +77,20 @@ class EndPortalFrame extends Solid{
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
0,
0,
0,
1,
(($this->getDamage() & 0x04) > 0 ? 1 : 0.8125),
$this->eye ? 1 : 0.8125,
1
);
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if($player !== null){
$this->facing = Bearing::toFacing(Bearing::opposite($player->getDirection()));
}
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -33,8 +33,30 @@ class EndRod extends Flowable{
protected $id = Block::END_ROD;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $facing = Facing::DOWN;
public function __construct(){
}
protected function writeStateToMeta() : int{
if(Facing::axis($this->facing) === Facing::AXIS_Y){
return $this->facing;
}
return $this->facing ^ 1; //TODO: in PC this is always the same as facing, just PE is stupid
}
public function readStateFromMeta(int $meta) : void{
if($meta === 0 or $meta === 1){
$this->facing = $meta;
}else{
$this->facing = $meta ^ 1; //TODO: see above
}
}
public function getStateBitmask() : int{
return 0b111;
}
public function getName() : string{
@ -42,13 +64,9 @@ class EndRod extends Flowable{
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if(Facing::axis($face) === Facing::AXIS_Y){
$this->meta = $face;
}else{
$this->meta = $face ^ 0x01;
}
if($blockClicked instanceof EndRod and $blockClicked->getDamage() === $this->meta){
$this->meta ^= 0x01;
$this->facing = $face;
if($blockClicked instanceof EndRod and $blockClicked->facing === $this->facing){
$this->facing = Facing::opposite($face);
}
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
@ -63,7 +81,7 @@ class EndRod extends Flowable{
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$m = $this->meta >> 1; //everything except up/down are inverted, but we can still use this for axis
$m = Facing::axis($this->facing);
$width = 0.375;
switch($m){
@ -98,8 +116,4 @@ class EndRod extends Flowable{
return null;
}
public function getVariantBitmask() : int{
return 0;
}
}

View File

@ -29,8 +29,8 @@ class EndStone extends Solid{
protected $id = self::END_STONE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -29,8 +29,8 @@ class EndStoneBricks extends Solid{
protected $id = self::END_BRICKS;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -62,8 +62,8 @@ class EnderChest extends Chest{
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if($player !== null){
$this->meta = Bearing::toFacing(Bearing::opposite($player->getDirection()));
if($player !== null){ //same as normal chest - TODO: clean up inheritance here
$this->facing = Bearing::toFacing(Bearing::opposite($player->getDirection()));
}
if(Block::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){

View File

@ -32,8 +32,23 @@ class Farmland extends Transparent{
protected $id = self::FARMLAND;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $wetness = 0; //"moisture" blockstate property in PC
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->wetness;
}
public function readStateFromMeta(int $meta) : void{
$this->wetness = $meta;
}
public function getStateBitmask() : int{
return 0b111;
}
public function getName() : string{
@ -64,14 +79,14 @@ class Farmland extends Transparent{
public function onRandomTick() : void{
if(!$this->canHydrate()){
if($this->meta > 0){
$this->meta--;
if($this->wetness > 0){
$this->wetness--;
$this->level->setBlock($this, $this, false, false);
}else{
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), false, true);
}
}elseif($this->meta < 7){
$this->meta = 7;
}elseif($this->wetness < 7){
$this->wetness = 7;
$this->level->setBlock($this, $this, false, false);
}
}

View File

@ -28,10 +28,6 @@ use pocketmine\math\Facing;
abstract class Fence extends Transparent{
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getThickness() : float{
return 0.25;
}

View File

@ -26,10 +26,29 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\sound\DoorSound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Bearing;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\Player;
class FenceGate extends Transparent{
/** @var bool */
protected $open = false;
/** @var int */
protected $facing = Facing::NORTH;
protected function writeStateToMeta() : int{
return Bearing::fromFacing($this->facing) | ($this->open ? 0x04 : 0);
}
public function readStateFromMeta(int $meta) : void{
$this->facing = Bearing::toFacing($meta & 0x03);
$this->open = ($meta & 0x04) !== 0;
}
public function getStateBitmask() : int{
return 0b111;
}
public function getHardness() : float{
return 2;
@ -41,12 +60,11 @@ class FenceGate extends Transparent{
protected function recalculateBoundingBox() : ?AxisAlignedBB{
if(($this->getDamage() & 0x04) > 0){
if($this->open){
return null;
}
$i = ($this->getDamage() & 0x03);
if($i === 2 or $i === 0){
if(Facing::axis($this->facing) === Facing::AXIS_Z){
return new AxisAlignedBB(
0,
0,
@ -69,21 +87,19 @@ class FenceGate extends Transparent{
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if($player !== null){
$this->meta = $player->getDirection();
$this->facing = Bearing::toFacing($player->getDirection());
}
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function getVariantBitmask() : int{
return 0;
}
public function onActivate(Item $item, Player $player = null) : bool{
$this->meta = (($this->meta ^ 0x04) & ~0x02);
if($player !== null){
$this->meta |= ($player->getDirection() & 0x02); //open towards the player, retaining axis
$this->open = !$this->open;
if($this->open and $player !== null){
$playerFacing = Bearing::toFacing($player->getDirection());
if($playerFacing === Facing::opposite($this->facing)){
$this->facing = $playerFacing;
}
}
$this->getLevel()->setBlock($this, $this, true);

View File

@ -37,8 +37,23 @@ class Fire extends Flowable{
protected $id = self::FIRE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $age = 0;
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->age;
}
public function readStateFromMeta(int $meta) : void{
$this->age = $meta;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function hasEntityCollision() : bool{
@ -95,22 +110,22 @@ class Fire extends Flowable{
$down = $this->getSide(Facing::DOWN);
$result = null;
if($this->meta < 15 and mt_rand(0, 2) === 0){
$this->meta++;
if($this->age < 15 and mt_rand(0, 2) === 0){
$this->age++;
$result = $this;
}
$canSpread = true;
if(!$down->burnsForever()){
//TODO: check rain
if($this->meta === 15){
if($this->age === 15){
if(!$down->isFlammable() and mt_rand(0, 3) === 3){ //1/4 chance to extinguish
$canSpread = false;
$result = BlockFactory::get(Block::AIR);
}
}elseif(!$this->hasAdjacentFlammableBlocks()){
$canSpread = false;
if(!$down->isSolid() or $this->meta > 3){ //fire older than 3, or without a solid block below
if(!$down->isSolid() or $this->age > 3){
$result = BlockFactory::get(Block::AIR);
}
}
@ -157,8 +172,10 @@ class Fire extends Flowable{
if(!$ev->isCancelled()){
$block->onIncinerate();
if(mt_rand(0, $this->meta + 9) < 5){ //TODO: check rain
$this->level->setBlock($block, BlockFactory::get(Block::FIRE, min(15, $this->meta + (mt_rand(0, 4) >> 2))));
if(mt_rand(0, $this->age + 9) < 5){ //TODO: check rain
$fire = clone $this;
$fire->age = min(15, $fire->age + (mt_rand(0, 4) >> 2));
$this->level->setBlock($block, $fire);
}else{
$this->level->setBlock($block, BlockFactory::get(Block::AIR));
}

View File

@ -39,27 +39,6 @@ class Flower extends Flowable{
public const TYPE_PINK_TULIP = 7;
public const TYPE_OXEYE_DAISY = 8;
protected $id = self::RED_FLOWER;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getName() : string{
static $names = [
self::TYPE_POPPY => "Poppy",
self::TYPE_BLUE_ORCHID => "Blue Orchid",
self::TYPE_ALLIUM => "Allium",
self::TYPE_AZURE_BLUET => "Azure Bluet",
self::TYPE_RED_TULIP => "Red Tulip",
self::TYPE_ORANGE_TULIP => "Orange Tulip",
self::TYPE_WHITE_TULIP => "White Tulip",
self::TYPE_PINK_TULIP => "Pink Tulip",
self::TYPE_OXEYE_DAISY => "Oxeye Daisy"
];
return $names[$this->meta] ?? "Unknown";
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
$down = $this->getSide(Facing::DOWN);
if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){

View File

@ -33,14 +33,26 @@ use pocketmine\tile\Tile;
class FlowerPot extends Flowable{
public const STATE_EMPTY = 0;
public const STATE_FULL = 1;
protected $id = self::FLOWER_POT_BLOCK;
protected $itemId = Item::FLOWER_POT;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var bool */
protected $occupied = false;
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->occupied ? 1 : 0;
}
public function readStateFromMeta(int $meta) : void{
$this->occupied = $meta !== 0;
}
public function getStateBitmask() : int{
return 0b1111; //vanilla uses various values, we only care about 1 and 0 for PE
}
public function getName() : string{
@ -80,17 +92,13 @@ class FlowerPot extends Flowable{
return true;
}
$this->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item.
$this->occupied = true;
$this->getLevel()->setBlock($this, $this, true, false);
$pot->setItem($item->pop());
return true;
}
public function getVariantBitmask() : int{
return 0;
}
public function getDropsForCompatibleTool(Item $item) : array{
$items = parent::getDropsForCompatibleTool($item);

View File

@ -23,16 +23,98 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use pocketmine\math\Bearing;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\Furnace as TileFurnace;
use pocketmine\tile\Tile;
class Furnace extends BurningFurnace{
class Furnace extends Solid{
protected $id = self::FURNACE;
protected $itemId = self::FURNACE;
/** @var int */
protected $facing = Facing::NORTH;
/** @var bool */
protected $lit = false; //this is set based on the blockID
public function __construct(){
}
public function getId() : int{
return $this->lit ? Block::BURNING_FURNACE : Block::FURNACE;
}
protected function writeStateToMeta() : int{
return $this->facing;
}
public function readStateFromMeta(int $meta) : void{
$this->facing = $meta;
}
public function getStateBitmask() : int{
return 0b111;
}
public function getName() : string{
return "Furnace";
}
public function getHardness() : float{
return 3.5;
}
public function getToolType() : int{
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getLightLevel() : int{
return 0;
return $this->lit ? 13 : 0;
}
public function isLit() : bool{
return $this->lit;
}
public function setLit(bool $lit = true) : void{
$this->lit = $lit;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if($player !== null){
$this->facing = Bearing::toFacing(Bearing::opposite($player->getDirection()));
}
if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));
return true;
}
return false;
}
public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){
$furnace = $this->getLevel()->getTile($this);
if(!($furnace instanceof TileFurnace)){
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
}
if(!$furnace->canOpenWith($item->getCustomName())){
return true;
}
$player->addWindow($furnace->getInventory());
}
return true;
}
}

View File

@ -27,16 +27,6 @@ use pocketmine\item\Item;
class Glass extends Transparent{
protected $id = self::GLASS;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getName() : string{
return "Glass";
}
public function getHardness() : float{
return 0.3;
}

View File

@ -27,16 +27,6 @@ use pocketmine\item\Item;
class GlassPane extends Thin{
protected $id = self::GLASS_PANE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getName() : string{
return "Glass Pane";
}
public function getHardness() : float{
return 0.3;
}

View File

@ -27,11 +27,27 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use pocketmine\math\Bearing;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\Player;
class GlazedTerracotta extends Solid{
/** @var int */
protected $facing = Facing::NORTH;
protected function writeStateToMeta() : int{
return $this->facing;
}
public function readStateFromMeta(int $meta) : void{
$this->facing = $meta;
}
public function getStateBitmask() : int{
return 0b111;
}
public function getHardness() : float{
return 1.4;
}
@ -46,13 +62,9 @@ class GlazedTerracotta extends Solid{
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if($player !== null){
$this->meta = Bearing::toFacing(Bearing::opposite($player->getDirection()));
$this->facing = Bearing::toFacing(Bearing::opposite($player->getDirection()));
}
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function getVariantBitmask() : int{
return 0;
}
}

View File

@ -30,8 +30,8 @@ class GlowingObsidian extends Solid{
protected $id = self::GLOWING_OBSIDIAN;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -1,58 +0,0 @@
<?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\Player;
class GlowingRedstoneOre extends RedstoneOre{
protected $id = self::GLOWING_REDSTONE_ORE;
protected $itemId = self::REDSTONE_ORE;
public function getName() : string{
return "Glowing Redstone Ore";
}
public function getLightLevel() : int{
return 9;
}
public function onActivate(Item $item, Player $player = null) : bool{
return false;
}
public function onNearbyBlockChange() : void{
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
$this->getLevel()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false);
}
}

View File

@ -30,8 +30,8 @@ class Glowstone extends Transparent{
protected $id = self::GLOWSTONE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -29,8 +29,8 @@ class Gold extends Solid{
protected $id = self::GOLD_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -29,8 +29,8 @@ class GoldOre extends Solid{
protected $id = self::GOLD_ORE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -37,8 +37,8 @@ class Grass extends Solid{
protected $id = self::GRASS;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -32,8 +32,8 @@ class GrassPath extends Transparent{
protected $id = self::GRASS_PATH;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -30,8 +30,8 @@ class Gravel extends Fallable{
protected $id = self::GRAVEL;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -27,16 +27,6 @@ use pocketmine\item\TieredTool;
class HardenedClay extends Solid{
protected $id = self::HARDENED_CLAY;
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function getName() : string{
return "Hardened Clay";
}
public function getToolType() : int{
return BlockToolType::TYPE_PICKAXE;
}

View File

@ -23,17 +23,19 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\PillarRotationHelper;
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;
protected $id = self::HAY_BALE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{
@ -45,14 +47,10 @@ class HayBale extends Solid{
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
$this->axis = Facing::axis($face);
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function getVariantBitmask() : int{
return 0x03;
}
public function getFlameEncouragement() : int{
return 60;
}

View File

@ -31,8 +31,8 @@ class Ice extends Transparent{
protected $id = self::ICE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -29,8 +29,8 @@ class Iron extends Solid{
protected $id = self::IRON_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -29,8 +29,8 @@ class IronBars extends Thin{
protected $id = self::IRON_BARS;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{
@ -48,8 +48,4 @@ class IronBars extends Thin{
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getVariantBitmask() : int{
return 0;
}
}

View File

@ -32,8 +32,8 @@ class IronDoor extends Door{
protected $itemId = Item::IRON_DOOR;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -29,8 +29,8 @@ class IronOre extends Solid{
protected $id = self::IRON_ORE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -35,8 +35,23 @@ class ItemFrame extends Flowable{
protected $itemId = Item::ITEM_FRAME;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $facing = Facing::NORTH;
public function __construct(){
}
protected function writeStateToMeta() : int{
return 5 - $this->facing;
}
public function readStateFromMeta(int $meta) : void{
$this->facing = 5 - $meta;
}
public function getStateBitmask() : int{
return 0b11;
}
public function getName() : string{
@ -59,7 +74,7 @@ class ItemFrame extends Flowable{
}
public function onNearbyBlockChange() : void{
if(!$this->getSide(Facing::opposite(5 - $this->meta))->isSolid()){
if(!$this->getSide(Facing::opposite($this->facing))->isSolid()){
$this->level->useBreakOn($this);
}
}
@ -69,7 +84,7 @@ class ItemFrame extends Flowable{
return false;
}
$this->meta = 5 - $face;
$this->facing = $face;
if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player));
@ -80,10 +95,6 @@ class ItemFrame extends Flowable{
}
public function getVariantBitmask() : int{
return 0;
}
public function getDropsForCompatibleTool(Item $item) : array{
$drops = parent::getDropsForCompatibleTool($item);

View File

@ -34,8 +34,23 @@ class Ladder extends Transparent{
protected $id = self::LADDER;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $facing = Facing::NORTH;
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->facing;
}
public function readStateFromMeta(int $meta) : void{
$this->facing = $meta;
}
public function getStateBitmask() : int{
return 0b111;
}
public function getName() : string{
@ -69,13 +84,13 @@ class Ladder extends Transparent{
$minX = $minZ = 0;
$maxX = $maxZ = 1;
if($this->meta === 2){
if($this->facing === Facing::NORTH){
$minZ = 1 - $f;
}elseif($this->meta === 3){
}elseif($this->facing === Facing::SOUTH){
$maxZ = $f;
}elseif($this->meta === 4){
}elseif($this->facing === Facing::WEST){
$minX = 1 - $f;
}elseif($this->meta === 5){
}elseif($this->facing === Facing::EAST){
$maxX = $f;
}
@ -92,7 +107,7 @@ class Ladder extends Transparent{
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if(!$blockClicked->isTransparent() and Facing::axis($face) !== Facing::AXIS_Y){
$this->meta = $face;
$this->facing = $face;
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
@ -100,7 +115,7 @@ class Ladder extends Transparent{
}
public function onNearbyBlockChange() : void{
if(!$this->getSide($this->meta ^ 0x01)->isSolid()){ //Replace with common break method
if(!$this->getSide(Facing::opposite($this->facing))->isSolid()){ //Replace with common break method
$this->level->useBreakOn($this);
}
}
@ -108,8 +123,4 @@ class Ladder extends Transparent{
public function getToolType() : int{
return BlockToolType::TYPE_AXE;
}
public function getVariantBitmask() : int{
return 0;
}
}

View File

@ -29,8 +29,8 @@ class Lapis extends Solid{
protected $id = self::LAPIS_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -31,8 +31,8 @@ class LapisOre extends Solid{
protected $id = self::LAPIS_ORE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -35,8 +35,8 @@ class Lava extends Liquid{
protected $id = self::FLOWING_LAVA;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getLightLevel() : int{
@ -48,11 +48,11 @@ class Lava extends Liquid{
}
public function getStillForm() : Block{
return BlockFactory::get(Block::STILL_LAVA, $this->meta);
return BlockFactory::get(Block::STILL_LAVA, $this->getDamage());
}
public function getFlowingForm() : Block{
return BlockFactory::get(Block::FLOWING_LAVA, $this->meta);
return BlockFactory::get(Block::FLOWING_LAVA, $this->getDamage());
}
public function getBucketFillSound() : int{
@ -85,19 +85,19 @@ class Lava extends Liquid{
}
if($colliding !== null){
if($this->getDamage() === 0){
if($this->decay === 0){
$this->liquidCollide($colliding, BlockFactory::get(Block::OBSIDIAN));
}elseif($this->getDamage() <= 4){
}elseif($this->decay <= 4){
$this->liquidCollide($colliding, BlockFactory::get(Block::COBBLESTONE));
}
}
}
protected function flowIntoBlock(Block $block, int $newFlowDecay) : void{
protected function flowIntoBlock(Block $block, int $newFlowDecay, bool $falling) : void{
if($block instanceof Water){
$block->liquidCollide($this, BlockFactory::get(Block::STONE));
}else{
parent::flowIntoBlock($block, $newFlowDecay);
parent::flowIntoBlock($block, $newFlowDecay, $falling);
}
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\WoodType;
use pocketmine\event\block\LeavesDecayEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
@ -32,17 +33,30 @@ use pocketmine\math\Vector3;
use pocketmine\Player;
class Leaves extends Transparent{
public const OAK = 0;
public const SPRUCE = 1;
public const BIRCH = 2;
public const JUNGLE = 3;
public const ACACIA = 0;
public const DARK_OAK = 1;
/** @var int */
protected $woodType;
protected $id = self::LEAVES;
/** @var bool */
protected $noDecay = false;
/** @var bool */
protected $checkDecay = false;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(int $id, int $variant, int $woodType, ?string $name = null){
parent::__construct($id, $variant, $name);
$this->woodType = $woodType;
}
protected function writeStateToMeta() : int{
return ($this->noDecay ? 0x04 : 0) | ($this->checkDecay ? 0x08 : 0);
}
public function readStateFromMeta(int $meta) : void{
$this->noDecay = ($meta & 0x04) !== 0;
$this->checkDecay = ($meta & 0x08) !== 0;
}
public function getStateBitmask() : int{
return 0b1100;
}
public function getHardness() : float{
@ -53,16 +67,6 @@ class Leaves extends Transparent{
return BlockToolType::TYPE_SHEARS;
}
public function getName() : string{
static $names = [
self::OAK => "Oak Leaves",
self::SPRUCE => "Spruce Leaves",
self::BIRCH => "Birch Leaves",
self::JUNGLE => "Jungle Leaves"
];
return $names[$this->getVariant()];
}
public function diffusesSkyLight() : bool{
return true;
}
@ -80,7 +84,7 @@ class Leaves extends Transparent{
return true;
}
if($pos->getId() === $this->id and $distance <= 4){
if($pos->getId() === $this->getId() and $distance <= 4){
foreach(Facing::ALL as $side){
if($this->findLog($pos->getSide($side), $visited, $distance + 1)){
return true;
@ -92,8 +96,8 @@ class Leaves extends Transparent{
}
public function onNearbyBlockChange() : void{
if(($this->meta & 0b00001100) === 0){
$this->meta |= 0x08;
if(!$this->noDecay and !$this->checkDecay){
$this->checkDecay = true;
$this->getLevel()->setBlock($this, $this, true, false);
}
}
@ -103,9 +107,7 @@ class Leaves extends Transparent{
}
public function onRandomTick() : void{
if(($this->meta & 0b00001100) === 0x08){
$this->meta &= 0x03;
if(!$this->noDecay and $this->checkDecay){
$this->getLevel()->getServer()->getPluginManager()->callEvent($ev = new LeavesDecayEvent($this));
if($ev->isCancelled() or $this->findLog($this)){
@ -117,14 +119,10 @@ class Leaves extends Transparent{
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
$this->meta |= 0x04;
$this->noDecay = true; //artificial leaves don't decay
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function getVariantBitmask() : int{
return 0x03;
}
public function getDrops(Item $item) : array{
if($item->getBlockToolType() & BlockToolType::TYPE_SHEARS){
return $this->getDropsForCompatibleTool($item);
@ -132,23 +130,15 @@ class Leaves extends Transparent{
$drops = [];
if(mt_rand(1, 20) === 1){ //Saplings
$drops[] = $this->getSaplingItem();
$drops[] = ItemFactory::get(Item::SAPLING, $this->woodType);
}
if($this->canDropApples() and mt_rand(1, 200) === 1){ //Apples
if(($this->woodType === WoodType::OAK or $this->woodType === WoodType::DARK_OAK) and mt_rand(1, 200) === 1){ //Apples
$drops[] = ItemFactory::get(Item::APPLE);
}
return $drops;
}
public function getSaplingItem() : Item{
return ItemFactory::get(Item::SAPLING, $this->getVariant());
}
public function canDropApples() : bool{
return $this->meta === self::OAK;
}
public function getFlameEncouragement() : int{
return 30;
}

View File

@ -1,48 +0,0 @@
<?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 Leaves2 extends Leaves{
protected $id = self::LEAVES2;
public function getName() : string{
static $names = [
self::ACACIA => "Acacia Leaves",
self::DARK_OAK => "Dark Oak Leaves"
];
return $names[$this->getVariant()] ?? "Unknown";
}
public function getSaplingItem() : Item{
return ItemFactory::get(Item::SAPLING, $this->getVariant() + 4);
}
public function canDropApples() : bool{
return $this->meta === self::DARK_OAK;
}
}

View File

@ -30,11 +30,52 @@ use pocketmine\math\Vector3;
use pocketmine\Player;
class Lever extends Flowable{
protected const BOTTOM = 0;
protected const SIDE = 1;
protected const TOP = 2;
protected $id = self::LEVER;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $position = self::BOTTOM;
/** @var int */
protected $facing = Facing::NORTH;
/** @var bool */
protected $powered = false;
public function __construct(){
}
protected function writeStateToMeta() : int{
if($this->position === self::BOTTOM){
$rotationMeta = Facing::axis($this->facing) === Facing::AXIS_Z ? 7 : 0;
}elseif($this->position === self::TOP){
$rotationMeta = Facing::axis($this->facing) === Facing::AXIS_Z ? 5 : 6;
}else{
$rotationMeta = 6 - $this->facing;
}
return $rotationMeta | ($this->powered ? 0x08 : 0);
}
public function readStateFromMeta(int $meta) : void{
$rotationMeta = $meta & 0x07;
if($rotationMeta === 5 or $rotationMeta === 6){
$this->position = self::TOP;
$this->facing = $rotationMeta === 5 ? Facing::SOUTH : Facing::EAST;
}elseif($rotationMeta === 7 or $rotationMeta === 0){
$this->position = self::BOTTOM;
$this->facing = $rotationMeta === 7 ? Facing::SOUTH : Facing::EAST;
}else{
$this->position = self::SIDE;
$this->facing = 6 - $rotationMeta;
}
$this->powered = ($meta & 0x08) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function getName() : string{
@ -45,49 +86,34 @@ class Lever extends Flowable{
return 0.5;
}
public function getVariantBitmask() : int{
return 0;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if(!$blockClicked->isSolid()){
return false;
}
if($face === Facing::DOWN){
$this->meta = 0;
}else{
$this->meta = 6 - $face;
}
if($player !== null){
$bearing = $player->getDirection();
if($bearing === Bearing::EAST or $bearing === Bearing::WEST){
if($face === Facing::UP){
$this->meta = 6;
}
}else{
if($face === Facing::DOWN){
$this->meta = 7;
}
if(Facing::axis($face) === Facing::AXIS_Y){
if($player !== null){
$this->facing = Bearing::toFacing(Bearing::opposite($player->getDirection()));
}
$this->position = $face === Facing::DOWN ? self::BOTTOM : self::TOP;
}else{
$this->facing = $face;
$this->position = self::SIDE;
}
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
static $faces = [
0 => Facing::UP,
1 => Facing::WEST,
2 => Facing::EAST,
3 => Facing::NORTH,
4 => Facing::SOUTH,
5 => Facing::DOWN,
6 => Facing::DOWN,
7 => Facing::UP
];
if(!$this->getSide($faces[$this->meta & 0x07])->isSolid()){
if($this->position === self::BOTTOM){
$face = Facing::UP;
}elseif($this->position === self::TOP){
$face = Facing::DOWN;
}else{
$face = Facing::opposite($this->facing);
}
if(!$this->getSide($face)->isSolid()){
$this->level->useBreakOn($this);
}
}

View File

@ -44,6 +44,24 @@ abstract class Liquid extends Transparent{
private const CAN_FLOW = 0;
private const BLOCKED = -1;
/** @var bool */
protected $falling = false;
/** @var int */
protected $decay = 0; //PC "level" property
protected function writeStateToMeta() : int{
return $this->decay | ($this->falling ? 0x08 : 0);
}
public function readStateFromMeta(int $meta) : void{
$this->decay = $meta & 0x07;
$this->falling = ($meta & 0x08) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function hasEntityCollision() : bool{
return true;
}
@ -84,35 +102,20 @@ abstract class Liquid extends Transparent{
abstract public function getBucketEmptySound() : int;
public function getFluidHeightPercent(){
$d = $this->meta;
if($d >= 8){
$d = 0;
}
return ($d + 1) / 9;
public function isSource() : bool{
return !$this->falling and $this->decay === 0;
}
protected function getFlowDecay(Block $block) : int{
if($block->getId() !== $this->getId()){
return -1;
}
return $block->getDamage();
public function getFluidHeightPercent(){
return (($this->falling ? 0 : $this->decay) + 1) / 9;
}
protected function getEffectiveFlowDecay(Block $block) : int{
if($block->getId() !== $this->getId()){
if(!($block instanceof Liquid) or $block->getId() !== $this->getId()){
return -1;
}
$decay = $block->getDamage();
if($decay >= 8){
$decay = 0;
}
return $decay;
return $block->falling ? 0 : $block->decay;
}
public function clearCaches() : void{
@ -170,7 +173,7 @@ abstract class Liquid extends Transparent{
}
}
if($this->getDamage() >= 8){
if($this->falling){
if(
!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y, $this->z - 1)) or
!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y, $this->z + 1)) or
@ -214,10 +217,9 @@ abstract class Liquid extends Transparent{
}
public function onScheduledUpdate() : void{
$decay = $this->getFlowDecay($this);
$multiplier = $this->getFlowDecayPerBlock();
if($decay > 0){
if(!$this->isSource()){
$smallestFlowDecay = -100;
$this->adjacentSources = 0;
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $smallestFlowDecay);
@ -226,80 +228,81 @@ abstract class Liquid extends Transparent{
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $smallestFlowDecay);
$newDecay = $smallestFlowDecay + $multiplier;
$falling = false;
if($newDecay >= 8 or $smallestFlowDecay < 0){
$newDecay = -1;
}
if(($topFlowDecay = $this->getFlowDecay($this->level->getBlockAt($this->x, $this->y + 1, $this->z))) >= 0){
$newDecay = $topFlowDecay | 0x08;
if($this->getEffectiveFlowDecay($this->level->getBlockAt($this->x, $this->y + 1, $this->z)) >= 0){
$falling = true;
}
if($this->adjacentSources >= 2 and $this instanceof Water){
$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
if($bottomBlock->isSolid()){
$newDecay = 0;
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
if($bottomBlock->isSolid() or ($bottomBlock instanceof Water and $bottomBlock->isSource())){
$newDecay = 0;
$falling = false;
}
}
if($newDecay !== $decay){
$decay = $newDecay;
if($decay < 0){
if($newDecay !== $this->decay or $falling !== $this->falling){
if(!$falling and $newDecay < 0){
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true, true);
}else{
$this->level->setBlock($this, BlockFactory::get($this->id, $decay), true, true);
$this->level->scheduleDelayedBlockUpdate($this, $this->tickRate());
return;
}
$this->falling = $falling;
$this->decay = $falling ? 0 : $newDecay;
$this->level->setBlock($this, $this, true, true); //local block update will cause an update to be scheduled
}
}
$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
$this->flowIntoBlock($bottomBlock, 0, true);
if($this->isSource() or !$bottomBlock->canBeFlowedInto()){
if($this->falling){
$adjacentDecay = 1; //falling liquid behaves like source block
}else{
$adjacentDecay = $this->decay + $multiplier;
}
if($adjacentDecay < 8){
$flags = $this->getOptimalFlowDirections();
if($flags[0]){
$this->flowIntoBlock($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $adjacentDecay, false);
}
if($flags[1]){
$this->flowIntoBlock($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $adjacentDecay, false);
}
if($flags[2]){
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $adjacentDecay, false);
}
if($flags[3]){
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $adjacentDecay, false);
}
}
}
if($decay >= 0){
$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
$this->flowIntoBlock($bottomBlock, $decay | 0x08);
if($decay === 0 or !$bottomBlock->canBeFlowedInto()){
if($decay >= 8){
$adjacentDecay = 1;
}else{
$adjacentDecay = $decay + $multiplier;
}
if($adjacentDecay < 8){
$flags = $this->getOptimalFlowDirections();
if($flags[0]){
$this->flowIntoBlock($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $adjacentDecay);
}
if($flags[1]){
$this->flowIntoBlock($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $adjacentDecay);
}
if($flags[2]){
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $adjacentDecay);
}
if($flags[3]){
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $adjacentDecay);
}
}
}
$this->checkForHarden();
}
$this->checkForHarden();
}
protected function flowIntoBlock(Block $block, int $newFlowDecay) : void{
protected function flowIntoBlock(Block $block, int $newFlowDecay, bool $falling) : void{
if($this->canFlowInto($block) and !($block instanceof Liquid)){
if($block->getId() > 0){
$this->level->useBreakOn($block);
}
$this->level->setBlock($block, BlockFactory::get($this->getId(), $newFlowDecay), true, true);
$this->level->scheduleDelayedBlockUpdate($block, $this->tickRate());
$new = clone $this;
$new->falling = $falling;
$new->decay = $falling ? 0 : $newFlowDecay;
$this->level->setBlock($block, $new, true, true);
}
}
@ -407,13 +410,15 @@ abstract class Liquid extends Transparent{
}
private function getSmallestFlowDecay(Block $block, int $decay) : int{
$blockDecay = $this->getFlowDecay($block);
if($blockDecay < 0){
if(!($block instanceof Liquid) or $block->getId() !== $this->getId()){
return $decay;
}elseif($blockDecay === 0){
}
$blockDecay = $block->decay;
if($block->isSource()){
++$this->adjacentSources;
}elseif($blockDecay >= 8){
}elseif($block->falling){
$blockDecay = 0;
}
@ -433,6 +438,6 @@ abstract class Liquid extends Transparent{
}
protected function canFlowInto(Block $block) : bool{
return $block->canBeFlowedInto() and !($block instanceof Liquid and $block->meta === 0); //TODO: I think this should only be liquids of the same type
return $block->canBeFlowedInto() and !($block instanceof Liquid and $block->isSource()); //TODO: I think this should only be liquids of the same type
}
}

View File

@ -1,37 +0,0 @@
<?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;
class LitRedstoneLamp extends RedstoneLamp{
protected $id = self::LIT_REDSTONE_LAMP;
public function getName() : string{
return "Lit Redstone Lamp";
}
public function getLightLevel() : int{
return 15;
}
}

View File

@ -32,8 +32,8 @@ class Magma extends Solid{
protected $id = Block::MAGMA;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -30,8 +30,8 @@ class Melon extends Transparent{
protected $id = self::MELON_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -37,15 +37,11 @@ class MelonStem extends Crops{
return "Melon Stem";
}
public function __construct(int $meta = 0){
$this->setDamage($meta);
}
public function onRandomTick() : void{
if(mt_rand(0, 2) === 1){
if($this->meta < 0x07){
if($this->age < 7){
$block = clone $this;
++$block->meta;
++$block->age;
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($this, $ev->getNewState(), true);

View File

@ -30,8 +30,8 @@ class MonsterSpawner extends Transparent{
protected $id = self::MONSTER_SPAWNER;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getHardness() : float{

View File

@ -33,8 +33,8 @@ class Mycelium extends Solid{
protected $id = self::MYCELIUM;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -29,6 +29,10 @@ class NetherBrickFence extends Fence{
protected $id = self::NETHER_BRICK_FENCE;
public function __construct(){
}
public function getHardness() : float{
return 2;
}

View File

@ -29,8 +29,8 @@ class NetherBrickStairs extends Stair{
protected $id = self::NETHER_BRICK_STAIRS;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -31,8 +31,8 @@ class NetherQuartzOre extends Solid{
protected $id = Block::NETHER_QUARTZ_ORE;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -28,19 +28,33 @@ use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;
class NetherReactor extends Solid{
protected const STATE_INACTIVE = 0;
protected const STATE_ACTIVE = 1;
protected const STATE_USED = 2;
protected $id = Block::NETHER_REACTOR;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $state = self::STATE_INACTIVE;
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->state;
}
public function readStateFromMeta(int $meta) : void{
$this->state = $meta;
}
public function getStateBitmask() : int{
return 0b11;
}
public function getName() : string{
static $prefixes = [
"",
"Active ",
"Used "
];
return ($prefixes[$this->meta] ?? "") . "Nether Reactor Core";
return "Nether Reactor Core";
}
public function getToolType() : int{

View File

@ -27,8 +27,8 @@ class NetherWartBlock extends Solid{
protected $id = Block::NETHER_WART_BLOCK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

View File

@ -36,8 +36,23 @@ class NetherWartPlant extends Flowable{
protected $itemId = Item::NETHER_WART;
public function __construct(int $meta = 0){
$this->setDamage($meta);
/** @var int */
protected $age = 0;
public function __construct(){
}
protected function writeStateToMeta() : int{
return $this->age;
}
public function readStateFromMeta(int $meta) : void{
$this->age = $meta;
}
public function getStateBitmask() : int{
return 0b11;
}
public function getName() : string{
@ -64,9 +79,9 @@ class NetherWartPlant extends Flowable{
}
public function onRandomTick() : void{
if($this->meta < 3 and mt_rand(0, 10) === 0){ //Still growing
if($this->age < 3 and mt_rand(0, 10) === 0){ //Still growing
$block = clone $this;
$block->meta++;
$block->age++;
$this->getLevel()->getServer()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
if(!$ev->isCancelled()){
@ -77,7 +92,7 @@ class NetherWartPlant extends Flowable{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get($this->getItemId(), 0, ($this->getDamage() === 3 ? mt_rand(2, 4) : 1))
ItemFactory::get($this->getItemId(), 0, ($this->age === 3 ? mt_rand(2, 4) : 1))
];
}

View File

@ -29,8 +29,8 @@ class Netherrack extends Solid{
protected $id = self::NETHERRACK;
public function __construct(int $meta = 0){
$this->setDamage($meta);
public function __construct(){
}
public function getName() : string{

Some files were not shown because too many files have changed in this diff Show More