Use dynamic state detection to localize stateinfo stored in tiles (hack)

This commit is contained in:
Dylan K. Taylor 2018-10-28 20:00:43 +00:00
parent 3af293f024
commit 3f3bdaeba5
15 changed files with 81 additions and 63 deletions

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\Color;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\ItemFactory; use pocketmine\item\ItemFactory;
use pocketmine\lang\TranslationContainer; use pocketmine\lang\TranslationContainer;
@ -50,6 +51,8 @@ class Bed extends Transparent{
protected $occupied = false; protected $occupied = false;
/** @var bool */ /** @var bool */
protected $head = false; protected $head = false;
/** @var int */
protected $color = Color::RED;
public function __construct(){ public function __construct(){
@ -71,6 +74,16 @@ class Bed extends Transparent{
return 0b1111; return 0b1111;
} }
public function updateState() : void{
parent::updateState();
//read extra state information from the tile - this is an ugly hack
//TODO: extend this hack to setting block as well so we don't have to deal with tile hacks in the main code
$tile = $this->level->getTile($this);
if($tile instanceof TileBed){
$this->color = $tile->getColor();
}
}
public function getHardness() : float{ public function getHardness() : float{
return 0.2; return 0.2;
} }
@ -161,6 +174,7 @@ class Bed extends Transparent{
} }
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
$this->color = $item->getDamage(); //TODO: replace this with a proper colour getter
$down = $this->getSide(Facing::DOWN); $down = $this->getSide(Facing::DOWN);
if(!$down->isTransparent()){ if(!$down->isTransparent()){
$this->facing = $player !== null ? Bearing::toFacing($player->getDirection()) : Facing::NORTH; $this->facing = $player !== null ? Bearing::toFacing($player->getDirection()) : Facing::NORTH;
@ -172,8 +186,15 @@ class Bed extends Transparent{
$nextState->head = true; $nextState->head = true;
$this->getLevel()->setBlock($next, $nextState); $this->getLevel()->setBlock($next, $nextState);
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player)); //TODO: make this happen automatically on block set
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player)); $tile1 = Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this));
if($tile1 instanceof TileBed){
$tile1->setColor($this->color);
}
$tile2 = Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next));
if($tile2 instanceof TileBed){
$tile2->setColor($this->color);
}
return true; return true;
} }
@ -191,12 +212,7 @@ class Bed extends Transparent{
} }
public function getItem() : Item{ public function getItem() : Item{
$tile = $this->getLevel()->getTile($this); return ItemFactory::get($this->getItemId(), $this->color);
if($tile instanceof TileBed){
return ItemFactory::get($this->getItemId(), $tile->getColor());
}
return ItemFactory::get($this->getItemId(), 14); //Red
} }
public function isAffectedBySilkTouch() : bool{ public function isAffectedBySilkTouch() : bool{

View File

@ -93,7 +93,7 @@ class Chest extends Transparent{
} }
if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){ if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
$tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player)); $tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $item));
if($chest instanceof TileChest and $tile instanceof TileChest){ if($chest instanceof TileChest and $tile instanceof TileChest){
$chest->pairWith($tile); $chest->pairWith($tile);

View File

@ -43,7 +43,7 @@ class EnchantingTable extends Transparent{
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){ if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player)); Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $item));
return true; return true;
} }

View File

@ -67,7 +67,7 @@ class EnderChest extends Chest{
} }
if(Block::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){ if(Block::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this, $face, $item, $player)); Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this, $item));
return true; return true;
} }

View File

@ -69,7 +69,7 @@ class FlowerPot extends Flowable{
} }
if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){ if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player)); Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $item));
return true; return true;
} }

View File

@ -94,7 +94,7 @@ class Furnace extends Solid{
$this->facing = Bearing::toFacing(Bearing::opposite($player->getDirection())); $this->facing = Bearing::toFacing(Bearing::opposite($player->getDirection()));
} }
if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){ if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player)); Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $item));
return true; return true;
} }

View File

@ -85,7 +85,7 @@ class ItemFrame extends Flowable{
$this->facing = $face; $this->facing = $face;
if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){ if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player)); Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $item));
return true; return true;
} }

View File

