aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLulu13022002 <[email protected]>2024-10-27 18:47:50 +0100
committerLulu13022002 <[email protected]>2024-10-27 18:47:50 +0100
commit4d873026726a150bcfe5cc6924bdd4dc8510d909 (patch)
tree885533374720c7c80bff4f23ab17faf5c836cde7
parent02bca1e6558bf4ac0cbf928d48e90f497b10b0a3 (diff)
downloadPaper-4d873026726a150bcfe5cc6924bdd4dc8510d909.tar.gz
Paper-4d873026726a150bcfe5cc6924bdd4dc8510d909.zip
Fix NPE and StackOverflowError for dispensers
-rw-r--r--patches/server/0459-Add-BlockFailedDispenseEvent.patch4
-rw-r--r--patches/server/0473-Add-BlockPreDispenseEvent.patch4
-rw-r--r--patches/server/0936-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch309
-rw-r--r--patches/server/0936-Fix-possible-StackOverflowError-for-some-dispenses.patch95
-rw-r--r--patches/server/0940-Properly-track-the-changed-item-from-dispense-events.patch6
-rw-r--r--patches/server/0948-Fix-helmet-damage-reduction-inconsistencies.patch2
-rw-r--r--patches/server/1017-Fix-InventoryOpenEvent-cancellation.patch2
7 files changed, 318 insertions, 104 deletions
diff --git a/patches/server/0459-Add-BlockFailedDispenseEvent.patch b/patches/server/0459-Add-BlockFailedDispenseEvent.patch
index ee65c26c99..c0dc74c0fe 100644
--- a/patches/server/0459-Add-BlockFailedDispenseEvent.patch
+++ b/patches/server/0459-Add-BlockFailedDispenseEvent.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Add BlockFailedDispenseEvent
diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
-index f4510b8e14d0b9997907ce1d1368ba3b3b5daf3e..f4853a5ff8a45efcda2d7781c1fa897c47d8ea46 100644
+index 3d05e71fef8fa70df05311a6a9ddad99994892a6..352f5412fc469a1fde6f14ffcaf00e88613b2704 100644
--- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
@@ -98,8 +98,10 @@ public class DispenserBlock extends BaseEntityBlock {
@@ -20,7 +20,7 @@ index f4510b8e14d0b9997907ce1d1368ba3b3b5daf3e..f4853a5ff8a45efcda2d7781c1fa897c
ItemStack itemstack = tileentitydispenser.getItem(i);
DispenseItemBehavior idispensebehavior = this.getDispenseMethod(world, itemstack);
diff --git a/src/main/java/net/minecraft/world/level/block/DropperBlock.java b/src/main/java/net/minecraft/world/level/block/DropperBlock.java
-index a08e8571f3a83afc80c2f1758a9029cd28ed6947..91b514967405115f22edf4255775361a672e5c2f 100644
+index 09e5ff5a0270cb88f3505a28c07ef816f18ac23b..3e09d4b11c881b9c7d3447df379286238076cfee 100644
--- a/src/main/java/net/minecraft/world/level/block/DropperBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DropperBlock.java
@@ -60,6 +60,7 @@ public class DropperBlock extends DispenserBlock {
diff --git a/patches/server/0473-Add-BlockPreDispenseEvent.patch b/patches/server/0473-Add-BlockPreDispenseEvent.patch
index d280bd07f1..d2ba7470a3 100644
--- a/patches/server/0473-Add-BlockPreDispenseEvent.patch
+++ b/patches/server/0473-Add-BlockPreDispenseEvent.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Add BlockPreDispenseEvent
diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
-index f4853a5ff8a45efcda2d7781c1fa897c47d8ea46..a02f24448b002824b068278fa427003008c0d0f1 100644
+index 352f5412fc469a1fde6f14ffcaf00e88613b2704..9f99a9ec8f8269a0aeee2d6aa68f8a344f5f64b6 100644
--- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
@@ -107,6 +107,7 @@ public class DispenserBlock extends BaseEntityBlock {
@@ -17,7 +17,7 @@ index f4853a5ff8a45efcda2d7781c1fa897c47d8ea46..a02f24448b002824b068278fa4270030
tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack));
}
diff --git a/src/main/java/net/minecraft/world/level/block/DropperBlock.java b/src/main/java/net/minecraft/world/level/block/DropperBlock.java
-index 91b514967405115f22edf4255775361a672e5c2f..ddecf443df3679e3098eb54edd19585a0512e342 100644
+index 3e09d4b11c881b9c7d3447df379286238076cfee..1762415720caa722600ab7e81344ee9168e42011 100644
--- a/src/main/java/net/minecraft/world/level/block/DropperBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DropperBlock.java
@@ -71,6 +71,7 @@ public class DropperBlock extends DispenserBlock {
diff --git a/patches/server/0936-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch b/patches/server/0936-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch
new file mode 100644
index 0000000000..a4d1c6d91e
--- /dev/null
+++ b/patches/server/0936-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch
@@ -0,0 +1,309 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Sat, 29 Oct 2022 17:02:42 -0700
+Subject: [PATCH] Fix possible StackOverflowError and NPE for some dispenses
+
+For saddles, carpets, horse armor, and chests for horse-likes
+a BlockDispenseEvent handler that always mutated the item without
+changing the type would result in a SO error because when it went
+to find the replacement dispense behavior (since the item "changed")
+it didn't properly handle if the replacement was the same instance
+of dispense behavior.
+
+Additionally equippable mob heads, wither skulls, and carved pumpkins
+are subject to the same possible error.
+
+Furthermore since 1.21.2, the DISPENSER_REGISTRY map doesn't have a default
+return value anymore and some dispense behaviors like equippable and
+regular items will not have a defined behavior in that map and might throw
+a NPE in that case.
+
+== AT ==
+public net.minecraft.world.level.block.DispenserBlock getDispenseMethod(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/core/dispenser/DispenseItemBehavior;
+
+diff --git a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
+index 36180e80dbd681e68c60e097015dad890a48b574..dff30954e4c588ee4cc79d3f6dab6fb456934d65 100644
+--- a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
+@@ -67,7 +67,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior {
+ stack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+diff --git a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
+index 39c96f5db6e90a470404c6387fa0c1d5531822e5..8aae1d113e84dfad9f2b6f0bcd203ca6c68bc5ce 100644
+--- a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
+@@ -101,7 +101,7 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior {
+ if (!dropper && !event.getItem().getType().equals(craftItem.getType())) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(sourceblock, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior.getClass() != DefaultDispenseItemBehavior.class) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ } else {
+diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
+index 18304349c9ab24657c4152aff800dba969174665..94b2647f69035dce9a3d56b6978e3884e06c5583 100644
+--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
+@@ -124,7 +124,7 @@ public interface DispenseItemBehavior {
+ stack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -178,7 +178,7 @@ public interface DispenseItemBehavior {
+ stack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -231,8 +231,8 @@ public interface DispenseItemBehavior {
+ stack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+ }
+@@ -282,8 +282,8 @@ public interface DispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+ }
+@@ -352,7 +352,7 @@ public interface DispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -414,7 +414,7 @@ public interface DispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -452,7 +452,7 @@ public interface DispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -514,7 +514,7 @@ public interface DispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -585,7 +585,7 @@ public interface DispenseItemBehavior {
+ stack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -625,7 +625,7 @@ public interface DispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -645,7 +645,7 @@ public interface DispenseItemBehavior {
+ stack.shrink(1);
+ this.setSuccess(true);
+ } else {
+- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack));
++ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError
+ }
+
+ return stack;
+@@ -674,7 +674,7 @@ public interface DispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -691,7 +691,7 @@ public interface DispenseItemBehavior {
+ stack.shrink(1);
+ this.setSuccess(true);
+ } else {
+- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack));
++ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError
+ }
+
+ return stack;
+@@ -736,7 +736,7 @@ public interface DispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+@@ -818,8 +818,8 @@ public interface DispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+ }
+diff --git a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
+index a03cc350973fda213251cad273a2db86f438904b..a43ea83dbbd5946096cdde31af766674bda6c3be 100644
+--- a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
+@@ -23,10 +23,15 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior {
+
+ @Override
+ protected ItemStack execute(BlockSource pointer, ItemStack stack) {
+- return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack) ? stack : super.execute(pointer, stack);
++ return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this) ? stack : super.execute(pointer, stack); // Paper - fix possible StackOverflowError
+ }
+
+- public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack) {
++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper
++ public static boolean dispenseEquipment(BlockSource pointer, ItemStack armor) {
++ // Paper start
++ return dispenseEquipment(pointer, armor, null);
++ }
++ public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack, @javax.annotation.Nullable DispenseItemBehavior currentBehavior) {
+ BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+ List<LivingEntity> list = pointer.level().getEntitiesOfClass(LivingEntity.class, new AABB(blockposition), (entityliving) -> {
+ return entityliving.canEquipWithDispenser(stack);
+@@ -58,8 +63,8 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior {
+ stack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
++ if (idispensebehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || idispensebehavior != currentBehavior)) { // Paper - fix possible StackOverflowError
+ idispensebehavior.dispense(pointer, eventStack);
+ return true;
+ }
+diff --git a/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
+index f2e19218cf0d3b44a617c7d74f782c3e15e3f07f..aae9ec8f3bd39685b37251bef3f9ac846d65c192 100644
+--- a/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
+@@ -87,7 +87,7 @@ public class MinecartDispenseItemBehavior extends DefaultDispenseItemBehavior {
+ stack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+diff --git a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
+index a9d230d6ff22d5e3a11b2f31e7d751f44888a12c..aba0ddfc5009a11b6c5cba95a90479083643bdad 100644
+--- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
+@@ -57,7 +57,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior {
+ stack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
+index f5206e4176f58cff4cfe70c94f014afebc98c589..afad4fa3ca1a3186c4569ea073f776dac16817e1 100644
+--- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
+@@ -52,7 +52,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+index f84987c36a16df19286d6f1badfb1ffb9cc7e770..cc85e96035f7cb2e6493b1cc4748031171d7dbee 100644
+--- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+@@ -48,7 +48,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return stack;
+diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
+index 9f99a9ec8f8269a0aeee2d6aa68f8a344f5f64b6..716d1a98775d7338a121af9fd0868a65e2c28288 100644
+--- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
++++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
+@@ -116,6 +116,12 @@ public class DispenserBlock extends BaseEntityBlock {
+ }
+ }
+
++ // Paper start - Fix NPE with equippable and items without behavior
++ public static DispenseItemBehavior getDispenseBehavior(BlockSource pointer, ItemStack stack) {
++ return ((DispenserBlock) pointer.state().getBlock()).getDispenseMethod(pointer.level(), stack);
++ }
++ // Paper end - Fix NPE with equippable and items without behavior
++
+ public DispenseItemBehavior getDispenseMethod(Level world, ItemStack stack) {
+ if (!stack.isItemEnabled(world.enabledFeatures())) {
+ return DispenserBlock.DEFAULT_BEHAVIOR;
+diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+index 96b901d07718d8926a2175925e867b4417c3947c..418e67ef5896325fe143501f5a4f1604b065ba0f 100644
+--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+@@ -2232,7 +2232,7 @@ public class CraftEventFactory {
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+- net.minecraft.core.dispenser.DispenseItemBehavior itemBehavior = net.minecraft.world.level.block.DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ net.minecraft.core.dispenser.DispenseItemBehavior itemBehavior = net.minecraft.world.level.block.DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (itemBehavior != net.minecraft.core.dispenser.DispenseItemBehavior.NOOP && itemBehavior != instance) {
+ itemBehavior.dispense(pointer, eventStack);
+ return itemStack;
diff --git a/patches/server/0936-Fix-possible-StackOverflowError-for-some-dispenses.patch b/patches/server/0936-Fix-possible-StackOverflowError-for-some-dispenses.patch
deleted file mode 100644
index 7e0fabb39a..0000000000
--- a/patches/server/0936-Fix-possible-StackOverflowError-for-some-dispenses.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Jake Potrebic <[email protected]>
-Date: Sat, 29 Oct 2022 17:02:42 -0700
-Subject: [PATCH] Fix possible StackOverflowError for some dispenses
-
-For saddles, carpets, horse armor, and chests for horse-likes
-a BlockDispenseEvent handler that always mutated the item without
-changing the type would result in a SO error because when it went
-to find the replacement dispense behavior (since the item "changed")
-it didn't properly handle if the replacement was the same instance
-of dispense behavior.
-
-Additionally equippable mob heads, wither skulls, and carved pumpkins
-are subject to the same possible error.
-
-diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
-index 18304349c9ab24657c4152aff800dba969174665..63b8c806b6ee0ea3cc5e6a7f613b5e57c94bfcf1 100644
---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
-+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
-@@ -232,7 +232,7 @@ public interface DispenseItemBehavior {
- // Chain to handler for new item
- ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
-- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
-+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError
- idispensebehavior.dispense(pointer, eventStack);
- return stack;
- }
-@@ -283,7 +283,7 @@ public interface DispenseItemBehavior {
- // Chain to handler for new item
- ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
-- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
-+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError
- idispensebehavior.dispense(pointer, eventStack);
- return stack;
- }
-@@ -645,7 +645,7 @@ public interface DispenseItemBehavior {
- stack.shrink(1);
- this.setSuccess(true);
- } else {
-- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack));
-+ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError
- }
-
- return stack;
-@@ -691,7 +691,7 @@ public interface DispenseItemBehavior {
- stack.shrink(1);
- this.setSuccess(true);
- } else {
-- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack));
-+ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError
- }
-
- return stack;
-@@ -819,7 +819,7 @@ public interface DispenseItemBehavior {
- // Chain to handler for new item
- ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
-- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
-+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError
- idispensebehavior.dispense(pointer, eventStack);
- return stack;
- }
-diff --git a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
-index a03cc350973fda213251cad273a2db86f438904b..036dd3b15dfee4cd079710eba1255d2bdb4d7220 100644
---- a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
-+++ b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
-@@ -23,10 +23,15 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior {
-
- @Override
- protected ItemStack execute(BlockSource pointer, ItemStack stack) {
-- return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack) ? stack : super.execute(pointer, stack);
-+ return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, null) ? stack : super.execute(pointer, stack); // Paper - fix possible StackOverflowError
- }
-
-- public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack) {
-+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper
-+ public static boolean dispenseEquipment(BlockSource pointer, ItemStack armor) {
-+ // Paper start
-+ return dispenseEquipment(pointer, armor, null);
-+ }
-+ public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack, @javax.annotation.Nullable DispenseItemBehavior currentBehavior) {
- BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
- List<LivingEntity> list = pointer.level().getEntitiesOfClass(LivingEntity.class, new AABB(blockposition), (entityliving) -> {
- return entityliving.canEquipWithDispenser(stack);
-@@ -59,7 +64,7 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior {
- // Chain to handler for new item
- ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
-- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
-+ if (idispensebehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE)) { // Paper - fix possible StackOverflowError
- idispensebehavior.dispense(pointer, eventStack);
- return true;
- }
diff --git a/patches/server/0940-Properly-track-the-changed-item-from-dispense-events.patch b/patches/server/0940-Properly-track-the-changed-item-from-dispense-events.patch
index 3885b9f8a2..d653a24df5 100644
--- a/patches/server/0940-Properly-track-the-changed-item-from-dispense-events.patch
+++ b/patches/server/0940-Properly-track-the-changed-item-from-dispense-events.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Properly track the changed item from dispense events
diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
-index 63b8c806b6ee0ea3cc5e6a7f613b5e57c94bfcf1..cd77e86ff289634d2dd1c56002e569ff70d15f25 100644
+index 94b2647f69035dce9a3d56b6978e3884e06c5583..a09b089565f9167e1a2d53116ae879d9f868342e 100644
--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -129,10 +129,14 @@ public interface DispenseItemBehavior {
@@ -72,7 +72,7 @@ index 63b8c806b6ee0ea3cc5e6a7f613b5e57c94bfcf1..cd77e86ff289634d2dd1c56002e569ff
} else {
return this.defaultDispenseItemBehavior.dispense(pointer, stack);
diff --git a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
-index a9d230d6ff22d5e3a11b2f31e7d751f44888a12c..af222679d0d44d24b2b10455eb52fa8a797ca28a 100644
+index aba0ddfc5009a11b6c5cba95a90479083643bdad..b341792b694e4d6d7ca98061976b8857d83c4233 100644
--- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
+++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
@@ -64,7 +64,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior {
@@ -85,7 +85,7 @@ index a9d230d6ff22d5e3a11b2f31e7d751f44888a12c..af222679d0d44d24b2b10455eb52fa8a
// itemstack.shrink(1); // CraftBukkit - Handled during event processing
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
-index f84987c36a16df19286d6f1badfb1ffb9cc7e770..8e089f7d5e7fa9ddeccd0691185555f279d55426 100644
+index cc85e96035f7cb2e6493b1cc4748031171d7dbee..16b435216dc7c6a3f8c1c0f9e2323e6afb3a6cb9 100644
--- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
@@ -57,7 +57,12 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior {
diff --git a/patches/server/0948-Fix-helmet-damage-reduction-inconsistencies.patch b/patches/server/0948-Fix-helmet-damage-reduction-inconsistencies.patch
index ef4efc0ef7..262b84900d 100644
--- a/patches/server/0948-Fix-helmet-damage-reduction-inconsistencies.patch
+++ b/patches/server/0948-Fix-helmet-damage-reduction-inconsistencies.patch
@@ -7,7 +7,7 @@ Affect the falling stalactite damage type where the
reduction is not applied like in Vanilla
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
-index 96b901d07718d8926a2175925e867b4417c3947c..6c60bb4f4d1133844a4232df518c062216847fdc 100644
+index 418e67ef5896325fe143501f5a4f1604b065ba0f..1e98f68e51618606f1178c12be77c1a945362630 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1226,7 +1226,7 @@ public class CraftEventFactory {
diff --git a/patches/server/1017-Fix-InventoryOpenEvent-cancellation.patch b/patches/server/1017-Fix-InventoryOpenEvent-cancellation.patch
index 6f31e5f363..05ec9a1266 100644
--- a/patches/server/1017-Fix-InventoryOpenEvent-cancellation.patch
+++ b/patches/server/1017-Fix-InventoryOpenEvent-cancellation.patch
@@ -183,7 +183,7 @@ index 673a92d383db463b5c4e2ac3a4ecbd7e97c15c6d..6a2123cd808fa79f3cdb1cb56632d29b
return InteractionResult.SUCCESS;
diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
-index a02f24448b002824b068278fa427003008c0d0f1..0427d590912561cb4f0354715e4ac513e53b3eb3 100644
+index 716d1a98775d7338a121af9fd0868a65e2c28288..b2243e883388d1c12480e470c391bb97b993b77d 100644
--- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java
@@ -80,8 +80,9 @@ public class DispenserBlock extends BaseEntityBlock {