From 3de408ee3e433f3f2d1afc3a9bca2941bac300dc Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Thu, 23 May 2024 10:39:44 -0700 Subject: [PATCH] Fix equipment slot and group API (#10767) --- ...478-Fix-equipment-slot-and-group-API.patch | 31 +++++++ ...046-Fix-equipment-slot-and-group-API.patch | 88 +++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 patches/api/0478-Fix-equipment-slot-and-group-API.patch create mode 100644 patches/server/1046-Fix-equipment-slot-and-group-API.patch diff --git a/patches/api/0478-Fix-equipment-slot-and-group-API.patch b/patches/api/0478-Fix-equipment-slot-and-group-API.patch new file mode 100644 index 0000000000..e743118494 --- /dev/null +++ b/patches/api/0478-Fix-equipment-slot-and-group-API.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 22 May 2024 10:00:19 -0700 +Subject: [PATCH] Fix equipment slot and group API + +was missing the 'body' slot group + +diff --git a/src/main/java/org/bukkit/attribute/AttributeModifier.java b/src/main/java/org/bukkit/attribute/AttributeModifier.java +index 8ba00f743b61cd33dd41ae7f1c272ee2b0c8546d..7cc1fd241e1f62a9fe9b5849110c0a3d05d08034 100644 +--- a/src/main/java/org/bukkit/attribute/AttributeModifier.java ++++ b/src/main/java/org/bukkit/attribute/AttributeModifier.java +@@ -95,6 +95,7 @@ public class AttributeModifier implements ConfigurationSerializable { + */ + @Nullable + @Deprecated ++ @io.papermc.paper.annotation.DoNotUse // Paper + public EquipmentSlot getSlot() { + return slot == EquipmentSlotGroup.ANY ? null : slot.getExample(); + } +diff --git a/src/main/java/org/bukkit/inventory/EquipmentSlotGroup.java b/src/main/java/org/bukkit/inventory/EquipmentSlotGroup.java +index 82416a078f697f627916c578e6c2dbc003519acf..f72aa9cfd2d1472cf26600ac0f2380660069407d 100644 +--- a/src/main/java/org/bukkit/inventory/EquipmentSlotGroup.java ++++ b/src/main/java/org/bukkit/inventory/EquipmentSlotGroup.java +@@ -25,6 +25,7 @@ public final class EquipmentSlotGroup implements Predicate { + public static final EquipmentSlotGroup CHEST = get("chest", EquipmentSlot.CHEST); + public static final EquipmentSlotGroup HEAD = get("head", EquipmentSlot.HEAD); + public static final EquipmentSlotGroup ARMOR = get("armor", (test) -> test == EquipmentSlot.FEET || test == EquipmentSlot.LEGS || test == EquipmentSlot.CHEST || test == EquipmentSlot.HEAD, EquipmentSlot.CHEST); ++ public static final EquipmentSlotGroup BODY = get("body", EquipmentSlot.BODY); // Paper - add missing slot group + // + private final String key; + private final Predicate predicate; diff --git a/patches/server/1046-Fix-equipment-slot-and-group-API.patch b/patches/server/1046-Fix-equipment-slot-and-group-API.patch new file mode 100644 index 0000000000..17b7e6580c --- /dev/null +++ b/patches/server/1046-Fix-equipment-slot-and-group-API.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 22 May 2024 10:01:19 -0700 +Subject: [PATCH] Fix equipment slot and group API + +Add test for EquipmentSlotGroup + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index 87bb193acd39515c2d80cf1ab41d1e2538112fe9..a39785b4e45e7bf57d6c60abae0771a629148342 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -1331,7 +1331,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + this.checkAttributeList(); + SetMultimap result = LinkedHashMultimap.create(); + for (Map.Entry entry : this.attributeModifiers.entries()) { +- if (entry.getValue().getSlot() == null || entry.getValue().getSlot() == slot) { ++ if (entry.getValue().getSlotGroup().test(slot)) { // Paper - correctly test slot against group + result.put(entry.getKey(), entry.getValue()); + } + } +@@ -1392,9 +1392,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + while (iter.hasNext()) { + Map.Entry entry = iter.next(); +- // Explicitly match against null because (as of MC 1.13) AttributeModifiers without a - +- // set slot are active in any slot. +- if (entry.getValue().getSlot() == null || entry.getValue().getSlot() == slot) { ++ if (entry.getValue().getSlotGroup().test(slot)) { // Paper - correctly test slot against group + iter.remove(); + ++removed; + } +diff --git a/src/test/java/io/papermc/paper/inventory/item/EquipmentSlotGroupTest.java b/src/test/java/io/papermc/paper/inventory/item/EquipmentSlotGroupTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ee0bfe4edb134d7ea3a3b97f5102a7f3122c3b99 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/inventory/item/EquipmentSlotGroupTest.java +@@ -0,0 +1,51 @@ ++package io.papermc.paper.inventory.item; ++ ++import java.lang.reflect.Field; ++import java.lang.reflect.Modifier; ++import java.util.ArrayList; ++import java.util.List; ++import net.minecraft.world.entity.EquipmentSlot; ++import org.bukkit.craftbukkit.CraftEquipmentSlot; ++import org.bukkit.inventory.EquipmentSlotGroup; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.EnumSource; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++import static org.junit.jupiter.api.Assertions.assertNotNull; ++ ++class EquipmentSlotGroupTest { ++ ++ static List apiValues() throws ReflectiveOperationException { ++ final List apiValues = new ArrayList<>(); ++ for (final Field field : EquipmentSlotGroup.class.getDeclaredFields()) { ++ if (!Modifier.isStatic(field.getModifiers()) || !Modifier.isFinal(field.getModifiers()) || !field.getType().equals(EquipmentSlotGroup.class)) { ++ continue; ++ } ++ apiValues.add((EquipmentSlotGroup) field.get(null)); ++ } ++ if (apiValues.isEmpty()) { ++ throw new RuntimeException("Didn't find any api " + EquipmentSlotGroup.class.getSimpleName()); ++ } ++ return apiValues; ++ } ++ ++ @ParameterizedTest ++ @MethodSource("apiValues") ++ void testBukkitToNms(final EquipmentSlotGroup slotGroup) { ++ final net.minecraft.world.entity.EquipmentSlotGroup nmsGroup = CraftEquipmentSlot.getNMSGroup(slotGroup); ++ assertNotNull(nmsGroup, "No nms slot group found for " + slotGroup); ++ assertEquals(nmsGroup.getSerializedName(), slotGroup.toString(), "slot group name mismatch"); ++ for (final EquipmentSlot slot : EquipmentSlot.values()) { ++ assertEquals(nmsGroup.test(slot), slotGroup.test(CraftEquipmentSlot.getSlot(slot))); ++ } ++ } ++ ++ @ParameterizedTest ++ @EnumSource(net.minecraft.world.entity.EquipmentSlotGroup.class) ++ void testNmsToBukkit(final net.minecraft.world.entity.EquipmentSlotGroup slotGroup) { ++ final EquipmentSlotGroup apiGroup = CraftEquipmentSlot.getSlot(slotGroup); ++ assertNotNull(apiGroup, "No api slot group found for " + slotGroup); ++ assertEquals(apiGroup.toString(), slotGroup.getSerializedName(), "slot group name mismatch"); ++ } ++}