From 34d9f70ac0c8b90ea629852decb6c491561f288a Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 9 Nov 2020 13:19:54 -0800 Subject: [PATCH] Fixed a bug where party members didn't have properly colored names, added some optimization and removed some unnecessary API --- Changelog.txt | 12 ++- pom.xml | 2 +- .../com/gmail/nossr50/chat/ChatManager.java | 11 ++- .../chat/author/AbstractPlayerAuthor.java | 99 ++++++++++++------- .../com/gmail/nossr50/chat/author/Author.java | 15 --- .../nossr50/chat/author/ConsoleAuthor.java | 12 +-- .../nossr50/chat/author/PlayerAuthor.java | 16 +-- .../nossr50/chat/mailer/AdminChatMailer.java | 15 ++- .../nossr50/chat/mailer/PartyChatMailer.java | 17 +++- .../chat/message/PartyChatMessage.java | 3 +- .../java/com/gmail/nossr50/util/Misc.java | 11 +++ .../gmail/nossr50/util/text/TextUtils.java | 6 -- 12 files changed, 124 insertions(+), 95 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 0e4573159..df2f38d3d 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,13 @@ +Version 2.1.155 + Optimized party/admin chat a bit + Fixed a bug where party members other than the party leader had names that weren't properly hex colored + (API) Removed AbstractPlayerAuthor#getComponentDisplayName + (API) Removed AbstractPlayerAuthor#getComponentUserName + (API) Removed Author#getAuthoredComponentName + + NOTES: + Removed some unnecessary API, we aren't a chat plugin so these things shouldn't be here. + Version 2.1.154 Hex colors are now supported in Party & Admin chat Added support for &#RRGGBB color codes (hex colors) in chat and nicknames for party and admin chat @@ -6,7 +16,7 @@ Version 2.1.154 Fixed a bug where using admin chat would in some circumstances throw a NPE (API) Author class has been reworked (API) McMMOChatEvent::getSender removed (use getDisplayName() instead) - (API) McMMMOChatEvent::setDisplayName() removed (you can set author names in Author) + (API) McMMMOChatEvent::setDisplayName() removed (API) Removed Author::setName use Player::SetDisplayName instead (API) Modified Author::getAuthoredName signature to -> Author::getAuthoredName(ChatChannel) (API) Added Author::getAuthoredComponentName(ChatChannel) diff --git a/pom.xml b/pom.xml index 246612928..3b24bfcb2 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.154 + 2.1.155-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/chat/ChatManager.java b/src/main/java/com/gmail/nossr50/chat/ChatManager.java index ae6499583..a0a1e6f30 100644 --- a/src/main/java/com/gmail/nossr50/chat/ChatManager.java +++ b/src/main/java/com/gmail/nossr50/chat/ChatManager.java @@ -10,6 +10,7 @@ import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.text.StringUtils; import net.kyori.adventure.audience.Audience; @@ -39,6 +40,7 @@ public class ChatManager { /** * Handles player messaging when they are either in party chat or admin chat modes + * * @param mmoPlayer target player * @param rawMessage the raw message from the player as it was typed * @param isAsync whether or not this is getting processed via async @@ -49,6 +51,7 @@ public class ChatManager { /** * Handles player messaging for a specific chat channel + * * @param mmoPlayer target player * @param args the raw command arguments from the player * @param chatChannel target channel @@ -62,6 +65,7 @@ public class ChatManager { /** * Handles player messaging for a specific chat channel + * * @param mmoPlayer target player * @param chatChannel target chat channel * @param rawMessage raw chat message as it was typed @@ -73,7 +77,7 @@ public class ChatManager { adminChatMailer.processChatMessage(mmoPlayer.getPlayerAuthor(), rawMessage, isAsync, Permissions.colorChat(mmoPlayer.getPlayer())); break; case PARTY: - partyChatMailer.processChatMessage(mmoPlayer.getPlayerAuthor(), rawMessage, mmoPlayer.getParty(), isAsync, Permissions.colorChat(mmoPlayer.getPlayer()), isPartyLeader(mmoPlayer)); + partyChatMailer.processChatMessage(mmoPlayer.getPlayerAuthor(), rawMessage, mmoPlayer.getParty(), isAsync, Permissions.colorChat(mmoPlayer.getPlayer()), Misc.isPartyLeader(mmoPlayer)); break; case PARTY_OFFICER: case NONE: @@ -81,10 +85,6 @@ public class ChatManager { } } - private boolean isPartyLeader(@NotNull McMMOPlayer mmoPlayer) { - return mmoPlayer.getParty().getLeader().getUniqueId().equals(mmoPlayer.getPlayer().getUniqueId()); - } - /** * Handles console messaging to admins * @param rawMessage raw message from the console @@ -221,4 +221,5 @@ public class ChatManager { } } } + } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java b/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java index 7cc36eee7..e2bb7c7e0 100644 --- a/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java +++ b/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java @@ -1,64 +1,87 @@ package com.gmail.nossr50.chat.author; +import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.util.text.TextUtils; import com.google.common.base.Objects; -import net.kyori.adventure.text.TextComponent; import org.bukkit.entity.Player; import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import java.util.HashMap; import java.util.UUID; public abstract class AbstractPlayerAuthor implements Author { private final @NotNull Player player; - private @NotNull String displayName; - private @Nullable TextComponent componentDisplayName; - private @Nullable TextComponent componentUserName; + private @NotNull String lastKnownDisplayName; + private final @NotNull HashMap sanitizedNameCache; public AbstractPlayerAuthor(@NotNull Player player) { this.player = player; - this.displayName = player.getDisplayName(); + this.lastKnownDisplayName = player.getDisplayName(); + this.sanitizedNameCache = new HashMap<>(); } /** - * Grabs the {@link TextComponent} version of a players display name - * Cached and only processed as needed - * Always checks if the player display name has changed, if it has it regenerates the output + * Returns true if a players display name has changed * - * @return the {@link TextComponent} version of a players display name + * @return true if the players display name has changed */ - public @NotNull TextComponent getComponentDisplayName() { - //Not sure if this is expensive but it ensures always up to date names - if(!player.getDisplayName().equals(displayName)) { - displayName = player.getDisplayName(); - componentDisplayName = null; - } - - if(componentDisplayName != null) { - return componentDisplayName; - } else { - //convert to adventure component - componentDisplayName = TextUtils.ofLegacyTextRaw(displayName); - } - return componentDisplayName; + private boolean hasPlayerDisplayNameChanged() { + return !player.getDisplayName().equals(lastKnownDisplayName); } /** - * Grabs the {@link TextComponent} version of a players current minecraft nickname - * Cached and only processed as needed - * - * @return the {@link TextComponent} version of a players current minecraft nickname + * Player display names can change and this method will update the last known display name of this player */ - public @NotNull TextComponent getComponentUserName() { - //Not sure if this is expensive but it ensures always up to date names - if(componentUserName != null) { - return componentUserName; + private void updateLastKnownDisplayName() { + lastKnownDisplayName = player.getDisplayName(); + } + + /** + * Gets a sanitized name for a channel + * Sanitized names are names that are friendly to the {@link net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer} + * Sanitized names for authors are cached by channel and are only created as needed + * Sanitized names will update if a players display name has updated + * + * @param chatChannel target chat channel + * @return the sanitized name for a player + */ + protected @NotNull String getSanitizedName(@NotNull ChatChannel chatChannel, boolean useDisplayName) { + //Already in cache + if(sanitizedNameCache.containsKey(chatChannel)) { + //Update cache + if(useDisplayName && hasPlayerDisplayNameChanged()) { + updateLastKnownDisplayName(); + updateSanitizedNameCache(chatChannel, true); + } } else { - //convert to adventure component - componentUserName = TextUtils.ofLegacyTextRaw(player.getName()); + //Update last known display name + if(useDisplayName && hasPlayerDisplayNameChanged()) { + updateLastKnownDisplayName(); + } + + //Add cache entry + updateSanitizedNameCache(chatChannel, useDisplayName); + } + + return sanitizedNameCache.get(chatChannel); + } + + /** + * Update the sanitized name cache + * This will add entries if one didn't exit + * Sanitized names are associated with a {@link ChatChannel} as different chat channels have different chat name settings + * + * @param chatChannel target chat channel + * @param useDisplayName whether or not to use this authors display name + */ + private void updateSanitizedNameCache(@NotNull ChatChannel chatChannel, boolean useDisplayName) { + if(useDisplayName) { + sanitizedNameCache.put(chatChannel, TextUtils.sanitizeForSerializer(player.getDisplayName())); + } else { + //No need to sanitize a basic String + sanitizedNameCache.put(chatChannel, player.getName()); } - return componentUserName; } @Override @@ -85,11 +108,13 @@ public abstract class AbstractPlayerAuthor implements Author { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AbstractPlayerAuthor that = (AbstractPlayerAuthor) o; - return Objects.equal(player, that.player); + return Objects.equal(player, that.player) && + Objects.equal(lastKnownDisplayName, that.lastKnownDisplayName) && + Objects.equal(sanitizedNameCache, that.sanitizedNameCache); } @Override public int hashCode() { - return Objects.hashCode(player); + return Objects.hashCode(player, lastKnownDisplayName, sanitizedNameCache); } } diff --git a/src/main/java/com/gmail/nossr50/chat/author/Author.java b/src/main/java/com/gmail/nossr50/chat/author/Author.java index 36977b99e..6f45a21b7 100644 --- a/src/main/java/com/gmail/nossr50/chat/author/Author.java +++ b/src/main/java/com/gmail/nossr50/chat/author/Author.java @@ -2,25 +2,10 @@ package com.gmail.nossr50.chat.author; import com.gmail.nossr50.datatypes.chat.ChatChannel; import net.kyori.adventure.identity.Identity; -import net.kyori.adventure.text.TextComponent; import org.jetbrains.annotations.NotNull; public interface Author extends Identity { - /** - * The name of this author as used in mcMMO chat - * This is the {@link TextComponent} representation of the users current chat username - * This can either be the player's display name or the player's official registered nickname with Mojang it depends on the servers chat settings for mcMMO - * - * NOTE: - * mcMMO doesn't transform a players name into a component when creating the chat message, instead it converts the whole string from raw legacy text (including md5 stuff) -> TextComponent via {@link net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer} - * This method is just provided for convenience, it uses lazy initialization - * - * @param chatChannel which chat channel this is going to - * @return The name of this author as used in mcMMO chat - */ - @NotNull TextComponent getAuthoredComponentName(@NotNull ChatChannel chatChannel); - /** * The name of this author as used in mcMMO chat * This is the {@link String} representation of the users current chat username diff --git a/src/main/java/com/gmail/nossr50/chat/author/ConsoleAuthor.java b/src/main/java/com/gmail/nossr50/chat/author/ConsoleAuthor.java index 978b5d544..3c6452d32 100644 --- a/src/main/java/com/gmail/nossr50/chat/author/ConsoleAuthor.java +++ b/src/main/java/com/gmail/nossr50/chat/author/ConsoleAuthor.java @@ -2,7 +2,6 @@ package com.gmail.nossr50.chat.author; import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.util.text.TextUtils; -import net.kyori.adventure.text.TextComponent; import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; @@ -11,20 +10,13 @@ import java.util.UUID; public class ConsoleAuthor implements Author { private final UUID uuid; private final @NotNull String name; - private final @NotNull TextComponent componentName; public ConsoleAuthor(@NotNull String name) { this.uuid = new UUID(0, 0); - this.name = name; - this.componentName = TextUtils.ofBungeeRawStrings(name); - } - - //TODO: Think of a better solution later - @Override - public @NotNull TextComponent getAuthoredComponentName(@NotNull ChatChannel chatChannel) { - return componentName; + this.name = TextUtils.sanitizeForSerializer(name); } + //TODO: Think of a less clunky solution later @Override public @NotNull String getAuthoredName(@NotNull ChatChannel chatChannel) { return name; diff --git a/src/main/java/com/gmail/nossr50/chat/author/PlayerAuthor.java b/src/main/java/com/gmail/nossr50/chat/author/PlayerAuthor.java index 1921faaed..72383e96e 100644 --- a/src/main/java/com/gmail/nossr50/chat/author/PlayerAuthor.java +++ b/src/main/java/com/gmail/nossr50/chat/author/PlayerAuthor.java @@ -2,7 +2,6 @@ package com.gmail.nossr50.chat.author; import com.gmail.nossr50.config.ChatConfig; import com.gmail.nossr50.datatypes.chat.ChatChannel; -import net.kyori.adventure.text.TextComponent; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -12,22 +11,9 @@ public class PlayerAuthor extends AbstractPlayerAuthor { super(player); } - @Override - public @NotNull TextComponent getAuthoredComponentName(@NotNull ChatChannel chatChannel) { - if(ChatConfig.getInstance().useDisplayNames(chatChannel)) { - return getComponentDisplayName(); - } else { - return getComponentUserName(); - } - } - @Override public @NotNull String getAuthoredName(@NotNull ChatChannel chatChannel) { - if(ChatConfig.getInstance().useDisplayNames(chatChannel)) { - return getPlayer().getDisplayName(); - } else { - return getPlayer().getName(); - } + return getSanitizedName(chatChannel, ChatConfig.getInstance().useDisplayNames(chatChannel)); } } diff --git a/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java b/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java index a238d4e63..de922e56a 100644 --- a/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java +++ b/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java @@ -29,6 +29,7 @@ public class AdminChatMailer extends AbstractChatMailer { /** * Constructs an audience of admins + * * @return an audience of admins */ public @NotNull Audience constructAudience() { @@ -37,6 +38,7 @@ public class AdminChatMailer extends AbstractChatMailer { /** * Predicate used to filter the audience + * * @return admin chat audience predicate */ public @NotNull Predicate predicate() { @@ -47,6 +49,7 @@ public class AdminChatMailer extends AbstractChatMailer { /** * Styles a string using a locale entry + * * @param author message author * @param message message contents * @param canColor whether to replace colors codes with colors in the raw message @@ -54,7 +57,7 @@ public class AdminChatMailer extends AbstractChatMailer { */ public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, boolean canColor) { if(canColor) { - return LocaleLoader.getTextComponent("Chat.Style.Admin", TextUtils.sanitizeAuthorName(author, ChatChannel.ADMIN), message); + return LocaleLoader.getTextComponent("Chat.Style.Admin", author.getAuthoredName(ChatChannel.ADMIN), message); } else { return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Admin", author.getAuthoredName(ChatChannel.ADMIN), message)); } @@ -65,6 +68,14 @@ public class AdminChatMailer extends AbstractChatMailer { chatMessage.sendMessage(); } + /** + * Processes a chat message from an author to an audience of admins + * + * @param author the author + * @param rawString the raw message as the author typed it before any styling + * @param isAsync whether or not this is being processed asynchronously + * @param canColor whether or not the author can use colors in chat + */ public void processChatMessage(@NotNull Author author, @NotNull String rawString, boolean isAsync, boolean canColor) { AdminChatMessage chatMessage = new AdminChatMessage(pluginRef, author, constructAudience(), rawString, addStyle(author, rawString, canColor)); @@ -77,4 +88,4 @@ public class AdminChatMailer extends AbstractChatMailer { } -} +} \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java b/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java index 37c02f144..6158ad826 100644 --- a/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java +++ b/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java @@ -22,6 +22,14 @@ public class PartyChatMailer extends AbstractChatMailer { super(pluginRef); } + /** + * Processes a chat message from an author to an audience of party members + * + * @param author the author + * @param rawString the raw message as the author typed it before any styling + * @param isAsync whether or not this is being processed asynchronously + * @param canColor whether or not the author can use colors in chat + */ public void processChatMessage(@NotNull Author author, @NotNull String rawString, @NotNull Party party, boolean isAsync, boolean canColor, boolean isLeader) { PartyChatMessage chatMessage = new PartyChatMessage(pluginRef, author, constructPartyAudience(party), rawString, addStyle(author, rawString, canColor, isLeader), party); @@ -33,12 +41,19 @@ public class PartyChatMailer extends AbstractChatMailer { } } + /** + * Constructs an {@link Audience} of party members + * + * @param party target party + * @return an {@link Audience} of party members + */ public @NotNull Audience constructPartyAudience(@NotNull Party party) { return mcMMO.getAudiences().filter(party.getSamePartyPredicate()); } /** * Styles a string using a locale entry + * * @param author message author * @param message message contents * @param canColor whether to replace colors codes with colors in the raw message @@ -47,7 +62,7 @@ public class PartyChatMailer extends AbstractChatMailer { public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, boolean canColor, boolean isLeader) { if(canColor) { if(isLeader) { - return LocaleLoader.getTextComponent("Chat.Style.Party.Leader", TextUtils.sanitizeAuthorName(author, ChatChannel.PARTY), message); + return LocaleLoader.getTextComponent("Chat.Style.Party.Leader", author.getAuthoredName(ChatChannel.PARTY), message); } else { return LocaleLoader.getTextComponent("Chat.Style.Party", author.getAuthoredName(ChatChannel.PARTY), message); } diff --git a/src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java b/src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java index c66644d6e..4c143ec69 100644 --- a/src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java +++ b/src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java @@ -7,7 +7,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.text.TextUtils; import com.google.common.base.Objects; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.TextComponent; @@ -46,7 +45,7 @@ public class PartyChatMessage extends AbstractChatMessage { //Sends to everyone but console audience.sendMessage(author, componentMessage); - TextComponent spyMessage = LocaleLoader.getTextComponent("Chat.Spy.Party", TextUtils.sanitizeAuthorName(author, ChatChannel.PARTY), rawMessage, party.getName()); + TextComponent spyMessage = LocaleLoader.getTextComponent("Chat.Spy.Party", author.getAuthoredName(ChatChannel.PARTY), rawMessage, party.getName()); //Relay to spies messagePartyChatSpies(spyMessage); diff --git a/src/main/java/com/gmail/nossr50/util/Misc.java b/src/main/java/com/gmail/nossr50/util/Misc.java index 92316d732..41195c08d 100644 --- a/src/main/java/com/gmail/nossr50/util/Misc.java +++ b/src/main/java/com/gmail/nossr50/util/Misc.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.util; import com.gmail.nossr50.api.ItemSpawnReason; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.events.items.McMMOItemSpawnEvent; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; @@ -299,4 +300,14 @@ public final class Misc { public static @NotNull Random getRandom() { return random; } + + /** + * Whether or not a player is the party leader of a party + * + * @param mmoPlayer target player + * @return true if the player is the party leader + */ + public static boolean isPartyLeader(@NotNull McMMOPlayer mmoPlayer) { + return mmoPlayer.getParty().getLeader().getUniqueId().equals(mmoPlayer.getPlayer().getUniqueId()); + } } diff --git a/src/main/java/com/gmail/nossr50/util/text/TextUtils.java b/src/main/java/com/gmail/nossr50/util/text/TextUtils.java index 231b7be69..1f1b24c2c 100644 --- a/src/main/java/com/gmail/nossr50/util/text/TextUtils.java +++ b/src/main/java/com/gmail/nossr50/util/text/TextUtils.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.util.text; -import com.gmail.nossr50.chat.author.Author; -import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.mcMMO; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.ComponentBuilder; @@ -130,8 +128,4 @@ public class TextUtils { TextComponent componentForm = ofLegacyTextRaw(string); return customLegacySerializer.serialize(componentForm); } - - public static @NotNull String sanitizeAuthorName(@NotNull Author author, @NotNull ChatChannel chatChannel) { - return sanitizeForSerializer(author.getAuthoredName(ChatChannel.ADMIN)); - } }