Browse Source

Full hex color support in admin/party chat

nossr50 4 years ago
parent
commit
4abf64f625

+ 10 - 2
Changelog.txt

@@ -1,6 +1,9 @@
 Version 2.1.154
 Version 2.1.154
-    Fixed a bug where Tree Feller was not dropping stuff like saplings
-    Fixed a bug where player names that used hex color codes weren't working in party or admin chat
+    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
+    Added hex colored nickname support to admin/party chat
+    Fixed a bug where Tree Feller was not dropping some items like saplings
+    Fixed a bug where using admin chat would in some circumstances throw a NPE
     (API) Author class has been reworked
     (API) Author class has been reworked
     (API) McMMOChatEvent::getSender removed (use getDisplayName() instead)
     (API) McMMOChatEvent::getSender removed (use getDisplayName() instead)
     (API) McMMMOChatEvent::setDisplayName() removed (you can set author names in Author)
     (API) McMMMOChatEvent::setDisplayName() removed (you can set author names in Author)
@@ -8,6 +11,11 @@ Version 2.1.154
     (API) Modified Author::getAuthoredName signature to -> Author::getAuthoredName(ChatChannel)
     (API) Modified Author::getAuthoredName signature to -> Author::getAuthoredName(ChatChannel)
     (API) Added Author::getAuthoredComponentName(ChatChannel)
     (API) Added Author::getAuthoredComponentName(ChatChannel)
     (API) PartyAuthor and AdminAuthor removed, replaced by PlayerAuthor
     (API) PartyAuthor and AdminAuthor removed, replaced by PlayerAuthor
+    (API) Probably some more undocumented changes that I'm forgetting...
+
+Notes:
+    For example '/p &#ccFF33hi guys' will send a message colored in hex colors
+    You'll see ~§x in console when hex color codes are used, this is a quirk of how the 'adventure' library we are using is handling some bungee component related things, so it's outside of my hands for now
 
 
 Version 2.1.153
 Version 2.1.153
     Fixed a bug where most sub-skills were not being displayed when using a skills command (for example /taming)
     Fixed a bug where most sub-skills were not being displayed when using a skills command (for example /taming)

+ 3 - 1
src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java

@@ -54,7 +54,7 @@ public class AdminChatMailer extends AbstractChatMailer {
      */
      */
     public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, boolean canColor) {
     public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, boolean canColor) {
         if(canColor) {
         if(canColor) {
-            return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Admin", author.getAuthoredName(ChatChannel.ADMIN), LocaleLoader.addColors(message)));
+            return LocaleLoader.getTextComponent("Chat.Style.Admin", TextUtils.sanitizeAuthorName(author, ChatChannel.ADMIN), message);
         } else {
         } else {
             return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Admin", author.getAuthoredName(ChatChannel.ADMIN), message));
             return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Admin", author.getAuthoredName(ChatChannel.ADMIN), message));
         }
         }
@@ -75,4 +75,6 @@ public class AdminChatMailer extends AbstractChatMailer {
             sendMail(chatMessage);
             sendMail(chatMessage);
         }
         }
     }
     }
+
+
 }
 }

+ 10 - 6
src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java

@@ -46,13 +46,17 @@ public class PartyChatMailer extends AbstractChatMailer {
      */
      */
     public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, boolean canColor, boolean isLeader) {
     public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, boolean canColor, boolean isLeader) {
         if(canColor) {
         if(canColor) {
-            message = LocaleLoader.addColors(message);
-        }
-
-        if(isLeader) {
-            return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Party.Leader", author.getAuthoredName(ChatChannel.PARTY), message));
+            if(isLeader) {
+                return LocaleLoader.getTextComponent("Chat.Style.Party.Leader", TextUtils.sanitizeAuthorName(author, ChatChannel.PARTY), message);
+            } else {
+                return LocaleLoader.getTextComponent("Chat.Style.Party", author.getAuthoredName(ChatChannel.PARTY), message);
+            }
         } else {
         } else {
-            return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Party", author.getAuthoredName(ChatChannel.PARTY), message));
+            if(isLeader) {
+                return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Party.Leader", author.getAuthoredName(ChatChannel.PARTY), message));
+            } else {
+                return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Party", author.getAuthoredName(ChatChannel.PARTY), message));
+            }
         }
         }
     }
     }
 
 

+ 1 - 1
src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java

@@ -46,7 +46,7 @@ public class PartyChatMessage extends AbstractChatMessage {
 
 
         //Sends to everyone but console
         //Sends to everyone but console
         audience.sendMessage(author, componentMessage);
         audience.sendMessage(author, componentMessage);
-        TextComponent spyMessage = TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Spy.Party", author.getAuthoredName(ChatChannel.PARTY), rawMessage, party.getName()));
+        TextComponent spyMessage = LocaleLoader.getTextComponent("Chat.Spy.Party", TextUtils.sanitizeAuthorName(author, ChatChannel.PARTY), rawMessage, party.getName());
 
 
         //Relay to spies
         //Relay to spies
         messagePartyChatSpies(spyMessage);
         messagePartyChatSpies(spyMessage);

+ 1 - 0
src/main/java/com/gmail/nossr50/commands/CommandManager.java

@@ -59,6 +59,7 @@ public class CommandManager {
             BukkitCommandIssuer issuer = context.getIssuer();
             BukkitCommandIssuer issuer = context.getIssuer();
 
 
             if(issuer.getIssuer() instanceof Player) {
             if(issuer.getIssuer() instanceof Player) {
+                validateLoadedData(issuer.getPlayer());
                 validateAdmin(issuer.getPlayer());
                 validateAdmin(issuer.getPlayer());
             }
             }
         });
         });

