summaryrefslogtreecommitdiffhomepage
path: root/patches/server/0968-Fix-equipment-slot-and-group-API.patch
diff options
context:
space:
mode:
authorBjarne Koll <[email protected]>2024-09-19 16:36:07 +0200
committerGitHub <[email protected]>2024-09-19 16:36:07 +0200
commitc5a10665b8b80af650500b9263036f778f06d500 (patch)
treefedc133f0dbc101067951e1fccd9d577c312fdb8 /patches/server/0968-Fix-equipment-slot-and-group-API.patch
parent5c829557332f21b34bc81e6ad1a73e511faef8f6 (diff)
downloadPaper-c5a10665b8b80af650500b9263036f778f06d500.tar.gz
Paper-c5a10665b8b80af650500b9263036f778f06d500.zip
Remove wall-time / unused skip tick protection (#11412)
Spigot still maintains some partial implementation of "tick skipping", a practice in which the MinecraftServer.currentTick field is updated not by an increment of one per actual tick, but instead set to System.currentTimeMillis() / 50. This behaviour means that the tracked tick may "skip" a tick value in case a previous tick took more than the expected 50ms. To compensate for this in important paths, spigot/craftbukkit implements "wall-time". Instead of incrementing/decrementing ticks on block entities/entities by one for each call to their tick() method, they instead increment/decrement important values, like an ItemEntity's age or pickupDelay, by the difference of `currentTick - lastTick`, where `lastTick` is the value of `currentTick` during the last tick() call. These "fixes" however do not play nicely with minecraft's simulation distance as entities/block entities implementing the above behaviour would "catch up" their values when moving from a non-ticking chunk to a ticking one as their `lastTick` value remains stuck on the last tick in a ticking chunk and hence lead to a large "catch up" once ticked again. Paper completely removes the "tick skipping" behaviour (See patch "Further-improve-server-tick-loop"), making the above precautions completely unnecessary, which also rids paper of the previous described incompatibility with non-ticking chunks.
Diffstat (limited to 'patches/server/0968-Fix-equipment-slot-and-group-API.patch')
-rw-r--r--patches/server/0968-Fix-equipment-slot-and-group-API.patch134
1 files changed, 134 insertions, 0 deletions
diff --git a/patches/server/0968-Fix-equipment-slot-and-group-API.patch b/patches/server/0968-Fix-equipment-slot-and-group-API.patch
new file mode 100644
index 0000000000..e84bebe105
--- /dev/null
+++ b/patches/server/0968-Fix-equipment-slot-and-group-API.patch
@@ -0,0 +1,134 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Wed, 22 May 2024 10:01:19 -0700
+Subject: [PATCH] Fix equipment slot and group API
+
+Adds the following:
+- Add test for EquipmentSlotGroup
+- Expose LivingEntity#canUseSlot
+
+Co-authored-by: SoSeDiK <[email protected]>
+
+diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+index 6c44aaef8f09b2a10183dba751557ac5c6233a87..a54cf98661cc678277855f21735e98fafd018ded 100644
+--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+@@ -1187,4 +1187,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
+ this.getHandle().setYBodyRot(bodyYaw);
+ }
+ // Paper end - body yaw API
++
++ // Paper start - Expose canUseSlot
++ @Override
++ public boolean canUseEquipmentSlot(org.bukkit.inventory.EquipmentSlot slot) {
++ return this.getHandle().canUseSlot(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot));
++ }
++ // Paper end - Expose canUseSlot
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java
+index 9d74577af071954e1e37201a96368c1360076209..eafa54c870c3e2aef30c3f9f96f516607a7cae24 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java
+@@ -135,6 +135,10 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i
+ case HEAD:
+ this.setHelmet(item);
+ break;
++ // Paper start
++ case BODY:
++ throw new IllegalArgumentException("BODY is not valid for players!");
++ // Paper end
+ default:
+ throw new IllegalArgumentException("Not implemented. This is a bug");
+ }
+@@ -162,6 +166,10 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i
+ return java.util.Objects.requireNonNullElseGet(this.getChestplate(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull
+ case HEAD:
+ return java.util.Objects.requireNonNullElseGet(this.getHelmet(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull
++ // Paper start
++ case BODY:
++ throw new IllegalArgumentException("BODY is not valid for players!");
++ // Paper end
+ default:
+ throw new IllegalArgumentException("Not implemented. This is a bug");
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+index beeed762e5ba49c317c5f214af17c44174b0c943..042bfdd14c9ff4cc8ed3421f73565f0f03b11bcb 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+@@ -1448,7 +1448,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ if (this.attributeModifiers == null) return LinkedHashMultimap.create(); // Paper - don't change the components
+ SetMultimap<Attribute, AttributeModifier> result = LinkedHashMultimap.create();
+ for (Map.Entry<Attribute, AttributeModifier> 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());
+ }
+ }
+@@ -1522,9 +1522,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+
+ while (iter.hasNext()) {
+ Map.Entry<Attribute, AttributeModifier> 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<EquipmentSlotGroup> apiValues() throws ReflectiveOperationException {
++ final List<EquipmentSlotGroup> 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");
++ }
++}