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
+    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) 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
     Added a new config file 'persistent_data.yml'

+ 38 - 16
pom.xml

@@ -63,8 +63,11 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>2.3.2</version>
+                <version>3.8.1</version>
                 <configuration>
+                    <compilerArgs>
+                        <arg>-parameters</arg> <!-- used for ACF syntax stuff -->
+                    </compilerArgs>
                     <source>1.8</source>
                     <target>1.8</target>
                     <excludes>
@@ -91,7 +94,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-shade-plugin</artifactId>
-                <version>3.1.1</version>
+                <version>3.2.3</version>
                 <configuration>
                     <artifactSet>
                         <includes>
@@ -112,28 +115,38 @@
                             <include>net.kyori:adventure-text-serializer-legacy</include>
                             <include>net.kyori:adventure-text-serializer-bungeecord</include>
                             <include>net.kyori:adventure-text-serializer-craftbukkit</include>
+                            <include>co.aikar:acf-bukkit</include>
                         </includes>
                     </artifactSet>
+<!--                    <dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>-->
                     <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>
                             <pattern>org.apache.commons.logging</pattern>
-                            <shadedPattern>com.gmail.nossr50.commons.logging</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.commons.logging</shadedPattern>
                         </relocation>
                         <relocation>
                             <pattern>org.apache.juli</pattern>
-                            <shadedPattern>com.gmail.nossr50.database.tomcat.juli</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.database.tomcat.juli</shadedPattern>
                         </relocation>
                         <relocation>
                             <pattern>org.apache.tomcat</pattern>
-                            <shadedPattern>com.gmail.nossr50.database.tomcat</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.database.tomcat</shadedPattern>
                         </relocation>
                         <relocation>
                             <pattern>net.kyori.adventure</pattern>
-                            <shadedPattern>com.gmail.nossr50.kyori.adventure</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.kyori.adventure</shadedPattern>
                         </relocation>
                         <relocation>
                             <pattern>org.bstats</pattern>
-                            <shadedPattern>com.gmail.nossr50.metrics.bstat</shadedPattern>
+                            <shadedPattern>com.gmail.nossr50.mcmmo.metrics.bstat</shadedPattern>
                         </relocation>
                     </relocations>
                 </configuration>
@@ -168,29 +181,38 @@
             <id>sk89q-repo</id>
             <url>https://maven.sk89q.com/repo/</url>
         </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>
     <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-->
         <dependency>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-text-serializer-gson</artifactId>
-            <version>4.0.0-SNAPSHOT</version>
+            <version>4.1.1</version>
         </dependency>
         <dependency>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-api</artifactId>
-            <version>4.0.0-SNAPSHOT</version>
+            <version>4.1.1</version>
         </dependency>
         <dependency>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-nbt</artifactId>
-            <version>4.0.0-SNAPSHOT</version>
+            <version>4.1.1</version>
         </dependency>
         <dependency>
             <groupId>net.kyori</groupId>

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

@@ -1,72 +1,68 @@
 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 org.bukkit.entity.Player;
-import org.bukkit.plugin.Plugin;
 
 public final class 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.