@ -83,7 +83,7 @@ class SignPost extends Transparent{
} }
if($ret){ if($ret){
Tile::createTile(Tile::SIGN, $this->getLevel(), TileSign::createNBT($this, $face, $item, $player)); Tile::createTile(Tile::SIGN, $this->getLevel(), TileSign::createNBT($this, $item));
return true; return true;
} }
} }

View File

@ -39,6 +39,10 @@ class Skull extends Flowable{
/** @var int */ /** @var int */
protected $facing = Facing::NORTH; protected $facing = Facing::NORTH;
protected $type = TileSkull::TYPE_SKELETON;
/** @var int */
protected $rotation = 0; //TODO: split this into floor skull and wall skull handling
public function __construct(){ public function __construct(){
} }
@ -55,6 +59,15 @@ class Skull extends Flowable{
return 0b111; return 0b111;
} }
public function updateState() : void{
parent::updateState();
$tile = $this->level->getTile($this);
if($tile instanceof TileSkull){
$this->type = $tile->getType();
$this->rotation = $tile->getRotation();
}
}
public function getHardness() : float{ public function getHardness() : float{
return 1; return 1;
} }
@ -74,8 +87,17 @@ class Skull extends Flowable{
} }
$this->facing = $face; $this->facing = $face;
$this->type = $item->getDamage(); //TODO: replace this with a proper variant getter
if($player !== null and $face === Facing::UP){
$this->rotation = ((int) floor(($player->yaw * 16 / 360) + 0.5)) & 0xf;
}
if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){ if(parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
Tile::createTile(Tile::SKULL, $this->getLevel(), TileSkull::createNBT($this, $face, $item, $player)); //TODO: make this automatic on block set
$tile = Tile::createTile(Tile::SKULL, $this->getLevel(), TileSkull::createNBT($this));
if($tile instanceof TileSkull){
$tile->setRotation($this->rotation);
$tile->setType($this->type);
}
return true; return true;
} }
@ -83,8 +105,7 @@ class Skull extends Flowable{
} }
public function getItem() : Item{ public function getItem() : Item{
$tile = $this->level->getTile($this); return ItemFactory::get(Item::SKULL, $this->type);
return ItemFactory::get(Item::SKULL, $tile instanceof TileSkull ? $tile->getType() : 0);
} }
public function isAffectedBySilkTouch() : bool{ public function isAffectedBySilkTouch() : bool{

View File

@ -83,7 +83,7 @@ class StandingBanner extends Transparent{
} }
if($ret){ if($ret){
Tile::createTile(Tile::BANNER, $this->getLevel(), TileBanner::createNBT($this, $face, $item, $player)); Tile::createTile(Tile::BANNER, $this->getLevel(), TileBanner::createNBT($this, $item));
return true; return true;
} }
} }

View File

