From 7afebb7fb639552dc8ab2a358dba3ce5e14fea37 Mon Sep 17 00:00:00 2001 From: Jake Potrebic <jake.m.potrebic@gmail.com> Date: Thu, 13 Jul 2023 13:09:26 -0700 Subject: [PATCH] Fix missing item types in SlotType for armor change event (#9379) Also added 2 parameterized tests to make sure this doesn't happen again. --- patches/api/Add-PlayerArmorChangeEvent.patch | 2 +- .../server/Add-PlayerArmorChangeEvent.patch | 122 ++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/patches/api/Add-PlayerArmorChangeEvent.patch b/patches/api/Add-PlayerArmorChangeEvent.patch index 89310f2072..86ff09fbe5 100644 --- a/patches/api/Add-PlayerArmorChangeEvent.patch +++ b/patches/api/Add-PlayerArmorChangeEvent.patch @@ -93,7 +93,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public enum SlotType { -+ HEAD(NETHERITE_HELMET, DIAMOND_HELMET, GOLDEN_HELMET, IRON_HELMET, CHAINMAIL_HELMET, LEATHER_HELMET, CARVED_PUMPKIN, PLAYER_HEAD, SKELETON_SKULL, ZOMBIE_HEAD, CREEPER_HEAD, WITHER_SKELETON_SKULL, TURTLE_HELMET), ++ HEAD(NETHERITE_HELMET, DIAMOND_HELMET, GOLDEN_HELMET, IRON_HELMET, CHAINMAIL_HELMET, LEATHER_HELMET, CARVED_PUMPKIN, PLAYER_HEAD, SKELETON_SKULL, ZOMBIE_HEAD, CREEPER_HEAD, WITHER_SKELETON_SKULL, TURTLE_HELMET, DRAGON_HEAD, PIGLIN_HEAD), + CHEST(NETHERITE_CHESTPLATE, DIAMOND_CHESTPLATE, GOLDEN_CHESTPLATE, IRON_CHESTPLATE, CHAINMAIL_CHESTPLATE, LEATHER_CHESTPLATE, ELYTRA), + LEGS(NETHERITE_LEGGINGS, DIAMOND_LEGGINGS, GOLDEN_LEGGINGS, IRON_LEGGINGS, CHAINMAIL_LEGGINGS, LEATHER_LEGGINGS), + FEET(NETHERITE_BOOTS, DIAMOND_BOOTS, GOLDEN_BOOTS, IRON_BOOTS, CHAINMAIL_BOOTS, LEATHER_BOOTS); diff --git a/patches/server/Add-PlayerArmorChangeEvent.patch b/patches/server/Add-PlayerArmorChangeEvent.patch index 3215e776f5..71214f825b 100644 --- a/patches/server/Add-PlayerArmorChangeEvent.patch +++ b/patches/server/Add-PlayerArmorChangeEvent.patch @@ -29,3 +29,125 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (map == null) { map = Maps.newEnumMap(EquipmentSlot.class); } +diff --git a/src/test/java/io/papermc/paper/inventory/item/ExtraArmorSlotTypeMaterialTest.java b/src/test/java/io/papermc/paper/inventory/item/ExtraArmorSlotTypeMaterialTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/inventory/item/ExtraArmorSlotTypeMaterialTest.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.inventory.item; ++ ++import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent; ++import java.util.ArrayList; ++import java.util.List; ++import net.minecraft.world.entity.EquipmentSlot; ++import net.minecraft.world.item.Equipable; ++import net.minecraft.world.item.Item; ++import net.minecraft.world.item.ItemStack; ++import org.bukkit.Material; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.support.AbstractTestingBase; ++import org.junit.Test; ++import org.junit.runner.RunWith; ++import org.junit.runners.Parameterized; ++ ++import static org.junit.Assert.assertEquals; ++import static org.junit.Assert.assertNotNull; ++ ++@RunWith(Parameterized.class) ++public class ExtraArmorSlotTypeMaterialTest extends AbstractTestingBase { ++ ++ @Parameterized.Parameter(0) ++ public PlayerArmorChangeEvent.SlotType slotType; ++ ++ @Parameterized.Parameter(1) ++ public Material item; ++ ++ @Parameterized.Parameters(name = "{0}: {1}") ++ public static Iterable<Object[]> parameters() { ++ final List<Object[]> parameters = new ArrayList<>(); ++ for (final PlayerArmorChangeEvent.SlotType slotType : PlayerArmorChangeEvent.SlotType.values()) { ++ for (final Material item : slotType.getTypes()) { ++ parameters.add(new Object[]{ slotType, item }); ++ } ++ } ++ return parameters; ++ } ++ ++ @Test ++ public void test() { ++ final Item nmsItem = CraftMagicNumbers.getItem(this.item); ++ final Equipable equipable = Equipable.get(new ItemStack(nmsItem)); ++ assertNotNull(this.item + " isn't equipable", equipable); ++ final EquipmentSlot slot = switch (this.slotType) { ++ case HEAD -> EquipmentSlot.HEAD; ++ case CHEST -> EquipmentSlot.CHEST; ++ case LEGS -> EquipmentSlot.LEGS; ++ case FEET -> EquipmentSlot.FEET; ++ }; ++ assertEquals(this.item + " isn't set to the right slot", equipable.getEquipmentSlot(), slot); ++ } ++} +diff --git a/src/test/java/io/papermc/paper/inventory/item/MissingArmorSlotTypeMaterialTest.java b/src/test/java/io/papermc/paper/inventory/item/MissingArmorSlotTypeMaterialTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/inventory/item/MissingArmorSlotTypeMaterialTest.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.inventory.item; ++ ++import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent; ++import java.util.ArrayList; ++import java.util.List; ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.world.entity.EquipmentSlot; ++import net.minecraft.world.item.Equipable; ++import net.minecraft.world.item.Item; ++import net.minecraft.world.item.ItemStack; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.support.AbstractTestingBase; ++import org.junit.Test; ++import org.junit.runner.RunWith; ++import org.junit.runners.Parameterized; ++ ++import static org.junit.Assert.assertTrue; ++ ++/** ++ * Test for {@link com.destroystokyo.paper.event.player.PlayerArmorChangeEvent.SlotType} ++ */ ++@RunWith(Parameterized.class) ++public class MissingArmorSlotTypeMaterialTest extends AbstractTestingBase { ++ ++ @Parameterized.Parameter(0) ++ public Equipable equipable; ++ ++ @Parameterized.Parameter(1) ++ public Item item; ++ ++ @Parameterized.Parameters(name = "{1}") ++ public static Iterable<Object[]> parameters() { ++ final List<Object[]> parameters = new ArrayList<>(); ++ for (final Item item : BuiltInRegistries.ITEM) { ++ final Equipable equipable = Equipable.get(new ItemStack(item)); ++ if (equipable != null) { ++ parameters.add(new Object[]{ equipable, item }); ++ } ++ } ++ return parameters; ++ } ++ ++ @Test ++ public void test() { ++ final EquipmentSlot equipmentSlot = this.equipable.getEquipmentSlot(); ++ PlayerArmorChangeEvent.SlotType slotType = switch (equipmentSlot) { ++ case HEAD -> PlayerArmorChangeEvent.SlotType.HEAD; ++ case CHEST -> PlayerArmorChangeEvent.SlotType.CHEST; ++ case LEGS -> PlayerArmorChangeEvent.SlotType.LEGS; ++ case FEET -> PlayerArmorChangeEvent.SlotType.FEET; ++ default -> null; ++ }; ++ if (slotType != null) { ++ assertTrue("SlotType " + slotType + " doesn't include " + this.item, slotType.getTypes().contains(CraftMagicNumbers.getMaterial(this.item))); ++ } ++ } ++}