Browse Source

Complete rewrite of Admin & Party chat code
There are some API breaks as a result of these rewrites, I tried to keep it minimal, but I'm sure some plugins will need to update.

nossr50 4 years ago
parent
commit
749c83ac59
44 changed files with 1419 additions and 713 deletions
  1. 19 0
      Changelog.txt
  2. 38 16
      pom.xml
  3. 65 76
      src/main/java/com/gmail/nossr50/api/ChatAPI.java
  4. 0 21
      src/main/java/com/gmail/nossr50/chat/AdminChatManager.java
  5. 164 68
      src/main/java/com/gmail/nossr50/chat/ChatManager.java
  6. 0 30
      src/main/java/com/gmail/nossr50/chat/ChatManagerFactory.java
  7. 0 29
      src/main/java/com/gmail/nossr50/chat/PartyChatManager.java
  8. 36 0
      src/main/java/com/gmail/nossr50/chat/SamePartyPredicate.java
  9. 52 0
      src/main/java/com/gmail/nossr50/chat/author/AdminAuthor.java
  10. 32 0
      src/main/java/com/gmail/nossr50/chat/author/Author.java
  11. 41 0
      src/main/java/com/gmail/nossr50/chat/author/ConsoleAuthor.java
  12. 52 0
      src/main/java/com/gmail/nossr50/chat/author/PartyAuthor.java
  13. 13 0
      src/main/java/com/gmail/nossr50/chat/mailer/AbstractChatMailer.java
  14. 72 0
      src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java
  15. 12 0
      src/main/java/com/gmail/nossr50/chat/mailer/ChatMailer.java
  16. 47 0
      src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java
  17. 59 0
      src/main/java/com/gmail/nossr50/chat/message/AbstractChatMessage.java
  18. 18 0
      src/main/java/com/gmail/nossr50/chat/message/AdminChatMessage.java
  19. 73 0
      src/main/java/com/gmail/nossr50/chat/message/ChatMessage.java
  20. 63 0
      src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java
  21. 103 0
      src/main/java/com/gmail/nossr50/commands/CommandManager.java
  22. 40 8
      src/main/java/com/gmail/nossr50/commands/chat/AdminChatCommand.java
  23. 0 141
      src/main/java/com/gmail/nossr50/commands/chat/ChatCommand.java
  24. 67 42
      src/main/java/com/gmail/nossr50/commands/chat/PartyChatCommand.java
  25. 0 4
      src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java
  26. 12 12
      src/main/java/com/gmail/nossr50/commands/skills/AprilCommand.java
  27. 6 3
      src/main/java/com/gmail/nossr50/datatypes/chat/ChatChannel.java
  28. 12 0
      src/main/java/com/gmail/nossr50/datatypes/party/Party.java
  29. 50 68
      src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java
  30. 10 9
      src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java
  31. 4 6
      src/main/java/com/gmail/nossr50/events/chat/McMMOAdminChatEvent.java
  32. 104 33
      src/main/java/com/gmail/nossr50/events/chat/McMMOChatEvent.java
  33. 26 10
      src/main/java/com/gmail/nossr50/events/chat/McMMOPartyChatEvent.java
  34. 6 25
      src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
  35. 16 0
      src/main/java/com/gmail/nossr50/mcMMO.java
  36. 2 2
      src/main/java/com/gmail/nossr50/party/PartyManager.java
  37. 2 1
      src/main/java/com/gmail/nossr50/util/McMMOMessageType.java
  38. 74 73
      src/main/java/com/gmail/nossr50/util/TextComponentFactory.java
  39. 0 1
      src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java
  40. 21 27
      src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java
  41. 2 2
      src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/AbstractPersistentDataLayer.java
  42. 0 1
      src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/SpigotPersistentDataLayer_1_14.java
  43. 4 3
      src/main/java/com/gmail/nossr50/util/player/NotificationManager.java
  44. 2 2
      src/main/resources/locale/locale_en_US.properties

+ 19 - 0
Changelog.txt

@@ -1,5 +1,24 @@
 Version 2.1.150
 Version 2.1.150
+    mcMMO Party & Admin Chat have had a rewrite, work was put in to make sure their API would be mostly compatible with the old one
+    mcMMO should now be compatible with 1.16.4's new social features
+    The style and look of admin/party chat is now determined by locale file instead of options in config.yml
+    Improved messages players recieve when they toggle on or off admin or party chat
+    All locale files have had [[]] color codes replaced by & color codes, you can still use [[GOLD]] and stuff if you want
+    Added new locale string 'Chat.Identity.Console'
+    Added new locale string 'Chat.Style.Admin'
+    Added new locale string 'Chat.Style.Party'
+    Added new locale string 'Chat.Channel.On'
+    Added new locale string 'Chat.Channel.Off'
+    (API) ChatAPI::getPartyChatManager() has been removed
+    (API) ChatAPI::sendPartyChat has been removed (similar functionality can be found in the new ChatManager class)
+    (API) ChatAPI::sendAdminChat has been removed (similar functionality can be found in the new ChatManager class)
     (API) Fake events in mcMMO now implement 'FakeEvent' (thanks TheBusyBiscuit)
     (API) Fake events in mcMMO now implement 'FakeEvent' (thanks TheBusyBiscuit)
+    (API) Updated Adventure Library to 4.1.1
+    (API) McMMOChatEvent has been reworked, plugins dependent on this event should review this class and make appropriate changes
+
+    NOTES:
+    The mcMMO chat events now make use of adventure library by Kyori, you can override the message payload with a TextComponent, which allows for some fancy stuff potentially.
+    I'll put in some of my own fancy stuff for party and admin chat in a future update.
 
 
 Version 2.1.149
 Version 2.1.149
     Added a new config file 'persistent_data.yml'
     Added a new config file 'persistent_data.yml'

+ 38 - 16
pom.xml

@@ -63,8 +63,11 @@
             <plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>2.3.2</version>
+                <version>3.8.1</version>
                 <configuration>
                 <configuration>
+                    <compilerArgs>
+                        <arg>-parameters</arg> <!-- used for ACF syntax stuff -->
+                    </compilerArgs>
                     <source>1.8</source>
                     <source>1.8</source>
                     <target>1.8</target>
                     <target>1.8</target>
                     <excludes>
                     <excludes>
@@ -91,7 +94,7 @@
             <plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-shade-plugin</artifactId>
                 <artifactId>maven-shade-plugin</artifactId>
-                <version>3.1.1</version>
+                <version>3.2.3</version>
                 <configuration>
                 <configuration>
                     <artifactSet>
                     <artifactSet>
                         <includes>
                         <includes>
@@ -112,28 +115,38 @@
                             <include>net.kyori:adventure-text-serializer-legacy</include>
                             <include>net.kyori:adventure-text-serializer-legacy</include>
                             <include>net.kyori:adventure-text-serializer-bungeecord</include>
                             <include>net.kyori:adventure-text-serializer-bungeecord</include>
                             <include>net.kyori:adventure-text-serializer-craftbukkit</include>
                             <include>net.kyori:adventure-text-serializer-craftbukkit</include>
+                            <include>co.aikar:acf-bukkit</include>
                         </includes>
                         </includes>
                     </artifactSet>
                     </artifactSet>
+<!--                    <dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>-->
                     <relocations>
                     <relocations>
+                        <relocation>
+                            <pattern>co.aikar.commands</pattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.acf</shadedPattern> <!-- Replace this -->
+                        </relocation>
+                        <relocation>
+                            <pattern>co.aikar.locales</pattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.locales</shadedPattern> <!-- Replace this -->
+                        </relocation>
                         <relocation>
                         <relocation>
                             <pattern>org.apache.commons.logging</pattern>
                             <pattern>org.apache.commons.logging</pattern>
-                            <shadedPattern>com.gmail.nossr50.commons.logging</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.commons.logging</shadedPattern>
                         </relocation>
                         </relocation>
                         <relocation>
                         <relocation>
                             <pattern>org.apache.juli</pattern>
                             <pattern>org.apache.juli</pattern>
-                            <shadedPattern>com.gmail.nossr50.database.tomcat.juli</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.database.tomcat.juli</shadedPattern>
                         </relocation>
                         </relocation>
                         <relocation>
                         <relocation>
                             <pattern>org.apache.tomcat</pattern>
                             <pattern>org.apache.tomcat</pattern>
-                            <shadedPattern>com.gmail.nossr50.database.tomcat</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.database.tomcat</shadedPattern>
                         </relocation>
                         </relocation>
                         <relocation>
                         <relocation>
                             <pattern>net.kyori.adventure</pattern>
                             <pattern>net.kyori.adventure</pattern>
-                            <shadedPattern>com.gmail.nossr50.kyori.adventure</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.kyori.adventure</shadedPattern>
                         </relocation>
                         </relocation>
                         <relocation>
                         <relocation>
                             <pattern>org.bstats</pattern>
                             <pattern>org.bstats</pattern>
-                            <shadedPattern>com.gmail.nossr50.metrics.bstat</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.metrics.bstat</shadedPattern>
                         </relocation>
                         </relocation>
                     </relocations>
                     </relocations>
                 </configuration>
                 </configuration>
@@ -168,29 +181,38 @@
             <id>sk89q-repo</id>
             <id>sk89q-repo</id>
             <url>https://maven.sk89q.com/repo/</url>
             <url>https://maven.sk89q.com/repo/</url>
         </repository>
         </repository>
-            <!-- ... -->
-            <repository> <!-- for development builds -->
-                <id>sonatype-oss</id>
-                <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
-            </repository>
-            <!-- ... -->
+        <repository>
+            <id>aikar</id>
+            <url>https://repo.aikar.co/content/groups/aikar/</url>
+        </repository>
+        <!-- ... -->
+        <repository> <!-- for development builds -->
+            <id>sonatype-oss</id>
+            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+        </repository>
+        <!-- ... -->
     </repositories>
     </repositories>
     <dependencies>
     <dependencies>
+        <dependency>
+            <groupId>co.aikar</groupId>
+            <artifactId>acf-bukkit</artifactId> <!-- Don't forget to replace this -->
+            <version>0.5.0-SNAPSHOT</version> <!-- Replace this as well -->
+        </dependency>
 <!--        adventure-api, adventure-text-serializer-gson, adventure-platform-bukkit-->
 <!--        adventure-api, adventure-text-serializer-gson, adventure-platform-bukkit-->
         <dependency>
         <dependency>
             <groupId>net.kyori</groupId>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-text-serializer-gson</artifactId>
             <artifactId>adventure-text-serializer-gson</artifactId>
-            <version>4.0.0-SNAPSHOT</version>
+            <version>4.1.1</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>net.kyori</groupId>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-api</artifactId>
             <artifactId>adventure-api</artifactId>
-            <version>4.0.0-SNAPSHOT</version>
+            <version>4.1.1</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>net.kyori</groupId>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-nbt</artifactId>
             <artifactId>adventure-nbt</artifactId>
-            <version>4.0.0-SNAPSHOT</version>
+            <version>4.1.1</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>net.kyori</groupId>
             <groupId>net.kyori</groupId>

+ 65 - 76
src/main/java/com/gmail/nossr50/api/ChatAPI.java

@@ -1,72 +1,68 @@
 package com.gmail.nossr50.api;
 package com.gmail.nossr50.api;
 
 
-import com.gmail.nossr50.chat.ChatManager;
-import com.gmail.nossr50.chat.ChatManagerFactory;
-import com.gmail.nossr50.chat.PartyChatManager;
-import com.gmail.nossr50.datatypes.chat.ChatMode;
-import com.gmail.nossr50.party.PartyManager;
+import com.gmail.nossr50.datatypes.chat.ChatChannel;
+import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
-import org.bukkit.plugin.Plugin;
 
 
 public final class ChatAPI {
 public final class ChatAPI {
     private ChatAPI() {}
     private ChatAPI() {}
 
 
-    /**
-     * Send a message to all members of a party
-     * </br>
-     * This function is designed for API usage.
-     *
-     * @param plugin The plugin sending the message
-     * @param sender The name of the sender
-     * @param displayName The display name of the sender
-     * @param party The name of the party to send to
-     * @param message The message to send
-     */
-    public static void sendPartyChat(Plugin plugin, String sender, String displayName, String party, String message) {
-        getPartyChatManager(plugin, party).handleChat(sender, displayName, message);
-    }
-
-    /**
-     * Send a message to all members of a party
-     * </br>
-     * This function is designed for API usage.
-     *
-     * @param plugin The plugin sending the message
-     * @param sender The name of the sender to display in the chat
-     * @param party The name of the party to send to
-     * @param message The message to send
-     */
-    public static void sendPartyChat(Plugin plugin, String sender, String party, String message) {
-        getPartyChatManager(plugin, party).handleChat(sender, message);
-    }
-
-    /**
-     * Send a message to administrators
-     * </br>
-     * This function is designed for API usage.
-     *
-     * @param plugin The plugin sending the message
-     * @param sender The name of the sender
-     * @param displayName The display name of the sender
-     * @param message The message to send
-     */
-    public static void sendAdminChat(Plugin plugin, String sender, String displayName, String message) {
-        ChatManagerFactory.getChatManager(plugin, ChatMode.ADMIN).handleChat(sender, displayName, message);
-    }
-
-    /**
-     * Send a message to administrators
-     * </br>
-     * This function is designed for API usage.
-     *
-     * @param plugin The plugin sending the message
-     * @param sender The name of the sender to display in the chat
-     * @param message The message to send
-     */
-    public static void sendAdminChat(Plugin plugin, String sender, String message) {
-        ChatManagerFactory.getChatManager(plugin, ChatMode.ADMIN).handleChat(sender, message);
-    }
+//    /**
+//     * Send a message to all members of a party
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param plugin The plugin sending the message
+//     * @param sender The name of the sender
+//     * @param displayName The display name of the sender
+//     * @param party The name of the party to send to
+//     * @param message The message to send
+//     */
+//    public static void sendPartyChat(Plugin plugin, String sender, String displayName, String party, String message) {
+//        getPartyChatManager(plugin, party).handleChat(sender, displayName, message);
+//    }
+//
+//    /**
+//     * Send a message to all members of a party
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param plugin The plugin sending the message
+//     * @param sender The name of the sender to display in the chat
+//     * @param party The name of the party to send to
+//     * @param message The message to send
+//     */
+//    public static void sendPartyChat(Plugin plugin, String sender, String party, String message) {
+//        getPartyChatManager(plugin, party).handleChat(sender, message);
+//    }
+//
+//    /**
+//     * Send a message to administrators
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param plugin The plugin sending the message
+//     * @param sender The name of the sender
+//     * @param displayName The display name of the sender
+//     * @param message The message to send
+//     */
+//    public static void sendAdminChat(Plugin plugin, String sender, String displayName, String message) {
+//        ChatManagerFactory.getChatManager(plugin, ChatChannel.ADMIN).handleChat(sender, displayName, message);
+//    }
+//
+//    /**
+//     * Send a message to administrators
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param plugin The plugin sending the message
+//     * @param sender The name of the sender to display in the chat
+//     * @param message The message to send
+//     */
+//    public static void sendAdminChat(Plugin plugin, String sender, String message) {
+//        ChatManagerFactory.getChatManager(plugin, ChatChannel.ADMIN).handleChat(sender, message);
+//    }
 
 
     /**
     /**
      * Check if a player is currently talking in party chat.
      * Check if a player is currently talking in party chat.
@@ -75,7 +71,7 @@ public final class ChatAPI {
      * @return true if the player is using party chat, false otherwise
      * @return true if the player is using party chat, false otherwise
      */
      */
     public static boolean isUsingPartyChat(Player player) {
     public static boolean isUsingPartyChat(Player player) {
-        return UserManager.getPlayer(player).isChatEnabled(ChatMode.PARTY);
+        return UserManager.getPlayer(player).getChatChannel() == ChatChannel.PARTY;
     }
     }
 
 
     /**
     /**
@@ -85,7 +81,7 @@ public final class ChatAPI {
      * @return true if the player is using party chat, false otherwise
      * @return true if the player is using party chat, false otherwise
      */
      */
     public static boolean isUsingPartyChat(String playerName) {
     public static boolean isUsingPartyChat(String playerName) {
-        return UserManager.getPlayer(playerName).isChatEnabled(ChatMode.PARTY);
+        return UserManager.getPlayer(playerName).getChatChannel() == ChatChannel.PARTY;
     }
     }
 
 
     /**
     /**
@@ -95,7 +91,7 @@ public final class ChatAPI {
      * @return true if the player is using admin chat, false otherwise
      * @return true if the player is using admin chat, false otherwise
      */
      */
     public static boolean isUsingAdminChat(Player player) {
     public static boolean isUsingAdminChat(Player player) {
-        return UserManager.getPlayer(player).isChatEnabled(ChatMode.ADMIN);
+        return UserManager.getPlayer(player).getChatChannel() == ChatChannel.ADMIN;
     }
     }
 
 
     /**
     /**
@@ -105,7 +101,7 @@ public final class ChatAPI {
      * @return true if the player is using admin chat, false otherwise
      * @return true if the player is using admin chat, false otherwise
      */
      */
     public static boolean isUsingAdminChat(String playerName) {
     public static boolean isUsingAdminChat(String playerName) {
-        return UserManager.getPlayer(playerName).isChatEnabled(ChatMode.ADMIN);
+        return UserManager.getPlayer(playerName).getChatChannel() == ChatChannel.ADMIN;
     }
     }
 
 
     /**
     /**
@@ -114,7 +110,7 @@ public final class ChatAPI {
      * @param player The player to toggle party chat on.
      * @param player The player to toggle party chat on.
      */
      */
     public static void togglePartyChat(Player player) {
     public static void togglePartyChat(Player player) {
-        UserManager.getPlayer(player).toggleChat(ChatMode.PARTY);
+        mcMMO.p.getChatManager().setOrToggleChatChannel(UserManager.getPlayer(player), ChatChannel.PARTY);
     }
     }
 
 
     /**
     /**
@@ -123,7 +119,7 @@ public final class ChatAPI {
      * @param playerName The name of the player to toggle party chat on.
      * @param playerName The name of the player to toggle party chat on.
      */
      */
     public static void togglePartyChat(String playerName) {
     public static void togglePartyChat(String playerName) {
-        UserManager.getPlayer(playerName).toggleChat(ChatMode.PARTY);
+        mcMMO.p.getChatManager().setOrToggleChatChannel(UserManager.getPlayer(playerName), ChatChannel.PARTY);
     }
     }
 
 
     /**
     /**
@@ -132,7 +128,7 @@ public final class ChatAPI {
      * @param player The player to toggle admin chat on.
      * @param player The player to toggle admin chat on.
      */
      */
     public static void toggleAdminChat(Player player) {
     public static void toggleAdminChat(Player player) {
-        UserManager.getPlayer(player).toggleChat(ChatMode.ADMIN);
+        mcMMO.p.getChatManager().setOrToggleChatChannel(UserManager.getPlayer(player), ChatChannel.ADMIN);
     }
     }
 
 
     /**
     /**
@@ -141,13 +137,6 @@ public final class ChatAPI {
      * @param playerName The name of the player to toggle party chat on.
      * @param playerName The name of the player to toggle party chat on.
      */
      */
     public static void toggleAdminChat(String playerName) {
     public static void toggleAdminChat(String playerName) {
-        UserManager.getPlayer(playerName).toggleChat(ChatMode.ADMIN);
-    }
-
-    private static ChatManager getPartyChatManager(Plugin plugin, String party) {
-        ChatManager chatManager = ChatManagerFactory.getChatManager(plugin, ChatMode.PARTY);
-        ((PartyChatManager) chatManager).setParty(PartyManager.getParty(party));
-
-        return chatManager;
+        mcMMO.p.getChatManager().setOrToggleChatChannel(UserManager.getPlayer(playerName), ChatChannel.ADMIN);
     }
     }
 }
 }

