From 68c408268c9f00dbbac080eb56f85b6f49f67e02 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 5 Jul 2020 19:04:22 +0100 Subject: [PATCH] Separate dye colour ID management from DyeColor enum --- src/block/Banner.php | 3 +- src/block/Bed.php | 3 +- src/block/BlockFactory.php | 20 +++---- src/block/tile/Banner.php | 16 +++--- src/block/tile/Bed.php | 7 +-- src/block/utils/DyeColor.php | 71 ++++++------------------- src/data/bedrock/DyeColorIdMap.php | 83 ++++++++++++++++++++++++++++++ src/item/Banner.php | 7 ++- src/item/ItemFactory.php | 8 +-- 9 files changed, 139 insertions(+), 79 deletions(-) create mode 100644 src/data/bedrock/DyeColorIdMap.php diff --git a/src/block/Banner.php b/src/block/Banner.php index c9ba9c5c9..683b90051 100644 --- a/src/block/Banner.php +++ b/src/block/Banner.php @@ -28,6 +28,7 @@ use pocketmine\block\tile\Banner as TileBanner; use pocketmine\block\utils\BannerPattern; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\DyeColor; +use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\item\Banner as ItemBanner; use pocketmine\item\Item; use pocketmine\item\ItemFactory; @@ -176,7 +177,7 @@ class Banner extends Transparent{ } public function asItem() : Item{ - return ItemFactory::getInstance()->get(ItemIds::BANNER, $this->baseColor->getInvertedMagicNumber()); + return ItemFactory::getInstance()->get(ItemIds::BANNER, DyeColorIdMap::getInstance()->toInvertedId($this->baseColor)); } public function getDropsForCompatibleTool(Item $item) : array{ diff --git a/src/block/Bed.php b/src/block/Bed.php index 57c643fef..5c457641c 100644 --- a/src/block/Bed.php +++ b/src/block/Bed.php @@ -26,6 +26,7 @@ namespace pocketmine\block; use pocketmine\block\tile\Bed as TileBed; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\DyeColor; +use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\item\Bed as ItemBed; use pocketmine\item\Item; use pocketmine\item\ItemFactory; @@ -193,7 +194,7 @@ class Bed extends Transparent{ } public function asItem() : Item{ - return ItemFactory::getInstance()->get($this->idInfo->getItemId(), $this->color->getMagicNumber()); + return ItemFactory::getInstance()->get($this->idInfo->getItemId(), DyeColorIdMap::getInstance()->toId($this->color)); } public function getAffectedBlocks() : array{ diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index 1864f5dd9..32b7f2f8a 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -46,6 +46,7 @@ use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\InvalidBlockStateException; use pocketmine\block\utils\PillarRotationTrait; use pocketmine\block\utils\TreeType; +use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\item\Item; use pocketmine\item\ItemIds; use pocketmine\item\ToolTier; @@ -451,17 +452,18 @@ class BlockFactory{ $this->register(new Opaque(new BID(Ids::RED_SANDSTONE, $variant), $prefix . "Red Sandstone", $sandstoneBreakInfo)); } + $colorIdMap = DyeColorIdMap::getInstance(); foreach(DyeColor::getAll() as $color){ - $this->register(new Carpet(new BID(Ids::CARPET, $color->getMagicNumber()), $color->getDisplayName() . " Carpet")); - $this->register(new Concrete(new BID(Ids::CONCRETE, $color->getMagicNumber()), $color->getDisplayName() . " Concrete")); - $this->register(new ConcretePowder(new BID(Ids::CONCRETE_POWDER, $color->getMagicNumber()), $color->getDisplayName() . " Concrete Powder")); - $this->register(new Glass(new BID(Ids::STAINED_GLASS, $color->getMagicNumber()), $color->getDisplayName() . " Stained Glass")); - $this->register(new GlassPane(new BID(Ids::STAINED_GLASS_PANE, $color->getMagicNumber()), $color->getDisplayName() . " Stained Glass Pane")); + $this->register(new Carpet(new BID(Ids::CARPET, $colorIdMap->toId($color)), $color->getDisplayName() . " Carpet")); + $this->register(new Concrete(new BID(Ids::CONCRETE, $colorIdMap->toId($color)), $color->getDisplayName() . " Concrete")); + $this->register(new ConcretePowder(new BID(Ids::CONCRETE_POWDER, $colorIdMap->toId($color)), $color->getDisplayName() . " Concrete Powder")); + $this->register(new Glass(new BID(Ids::STAINED_GLASS, $colorIdMap->toId($color)), $color->getDisplayName() . " Stained Glass")); + $this->register(new GlassPane(new BID(Ids::STAINED_GLASS_PANE, $colorIdMap->toId($color)), $color->getDisplayName() . " Stained Glass Pane")); $this->register(new GlazedTerracotta(BlockLegacyIdHelper::getGlazedTerracottaIdentifier($color), $color->getDisplayName() . " Glazed Terracotta")); - $this->register(new HardenedClay(new BID(Ids::STAINED_CLAY, $color->getMagicNumber()), $color->getDisplayName() . " Stained Clay")); - $this->register(new HardenedGlass(new BID(Ids::HARD_STAINED_GLASS, $color->getMagicNumber()), "Hardened " . $color->getDisplayName() . " Stained Glass")); - $this->register(new HardenedGlassPane(new BID(Ids::HARD_STAINED_GLASS_PANE, $color->getMagicNumber()), "Hardened " . $color->getDisplayName() . " Stained Glass Pane")); - $this->register(new Wool(new BID(Ids::WOOL, $color->getMagicNumber()), $color->getDisplayName() . " Wool")); + $this->register(new HardenedClay(new BID(Ids::STAINED_CLAY, $colorIdMap->toId($color)), $color->getDisplayName() . " Stained Clay")); + $this->register(new HardenedGlass(new BID(Ids::HARD_STAINED_GLASS, $colorIdMap->toId($color)), "Hardened " . $color->getDisplayName() . " Stained Glass")); + $this->register(new HardenedGlassPane(new BID(Ids::HARD_STAINED_GLASS_PANE, $colorIdMap->toId($color)), "Hardened " . $color->getDisplayName() . " Stained Glass Pane")); + $this->register(new Wool(new BID(Ids::WOOL, $colorIdMap->toId($color)), $color->getDisplayName() . " Wool")); } $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_ANDESITE), "Andesite Wall")); diff --git a/src/block/tile/Banner.php b/src/block/tile/Banner.php index e72ee276d..ec9d17ca8 100644 --- a/src/block/tile/Banner.php +++ b/src/block/tile/Banner.php @@ -26,6 +26,7 @@ namespace pocketmine\block\tile; use Ds\Deque; use pocketmine\block\utils\BannerPattern; use pocketmine\block\utils\DyeColor; +use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; @@ -59,38 +60,41 @@ class Banner extends Spawnable{ } public function readSaveData(CompoundTag $nbt) : void{ + $colorIdMap = DyeColorIdMap::getInstance(); if($nbt->hasTag(self::TAG_BASE, IntTag::class)){ - $this->baseColor = DyeColor::fromMagicNumber($nbt->getInt(self::TAG_BASE), true); + $this->baseColor = $colorIdMap->fromInvertedId($nbt->getInt(self::TAG_BASE)); } $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)); + $this->patterns[] = new BannerPattern($pattern->getString(self::TAG_PATTERN_NAME), $colorIdMap->fromInvertedId($pattern->getInt(self::TAG_PATTERN_COLOR))); } } } protected function writeSaveData(CompoundTag $nbt) : void{ - $nbt->setInt(self::TAG_BASE, $this->baseColor->getInvertedMagicNumber()); + $colorIdMap = DyeColorIdMap::getInstance(); + $nbt->setInt(self::TAG_BASE, $colorIdMap->toInvertedId($this->baseColor)); $patterns = new ListTag(); foreach($this->patterns as $pattern){ $patterns->push(CompoundTag::create() ->setString(self::TAG_PATTERN_NAME, $pattern->getId()) - ->setInt(self::TAG_PATTERN_COLOR, $pattern->getColor()->getInvertedMagicNumber()) + ->setInt(self::TAG_PATTERN_COLOR, $colorIdMap->toInvertedId($pattern->getColor())) ); } $nbt->setTag(self::TAG_PATTERNS, $patterns); } protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ - $nbt->setInt(self::TAG_BASE, $this->baseColor->getInvertedMagicNumber()); + $colorIdMap = DyeColorIdMap::getInstance(); + $nbt->setInt(self::TAG_BASE, $colorIdMap->toInvertedId($this->baseColor)); $patterns = new ListTag(); foreach($this->patterns as $pattern){ $patterns->push(CompoundTag::create() ->setString(self::TAG_PATTERN_NAME, $pattern->getId()) - ->setInt(self::TAG_PATTERN_COLOR, $pattern->getColor()->getInvertedMagicNumber()) + ->setInt(self::TAG_PATTERN_COLOR, $colorIdMap->toInvertedId($pattern->getColor())) ); } $nbt->setTag(self::TAG_PATTERNS, $patterns); diff --git a/src/block/tile/Bed.php b/src/block/tile/Bed.php index 28b68ee62..b41489787 100644 --- a/src/block/tile/Bed.php +++ b/src/block/tile/Bed.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block\tile; use pocketmine\block\utils\DyeColor; +use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\math\Vector3; use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; @@ -49,15 +50,15 @@ class Bed extends Spawnable{ public function readSaveData(CompoundTag $nbt) : void{ if($nbt->hasTag(self::TAG_COLOR, ByteTag::class)){ - $this->color = DyeColor::fromMagicNumber($nbt->getByte(self::TAG_COLOR)); + $this->color = DyeColorIdMap::getInstance()->fromId($nbt->getByte(self::TAG_COLOR)); } } protected function writeSaveData(CompoundTag $nbt) : void{ - $nbt->setByte(self::TAG_COLOR, $this->color->getMagicNumber()); + $nbt->setByte(self::TAG_COLOR, DyeColorIdMap::getInstance()->toId($this->color)); } protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ - $nbt->setByte(self::TAG_COLOR, $this->color->getMagicNumber()); + $nbt->setByte(self::TAG_COLOR, DyeColorIdMap::getInstance()->toId($this->color)); } } diff --git a/src/block/utils/DyeColor.php b/src/block/utils/DyeColor.php index 855f8659c..0c0761d61 100644 --- a/src/block/utils/DyeColor.php +++ b/src/block/utils/DyeColor.php @@ -50,67 +50,38 @@ use pocketmine\utils\EnumTrait; */ final class DyeColor{ use EnumTrait { - register as Enum_register; __construct as Enum___construct; } - /** @var DyeColor[] */ - private static $numericIdMap = []; - protected static function setup() : void{ self::registerAll( - new DyeColor("white", "White", 0, new Color(0xf0, 0xf0, 0xf0)), - new DyeColor("orange", "Orange", 1, new Color(0xf9, 0x80, 0x1d)), - new DyeColor("magenta", "Magenta", 2, new Color(0xc7, 0x4e, 0xbd)), - new DyeColor("light_blue", "Light Blue", 3, new Color(0x3a, 0xb3, 0xda)), - new DyeColor("yellow", "Yellow", 4, new Color(0xfe, 0xd8, 0x3d)), - new DyeColor("lime", "Lime", 5, new Color(0x80, 0xc7, 0x1f)), - new DyeColor("pink", "Pink", 6, new Color(0xf3, 0x8b, 0xaa)), - new DyeColor("gray", "Gray", 7, new Color(0x47, 0x4f, 0x52)), - new DyeColor("light_gray", "Light Gray", 8, new Color(0x9d, 0x9d, 0x97)), - new DyeColor("cyan", "Cyan", 9, new Color(0x16, 0x9c, 0x9c)), - new DyeColor("purple", "Purple", 10, new Color(0x89, 0x32, 0xb8)), - new DyeColor("blue", "Blue", 11, new Color(0x3c, 0x44, 0xaa)), - new DyeColor("brown", "Brown", 12, new Color(0x83, 0x54, 0x32)), - new DyeColor("green", "Green", 13, new Color(0x5e, 0x7c, 0x16)), - new DyeColor("red", "Red", 14, new Color(0xb0, 0x2e, 0x26)), - new DyeColor("black", "Black", 15, new Color(0x1d, 0x1d, 0x21)) + new DyeColor("white", "White", new Color(0xf0, 0xf0, 0xf0)), + new DyeColor("orange", "Orange", new Color(0xf9, 0x80, 0x1d)), + new DyeColor("magenta", "Magenta", new Color(0xc7, 0x4e, 0xbd)), + new DyeColor("light_blue", "Light Blue", new Color(0x3a, 0xb3, 0xda)), + new DyeColor("yellow", "Yellow", new Color(0xfe, 0xd8, 0x3d)), + new DyeColor("lime", "Lime", new Color(0x80, 0xc7, 0x1f)), + new DyeColor("pink", "Pink", new Color(0xf3, 0x8b, 0xaa)), + new DyeColor("gray", "Gray", new Color(0x47, 0x4f, 0x52)), + new DyeColor("light_gray", "Light Gray", new Color(0x9d, 0x9d, 0x97)), + new DyeColor("cyan", "Cyan", new Color(0x16, 0x9c, 0x9c)), + new DyeColor("purple", "Purple", new Color(0x89, 0x32, 0xb8)), + new DyeColor("blue", "Blue", new Color(0x3c, 0x44, 0xaa)), + new DyeColor("brown", "Brown", new Color(0x83, 0x54, 0x32)), + new DyeColor("green", "Green", new Color(0x5e, 0x7c, 0x16)), + new DyeColor("red", "Red", new Color(0xb0, 0x2e, 0x26)), + new DyeColor("black", "Black", new Color(0x1d, 0x1d, 0x21)) ); } - protected static function register(DyeColor $color) : void{ - self::Enum_register($color); - self::$numericIdMap[$color->getMagicNumber()] = $color; - } - - /** - * Returns a DyeColor object matching the given magic number - * @internal - * - * @param bool $inverted Invert the ID before using it (useful for actual dye magic IDs) - * - * @throws \InvalidArgumentException - */ - public static function fromMagicNumber(int $magicNumber, bool $inverted = false) : DyeColor{ - self::checkInit(); - $real = $inverted ? ~$magicNumber & 0xf : $magicNumber; - if(!isset(self::$numericIdMap[$real])){ - throw new \InvalidArgumentException("Unknown dye colour magic number $magicNumber"); - } - return self::$numericIdMap[$real]; - } - /** @var string */ private $displayName; - /** @var int */ - private $magicNumber; /** @var Color */ private $rgbValue; - private function __construct(string $enumName, string $displayName, int $magicNumber, Color $rgbValue){ + private function __construct(string $enumName, string $displayName, Color $rgbValue){ $this->Enum___construct($enumName); $this->displayName = $displayName; - $this->magicNumber = $magicNumber; $this->rgbValue = $rgbValue; } @@ -121,12 +92,4 @@ final class DyeColor{ public function getRgbValue() : Color{ return $this->rgbValue; } - - public function getMagicNumber() : int{ - return $this->magicNumber; - } - - public function getInvertedMagicNumber() : int{ - return ~$this->magicNumber & 0xf; - } } diff --git a/src/data/bedrock/DyeColorIdMap.php b/src/data/bedrock/DyeColorIdMap.php new file mode 100644 index 000000000..a96b19f65 --- /dev/null +++ b/src/data/bedrock/DyeColorIdMap.php @@ -0,0 +1,83 @@ + + */ + private $idToEnum = []; + + /** + * @var int[] + * @phpstan-var array + */ + private $enumToId = []; + + private function __construct(){ + $this->register(0, DyeColor::WHITE()); + $this->register(1, DyeColor::ORANGE()); + $this->register(2, DyeColor::MAGENTA()); + $this->register(3, DyeColor::LIGHT_BLUE()); + $this->register(4, DyeColor::YELLOW()); + $this->register(5, DyeColor::LIME()); + $this->register(6, DyeColor::PINK()); + $this->register(7, DyeColor::GRAY()); + $this->register(8, DyeColor::LIGHT_GRAY()); + $this->register(9, DyeColor::CYAN()); + $this->register(10, DyeColor::PURPLE()); + $this->register(11, DyeColor::BLUE()); + $this->register(12, DyeColor::BROWN()); + $this->register(13, DyeColor::GREEN()); + $this->register(14, DyeColor::RED()); + $this->register(15, DyeColor::BLACK()); + } + + private function register(int $id, DyeColor $color) : void{ + $this->idToEnum[$id] = $color; + $this->enumToId[$color->id()] = $id; + } + + public function toId(DyeColor $color) : int{ + return $this->enumToId[$color->id()]; //TODO: is it possible for this to be missing? + } + + public function toInvertedId(DyeColor $color) : int{ + return ~$this->toId($color) & 0xf; + } + + public function fromId(int $id) : DyeColor{ + return $this->idToEnum[$id]; //TODO: this might not be present (e.g. corrupted data) + } + + public function fromInvertedId(int $id) : DyeColor{ + return $this->fromId(~$id & 0xf); + } +} diff --git a/src/item/Banner.php b/src/item/Banner.php index e534a5109..3a659fa08 100644 --- a/src/item/Banner.php +++ b/src/item/Banner.php @@ -29,6 +29,7 @@ use pocketmine\block\tile\Banner as TileBanner; use pocketmine\block\utils\BannerPattern; use pocketmine\block\utils\DyeColor; use pocketmine\block\VanillaBlocks; +use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\ListTag; @@ -93,11 +94,12 @@ class Banner extends Item{ $this->patterns = new Deque(); + $colorIdMap = DyeColorIdMap::getInstance(); $patterns = $tag->getListTag(self::TAG_PATTERNS); if($patterns !== null){ /** @var CompoundTag $t */ foreach($patterns as $t){ - $this->patterns->push(new BannerPattern($t->getString(self::TAG_PATTERN_NAME), DyeColor::fromMagicNumber($t->getInt(self::TAG_PATTERN_COLOR), true))); + $this->patterns->push(new BannerPattern($t->getString(self::TAG_PATTERN_NAME), $colorIdMap->fromInvertedId($t->getInt(self::TAG_PATTERN_COLOR)))); } } } @@ -107,11 +109,12 @@ class Banner extends Item{ if(!$this->patterns->isEmpty()){ $patterns = new ListTag(); + $colorIdMap = DyeColorIdMap::getInstance(); /** @var BannerPattern $pattern */ foreach($this->patterns as $pattern){ $patterns->push(CompoundTag::create() ->setString(self::TAG_PATTERN_NAME, $pattern->getId()) - ->setInt(self::TAG_PATTERN_COLOR, $pattern->getColor()->getInvertedMagicNumber()) + ->setInt(self::TAG_PATTERN_COLOR, $colorIdMap->toInvertedId($pattern->getColor())) ); } diff --git a/src/item/ItemFactory.php b/src/item/ItemFactory.php index c7bcee89b..479fe661c 100644 --- a/src/item/ItemFactory.php +++ b/src/item/ItemFactory.php @@ -29,6 +29,7 @@ use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\SkullType; use pocketmine\block\utils\TreeType; use pocketmine\block\VanillaBlocks; +use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\entity\Entity; use pocketmine\entity\Location; use pocketmine\entity\Squid; @@ -243,12 +244,13 @@ class ItemFactory{ DyeColor::BLUE()->id() => 18, DyeColor::WHITE()->id() => 19 ]; + $colorIdMap = DyeColorIdMap::getInstance(); foreach(DyeColor::getAll() as $color){ //TODO: use colour object directly //TODO: add interface to dye-colour objects - $this->register(new Dye(new ItemIdentifier(ItemIds::DYE, $dyeMap[$color->id()] ?? $color->getInvertedMagicNumber()), $color->getDisplayName() . " Dye", $color)); - $this->register(new Bed(new ItemIdentifier(ItemIds::BED, $color->getMagicNumber()), $color->getDisplayName() . " Bed", $color)); - $this->register(new Banner(new ItemIdentifier(ItemIds::BANNER, $color->getInvertedMagicNumber()), $color->getDisplayName() . " Banner", $color)); + $this->register(new Dye(new ItemIdentifier(ItemIds::DYE, $dyeMap[$color->id()] ?? $colorIdMap->toInvertedId($color)), $color->getDisplayName() . " Dye", $color)); + $this->register(new Bed(new ItemIdentifier(ItemIds::BED, $colorIdMap->toId($color)), $color->getDisplayName() . " Bed", $color)); + $this->register(new Banner(new ItemIdentifier(ItemIds::BANNER, $colorIdMap->toInvertedId($color)), $color->getDisplayName() . " Banner", $color)); } foreach(Potion::ALL as $type){