From ae2a5bf12f3ed13dc95c8947f8f1fe4210136a2c Mon Sep 17 00:00:00 2001 From: Clexus <528373858@qq.com> Date: Fri, 7 Aug 2026 10:03:15 +0800 Subject: [PATCH 1/2] Add ZombieBecomeLeaderEvent --- .../event/entity/ZombieBecomeLeaderEvent.java | 47 +++++++++++++++++++ .../entity/monster/zombie/Zombie.java.patch | 36 ++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 paper-api/src/main/java/io/papermc/paper/event/entity/ZombieBecomeLeaderEvent.java diff --git a/paper-api/src/main/java/io/papermc/paper/event/entity/ZombieBecomeLeaderEvent.java b/paper-api/src/main/java/io/papermc/paper/event/entity/ZombieBecomeLeaderEvent.java new file mode 100644 index 000000000000..c2b867a09d04 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/entity/ZombieBecomeLeaderEvent.java @@ -0,0 +1,47 @@ +package io.papermc.paper.event.entity; + +import org.bukkit.entity.Zombie; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when a zombie becomes a leader zombie and gets extra attributes + * and the ability to break door. + *

+ * If the event is cancelled, the zombie will not have the extra attributes + * or door-breaking ability. + */ + +@NullMarked +public class ZombieBecomeLeaderEvent extends EntityEvent implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + private boolean cancelled; + + @ApiStatus.Internal + public ZombieBecomeLeaderEvent(final Zombie zombie) { + super(zombie); + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch index 6771344f6050..e458820a2799 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch @@ -229,3 +229,39 @@ } } +@@ -546,19 +_,23 @@ + } + + if (this.random.nextFloat() < difficultyModifier * 0.05F) { +- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE) +- .addOrReplacePermanentModifier( +- new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 0.25 + 0.5, AttributeModifier.Operation.ADD_VALUE) +- ); +- this.getAttribute(Attributes.MAX_HEALTH) +- .addOrReplacePermanentModifier( +- new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 3.0 + 1.0, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL) +- ); +- if (spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) { +- this.setHealth(this.getMaxHealth()); +- } ++ // Paper start - Add ZombieBecomeLeaderEvent ++ if(new io.papermc.paper.event.entity.ZombieBecomeLeaderEvent((org.bukkit.entity.Zombie) this.getBukkitEntity()).callEvent()){ ++ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE) ++ .addOrReplacePermanentModifier( ++ new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 0.25 + 0.5, AttributeModifier.Operation.ADD_VALUE) ++ ); ++ this.getAttribute(Attributes.MAX_HEALTH) ++ .addOrReplacePermanentModifier( ++ new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 3.0 + 1.0, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL) ++ ); ++ if (spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) { ++ this.setHealth(this.getMaxHealth()); ++ } + +- this.setCanBreakDoors(true); ++ this.setCanBreakDoors(true); ++ } ++ // Paper end - Add ZombieBecomeLeaderEvent + } + } + From e07b3ecb4c7198f613d099b41a280c2fd2ee3b4c Mon Sep 17 00:00:00 2001 From: Clexus <528373858@qq.com> Date: Fri, 7 Aug 2026 23:03:16 +0800 Subject: [PATCH 2/2] Move call --- .../entity/monster/zombie/Zombie.java.patch | 44 ++++++------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch index e458820a2799..81824ec603bd 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch @@ -229,39 +229,21 @@ } } -@@ -546,19 +_,23 @@ +@@ -545,7 +_,7 @@ + ); } - if (this.random.nextFloat() < difficultyModifier * 0.05F) { -- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE) -- .addOrReplacePermanentModifier( -- new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 0.25 + 0.5, AttributeModifier.Operation.ADD_VALUE) -- ); -- this.getAttribute(Attributes.MAX_HEALTH) -- .addOrReplacePermanentModifier( -- new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 3.0 + 1.0, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL) -- ); -- if (spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) { -- this.setHealth(this.getMaxHealth()); -- } -+ // Paper start - Add ZombieBecomeLeaderEvent -+ if(new io.papermc.paper.event.entity.ZombieBecomeLeaderEvent((org.bukkit.entity.Zombie) this.getBukkitEntity()).callEvent()){ -+ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE) -+ .addOrReplacePermanentModifier( -+ new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 0.25 + 0.5, AttributeModifier.Operation.ADD_VALUE) -+ ); -+ this.getAttribute(Attributes.MAX_HEALTH) -+ .addOrReplacePermanentModifier( -+ new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 3.0 + 1.0, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL) -+ ); -+ if (spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) { -+ this.setHealth(this.getMaxHealth()); -+ } +- if (this.random.nextFloat() < difficultyModifier * 0.05F) { ++ if (this.random.nextFloat() < difficultyModifier * 0.05F && (new io.papermc.paper.event.entity.ZombieBecomeLeaderEvent((org.bukkit.entity.Zombie) this.getBukkitEntity())).callEvent()) { // Paper start - Add ZombieBecomeLeaderEvent + this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE) + .addOrReplacePermanentModifier( + new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 0.25 + 0.5, AttributeModifier.Operation.ADD_VALUE) +@@ -559,7 +_,7 @@ + } -- this.setCanBreakDoors(true); -+ this.setCanBreakDoors(true); -+ } -+ // Paper end - Add ZombieBecomeLeaderEvent - } + this.setCanBreakDoors(true); +- } ++ } // Paper end - Add ZombieBecomeLeaderEvent } + protected void randomizeReinforcementsChance() {