+ 0 - 21
src/main/java/com/gmail/nossr50/chat/AdminChatManager.java

@@ -1,21 +0,0 @@
-package com.gmail.nossr50.chat;
-
-import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.events.chat.McMMOAdminChatEvent;
-import org.bukkit.plugin.Plugin;
-
-public class AdminChatManager extends ChatManager {
-    protected AdminChatManager(Plugin plugin) {
-        super(plugin, Config.getInstance().getAdminDisplayNames(), Config.getInstance().getAdminChatPrefix());
-    }
-
-    @Override
-    public void handleChat(String senderName, String displayName, String message, boolean isAsync) {
-        handleChat(new McMMOAdminChatEvent(plugin, senderName, displayName, message, isAsync));
-    }
-
-    @Override
-    protected void sendMessage() {
-        plugin.getServer().broadcast(message, "mcmmo.chat.adminchat");
-    }
-}

+ 164 - 68
src/main/java/com/gmail/nossr50/chat/ChatManager.java

@@ -1,88 +1,184 @@
 package com.gmail.nossr50.chat;
 package com.gmail.nossr50.chat;
 
 
+import com.gmail.nossr50.chat.author.Author;
+import com.gmail.nossr50.chat.author.ConsoleAuthor;
+import com.gmail.nossr50.chat.mailer.AdminChatMailer;
+import com.gmail.nossr50.chat.mailer.PartyChatMailer;
+import com.gmail.nossr50.datatypes.chat.ChatChannel;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
-import com.gmail.nossr50.events.chat.McMMOChatEvent;
-import com.gmail.nossr50.events.chat.McMMOPartyChatEvent;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
-import com.gmail.nossr50.util.player.UserManager;
-import org.bukkit.entity.Player;
-import org.bukkit.plugin.Plugin;
-
-public abstract class ChatManager {
-    protected Plugin plugin;
-    protected boolean useDisplayNames;
-    protected String chatPrefix;
-
-    protected String senderName;
-    protected String displayName;
-    protected String message;
-
-    protected ChatManager(Plugin plugin, boolean useDisplayNames, String chatPrefix) {
-        this.plugin = plugin;
-        this.useDisplayNames = useDisplayNames;
-        this.chatPrefix = chatPrefix;
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+//TODO: Micro optimization - Cache audiences and update cache when needed
+public class ChatManager {
+
+    private final @NotNull AdminChatMailer adminChatMailer;
+    private final @NotNull PartyChatMailer partyChatMailer;
+
+    private @Nullable ConsoleAuthor consoleAuthor;
+
+    public ChatManager(@NotNull mcMMO pluginRef) {
+        adminChatMailer = new AdminChatMailer(pluginRef);
+        partyChatMailer = new PartyChatMailer(pluginRef);
     }
     }
 
 
-    protected void handleChat(McMMOChatEvent event) {
-        plugin.getServer().getPluginManager().callEvent(event);
+    /**
+     * 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
+     */
+    public void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull String rawMessage, boolean isAsync) {
+        processPlayerMessage(mmoPlayer, mmoPlayer.getChatChannel(), rawMessage, isAsync);
+    }
 
 
-        if (event.isCancelled()) {
-            return;
-        }
+    /**
+     * 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
+     */
+    public void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull String[] args, @NotNull ChatChannel chatChannel) {
+        String chatMessageWithoutCommand = buildChatMessage(args);
+
+        //Commands are never async
+        processPlayerMessage(mmoPlayer, chatChannel, chatMessageWithoutCommand, false);
+    }
 
 
-        senderName = event.getSender();
-        displayName = useDisplayNames ? event.getDisplayName() : senderName;
-        message = LocaleLoader.formatString(chatPrefix, displayName) + " " + event.getMessage();
-
-        sendMessage();
-
-        /*
-         * Party Chat Spying
-         * Party messages will be copied to people with the mcmmo.admin.chatspy permission node
-         */
-        if(event instanceof McMMOPartyChatEvent)
-        {
-            //We need to grab the party chat name
-            McMMOPartyChatEvent partyChatEvent = (McMMOPartyChatEvent) event;
-
-            //Find the people with permissions
-            for(McMMOPlayer mcMMOPlayer : UserManager.getPlayers())
-            {
-                Player player = mcMMOPlayer.getPlayer();
-
-                //Check for toggled players
-                if(mcMMOPlayer.isPartyChatSpying())
-                {
-                    Party adminParty = mcMMOPlayer.getParty();
-
-                    //Only message admins not part of this party
-                    if(adminParty != null)
-                    {
-                        //TODO: Incorporate JSON
-                        if(!adminParty.getName().equalsIgnoreCase(partyChatEvent.getParty()))
-                            player.sendMessage(LocaleLoader.getString("Commands.AdminChatSpy.Chat", partyChatEvent.getParty(), message));
-                    } else {
-                        player.sendMessage(LocaleLoader.getString("Commands.AdminChatSpy.Chat", partyChatEvent.getParty(), message));
-                    }
-                }
-            }
+    /**
+     * 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
+     * @param isAsync whether or not this is getting processed via async
+     */
+    private void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull ChatChannel chatChannel, @NotNull String rawMessage, boolean isAsync) {
+        switch (chatChannel) {
+            case ADMIN:
+                adminChatMailer.processChatMessage(mmoPlayer.getAdminAuthor(), rawMessage, isAsync);
+                break;
+            case PARTY:
+                partyChatMailer.processChatMessage(mmoPlayer.getPartyAuthor(), rawMessage, mmoPlayer.getParty(), isAsync);
+                break;
+            case PARTY_OFFICER:
+            case NONE:
+                break;
         }
         }
     }
     }
 
 
-    public void handleChat(String senderName, String message) {
-        handleChat(senderName, senderName, message, false);
+    /**
+     * Handles console messaging to admins
+     * @param rawMessage raw message from the console
+     */
+    public void processConsoleMessage(@NotNull String rawMessage) {
+        adminChatMailer.processChatMessage(getConsoleAuthor(), rawMessage, false);
+    }
+
+    /**
+     * Handles console messaging to admins
+     * @param args raw command args from the console
+     */
+    public void processConsoleMessage(@NotNull String[] args) {
+        processConsoleMessage(buildChatMessage(args));
     }
     }
 
 
-    public void handleChat(Player player, String message, boolean isAsync) {
-        handleChat(player.getName(), player.getDisplayName(), message, isAsync);
+    /**
+     * Handles console messaging to a specific party
+     * @param rawMessage raw message from the console
+     * @param party target party
+     */
+    public void processConsoleMessage(@NotNull String rawMessage, @NotNull Party party) {
+        partyChatMailer.processChatMessage(getConsoleAuthor(), rawMessage, party, false);
     }
     }
 
 
-    public void handleChat(String senderName, String displayName, String message) {
-        handleChat(senderName, displayName, message, false);
+    /**
+     * Handles console messaging to a specific party
+     * @param args raw command args from the console
+     * @param party target party
+     */
+    public void processConsoleMessage(@NotNull String[] args, @NotNull Party party) {
+        String chatMessageWithoutCommand = buildChatMessage(args);
+
+        processConsoleMessage(chatMessageWithoutCommand, party);
     }
     }
 
 
-    public abstract void handleChat(String senderName, String displayName, String message, boolean isAsync);
+    /**
+     * Gets a console author
+     * Constructs one if it doesn't already exist
+     * @return a {@link ConsoleAuthor}
+     */
+    private @NotNull Author getConsoleAuthor() {
+        if (consoleAuthor == null) {
+            consoleAuthor = new ConsoleAuthor(LocaleLoader.getString("Chat.Identity.Console"));
+        }
+
+        return consoleAuthor;
+    }
 
 
-    protected abstract void sendMessage();
+    /**
+     * Change the chat channel of a {@link McMMOPlayer}
+     *  Targeting the channel a player is already in will remove that player from the chat channel
+     * @param mmoPlayer target player
+     * @param targetChatChannel target chat channel
+     */
+    public void setOrToggleChatChannel(@NotNull McMMOPlayer mmoPlayer, @NotNull ChatChannel targetChatChannel) {
+        if(targetChatChannel == mmoPlayer.getChatChannel()) {
+            //Disabled message
+            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Chat.Channel.Off", StringUtils.getCapitalized(targetChatChannel.toString())));
+            mmoPlayer.setChatMode(ChatChannel.NONE);
+        } else {
+            mmoPlayer.setChatMode(targetChatChannel);
+            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Chat.Channel.On", StringUtils.getCapitalized(targetChatChannel.toString())));
+        }
+    }
+
+    /**
+     * Create a chat message from an array of {@link String}
+     * @param args array of {@link String}
+     * @return a String built from the array
+     */
+    private @NotNull String buildChatMessage(@NotNull String[] args) {
+        StringBuilder stringBuilder = new StringBuilder();
+
+        for(int i = 0; i < args.length; i++) {
+            if(i + 1 >= args.length) {
+                stringBuilder.append(args[i]);
+            } else {
+                stringBuilder.append(args[i]).append(" ");
+            }
+        }
+
+        return stringBuilder.toString();
+    }
+
+    /**
+     * Whether or not the player is allowed to send a message to the chat channel they are targeting
+     * @param mmoPlayer target player
+     * @return true if the player can send messages to that chat channel
+     */
+    public boolean isMessageAllowed(@NotNull McMMOPlayer mmoPlayer) {
+        switch (mmoPlayer.getChatChannel()) {
+            case ADMIN:
+                if(mmoPlayer.getPlayer().isOp() || Permissions.adminChat(mmoPlayer.getPlayer())) {
+                    return true;
+                }
+                break;
+            case PARTY:
+                if(mmoPlayer.getParty() != null) {
+                    return true;
+                }
+                break;
+            case PARTY_OFFICER:
+            case NONE:
+                return false;
+        }
+
+        return false;
+    }
 }
 }
+

+ 0 - 30
src/main/java/com/gmail/nossr50/chat/ChatManagerFactory.java

@@ -1,30 +0,0 @@
-package com.gmail.nossr50.chat;
-
-import com.gmail.nossr50.datatypes.chat.ChatMode;
-import org.bukkit.plugin.Plugin;
-
-import java.util.HashMap;
-
-public class ChatManagerFactory {
-    private static final HashMap<Plugin, AdminChatManager> adminChatManagers = new HashMap<>();
-    private static final HashMap<Plugin, PartyChatManager> partyChatManagers = new HashMap<>();
-
-    public static ChatManager getChatManager(Plugin plugin, ChatMode mode) {
-        switch (mode) {
-            case ADMIN:
-                if (!adminChatManagers.containsKey(plugin)) {
-                    adminChatManagers.put(plugin, new AdminChatManager(plugin));
-                }
-
-                return adminChatManagers.get(plugin);
-            case PARTY:
-                if (!partyChatManagers.containsKey(plugin)) {
-                    partyChatManagers.put(plugin, new PartyChatManager(plugin));
-                }
-
-                return partyChatManagers.get(plugin);
-            default:
-                return null;
-        }
-    }
-}

+ 0 - 29
src/main/java/com/gmail/nossr50/chat/PartyChatManager.java

@@ -1,29 +0,0 @@
-package com.gmail.nossr50.chat;
-
-import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.datatypes.party.Party;
-import com.gmail.nossr50.events.chat.McMMOPartyChatEvent;
-import com.gmail.nossr50.runnables.party.PartyChatTask;
-import org.bukkit.plugin.Plugin;
-
-public class PartyChatManager extends ChatManager {
-    private Party party;
-
-    protected PartyChatManager(Plugin plugin) {
-        super(plugin, Config.getInstance().getPartyDisplayNames(), Config.getInstance().getPartyChatPrefix());
-    }
-
-    public void setParty(Party party) {
-        this.party = party;
-    }
-
-    @Override
-    public void handleChat(String senderName, String displayName, String message, boolean isAsync) {
-        handleChat(new McMMOPartyChatEvent(plugin, senderName, displayName, party.getName(), message, isAsync));
-    }
-
-    @Override
-    protected void sendMessage() {
-        new PartyChatTask(plugin, party, senderName, displayName, message).runTask(plugin);
-    }
-}

+ 36 - 0
src/main/java/com/gmail/nossr50/chat/SamePartyPredicate.java

@@ -0,0 +1,36 @@
+package com.gmail.nossr50.chat;
+
+import com.gmail.nossr50.datatypes.party.Party;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.util.player.UserManager;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.function.Predicate;
+
+public class SamePartyPredicate<T extends CommandSender> implements Predicate<T> {
+
+    final Party party;
+
+    public SamePartyPredicate(Party party) {
+        this.party = party;
+    }
+
+    @Override
+    public boolean test(T t) {
+        //Include the console in the audience
+        if(t instanceof ConsoleCommandSender) {
+            return true;
+        } else {
+            if(t instanceof Player) {
+                Player player = (Player) t;
+                McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
+                if(mcMMOPlayer != null) {
+                    return mcMMOPlayer.getParty() == party;
+                }
+            }
+        }
+        return false;
+    }
+}

+ 52 - 0
src/main/java/com/gmail/nossr50/chat/author/AdminAuthor.java

@@ -0,0 +1,52 @@
+package com.gmail.nossr50.chat.author;
+
+import com.gmail.nossr50.config.Config;
+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.UUID;
+
+public class AdminAuthor implements Author {
+
+    private final @NotNull Player player;
+    private @Nullable String overrideName;
+
+    public AdminAuthor(@NotNull Player player) {
+        this.player = player;
+    }
+
+    @Override
+    public @NotNull String getAuthoredName() {
+        if(overrideName != null) {
+            return overrideName;
+        } else {
+            if(Config.getInstance().getAdminDisplayNames()) {
+                return player.getDisplayName();
+            } else {
+                return player.getName();
+            }
+        }
+    }
+
+    @Override
+    public void setName(@NotNull String newName) {
+        overrideName = newName;
+    }
+
+    @Override
+    public boolean isConsole() {
+        return false;
+    }
+
+    @Override
+    public boolean isPlayer() {
+        return true;
+    }
+
+    @Override
+    public @NonNull UUID uuid() {
+        return player.getUniqueId();
+    }
+}