+ 3 - 0
src/main/java/com/gmail/nossr50/commands/chat/AdminChatCommand.java

@@ -36,6 +36,9 @@ public class AdminChatCommand extends BaseCommand {
             if(bukkitCommandIssuer.isPlayer()) {
             if(bukkitCommandIssuer.isPlayer()) {
                 McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer());
                 McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer());
 
 
+                if(mmoPlayer == null)
+                    return;
+
                 //Message contains the original command so it needs to be passed to this method to trim it
                 //Message contains the original command so it needs to be passed to this method to trim it
                 pluginRef.getChatManager().processPlayerMessage(mmoPlayer, args, ChatChannel.ADMIN);
                 pluginRef.getChatManager().processPlayerMessage(mmoPlayer, args, ChatChannel.ADMIN);
             } else {
             } else {

+ 29 - 0
src/main/java/com/gmail/nossr50/locale/LocaleLoader.java

@@ -2,6 +2,8 @@ package com.gmail.nossr50.locale;
 
 
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.text.TextUtils;
+import net.kyori.adventure.text.TextComponent;
 import org.bukkit.ChatColor;
 import org.bukkit.ChatColor;
 
 
 import java.io.IOException;
 import java.io.IOException;
@@ -42,6 +44,23 @@ public final class LocaleLoader {
         return formatString(rawMessage, messageArguments);
         return formatString(rawMessage, messageArguments);
     }
     }
 
 
+    //TODO: Remove this hacky crap with something better later
+    /**
+     * Gets the appropriate TextComponent representation of a formatted string from the Locale files.
+     *
+     * @param key The key to look up the string with
+     * @param messageArguments Any arguments to be added to the text component
+     * @return The properly formatted text component
+     */
+    public static TextComponent getTextComponent(String key, Object... messageArguments) {
+        if (bundle == null) {
+            initialize();
+        }
+
+        String rawMessage = bundleCache.computeIfAbsent(key, LocaleLoader::getRawString);
+        return formatComponent(rawMessage, messageArguments);
+    }
+
     /**
     /**
      * Reloads locale
      * Reloads locale
      */
      */
@@ -90,6 +109,16 @@ public final class LocaleLoader {
         return string;
         return string;
     }
     }
 
 
+    public static TextComponent formatComponent(String string, Object... messageArguments) {
+        if (messageArguments != null) {
+            MessageFormat formatter = new MessageFormat("");
+            formatter.applyPattern(string.replace("'", "''"));
+            string = formatter.format(messageArguments);
+        }
+
+        return TextUtils.colorizeText(string);
+    }
+
     public static Locale getCurrentLocale() {
     public static Locale getCurrentLocale() {
         if (bundle == null) {
         if (bundle == null) {
             initialize();
             initialize();

+ 31 - 0
src/main/java/com/gmail/nossr50/util/text/TextUtils.java

@@ -1,5 +1,7 @@
 package com.gmail.nossr50.util.text;
 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 com.gmail.nossr50.mcMMO;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.ComponentBuilder;
 import net.kyori.adventure.text.ComponentBuilder;
@@ -14,6 +16,9 @@ import org.jetbrains.annotations.Nullable;
 import java.util.List;
 import java.util.List;
 
 
 public class TextUtils {
 public class TextUtils {
+
+    private static @Nullable LegacyComponentSerializer customLegacySerializer;
+
     /**
     /**
      * Makes a single component from an array of components, can optionally add prefixes and suffixes to come before and after each component
      * Makes a single component from an array of components, can optionally add prefixes and suffixes to come before and after each component
      * @param componentsArray target array
      * @param componentsArray target array
@@ -103,4 +108,30 @@ public class TextUtils {
     public static @NotNull TextComponent ofLegacyTextRaw(@NotNull String rawString) {
     public static @NotNull TextComponent ofLegacyTextRaw(@NotNull String rawString) {
         return LegacyComponentSerializer.legacySection().deserialize(rawString);
         return LegacyComponentSerializer.legacySection().deserialize(rawString);
     }
     }
+
+    public static @NotNull TextComponent colorizeText(String rawtext) {
+        if(customLegacySerializer == null) {
+            customLegacySerializer = getSerializer();
+        }
+
+        return customLegacySerializer.deserialize(rawtext);
+    }
+
+    @NotNull
+    private static LegacyComponentSerializer getSerializer() {
+        return LegacyComponentSerializer.builder().hexColors().useUnusualXRepeatedCharacterHexFormat().character('&').hexCharacter('#').build();
+    }
+
+    public static @NotNull String sanitizeForSerializer(@NotNull String string) {
+        if(customLegacySerializer == null) {
+            customLegacySerializer = getSerializer();
+        }
+
+        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));
+    }
 }
 }