From e9125af51d7f8c1cfe9b2a950009c1f851302b15 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Mar 2019 17:57:07 +0000 Subject: [PATCH] Revamp Banner API (still rather ghetto) this needs more work, like signs do. --- src/pocketmine/block/StandingBanner.php | 78 ++++++- src/pocketmine/block/utils/BannerPattern.php | 95 ++++++++ src/pocketmine/item/Banner.php | 172 ++------------ src/pocketmine/tile/Banner.php | 232 ++++--------------- 4 files changed, 230 insertions(+), 347 deletions(-) create mode 100644 src/pocketmine/block/utils/BannerPattern.php diff --git a/src/pocketmine/block/StandingBanner.php b/src/pocketmine/block/StandingBanner.php index e20490fbb..18aa39743 100644 --- a/src/pocketmine/block/StandingBanner.php +++ b/src/pocketmine/block/StandingBanner.php @@ -23,6 +23,9 @@ declare(strict_types=1); namespace pocketmine\block; +use Ds\Deque; +use pocketmine\block\utils\BannerPattern; +use pocketmine\block\utils\DyeColor; use pocketmine\item\Banner as ItemBanner; use pocketmine\item\Item; use pocketmine\item\ItemFactory; @@ -31,6 +34,7 @@ use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\Player; use pocketmine\tile\Banner as TileBanner; +use function assert; use function floor; class StandingBanner extends Transparent{ @@ -38,6 +42,18 @@ class StandingBanner extends Transparent{ /** @var int */ protected $rotation = 0; + /** @var DyeColor */ + protected $baseColor; + + /** @var Deque|BannerPattern[] */ + protected $patterns; + + public function __construct(BlockIdentifier $idInfo, string $name){ + parent::__construct($idInfo, $name); + $this->baseColor = DyeColor::BLACK(); + $this->patterns = new Deque(); + } + protected function writeStateToMeta() : int{ return $this->rotation; } @@ -50,6 +66,23 @@ class StandingBanner extends Transparent{ return 0b1111; } + public function readStateFromWorld() : void{ + parent::readStateFromWorld(); + $tile = $this->level->getTile($this); + if($tile instanceof TileBanner){ + $this->baseColor = $tile->getBaseColor(); + $this->setPatterns($tile->getPatterns()); + } + } + + public function writeStateToWorld() : void{ + parent::writeStateToWorld(); + $tile = $this->level->getTile($this); + assert($tile instanceof TileBanner); + $tile->setBaseColor($this->baseColor); + $tile->setPatterns($this->patterns); + } + public function getHardness() : float{ return 1; } @@ -58,18 +91,53 @@ class StandingBanner extends Transparent{ return false; } + /** + * TODO: interface method? this is only the BASE colour... + * @return DyeColor + */ + public function getColor() : DyeColor{ + return $this->baseColor; + } + + /** + * @return Deque|BannerPattern[] + */ + public function getPatterns() : Deque{ + return $this->patterns; + } + + /** + * @param Deque|BannerPattern[] $patterns + */ + public function setPatterns(Deque $patterns) : void{ + $checked = $patterns->filter(function($v){ return $v instanceof BannerPattern; }); + if($checked->count() !== $patterns->count()){ + throw new \TypeError("Deque must only contain " . BannerPattern::class . " objects"); + } + $this->patterns = $checked; + } + protected function recalculateBoundingBox() : ?AxisAlignedBB{ return null; } public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ + if($item instanceof ItemBanner){ + $this->baseColor = $item->getColor(); + $this->setPatterns($item->getPatterns()); + } if($face !== Facing::DOWN){ if($face === Facing::UP and $player !== null){ $this->rotation = ((int) floor((($player->yaw + 180) * 16 / 360) + 0.5)) & 0x0f; return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player); } - return $this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $face)); + //TODO: awful hack :( + $wallBanner = BlockFactory::get(Block::WALL_BANNER, $face); + assert($wallBanner instanceof WallBanner); + $wallBanner->baseColor = $this->baseColor; + $wallBanner->setPatterns($this->patterns); + return $this->getLevel()->setBlock($blockReplace, $wallBanner); } return false; @@ -86,11 +154,9 @@ class StandingBanner extends Transparent{ } public function getDropsForCompatibleTool(Item $item) : array{ - $tile = $this->level->getTile($this); - - $drop = ItemFactory::get(Item::BANNER, ($tile instanceof TileBanner ? $tile->getBaseColor()->getInvertedMagicNumber() : 0)); - if($tile instanceof TileBanner and $drop instanceof ItemBanner and !($patterns = $tile->getPatterns())->empty()){ - $drop->setPatterns($patterns); + $drop = ItemFactory::get(Item::BANNER, $this->baseColor->getInvertedMagicNumber()); + if($drop instanceof ItemBanner and !$this->patterns->isEmpty()){ + $drop->setPatterns($this->patterns); } return [$drop]; diff --git a/src/pocketmine/block/utils/BannerPattern.php b/src/pocketmine/block/utils/BannerPattern.php new file mode 100644 index 000000000..cde366b25 --- /dev/null +++ b/src/pocketmine/block/utils/BannerPattern.php @@ -0,0 +1,95 @@ +id = $id; + $this->color = $color; + } + + /** + * @return string + */ + public function getId() : string{ + return $this->id; + } + + /** + * @return DyeColor + */ + public function getColor() : DyeColor{ + return $this->color; + } +} diff --git a/src/pocketmine/item/Banner.php b/src/pocketmine/item/Banner.php index c9deb5be4..33bb1456d 100644 --- a/src/pocketmine/item/Banner.php +++ b/src/pocketmine/item/Banner.php @@ -23,15 +23,16 @@ declare(strict_types=1); namespace pocketmine\item; +use Ds\Deque; use pocketmine\block\Block; use pocketmine\block\BlockFactory; +use pocketmine\block\utils\BannerPattern; use pocketmine\block\utils\DyeColor; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; use pocketmine\tile\Banner as TileBanner; -use function assert; class Banner extends Item{ public const TAG_PATTERNS = TileBanner::TAG_PATTERNS; @@ -62,162 +63,33 @@ class Banner extends Item{ } /** - * Applies a new pattern on the banner with the given color. - * Banner items have to be resent to see the changes in the inventory. - * - * @param string $pattern - * @param DyeColor $color - * - * @return int ID of pattern. + * @return Deque|BannerPattern[] */ - public function addPattern(string $pattern, DyeColor $color) : int{ - $patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS); - assert($patternsTag !== null); - - $patternsTag->push(new CompoundTag("", [ - new IntTag(self::TAG_PATTERN_COLOR, $color->getInvertedMagicNumber()), - new StringTag(self::TAG_PATTERN_NAME, $pattern) - ])); - - $this->setNamedTagEntry($patternsTag); - - return $patternsTag->count() - 1; - } - - /** - * Returns whether a pattern with the given ID exists on the banner or not. - * - * @param int $patternId - * - * @return bool - */ - public function patternExists(int $patternId) : bool{ - $this->correctNBT(); - return $this->getNamedTag()->getListTag(self::TAG_PATTERNS)->isset($patternId); - } - - /** - * Returns the data of a pattern with the given ID. - * - * @param int $patternId - * - * @return array - */ - public function getPatternData(int $patternId) : array{ - if(!$this->patternExists($patternId)){ - return []; + public function getPatterns() : Deque{ + $result = new Deque(); + $tag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS); + if($tag !== null){ + /** @var CompoundTag $t */ + foreach($tag as $t){ + $result->push(new BannerPattern($t->getString(self::TAG_PATTERN_NAME), DyeColor::fromMagicNumber($t->getInt(self::TAG_PATTERN_COLOR), true))); + } } - - $patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS); - assert($patternsTag !== null); - $pattern = $patternsTag->get($patternId); - assert($pattern instanceof CompoundTag); - - return [ - self::TAG_PATTERN_COLOR => DyeColor::fromMagicNumber($pattern->getInt(self::TAG_PATTERN_COLOR), true), - self::TAG_PATTERN_NAME => $pattern->getString(self::TAG_PATTERN_NAME) - ]; + return $result; } /** - * Changes the pattern of a previously existing pattern. - * Banner items have to be resent to see the changes in the inventory. - * - * @param int $patternId - * @param string $pattern - * @param DyeColor $color - * - * @return bool indicating success. + * @param Deque|BannerPattern[] $patterns */ - public function changePattern(int $patternId, string $pattern, DyeColor $color) : bool{ - if(!$this->patternExists($patternId)){ - return false; + public function setPatterns(Deque $patterns) : void{ + $tag = new ListTag(self::TAG_PATTERNS); + /** @var BannerPattern $pattern */ + foreach($patterns as $pattern){ + $tag->push(new CompoundTag("", [ + new StringTag(self::TAG_PATTERN_NAME, $pattern->getId()), + new IntTag(self::TAG_PATTERN_COLOR, $pattern->getColor()->getInvertedMagicNumber()) + ])); } - - $patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS); - assert($patternsTag !== null); - - $patternsTag->set($patternId, new CompoundTag("", [ - new IntTag(self::TAG_PATTERN_COLOR, $color->getInvertedMagicNumber()), - new StringTag(self::TAG_PATTERN_NAME, $pattern) - ])); - - $this->setNamedTagEntry($patternsTag); - return true; - } - - /** - * Deletes a pattern from the banner with the given ID. - * Banner items have to be resent to see the changes in the inventory. - * - * @param int $patternId - * - * @return bool indicating whether the pattern existed or not. - */ - public function deletePattern(int $patternId) : bool{ - if(!$this->patternExists($patternId)){ - return false; - } - - $patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS); - if($patternsTag instanceof ListTag){ - $patternsTag->remove($patternId); - $this->setNamedTagEntry($patternsTag); - } - - return true; - } - - /** - * Deletes the top most pattern of the banner. - * Banner items have to be resent to see the changes in the inventory. - * - * @return bool indicating whether the banner was empty or not. - */ - public function deleteTopPattern() : bool{ - return $this->deletePattern($this->getPatternCount() - 1); - } - - /** - * Deletes the bottom pattern of the banner. - * Banner items have to be resent to see the changes in the inventory. - * - * @return bool indicating whether the banner was empty or not. - */ - public function deleteBottomPattern() : bool{ - return $this->deletePattern(0); - } - - /** - * Returns the total count of patterns on this banner. - * - * @return int - */ - public function getPatternCount() : int{ - return $this->getNamedTag()->getListTag(self::TAG_PATTERNS)->count(); - } - - /** - * @return ListTag|null - */ - public function getPatterns() : ?ListTag{ - return $this->getNamedTag()->getListTag(self::TAG_PATTERNS); - } - - /** - * @param ListTag $patterns - */ - public function setPatterns(ListTag $patterns) : void{ - $this->setNamedTagEntry(clone $patterns); - } - - public function correctNBT() : void{ - $tag = $this->getNamedTag(); - - if(!$tag->hasTag(self::TAG_PATTERNS, ListTag::class)){ - $tag->setTag(new ListTag(self::TAG_PATTERNS)); - } - $this->setNamedTag($tag); + $this->setNamedTagEntry($tag); } public function getFuelTime() : int{ diff --git a/src/pocketmine/tile/Banner.php b/src/pocketmine/tile/Banner.php index 043d875f9..73593fd86 100644 --- a/src/pocketmine/tile/Banner.php +++ b/src/pocketmine/tile/Banner.php @@ -23,78 +23,37 @@ declare(strict_types=1); namespace pocketmine\tile; +use Ds\Deque; +use pocketmine\block\StandingBanner; +use pocketmine\block\utils\BannerPattern; use pocketmine\block\utils\DyeColor; -use pocketmine\item\Banner as ItemBanner; -use pocketmine\item\Item; use pocketmine\level\Level; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; -use function assert; -class Banner extends Spawnable implements Nameable{ - use NameableTrait { - addAdditionalSpawnData as addNameSpawnData; - copyDataFromItem as protected copyNameFromItem; - } +/** + * @deprecated + * @see StandingBanner + */ +class Banner extends Spawnable{ public const TAG_BASE = "Base"; public const TAG_PATTERNS = "Patterns"; public const TAG_PATTERN_COLOR = "Color"; public const TAG_PATTERN_NAME = "Pattern"; - public const PATTERN_BORDER = "bo"; - public const PATTERN_BOTTOM_LEFT_CORNER = "bl"; - public const PATTERN_BOTTOM_RIGHT_CORNER = "br"; - public const PATTERN_BOTTOM_STRIPE = "bs"; - public const PATTERN_BOTTOM_TRIANGLE = "bt"; - public const PATTERN_BOTTOM_TRIANGLE_SAWTOOTH = "bts"; - public const PATTERN_BRICK = "bri"; - public const PATTERN_CENTER_STRIPE = "cs"; - public const PATTERN_CREEPER = "cre"; - public const PATTERN_CURLY_BORDER = "cbo"; - public const PATTERN_DIAGONAL_CROSS = "cr"; - public const PATTERN_DOWN_LEFT_STRIPE = "dls"; - public const PATTERN_DOWN_RIGHT_STRIPE = "drs"; - public const PATTERN_FLOWER = "flo"; - public const PATTERN_GRADIENT = "gra"; - public const PATTERN_GRADIENT_UPSIDE_DOWN = "gru"; - public const PATTERN_HORIZONTAL_HALF_BOTTOM = "hhb"; - public const PATTERN_HORIZONTAL_HALF_TOP = "hh"; - public const PATTERN_LEFT_OF_DIAGONAL = "ld"; - public const PATTERN_LEFT_OF_UPSIDE_DOWN_DIAGONAL = "lud"; - public const PATTERN_LEFT_STRIPE = "ls"; - public const PATTERN_MIDDLE_CIRCLE = "mc"; - public const PATTERN_MIDDLE_RHOMBUS = "mr"; - public const PATTERN_MIDDLE_STRIPE = "ms"; - public const PATTERN_MOJANG = "moj"; - public const PATTERN_RIGHT_OF_DIAGONAL = "rd"; - public const PATTERN_RIGHT_OF_UPSIDE_DOWN_DIAGONAL = "rud"; - public const PATTERN_RIGHT_STRIPE = "rs"; - public const PATTERN_SKULL = "sku"; - public const PATTERN_SMALL_STRIPES = "ss"; - public const PATTERN_SQUARE_CROSS = "sc"; - public const PATTERN_TOP_LEFT_CORNER = "tl"; - public const PATTERN_TOP_RIGHT_CORNER = "tr"; - public const PATTERN_TOP_STRIPE = "ts"; - public const PATTERN_TOP_TRIANGLE = "tt"; - public const PATTERN_TOP_TRIANGLE_SAWTOOTH = "tts"; - public const PATTERN_VERTICAL_HALF_LEFT = "vh"; - public const PATTERN_VERTICAL_HALF_RIGHT = "vhr"; - /** @var DyeColor */ private $baseColor; - /** - * @var ListTag - * TODO: break this down further and remove runtime NBT from here entirely - */ - private $patterns; + + /** @var BannerPattern[]|Deque */ + private $patterns = []; public function __construct(Level $level, Vector3 $pos){ $this->baseColor = DyeColor::BLACK(); - $this->patterns = new ListTag(self::TAG_PATTERNS); + $this->patterns = new Deque(); parent::__construct($level, $pos); } @@ -103,31 +62,37 @@ class Banner extends Spawnable implements Nameable{ $this->baseColor = DyeColor::fromMagicNumber($nbt->getInt(self::TAG_BASE), true); } - $this->patterns = $nbt->getListTag(self::TAG_PATTERNS) ?? $this->patterns; - $this->loadName($nbt); + $patterns = $nbt->getListTag(self::TAG_PATTERNS); + if($patterns !== null){ + /** @var CompoundTag $pattern */ + foreach($patterns as $pattern){ + $this->patterns[] = new BannerPattern($pattern->getString(self::TAG_PATTERN_NAME), DyeColor::fromMagicNumber($pattern->getInt(self::TAG_PATTERN_COLOR), true)); + } + } } protected function writeSaveData(CompoundTag $nbt) : void{ $nbt->setInt(self::TAG_BASE, $this->baseColor->getInvertedMagicNumber()); - $nbt->setTag($this->patterns); - $this->saveName($nbt); + $patterns = new ListTag(self::TAG_PATTERNS); + foreach($this->patterns as $pattern){ + $patterns->push(new CompoundTag("", [ + new StringTag(self::TAG_PATTERN_NAME, $pattern->getId()), + new IntTag(self::TAG_PATTERN_COLOR, $pattern->getColor()->getInvertedMagicNumber()) + ])); + } + $nbt->setTag($patterns); } protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ $nbt->setInt(self::TAG_BASE, $this->baseColor->getInvertedMagicNumber()); - $nbt->setTag($this->patterns); - $this->addNameSpawnData($nbt); - } - - public function copyDataFromItem(Item $item) : void{ - parent::copyDataFromItem($item); - $this->copyNameFromItem($item); - if($item instanceof ItemBanner){ - $this->setBaseColor($item->getColor()); - if(($patterns = $item->getPatterns()) !== null){ - $this->setPatterns($patterns); - } + $patterns = new ListTag(self::TAG_PATTERNS); + foreach($this->patterns as $pattern){ + $patterns->push(new CompoundTag("", [ + new StringTag(self::TAG_PATTERN_NAME, $pattern->getId()), + new IntTag(self::TAG_PATTERN_COLOR, $pattern->getColor()->getInvertedMagicNumber()) + ])); } + $nbt->setTag($patterns); } /** @@ -150,132 +115,17 @@ class Banner extends Spawnable implements Nameable{ } /** - * Applies a new pattern on the banner with the given color. - * - * @param string $pattern - * @param DyeColor $color - * - * @return int ID of pattern. + * @return BannerPattern[]|Deque */ - public function addPattern(string $pattern, DyeColor $color) : int{ - $this->patterns->push(new CompoundTag("", [ - new IntTag(self::TAG_PATTERN_COLOR, $color->getInvertedMagicNumber()), - new StringTag(self::TAG_PATTERN_NAME, $pattern) - ])); - - $this->onChanged(); - return $this->patterns->count() - 1; //Last offset in the list - } - - /** - * Returns whether a pattern with the given ID exists on the banner or not. - * - * @param int $patternId - * - * @return bool - */ - public function patternExists(int $patternId) : bool{ - return $this->patterns->isset($patternId); - } - - /** - * Returns the data of a pattern with the given ID. - * - * @param int $patternId - * - * @return array - */ - public function getPatternData(int $patternId) : array{ - if(!$this->patternExists($patternId)){ - return []; - } - - $patternTag = $this->patterns->get($patternId); - assert($patternTag instanceof CompoundTag); - - return [ - self::TAG_PATTERN_COLOR => DyeColor::fromMagicNumber($patternTag->getInt(self::TAG_PATTERN_COLOR), true), - self::TAG_PATTERN_NAME => $patternTag->getString(self::TAG_PATTERN_NAME) - ]; - } - - /** - * Changes the pattern of a previously existing pattern. - * - * @param int $patternId - * @param string $pattern - * @param DyeColor $color - * - * @return bool indicating success. - */ - public function changePattern(int $patternId, string $pattern, DyeColor $color) : bool{ - if(!$this->patternExists($patternId)){ - return false; - } - - $this->patterns->set($patternId, new CompoundTag("", [ - new IntTag(self::TAG_PATTERN_COLOR, $color->getInvertedMagicNumber()), - new StringTag(self::TAG_PATTERN_NAME, $pattern) - ])); - - $this->onChanged(); - return true; - } - - /** - * Deletes a pattern from the banner with the given ID. - * - * @param int $patternId - * - * @return bool indicating whether the pattern existed or not. - */ - public function deletePattern(int $patternId) : bool{ - if(!$this->patternExists($patternId)){ - return false; - } - - $this->patterns->remove($patternId); - - $this->onChanged(); - return true; - } - - /** - * Deletes the top most pattern of the banner. - * - * @return bool indicating whether the banner was empty or not. - */ - public function deleteTopPattern() : bool{ - return $this->deletePattern($this->getPatternCount() - 1); - } - - /** - * Deletes the bottom pattern of the banner. - * - * @return bool indicating whether the banner was empty or not. - */ - public function deleteBottomPattern() : bool{ - return $this->deletePattern(0); - } - - /** - * Returns the total count of patterns on this banner. - * - * @return int - */ - public function getPatternCount() : int{ - return $this->patterns->count(); - } - - /** - * @return ListTag - */ - public function getPatterns() : ListTag{ + public function getPatterns() : Deque{ return $this->patterns; } - public function setPatterns(ListTag $patterns) : void{ - $this->patterns = clone $patterns; + /** + * @param BannerPattern[]|Deque $patterns + */ + public function setPatterns(Deque $patterns) : void{ + $this->patterns = $patterns; $this->onChanged(); }