@@ -75,7 +71,7 @@ public final class ChatAPI {
      * @return true if the player is using party chat, false otherwise
      */
     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
      */
     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
      */
     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
      */
     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.
      */
     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.
      */
     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.
      */
     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.
      */
     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;
 
+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.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.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;
 
-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;
 
-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.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.util.player.UserManager;
-import org.bukkit.command.CommandSender;
 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;
 
-import com.gmail.nossr50.commands.chat.PartyChatCommand;
 import com.gmail.nossr50.commands.party.alliance.PartyAllianceCommand;
 import com.gmail.nossr50.commands.party.teleport.PtpCommand;
 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 partyHelpCommand           = new PartyHelpCommand();
     private final CommandExecutor partyTeleportCommand       = new PtpCommand();
-    private final CommandExecutor partyChatCommand           = new PartyChatCommand();
     private final CommandExecutor partyAllianceCommand       = new PartyAllianceCommand();
 
     @Override
@@ -132,8 +130,6 @@ public class PartyCommand implements TabExecutor {
                 return partyInviteCommand.onCommand(sender, command, label, args);
             case TELEPORT:
                 return partyTeleportCommand.onCommand(sender, command, label, extractArgs(args));
-            case CHAT:
-                return partyChatCommand.onCommand(sender, command, label, extractArgs(args));
             default:
                 break;
         }

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

@@ -157,40 +157,40 @@ public class AprilCommand implements TabExecutor {
 
         switch (fakeSkillType) {
             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;
             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;
             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;
             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;
             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;
             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;
             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;
             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;
             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;
             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;
             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;
             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;
         }
 

+ 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;
 
 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")),
-    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 disabledMessage;
 
-    ChatMode(String enabledMessage, String disabledMessage) {
+    ChatChannel(@Nullable String enabledMessage, @Nullable String disabledMessage) {
         this.enabledMessage  = enabledMessage;
         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;
 
+import com.gmail.nossr50.chat.SamePartyPredicate;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.datatypes.experience.FormulaType;
@@ -16,15 +17,18 @@ import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
 
 import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.UUID;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 public class Party {
+    private final @NotNull Predicate<CommandSender> samePartyPredicate;
 //    private static final String ONLINE_PLAYER_PREFIX = "★";
 //    private static final String ONLINE_PLAYER_PREFIX = "●" + ChatColor.RESET;
     private static final String ONLINE_PLAYER_PREFIX = "⬤";
@@ -53,6 +57,7 @@ public class Party {
 
     public Party(String name) {
         this.name = name;
+        samePartyPredicate = new SamePartyPredicate<>(this);
     }
 
     public Party(PartyLeader leader, String name) {
@@ -60,6 +65,7 @@ public class Party {
         this.name = name;
         this.locked = true;
         this.level = 0;
+        samePartyPredicate = new SamePartyPredicate<>(this);
     }
 
     public Party(PartyLeader leader, String name, String password) {
@@ -68,6 +74,7 @@ public class Party {
         this.password = password;
         this.locked = true;
         this.level = 0;
+        samePartyPredicate = new SamePartyPredicate<>(this);
     }
 
     public Party(PartyLeader leader, String name, String password, boolean locked) {
@@ -76,6 +83,7 @@ public class Party {
         this.password = password;
         this.locked = locked;
         this.level = 0;
+        samePartyPredicate = new SamePartyPredicate<>(this);
     }
 
     public LinkedHashMap<UUID, String> getMembers() {
@@ -550,4 +558,8 @@ public class Party {
 
         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;
 
+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.Config;
 import com.gmail.nossr50.config.WorldBlacklist;
 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.XPGainSource;
 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.sounds.SoundManager;
 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.bukkit.GameMode;
 import org.bukkit.Location;
@@ -57,13 +61,21 @@ import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.metadata.FixedMetadataValue;
 import org.bukkit.plugin.Plugin;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 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 PlayerProfile profile;
 
@@ -77,8 +89,6 @@ public class McMMOPlayer {
 
     private PartyTeleportRecord ptpRecord;
 
-    private boolean partyChatMode;
-    private boolean adminChatMode;
     private boolean displaySkillNotifications = true;
     private boolean debugMode;
 
@@ -86,6 +96,8 @@ public class McMMOPlayer {
     private boolean godMode;
     private boolean chatSpy = false; //Off by default
 
+    private ChatChannel chatChannel;
+
     private final Map<SuperAbilityType, Boolean> abilityMode     = new HashMap<>();
     private final Map<SuperAbilityType, Boolean> abilityInformed = new HashMap<>();
 
@@ -106,6 +118,7 @@ public class McMMOPlayer {
     public McMMOPlayer(Player player, PlayerProfile profile) {
         this.playerName = player.getName();
         UUID uuid = player.getUniqueId();
+        identity = Identity.identity(uuid);
 
         this.player = player;
         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
         attackStrength = 1.0D;
+
+        this.adminAuthor = new AdminAuthor(player);
+        this.partyAuthor = new PartyAuthor(player);
+
+        this.chatChannel = ChatChannel.NONE;
     }
 
     public String getPlayerName() {
@@ -737,70 +755,6 @@ public class McMMOPlayer {
         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() {
         return isUsingUnarmed;
     }
@@ -1080,4 +1034,32 @@ public class McMMOPlayer {
         resetAbilityMode();
         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.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
+import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.TextComponent;
 import org.bukkit.Location;
 import org.bukkit.Material;
@@ -143,21 +144,21 @@ public class Roll extends AcrobaticsSubSkill {
         componentBuilder.append("\n");*/
 
         //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
-        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
 
         //Lucky Notice
         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;
 
+import com.gmail.nossr50.chat.message.AbstractChatMessage;
 import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Called when a chat is sent to the admin chat channel
  */
 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;
 
+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.Event;
 import org.bukkit.event.HandlerList;
@@ -8,66 +14,123 @@ import org.jetbrains.annotations.NotNull;
 
 public abstract class McMMOChatEvent extends Event implements Cancellable {
     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.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 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 **/
@@ -82,14 +145,22 @@ public abstract class McMMOChatEvent extends Event implements Cancellable {
     }
 
     /** 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
     public @NotNull HandlerList getHandlers() {
         return handlers;
     }
 
-    public static HandlerList getHandlerList() {
+    public static @NotNull HandlerList getHandlerList() {
         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;
 
+import com.gmail.nossr50.chat.message.PartyChatMessage;
+import com.gmail.nossr50.datatypes.party.Party;
 import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Called when a chat is sent to a party channel
  */
 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
+     *
+     * @deprecated this will be removed in the future
      */
-    public String getParty() {
+    @Deprecated
+    public @NotNull String getParty() {
         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;
 
-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.WorldBlacklist;
 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.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
@@ -896,27 +891,13 @@ public class PlayerListener implements Listener {
             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);
+        } 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;
 
+import com.gmail.nossr50.chat.ChatManager;
+import com.gmail.nossr50.commands.CommandManager;
 import com.gmail.nossr50.config.*;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.config.mods.ArmorConfigManager;
@@ -82,6 +84,8 @@ public class mcMMO extends JavaPlugin {
     private static PlayerLevelUtils playerLevelUtils;
     private static SmeltingTracker smeltingTracker;
     private static TransientMetadataTools transientMetadataTools;
+    private static ChatManager chatManager;
+    private static CommandManager commandManager; //ACF
 
     /* Adventure */
     private static BukkitAudiences audiences;
@@ -280,6 +284,10 @@ public class mcMMO extends JavaPlugin {
         audiences = BukkitAudiences.create(this);
 
         transientMetadataTools = new TransientMetadataTools(this);
+
+        chatManager = new ChatManager(this);
+
+        commandManager = new CommandManager(this);
     }
 
     public static PlayerLevelUtils getPlayerLevelUtils() {
@@ -701,4 +709,12 @@ public class mcMMO extends JavaPlugin {
     public static TransientMetadataTools getTransientMetadataTools() {
         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;
 
 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.interactions.NotificationType;
 import com.gmail.nossr50.datatypes.party.ItemShareType;
@@ -799,7 +799,7 @@ public final class PartyManager {
      */
     public static void processPartyLeaving(McMMOPlayer mcMMOPlayer) {
         mcMMOPlayer.removeParty();
-        mcMMOPlayer.disableChat(ChatMode.PARTY);
+        mcMMOPlayer.setChatMode(ChatChannel.NONE);
         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.MessageType;
+import net.kyori.adventure.identity.Identity;
 import net.kyori.adventure.text.Component;
 
 import java.util.function.BiConsumer;
 
 public enum McMMOMessageType {
     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;
 

+ 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 net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.audience.MessageType;
+import net.kyori.adventure.identity.Identity;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.ComponentBuilder;
 import net.kyori.adventure.text.TextComponent;
@@ -41,7 +42,7 @@ public class TextComponentFactory {
     public static TextComponent getNotificationMultipleValues(String localeKey, String... values)
     {
         String preColoredString = LocaleLoader.getString(localeKey, (Object[]) values);
-        return TextComponent.of(preColoredString);
+        return Component.text(preColoredString);
     }
 
     public static Component getNotificationTextComponentFromLocale(String localeKey)
@@ -51,13 +52,13 @@ public class TextComponentFactory {
 
     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)
     {
         //textComponent.setColor(getNotificationColor(notificationType));
-        return TextComponent.of(text);
+        return Component.text(text);
     }
 
     public static void sendPlayerSubSkillWikiLink(Player player, String subskillformatted)
@@ -65,29 +66,29 @@ public class TextComponentFactory {
         if(!Config.getInstance().getUrlLinksEnabled())
             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);
 
         String wikiUrl = "https://mcmmo.org/wiki/"+subskillformatted;
 
         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()));
 
-        mcMMO.getAudiences().player(player).sendMessage(wikiLinkComponent, MessageType.SYSTEM);
+        mcMMO.getAudiences().player(player).sendMessage(Identity.nil(), wikiLinkComponent, MessageType.SYSTEM);
     }
 
     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);*/
-        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);*/
 
-        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,
           getWebLinkTextComponent(McMMOWebLinks.WEBSITE),
           emptySpace,
@@ -106,7 +107,7 @@ public class TextComponentFactory {
 
     public static void sendPlayerSubSkillList(Player player, List<Component> textComponents)
     {
-        TextComponent emptySpace = TextComponent.space();
+        TextComponent emptySpace = Component.space();
 
         AtomicReference<Component> messageToSend = new AtomicReference<>();
         int newLineCount = 0; //Hacky solution to wordwrap problems
@@ -118,7 +119,7 @@ public class TextComponentFactory {
             {
                 Component toSend = messageToSend.get();
                 if (toSend != null) {
-                    audience.sendMessage(toSend.append(emptySpace));
+                    audience.sendMessage(Identity.nil(), toSend.append(emptySpace));
                 }
 
                 messageToSend.set(null);
@@ -127,7 +128,7 @@ public class TextComponentFactory {
             //Style the skills into @links
             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);
 
             if(textComponent.hoverEvent() != null)
@@ -143,7 +144,7 @@ public class TextComponentFactory {
 
         Component toSend = messageToSend.get();
         if (toSend != null) {
-            audience.sendMessage(toSend.append(emptySpace));
+            audience.sendMessage(Identity.nil(), toSend.append(emptySpace));
         }
     }
 
@@ -154,37 +155,37 @@ public class TextComponentFactory {
         switch(webLinks)
         {
             case WEBSITE:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Web");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWebsite));
                 break;
             case SPIGOT:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Spigot");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlSpigot));
                 break;
             case DISCORD:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Discord");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlDiscord));
                 break;
             case PATREON:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Patreon");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlPatreon));
                 break;
             case WIKI:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Wiki");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWiki));
                 break;
             case HELP_TRANSLATE:
-                webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
+                webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
                 addChild(webTextComponent, "Lang");
                 webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlTranslate));
                 break;
             default:
-                webTextComponent = TextComponent.builder("NOT DEFINED");
+                webTextComponent = Component.text().content("NOT DEFINED");
         }
 
         addNewHoverComponentToTextComponent(webTextComponent, getUrlHoverEvent(webLinks));
@@ -194,60 +195,60 @@ public class TextComponentFactory {
     }
 
     private static void addChild(Component webTextComponent, String childName) {
-        TextComponent childComponent = TextComponent.of(childName);
+        TextComponent childComponent = Component.text(childName);
         childComponent.color(NamedTextColor.BLUE);
         webTextComponent.append(childComponent);
     }
 
     private static void addChild(ComponentBuilder<?, ?> webTextComponent, String childName) {
-        TextComponent childComponent = TextComponent.of(childName);
+        TextComponent childComponent = Component.text(childName);
         childComponent.color(NamedTextColor.BLUE);
         webTextComponent.append(childComponent);
     }
 
     private static Component getUrlHoverEvent(McMMOWebLinks webLinks)
     {
-        TextComponent.Builder componentBuilder = TextComponent.builder(webLinks.getNiceTitle());
+        TextComponent.Builder componentBuilder = Component.text().content(webLinks.getNiceTitle());
 
         switch(webLinks)
         {
             case WEBSITE:
                 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;
             case SPIGOT:
                 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;
             case PATREON:
                 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;
             case WIKI:
                 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;
             case DISCORD:
                 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;
             case HELP_TRANSLATE:
                 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));
         }
 
@@ -255,8 +256,8 @@ public class TextComponentFactory {
     }
 
     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)
@@ -311,14 +312,14 @@ public class TextComponentFactory {
         TextComponent.Builder textComponent;
         if (skillUnlocked) {
             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
-                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)));
 
         } else {
-            textComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.Mystery",
+            textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.Mystery",
                     String.valueOf(RankUtils.getUnlockLevel(subSkillType))));
 
             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);
 
-            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
-            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
             abstractSubSkill.addStats(componentBuilder, player);
@@ -410,19 +411,19 @@ public class TextComponentFactory {
     }
 
     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;
     }
 
     private static void addRanked(TextColor ccRank, TextColor ccCurRank, TextColor ccPossessive, TextColor ccNumRanks, TextComponent.Builder componentBuilder, int numRanks, int rank, int nextRank) {
         if (numRanks > 0) {
             //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
             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(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) {
         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) {
         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) {
-        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
@@ -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.append("\n");
-            componentBuilder.append(subSkillType.getLocaleDescription());
+            componentBuilder.append(Component.newline());
+            componentBuilder.append(Component.text(subSkillType.getLocaleDescription()));
             componentBuilder.color(ccDescription);
         }
 
@@ -505,15 +506,15 @@ public class TextComponentFactory {
     {
         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())
         {
-            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 {
-            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) {
@@ -542,7 +543,7 @@ public class TextComponentFactory {
 
     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.clickEvent(ClickEvent.runCommand("/"+subSkillType.getParentSkill().toString().toLowerCase(Locale.ENGLISH)));
         return unlockMessage.build();

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

@@ -1,7 +1,6 @@
 package com.gmail.nossr50.util;
 
 import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataLayer_1_13;
 import org.bukkit.entity.LivingEntity;
 
 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.McmmoReloadLocaleCommand;
 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.PartyChatCommand;
 import com.gmail.nossr50.commands.database.McpurgeCommand;
 import com.gmail.nossr50.commands.database.McremoveCommand;
 import com.gmail.nossr50.commands.database.MmoshowdbCommand;
@@ -313,27 +311,27 @@ public final class CommandRegistrationManager {
         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() {
         PluginCommand command = mcMMO.p.getCommand("party");
@@ -453,10 +451,6 @@ public final class CommandRegistrationManager {
         registerMHDCommand();
         registerXprateCommand();
 
-        // Chat Commands
-        registerPartyChatCommand();
-        registerAdminChatCommand();
-
         // Database Commands
         registerMcpurgeCommand();
         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;
 
-import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.compat.layers.AbstractCompatibilityLayer;
 import org.bukkit.NamespacedKey;
@@ -11,7 +10,8 @@ import org.bukkit.inventory.meta.ItemMeta;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.*;
+import java.util.List;
+import java.util.UUID;
 
 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.config.PersistentDataConfig;
 import com.gmail.nossr50.mcMMO;
-import org.bukkit.Bukkit;
 import org.bukkit.NamespacedKey;
 import org.bukkit.block.Furnace;
 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 net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.audience.MessageType;
+import net.kyori.adventure.identity.Identity;
 import net.kyori.adventure.text.Component;
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
@@ -115,10 +116,10 @@ public class NotificationManager {
             if(customEvent.isMessageAlsoBeingSentToChat())
             {
                 //Send copy to chat system
-                audience.sendMessage(customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
+                audience.sendMessage(Identity.nil(), customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
             }
         } else {
-            audience.sendMessage(customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
+            audience.sendMessage(Identity.nil(), customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
         }
     }
 
@@ -165,7 +166,7 @@ public class NotificationManager {
             return;
 
         //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
         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.Party=&a[&6{0}&a] {1}
 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.