From 36b5ec92b3a9de285b128ec9597b0d5f6fd218c0 Mon Sep 17 00:00:00 2001 From: Warrior <50800980+Warriorrrr@users.noreply.github.com> Date: Fri, 7 Aug 2026 13:18:54 +0200 Subject: [PATCH] Improve EntityAirChangeEvent Adds guards to avoid calling the event if it has no listeners, and prevents calling the event if no change occurred. This event is potentially hot since all WaterAnimals call it once every tick (even when no change occurs). The resend for players when cancelled did not seem to be needed, when using the event to cancel or hardcode the amount of air I had I wasn't able to see any desync occurring --- .../java/org/bukkit/event/HandlerList.java | 7 ++++++ .../minecraft/world/entity/Entity.java.patch | 22 +++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/event/HandlerList.java b/paper-api/src/main/java/org/bukkit/event/HandlerList.java index ef9d9f3ddaf2..c6f5800024ce 100644 --- a/paper-api/src/main/java/org/bukkit/event/HandlerList.java +++ b/paper-api/src/main/java/org/bukkit/event/HandlerList.java @@ -206,6 +206,13 @@ public synchronized void bake() { return handlers; } + /** + * {@return whether this handler list has any listeners} + */ + public boolean hasListeners() { + return getRegisteredListeners().length != 0; + } + /** * Get a specific plugin's registered listeners associated with this * handler list diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch index 1c621b870cac..cd2e42a2b4de 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -1322,20 +1322,20 @@ public void setAirSupply(final int supply) { - this.entityData.set(DATA_AIR_SUPPLY_ID, supply); -+ // CraftBukkit start -+ org.bukkit.event.entity.EntityAirChangeEvent event = new org.bukkit.event.entity.EntityAirChangeEvent(this.getBukkitEntity(), supply); ++ // Paper start - EntityAirChangeEvent ++ int newAmount = supply; + // Suppress during worldgen -+ if (this.valid) { -+ event.getEntity().getServer().getPluginManager().callEvent(event); -+ } -+ if (event.isCancelled() && this.getAirSupply() != supply) { -+ if (this instanceof ServerPlayer player) { -+ this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_AIR_SUPPLY_ID), player); // todo is that even needed? ++ if (this.valid && org.bukkit.event.entity.EntityAirChangeEvent.getHandlerList().hasListeners() && this.getAirSupply() != supply) { ++ final org.bukkit.event.entity.EntityAirChangeEvent event = new org.bukkit.event.entity.EntityAirChangeEvent(this.getBukkitEntity(), supply); ++ if (!event.callEvent()) { ++ return; + } -+ return; ++ ++ newAmount = event.getAmount(); + } -+ this.entityData.set(DATA_AIR_SUPPLY_ID, event.getAmount()); -+ // CraftBukkit end ++ ++ this.entityData.set(DATA_AIR_SUPPLY_ID, newAmount); ++ // Paper end - EntityAirChangeEvent } public void clearFreeze() {