+ 32 - 0
src/main/java/com/gmail/nossr50/chat/author/Author.java

@@ -0,0 +1,32 @@
+package com.gmail.nossr50.chat.author;
+
+import net.kyori.adventure.identity.Identity;
+import org.jetbrains.annotations.NotNull;
+
+public interface Author extends Identity {
+
+    /**
+     * The name of this author
+     * @return the name of this author
+     */
+    @NotNull String getAuthoredName();
+
+    /**
+     * Set the name of this author
+     * @param newName value of the new name
+     */
+    void setName(@NotNull String newName);
+
+    /**
+     * Whether or not this author is a {@link org.bukkit.command.ConsoleCommandSender}
+     *
+     * @return true if this author is the console
+     */
+    boolean isConsole();
+
+    /**
+     * Whether or not this author is a {@link org.bukkit.entity.Player}
+     * @return true if this author is a player
+     */
+    boolean isPlayer();
+}

+ 41 - 0
src/main/java/com/gmail/nossr50/chat/author/ConsoleAuthor.java

@@ -0,0 +1,41 @@
+package com.gmail.nossr50.chat.author;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class ConsoleAuthor implements Author {
+    private final UUID uuid;
+    private @NotNull String name;
+
+    public ConsoleAuthor(@NotNull String name) {
+        this.name = name;
+        this.uuid = new UUID(0, 0);
+    }
+
+    @Override
+    public @NotNull String getAuthoredName() {
+        return name;
+    }
+
+    @Override
+    public void setName(@NotNull String newName) {
+        this.name = newName;
+    }
+
+    @Override
+    public boolean isConsole() {
+        return true;
+    }
+
+    @Override
+    public boolean isPlayer() {
+        return false;
+    }
+
+    @Override
+    public @NonNull UUID uuid() {
+        return uuid;
+    }
+}

+ 52 - 0
src/main/java/com/gmail/nossr50/chat/author/PartyAuthor.java

@@ -0,0 +1,52 @@
+package com.gmail.nossr50.chat.author;
+
+import com.gmail.nossr50.config.Config;
+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.UUID;
+
+public class PartyAuthor implements Author {
+
+    private final @NotNull Player player;
+    private @Nullable String overrideName;
+
+    public PartyAuthor(@NotNull Player player) {
+        this.player = player;
+    }
+
+    @Override
+    public @NotNull String getAuthoredName() {
+        if(overrideName != null) {
+            return overrideName;
+        } else {
+            if(Config.getInstance().getPartyDisplayNames()) {
+                return player.getDisplayName();
+            } else {
+                return player.getName();
+            }
+        }
+    }
+
+    @Override
+    public void setName(@NotNull String newName) {
+        overrideName = newName;
+    }
+
+    @Override
+    public boolean isConsole() {
+        return false;
+    }
+
+    @Override
+    public boolean isPlayer() {
+        return true;
+    }
+
+    @Override
+    public @NonNull UUID uuid() {
+        return player.getUniqueId();
+    }
+}

+ 13 - 0
src/main/java/com/gmail/nossr50/chat/mailer/AbstractChatMailer.java

@@ -0,0 +1,13 @@
+package com.gmail.nossr50.chat.mailer;
+
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+
+public abstract class AbstractChatMailer implements ChatMailer {
+    protected final @NotNull Plugin pluginRef;
+
+    public AbstractChatMailer(@NotNull Plugin pluginRef) {
+        this.pluginRef = pluginRef;
+    }
+}

+ 72 - 0
src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java

@@ -0,0 +1,72 @@
+package com.gmail.nossr50.chat.mailer;
+
+import com.gmail.nossr50.chat.author.Author;
+import com.gmail.nossr50.chat.message.AdminChatMessage;
+import com.gmail.nossr50.chat.message.ChatMessage;
+import com.gmail.nossr50.events.chat.McMMOAdminChatEvent;
+import com.gmail.nossr50.events.chat.McMMOChatEvent;
+import com.gmail.nossr50.locale.LocaleLoader;
+import com.gmail.nossr50.mcMMO;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.Predicate;
+
+public class AdminChatMailer extends AbstractChatMailer {
+
+    public AdminChatMailer(Plugin pluginRef) {
+        super(pluginRef);
+    }
+
+    public static final @NotNull String MCMMO_CHAT_ADMINCHAT_PERMISSION = "mcmmo.chat.adminchat";
+
+    /**
+     * Constructs an audience of admins
+     * @return an audience of admins
+     */
+    public @NotNull Audience constructAudience() {
+        return mcMMO.getAudiences().filter(predicate());
+    }
+
+    /**
+     * Predicate used to filter the audience
+     * @return admin chat audience predicate
+     */
+    public @NotNull Predicate<CommandSender> predicate() {
+        return (commandSender) -> commandSender.isOp()
+                || commandSender.hasPermission(MCMMO_CHAT_ADMINCHAT_PERMISSION)
+                || commandSender instanceof ConsoleCommandSender;
+    }
+
+    /**
+     * Styles a string using a locale entry
+     * @param author message author
+     * @param message message contents
+     * @return the styled string, based on a locale entry
+     */
+    public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message) {
+        return Component.text(LocaleLoader.getString("Chat.Style.Admin", author.getAuthoredName(), message));
+    }
+
+    @Override
+    public void sendMail(@NotNull ChatMessage chatMessage) {
+        chatMessage.sendMessage();
+    }
+
+    public void processChatMessage(@NotNull Author author, @NotNull String rawString, boolean isAsync) {
+        AdminChatMessage chatMessage = new AdminChatMessage(pluginRef, author, constructAudience(), rawString, addStyle(author, rawString));
+
+        McMMOChatEvent chatEvent = new McMMOAdminChatEvent(pluginRef, chatMessage, isAsync);
+        Bukkit.getPluginManager().callEvent(chatEvent);
+
+        if(!chatEvent.isCancelled()) {
+            sendMail(chatMessage);
+        }
+    }
+}

+ 12 - 0
src/main/java/com/gmail/nossr50/chat/mailer/ChatMailer.java

@@ -0,0 +1,12 @@
+package com.gmail.nossr50.chat.mailer;
+
+import com.gmail.nossr50.chat.message.ChatMessage;
+import org.jetbrains.annotations.NotNull;
+
+public interface ChatMailer {
+    /**
+     * Send out a chat message
+     * @param chatMessage the {@link ChatMessage}
+     */
+    void sendMail(@NotNull ChatMessage chatMessage);
+}

+ 47 - 0
src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java

@@ -0,0 +1,47 @@
+package com.gmail.nossr50.chat.mailer;
+
+import com.gmail.nossr50.chat.author.Author;
+import com.gmail.nossr50.chat.message.ChatMessage;
+import com.gmail.nossr50.chat.message.PartyChatMessage;
+import com.gmail.nossr50.datatypes.party.Party;
+import com.gmail.nossr50.events.chat.McMMOChatEvent;
+import com.gmail.nossr50.events.chat.McMMOPartyChatEvent;
+import com.gmail.nossr50.locale.LocaleLoader;
+import com.gmail.nossr50.mcMMO;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+public class PartyChatMailer extends AbstractChatMailer {
+
+    public PartyChatMailer(@NotNull Plugin pluginRef) {
+        super(pluginRef);
+    }
+
+    public void processChatMessage(@NotNull Author author, @NotNull String rawString, @NotNull Party party, boolean isAsync) {
+        PartyChatMessage chatMessage = new PartyChatMessage(pluginRef, author, constructPartyAudience(party), rawString, addStyle(author, rawString), party);
+
+        McMMOChatEvent chatEvent = new McMMOPartyChatEvent(pluginRef, chatMessage, party, isAsync);
+        Bukkit.getPluginManager().callEvent(chatEvent);
+
+        if(!chatEvent.isCancelled()) {
+            sendMail(chatMessage);
+        }
+    }
+
+    public @NotNull Audience constructPartyAudience(@NotNull Party party) {
+        return mcMMO.getAudiences().filter(party.getSamePartyPredicate());
+    }
+
+    public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message) {
+        return Component.text(LocaleLoader.getString("Chat.Style.Party", author.getAuthoredName(), message));
+    }
+
+    @Override
+    public void sendMail(@NotNull ChatMessage chatMessage) {
+        chatMessage.sendMessage();
+    }
+}

+ 59 - 0
src/main/java/com/gmail/nossr50/chat/message/AbstractChatMessage.java

@@ -0,0 +1,59 @@
+package com.gmail.nossr50.chat.message;
+
+import com.gmail.nossr50.chat.author.Author;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.TextComponent;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+public abstract class AbstractChatMessage implements ChatMessage {
+
+    protected final @NotNull Plugin pluginRef;
+    protected final @NotNull Author author;
+    protected final @NotNull String rawMessage;
+    protected @NotNull TextComponent componentMessage;
+    protected @NotNull Audience audience;
+
+    public AbstractChatMessage(@NotNull Plugin pluginRef, @NotNull Author author, @NotNull Audience audience, @NotNull String rawMessage, @NotNull TextComponent componentMessage) {
+        this.pluginRef = pluginRef;
+        this.author = author;
+        this.audience = audience;
+        this.rawMessage = rawMessage;
+        this.componentMessage = componentMessage;
+    }
+
+    @Override
+    public @NotNull String rawMessage() {
+        return rawMessage;
+    }
+
+    @Override
+    public @NotNull Author getAuthor() {
+        return author;
+    }
+
+    @Override
+    public @NotNull String getAuthorDisplayName() {
+        return author.getAuthoredName();
+    }
+
+    @Override
+    public @NotNull Audience getAudience() {
+        return audience;
+    }
+
+    @Override
+    public @NotNull TextComponent getChatMessage() {
+        return componentMessage;
+    }
+
+    @Override
+    public void setChatMessage(@NotNull TextComponent textComponent) {
+        this.componentMessage = textComponent;
+    }
+
+    @Override
+    public void setAudience(@NotNull Audience newAudience) {
+        audience = newAudience;
+    }
+}

+ 18 - 0
src/main/java/com/gmail/nossr50/chat/message/AdminChatMessage.java

@@ -0,0 +1,18 @@
+package com.gmail.nossr50.chat.message;
+
+import com.gmail.nossr50.chat.author.Author;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.TextComponent;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+public class AdminChatMessage extends AbstractChatMessage {
+    public AdminChatMessage(@NotNull Plugin pluginRef, @NotNull Author author, @NotNull Audience audience, @NotNull String rawMessage, @NotNull TextComponent componentMessage) {
+        super(pluginRef, author, audience, rawMessage, componentMessage);
+    }
+
+    @Override
+    public void sendMessage() {
+        audience.sendMessage(author, componentMessage);
+    }
+}

+ 73 - 0
src/main/java/com/gmail/nossr50/chat/message/ChatMessage.java

@@ -0,0 +1,73 @@
+package com.gmail.nossr50.chat.message;
+
+import com.gmail.nossr50.chat.author.Author;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.TextComponent;
+import org.jetbrains.annotations.NotNull;
+
+public interface ChatMessage {
+    /**
+     * The original message from the {@link Author}
+     * This is formatted and styled before being sent out to players by mcMMO
+     *
+     * @return the original message without any formatting or alterations
+     * @see #getChatMessage()
+     */
+    @NotNull String rawMessage();
+
+    /**
+     * The {@link Author} from which this payload originated
+     *
+     * @see #getChatMessage()
+     * @return the source of the chat message
+     */
+    @NotNull Author getAuthor();
+
+    /**
+     * The authors display name which is used in the initial creation of the message payload, it is provided for convenience.
+     *
+     * This is a name generated by mcMMO during the creation of the {@link ChatMessage}
+     *
+     * This is used by mcMMO when generating the message payload
+     *
+     * This method provides the display name for the convenience of plugins constructing their own {@link TextComponent payloads}
+     *
+     * @see #getChatMessage()
+     * @return the author display name as generated by mcMMO
+     */
+    @NotNull String getAuthorDisplayName();
+
+    /**
+     * The target audience of this chat message
+     * Unless modified, this will include the {@link Author}
+     *
+     * @return target audience
+     */
+    @NotNull Audience getAudience();
+
+    /**
+     * The {@link TextComponent message} being sent to the audience
+     *
+     * @return the {@link TextComponent message} that will be sent to the audience
+     */
+    @NotNull TextComponent getChatMessage();
+
+    /**
+     * Change the value of the {@link TextComponent message}
+     *
+     * @param textComponent new message value
+     */
+    void setChatMessage(@NotNull TextComponent textComponent);
+
+    /**
+     * Changes the audience
+     *
+     * @param newAudience the replacement audience
+     */
+    void setAudience(@NotNull Audience newAudience);
+
+    /**
+     * Deliver the message to the audience
+     */
+    void sendMessage();
+}

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

@@ -0,0 +1,63 @@
+package com.gmail.nossr50.chat.message;
+
+import com.gmail.nossr50.chat.author.Author;
+import com.gmail.nossr50.datatypes.party.Party;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.player.UserManager;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+public class PartyChatMessage extends AbstractChatMessage {
+
+    private final @NotNull Party party;
+
+    public PartyChatMessage(@NotNull Plugin pluginRef, @NotNull Author author, @NotNull Audience audience, @NotNull String rawMessage, @NotNull TextComponent componentMessage, @NotNull Party party) {
+        super(pluginRef, author, audience, rawMessage, componentMessage);
+        this.party = party;
+    }
+
+    /**
+     * The party that this chat message was intended for
+     * @return the party that this message was intended for
+     */
+    public @NotNull Party getParty() {
+        return party;
+    }
+
+    @Override
+    public void sendMessage() {
+        audience.sendMessage(author, componentMessage);
+
+        //Relay to spies
+        TextComponent textComponent = Component.text("[" + getParty().getName() + "] ->" ).append(getChatMessage());
+        relayChatToSpies(textComponent);
+    }
+
+    /**
+     * Party Chat Spies will get a copy of the message as well
+     * @param spyMessage the message to copy to spies
+     */
+    private void relayChatToSpies(@NotNull TextComponent spyMessage) {
+        //Find the people with permissions
+        for(McMMOPlayer mcMMOPlayer : UserManager.getPlayers()) {
+            Player player = mcMMOPlayer.getPlayer();
+
+            //Check for toggled players
+            if(mcMMOPlayer.isPartyChatSpying()) {
+                Party adminParty = mcMMOPlayer.getParty();
+
+                //Only message admins not part of this party
+                if(adminParty == null || adminParty != getParty()) {
+                    //TODO: Hacky, rewrite later
+                    Audience audience = mcMMO.getAudiences().player(player);
+                    audience.sendMessage(spyMessage);
+                }
+            }
+        }
+    }
+}

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

@@ -0,0 +1,103 @@
+package com.gmail.nossr50.commands;
+
+import co.aikar.commands.BukkitCommandIssuer;
+import co.aikar.commands.BukkitCommandManager;
+import co.aikar.commands.ConditionFailedException;
+import com.gmail.nossr50.commands.chat.AdminChatCommand;
+import com.gmail.nossr50.commands.chat.PartyChatCommand;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.locale.LocaleLoader;
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.player.UserManager;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+/*
+ * For now this class will only handle ACF converted commands, all other commands will be handled elsewhere
+ */
+public class CommandManager {
+    public static final String ADMIN_CONDITION = "adminCondition";
+    public static final String PARTY_CONDITION = "partyCondition";
+    public static final String MMO_DATA_LOADED = "mmoDataLoaded";
+
+    private final @NotNull mcMMO pluginRef;
+    private final @NotNull BukkitCommandManager bukkitCommandManager;
+
+    public CommandManager(@NotNull mcMMO pluginRef) {
+        this.pluginRef = pluginRef;
+        bukkitCommandManager = new BukkitCommandManager(pluginRef);
+
+        registerConditions();
+        registerCommands();
+    }
+
+    public void registerConditions() {
+        //TODO: Might be making a mistake with this lambda here, double check
+        //TODO: Might be making a mistake with this lambda here, double check
+        //TODO: Might be making a mistake with this lambda here, double check
+        //TODO: Might be making a mistake with this lambda here, double check
+        //TODO: Might be making a mistake with this lambda here, double check
+        //TODO: Might be making a mistake with this lambda here, double check
+        //TODO: Might be making a mistake with this lambda here, double check
+        //TODO: Might be making a mistake with this lambda here, double check
+        //TODO: Might be making a mistake with this lambda here, double check
+        //TODO: Might be making a mistake with this lambda here, double check
+
+        // Method or Class based - Can only be used on methods
+        bukkitCommandManager.getCommandConditions().addCondition(ADMIN_CONDITION, (context) -> {
+            BukkitCommandIssuer issuer = context.getIssuer();
+
+            if(issuer.getIssuer() instanceof Player) {
+                validateAdmin(issuer.getPlayer());
+            }
+        });
+
+        bukkitCommandManager.getCommandConditions().addCondition(MMO_DATA_LOADED, (context) -> {
+            BukkitCommandIssuer bukkitCommandIssuer = context.getIssuer();
+
+            if(bukkitCommandIssuer.getIssuer() instanceof Player) {
+                validateLoadedData(bukkitCommandIssuer.getPlayer());
+            }
+        });
+
+        bukkitCommandManager.getCommandConditions().addCondition(PARTY_CONDITION, (context) -> {
+            BukkitCommandIssuer bukkitCommandIssuer = context.getIssuer();
+
+            if(bukkitCommandIssuer.getIssuer() instanceof Player) {
+                validateLoadedData(bukkitCommandIssuer.getPlayer());
+                validatePlayerParty(bukkitCommandIssuer.getPlayer());
+            }
+        });
+    }
+
+    private void registerCommands() {
+        bukkitCommandManager.registerCommand(new AdminChatCommand(pluginRef));
+        bukkitCommandManager.registerCommand(new PartyChatCommand(pluginRef));
+    }
+
+
+    public void validateAdmin(@NotNull Player player) {
+        if(!player.isOp() && !Permissions.adminChat(player)) {
+            throw new ConditionFailedException("You are lacking the correct permissions to use this command.");
+        }
+    }
+
+    public void validateLoadedData(@NotNull Player player) {
+        if(UserManager.getPlayer(player) == null) {
+            throw new ConditionFailedException("Your mcMMO player data has not yet loaded!");
+        }
+    }
+
+    public void validatePlayerParty(@NotNull Player player) {
+        McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
+
+        if(mmoPlayer.getParty() == null) {
+            throw new ConditionFailedException(LocaleLoader.getString("Commands.Party.None"));
+        }
+    }
+
+    public @NotNull BukkitCommandManager getBukkitCommandManager() {
+        return bukkitCommandManager;
+    }
+}

