From d1ca62a9d0fe0aa4dc48b4645d6254ebe398bd65 Mon Sep 17 00:00:00 2001
From: Bjarne Koll <LynxPlay101@gmail.com>
Date: Thu, 31 Oct 2024 12:44:02 +0100
Subject: [PATCH] Correctly cancel consumption of consumable

See: #11534
---
 ...ItemConsumeEvent-cancelling-properly.patch | 12 +--
 patches/server/Properly-resend-entities.patch | 94 +++++++++++++++++--
 2 files changed, 91 insertions(+), 15 deletions(-)

diff --git a/patches/server/Fix-PlayerItemConsumeEvent-cancelling-properly.patch b/patches/server/Fix-PlayerItemConsumeEvent-cancelling-properly.patch
index eb3ef45b6f..b72ce157d4 100644
--- a/patches/server/Fix-PlayerItemConsumeEvent-cancelling-properly.patch
+++ b/patches/server/Fix-PlayerItemConsumeEvent-cancelling-properly.patch
@@ -13,10 +13,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
 +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
 @@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
-                         this.level().getCraftServer().getPluginManager().callEvent(event);
- 
-                         if (event.isCancelled()) {
+                             }
+                             entityPlayer.getBukkitEntity().updateInventory();
+                             entityPlayer.getBukkitEntity().updateScaledHealth();
 +                            this.stopUsingItem(); // Paper - event is using an item, clear active item to reset its use
-                             // Update client
-                             Consumable consumable = this.useItem.get(DataComponents.CONSUMABLE);
-                             if (consumable != null) {
+                             return;
+                         }
+ 
diff --git a/patches/server/Properly-resend-entities.patch b/patches/server/Properly-resend-entities.patch
index 73e35286bf..1b087660da 100644
--- a/patches/server/Properly-resend-entities.patch
+++ b/patches/server/Properly-resend-entities.patch
@@ -114,6 +114,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
          this.sendLevelInfo(player, worldserver1);
  
+@@ -0,0 +0,0 @@ public abstract class PlayerList {
+     }
+ 
+     public void sendActiveEffects(LivingEntity entity, ServerGamePacketListenerImpl networkHandler) {
++        // Paper start - collect packets
++        this.sendActiveEffects(entity, networkHandler::send);
++    }
++    public void sendActiveEffects(LivingEntity entity, java.util.function.Consumer<Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> packetConsumer) {
++        // Paper end - collect packets
+         Iterator iterator = entity.getActiveEffects().iterator();
+ 
+         while (iterator.hasNext()) {
+             MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
+ 
+-            networkHandler.send(new ClientboundUpdateMobEffectPacket(entity.getId(), mobeffect, false));
++            packetConsumer.accept(new ClientboundUpdateMobEffectPacket(entity.getId(), mobeffect, false)); // Paper - collect packets
+         }
+ 
+     }
 diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/entity/Entity.java
@@ -182,15 +201,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      private void updatingUsingItem() {
          if (this.isUsingItem()) {
              if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
-@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
-                             this.stopUsingItem(); // Paper - event is using an item, clear active item to reset its use
-                             // Update client
-                             Consumable consumable = this.useItem.get(DataComponents.CONSUMABLE);
--                            if (consumable != null) {
-+                            if (false && consumable != null) { // Paper
-                                 consumable.cancelUsingItem(entityPlayer, this.useItem);
-                             }
-                             entityPlayer.getBukkitEntity().updateInventory();
 diff --git a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
@@ -205,6 +215,72 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
                  return Optional.of(InteractionResult.FAIL);
              }
              entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F);
+diff --git a/src/main/java/net/minecraft/world/item/component/Consumable.java b/src/main/java/net/minecraft/world/item/component/Consumable.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/item/component/Consumable.java
++++ b/src/main/java/net/minecraft/world/item/component/Consumable.java
+@@ -0,0 +0,0 @@ public record Consumable(float consumeSeconds, ItemUseAnimation animation, Holde
+ 
+     // CraftBukkit start
+     public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack) {
++        final java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> packets = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // Paper - properly resend entities - collect packets for bundle
+         itemstack.getAllOfType(ConsumableListener.class).forEach((consumablelistener) -> {
+-            consumablelistener.cancelUsingItem(entityplayer, itemstack);
++            consumablelistener.cancelUsingItem(entityplayer, itemstack, packets); // Paper - properly resend entities - collect packets for bundle
+         });
+-        entityplayer.server.getPlayerList().sendActivePlayerEffects(entityplayer);
++        entityplayer.server.getPlayerList().sendActiveEffects(entityplayer, packets::add); // Paper - properly resend entities - collect packets for bundle
++        entityplayer.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(packets));
+     }
+     // CraftBukkit end
+ 
+diff --git a/src/main/java/net/minecraft/world/item/component/ConsumableListener.java b/src/main/java/net/minecraft/world/item/component/ConsumableListener.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/item/component/ConsumableListener.java
++++ b/src/main/java/net/minecraft/world/item/component/ConsumableListener.java
+@@ -0,0 +0,0 @@ public interface ConsumableListener {
+ 
+     void onConsume(Level world, LivingEntity user, ItemStack stack, Consumable consumable);
+ 
+-    default void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack) {} // CraftBukkit
++    default void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack, java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> collectedPackets) {} // CraftBukkit // Paper - properly resend entities - collect packets for bundle
+ }
+diff --git a/src/main/java/net/minecraft/world/item/component/OminousBottleAmplifier.java b/src/main/java/net/minecraft/world/item/component/OminousBottleAmplifier.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/item/component/OminousBottleAmplifier.java
++++ b/src/main/java/net/minecraft/world/item/component/OminousBottleAmplifier.java
+@@ -0,0 +0,0 @@ public record OminousBottleAmplifier(int value) implements ConsumableListener, T
+ 
+     @Override
+     public void onConsume(Level world, LivingEntity user, ItemStack stack, Consumable consumable) {
+-        user.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true));
++        user.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below
+     }
++    // Paper start - properly resend entities - collect packets for bundle
++    @Override
++    public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack, java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> collectedPackets) {
++        collectedPackets.add(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), MobEffects.BAD_OMEN));
++    }
++    // Paper end - properly resend entities - collect packets for bundle
+ 
+     @Override
+     public void addToTooltip(Item.TooltipContext context, Consumer<Component> tooltip, TooltipFlag type) {
+diff --git a/src/main/java/net/minecraft/world/item/component/SuspiciousStewEffects.java b/src/main/java/net/minecraft/world/item/component/SuspiciousStewEffects.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/item/component/SuspiciousStewEffects.java
++++ b/src/main/java/net/minecraft/world/item/component/SuspiciousStewEffects.java
+@@ -0,0 +0,0 @@ public record SuspiciousStewEffects(List<SuspiciousStewEffects.Entry> effects) i
+ 
+     // CraftBukkit start
+     @Override
+-    public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack) {
++    public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack, java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> collectedPackets) { // Paper - properly resend entities - collect packets for bundle
+         for (SuspiciousStewEffects.Entry suspicioussteweffects_a : this.effects) {
+-            entityplayer.connection.send(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), suspicioussteweffects_a.effect()));
++            collectedPackets.add(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), suspicioussteweffects_a.effect())); // Paper - bundlize packets
+         }
+     }
+     // CraftBukkit end
 diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java