@ -23,13 +23,12 @@ declare(strict_types=1);
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\item\Banner as ItemBanner;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
class Banner extends Spawnable implements Nameable{ class Banner extends Spawnable implements Nameable{
use NameableTrait { use NameableTrait {
@ -268,15 +267,16 @@ class Banner extends Spawnable implements Nameable{
return $this->patterns; return $this->patterns;
} }
protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{ protected static function createAdditionalNBT(CompoundTag $nbt, ?Item $item = null) : void{
$nbt->setInt(self::TAG_BASE, $item !== null ? $item->getDamage() & 0x0f : 0); if($item instanceof ItemBanner){
$nbt->setInt(self::TAG_BASE, $item->getBaseColor());
if($item !== null){ //TODO: clean this mess up
if($item->getNamedTag()->hasTag(self::TAG_PATTERNS, ListTag::class)){ if($item->getNamedTag()->hasTag(self::TAG_PATTERNS, ListTag::class)){
$nbt->setTag($item->getNamedTag()->getListTag(self::TAG_PATTERNS)); $nbt->setTag($item->getNamedTag()->getListTag(self::TAG_PATTERNS));
} }
self::createNameNBT($nbt, $pos, $face, $item, $player); self::createNameNBT($nbt, $item);
} }
} }

View File

@ -23,11 +23,7 @@ declare(strict_types=1);
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player;
class Bed extends Spawnable{ class Bed extends Spawnable{
public const TAG_COLOR = "color"; public const TAG_COLOR = "color";
@ -54,10 +50,4 @@ class Bed extends Spawnable{
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->setByte(self::TAG_COLOR, $this->color); $nbt->setByte(self::TAG_COLOR, $this->color);
} }
protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{
if($item !== null){
$nbt->setByte(self::TAG_COLOR, $item->getDamage());
}
}
} }

View File

@ -24,10 +24,8 @@ declare(strict_types=1);
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
/** /**
* This trait implements most methods in the {@link Nameable} interface. It should only be used by Tiles. * This trait implements most methods in the {@link Nameable} interface. It should only be used by Tiles.
@ -66,7 +64,7 @@ trait NameableTrait{
return $this->customName !== null; return $this->customName !== null;
} }
protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{ protected static function createAdditionalNBT(CompoundTag $nbt, ?Item $item = null) : void{
if($item !== null and $item->hasCustomName()){ if($item !== null and $item->hasCustomName()){
$nbt->setString(Nameable::TAG_CUSTOM_NAME, $item->getCustomName()); $nbt->setString(Nameable::TAG_CUSTOM_NAME, $item->getCustomName());
} }

View File

@ -23,11 +23,7 @@ declare(strict_types=1);
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player;
class Skull extends Spawnable{ class Skull extends Spawnable{
public const TYPE_SKELETON = 0; public const TYPE_SKELETON = 0;
@ -66,18 +62,17 @@ class Skull extends Spawnable{
return $this->skullType; return $this->skullType;
} }
public function getRotation() : int{
return $this->skullRotation;
}
public function setRotation(int $rotation) : void{
$this->skullRotation = $rotation;
$this->onChanged();
}
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);
$nbt->setByte(self::TAG_ROT, $this->skullRotation); $nbt->setByte(self::TAG_ROT, $this->skullRotation);
} }
protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{
$nbt->setByte(self::TAG_SKULL_TYPE, $item !== null ? $item->getDamage() : self::TYPE_SKELETON);
$rot = 0;
if($face === Facing::UP and $player !== null){
$rot = floor(($player->yaw * 16 / 360) + 0.5) & 0x0F;
}
$nbt->setByte(self::TAG_ROT, $rot);
}
} }

View File

@ -35,7 +35,6 @@ use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\timings\Timings; use pocketmine\timings\Timings;
use pocketmine\timings\TimingsHandler; use pocketmine\timings\TimingsHandler;
@ -184,13 +183,14 @@ abstract class Tile extends Position{
* Creates and returns a CompoundTag containing the necessary information to spawn a tile of this type. * Creates and returns a CompoundTag containing the necessary information to spawn a tile of this type.
* *
* @param Vector3 $pos * @param Vector3 $pos
* @param int|null $face
* @param Item|null $item * @param Item|null $item
* @param Player|null $player
* *
* @return CompoundTag * @return CompoundTag
* @throws \BadMethodCallException
* @throws \InvalidArgumentException
* @throws \InvalidStateException
*/ */
public static function createNBT(Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : CompoundTag{ public static function createNBT(Vector3 $pos, ?Item $item = null) : CompoundTag{
if(static::class === self::class){ if(static::class === self::class){
throw new \BadMethodCallException(__METHOD__ . " must be called from the scope of a child class"); throw new \BadMethodCallException(__METHOD__ . " must be called from the scope of a child class");
} }
@ -201,7 +201,7 @@ abstract class Tile extends Position{
new IntTag(self::TAG_Z, (int) $pos->z) new IntTag(self::TAG_Z, (int) $pos->z)
]); ]);
static::createAdditionalNBT($nbt, $pos, $face, $item, $player); static::createAdditionalNBT($nbt, $item);
if($item !== null){ if($item !== null){
$customBlockData = $item->getCustomBlockData(); $customBlockData = $item->getCustomBlockData();
@ -217,14 +217,12 @@ abstract class Tile extends Position{
/** /**
* Called by createNBT() to allow descendent classes to add their own base NBT using the parameters provided. * Called by createNBT() to allow descendent classes to add their own base NBT using the parameters provided.
* TODO: remove this and add a hook for setting data from items post-place
* *
* @param CompoundTag $nbt * @param CompoundTag $nbt
* @param Vector3 $pos
* @param int|null $face
* @param Item|null $item * @param Item|null $item
* @param Player|null $player
*/ */
protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{ protected static function createAdditionalNBT(CompoundTag $nbt, ?Item $item = null) : void{
} }