Added SkullType enum, some cleanup to skull handling

this is still more ugly than I'd like it to be because of the way the blockfactory currently works.
This commit is contained in:
Dylan K. Taylor 2019-02-26 18:27:30 +00:00
parent edf4a719d5
commit cb91afcc00
5 changed files with 242 additions and 33 deletions

View File

@ -24,24 +24,33 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\BlockDataValidator; use pocketmine\block\utils\BlockDataValidator;
use pocketmine\block\utils\SkullType;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\ItemFactory; use pocketmine\item\ItemFactory;
use pocketmine\item\Skull as ItemSkull;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\tile\Skull as TileSkull; use pocketmine\tile\Skull as TileSkull;
use function assert;
use function floor; use function floor;
class Skull extends Flowable{ class Skull extends Flowable{
/** @var SkullType */
protected $skullType;
/** @var int */ /** @var int */
protected $facing = Facing::NORTH; protected $facing = Facing::NORTH;
protected $type = TileSkull::TYPE_SKELETON;
/** @var int */ /** @var int */
protected $rotation = 0; //TODO: split this into floor skull and wall skull handling protected $rotation = 0; //TODO: split this into floor skull and wall skull handling
public function __construct(BlockIdentifier $idInfo, string $name){
$this->skullType = SkullType::SKELETON(); //TODO: this should be a parameter
parent::__construct($idInfo, $name);
}
protected function writeStateToMeta() : int{ protected function writeStateToMeta() : int{
return $this->facing; return $this->facing;
} }
@ -58,7 +67,7 @@ class Skull extends Flowable{
parent::readStateFromWorld(); parent::readStateFromWorld();
$tile = $this->level->getTile($this); $tile = $this->level->getTile($this);
if($tile instanceof TileSkull){ if($tile instanceof TileSkull){
$this->type = $tile->getType(); $this->skullType = $tile->getSkullType();
$this->rotation = $tile->getRotation(); $this->rotation = $tile->getRotation();
} }
} }
@ -67,16 +76,22 @@ class Skull extends Flowable{
parent::writeStateToWorld(); parent::writeStateToWorld();
//extra block properties storage hack //extra block properties storage hack
$tile = $this->level->getTile($this); $tile = $this->level->getTile($this);
if($tile instanceof TileSkull){ assert($tile instanceof TileSkull);
$tile->setRotation($this->rotation); $tile->setRotation($this->rotation);
$tile->setType($this->type); $tile->setSkullType($this->skullType);
}
} }
public function getHardness() : float{ public function getHardness() : float{
return 1; return 1;
} }
/**
* @return SkullType
*/
public function getSkullType() : SkullType{
return $this->skullType;
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{ protected function recalculateBoundingBox() : ?AxisAlignedBB{
//TODO: different bounds depending on attached face //TODO: different bounds depending on attached face
return AxisAlignedBB::one()->contract(0.25, 0, 0.25)->trim(Facing::UP, 0.5); return AxisAlignedBB::one()->contract(0.25, 0, 0.25)->trim(Facing::UP, 0.5);
@ -88,7 +103,9 @@ class Skull extends Flowable{
} }
$this->facing = $face; $this->facing = $face;
$this->type = $item->getDamage(); //TODO: replace this with a proper variant getter if($item instanceof ItemSkull){
$this->skullType = $item->getSkullType(); //TODO: the item should handle this, but this hack is currently needed because of tile mess
}
if($player !== null and $face === Facing::UP){ if($player !== null and $face === Facing::UP){
$this->rotation = ((int) floor(($player->yaw * 16 / 360) + 0.5)) & 0xf; $this->rotation = ((int) floor(($player->yaw * 16 / 360) + 0.5)) & 0xf;
} }
@ -96,7 +113,7 @@ class Skull extends Flowable{
} }
public function asItem() : Item{ public function asItem() : Item{
return ItemFactory::get(Item::SKULL, $this->type); return ItemFactory::get(Item::SKULL, $this->skullType->getMagicNumber());
} }
public function isAffectedBySilkTouch() : bool{ public function isAffectedBySilkTouch() : bool{

View File

@ -0,0 +1,131 @@
<?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\utils;
final class SkullType{
/** @var SkullType */
private static $SKELETON;
/** @var SkullType */
private static $WITHER_SKELETON;
/** @var SkullType */
private static $ZOMBIE;
/** @var SkullType */
private static $HUMAN;
/** @var SkullType */
private static $CREEPER;
/** @var SkullType */
private static $DRAGON;
/* auto-generated code */
public static function SKELETON() : SkullType{
return self::$SKELETON;
}
public static function WITHER_SKELETON() : SkullType{
return self::$WITHER_SKELETON;
}
public static function ZOMBIE() : SkullType{
return self::$ZOMBIE;
}
public static function HUMAN() : SkullType{
return self::$HUMAN;
}
public static function CREEPER() : SkullType{
return self::$CREEPER;
}
public static function DRAGON() : SkullType{
return self::$DRAGON;
}
/** @var SkullType[] */
private static $all = [];
/** @var SkullType[] */
private static $numericIdMap = [];
public static function _init() : void{
self::register(self::$SKELETON = new SkullType("Skeleton Skull", 0));
self::register(self::$WITHER_SKELETON = new SkullType("Wither Skeleton Skull", 1));
self::register(self::$ZOMBIE = new SkullType("Zombie Head", 2));
self::register(self::$HUMAN = new SkullType("Player Head", 3));
self::register(self::$CREEPER = new SkullType("Creeper Head", 4));
self::register(self::$DRAGON = new SkullType("Dragon Head", 5));
}
private static function register(SkullType $type) : void{
self::$numericIdMap[$type->getMagicNumber()] = $type;
self::$all[] = $type;
}
/**
* @return SkullType[]
*/
public static function getAll() : array{
return self::$all;
}
/**
* @internal
* @param int $magicNumber
*
* @return SkullType
* @throws \InvalidArgumentException
*/
public static function fromMagicNumber(int $magicNumber) : SkullType{
if(!isset(self::$numericIdMap[$magicNumber])){
throw new \InvalidArgumentException("Unknown skull type magic number $magicNumber");
}
return self::$numericIdMap[$magicNumber];
}
/** @var string */
private $displayName;
/** @var int */
private $magicNumber;
public function __construct(string $displayName, int $magicNumber){
$this->displayName = $displayName;
$this->magicNumber = $magicNumber;
}
/**
* @return string
*/
public function getDisplayName() : string{
return $this->displayName;
}
/**
* @return int
*/
public function getMagicNumber() : int{
return $this->magicNumber;
}
}
SkullType::_init();

View File

@ -26,10 +26,10 @@ namespace pocketmine\item;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\block\BlockFactory; use pocketmine\block\BlockFactory;
use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SkullType;
use pocketmine\entity\EntityFactory; use pocketmine\entity\EntityFactory;
use pocketmine\entity\Living; use pocketmine\entity\Living;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\tile\Skull;
use function constant; use function constant;
use function defined; use function defined;
use function explode; use function explode;
@ -172,12 +172,6 @@ class ItemFactory{
self::register(new ItemBlock(Block::NETHER_WART_PLANT, 0, Item::NETHER_WART)); self::register(new ItemBlock(Block::NETHER_WART_PLANT, 0, Item::NETHER_WART));
self::register(new ItemBlock(Block::OAK_DOOR_BLOCK, 0, Item::OAK_DOOR)); self::register(new ItemBlock(Block::OAK_DOOR_BLOCK, 0, Item::OAK_DOOR));
self::register(new ItemBlock(Block::REPEATER_BLOCK, 0, Item::REPEATER)); self::register(new ItemBlock(Block::REPEATER_BLOCK, 0, Item::REPEATER));
self::register(new ItemBlock(Block::SKULL_BLOCK, Skull::TYPE_CREEPER, Item::SKULL));
self::register(new ItemBlock(Block::SKULL_BLOCK, Skull::TYPE_DRAGON, Item::SKULL));
self::register(new ItemBlock(Block::SKULL_BLOCK, Skull::TYPE_HUMAN, Item::SKULL));
self::register(new ItemBlock(Block::SKULL_BLOCK, Skull::TYPE_SKELETON, Item::SKULL));
self::register(new ItemBlock(Block::SKULL_BLOCK, Skull::TYPE_WITHER, Item::SKULL));
self::register(new ItemBlock(Block::SKULL_BLOCK, Skull::TYPE_ZOMBIE, Item::SKULL));
self::register(new ItemBlock(Block::SPRUCE_DOOR_BLOCK, 0, Item::SPRUCE_DOOR)); self::register(new ItemBlock(Block::SPRUCE_DOOR_BLOCK, 0, Item::SPRUCE_DOOR));
self::register(new ItemBlock(Block::SUGARCANE_BLOCK, 0, Item::SUGARCANE)); self::register(new ItemBlock(Block::SUGARCANE_BLOCK, 0, Item::SUGARCANE));
self::register(new LeatherBoots()); self::register(new LeatherBoots());
@ -236,6 +230,10 @@ class ItemFactory{
self::register(new WritableBook()); self::register(new WritableBook());
self::register(new WrittenBook()); self::register(new WrittenBook());
foreach(SkullType::getAll() as $skullType){
self::register(new Skull(Item::SKULL, $skullType->getMagicNumber(), $skullType->getDisplayName(), $skullType));
}
/** @var int[]|\SplObjectStorage $dyeMap */ /** @var int[]|\SplObjectStorage $dyeMap */
$dyeMap = new \SplObjectStorage(); $dyeMap = new \SplObjectStorage();
$dyeMap[DyeColor::BLACK()] = 16; $dyeMap[DyeColor::BLACK()] = 16;

View File

@ -0,0 +1,47 @@
<?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\item;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\block\utils\SkullType;
class Skull extends Item{
/** @var SkullType */
private $skullType;
public function __construct(int $id, int $variant, string $name, SkullType $skullType){
parent::__construct($id, $variant, $name);
$this->skullType = $skullType;
}
public function getBlock() : Block{
return BlockFactory::get(Block::SKULL_BLOCK);
}
public function getSkullType() : SkullType{
return $this->skullType;
}
}

View File

@ -23,42 +23,58 @@ declare(strict_types=1);
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\block\utils\SkullType;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
/**
* @deprecated
* @see \pocketmine\block\Skull
*/
class Skull extends Spawnable{ class Skull extends Spawnable{
public const TYPE_SKELETON = 0;
public const TYPE_WITHER = 1;
public const TYPE_ZOMBIE = 2;
public const TYPE_HUMAN = 3;
public const TYPE_CREEPER = 4;
public const TYPE_DRAGON = 5;
public const TAG_SKULL_TYPE = "SkullType"; //TAG_Byte private const TAG_SKULL_TYPE = "SkullType"; //TAG_Byte
public const TAG_ROT = "Rot"; //TAG_Byte private const TAG_ROT = "Rot"; //TAG_Byte
public const TAG_MOUTH_MOVING = "MouthMoving"; //TAG_Byte private const TAG_MOUTH_MOVING = "MouthMoving"; //TAG_Byte
public const TAG_MOUTH_TICK_COUNT = "MouthTickCount"; //TAG_Int private const TAG_MOUTH_TICK_COUNT = "MouthTickCount"; //TAG_Int
/** @var int */ /** @var SkullType */
private $skullType = self::TYPE_SKELETON; private $skullType;
/** @var int */ /** @var int */
private $skullRotation = 0; private $skullRotation = 0;
public function __construct(Level $level, Vector3 $pos){
$this->skullType = SkullType::SKELETON();
parent::__construct($level, $pos);
}
public function readSaveData(CompoundTag $nbt) : void{ public function readSaveData(CompoundTag $nbt) : void{
$this->skullType = $nbt->getByte(self::TAG_SKULL_TYPE, $this->skullType, true); if($nbt->hasTag(self::TAG_SKULL_TYPE, ByteTag::class)){
$this->skullRotation = $nbt->getByte(self::TAG_ROT, $this->skullRotation, true); try{
$this->skullType = SkullType::fromMagicNumber($nbt->getByte(self::TAG_SKULL_TYPE));
}catch(\InvalidArgumentException $e){
//bad data, drop it
}
}
$rotation = $nbt->getByte(self::TAG_ROT, 0, true);
if($rotation >= 0 and $rotation <= 15){
$this->skullRotation = $rotation;
}
} }
protected function writeSaveData(CompoundTag $nbt) : void{ protected function writeSaveData(CompoundTag $nbt) : void{
$nbt->setByte(self::TAG_SKULL_TYPE, $this->skullType); $nbt->setByte(self::TAG_SKULL_TYPE, $this->skullType->getMagicNumber());
$nbt->setByte(self::TAG_ROT, $this->skullRotation); $nbt->setByte(self::TAG_ROT, $this->skullRotation);
} }
public function setType(int $type){ public function setSkullType(SkullType $type){
$this->skullType = $type; $this->skullType = $type;
$this->onChanged(); $this->onChanged();
} }
public function getType() : int{ public function getSkullType() : SkullType{
return $this->skullType; return $this->skullType;
} }
@ -72,7 +88,7 @@ class Skull extends Spawnable{
} }
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->setByte(self::TAG_SKULL_TYPE, $this->skullType); $nbt->setByte(self::TAG_SKULL_TYPE, $this->skullType->getMagicNumber());
$nbt->setByte(self::TAG_ROT, $this->skullRotation); $nbt->setByte(self::TAG_ROT, $this->skullRotation);
} }
} }