From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 15 Dec 2022 00:14:44 -0800
Subject: [PATCH] Fix several issues with EntityBreedEvent

Upstream did not account for different hands when storing
the breed item for later use in the event. Also they only
stored a reference to the stack, not a copy so if the stack
changed after love mode was started, the breed item in the event
also changed. Also in several places, the breed item was stored after
it was decreased by one to consume the item.

diff --git a/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Animal.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java
@@ -0,0 +0,0 @@ public abstract class Animal extends AgeableMob {
             int i = this.getAge();
 
             if (!this.level().isClientSide && i == 0 && this.canFallInLove()) {
+                final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying
                 this.usePlayerItem(player, hand, itemstack);
-                this.setInLove(player);
+                this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying
                 return InteractionResult.SUCCESS;
             }
 
@@ -0,0 +0,0 @@ public abstract class Animal extends AgeableMob {
         return this.inLove <= 0;
     }
 
+    @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Fix EntityBreedEvent copying
     public void setInLove(@Nullable Player player) {
+        // Paper start - Fix EntityBreedEvent copying
+        this.setInLove(player, null);
+    }
+    public void setInLove(@Nullable Player player, @Nullable ItemStack breedItemCopy) {
+        if (breedItemCopy != null) this.breedItem = breedItemCopy;
+        // Paper end - Fix EntityBreedEvent copying
         // CraftBukkit start
         EntityEnterLoveModeEvent entityEnterLoveModeEvent = CraftEventFactory.callEntityEnterLoveModeEvent(player, this, 600);
         if (entityEnterLoveModeEvent.isCancelled()) {
+            this.breedItem = null; // Paper - Fix EntityBreedEvent copying; clear if cancelled
             return;
         }
         this.inLove = entityEnterLoveModeEvent.getTicksInLove();
@@ -0,0 +0,0 @@ public abstract class Animal extends AgeableMob {
         if (player != null) {
             this.loveCause = player.getUUID();
         }
-        this.breedItem = player.getInventory().getSelected(); // CraftBukkit
+        // Paper - Fix EntityBreedEvent copying; set breed item in better place
 
         this.level().broadcastEntityEvent(this, (byte) 18);
     }
diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java
@@ -0,0 +0,0 @@ public class Panda extends Animal {
                 this.usePlayerItem(player, hand, itemstack);
                 this.ageUp((int) ((float) (-this.getAge() / 20) * 0.1F), true);
             } else if (!this.level().isClientSide && this.getAge() == 0 && this.canFallInLove()) {
+                final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying
                 this.usePlayerItem(player, hand, itemstack);
-                this.setInLove(player);
+                this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying
             } else {
                 if (this.level().isClientSide || this.isSitting() || this.isInWater()) {
                     return InteractionResult.PASS;
diff --git a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java
+++ b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java
@@ -0,0 +0,0 @@ public class Armadillo extends Animal {
     }
 
     @Override
-    public void setInLove(@Nullable Player player) {
-        super.setInLove(player);
+    public void setInLove(@Nullable Player player, @Nullable ItemStack breedItemCopy) { // Paper
+        super.setInLove(player, breedItemCopy); // Paper
         this.makeSound(SoundEvents.ARMADILLO_EAT);
     }
 
diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
+++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java
@@ -0,0 +0,0 @@ public class Camel extends AbstractHorse implements PlayerRideableJumping, Saddl
             boolean flag1 = this.isTamed() && this.getAge() == 0 && this.canFallInLove();
 
             if (flag1) {
-                this.setInLove(player);
+                this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying
             }
 
             boolean flag2 = this.isBaby();
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java
@@ -0,0 +0,0 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
             b0 = 5;
             if (!this.level().isClientSide && this.isTamed() && this.getAge() == 0 && !this.isInLove()) {
                 flag = true;
-                this.setInLove(player);
+                this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying
             }
         } else if (item.is(Items.GOLDEN_APPLE) || item.is(Items.ENCHANTED_GOLDEN_APPLE)) {
             f = 10.0F;
@@ -0,0 +0,0 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
             b0 = 10;
             if (!this.level().isClientSide && this.isTamed() && this.getAge() == 0 && !this.isInLove()) {
                 flag = true;
-                this.setInLove(player);
+                this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying
             }
         }
 
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java
@@ -0,0 +0,0 @@ public class Llama extends AbstractChestedHorse implements VariantHolder<Llama.V
             f = 10.0F;
             if (this.isTamed() && this.getAge() == 0 && this.canFallInLove()) {
                 flag = true;
-                this.setInLove(player);
+                this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying
             }
         }
 