+ 40 - 8
src/main/java/com/gmail/nossr50/commands/chat/AdminChatCommand.java

@@ -1,15 +1,47 @@
 package com.gmail.nossr50.commands.chat;
 package com.gmail.nossr50.commands.chat;
 
 
-import com.gmail.nossr50.datatypes.chat.ChatMode;
-import org.bukkit.command.CommandSender;
+import co.aikar.commands.BaseCommand;
+import co.aikar.commands.BukkitCommandIssuer;
+import co.aikar.commands.annotation.CommandAlias;
+import co.aikar.commands.annotation.Conditions;
+import co.aikar.commands.annotation.Default;
+import com.gmail.nossr50.commands.CommandManager;
+import com.gmail.nossr50.datatypes.chat.ChatChannel;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.player.UserManager;
+import org.jetbrains.annotations.NotNull;
 
 
-public class AdminChatCommand extends ChatCommand {
-    public AdminChatCommand() {
-        super(ChatMode.ADMIN);
+@CommandAlias("a|adminchat") //Kept for historical reasons
+public class AdminChatCommand extends BaseCommand {
+    private final @NotNull mcMMO pluginRef;
+
+    public AdminChatCommand(@NotNull mcMMO pluginRef) {
+        this.pluginRef = pluginRef;
     }
     }
 
 
-    @Override
-    protected void handleChatSending(CommandSender sender, String[] args) {
-        chatManager.handleChat(sender.getName(), getDisplayName(sender), buildChatMessage(args, 0));
+    @Default @Conditions(CommandManager.ADMIN_CONDITION)
+    public void processCommand(String[] args) {
+        BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer();
+        if(args == null || args.length == 0) {
+            //Process with no arguments
+            if(bukkitCommandIssuer.isPlayer()) {
+                McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer());
+                pluginRef.getChatManager().setOrToggleChatChannel(mmoPlayer, ChatChannel.ADMIN);
+            } else {
+                //Not support for console
+                mcMMO.p.getLogger().info("You cannot switch chat channels as console, please provide full arguments.");
+            }
+        } else {
+            if(bukkitCommandIssuer.isPlayer()) {
+                McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer());
+
+                //Message contains the original command so it needs to be passed to this method to trim it
+                pluginRef.getChatManager().processPlayerMessage(mmoPlayer, args, ChatChannel.ADMIN);
+            } else {
+                pluginRef.getChatManager().processConsoleMessage(args);
+            }
+            //Arguments are greater than 0, therefore directly send message and skip toggles
+        }
     }
     }
 }
 }

+ 0 - 141
src/main/java/com/gmail/nossr50/commands/chat/ChatCommand.java

@@ -1,141 +0,0 @@
-package com.gmail.nossr50.commands.chat;
-
-import com.gmail.nossr50.chat.ChatManager;
-import com.gmail.nossr50.chat.ChatManagerFactory;
-import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.datatypes.chat.ChatMode;
-import com.gmail.nossr50.datatypes.party.PartyFeature;
-import com.gmail.nossr50.datatypes.player.McMMOPlayer;
-import com.gmail.nossr50.locale.LocaleLoader;
-import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.commands.CommandUtils;
-import com.gmail.nossr50.util.player.UserManager;
-import com.google.common.collect.ImmutableList;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandSender;
-import org.bukkit.command.TabExecutor;
-import org.bukkit.entity.Player;
-import org.bukkit.util.StringUtil;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public abstract class ChatCommand implements TabExecutor {
-    private final ChatMode chatMode;
-    protected ChatManager chatManager;
-
-    public ChatCommand(ChatMode chatMode) {
-        this.chatMode = chatMode;
-        this.chatManager = ChatManagerFactory.getChatManager(mcMMO.p, chatMode);
-    }
-
-    @Override
-    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
-        McMMOPlayer mcMMOPlayer;
-
-        switch (args.length) {
-            case 0:
-                if (CommandUtils.noConsoleUsage(sender)) {
-                    return true;
-                }
-
-                if (!CommandUtils.hasPlayerDataKey(sender)) {
-                    return true;
-                }
-
-                mcMMOPlayer = UserManager.getPlayer(sender.getName());
-
-                if (mcMMOPlayer.isChatEnabled(chatMode)) {
-                    disableChatMode(mcMMOPlayer, sender);
-                }
-                else {
-                    enableChatMode(mcMMOPlayer, sender);
-                }
-
-                return true;
-
-            case 1:
-                if (CommandUtils.shouldEnableToggle(args[0])) {
-                    if (CommandUtils.noConsoleUsage(sender)) {
-                        return true;
-                    }
-                    if (!CommandUtils.hasPlayerDataKey(sender)) {
-                        return true;
-                    }
-
-                    enableChatMode(UserManager.getPlayer(sender.getName()), sender);
-                    return true;
-                }
-
-                if (CommandUtils.shouldDisableToggle(args[0])) {
-                    if (CommandUtils.noConsoleUsage(sender)) {
-                        return true;
-                    }
-                    if (!CommandUtils.hasPlayerDataKey(sender)) {
-                        return true;
-                    }
-
-                    disableChatMode(UserManager.getPlayer(sender.getName()), sender);
-                    return true;
-                }
-
-                // Fallthrough
-
-            default:
-                handleChatSending(sender, args);
-                return true;
-        }
-    }
-
-    @Override
-    public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
-        if (args.length == 1) {
-            return StringUtil.copyPartialMatches(args[0], CommandUtils.TRUE_FALSE_OPTIONS, new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size()));
-        }
-        return ImmutableList.of();
-    }
-
-    protected String buildChatMessage(String[] args, int index) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(args[index]);
-
-        for (int i = index + 1; i < args.length; i++) {
-            builder.append(" ");
-            builder.append(args[i]);
-        }
-
-        return builder.toString();
-    }
-
-    protected String getDisplayName(CommandSender sender) {
-        return (sender instanceof Player) ? ((Player) sender).getDisplayName() : LocaleLoader.getString("Commands.Chat.Console");
-    }
-
-    protected abstract void handleChatSending(CommandSender sender, String[] args);
-
-    private void enableChatMode(McMMOPlayer mcMMOPlayer, CommandSender sender) {
-        if (chatMode == ChatMode.PARTY && mcMMOPlayer.getParty() == null) {
-            sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
-            return;
-        }
-
-        if (chatMode == ChatMode.PARTY && (mcMMOPlayer.getParty().getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.CHAT))) {
-            sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.1"));
-            return;
-        }
-
-        mcMMOPlayer.enableChat(chatMode);
-        sender.sendMessage(chatMode.getEnabledMessage());
-    }
-
-    private void disableChatMode(McMMOPlayer mcMMOPlayer, CommandSender sender) {
-        if (chatMode == ChatMode.PARTY && mcMMOPlayer.getParty() == null) {
-            sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
-            return;
-        }
-
-        mcMMOPlayer.disableChat(chatMode);
-        sender.sendMessage(chatMode.getDisabledMessage());
-    }
-}

+ 67 - 42
src/main/java/com/gmail/nossr50/commands/chat/PartyChatCommand.java

@@ -1,62 +1,87 @@
 package com.gmail.nossr50.commands.chat;
 package com.gmail.nossr50.commands.chat;
 
 
-import com.gmail.nossr50.chat.PartyChatManager;
-import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.datatypes.chat.ChatMode;
+import co.aikar.commands.BaseCommand;
+import co.aikar.commands.BukkitCommandIssuer;
+import co.aikar.commands.annotation.CommandAlias;
+import co.aikar.commands.annotation.Conditions;
+import co.aikar.commands.annotation.Default;
+import com.gmail.nossr50.commands.CommandManager;
+import com.gmail.nossr50.datatypes.chat.ChatChannel;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.Party;
-import com.gmail.nossr50.datatypes.party.PartyFeature;
-import com.gmail.nossr50.locale.LocaleLoader;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.party.PartyManager;
 import com.gmail.nossr50.party.PartyManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
-import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
 
 
-public class PartyChatCommand extends ChatCommand {
-    public PartyChatCommand() {
-        super(ChatMode.PARTY);
-    }
-
-    @Override
-    protected void handleChatSending(CommandSender sender, String[] args) {
-        Party party;
-        String message;
+@CommandAlias("p|partychat") //Kept for historical reasons
+public class PartyChatCommand extends BaseCommand {
+    private final @NotNull mcMMO pluginRef;
 
 
-        if (sender instanceof Player) {
-            //Check if player profile is loaded
-            if(UserManager.getPlayer((Player) sender) == null)
-                return;
+    public PartyChatCommand(@NotNull mcMMO pluginRef) {
+        this.pluginRef = pluginRef;
+    }
 
 
-            party = UserManager.getPlayer((Player) sender).getParty();
+    @Default
+    @Conditions(CommandManager.PARTY_CONDITION)
+    public void processCommand(String[] args) {
+        BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer();
 
 
-            if (party == null) {
-                sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
-                return;
+        if(args == null || args.length == 0) {
+            //Process with no arguments
+            if(bukkitCommandIssuer.isPlayer()) {
+                McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer());
+                pluginRef.getChatManager().setOrToggleChatChannel(mmoPlayer, ChatChannel.PARTY);
+            } else {
+                //Not support for console
+                mcMMO.p.getLogger().info("You cannot switch chat channels as console, please provide full arguments.");
             }
             }
+        } else {
+            //Here we split the logic, consoles need to target a party name and players do not
 
 
-            if (party.getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.CHAT)) {
-                sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.1"));
-                return;
+            /*
+             * Player Logic
+             */
+            if(bukkitCommandIssuer.getIssuer() instanceof Player) {
+                McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer());
+                processCommandArgsPlayer(mmoPlayer, args);
+            /*
+             * Console Logic
+             */
+            } else {
+                processCommandArgsConsole(args);
             }
             }
-
-            message = buildChatMessage(args, 0);
         }
         }
-        else {
-            if (args.length < 2) {
-                sender.sendMessage(LocaleLoader.getString("Party.Specify"));
-                return;
-            }
+    }
 
 
-            party = PartyManager.getParty(args[0]);
+    /**
+     * Processes the command with arguments for a {@link McMMOPlayer}
+     * @param mmoPlayer target player
+     * @param args command arguments
+     */
+    private void processCommandArgsPlayer(@NotNull McMMOPlayer mmoPlayer, @NotNull String[] args) {
+        //Player is not toggling and is chatting directly to party
+        pluginRef.getChatManager().processPlayerMessage(mmoPlayer, args, ChatChannel.PARTY);
+    }
 
 
-            if (party == null) {
-                sender.sendMessage(LocaleLoader.getString("Party.InvalidName"));
-                return;
-            }
+    /**
+     * Processes the command with arguments for a {@link com.gmail.nossr50.chat.author.ConsoleAuthor}
+     * @param args command arguments
+     */
+    private void processCommandArgsConsole(@NotNull String[] args) {
+        if(args.length <= 1) {
+            //Only specific a party and not the message
+            mcMMO.p.getLogger().severe("You need to specify a party name and then write a message afterwards.");
+        } else {
+            //Grab party
+            Party targetParty = PartyManager.getParty(args[0]);
 
 
-            message = buildChatMessage(args, 1);
+            if(targetParty != null) {
+                pluginRef.getChatManager().processConsoleMessage(args, targetParty);
+            } else {
+                mcMMO.p.getLogger().severe("A party with that name doesn't exist!");
+            }
         }
         }
-
-        ((PartyChatManager) chatManager).setParty(party);
-        chatManager.handleChat(sender.getName(), getDisplayName(sender), message);
     }
     }
 }
 }

+ 0 - 4
src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.commands.party;
 package com.gmail.nossr50.commands.party;
 
 
-import com.gmail.nossr50.commands.chat.PartyChatCommand;
 import com.gmail.nossr50.commands.party.alliance.PartyAllianceCommand;
 import com.gmail.nossr50.commands.party.alliance.PartyAllianceCommand;
 import com.gmail.nossr50.commands.party.teleport.PtpCommand;
 import com.gmail.nossr50.commands.party.teleport.PtpCommand;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.Party;
@@ -55,7 +54,6 @@ public class PartyCommand implements TabExecutor {
     private final CommandExecutor partyInfoCommand           = new PartyInfoCommand();
     private final CommandExecutor partyInfoCommand           = new PartyInfoCommand();
     private final CommandExecutor partyHelpCommand           = new PartyHelpCommand();
     private final CommandExecutor partyHelpCommand           = new PartyHelpCommand();
     private final CommandExecutor partyTeleportCommand       = new PtpCommand();
     private final CommandExecutor partyTeleportCommand       = new PtpCommand();
-    private final CommandExecutor partyChatCommand           = new PartyChatCommand();
     private final CommandExecutor partyAllianceCommand       = new PartyAllianceCommand();
     private final CommandExecutor partyAllianceCommand       = new PartyAllianceCommand();
 
 
     @Override
     @Override
@@ -132,8 +130,6 @@ public class PartyCommand implements TabExecutor {
                 return partyInviteCommand.onCommand(sender, command, label, args);
                 return partyInviteCommand.onCommand(sender, command, label, args);
             case TELEPORT:
             case TELEPORT:
                 return partyTeleportCommand.onCommand(sender, command, label, extractArgs(args));
                 return partyTeleportCommand.onCommand(sender, command, label, extractArgs(args));
-            case CHAT:
-                return partyChatCommand.onCommand(sender, command, label, extractArgs(args));
             default:
             default:
                 break;
                 break;
         }
         }

+ 12 - 12
src/main/java/com/gmail/nossr50/commands/skills/AprilCommand.java

