diff --git a/patches/api/Add-EntityFertilizeEggEvent.patch b/patches/api/Add-EntityFertilizeEggEvent.patch index 764f9da731..ba7d99470a 100644 --- a/patches/api/Add-EntityFertilizeEggEvent.patch +++ b/patches/api/Add-EntityFertilizeEggEvent.patch @@ -23,8 +23,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import org.jetbrains.annotations.Nullable; + +/** -+ * Called when a mating occurs that results in a pregnancy. -+ * After a bit of time, the mother will lay an egg. ++ * Called when two entities mate and the mating process results in a fertilization. ++ * Fertilization differs from normal breeding, as represented by the {@link org.bukkit.event.entity.EntityBreedEvent}, as ++ * it does not result in the immediate creation of the child entity in the world. ++ *

++ * An example of this would be: ++ *

++ * ++ * The event hence only exposes the two parent entities in the fertilization process and cannot provide the child entity, as it will only exist at a later point in time. + */ +public class EntityFertilizeEggEvent extends EntityEvent implements Cancellable { + @@ -58,9 +68,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + /** -+ * Gets the parent creating this entity. ++ * Provides the entity in the fertilization process that will eventually be responsible for "creating" offspring, ++ * may that be by setting a block that later hatches or dropping an egg that has to be placed. + * -+ * @return The "birth" parent ++ * @return The "mother" entity. + */ + @NotNull + public LivingEntity getMother() { @@ -68,7 +79,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + /** -+ * Gets the other parent of the newly born entity. ++ * Provides the "father" entity in the fertilization process that is not responsible for initiating the offspring ++ * creation. + * + * @return the other parent + */ diff --git a/patches/server/Add-EntityFertilizeEggEvent.patch b/patches/server/Add-EntityFertilizeEggEvent.patch index e7ed3b45a0..d3a14192ba 100644 --- a/patches/server/Add-EntityFertilizeEggEvent.patch +++ b/patches/server/Add-EntityFertilizeEggEvent.patch @@ -12,30 +12,93 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (entityplayer == null && this.partner.getLoveCause() != null) { entityplayer = this.partner.getLoveCause(); } -+ // Paper start -+ RandomSource randomsource = this.animal.getRandom(); -+ int experience = randomsource.nextInt(7) + 1; -+ io.papermc.paper.event.entity.EntityFertilizeEggEvent event = new io.papermc.paper.event.entity.EntityFertilizeEggEvent((org.bukkit.entity.LivingEntity) turtle.getBukkitEntity(), (org.bukkit.entity.LivingEntity) partner.getBukkitEntity(), entityplayer == null ? null : entityplayer.getBukkitEntity(), turtle.breedItem == null ? null : org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(turtle.breedItem).clone(), experience); -+ if (!event.callEvent()) { -+ animal.resetLove(); -+ partner.resetLove(); // stop the pathfinding to avoid infinite loop -+ return; -+ } -+ experience = event.getExperience(); -+ // Paper end ++ // Paper start - Add EntityFertilizeEggEvent event ++ io.papermc.paper.event.entity.EntityFertilizeEggEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this.animal, this.partner); ++ if (event.isCancelled()) return; ++ // Paper end - Add EntityFertilizeEggEvent event if (entityplayer != null) { entityplayer.awardStat(Stats.ANIMALS_BRED); @@ -0,0 +0,0 @@ public class Turtle extends Animal { - this.partner.setAge(6000); - this.animal.resetLove(); - this.partner.resetLove(); -- RandomSource randomsource = this.animal.getRandom(); + RandomSource randomsource = this.animal.getRandom(); -- if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { + if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { - this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper; -+ if (experience > 0 && this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper -+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper ++ if(event.getExperience() > 0) this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), event.getExperience(), org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper - Add EntityFertilizeEggEvent event } } +diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java ++++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java +@@ -0,0 +0,0 @@ public class Frog extends Animal implements VariantHolder { + + @Override + public void spawnChildFromBreeding(ServerLevel world, Animal other) { +- this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob)null); ++ // Paper start - Add EntityFertilizeEggEvent event ++ final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other); ++ if (result.isCancelled()) return; ++ ++ this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob)null, result.getExperience()); // Paper - use craftbukkit call that takes experience amount ++ // Paper end - Add EntityFertilizeEggEvent event + this.getBrain().setMemory(MemoryModuleType.IS_PREGNANT, Unit.INSTANCE); + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java ++++ b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java +@@ -0,0 +0,0 @@ public class Sniffer extends Animal { + + @Override + public void spawnChildFromBreeding(ServerLevel world, Animal other) { ++ // Paper start - Add EntityFertilizeEggEvent event ++ final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other); ++ if (result.isCancelled()) return; ++ // Paper end - Add EntityFertilizeEggEvent event ++ + ItemStack itemstack = new ItemStack(Items.SNIFFER_EGG); + ItemEntity entityitem = new ItemEntity(world, this.position().x(), this.position().y(), this.position().z(), itemstack); + + entityitem.setDefaultPickUpDelay(); +- this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null); ++ this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null, result.getExperience()); // Paper - Add EntityFertilizeEggEvent event + this.playSound(SoundEvents.SNIFFER_EGG_PLOP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 0.5F); + world.addFreshEntity(entityitem); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -0,0 +0,0 @@ public class CraftEventFactory { + return event.callEvent(); + } + // Paper end ++ ++ // Paper start - add EntityFertilizeEggEvent ++ /** ++ * Calls the io.papermc.paper.event.entity.EntityFertilizeEggEvent. ++ * If the event is cancelled, this method also resets the love on both the {@code breeding} and {@code other} entity. ++ * ++ * @param breeding the entity on which #spawnChildFromBreeding was called. ++ * @param other the partner of the entity. ++ * @return the event after it was called. The instance may be used to retrieve the experience of the event. ++ */ ++ public static io.papermc.paper.event.entity.EntityFertilizeEggEvent callEntityFertilizeEggEvent(net.minecraft.world.entity.animal.Animal breeding, ++ net.minecraft.world.entity.animal.Animal other) { ++ net.minecraft.server.level.ServerPlayer serverPlayer = breeding.getLoveCause(); ++ if (serverPlayer == null) serverPlayer = other.getLoveCause(); ++ final int experience = breeding.getRandom().nextInt(7) + 1; // From Animal#spawnChildFromBreeding(ServerLevel, Animal) ++ ++ final io.papermc.paper.event.entity.EntityFertilizeEggEvent event = new io.papermc.paper.event.entity.EntityFertilizeEggEvent((org.bukkit.entity.LivingEntity) breeding.getBukkitEntity(), (org.bukkit.entity.LivingEntity) other.getBukkitEntity(), serverPlayer == null ? null : serverPlayer.getBukkitEntity(), breeding.breedItem == null ? null : org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(breeding.breedItem).clone(), experience); ++ if (!event.callEvent()) { ++ breeding.resetLove(); ++ other.resetLove(); // stop the pathfinding to avoid infinite loop ++ } ++ ++ return event; ++ } ++ // Paper end - add EntityFertilizeEggEvent + }