javaminecraftbukkitcustom-formatting

Bukkit/Spigot HeroChat 5: Custom Replacement in format string


This has been something that has eluded me for some time...

HeroChat, in its config.yml file, has a section called format:, under which you'll find a default format string. This is echoed in the config for each channel. This is an example of what mine looks like...

format:
  default: '{color}[{nick}]{title} {groupprefix}&f{sender}: {color}{msg}'

{color} represents the color defined in that channel's config
{nick} represents the channel's "nickname"
{title} is a custom formatting string
{groupprefix} is the prefix assigned to the player's Vault group.
{sender} is the display name (or nickname) of the player sending the message. {msg} is the message they typed into the console, after going through the built-in censorship.

So, how do you get {title} or whatever your custom string is to change? As I said above, this is something that I could not figure out for a long time. But, doing some research, I've figured it out and it's actually not that difficult. I'm leaving this here as a resource for Java developers running into the same issue.


Solution

  • I'll leave a step-by-step solution below. This tutorial assumes you are familiar with your chosen IDE and have a way to retrieve a player-specific or group-specific replacement string...

    1. Load HeroChat.jar into your environment.
    2. Create and register a new PlayerListener.
    3. Add the following imports:
      • import org.bukkit.entity.Player;
      • import org.bukkit.event.EventHandler;
      • import org.bukkit.event.Listener;
      • import org.bukkit.event.player.PlayerJoinEvent;
      • import com.dthielke.herochat.ChannelChatEvent;
      • import com.dthielke.herochat.ChannelManager;
      • import com.dthielke.herochat.Herochat;
    4. Add the following event:
    @EventHandler
    public void onPlayerChat(ChannelChatEvent event) {
        ChannelManager cm = Herochat.getChannelManager();
        String newFormat;
        Player player = event.getSender().getPlayer();
        String chatReplacement = plugin.classWithReplacer.replacer(player);
    
        // Simple replacement here. If it is equal to "", let it replace as
        // normal. If it actually has a value, surround it with brackets.
        if (!chatTitle.equalsIgnoreCase("")) {
            chatTitle = "[" + chatTitle + "]";
        }
    
        // When the channel being spoken in uses the default format,
        // asking it for the format returns "{format}"
        //
        // We do not need to escape the brackets because
        // String.equalsIgnoreCase does not use regex.
        if (event.getFormat().equalsIgnoreCase("{default}")) {
            // cm.getStandardFormat() returns the format provided in config.yml
            newFormat = cm.getStandardFormat();
    
            // IMPORTANT!! You MUST escape the curly brackets or your plugin WILL throw regex errors!
            // We escape with two backslashes because the java parser takes one away, resulting in \{ and \} respectively.
            // Then, the regex parser comes in and converts \{ into a safe {, and \} into a safe }
            // "your_replacement_here" should be whatever your custom tag is within the config.yml or the channel's config file.
            // In my case, this was {title}.
            // Note: the square brackets can be added to your config file, but I chose to add them here to avoid empty brackets
            // when the player did not have a title.
            newFormat = newFormat.replaceAll("\\{your_replacement_here\\}", chatReplacement);
        } else {
            // event.getFormat() returns the current channel's format or "{default}"
            newFormat = event.getFormat();
            newFormat = newFormat.replaceAll("\\{your_replacement_here\\}", chatReplacement);
        }
    
        // This method performs a "one-time" change to the default format.
        // Because you are providing the same format as the original, only
        // contextually modified for the player or player's group, the chat
        // output will still be determined by the global or channel config
        event.setFormat(newFormat);
    }
    

    And here's the complete (though uncommented) version

    package your.package.here;
    
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.PlayerJoinEvent;
    
    import com.dthielke.herochat.ChannelChatEvent;
    import com.dthielke.herochat.ChannelManager;
    import com.dthielke.herochat.Herochat;
    import your.package.here.MyPlugin;
    
    public class MyPluginPlayerListener implements Listener {
    
        private MyPlugin plugin;
    
        public MyPluginPlayerListener(MyPlugin plugin) {
            this.plugin = plugin;
        }
    
        @EventHandler
        public void onPlayerChat(ChannelChatEvent event) {
            ChannelManager cm = Herochat.getChannelManager();
            String newFormat;
            Player player = event.getSender().getPlayer();
            String chatTitle = plugin.titlesConfig.getTitle(player);
    
            if (!chatTitle.equalsIgnoreCase("")) {
                chatTitle = "[" + chatTitle + "]";
            }
            if (event.getFormat().equalsIgnoreCase("{default}")) {
                newFormat = cm.getStandardFormat();
                newFormat = newFormat.replaceAll("\\{title\\}", chatTitle");
            } else {
                newFormat = event.getFormat();
                newFormat = newFormat.replaceAll("\\{title\\", chatTitle");
            }
    
            event.setFormat(newFormat);
        }
    }