aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/1027-Proxy-ItemStack-to-CraftItemStack.patch
diff options
context:
space:
mode:
authorSpottedleaf <[email protected]>2024-07-11 12:09:15 -0700
committerSpottedleaf <[email protected]>2024-07-11 12:09:15 -0700
commit90ae1dc573bc9f2f0a60bbdcf497aa096e966c9d (patch)
treede2f1e3619c5d7fb8cabb13bc261850a8c2c3298 /patches/server/1027-Proxy-ItemStack-to-CraftItemStack.patch
parent7bd22b1835af2611c5ad597aef6470b1ece9b547 (diff)
downloadPaper-90ae1dc573bc9f2f0a60bbdcf497aa096e966c9d.tar.gz
Paper-90ae1dc573bc9f2f0a60bbdcf497aa096e966c9d.zip
Port collision optimisation patch from Moonrise
Drop random ticking optimisation for now
Diffstat (limited to 'patches/server/1027-Proxy-ItemStack-to-CraftItemStack.patch')
-rw-r--r--patches/server/1027-Proxy-ItemStack-to-CraftItemStack.patch300
1 files changed, 300 insertions, 0 deletions
diff --git a/patches/server/1027-Proxy-ItemStack-to-CraftItemStack.patch b/patches/server/1027-Proxy-ItemStack-to-CraftItemStack.patch
new file mode 100644
index 0000000000..ad3c75feb2
--- /dev/null
+++ b/patches/server/1027-Proxy-ItemStack-to-CraftItemStack.patch
@@ -0,0 +1,300 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Tue, 14 May 2024 11:57:43 -0700
+Subject: [PATCH] Proxy ItemStack to CraftItemStack
+
+
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+index be36336a3c7d1ae88277f4ee1be70075001de7a7..814e8ece6821e359b504e8c4d140cc38700f2abe 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+@@ -25,15 +25,57 @@ import org.bukkit.material.MaterialData;
+ @DelegateDeserialization(ItemStack.class)
+ public final class CraftItemStack extends ItemStack {
+
+- // Paper start - MC Utils
+- public static net.minecraft.world.item.ItemStack unwrap(ItemStack bukkit) {
+- if (bukkit instanceof CraftItemStack craftItemStack) {
+- return craftItemStack.handle != null ? craftItemStack.handle : net.minecraft.world.item.ItemStack.EMPTY;
++ // Paper start - delegate api-ItemStack to CraftItemStack
++ private static final java.lang.invoke.VarHandle API_ITEM_STACK_CRAFT_DELEGATE_FIELD;
++ static {
++ try {
++ API_ITEM_STACK_CRAFT_DELEGATE_FIELD = java.lang.invoke.MethodHandles.privateLookupIn(
++ ItemStack.class,
++ java.lang.invoke.MethodHandles.lookup()
++ ).findVarHandle(ItemStack.class, "craftDelegate", ItemStack.class);
++ } catch (final IllegalAccessException | NoSuchFieldException exception) {
++ throw new RuntimeException(exception);
++ }
++ }
++
++ private static CraftItemStack getCraftStack(final ItemStack bukkit) {
++ if (bukkit instanceof final CraftItemStack craftItemStack) {
++ return craftItemStack;
+ } else {
+- return asNMSCopy(bukkit);
++ return (CraftItemStack) API_ITEM_STACK_CRAFT_DELEGATE_FIELD.get(bukkit);
+ }
+ }
+
++ @Override
++ public int hashCode() {
++ if (this.handle == null || this.handle.isEmpty()) {
++ return net.minecraft.world.item.ItemStack.EMPTY.hashCode();
++ } else {
++ int hash = net.minecraft.world.item.ItemStack.hashItemAndComponents(this.handle);
++ hash = hash * 31 + this.handle.getCount();
++ return hash;
++ }
++ }
++
++ @Override
++ public boolean equals(final Object obj) {
++ if (!(obj instanceof final org.bukkit.inventory.ItemStack bukkit)) return false;
++ final CraftItemStack craftStack = getCraftStack(bukkit);
++ if (this.handle == craftStack.handle) return true;
++ else if (this.handle == null || craftStack.handle == null) return false;
++ else if (this.handle.isEmpty() && craftStack.handle.isEmpty()) return true;
++ else return net.minecraft.world.item.ItemStack.matches(this.handle, craftStack.handle);
++ }
++ // Paper end
++
++ // Paper start - MC Utils
++ public static net.minecraft.world.item.ItemStack unwrap(ItemStack bukkit) {
++ // Paper start - re-implement after delegating all api ItemStack calls to CraftItemStack
++ final CraftItemStack craftItemStack = getCraftStack(bukkit);
++ return craftItemStack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : craftItemStack.handle;
++ // Paper end - re-implement after delegating all api ItemStack calls to CraftItemStack
++ }
++
+ public static net.minecraft.world.item.ItemStack getOrCloneOnMutation(ItemStack old, ItemStack newInstance) {
+ return old == newInstance ? unwrap(old) : asNMSCopy(newInstance);
+ }
+@@ -47,25 +89,13 @@ public final class CraftItemStack extends ItemStack {
+ // Paper end - override isEmpty to use vanilla's impl
+
+ public static net.minecraft.world.item.ItemStack asNMSCopy(ItemStack original) {
+- if (original instanceof CraftItemStack) {
+- CraftItemStack stack = (CraftItemStack) original;
+- return stack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : stack.handle.copy();
+- }
+- if (original == null || original.isEmpty()) { // Paper - override isEmpty to use vanilla's impl; use isEmpty
++ // Paper start - re-implement after delegating all api ItemStack calls to CraftItemStack
++ if (original == null || original.isEmpty()) {
+ return net.minecraft.world.item.ItemStack.EMPTY;
+ }
+-
+- Item item = CraftItemType.bukkitToMinecraft(original.getType());
+-
+- if (item == null) {
+- return net.minecraft.world.item.ItemStack.EMPTY;
+- }
+-
+- net.minecraft.world.item.ItemStack stack = new net.minecraft.world.item.ItemStack(item, original.getAmount());
+- if (original.hasItemMeta()) {
+- CraftItemStack.setItemMeta(stack, original.getItemMeta());
+- }
+- return stack;
++ final CraftItemStack stack = getCraftStack(original);
++ return stack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : stack.handle.copy();
++ // Paper end - re-implement after delegating all api ItemStack calls to CraftItemStack
+ }
+
+ // Paper start
+@@ -88,14 +118,10 @@ public final class CraftItemStack extends ItemStack {
+ * Copies the NMS stack to return as a strictly-Bukkit stack
+ */
+ public static ItemStack asBukkitCopy(net.minecraft.world.item.ItemStack original) {
+- if (original.isEmpty()) {
+- return new ItemStack(Material.AIR);
+- }
+- ItemStack stack = new ItemStack(CraftItemType.minecraftToBukkit(original.getItem()), original.getCount());
+- if (CraftItemStack.hasItemMeta(original)) {
+- stack.setItemMeta(CraftItemStack.getItemMeta(original));
+- }
+- return stack;
++ // Paper start - no such thing as a "strictly-Bukkit stack" anymore
++ // we copy the stack since it should be a complete copy not a mirror
++ return asCraftMirror(original.copy());
++ // Paper end
+ }
+
+ public static CraftItemStack asCraftMirror(net.minecraft.world.item.ItemStack original) {
+@@ -313,11 +339,7 @@ public final class CraftItemStack extends ItemStack {
+
+ @Override
+ public CraftItemStack clone() {
+- CraftItemStack itemStack = (CraftItemStack) super.clone();
+- if (this.handle != null) {
+- itemStack.handle = this.handle.copy();
+- }
+- return itemStack;
++ return new org.bukkit.craftbukkit.inventory.CraftItemStack(this.handle != null ? this.handle.copy() : null); // Paper
+ }
+
+ @Override
+@@ -420,22 +442,14 @@ public final class CraftItemStack extends ItemStack {
+ if (stack == this) {
+ return true;
+ }
+- if (!(stack instanceof CraftItemStack)) {
+- return stack.getClass() == ItemStack.class && stack.isSimilar(this);
+- }
+-
+- CraftItemStack that = (CraftItemStack) stack;
++ final CraftItemStack that = getCraftStack(stack); // Paper - re-implement after delegating all api ItemStack calls to CraftItemStack
+ if (this.handle == that.handle) {
+ return true;
+ }
+ if (this.handle == null || that.handle == null) {
+ return false;
+ }
+- Material comparisonType = CraftLegacy.fromLegacy(that.getType()); // This may be called from legacy item stacks, try to get the right material
+- if (!(comparisonType == this.getType() && this.getDurability() == that.getDurability())) {
+- return false;
+- }
+- return this.hasItemMeta() ? that.hasItemMeta() && this.handle.getComponents().equals(that.handle.getComponents()) : !that.hasItemMeta();
++ return net.minecraft.world.item.ItemStack.isSameItemSameComponents(this.handle, that.handle); // Paper - re-implement after delegating all api ItemStack calls to CraftItemStack
+ }
+
+ @Override
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
+index d03f4a767f6c7fe7d6bcef20e6676c39d9657584..bae3dd5fc67e6b3d98a5e63ffbf639c5042f8843 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
+@@ -100,13 +100,14 @@ public class CraftItemType<M extends ItemMeta> implements ItemType.Typed<M>, Han
+ @NotNull
+ @Override
+ public ItemStack createItemStack(final int amount, @Nullable final Consumer<? super M> metaConfigurator) {
+- final ItemStack itemStack = new ItemStack(this.asMaterial(), amount);
++ // Paper start - re-implement to return CraftItemStack
++ final net.minecraft.world.item.ItemStack stack = new net.minecraft.world.item.ItemStack(this.item, amount);
++ final CraftItemStack mirror = CraftItemStack.asCraftMirror(stack);
+ if (metaConfigurator != null) {
+- final ItemMeta itemMeta = itemStack.getItemMeta();
+- metaConfigurator.accept((M) itemMeta);
+- itemStack.setItemMeta(itemMeta);
++ mirror.editMeta(this.getItemMetaClass(), metaConfigurator);
+ }
+- return itemStack;
++ return mirror;
++ // Paper start - reimplement to return CraftItemStack
+ }
+
+ @Override
+diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
+index 9c004e7cb46841d874ab997bf2e3b63ae763aec7..d7c8f26b21276d9ff1d5c7c9738cc1126ce7d4b9 100644
+--- a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
++++ b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
+@@ -678,4 +678,16 @@ public class MaterialRerouting {
+ return itemStack.withType(material);
+ }
+ // Paper end - register paper API specific material consumers in rerouting
++
++ // Paper start - methods added post 1.13, no-op
++ @RerouteStatic("org/bukkit/inventory/ItemStack")
++ public static ItemStack of(final Material material) {
++ return ItemStack.of(material);
++ }
++
++ @RerouteStatic("org/bukkit/inventory/ItemStack")
++ public static ItemStack of(final Material material, final int amount) {
++ return ItemStack.of(material, amount);
++ }
++ // Paper end
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+index 0984843ff443ba40406839d06f83304902ee4f43..3137391cadef7c67019561e65fedd0664e689eae 100644
+--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+@@ -694,6 +694,13 @@ public final class CraftMagicNumbers implements UnsafeValues {
+ }
+ // Paper end - hack to get tags for non server-backed registries
+
++ // Paper start - proxy ItemStack
++ @Override
++ public org.bukkit.inventory.ItemStack createEmptyStack() {
++ return CraftItemStack.asCraftMirror(null);
++ }
++ // Paper end - proxy ItemStack
++
+ /**
+ * This helper class represents the different NBT Tags.
+ * <p>
+diff --git a/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java b/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..e5c2fb160e9d390cdfa0259a3feb9f488b2dc14d
+--- /dev/null
++++ b/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java
+@@ -0,0 +1,53 @@
++package io.papermc.paper.configuration;
++
++import org.bukkit.Material;
++import org.bukkit.configuration.ConfigurationSection;
++import org.bukkit.inventory.ItemStack;
++import org.bukkit.support.AbstractTestingBase;
++import org.junit.jupiter.api.Test;
++
++import static org.junit.jupiter.api.Assertions.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertFalse;
++import static org.junit.jupiter.api.Assertions.assertNull;
++import static org.junit.jupiter.api.Assertions.assertTrue;
++
++public abstract class ConfigurationSectionTest extends AbstractTestingBase {
++ public abstract ConfigurationSection getConfigurationSection();
++
++ @Test
++ public void testGetItemStack_String() {
++ ConfigurationSection section = getConfigurationSection();
++ String key = "exists";
++ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
++
++ section.set(key, value);
++
++ assertEquals(value, section.getItemStack(key));
++ assertNull(section.getString("doesntExist"));
++ }
++
++ @Test
++ public void testGetItemStack_String_ItemStack() {
++ ConfigurationSection section = getConfigurationSection();
++ String key = "exists";
++ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
++ ItemStack def = new ItemStack(Material.STONE, 1);
++
++ section.set(key, value);
++
++ assertEquals(value, section.getItemStack(key, def));
++ assertEquals(def, section.getItemStack("doesntExist", def));
++ }
++
++ @Test
++ public void testIsItemStack() {
++ ConfigurationSection section = getConfigurationSection();
++ String key = "exists";
++ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
++
++ section.set(key, value);
++
++ assertTrue(section.isItemStack(key));
++ assertFalse(section.isItemStack("doesntExist"));
++ }
++}
+diff --git a/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java b/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..def33c36f207a4c5306b5a895336aa70335c1678
+--- /dev/null
++++ b/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java
+@@ -0,0 +1,11 @@
++package io.papermc.paper.configuration;
++
++import org.bukkit.configuration.ConfigurationSection;
++import org.bukkit.configuration.MemoryConfiguration;
++
++public class MemorySectionTest extends ConfigurationSectionTest {
++ @Override
++ public ConfigurationSection getConfigurationSection() {
++ return new MemoryConfiguration().createSection("section");
++ }
++}