diff --git a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerTransientModifierUpdateEvent.java b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerTransientModifierUpdateEvent.java new file mode 100644 index 000000000000..3f2418661b49 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerTransientModifierUpdateEvent.java @@ -0,0 +1,86 @@ +package io.papermc.paper.event.player; + +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when the server temporarily updates a player's modifier. This is not called for any arbitrary modifier update + * on the player. + *

+ * Note: Currently only called when a player crouches making their waypoint transmit range attribute disappear. + *

+ */ +@NullMarked +public class PlayerTransientModifierUpdateEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private boolean cancelled; + private final boolean removal; + private final Attribute attribute; + private AttributeModifier modifier; + + @ApiStatus.Internal + public PlayerTransientModifierUpdateEvent(Player player, boolean removal, Attribute attribute, AttributeModifier modifier) { + super(player); + this.removal = removal; + this.attribute = attribute; + this.modifier = modifier; + } + + /** + * Returns whether this event involves a removal or addition of the transient modifier. + * @return whether the modifier is being removed + */ + public boolean isRemoval() { + return this.removal; + } + /** + * The attribute type this modifier is being applied on. + * @return the attribute type + */ + public Attribute getAttribute() { + return this.attribute; + } + + /** + * Returns transient modifier to be updated. + * @return the modifier + */ + public AttributeModifier getModifier() { + return this.modifier; + } + + /** + * Sets the transient modifier to be updated. + * @param modifier the new modifier + */ + public void setModifier(AttributeModifier modifier) { + this.modifier = modifier; + } + + @Override + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index 83043bcd1fe2..78fcee325f86 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -252,7 +252,22 @@ this.containerMenu = this.inventoryMenu; } -@@ -636,10 +_,10 @@ +@@ -626,20 +_,23 @@ + + AttributeInstance attribute2 = this.getAttribute(Attributes.WAYPOINT_TRANSMIT_RANGE); + if (attribute2 != null) { ++ io.papermc.paper.event.player.PlayerTransientModifierUpdateEvent event = new io.papermc.paper.event.player.PlayerTransientModifierUpdateEvent(this.getBukkitEntity(), this.isCrouching(), org.bukkit.attribute.Attribute.WAYPOINT_TRANSMIT_RANGE, org.bukkit.craftbukkit.attribute.CraftAttributeInstance.convert(WAYPOINT_TRANSMIT_RANGE_CROUCH_MODIFIER)); ++ if (!event.callEvent()) return; ++ net.minecraft.world.entity.ai.attributes.AttributeModifier modifier = org.bukkit.craftbukkit.attribute.CraftAttributeInstance.convert(event.getModifier()); + if (this.isCrouching()) { +- attribute2.addOrUpdateTransientModifier(WAYPOINT_TRANSMIT_RANGE_CROUCH_MODIFIER); ++ attribute2.addOrUpdateTransientModifier(modifier); + } else { +- attribute2.removeModifier(WAYPOINT_TRANSMIT_RANGE_CROUCH_MODIFIER); ++ attribute2.removeModifier(modifier); + } + } + } public void doTick() { try {