From ca5d7523e28ee335d0e6018add2d42fae3d4479b Mon Sep 17 00:00:00 2001 From: amyavi <144570677+amyavi@users.noreply.github.com> Date: Thu, 31 Jul 2025 16:23:23 -0300 Subject: [PATCH 1/4] refactor: improve attribute reset code Now it accounts for the entity's default attribute being different from the attribute's default. --- .../extras/modules/player/PlayerDamage.java | 13 +++--------- .../extras/modules/player/PlayerTeleport.java | 2 +- .../java/pw/kaboom/extras/util/Utility.java | 21 +++++++++++++++---- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerDamage.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerDamage.java index f3c04bdf..b97eb4af 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerDamage.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerDamage.java @@ -53,7 +53,7 @@ void onFoodLevelChange(final FoodLevelChangeEvent event) { final AttributeInstance attribute = player.getAttribute(Attribute.MAX_HEALTH); if (attribute == null) return; if (attribute.getValue() <= 0) { - Utility.resetAttribute(attribute); + Utility.resetAttribute(player, Attribute.MAX_HEALTH); player.setHealth(20); } } @@ -97,11 +97,7 @@ void onPlayerDeath(final PlayerDeathEvent event) { xp.setExperience(event.getDroppedExp()); } - final AttributeInstance attribute = player.getAttribute(Attribute.MAX_HEALTH); - if (attribute != null) { - Utility.resetAttribute(attribute); - } - + Utility.resetAttribute(player, Attribute.MAX_HEALTH); player.setHealth(20); if (player.getRespawnLocation() != null) { @@ -111,10 +107,7 @@ void onPlayerDeath(final PlayerDeathEvent event) { player.teleportAsync(world.getSpawnLocation()); } } catch (Exception exception) { - final AttributeInstance attribute = player.getAttribute(Attribute.MAX_HEALTH); - if (attribute != null) { - Utility.resetAttribute(attribute); - } + Utility.resetAttribute(player, Attribute.MAX_HEALTH); player.setHealth(20); } diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerTeleport.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerTeleport.java index 0c94ff2e..ddafbbe6 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerTeleport.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerTeleport.java @@ -16,7 +16,7 @@ void onPlayerChangedWorld(final PlayerChangedWorldEvent event) { final AttributeInstance attribute = player.getAttribute(Attribute.MAX_HEALTH); if (attribute == null) return; if (attribute.getValue() <= 0) { - Utility.resetAttribute(attribute); + Utility.resetAttribute(player, Attribute.MAX_HEALTH); player.setHealth(20); } } diff --git a/src/main/java/pw/kaboom/extras/util/Utility.java b/src/main/java/pw/kaboom/extras/util/Utility.java index 9c1968f4..18f5dceb 100644 --- a/src/main/java/pw/kaboom/extras/util/Utility.java +++ b/src/main/java/pw/kaboom/extras/util/Utility.java @@ -1,8 +1,11 @@ package pw.kaboom.extras.util; import org.bukkit.Bukkit; +import org.bukkit.attribute.Attributable; +import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; import org.bukkit.attribute.AttributeModifier; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import javax.annotation.Nonnull; @@ -19,12 +22,22 @@ public final class Utility { .orElse(null); } - public static void resetAttribute(final AttributeInstance attribute) { - for (final AttributeModifier modifier: attribute.getModifiers()) { - attribute.removeModifier(modifier); + public static void resetAttribute (final T entity, + final Attribute attrib) { + final AttributeInstance instance = entity.getAttribute(attrib); + if (instance == null) return; + + for (final AttributeModifier modifier : instance.getModifiers()) { + instance.removeModifier(modifier); } - attribute.setBaseValue(attribute.getDefaultValue()); + final AttributeInstance defaultInstance = entity.getType().getDefaultAttributes() + .getAttribute(instance.getAttribute()); + if (defaultInstance != null) { + instance.setBaseValue(defaultInstance.getBaseValue()); + } else { + instance.setBaseValue(instance.getDefaultValue()); + } } // TODO: Support hex color codes, too (they aren't supported in Spigot either) From 641b43b8a15926c4feb8c8bfbd763f67beab6fbb Mon Sep 17 00:00:00 2001 From: amyavi <144570677+amyavi@users.noreply.github.com> Date: Thu, 31 Jul 2025 17:32:44 -0300 Subject: [PATCH 2/4] refactor: cleanup prefix rendering Now with 50% less map access per chat :) --- .../extras/modules/player/PlayerChat.java | 12 +++---- .../extras/modules/player/PlayerPrefix.java | 36 +++++++++---------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java index a40644e7..bc8ef4a0 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java @@ -98,11 +98,6 @@ private Component renderVanilla(@Nonnull Component displayName, @Nonnull Component displayName, @Nonnull Component component, @Nonnull Audience audience) { - if (PlayerPrefix.isUsingVanillaFormat(player)) { - return renderVanilla(displayName, component); - } - - Component newComponent = Component.empty(); final Component prefix; Component prefix1; @@ -114,9 +109,12 @@ private Component renderVanilla(@Nonnull Component displayName, } prefix = prefix1; - final String message = ((TextComponent) component).content(); + if (prefix == null) { + return renderVanilla(displayName, component); + } - newComponent = newComponent + final String message = ((TextComponent) component).content(); + final Component newComponent = Component.empty() .append(prefix) .append(displayName) .append(Component.text(":")) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerPrefix.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerPrefix.java index 1e5a7fdb..efae707f 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerPrefix.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerPrefix.java @@ -13,6 +13,7 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitScheduler; +import org.jetbrains.annotations.Nullable; import pw.kaboom.extras.Main; import java.io.File; @@ -74,21 +75,14 @@ public static Component setPrefix(Player player, String legacyPrefix) throws IOE return prefix; } - public static boolean isUsingVanillaFormat(Player player) { + public static @Nullable Component getPrefix(Player player) throws IOException { final UUID playerUUID = player.getUniqueId(); final String stringifiedUUID = playerUUID.toString(); final String legacyPrefix = PREFIX_CONFIG.getString(stringifiedUUID); - - return legacyPrefix != null && legacyPrefix.equals("%"); - } - - public static Component getPrefix(Player player) throws IOException { - final UUID playerUUID = player.getUniqueId(); - final String stringifiedUUID = playerUUID.toString(); - final String legacyPrefix = PREFIX_CONFIG.getString(stringifiedUUID); - if (legacyPrefix == null) { - return player.isOp() ? OP_TAG : DE_OP_TAG; + return getDefaultPrefix(player); + } else if (legacyPrefix.equals("%")) { + return null; } return LegacyComponentSerializer.legacyAmpersand() @@ -101,14 +95,18 @@ public static Component getDefaultPrefix(Player player) { } private static void onUpdate(Player player) throws IOException { - final Component component = Component.empty() - .append( - isUsingVanillaFormat(player) ? - Component.empty() : getPrefix(player) - ) - .append(player.displayName()); - - player.playerListName(component); + final Component prefix = getPrefix(player); + + final Component playerListName; + if (prefix != null) { + playerListName = Component.empty() + .append(prefix) + .append(player.displayName()); + } else { + playerListName = player.displayName(); + } + + player.playerListName(playerListName); } @EventHandler(priority = EventPriority.MONITOR) From a15256cd274b193629570a7da27744ab786a6e52 Mon Sep 17 00:00:00 2001 From: amyavi <144570677+amyavi@users.noreply.github.com> Date: Thu, 31 Jul 2025 17:49:48 -0300 Subject: [PATCH 3/4] perf: make our chat renderer ViewerUnaware This means it gets rendered only once per message, instead of being rendered for each viewer. --- .../java/pw/kaboom/extras/modules/player/PlayerChat.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java index bc8ef4a0..d604001c 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java @@ -42,10 +42,10 @@ void onAsyncChatEventProcess(final AsyncChatEvent event) { @EventHandler(priority = EventPriority.MONITOR) void onAsyncChatEventRenderer(final AsyncChatEvent event) { - event.renderer(CHAT_RENDERER); + event.renderer(ChatRenderer.viewerUnaware(CHAT_RENDERER)); } - public static class PlayerChatRenderer implements ChatRenderer { + public static class PlayerChatRenderer implements ChatRenderer.ViewerUnaware { private static final TextReplacementConfig URL_REPLACEMENT_CONFIG = TextReplacementConfig .builder() @@ -96,8 +96,7 @@ private Component renderVanilla(@Nonnull Component displayName, @Override public @Nonnull Component render(@Nonnull Player player, @Nonnull Component displayName, - @Nonnull Component component, - @Nonnull Audience audience) { + @Nonnull Component component) { final Component prefix; Component prefix1; From 3d94b91c9689bdbf13ab5a40ea31d123fd427359 Mon Sep 17 00:00:00 2001 From: amyavi <144570677+amyavi@users.noreply.github.com> Date: Thu, 31 Jul 2025 18:10:55 -0300 Subject: [PATCH 4/4] refactor: use LegacyComponentSerializer for rendering urls Behaves exactly like before, just with less code. --- .../extras/modules/player/PlayerChat.java | 89 +++++++------------ 1 file changed, 30 insertions(+), 59 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java index d604001c..5bcf2704 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java @@ -2,12 +2,10 @@ import io.papermc.paper.chat.ChatRenderer; import io.papermc.paper.event.player.AsyncChatEvent; -import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; -import net.kyori.adventure.text.TextReplacementConfig; -import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.entity.Player; @@ -46,57 +44,37 @@ void onAsyncChatEventRenderer(final AsyncChatEvent event) { } public static class PlayerChatRenderer implements ChatRenderer.ViewerUnaware { - private static final TextReplacementConfig URL_REPLACEMENT_CONFIG = - TextReplacementConfig - .builder() - .match(Pattern - .compile("((https?://(ww(w|\\d)\\.)?|ww(w|\\d))[-a-zA-Z0-9@:%._+~#=]{1,256}" - + "\\.[a-zA-Z0-9]{2,6}\\b([-a-zA-Z0-9@:%_+.~#?&/=]*))")) - .replacement((b, c) -> { - if (c == null) { - return null; - } - - if (b.groupCount() < 1) { - return null; - } - - final String content = b.group(1); - final String url; - - /* - Minecraft doesn't accept "www.google.com" as a URL - in click events - */ - if (content.contains("://")) { - url = content; - } else { - url = "https://" + content; - } - - return Component.text(content, NamedTextColor.BLUE) - .decorate(TextDecoration.UNDERLINED) - .clickEvent(ClickEvent.openUrl(url)); - }) - .build(); - - private static final LegacyComponentSerializer LEGACY_COMPONENT_SERIALIZER = - LegacyComponentSerializer - .legacyAmpersand(); - - private Component renderVanilla(@Nonnull Component displayName, - @Nonnull Component component) { - return Component.translatable( - "chat.type.text", - displayName, - component.replaceText(URL_REPLACEMENT_CONFIG) - ); + private static final Pattern URL_PATTERN = Pattern + .compile("((https?://(ww(w|\\d)\\.)?|ww(w|\\d))[-a-zA-Z0-9@:%._+~#=]{1,256}" + + "\\.[a-zA-Z0-9]{2,6}\\b([-a-zA-Z0-9@:%_+.~#?&/=]*))"); + private static final Style URL_STYLE = Style.style(NamedTextColor.BLUE, + TextDecoration.UNDERLINED); + + // Match vanilla by only rendering section sign legacy colors in vanilla chat + private static final LegacyComponentSerializer VANILLA_CHAT_SERIALIZER = + LegacyComponentSerializer.builder() + .character(LegacyComponentSerializer.SECTION_CHAR) + .extractUrls(URL_PATTERN, URL_STYLE) + .hexColors() + .build(); + + private static final LegacyComponentSerializer CHAT_SERIALIZER = + LegacyComponentSerializer.builder() + .character(LegacyComponentSerializer.AMPERSAND_CHAR) + .extractUrls(URL_PATTERN, URL_STYLE) + .hexColors() + .build(); + + private Component renderVanilla(final @Nonnull Component displayName, + final @Nonnull Component component) { + return Component.translatable("chat.type.text", displayName, component); } @Override public @Nonnull Component render(@Nonnull Player player, @Nonnull Component displayName, @Nonnull Component component) { + final String message = ((TextComponent) component).content(); final Component prefix; Component prefix1; @@ -109,22 +87,15 @@ private Component renderVanilla(@Nonnull Component displayName, prefix = prefix1; if (prefix == null) { - return renderVanilla(displayName, component); + return renderVanilla(displayName, VANILLA_CHAT_SERIALIZER.deserialize(message)); } - final String message = ((TextComponent) component).content(); - final Component newComponent = Component.empty() + return Component.empty() .append(prefix) .append(displayName) .append(Component.text(":")) - .append(Component.space()); - - final Component messageWithColorCodes = LEGACY_COMPONENT_SERIALIZER - .deserialize(message); - final Component completedMessage = messageWithColorCodes - .replaceText(URL_REPLACEMENT_CONFIG); - - return newComponent.append(completedMessage); + .append(Component.space()) + .append(CHAT_SERIALIZER.deserialize(message)); } } }