diff --git a/src/block/tile/MobHead.php b/src/block/tile/MobHead.php index 35a82e834..70a199bf6 100644 --- a/src/block/tile/MobHead.php +++ b/src/block/tile/MobHead.php @@ -24,6 +24,8 @@ declare(strict_types=1); namespace pocketmine\block\tile; use pocketmine\block\utils\MobHeadType; +use pocketmine\data\bedrock\MobHeadTypeIdMap; +use pocketmine\data\SavedDataLoadingException; use pocketmine\math\Vector3; use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; @@ -50,11 +52,11 @@ class MobHead extends Spawnable{ public function readSaveData(CompoundTag $nbt) : void{ if(($skullTypeTag = $nbt->getTag(self::TAG_SKULL_TYPE)) instanceof ByteTag){ - try{ - $this->mobHeadType = MobHeadType::fromMagicNumber($skullTypeTag->getValue()); - }catch(\InvalidArgumentException $e){ - //bad data, drop it + $mobHeadType = MobHeadTypeIdMap::getInstance()->fromId($skullTypeTag->getValue()); + if($mobHeadType === null){ + throw new SavedDataLoadingException("Invalid skull type tag value " . $skullTypeTag->getValue()); } + $this->mobHeadType = $mobHeadType; } $rotation = $nbt->getByte(self::TAG_ROT, 0); if($rotation >= 0 && $rotation <= 15){ @@ -63,7 +65,7 @@ class MobHead extends Spawnable{ } protected function writeSaveData(CompoundTag $nbt) : void{ - $nbt->setByte(self::TAG_SKULL_TYPE, $this->mobHeadType->getMagicNumber()); + $nbt->setByte(self::TAG_SKULL_TYPE, MobHeadTypeIdMap::getInstance()->toId($this->mobHeadType)); $nbt->setByte(self::TAG_ROT, $this->rotation); } @@ -84,7 +86,7 @@ class MobHead extends Spawnable{ } protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ - $nbt->setByte(self::TAG_SKULL_TYPE, $this->mobHeadType->getMagicNumber()); + $nbt->setByte(self::TAG_SKULL_TYPE, MobHeadTypeIdMap::getInstance()->toId($this->mobHeadType)); $nbt->setByte(self::TAG_ROT, $this->rotation); } } diff --git a/src/block/utils/MobHeadType.php b/src/block/utils/MobHeadType.php index 3259a0757..45d31e9bb 100644 --- a/src/block/utils/MobHeadType.php +++ b/src/block/utils/MobHeadType.php @@ -40,45 +40,23 @@ use pocketmine\utils\EnumTrait; */ final class MobHeadType{ use EnumTrait { - register as Enum_register; __construct as Enum___construct; } - /** @var MobHeadType[] */ - private static array $numericIdMap = []; - protected static function setup() : void{ self::registerAll( - new MobHeadType("skeleton", "Skeleton Skull", 0), - new MobHeadType("wither_skeleton", "Wither Skeleton Skull", 1), - new MobHeadType("zombie", "Zombie Head", 2), - new MobHeadType("player", "Player Head", 3), - new MobHeadType("creeper", "Creeper Head", 4), - new MobHeadType("dragon", "Dragon Head", 5) + new MobHeadType("skeleton", "Skeleton Skull"), + new MobHeadType("wither_skeleton", "Wither Skeleton Skull"), + new MobHeadType("zombie", "Zombie Head"), + new MobHeadType("player", "Player Head"), + new MobHeadType("creeper", "Creeper Head"), + new MobHeadType("dragon", "Dragon Head") ); } - protected static function register(MobHeadType $type) : void{ - self::Enum_register($type); - self::$numericIdMap[$type->getMagicNumber()] = $type; - } - - /** - * @internal - * - * @throws \InvalidArgumentException - */ - public static function fromMagicNumber(int $magicNumber) : MobHeadType{ - if(!isset(self::$numericIdMap[$magicNumber])){ - throw new \InvalidArgumentException("Unknown skull type magic number $magicNumber"); - } - return self::$numericIdMap[$magicNumber]; - } - private function __construct( string $enumName, - private string $displayName, - private int $magicNumber + private string $displayName ){ $this->Enum___construct($enumName); } @@ -86,8 +64,4 @@ final class MobHeadType{ public function getDisplayName() : string{ return $this->displayName; } - - public function getMagicNumber() : int{ - return $this->magicNumber; - } } diff --git a/src/data/bedrock/MobHeadTypeIdMap.php b/src/data/bedrock/MobHeadTypeIdMap.php new file mode 100644 index 000000000..9b9fe2c06 --- /dev/null +++ b/src/data/bedrock/MobHeadTypeIdMap.php @@ -0,0 +1,68 @@ + + */ + private array $idToEnum = []; + + /** + * @var int[] + * @phpstan-var array + */ + private array $enumToId = []; + + private function __construct(){ + $this->register(0, MobHeadType::SKELETON()); + $this->register(1, MobHeadType::WITHER_SKELETON()); + $this->register(2, MobHeadType::ZOMBIE()); + $this->register(3, MobHeadType::PLAYER()); + $this->register(4, MobHeadType::CREEPER()); + $this->register(5, MobHeadType::DRAGON()); + } + + private function register(int $id, MobHeadType $type) : void{ + $this->idToEnum[$id] = $type; + $this->enumToId[$type->id()] = $id; + } + + public function fromId(int $id) : ?MobHeadType{ + return $this->idToEnum[$id] ?? null; + } + + public function toId(MobHeadType $type) : int{ + if(!isset($this->enumToId[$type->id()])){ + throw new \InvalidArgumentException("Type does not have a mapped ID"); + } + return $this->enumToId[$type->id()]; + } +} diff --git a/src/data/bedrock/NoteInstrumentIdMap.php b/src/data/bedrock/NoteInstrumentIdMap.php new file mode 100644 index 000000000..b9a647053 --- /dev/null +++ b/src/data/bedrock/NoteInstrumentIdMap.php @@ -0,0 +1,67 @@ + + */ + private array $idToEnum = []; + + /** + * @var int[] + * @phpstan-var array + */ + private array $enumToId = []; + + private function __construct(){ + $this->register(0, NoteInstrument::PIANO()); + $this->register(1, NoteInstrument::BASS_DRUM()); + $this->register(2, NoteInstrument::SNARE()); + $this->register(3, NoteInstrument::CLICKS_AND_STICKS()); + $this->register(4, NoteInstrument::DOUBLE_BASS()); + } + + private function register(int $id, NoteInstrument $instrument) : void{ + $this->idToEnum[$id] = $instrument; + $this->enumToId[$instrument->id()] = $id; + } + + public function fromId(int $id) : ?NoteInstrument{ + return $this->idToEnum[$id] ?? null; + } + + public function toId(NoteInstrument $instrument) : int{ + if(!isset($this->enumToId[$instrument->id()])){ + throw new \InvalidArgumentException("Type does not have a mapped ID"); + } + return $this->enumToId[$instrument->id()]; + } +} diff --git a/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php b/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php index 699c7e393..7e2e3bad0 100644 --- a/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php +++ b/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php @@ -27,13 +27,13 @@ use pocketmine\block\Bed; use pocketmine\block\Block; use pocketmine\block\MobHead; use pocketmine\block\utils\DyeColor; -use pocketmine\block\utils\MobHeadType; use pocketmine\block\VanillaBlocks as Blocks; use pocketmine\data\bedrock\CompoundTypeIds; use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\data\bedrock\item\ItemTypeNames as Ids; use pocketmine\data\bedrock\item\SavedItemData as Data; use pocketmine\data\bedrock\MedicineTypeIdMap; +use pocketmine\data\bedrock\MobHeadTypeIdMap; use pocketmine\data\bedrock\PotionTypeIdMap; use pocketmine\data\bedrock\SuspiciousStewTypeIdMap; use pocketmine\item\Banner; @@ -445,14 +445,9 @@ final class ItemSerializerDeserializerRegistrar{ Ids::SKULL, Blocks::MOB_HEAD(), function(MobHead $block, int $meta) : void{ - try{ - $skullType = MobHeadType::fromMagicNumber($meta); - }catch(\InvalidArgumentException $e){ - throw new ItemTypeDeserializeException($e->getMessage(), 0, $e); - } - $block->setMobHeadType($skullType); + $block->setMobHeadType(MobHeadTypeIdMap::getInstance()->fromId($meta) ?? throw new ItemTypeDeserializeException("Unknown mob head type ID $meta")); }, - fn(MobHead $block) => $block->getMobHeadType()->getMagicNumber() + fn(MobHead $block) => MobHeadTypeIdMap::getInstance()->toId($block->getMobHeadType()) ); } diff --git a/src/world/sound/NoteInstrument.php b/src/world/sound/NoteInstrument.php index 06053c566..824f9e3c4 100644 --- a/src/world/sound/NoteInstrument.php +++ b/src/world/sound/NoteInstrument.php @@ -38,28 +38,15 @@ use pocketmine\utils\EnumTrait; * @method static NoteInstrument SNARE() */ final class NoteInstrument{ - use EnumTrait { - __construct as Enum___construct; - } + use EnumTrait; protected static function setup() : void{ self::registerAll( - new self("piano", 0), - new self("bass_drum", 1), - new self("snare", 2), - new self("clicks_and_sticks", 3), - new self("double_bass", 4) + new self("piano"), + new self("bass_drum"), + new self("snare"), + new self("clicks_and_sticks"), + new self("double_bass") ); } - - private function __construct( - string $name, - private int $magicNumber - ){ - $this->Enum___construct($name); - } - - public function getMagicNumber() : int{ - return $this->magicNumber; - } } diff --git a/src/world/sound/NoteSound.php b/src/world/sound/NoteSound.php index b0459bdbe..608256709 100644 --- a/src/world/sound/NoteSound.php +++ b/src/world/sound/NoteSound.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\world\sound; +use pocketmine\data\bedrock\NoteInstrumentIdMap; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; @@ -38,6 +39,7 @@ class NoteSound implements Sound{ } public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::NOTE, $pos, false, ($this->instrument->getMagicNumber() << 8) | $this->note)]; + $instrumentId = NoteInstrumentIdMap::getInstance()->toId($this->instrument); + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::NOTE, $pos, false, ($instrumentId << 8) | $this->note)]; } }