@@ -157,40 +157,40 @@ public class AprilCommand implements TabExecutor {
 
 
         switch (fakeSkillType) {
         switch (fakeSkillType) {
             case MACHO:
             case MACHO:
-                messages.add(LocaleLoader.formatString("[[RED]]Damage Taken: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(77))));
+                messages.add(LocaleLoader.formatString("&cDamage Taken: &e{0}%", decimal.format(Misc.getRandom().nextInt(77))));
                 break;
                 break;
             case JUMPING:
             case JUMPING:
-                messages.add(LocaleLoader.formatString("[[RED]]Double Jump Chance: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(27))));
+                messages.add(LocaleLoader.formatString("&cDouble Jump Chance: &e{0}%", decimal.format(Misc.getRandom().nextInt(27))));
                 break;
                 break;
             case THROWING:
             case THROWING:
-                messages.add(LocaleLoader.formatString("[[RED]]Drop Item Chance: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(87))));
+                messages.add(LocaleLoader.formatString("&cDrop Item Chance: &e{0}%", decimal.format(Misc.getRandom().nextInt(87))));
                 break;
                 break;
             case WRECKING:
             case WRECKING:
-                messages.add(LocaleLoader.formatString("[[RED]]Wrecking Chance: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(14))));
+                messages.add(LocaleLoader.formatString("&cWrecking Chance: &e{0}%", decimal.format(Misc.getRandom().nextInt(14))));
                 break;
                 break;
             case CRAFTING:
             case CRAFTING:
-                messages.add(LocaleLoader.formatString("[[RED]]Crafting Success: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(27))));
+                messages.add(LocaleLoader.formatString("&cCrafting Success: &e{0}%", decimal.format(Misc.getRandom().nextInt(27))));
                 break;
                 break;
             case WALKING:
             case WALKING:
-                messages.add(LocaleLoader.formatString("[[RED]]Walk Chance: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(27))));
+                messages.add(LocaleLoader.formatString("&cWalk Chance: &e{0}%", decimal.format(Misc.getRandom().nextInt(27))));
                 break;
                 break;
             case SWIMMING:
             case SWIMMING:
-                messages.add(LocaleLoader.formatString("[[RED]]Swim Chance: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(27))));
+                messages.add(LocaleLoader.formatString("&cSwim Chance: &e{0}%", decimal.format(Misc.getRandom().nextInt(27))));
                 break;
                 break;
             case FALLING:
             case FALLING:
-                messages.add(LocaleLoader.formatString("[[RED]]Skydiving Success: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(37))));
+                messages.add(LocaleLoader.formatString("&cSkydiving Success: &e{0}%", decimal.format(Misc.getRandom().nextInt(37))));
                 break;
                 break;
             case CLIMBING:
             case CLIMBING:
-                messages.add(LocaleLoader.formatString("[[RED]]Rock Climber Chance: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(27))));
+                messages.add(LocaleLoader.formatString("&cRock Climber Chance: &e{0}%", decimal.format(Misc.getRandom().nextInt(27))));
                 break;
                 break;
             case FLYING:
             case FLYING:
-                messages.add(LocaleLoader.formatString("[[RED]]Fly Chance: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(27))));
+                messages.add(LocaleLoader.formatString("&cFly Chance: &e{0}%", decimal.format(Misc.getRandom().nextInt(27))));
                 break;
                 break;
             case DIVING:
             case DIVING:
-                messages.add(LocaleLoader.formatString("[[RED]]Hold Breath Chance: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(27))));
+                messages.add(LocaleLoader.formatString("&cHold Breath Chance: &e{0}%", decimal.format(Misc.getRandom().nextInt(27))));
                 break;
                 break;
             case PIGGY:
             case PIGGY:
-                messages.add(LocaleLoader.formatString("[[RED]]Carrot Turbo Boost: [[YELLOW]]{0}%", decimal.format(Misc.getRandom().nextInt(80)) + 10));
+                messages.add(LocaleLoader.formatString("&cCarrot Turbo Boost: &e{0}%", decimal.format(Misc.getRandom().nextInt(80)) + 10));
                 break;
                 break;
         }
         }
 
 

+ 6 - 3
src/main/java/com/gmail/nossr50/datatypes/chat/ChatMode.java → src/main/java/com/gmail/nossr50/datatypes/chat/ChatChannel.java

@@ -1,15 +1,18 @@
 package com.gmail.nossr50.datatypes.chat;
 package com.gmail.nossr50.datatypes.chat;
 
 
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
+import org.jetbrains.annotations.Nullable;
 
 
-public enum ChatMode {
+public enum ChatChannel {
     ADMIN(LocaleLoader.getString("Commands.AdminChat.On"), LocaleLoader.getString("Commands.AdminChat.Off")),
     ADMIN(LocaleLoader.getString("Commands.AdminChat.On"), LocaleLoader.getString("Commands.AdminChat.Off")),
-    PARTY(LocaleLoader.getString("Commands.Party.Chat.On"), LocaleLoader.getString("Commands.Party.Chat.Off"));
+    PARTY(LocaleLoader.getString("Commands.Party.Chat.On"), LocaleLoader.getString("Commands.Party.Chat.Off")),
+    PARTY_OFFICER(null, null),
+    NONE(null, null);
 
 
     private final String enabledMessage;
     private final String enabledMessage;
     private final String disabledMessage;
     private final String disabledMessage;
 
 
-    ChatMode(String enabledMessage, String disabledMessage) {
+    ChatChannel(@Nullable String enabledMessage, @Nullable String disabledMessage) {
         this.enabledMessage  = enabledMessage;
         this.enabledMessage  = enabledMessage;
         this.disabledMessage = disabledMessage;
         this.disabledMessage = disabledMessage;
     }
     }

+ 12 - 0
src/main/java/com/gmail/nossr50/datatypes/party/Party.java

@@ -1,5 +1,6 @@
 package com.gmail.nossr50.datatypes.party;
 package com.gmail.nossr50.datatypes.party;
 
 
+import com.gmail.nossr50.chat.SamePartyPredicate;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.datatypes.experience.FormulaType;
 import com.gmail.nossr50.datatypes.experience.FormulaType;
@@ -16,15 +17,18 @@ import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
 import org.bukkit.ChatColor;
 import org.bukkit.command.CommandSender;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
 
 
 import java.text.DecimalFormat;
 import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 import java.util.UUID;
 import java.util.UUID;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 public class Party {
 public class Party {
+    private final @NotNull Predicate<CommandSender> samePartyPredicate;
 //    private static final String ONLINE_PLAYER_PREFIX = "★";
 //    private static final String ONLINE_PLAYER_PREFIX = "★";
 //    private static final String ONLINE_PLAYER_PREFIX = "●" + ChatColor.RESET;
 //    private static final String ONLINE_PLAYER_PREFIX = "●" + ChatColor.RESET;
     private static final String ONLINE_PLAYER_PREFIX = "⬤";
     private static final String ONLINE_PLAYER_PREFIX = "⬤";
@@ -53,6 +57,7 @@ public class Party {
 
 
     public Party(String name) {
     public Party(String name) {
         this.name = name;
         this.name = name;
+        samePartyPredicate = new SamePartyPredicate<>(this);
     }
     }
 
 
     public Party(PartyLeader leader, String name) {
     public Party(PartyLeader leader, String name) {
@@ -60,6 +65,7 @@ public class Party {
         this.name = name;
         this.name = name;
         this.locked = true;
         this.locked = true;
         this.level = 0;
         this.level = 0;
+        samePartyPredicate = new SamePartyPredicate<>(this);
     }
     }
 
 
     public Party(PartyLeader leader, String name, String password) {
     public Party(PartyLeader leader, String name, String password) {
@@ -68,6 +74,7 @@ public class Party {
         this.password = password;
         this.password = password;
         this.locked = true;
         this.locked = true;
         this.level = 0;
         this.level = 0;
+        samePartyPredicate = new SamePartyPredicate<>(this);
     }
     }
 
 
     public Party(PartyLeader leader, String name, String password, boolean locked) {
     public Party(PartyLeader leader, String name, String password, boolean locked) {
@@ -76,6 +83,7 @@ public class Party {
         this.password = password;
         this.password = password;
         this.locked = locked;
         this.locked = locked;
         this.level = 0;
         this.level = 0;
+        samePartyPredicate = new SamePartyPredicate<>(this);
     }
     }
 
 
     public LinkedHashMap<UUID, String> getMembers() {
     public LinkedHashMap<UUID, String> getMembers() {
@@ -550,4 +558,8 @@ public class Party {
 
 
         return this.getName().equals(other.getName());
         return this.getName().equals(other.getName());
     }
     }
+
+    public @NotNull Predicate<CommandSender> getSamePartyPredicate() {
+        return samePartyPredicate;
+    }
 }
 }

+ 50 - 68
src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java

@@ -1,10 +1,12 @@
 package com.gmail.nossr50.datatypes.player;
 package com.gmail.nossr50.datatypes.player;
 
 
+import com.gmail.nossr50.chat.author.AdminAuthor;
+import com.gmail.nossr50.chat.author.PartyAuthor;
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.WorldBlacklist;
 import com.gmail.nossr50.config.WorldBlacklist;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
-import com.gmail.nossr50.datatypes.chat.ChatMode;
+import com.gmail.nossr50.datatypes.chat.ChatChannel;
 import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.experience.XPGainSource;
 import com.gmail.nossr50.datatypes.experience.XPGainSource;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
@@ -50,6 +52,8 @@ import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
 import com.gmail.nossr50.util.sounds.SoundType;
+import net.kyori.adventure.identity.Identified;
+import net.kyori.adventure.identity.Identity;
 import org.apache.commons.lang.Validate;
 import org.apache.commons.lang.Validate;
 import org.bukkit.GameMode;
 import org.bukkit.GameMode;
 import org.bukkit.Location;
 import org.bukkit.Location;
@@ -57,13 +61,21 @@ import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.metadata.FixedMetadataValue;
 import org.bukkit.metadata.FixedMetadataValue;
 import org.bukkit.plugin.Plugin;
 import org.bukkit.plugin.Plugin;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.NotNull;
 
 
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 import java.util.Set;
 import java.util.Set;
 import java.util.UUID;
 import java.util.UUID;
 
 
-public class McMMOPlayer {
+public class McMMOPlayer implements Identified {
+    private final @NotNull Identity identity;
+
+    //Hacky fix for now, redesign later
+    private final @NotNull PartyAuthor partyAuthor;
+    private final @NotNull AdminAuthor adminAuthor;
+
     private final Player        player;
     private final Player        player;
     private final PlayerProfile profile;
     private final PlayerProfile profile;
 
 
@@ -77,8 +89,6 @@ public class McMMOPlayer {
 
 
     private PartyTeleportRecord ptpRecord;
     private PartyTeleportRecord ptpRecord;
 
 
-    private boolean partyChatMode;
-    private boolean adminChatMode;
     private boolean displaySkillNotifications = true;
     private boolean displaySkillNotifications = true;
     private boolean debugMode;
     private boolean debugMode;
 
 
@@ -86,6 +96,8 @@ public class McMMOPlayer {
     private boolean godMode;
     private boolean godMode;
     private boolean chatSpy = false; //Off by default
     private boolean chatSpy = false; //Off by default
 
 
+    private ChatChannel chatChannel;
+
     private final Map<SuperAbilityType, Boolean> abilityMode     = new HashMap<>();
     private final Map<SuperAbilityType, Boolean> abilityMode     = new HashMap<>();
     private final Map<SuperAbilityType, Boolean> abilityInformed = new HashMap<>();
     private final Map<SuperAbilityType, Boolean> abilityInformed = new HashMap<>();
 
 
@@ -106,6 +118,7 @@ public class McMMOPlayer {
     public McMMOPlayer(Player player, PlayerProfile profile) {
     public McMMOPlayer(Player player, PlayerProfile profile) {
         this.playerName = player.getName();
         this.playerName = player.getName();
         UUID uuid = player.getUniqueId();
         UUID uuid = player.getUniqueId();
+        identity = Identity.identity(uuid);
 
 
         this.player = player;
         this.player = player;
         playerMetadata = new FixedMetadataValue(mcMMO.p, playerName);
         playerMetadata = new FixedMetadataValue(mcMMO.p, playerName);
@@ -143,6 +156,11 @@ public class McMMOPlayer {
 
 
         debugMode = false; //Debug mode helps solve support issues, players can toggle it on or off
         debugMode = false; //Debug mode helps solve support issues, players can toggle it on or off
         attackStrength = 1.0D;
         attackStrength = 1.0D;
+
+        this.adminAuthor = new AdminAuthor(player);
+        this.partyAuthor = new PartyAuthor(player);
+
+        this.chatChannel = ChatChannel.NONE;
     }
     }
 
 
     public String getPlayerName() {
     public String getPlayerName() {
@@ -737,70 +755,6 @@ public class McMMOPlayer {
         itemShareModifier = Math.max(10, modifier);
         itemShareModifier = Math.max(10, modifier);
     }
     }
 
 
-    /*
-     * Chat modes
-     */
-
-    public boolean isChatEnabled(ChatMode mode) {
-        switch (mode) {
-            case ADMIN:
-                return adminChatMode;
-
-            case PARTY:
-                return partyChatMode;
-
-            default:
-                return false;
-        }
-    }
-
-    public void disableChat(ChatMode mode) {
-        switch (mode) {
-            case ADMIN:
-                adminChatMode = false;
-                return;
-
-            case PARTY:
-                partyChatMode = false;
-                return;
-
-            default:
-        }
-    }
-
-    public void enableChat(ChatMode mode) {
-        switch (mode) {
-            case ADMIN:
-                adminChatMode = true;
-                partyChatMode = false;
-                return;
-
-            case PARTY:
-                partyChatMode = true;
-                adminChatMode = false;
-                return;
-
-            default:
-        }
-
-    }
-
-    public void toggleChat(ChatMode mode) {
-        switch (mode) {
-            case ADMIN:
-                adminChatMode = !adminChatMode;
-                partyChatMode = !adminChatMode && partyChatMode;
-                return;
-
-            case PARTY:
-                partyChatMode = !partyChatMode;
-                adminChatMode = !partyChatMode && adminChatMode;
-                return;
-
-            default:
-        }
-    }
-
     public boolean isUsingUnarmed() {
     public boolean isUsingUnarmed() {
         return isUsingUnarmed;
         return isUsingUnarmed;
     }
     }
@@ -1080,4 +1034,32 @@ public class McMMOPlayer {
         resetAbilityMode();
         resetAbilityMode();
         getTamingManager().cleanupAllSummons();
         getTamingManager().cleanupAllSummons();
     }
     }
+
+    /**
+     * For use with Adventure API (Kyori lib)
+     * @return this players identity
+     */
+    @Override
+    public @NonNull Identity identity() {
+        return identity;
+    }
+
+    //TODO: Replace this hacky crap
+    public @NotNull PartyAuthor getPartyAuthor() {
+        return partyAuthor;
+    }
+
+    //TODO: Replace this hacky crap
+    public @NotNull AdminAuthor getAdminAuthor() {
+        return adminAuthor;
+    }
+
+    public @NotNull ChatChannel getChatChannel() {
+        return chatChannel;
+    }
+
+    public void setChatMode(ChatChannel chatChannel) {
+        //TODO: Code in the "you turned off blah, you turned on blah" messages.
+        this.chatChannel = chatChannel;
+    }
 }
 }

+ 10 - 9
src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java

@@ -22,6 +22,7 @@ import com.gmail.nossr50.util.skills.SkillActivationType;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
 import com.gmail.nossr50.util.sounds.SoundType;
+import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.TextComponent;
 import net.kyori.adventure.text.TextComponent;
 import org.bukkit.Location;
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.Material;
@@ -143,21 +144,21 @@ public class Roll extends AcrobaticsSubSkill {
         componentBuilder.append("\n");*/
         componentBuilder.append("\n");*/
 
 
         //Acrobatics.SubSkill.Roll.Chance
         //Acrobatics.SubSkill.Roll.Chance
-        componentBuilder.append(LocaleLoader.getString("Acrobatics.SubSkill.Roll.Chance", rollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollChanceLucky) : ""));
-        componentBuilder.append("\n");
-        componentBuilder.append(LocaleLoader.getString("Acrobatics.SubSkill.Roll.GraceChance", gracefulRollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", gracefulRollChanceLucky) : ""));
+        componentBuilder.append(Component.text(LocaleLoader.getString("Acrobatics.SubSkill.Roll.Chance", rollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollChanceLucky) : "")));
+        componentBuilder.append(Component.newline());
+        componentBuilder.append(Component.text(LocaleLoader.getString("Acrobatics.SubSkill.Roll.GraceChance", gracefulRollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", gracefulRollChanceLucky) : "")));
         //Activation Tips
         //Activation Tips
-        componentBuilder.append("\n").append(LocaleLoader.getString("JSON.Hover.Tips")).append("\n");
-        componentBuilder.append(getTips());
-        componentBuilder.append("\n");
+        componentBuilder.append(Component.newline()).append(Component.text(LocaleLoader.getString("JSON.Hover.Tips"))).append(Component.newline());
+        componentBuilder.append(Component.text(getTips()));
+        componentBuilder.append(Component.newline());
         //Advanced
         //Advanced
 
 
         //Lucky Notice
         //Lucky Notice
         if(isLucky)
         if(isLucky)
         {
         {
-            componentBuilder.append(LocaleLoader.getString("JSON.JWrapper.Perks.Header"));
-            componentBuilder.append("\n");
-            componentBuilder.append(LocaleLoader.getString("JSON.JWrapper.Perks.Lucky", "33"));
+            componentBuilder.append(Component.text(LocaleLoader.getString("JSON.JWrapper.Perks.Header")));
+            componentBuilder.append(Component.newline());
+            componentBuilder.append(Component.text(LocaleLoader.getString("JSON.JWrapper.Perks.Lucky", "33")));
         }
         }
 
 
     }
     }

+ 4 - 6
src/main/java/com/gmail/nossr50/events/chat/McMMOAdminChatEvent.java

@@ -1,16 +1,14 @@
 package com.gmail.nossr50.events.chat;
 package com.gmail.nossr50.events.chat;
 
 
+import com.gmail.nossr50.chat.message.AbstractChatMessage;
 import org.bukkit.plugin.Plugin;
 import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
 
 
 /**
 /**
  * Called when a chat is sent to the admin chat channel
  * Called when a chat is sent to the admin chat channel
  */
  */
 public class McMMOAdminChatEvent extends McMMOChatEvent {
 public class McMMOAdminChatEvent extends McMMOChatEvent {
-    public McMMOAdminChatEvent(Plugin plugin, String sender, String displayName, String message) {
-        super(plugin, sender, displayName, message);
-    }
-
-    public McMMOAdminChatEvent(Plugin plugin, String sender, String displayName, String message, boolean isAsync) {
-        super(plugin, sender, displayName, message, isAsync);
+    public McMMOAdminChatEvent(@NotNull Plugin plugin, @NotNull AbstractChatMessage chatMessage, boolean isAsync) {
+        super(plugin, chatMessage, isAsync);
     }
     }
 }
 }

+ 104 - 33
src/main/java/com/gmail/nossr50/events/chat/McMMOChatEvent.java

@@ -1,5 +1,11 @@
 package com.gmail.nossr50.events.chat;
 package com.gmail.nossr50.events.chat;
 
 
+import com.gmail.nossr50.chat.author.Author;
+import com.gmail.nossr50.chat.message.AbstractChatMessage;
+import com.gmail.nossr50.chat.message.ChatMessage;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
 import org.bukkit.event.Cancellable;
 import org.bukkit.event.Cancellable;
 import org.bukkit.event.Event;
 import org.bukkit.event.Event;
 import org.bukkit.event.HandlerList;
 import org.bukkit.event.HandlerList;
@@ -8,66 +14,123 @@ import org.jetbrains.annotations.NotNull;
 
 
 public abstract class McMMOChatEvent extends Event implements Cancellable {
 public abstract class McMMOChatEvent extends Event implements Cancellable {
     private boolean cancelled;
     private boolean cancelled;
-    private final Plugin plugin;
-    private final String sender;
-    private String displayName;
-    private String message;
+    protected final @NotNull Plugin plugin;
+    protected final @NotNull AbstractChatMessage chatMessage;
 
 
-    protected McMMOChatEvent(Plugin plugin, String sender, String displayName, String message) {
+    protected McMMOChatEvent(@NotNull Plugin plugin, @NotNull AbstractChatMessage chatMessage, boolean isAsync) {
+        super(isAsync);
         this.plugin = plugin;
         this.plugin = plugin;
-        this.sender = sender;
-        this.displayName = displayName;
-        this.message = message;
+        this.chatMessage = chatMessage;
     }
     }
 
 
-    protected McMMOChatEvent(Plugin plugin, String sender, String displayName, String message, boolean isAsync) {
-        super(isAsync);
-        this.plugin = plugin;
-        this.sender = sender;
-        this.displayName = displayName;
-        this.message = message;
+    /**
+     * The {@link Author} of this message
+     *
+     * @return the {@link Author} of this message
+     */
+    public @NotNull Author getAuthor() {
+        return chatMessage.getAuthor();
     }
     }
 
 
     /**
     /**
-     * @return The plugin responsible for this event, note this can be null
+     * The {@link Audience} for this message
+     *
+     * @return the {@link Audience} for this message
      */
      */
-    public Plugin getPlugin() {
+    public @NotNull Audience getAudience() {
+        return chatMessage.getAudience();
+    }
+
+    /**
+     * Set the {@link Audience} for this message
+     *
+     * @param audience target {@link Audience}
+     */
+    public void setAudience(@NotNull Audience audience) {
+        chatMessage.setAudience(audience);
+    }
+
+    /**
+     * @return The plugin responsible for this event
+     */
+    public @NotNull Plugin getPlugin() {
         return plugin;
         return plugin;
     }
     }
 
 
     /**
     /**
-     * @return String name of the player who sent the chat, or "Console"
+     * The display name of the author
+     *
+     * @return the display name of the author
+     * @deprecated Use {@link #getDisplayName()} instead
      */
      */
-    public String getSender() {
-        return sender;
+    @Deprecated
+    public @NotNull String getSender() {
+        return getAuthor().getAuthoredName();
     }
     }
 
 
     /**
     /**
-     * @return String display name of the player who sent the chat, or "Console"
+     * The name of the author
+     * @return the author's name
      */
      */
-    public String getDisplayName() {
-        return displayName;
+    public @NotNull String getDisplayName() {
+        return getAuthor().getAuthoredName();
     }
     }
 
 
     /**
     /**
-     * @return String message that will be sent
+     * Don't use this method
+     *
+     * @return The raw message
+     * @deprecated use {@link #getComponentMessage()} instead
      */
      */
-    public String getMessage() {
-        return message;
+    @Deprecated
+    public @NotNull String getMessage() {
+        return chatMessage.rawMessage();
     }
     }
 
 
     /**
     /**
-     * @param displayName String display name of the player who sent the chat
+     * The original message typed by the player before any formatting
+     * The raw message is immutable
+     *
+     * @return the message as it was typed by the player, this is before any formatting
      */
      */
-    public void setDisplayName(String displayName) {
-        this.displayName = displayName;
+    public @NotNull String getRawMessage() {
+        return chatMessage.rawMessage();
     }
     }
 
 
     /**
     /**
-     * @param message String message to be sent in chat
+     * The {@link TextComponent} as it will be sent to all players which should include formatting such as adding chat prefixes, player names, etc
+     *
+     * @return the message that will be sent to the {@link Audience}
      */
      */
-    public void setMessage(String message) {
-        this.message = message;
+    public @NotNull TextComponent getComponentMessage() {
+        return chatMessage.getChatMessage();
+    }
+
+    /**
+     * This will be the final message sent to the audience, this should be the message after its been formatted and has had player names added to it etc
+     *
+     * @param chatMessage the new chat message
+     */
+    public void setMessagePayload(@NotNull TextComponent chatMessage) {
+        this.chatMessage.setChatMessage(chatMessage);
+    }
+
+    /**
+     * Does not function anymore
+     */
+    @Deprecated
+    public void setDisplayName(@NotNull String displayName) {
+        return;
+    }
+
+    /**
+     * @param message Adjusts the final message sent to players in the party
+     *
+     * @deprecated use {{@link #setMessagePayload(TextComponent)}}
+     */
+    @Deprecated
+    public void setMessage(@NotNull String message) {
+        chatMessage.setChatMessage(Component.text(message));
     }
     }
 
 
     /** Following are required for Cancellable **/
     /** Following are required for Cancellable **/
@@ -82,14 +145,22 @@ public abstract class McMMOChatEvent extends Event implements Cancellable {
     }
     }
 
 
     /** Rest of file is required boilerplate for custom events **/
     /** Rest of file is required boilerplate for custom events **/
-    private static final HandlerList handlers = new HandlerList();
+    private static final @NotNull HandlerList handlers = new HandlerList();
 
 
     @Override
     @Override
     public @NotNull HandlerList getHandlers() {
     public @NotNull HandlerList getHandlers() {
         return handlers;
         return handlers;
     }
     }
 
 
-    public static HandlerList getHandlerList() {
+    public static @NotNull HandlerList getHandlerList() {
         return handlers;
         return handlers;
     }
     }
+
+    /**
+     * The {@link ChatMessage}
+     * @return the chat message
+     */
+    public @NotNull ChatMessage getChatMessage() {
+        return chatMessage;
+    }
 }
 }

+ 26 - 10
src/main/java/com/gmail/nossr50/events/chat/McMMOPartyChatEvent.java

@@ -1,27 +1,43 @@
 package com.gmail.nossr50.events.chat;
 package com.gmail.nossr50.events.chat;
 
 
+import com.gmail.nossr50.chat.message.PartyChatMessage;
+import com.gmail.nossr50.datatypes.party.Party;
 import org.bukkit.plugin.Plugin;
 import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
 
 
 /**
 /**
  * Called when a chat is sent to a party channel
  * Called when a chat is sent to a party channel
  */
  */
 public class McMMOPartyChatEvent extends McMMOChatEvent {
 public class McMMOPartyChatEvent extends McMMOChatEvent {
-    private final String party;
+    private final @NotNull String party; //Not going to break the API to rename this for now
+    private final @NotNull Party targetParty;
 
 
-    public McMMOPartyChatEvent(Plugin plugin, String sender, String displayName, String party, String message) {
-        super(plugin, sender, displayName, message);
-        this.party = party;
-    }
-
-    public McMMOPartyChatEvent(Plugin plugin, String sender, String displayName, String party, String message, boolean isAsync) {
-        super(plugin, sender, displayName, message, isAsync);
-        this.party = party;
+    public McMMOPartyChatEvent(@NotNull Plugin pluginRef, @NotNull PartyChatMessage chatMessage, @NotNull Party party, boolean isAsync) {
+        super(pluginRef, chatMessage, isAsync);
+        this.party = party.getName();
+        this.targetParty = party;
     }
     }
 
 
     /**
     /**
      * @return String name of the party the message will be sent to
      * @return String name of the party the message will be sent to
+     *
+     * @deprecated this will be removed in the future
      */
      */
-    public String getParty() {
+    @Deprecated
+    public @NotNull String getParty() {
         return party;
         return party;
     }
     }
+
+    public @NotNull PartyChatMessage getPartyChatMessage() {
+        return (PartyChatMessage) chatMessage;
+    }
+
+    /**
+     * The authors party
+     *
+     * @return the party that this message will be delivered to
+     */
+    public @NotNull Party getAuthorParty() {
+        return targetParty;
+    }
 }
 }

+ 6 - 25
src/main/java/com/gmail/nossr50/listeners/PlayerListener.java

@@ -1,13 +1,8 @@
 package com.gmail.nossr50.listeners;
 package com.gmail.nossr50.listeners;
 
 
-import com.gmail.nossr50.chat.ChatManager;
-import com.gmail.nossr50.chat.ChatManagerFactory;
-import com.gmail.nossr50.chat.PartyChatManager;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.WorldBlacklist;
 import com.gmail.nossr50.config.WorldBlacklist;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
-import com.gmail.nossr50.datatypes.chat.ChatMode;
-import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
@@ -896,27 +891,13 @@ public class PlayerListener implements Listener {
             return;
             return;
         }
         }
 
 
-        ChatManager chatManager = null;
-
-        if (mcMMOPlayer.isChatEnabled(ChatMode.PARTY)) {
-            Party party = mcMMOPlayer.getParty();
-
-            if (party == null) {
-                mcMMOPlayer.disableChat(ChatMode.PARTY);
-                player.sendMessage(LocaleLoader.getString("Commands.Party.None"));
-                return;
-            }
-
-            chatManager = ChatManagerFactory.getChatManager(plugin, ChatMode.PARTY);
-            ((PartyChatManager) chatManager).setParty(party);
-        }
-        else if (mcMMOPlayer.isChatEnabled(ChatMode.ADMIN)) {
-            chatManager = ChatManagerFactory.getChatManager(plugin, ChatMode.ADMIN);
-        }
-
-        if (chatManager != null) {
-            chatManager.handleChat(player, event.getMessage(), event.isAsynchronous());
+        //If the message is allowed we cancel this event to avoid double sending messages
+        if(plugin.getChatManager().isMessageAllowed(mcMMOPlayer)) {
+            plugin.getChatManager().processPlayerMessage(mcMMOPlayer, event.getMessage(), event.isAsynchronous());
             event.setCancelled(true);
             event.setCancelled(true);
+        } else {
+            //Message wasn't allowed, remove the player from their channel
+            plugin.getChatManager().setOrToggleChatChannel(mcMMOPlayer, mcMMOPlayer.getChatChannel());
         }
         }
     }
     }
 
 

+ 16 - 0
src/main/java/com/gmail/nossr50/mcMMO.java

@@ -1,5 +1,7 @@
 package com.gmail.nossr50;
 package com.gmail.nossr50;
 
 
+import com.gmail.nossr50.chat.ChatManager;
+import com.gmail.nossr50.commands.CommandManager;
 import com.gmail.nossr50.config.*;
 import com.gmail.nossr50.config.*;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.config.mods.ArmorConfigManager;
 import com.gmail.nossr50.config.mods.ArmorConfigManager;
@@ -82,6 +84,8 @@ public class mcMMO extends JavaPlugin {
     private static PlayerLevelUtils playerLevelUtils;
     private static PlayerLevelUtils playerLevelUtils;
     private static SmeltingTracker smeltingTracker;
     private static SmeltingTracker smeltingTracker;
     private static TransientMetadataTools transientMetadataTools;
     private static TransientMetadataTools transientMetadataTools;
+    private static ChatManager chatManager;
+    private static CommandManager commandManager; //ACF
 
 
     /* Adventure */
     /* Adventure */
     private static BukkitAudiences audiences;
     private static BukkitAudiences audiences;
@@ -280,6 +284,10 @@ public class mcMMO extends JavaPlugin {
         audiences = BukkitAudiences.create(this);
         audiences = BukkitAudiences.create(this);
 
 
         transientMetadataTools = new TransientMetadataTools(this);
         transientMetadataTools = new TransientMetadataTools(this);
+
+        chatManager = new ChatManager(this);
+
+        commandManager = new CommandManager(this);
     }
     }
 
 
     public static PlayerLevelUtils getPlayerLevelUtils() {
     public static PlayerLevelUtils getPlayerLevelUtils() {
@@ -701,4 +709,12 @@ public class mcMMO extends JavaPlugin {
     public static TransientMetadataTools getTransientMetadataTools() {
     public static TransientMetadataTools getTransientMetadataTools() {
         return transientMetadataTools;
         return transientMetadataTools;
     }
     }
+
+    public ChatManager getChatManager() {
+        return chatManager;
+    }
+
+    public CommandManager getCommandManager() {
+        return commandManager;
+    }
 }
 }

+ 2 - 2
src/main/java/com/gmail/nossr50/party/PartyManager.java

@@ -1,7 +1,7 @@
 package com.gmail.nossr50.party;
 package com.gmail.nossr50.party;
 
 
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.datatypes.chat.ChatMode;
+import com.gmail.nossr50.datatypes.chat.ChatChannel;
 import com.gmail.nossr50.datatypes.database.UpgradeType;
 import com.gmail.nossr50.datatypes.database.UpgradeType;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.gmail.nossr50.datatypes.party.ItemShareType;
 import com.gmail.nossr50.datatypes.party.ItemShareType;
@@ -799,7 +799,7 @@ public final class PartyManager {
      */
      */
     public static void processPartyLeaving(McMMOPlayer mcMMOPlayer) {
     public static void processPartyLeaving(McMMOPlayer mcMMOPlayer) {
         mcMMOPlayer.removeParty();
         mcMMOPlayer.removeParty();
-        mcMMOPlayer.disableChat(ChatMode.PARTY);
+        mcMMOPlayer.setChatMode(ChatChannel.NONE);
         mcMMOPlayer.setItemShareModifier(10);
         mcMMOPlayer.setItemShareModifier(10);
     }
     }
 
 

+ 2 - 1
src/main/java/com/gmail/nossr50/util/McMMOMessageType.java

@@ -2,13 +2,14 @@ package com.gmail.nossr50.util;
 
 
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.audience.MessageType;
 import net.kyori.adventure.audience.MessageType;
+import net.kyori.adventure.identity.Identity;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 
 
 import java.util.function.BiConsumer;
 import java.util.function.BiConsumer;
 
 
 public enum McMMOMessageType {
 public enum McMMOMessageType {
     ACTION_BAR(Audience::sendActionBar),
     ACTION_BAR(Audience::sendActionBar),
-    SYSTEM((audience, message) -> audience.sendMessage(message, MessageType.SYSTEM));
+    SYSTEM((audience, message) -> audience.sendMessage(Identity.nil(), message, MessageType.SYSTEM));
 
 
     private final BiConsumer<Audience, Component> sender;
     private final BiConsumer<Audience, Component> sender;
 
 

+ 74 - 73
src/main/java/com/gmail/nossr50/util/TextComponentFactory.java

@@ -13,6 +13,7 @@ import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.audience.MessageType;
 import net.kyori.adventure.audience.MessageType;
+import net.kyori.adventure.identity.Identity;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.ComponentBuilder;
 import net.kyori.adventure.text.ComponentBuilder;
 import net.kyori.adventure.text.TextComponent;
 import net.kyori.adventure.text.TextComponent;
@@ -41,7 +42,7 @@ public class TextComponentFactory {
     public static TextComponent getNotificationMultipleValues(String localeKey, String... values)
     public static TextComponent getNotificationMultipleValues(String localeKey, String... values)
     {
     {
         String preColoredString = LocaleLoader.getString(localeKey, (Object[]) values);
         String preColoredString = LocaleLoader.getString(localeKey, (Object[]) values);
-        return TextComponent.of(preColoredString);
+        return Component.text(preColoredString);
     }
     }
 
 
     public static Component getNotificationTextComponentFromLocale(String localeKey)
     public static Component getNotificationTextComponentFromLocale(String localeKey)
@@ -51,13 +52,13 @@ public class TextComponentFactory {
 
 
     public static Component getNotificationLevelUpTextComponent(PrimarySkillType skill, int levelsGained, int currentLevel)
     public static Component getNotificationLevelUpTextComponent(PrimarySkillType skill, int levelsGained, int currentLevel)
     {
     {
-        return TextComponent.of(LocaleLoader.getString("Overhaul.Levelup", LocaleLoader.getString("Overhaul.Name."+StringUtils.getCapitalized(skill.toString())), levelsGained, currentLevel));
+        return Component.text(LocaleLoader.getString("Overhaul.Levelup", LocaleLoader.getString("Overhaul.Name."+StringUtils.getCapitalized(skill.toString())), levelsGained, currentLevel));
     }
     }
 
 
     private static TextComponent getNotificationTextComponent(String text)
     private static TextComponent getNotificationTextComponent(String text)
     {
     {
         //textComponent.setColor(getNotificationColor(notificationType));
         //textComponent.setColor(getNotificationColor(notificationType));
-        return TextComponent.of(text);
+        return Component.text(text);
     }
     }
 
 
     public static void sendPlayerSubSkillWikiLink(Player player, String subskillformatted)
     public static void sendPlayerSubSkillWikiLink(Player player, String subskillformatted)
@@ -65,29 +66,29 @@ public class TextComponentFactory {
         if(!Config.getInstance().getUrlLinksEnabled())
         if(!Config.getInstance().getUrlLinksEnabled())
             return;
             return;
 
 
-        TextComponent.Builder wikiLinkComponent = TextComponent.builder(LocaleLoader.getString("Overhaul.mcMMO.MmoInfo.Wiki"));
+        TextComponent.Builder wikiLinkComponent = Component.text().content(LocaleLoader.getString("Overhaul.mcMMO.MmoInfo.Wiki"));
         wikiLinkComponent.decoration(TextDecoration.UNDERLINED, true);
         wikiLinkComponent.decoration(TextDecoration.UNDERLINED, true);
 
 
         String wikiUrl = "https://mcmmo.org/wiki/"+subskillformatted;
         String wikiUrl = "https://mcmmo.org/wiki/"+subskillformatted;
 
 
         wikiLinkComponent.clickEvent(ClickEvent.openUrl(wikiUrl));
         wikiLinkComponent.clickEvent(ClickEvent.openUrl(wikiUrl));
 
 
-        TextComponent.Builder componentBuilder = TextComponent.builder(subskillformatted).append("\n").append(wikiUrl).color(NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, true);
+        TextComponent.Builder componentBuilder = Component.text().content(subskillformatted).append(Component.newline()).append(Component.text(wikiUrl)).color(NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, true);
 
 
         wikiLinkComponent.hoverEvent(HoverEvent.showText(componentBuilder.build()));
         wikiLinkComponent.hoverEvent(HoverEvent.showText(componentBuilder.build()));
 
 
-        mcMMO.getAudiences().player(player).sendMessage(wikiLinkComponent, MessageType.SYSTEM);
+        mcMMO.getAudiences().player(player).sendMessage(Identity.nil(), wikiLinkComponent, MessageType.SYSTEM);
     }
     }
 
 
     public static void sendPlayerUrlHeader(Player player) {
     public static void sendPlayerUrlHeader(Player player) {
-        TextComponent prefix = TextComponent.of(LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Prefix") + " ");
+        TextComponent prefix = Component.text(LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Prefix") + " ");
         /*prefix.setColor(ChatColor.DARK_AQUA);*/
         /*prefix.setColor(ChatColor.DARK_AQUA);*/
-        TextComponent suffix = TextComponent.of(" "+LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Suffix"));
+        TextComponent suffix = Component.text(" "+LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Suffix"));
         /*suffix.setColor(ChatColor.DARK_AQUA);*/
         /*suffix.setColor(ChatColor.DARK_AQUA);*/
 
 
-        TextComponent emptySpace = TextComponent.space();
+        TextComponent emptySpace = Component.space();
 
 
-        mcMMO.getAudiences().player(player).sendMessage(TextComponent.ofChildren(
+        mcMMO.getAudiences().player(player).sendMessage(Identity.nil(),TextComponent.ofChildren(
           prefix,
           prefix,
           getWebLinkTextComponent(McMMOWebLinks.WEBSITE),
           getWebLinkTextComponent(McMMOWebLinks.WEBSITE),
           emptySpace,
           emptySpace,
@@ -106,7 +107,7 @@ public class TextComponentFactory {
 
 
     public static void sendPlayerSubSkillList(Player player, List<Component> textComponents)
     public static void sendPlayerSubSkillList(Player player, List<Component> textComponents)
     {
     {
-        TextComponent emptySpace = TextComponent.space();
+        TextComponent emptySpace = Component.space();
 
 
         AtomicReference<Component> messageToSend = new AtomicReference<>();
         AtomicReference<Component> messageToSend = new AtomicReference<>();
         int newLineCount = 0; //Hacky solution to wordwrap problems
         int newLineCount = 0; //Hacky solution to wordwrap problems
@@ -118,7 +119,7 @@ public class TextComponentFactory {
             {
             {
                 Component toSend = messageToSend.get();
                 Component toSend = messageToSend.get();
                 if (toSend != null) {
                 if (toSend != null) {
-                    audience.sendMessage(toSend.append(emptySpace));
+                    audience.sendMessage(Identity.nil(), toSend.append(emptySpace));
                 }
                 }
 
 
                 messageToSend.set(null);
                 messageToSend.set(null);
@@ -127,7 +128,7 @@ public class TextComponentFactory {
             //Style the skills into @links
             //Style the skills into @links
             final String originalTxt = textComponent instanceof TextComponent ? ((TextComponent) textComponent).content() : "";
             final String originalTxt = textComponent instanceof TextComponent ? ((TextComponent) textComponent).content() : "";
 
 
-            TextComponent.Builder stylizedText = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolSkills"));
+            TextComponent.Builder stylizedText = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolSkills"));
             addChild(stylizedText, originalTxt);
             addChild(stylizedText, originalTxt);
 
 
             if(textComponent.hoverEvent() != null)
             if(textComponent.hoverEvent() != null)
@@ -143,7 +144,7 @@ public class TextComponentFactory {
 
 
         Component toSend = messageToSend.get();
         Component toSend = messageToSend.get();
         if (toSend != null) {
         if (toSend != null) {
-            audience.sendMessage(toSend.append(emptySpace));
+            audience.sendMessage(Identity.nil(), toSend.append(emptySpace));
         }
         }
     }
     }
 
 
@@ -154,37 +155,37 @@ public class TextComponentFactory {
         switch(webLinks)
         switch(webLinks)
         {
         {
             case WEBSITE:
             case WEBSITE:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Web");
                 addChild(webTextComponent, "Web");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWebsite));
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWebsite));
                 break;
                 break;
             case SPIGOT:
             case SPIGOT:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Spigot");
                 addChild(webTextComponent, "Spigot");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlSpigot));
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlSpigot));
                 break;
                 break;
             case DISCORD:
             case DISCORD:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Discord");
                 addChild(webTextComponent, "Discord");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlDiscord));
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlDiscord));
                 break;
                 break;
             case PATREON:
             case PATREON:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Patreon");
                 addChild(webTextComponent, "Patreon");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlPatreon));
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlPatreon));
                 break;
                 break;
             case WIKI:
             case WIKI:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Wiki");
                 addChild(webTextComponent, "Wiki");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWiki));
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWiki));
                 break;
                 break;
             case HELP_TRANSLATE:
             case HELP_TRANSLATE:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Lang");
                 addChild(webTextComponent, "Lang");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlTranslate));
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlTranslate));
                 break;
                 break;
             default:
             default:
-                webTextComponent = TextComponent.builder("NOT DEFINED");
+                webTextComponent = Component.text().content("NOT DEFINED");
         }
         }
 
 
         addNewHoverComponentToTextComponent(webTextComponent, getUrlHoverEvent(webLinks));
         addNewHoverComponentToTextComponent(webTextComponent, getUrlHoverEvent(webLinks));
@@ -194,60 +195,60 @@ public class TextComponentFactory {
     }
     }
 
 
     private static void addChild(Component webTextComponent, String childName) {
     private static void addChild(Component webTextComponent, String childName) {
-        TextComponent childComponent = TextComponent.of(childName);
+        TextComponent childComponent = Component.text(childName);
         childComponent.color(NamedTextColor.BLUE);
         childComponent.color(NamedTextColor.BLUE);
         webTextComponent.append(childComponent);
         webTextComponent.append(childComponent);
     }
     }
 
 
     private static void addChild(ComponentBuilder<?, ?> webTextComponent, String childName) {
     private static void addChild(ComponentBuilder<?, ?> webTextComponent, String childName) {
-        TextComponent childComponent = TextComponent.of(childName);
+        TextComponent childComponent = Component.text(childName);
         childComponent.color(NamedTextColor.BLUE);
         childComponent.color(NamedTextColor.BLUE);
         webTextComponent.append(childComponent);
         webTextComponent.append(childComponent);
     }
     }
 
 
     private static Component getUrlHoverEvent(McMMOWebLinks webLinks)
     private static Component getUrlHoverEvent(McMMOWebLinks webLinks)
     {
     {
-        TextComponent.Builder componentBuilder = TextComponent.builder(webLinks.getNiceTitle());
+        TextComponent.Builder componentBuilder = Component.text().content(webLinks.getNiceTitle());
 
 
         switch(webLinks)
         switch(webLinks)
         {
         {
             case WEBSITE:
             case WEBSITE:
                 addUrlHeaderHover(webLinks, componentBuilder);
                 addUrlHeaderHover(webLinks, componentBuilder);
-                componentBuilder.append("\n\n");
-                componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
-                componentBuilder.append(TextComponent.of("\nDev Blogs, and information related to mcMMO can be found here", NamedTextColor.GRAY));
+                componentBuilder.append(Component.newline()).append(Component.newline());
+                componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
+                componentBuilder.append(Component.text("\nDev Blogs, and information related to mcMMO can be found here", NamedTextColor.GRAY));
                 break;
                 break;
             case SPIGOT:
             case SPIGOT:
                 addUrlHeaderHover(webLinks, componentBuilder);
                 addUrlHeaderHover(webLinks, componentBuilder);
-                componentBuilder.append("\n\n");
-                componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
-                componentBuilder.append(TextComponent.of("\nI post regularly in the discussion thread here!", NamedTextColor.GRAY));
+                componentBuilder.append(Component.newline()).append(Component.newline());
+                componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
+                componentBuilder.append(Component.text("\nI post regularly in the discussion thread here!", NamedTextColor.GRAY));
                 break;
                 break;
             case PATREON:
             case PATREON:
                 addUrlHeaderHover(webLinks, componentBuilder);
                 addUrlHeaderHover(webLinks, componentBuilder);
-                componentBuilder.append("\n\n");
-                componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
-                componentBuilder.append("\n");
-                componentBuilder.append(TextComponent.of("Show support by buying me a coffee :)", NamedTextColor.GRAY));
+                componentBuilder.append(Component.newline()).append(Component.newline());
+                componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
+                componentBuilder.append(Component.newline());
+                componentBuilder.append(Component.text("Show support by buying me a coffee :)", NamedTextColor.GRAY));
                 break;
                 break;
             case WIKI:
             case WIKI:
                 addUrlHeaderHover(webLinks, componentBuilder);
                 addUrlHeaderHover(webLinks, componentBuilder);
-                componentBuilder.append("\n\n");
-                componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
-                componentBuilder.append("\n");
-                componentBuilder.append(TextComponent.of("I'm looking for more wiki staff, contact me on our discord!", NamedTextColor.DARK_GRAY));
+                componentBuilder.append(Component.newline()).append(Component.newline());
+                componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
+                componentBuilder.append(Component.newline());
+                componentBuilder.append(Component.text("I'm looking for more wiki staff, contact me on our discord!", NamedTextColor.DARK_GRAY));
                 break;
                 break;
             case DISCORD:
             case DISCORD:
                 addUrlHeaderHover(webLinks, componentBuilder);
                 addUrlHeaderHover(webLinks, componentBuilder);
-                componentBuilder.append("\n\n");
-                componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
+                componentBuilder.append(Component.newline()).append(Component.newline());
+                componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
                 break;
                 break;
             case HELP_TRANSLATE:
             case HELP_TRANSLATE:
                 addUrlHeaderHover(webLinks, componentBuilder);
                 addUrlHeaderHover(webLinks, componentBuilder);
-                componentBuilder.append("\n\n");
-                componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
-                componentBuilder.append("\n");
-                componentBuilder.append(TextComponent.of("You can use this website to help translate mcMMO into your language!" +
+                componentBuilder.append(Component.newline()).append(Component.newline());
+                componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
+                componentBuilder.append(Component.newline());
+                componentBuilder.append(Component.text("You can use this website to help translate mcMMO into your language!" +
                   "\nIf you want to know more contact me in discord.", NamedTextColor.DARK_GRAY));
                   "\nIf you want to know more contact me in discord.", NamedTextColor.DARK_GRAY));
         }
         }
 
 
@@ -255,8 +256,8 @@ public class TextComponentFactory {
     }
     }
 
 
     private static void addUrlHeaderHover(McMMOWebLinks webLinks, TextComponent.Builder componentBuilder) {
     private static void addUrlHeaderHover(McMMOWebLinks webLinks, TextComponent.Builder componentBuilder) {
-        componentBuilder.append("\n");
-        componentBuilder.append(TextComponent.of(webLinks.getUrl(), NamedTextColor.GRAY, TextDecoration.ITALIC));
+        componentBuilder.append(Component.newline());
+        componentBuilder.append(Component.text(webLinks.getUrl(), NamedTextColor.GRAY, TextDecoration.ITALIC));
     }
     }
 
 
     private static ClickEvent getUrlClickEvent(String url)
     private static ClickEvent getUrlClickEvent(String url)
@@ -311,14 +312,14 @@ public class TextComponentFactory {
         TextComponent.Builder textComponent;
         TextComponent.Builder textComponent;
         if (skillUnlocked) {
         if (skillUnlocked) {
             if (RankUtils.getHighestRank(subSkillType) == RankUtils.getRank(player, subSkillType) && subSkillType.getNumRanks() > 1)
             if (RankUtils.getHighestRank(subSkillType) == RankUtils.getRank(player, subSkillType) && subSkillType.getNumRanks() > 1)
-                textComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.MaxRankSkillName", skillName));
+                textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.MaxRankSkillName", skillName));
             else
             else
-                textComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.SkillName", skillName));
+                textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.SkillName", skillName));
 
 
             textComponent.clickEvent(ClickEvent.runCommand("/mmoinfo " + subSkillType.getNiceNameNoSpaces(subSkillType)));
             textComponent.clickEvent(ClickEvent.runCommand("/mmoinfo " + subSkillType.getNiceNameNoSpaces(subSkillType)));
 
 
         } else {
         } else {
-            textComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.Mystery",
+            textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.Mystery",
                     String.valueOf(RankUtils.getUnlockLevel(subSkillType))));
                     String.valueOf(RankUtils.getUnlockLevel(subSkillType))));
 
 
             textComponent.clickEvent(ClickEvent.runCommand("/mmoinfo ???"));
             textComponent.clickEvent(ClickEvent.runCommand("/mmoinfo ???"));
@@ -382,12 +383,12 @@ public class TextComponentFactory {
 
 
             addRanked(ccRank, ccCurRank, ccPossessive, ccCurRank, componentBuilder, abstractSubSkill.getNumRanks(), RankUtils.getRank(player, abstractSubSkill), nextRank);
             addRanked(ccRank, ccCurRank, ccPossessive, ccCurRank, componentBuilder, abstractSubSkill.getNumRanks(), RankUtils.getRank(player, abstractSubSkill), nextRank);
 
 
-            componentBuilder.append(LocaleLoader.getString("JSON.DescriptionHeader"));
-            componentBuilder.append("\n").append(abstractSubSkill.getDescription()).append("\n");
+            componentBuilder.append(Component.text(LocaleLoader.getString("JSON.DescriptionHeader")));
+            componentBuilder.append(Component.newline()).append(Component.text(abstractSubSkill.getDescription())).append(Component.newline());
 
 
             //Empty line
             //Empty line
-            componentBuilder.append("\n").decoration(TextDecoration.BOLD, false);
-            componentBuilder.append("\n");
+            componentBuilder.append(Component.newline()).decoration(TextDecoration.BOLD, false);
+            componentBuilder.append(Component.newline());
 
 
             //Finally, add details to the tooltip
             //Finally, add details to the tooltip
             abstractSubSkill.addStats(componentBuilder, player);
             abstractSubSkill.addStats(componentBuilder, player);
@@ -410,19 +411,19 @@ public class TextComponentFactory {
     }
     }
 
 
     private static TextComponent.Builder getNewComponentBuilder(String skillName) {
     private static TextComponent.Builder getNewComponentBuilder(String skillName) {
-        TextComponent.Builder componentBuilder = TextComponent.builder(skillName);
-        componentBuilder.append("\n");
+        TextComponent.Builder componentBuilder = Component.text().content(skillName);
+        componentBuilder.append(Component.newline());
         return componentBuilder;
         return componentBuilder;
     }
     }
 
 
     private static void addRanked(TextColor ccRank, TextColor ccCurRank, TextColor ccPossessive, TextColor ccNumRanks, TextComponent.Builder componentBuilder, int numRanks, int rank, int nextRank) {
     private static void addRanked(TextColor ccRank, TextColor ccCurRank, TextColor ccPossessive, TextColor ccNumRanks, TextComponent.Builder componentBuilder, int numRanks, int rank, int nextRank) {
         if (numRanks > 0) {
         if (numRanks > 0) {
             //Rank: x
             //Rank: x
-            componentBuilder.append(LocaleLoader.getString("JSON.Hover.Rank", String.valueOf(rank))).append("\n");
+            componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Hover.Rank", String.valueOf(rank)))).append(Component.newline());
 
 
             //Next Rank: x
             //Next Rank: x
             if(nextRank > rank)
             if(nextRank > rank)
-                componentBuilder.append(LocaleLoader.getString("JSON.Hover.NextRank", String.valueOf(nextRank))).append("\n");
+                componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Hover.NextRank", String.valueOf(nextRank)))).append(Component.newline());
 
 
             /*componentBuilder.append(" " + LocaleLoader.getString("JSON.RankPossesive") + " ").color(ccPossessive);
             /*componentBuilder.append(" " + LocaleLoader.getString("JSON.RankPossesive") + " ").color(ccPossessive);
             componentBuilder.append(String.valueOf(numRanks)).color(ccNumRanks);*/
             componentBuilder.append(String.valueOf(numRanks)).color(ccNumRanks);*/
@@ -431,20 +432,20 @@ public class TextComponentFactory {
 
 
     private static void addLocked(SubSkillType subSkillType, TextColor ccLocked, TextColor ccLevelRequirement, TextColor ccLevelRequired, TextComponent.Builder componentBuilder) {
     private static void addLocked(SubSkillType subSkillType, TextColor ccLocked, TextColor ccLevelRequirement, TextColor ccLevelRequired, TextComponent.Builder componentBuilder) {
         addLocked(ccLocked, ccLevelRequirement, componentBuilder);
         addLocked(ccLocked, ccLevelRequirement, componentBuilder);
-        componentBuilder.append(TextComponent.of(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1)), ccLevelRequired));
-        //componentBuilder.append("\n");
+        componentBuilder.append(Component.text(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1)), ccLevelRequired));
+        //componentBuilder.append(Component.newline());
     }
     }
 
 
     private static void addLocked(AbstractSubSkill abstractSubSkill, TextColor ccLocked, TextColor ccLevelRequirement, TextColor ccLevelRequired, TextComponent.Builder componentBuilder) {
     private static void addLocked(AbstractSubSkill abstractSubSkill, TextColor ccLocked, TextColor ccLevelRequirement, TextColor ccLevelRequired, TextComponent.Builder componentBuilder) {
         addLocked(ccLocked, ccLevelRequirement, componentBuilder);
         addLocked(ccLocked, ccLevelRequirement, componentBuilder);
-        componentBuilder.append(TextComponent.of(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1)), ccLevelRequired));
-        //componentBuilder.append("\n");
+        componentBuilder.append(Component.text(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1)), ccLevelRequired));
+        //componentBuilder.append(Component.newline());
     }
     }
 
 
     private static void addLocked(TextColor ccLocked, TextColor ccLevelRequirement, TextComponent.Builder componentBuilder) {
     private static void addLocked(TextColor ccLocked, TextColor ccLevelRequirement, TextComponent.Builder componentBuilder) {
-        componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.Locked"), ccLocked, TextDecoration.BOLD));
-        componentBuilder.append("\n").append("\n");
-        componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.LevelRequirement") + ": ", ccLevelRequirement));
+        componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Locked"), ccLocked, TextDecoration.BOLD));
+        componentBuilder.append(Component.newline()).append(Component.newline());
+        componentBuilder.append(Component.text(LocaleLoader.getString("JSON.LevelRequirement") + ": ", ccLevelRequirement));
     }
     }
 
 
     @Deprecated
     @Deprecated
@@ -490,11 +491,11 @@ public class TextComponentFactory {
 
 
             }
             }
 
 
-            componentBuilder.append("\n");
-            componentBuilder.append(LocaleLoader.getString("JSON.DescriptionHeader"));
+            componentBuilder.append(Component.newline());
+            componentBuilder.append(Component.text(LocaleLoader.getString("JSON.DescriptionHeader")));
             componentBuilder.color(ccDescriptionHeader);
             componentBuilder.color(ccDescriptionHeader);
-            componentBuilder.append("\n");
-            componentBuilder.append(subSkillType.getLocaleDescription());
+            componentBuilder.append(Component.newline());
+            componentBuilder.append(Component.text(subSkillType.getLocaleDescription()));
             componentBuilder.color(ccDescription);
             componentBuilder.color(ccDescription);
         }
         }
 
 
@@ -505,15 +506,15 @@ public class TextComponentFactory {
     {
     {
         if(abstractSubSkill.isSuperAbility())
         if(abstractSubSkill.isSuperAbility())
         {
         {
-            componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.Type.SuperAbility"), NamedTextColor.LIGHT_PURPLE, TextDecoration.BOLD));
+            componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Type.SuperAbility"), NamedTextColor.LIGHT_PURPLE, TextDecoration.BOLD));
         } else if(abstractSubSkill.isActiveUse())
         } else if(abstractSubSkill.isActiveUse())
         {
         {
-            componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.Type.Active"), NamedTextColor.DARK_RED, TextDecoration.BOLD));
+            componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Type.Active"), NamedTextColor.DARK_RED, TextDecoration.BOLD));
         } else {
         } else {
-            componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.Type.Passive"), NamedTextColor.GREEN, TextDecoration.BOLD));
+            componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Type.Passive"), NamedTextColor.GREEN, TextDecoration.BOLD));
         }
         }
 
 
-        componentBuilder.append("\n");
+        componentBuilder.append(Component.newline());
     }
     }
 
 
     public static void getSubSkillTextComponents(Player player, List<Component> textComponents, PrimarySkillType parentSkill) {
     public static void getSubSkillTextComponents(Player player, List<Component> textComponents, PrimarySkillType parentSkill) {
@@ -542,7 +543,7 @@ public class TextComponentFactory {
 
 
     public static TextComponent getSubSkillUnlockedNotificationComponents(Player player, SubSkillType subSkillType)
     public static TextComponent getSubSkillUnlockedNotificationComponents(Player player, SubSkillType subSkillType)
     {
     {
-        TextComponent.Builder unlockMessage = TextComponent.builder(LocaleLoader.getString("JSON.SkillUnlockMessage", subSkillType.getLocaleName(), RankUtils.getRank(player, subSkillType)));
+        TextComponent.Builder unlockMessage = Component.text().content(LocaleLoader.getString("JSON.SkillUnlockMessage", subSkillType.getLocaleName(), RankUtils.getRank(player, subSkillType)));
         unlockMessage.hoverEvent(HoverEvent.showText(getSubSkillHoverComponent(player, subSkillType)));
         unlockMessage.hoverEvent(HoverEvent.showText(getSubSkillHoverComponent(player, subSkillType)));
         unlockMessage.clickEvent(ClickEvent.runCommand("/"+subSkillType.getParentSkill().toString().toLowerCase(Locale.ENGLISH)));
         unlockMessage.clickEvent(ClickEvent.runCommand("/"+subSkillType.getParentSkill().toString().toLowerCase(Locale.ENGLISH)));
         return unlockMessage.build();
         return unlockMessage.build();

+ 0 - 1
src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java

@@ -1,7 +1,6 @@
 package com.gmail.nossr50.util;
 package com.gmail.nossr50.util;
 
 
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataLayer_1_13;
 import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.LivingEntity;
 
 
 public class TransientMetadataTools {
 public class TransientMetadataTools {

+ 21 - 27
src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java

@@ -4,9 +4,7 @@ import com.gmail.nossr50.commands.*;
 import com.gmail.nossr50.commands.admin.CompatibilityCommand;
 import com.gmail.nossr50.commands.admin.CompatibilityCommand;
 import com.gmail.nossr50.commands.admin.McmmoReloadLocaleCommand;
 import com.gmail.nossr50.commands.admin.McmmoReloadLocaleCommand;
 import com.gmail.nossr50.commands.admin.PlayerDebugCommand;
 import com.gmail.nossr50.commands.admin.PlayerDebugCommand;
-import com.gmail.nossr50.commands.chat.AdminChatCommand;
 import com.gmail.nossr50.commands.chat.McChatSpy;
 import com.gmail.nossr50.commands.chat.McChatSpy;
-import com.gmail.nossr50.commands.chat.PartyChatCommand;
 import com.gmail.nossr50.commands.database.McpurgeCommand;
 import com.gmail.nossr50.commands.database.McpurgeCommand;
 import com.gmail.nossr50.commands.database.McremoveCommand;
 import com.gmail.nossr50.commands.database.McremoveCommand;
 import com.gmail.nossr50.commands.database.MmoshowdbCommand;
 import com.gmail.nossr50.commands.database.MmoshowdbCommand;
@@ -313,27 +311,27 @@ public final class CommandRegistrationManager {
         command.setExecutor(new McconvertCommand());
         command.setExecutor(new McconvertCommand());
     }
     }
 
 
-    private static void registerAdminChatCommand() {
-        PluginCommand command = mcMMO.p.getCommand("adminchat");
-        command.setDescription(LocaleLoader.getString("Commands.Description.adminchat"));
-        command.setPermission("mcmmo.chat.adminchat");
-        command.setPermissionMessage(permissionsMessage);
-        command.setUsage(LocaleLoader.getString("Commands.Usage.0", "adminchat"));
-        command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "<on|off>"));
-        command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">"));
-        command.setExecutor(new AdminChatCommand());
-    }
-
-    private static void registerPartyChatCommand() {
-        PluginCommand command = mcMMO.p.getCommand("partychat");
-        command.setDescription(LocaleLoader.getString("Commands.Description.partychat"));
-        command.setPermission("mcmmo.chat.partychat;mcmmo.commands.party");
-        command.setPermissionMessage(permissionsMessage);
-        command.setUsage(LocaleLoader.getString("Commands.Usage.0", "partychat"));
-        command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "<on|off>"));
-        command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">"));
-        command.setExecutor(new PartyChatCommand());
-    }
+//    private static void registerAdminChatCommand() {
+//        PluginCommand command = mcMMO.p.getCommand("adminchat");
+//        command.setDescription(LocaleLoader.getString("Commands.Description.adminchat"));
+//        command.setPermission("mcmmo.chat.adminchat");
+//        command.setPermissionMessage(permissionsMessage);
+//        command.setUsage(LocaleLoader.getString("Commands.Usage.0", "adminchat"));
+//        command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "<on|off>"));
+//        command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">"));
+//        command.setExecutor(new AdminChatCommand());
+//    }
+
+//    private static void registerPartyChatCommand() {
+//        PluginCommand command = mcMMO.p.getCommand("partychat");
+//        command.setDescription(LocaleLoader.getString("Commands.Description.partychat"));
+//        command.setPermission("mcmmo.chat.partychat;mcmmo.commands.party");
+//        command.setPermissionMessage(permissionsMessage);
+//        command.setUsage(LocaleLoader.getString("Commands.Usage.0", "partychat"));
+//        command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "<on|off>"));
+//        command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">"));
+//        command.setExecutor(new PartyChatCommand());
+//    }
 
 
     private static void registerPartyCommand() {
     private static void registerPartyCommand() {
         PluginCommand command = mcMMO.p.getCommand("party");
         PluginCommand command = mcMMO.p.getCommand("party");
@@ -453,10 +451,6 @@ public final class CommandRegistrationManager {
         registerMHDCommand();
         registerMHDCommand();
         registerXprateCommand();
         registerXprateCommand();
 
 
-        // Chat Commands
-        registerPartyChatCommand();
-        registerAdminChatCommand();
-
         // Database Commands
         // Database Commands
         registerMcpurgeCommand();
         registerMcpurgeCommand();
         registerMcremoveCommand();
         registerMcremoveCommand();

+ 2 - 2
src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/AbstractPersistentDataLayer.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.util.compat.layers.persistentdata;
 package com.gmail.nossr50.util.compat.layers.persistentdata;
 
 
-import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.compat.layers.AbstractCompatibilityLayer;
 import com.gmail.nossr50.util.compat.layers.AbstractCompatibilityLayer;
 import org.bukkit.NamespacedKey;
 import org.bukkit.NamespacedKey;
@@ -11,7 +10,8 @@ import org.bukkit.inventory.meta.ItemMeta;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.Nullable;
 
 
-import java.util.*;
+import java.util.List;
+import java.util.UUID;
 
 
 public abstract class AbstractPersistentDataLayer extends AbstractCompatibilityLayer {
 public abstract class AbstractPersistentDataLayer extends AbstractCompatibilityLayer {
 
 

+ 0 - 1
src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/SpigotPersistentDataLayer_1_14.java

@@ -3,7 +3,6 @@ package com.gmail.nossr50.util.compat.layers.persistentdata;
 import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister;
 import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister;
 import com.gmail.nossr50.config.PersistentDataConfig;
 import com.gmail.nossr50.config.PersistentDataConfig;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
-import org.bukkit.Bukkit;
 import org.bukkit.NamespacedKey;
 import org.bukkit.NamespacedKey;
 import org.bukkit.block.Furnace;
 import org.bukkit.block.Furnace;
 import org.bukkit.enchantments.Enchantment;
 import org.bukkit.enchantments.Enchantment;

+ 4 - 3
src/main/java/com/gmail/nossr50/util/player/NotificationManager.java

@@ -17,6 +17,7 @@ import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
 import com.gmail.nossr50.util.sounds.SoundType;
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.audience.MessageType;
 import net.kyori.adventure.audience.MessageType;
+import net.kyori.adventure.identity.Identity;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.Bukkit;
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
 import org.bukkit.ChatColor;
@@ -115,10 +116,10 @@ public class NotificationManager {
             if(customEvent.isMessageAlsoBeingSentToChat())
             if(customEvent.isMessageAlsoBeingSentToChat())
             {
             {
                 //Send copy to chat system
                 //Send copy to chat system
-                audience.sendMessage(customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
+                audience.sendMessage(Identity.nil(), customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
             }
             }
         } else {
         } else {
-            audience.sendMessage(customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
+            audience.sendMessage(Identity.nil(), customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
         }
         }
     }
     }
 
 
@@ -165,7 +166,7 @@ public class NotificationManager {
             return;
             return;
 
 
         //CHAT MESSAGE
         //CHAT MESSAGE
-        mcMMO.getAudiences().player(mcMMOPlayer.getPlayer()).sendMessage(TextComponentFactory.getSubSkillUnlockedNotificationComponents(mcMMOPlayer.getPlayer(), subSkillType));
+        mcMMO.getAudiences().player(mcMMOPlayer.getPlayer()).sendMessage(Identity.nil(), TextComponentFactory.getSubSkillUnlockedNotificationComponents(mcMMOPlayer.getPlayer(), subSkillType));
 
 
         //Unlock Sound Effect
         //Unlock Sound Effect
         SoundManager.sendCategorizedSound(mcMMOPlayer.getPlayer(), mcMMOPlayer.getPlayer().getLocation(), SoundType.SKILL_UNLOCKED, SoundCategory.MASTER);
         SoundManager.sendCategorizedSound(mcMMOPlayer.getPlayer(), mcMMOPlayer.getPlayer().getLocation(), SoundType.SKILL_UNLOCKED, SoundCategory.MASTER);

+ 2 - 2
src/main/resources/locale/locale_en_US.properties

@@ -1119,5 +1119,5 @@ Commands.XPBar.DisableAll=&6 All mcMMO XP bars are now disabled, use /mmoxpbar r
 Chat.Style.Admin=&b[&f{0}&b] {1}
 Chat.Style.Admin=&b[&f{0}&b] {1}
 Chat.Style.Party=&a[&6{0}&a] {1}
 Chat.Style.Party=&a[&6{0}&a] {1}
 Chat.Identity.Console=* Console *
 Chat.Identity.Console=* Console *
-Chat.Channel.On=&6(&amcMMO-Chat&6) &eYour chat messages will now be delivered automatically to the &a{0}&e chat channel.
-Chat.Channel.Off=&6(&amcMMO-Chat&6) &7Your chat messages will no longer automatically be delivered to specific chat channels.
+Chat.Channel.On=&6(&amcMMO-Chat&6) &eYour chat messages will now be automatically delivered to the &a{0}&e chat channel.
+Chat.Channel.Off=&6(&amcMMO-Chat&6) &7Your chat messages will no longer be automatically delivered to specific chat channels.