diff --git a/build/generate-runtime-enum-serializers.php b/build/generate-runtime-enum-serializers.php index 5907628f0..f71b87cdc 100644 --- a/build/generate-runtime-enum-serializers.php +++ b/build/generate-runtime-enum-serializers.php @@ -33,6 +33,7 @@ use pocketmine\block\utils\LeverFacing; use pocketmine\block\utils\MushroomBlockType; use pocketmine\block\utils\SkullType; use pocketmine\block\utils\SlabType; +use pocketmine\item\MedicineType; use pocketmine\item\PotionType; use pocketmine\item\SuspiciousStewType; use function array_key_first; @@ -166,6 +167,7 @@ $enumsUsed = [ DyeColor::getAll(), FroglightType::getAll(), LeverFacing::getAll(), + MedicineType::getAll(), MushroomBlockType::getAll(), SkullType::getAll(), SlabType::getAll(), diff --git a/src/data/bedrock/MedicineTypeIdMap.php b/src/data/bedrock/MedicineTypeIdMap.php new file mode 100644 index 000000000..a85dbb7a8 --- /dev/null +++ b/src/data/bedrock/MedicineTypeIdMap.php @@ -0,0 +1,66 @@ + + */ + private array $idToEnum = []; + + /** + * @var int[] + * @phpstan-var array + */ + private array $enumToId = []; + + private function __construct(){ + $this->register(MedicineTypeIds::ANTIDOTE, MedicineType::ANTIDOTE()); + $this->register(MedicineTypeIds::ELIXIR, MedicineType::ELIXIR()); + $this->register(MedicineTypeIds::EYE_DROPS, MedicineType::EYE_DROPS()); + $this->register(MedicineTypeIds::TONIC, MedicineType::TONIC()); + } + + private function register(int $id, MedicineType $type) : void{ + $this->idToEnum[$id] = $type; + $this->enumToId[$type->id()] = $id; + } + + public function fromId(int $id) : ?MedicineType{ + return $this->idToEnum[$id] ?? null; + } + + public function toId(MedicineType $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/MedicineTypeIds.php b/src/data/bedrock/MedicineTypeIds.php new file mode 100644 index 000000000..8c0110ec3 --- /dev/null +++ b/src/data/bedrock/MedicineTypeIds.php @@ -0,0 +1,31 @@ + DyeColorIdMap::getInstance()->toInvertedId($item->getColor()) ); + $this->map1to1ItemWithMeta( + Ids::MEDICINE, + Items::MEDICINE(), + function(Medicine $item, int $meta) : void{ + $item->setType(MedicineTypeIdMap::getInstance()->fromId($meta) ?? throw new ItemTypeDeserializeException("Unknown medicine type ID $meta")); + }, + fn(Medicine $item) => MedicineTypeIdMap::getInstance()->toId($item->getType()) + ); $this->map1to1ItemWithMeta( Ids::POTION, Items::POTION(), diff --git a/src/data/runtime/RuntimeEnumDeserializerTrait.php b/src/data/runtime/RuntimeEnumDeserializerTrait.php index bb83e805e..278cfc152 100644 --- a/src/data/runtime/RuntimeEnumDeserializerTrait.php +++ b/src/data/runtime/RuntimeEnumDeserializerTrait.php @@ -116,6 +116,16 @@ trait RuntimeEnumDeserializerTrait{ }; } + public function medicineType(\pocketmine\item\MedicineType &$value) : void{ + $value = match($this->readInt(2)){ + 0 => \pocketmine\item\MedicineType::ANTIDOTE(), + 1 => \pocketmine\item\MedicineType::ELIXIR(), + 2 => \pocketmine\item\MedicineType::EYE_DROPS(), + 3 => \pocketmine\item\MedicineType::TONIC(), + default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for MedicineType") + }; + } + public function mushroomBlockType(\pocketmine\block\utils\MushroomBlockType &$value) : void{ $value = match($this->readInt(4)){ 0 => \pocketmine\block\utils\MushroomBlockType::ALL_CAP(), diff --git a/src/data/runtime/RuntimeEnumSerializerTrait.php b/src/data/runtime/RuntimeEnumSerializerTrait.php index 91deba5e3..09a706e95 100644 --- a/src/data/runtime/RuntimeEnumSerializerTrait.php +++ b/src/data/runtime/RuntimeEnumSerializerTrait.php @@ -116,6 +116,16 @@ trait RuntimeEnumSerializerTrait{ }); } + public function medicineType(\pocketmine\item\MedicineType $value) : void{ + $this->int(2, match($value){ + \pocketmine\item\MedicineType::ANTIDOTE() => 0, + \pocketmine\item\MedicineType::ELIXIR() => 1, + \pocketmine\item\MedicineType::EYE_DROPS() => 2, + \pocketmine\item\MedicineType::TONIC() => 3, + default => throw new \pocketmine\utils\AssumptionFailedError("All MedicineType cases should be covered") + }); + } + public function mushroomBlockType(\pocketmine\block\utils\MushroomBlockType $value) : void{ $this->int(4, match($value){ \pocketmine\block\utils\MushroomBlockType::ALL_CAP() => 0, diff --git a/src/item/ItemTypeIds.php b/src/item/ItemTypeIds.php index cc4be26d4..b7eea8055 100644 --- a/src/item/ItemTypeIds.php +++ b/src/item/ItemTypeIds.php @@ -299,8 +299,9 @@ final class ItemTypeIds{ public const FIRE_CHARGE = 20260; public const SUSPICIOUS_STEW = 20261; public const TURTLE_HELMET = 20262; + public const MEDICINE = 20263; - public const FIRST_UNUSED_ITEM_ID = 20263; + public const FIRST_UNUSED_ITEM_ID = 20264; private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID; diff --git a/src/item/Medicine.php b/src/item/Medicine.php new file mode 100644 index 000000000..0915a19c1 --- /dev/null +++ b/src/item/Medicine.php @@ -0,0 +1,73 @@ +medicineType = MedicineType::EYE_DROPS(); + parent::__construct($identifier, $name); + } + + protected function describeType(RuntimeDataReader|RuntimeDataWriter $w) : void{ + $w->medicineType($this->medicineType); + } + + public function getType() : MedicineType{ return $this->medicineType; } + + /** + * @return $this + */ + public function setType(MedicineType $type) : self{ + $this->medicineType = $type; + return $this; + } + + public function getMaxStackSize() : int{ + return 1; + } + + public function onConsume(Living $consumer) : void{ + $consumer->getEffects()->remove($this->getType()->getCuredEffect()); + } + + public function getAdditionalEffects() : array{ + return []; + } + + public function getResidue() : Item{ + return VanillaItems::GLASS_BOTTLE(); + } + + public function canStartUsingItem(Player $player) : bool{ + return $player->getEffects()->has($this->getType()->getCuredEffect()); + } +} diff --git a/src/item/MedicineType.php b/src/item/MedicineType.php new file mode 100644 index 000000000..f7ce2b816 --- /dev/null +++ b/src/item/MedicineType.php @@ -0,0 +1,66 @@ +Enum___construct($enumName); + } + + public function getDisplayName() : string{ return $this->displayName; } + + public function getCuredEffect() : Effect{ return $this->curedEffect; } +} diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index 836371147..63baf3eff 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -1133,6 +1133,7 @@ final class StringToItemParser extends StringToTParser{ $result->register("acacia_boat", fn() => Items::ACACIA_BOAT()); $result->register("amethyst_shard", fn() => Items::AMETHYST_SHARD()); + $result->register("antidote", fn() => Items::MEDICINE()->setType(MedicineType::ANTIDOTE())); $result->register("apple", fn() => Items::APPLE()); $result->register("apple_enchanted", fn() => Items::ENCHANTED_GOLDEN_APPLE()); $result->register("appleenchanted", fn() => Items::ENCHANTED_GOLDEN_APPLE()); @@ -1248,11 +1249,13 @@ final class StringToItemParser extends StringToTParser{ $result->register("dye", fn() => Items::INK_SAC()); $result->register("echo_shard", fn() => Items::ECHO_SHARD()); $result->register("egg", fn() => Items::EGG()); + $result->register("elixir", fn() => Items::MEDICINE()->setType(MedicineType::ELIXIR())); $result->register("emerald", fn() => Items::EMERALD()); $result->register("enchanted_golden_apple", fn() => Items::ENCHANTED_GOLDEN_APPLE()); $result->register("enchanting_bottle", fn() => Items::EXPERIENCE_BOTTLE()); $result->register("ender_pearl", fn() => Items::ENDER_PEARL()); $result->register("experience_bottle", fn() => Items::EXPERIENCE_BOTTLE()); + $result->register("eye_drops", fn() => Items::MEDICINE()->setType(MedicineType::EYE_DROPS())); $result->register("feather", fn() => Items::FEATHER()); $result->register("fermented_spider_eye", fn() => Items::FERMENTED_SPIDER_EYE()); $result->register("fire_charge", fn() => Items::FIRE_CHARGE()); @@ -1492,6 +1495,7 @@ final class StringToItemParser extends StringToTParser{ $result->register("swiftness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::SWIFTNESS())); $result->register("thick_potion", fn() => Items::POTION()->setType(PotionType::THICK())); $result->register("thick_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::THICK())); + $result->register("tonic", fn() => Items::MEDICINE()->setType(MedicineType::TONIC())); $result->register("totem", fn() => Items::TOTEM()); $result->register("turtle_helmet", fn() => Items::TURTLE_HELMET()); $result->register("turtle_master_potion", fn() => Items::POTION()->setType(PotionType::TURTLE_MASTER())); diff --git a/src/item/VanillaItems.php b/src/item/VanillaItems.php index d39869f92..38d7eff9f 100644 --- a/src/item/VanillaItems.php +++ b/src/item/VanillaItems.php @@ -205,6 +205,7 @@ use pocketmine\world\World; * @method static Armor LEATHER_TUNIC() * @method static Item MAGMA_CREAM() * @method static ItemBlockWallOrFloor MANGROVE_SIGN() + * @method static Medicine MEDICINE() * @method static Melon MELON() * @method static MelonSeeds MELON_SEEDS() * @method static MilkBucket MILK_BUCKET() @@ -456,6 +457,7 @@ final class VanillaItems{ self::register("leather", new Item(new IID(Ids::LEATHER), "Leather")); self::register("magma_cream", new Item(new IID(Ids::MAGMA_CREAM), "Magma Cream")); self::register("mangrove_sign", new ItemBlockWallOrFloor(new IID(Ids::MANGROVE_SIGN), Blocks::MANGROVE_SIGN(), Blocks::MANGROVE_WALL_SIGN())); + self::register("medicine", new Medicine(new IID(Ids::MEDICINE), "Medicine")); self::register("melon", new Melon(new IID(Ids::MELON), "Melon")); self::register("melon_seeds", new MelonSeeds(new IID(Ids::MELON_SEEDS), "Melon Seeds")); self::register("milk_bucket", new MilkBucket(new IID(Ids::MILK_BUCKET), "Milk Bucket"));