All source projects

MrUltimateLibrary Source

Standalone source project / 68 files

MrUltimateLibrary is the backbone of all my plugins; it offers features that facilitate plugin creation, maintenance, and updates.

java

MrUltimateLibrary/src/main/java/eu/mrneznamy/mrultimatelibrary/utils/MrLibColors.java

JAVA · Read-only source

package eu.mrneznamy.mrultimatelibrary.utils;

import java.awt.Color;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

public class MrLibColors {
    
    private static final List<String> legacyColors = Arrays.asList("&0", "&1", "&2", "&3", "&4", "&5", "&6", "&7", "&8", "&9", "&a", "&b", "&c", "&d", "&e", "&f", "§0", "§1", "§2", "§3", "§4", "§5", "§6", "§7", "§8", "§9", "§a", "§b", "§c", "§d", "§e", "§f");
    private static final List<String> specialChars = Arrays.asList("&l", "&n", "&o", "&k", "&m", "&r", "§l", "§n", "§o", "§k", "§m", "§r");
    
    private static final Pattern patternNormal = Pattern.compile("\\{#([0-9A-Fa-f]{6})\\}");
    private static final Pattern patternGrad = Pattern.compile("\\{#([0-9A-Fa-f]{6})>\\}(.*?)\\{#([0-9A-Fa-f]{6})<\\}");
    private static final Pattern patternGradReverse = Pattern.compile("\\{#([0-9A-Fa-f]{6})<\\}(.*?)\\{#([0-9A-Fa-f]{6})>\\}");
    private static final Pattern patternOneFromTwo = Pattern.compile("\\{#([0-9A-Fa-f]{6})<>\\}");
    
    
    private static final Pattern patternAngleBrackets = Pattern.compile("<#([0-9A-Fa-f]{6})>");
    private static final Pattern patternHashOnly = Pattern.compile("(?<!\\{)(?<!<)#([0-9A-Fa-f]{6})(?!\\})(?!>)");
    private static final Pattern patternHtmlStyle = Pattern.compile("<#([0-9A-Fa-f]{6})>(.*?)</#([0-9A-Fa-f]{6})>");
    
    private static boolean placeholderAPIAvailable = false;
    private static boolean miniMessageAvailable = false;

    
    
    private static final Pattern MINI_MESSAGE_TAG = Pattern.compile(
        "<(?:red|blue|green|yellow|gold|aqua|dark_[a-z_]+|light_purple|white|black|gray|grey|" +
        "bold|italic|underlined|strikethrough|obfuscated|reset|gradient(?::[^>]+)?|rainbow(?::[^>]+)?|" +
        "color:#[0-9A-Fa-f]{6}|#[0-9A-Fa-f]{6}|hover:[^>]+|click:[^>]+|font:[^>]+|lang:[^>]+|" +
        "key:[^>]+|transition(?::[^>]+)?|newline|br|/[a-z_]+)>"
    );

    static {
        try {
            Class.forName("me.clip.placeholderapi.PlaceholderAPI");
            placeholderAPIAvailable = true;
        } catch (ClassNotFoundException e) {
            placeholderAPIAvailable = false;
        }
        try {
            Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
            miniMessageAvailable = true;
        } catch (ClassNotFoundException e) {
            miniMessageAvailable = false;
        }
    }

    /**
     * Checks if the string contains MiniMessage tags and routes it through
     * MiniMessage -> LegacySerializer, then returns the §-colored result.
     * Falls back gracefully if Adventure is not present on the classpath.
     */
    private static String processMiniMessage(String input) {
        if (!miniMessageAvailable) return input;
        try {
            net.kyori.adventure.text.minimessage.MiniMessage mm =
                net.kyori.adventure.text.minimessage.MiniMessage.miniMessage();
            net.kyori.adventure.text.Component component = mm.deserialize(input);
            return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
                .legacySection().serialize(component);
        } catch (Exception e) {
            return input;
        }
    }

    /** Returns true if the string contains recognisable MiniMessage tags. */
    private static boolean hasMiniMessageTags(String input) {
        return miniMessageAvailable && MINI_MESSAGE_TAG.matcher(input).find();
    }

    public static String colorize(String input, Player player) {
        if (input == null) return null;

        if (placeholderAPIAvailable && player != null) {
            input = applyPlaceholders(input, player);
        }

        
        
        if (hasMiniMessageTags(input)) {
            input = processMiniMessage(input);
            
            input = ChatColor.translateAlternateColorCodes('&', input);
            return input;
        }

        input = colorizeGradient(input);
        input = colorizeRGB(input);
        input = colorizeNewFormats(input);
        input = ChatColor.translateAlternateColorCodes('&', input);

        return input;
    }

    public static String colorize(String input) {
        return colorize(input, null);
    }

    /** Convenience: parse a raw MiniMessage string and return §-colored legacy string. */
    public static String fromMiniMessage(String miniMessageInput) {
        if (miniMessageInput == null) return null;
        if (!miniMessageAvailable) {
            
            return ChatColor.translateAlternateColorCodes('&',
                miniMessageInput.replaceAll("<[^>]+>", ""));
        }
        return processMiniMessage(miniMessageInput);
    }

    public static boolean isMiniMessageAvailable() {
        return miniMessageAvailable;
    }

    private static String applyPlaceholders(String input, Player player) {
        try {
            return me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, input);
        } catch (Throwable e) {
            placeholderAPIAvailable = false;
            try {
                eu.mrneznamy.mrultimatelibrary.MrUltimateLibrary.reportError("mrultimatelibrary", e, "PlaceholderAPI error in applyPlaceholders");
            } catch (Throwable ignored) {}
            return input;
        }
    }

    private static String colorizeNewFormats(String input) {
        Matcher htmlMatcher = patternHtmlStyle.matcher(input);
        while (htmlMatcher.find()) {
            String startColor = htmlMatcher.group(1);
            String text = htmlMatcher.group(2);
            String endColor = htmlMatcher.group(3);
            
            if (startColor.equals(endColor)) {
                String colored = ChatColor.of("#" + startColor) + text;
                input = input.replace(htmlMatcher.group(), colored);
            } else {
                String gradient = color(text, new Color(Integer.parseInt(startColor, 16)), new Color(Integer.parseInt(endColor, 16)));
                input = input.replace(htmlMatcher.group(), gradient);
            }
        }
        
        Matcher angleMatcher = patternAngleBrackets.matcher(input);
        while (angleMatcher.find()) {
            String color = angleMatcher.group(1);
            input = input.replace(angleMatcher.group(), String.valueOf(getColor(color)));
        }
        
        Matcher hashMatcher = patternHashOnly.matcher(input);
        while (hashMatcher.find()) {
            String color = hashMatcher.group(1);
            input = input.replace("#" + color, String.valueOf(getColor(color)));
        }
        
        return input;
    }

    public static String sbcolorize(String input) {
        return ChatColor.translateAlternateColorCodes('&', input);
    }

    public static String clear(String input) {
        input = removePatterns(input);
        input = removeLegacyColors(input);
        input = removeSpecialChars(input);
        return input;
    }
    
    /**
     * Alias for clear() - strips all color codes
     */
    public static String stripColor(String input) {
        return clear(input);
    }

    public static String removeSpecialChars(String input) {
        for (String chars : specialChars) {
            if (input.contains(chars)) {
                input = input.replaceAll(Pattern.quote(chars), "");
            }
        }
        return input;
    }

    public static String removeLegacyColors(String input) {
        for (String color : legacyColors) {
            if (input.contains(color)) {
                input = input.replaceAll(Pattern.quote(color), "");
            }
        }
        return input;
    }

    public static String removePatterns(String input) {
        input = input.replaceAll("\\{#([0-9A-Fa-f]{6})>\\}", "");
        input = input.replaceAll("\\{#([0-9A-Fa-f]{6})<\\}", "");
        input = input.replaceAll("\\{#([0-9A-Fa-f]{6})\\}", "");
        input = input.replaceAll("<#([0-9A-Fa-f]{6})>", "");
        input = input.replaceAll("</#([0-9A-Fa-f]{6})>", "");
        input = input.replaceAll("#([0-9A-Fa-f]{6})", "");
        return input;
    }

    public static String colorizeClassic(String input) {
        return ChatColor.translateAlternateColorCodes('&', input);
    }

    public static String colorizeGradient(String input) {
        Matcher oneFromTwoMatcher = patternOneFromTwo.matcher(input);
        StringBuffer output = new StringBuffer();
        while (oneFromTwoMatcher.find()) {
            String text = oneFromTwoMatcher.group(1);
            oneFromTwoMatcher.appendReplacement(output, "{#" + text + "<}{#" + text + ">}");
        }
        oneFromTwoMatcher.appendTail(output);
        input = output.toString();
        
        Matcher gradMatcher = patternGrad.matcher(input);
        while (gradMatcher.find()) {
            String text = gradMatcher.group(2);
            Color startColor = new Color(Integer.parseInt(gradMatcher.group(1), 16));
            Color endColor = new Color(Integer.parseInt(gradMatcher.group(3), 16));
            input = input.replace(gradMatcher.group(), color(text, startColor, endColor));
        }
        
        Matcher gradReverseMatcher = patternGradReverse.matcher(input);
        while (gradReverseMatcher.find()) {
            String text = gradReverseMatcher.group(2);
            Color startColor = new Color(Integer.parseInt(gradReverseMatcher.group(1), 16));
            Color endColor = new Color(Integer.parseInt(gradReverseMatcher.group(3), 16));
            input = input.replace(gradReverseMatcher.group(), color(text, startColor, endColor));
        }
        
        return ChatColor.translateAlternateColorCodes('&', input);
    }

    public static String colorizeRGB(String input) {
        Matcher matcher = patternNormal.matcher(input);
        while (matcher.find()) {
            String color = matcher.group(1);
            input = input.replace(matcher.group(), String.valueOf(getColor(color)));
        }
        return input;
    }

    public static String color(String input, Color first, Color second) {
        ChatColor[] colors = createGradient(first, second, removeSpecialChars(input).length());
        return apply(input, colors);
    }

    private static String apply(String input, ChatColor[] colors) {
        StringBuilder specialColors = new StringBuilder();
        StringBuilder stringBuilder = new StringBuilder();
        String[] characters = input.split("");
        int outIndex = 0;
        
        for (int i = 0; i < characters.length; i++) {
            if (!characters[i].equals("&") && !characters[i].equals("§")) {
                if (outIndex < colors.length) {
                    stringBuilder.append(colors[outIndex++]).append(specialColors).append(characters[i]);
                } else {
                    stringBuilder.append(characters[i]);
                }
                continue;
            }
            
            if (i + 1 >= characters.length) {
                if (outIndex < colors.length) {
                    stringBuilder.append(colors[outIndex++]).append(specialColors).append(characters[i]);
                } else {
                    stringBuilder.append(characters[i]);
                }
                continue;
            }
            
            if (characters[i + 1].equals("r")) {
                specialColors.setLength(0);
            } else {
                specialColors.append(characters[i]);
                specialColors.append(characters[i + 1]);
            }
            i++;
        }
        
        return stringBuilder.toString();
    }

    private static ChatColor[] createGradient(Color first, Color second, int amount) {
        if (amount <= 0) amount = 1;
        
        ChatColor[] colors = new ChatColor[amount];
        
        if (amount == 1) {
            colors[0] = ChatColor.of(first);
            return colors;
        }
        
        int amountR = Math.abs(first.getRed() - second.getRed()) / (amount - 1);
        int amountG = Math.abs(first.getGreen() - second.getGreen()) / (amount - 1);
        int amountB = Math.abs(first.getBlue() - second.getBlue()) / (amount - 1);
        
        int[] colorDir = new int[]{
            first.getRed() < second.getRed() ? 1 : -1, 
            first.getGreen() < second.getGreen() ? 1 : -1, 
            first.getBlue() < second.getBlue() ? 1 : -1
        };
        
        for (int i = 0; i < amount; i++) {
            int r = Math.max(0, Math.min(255, first.getRed() + amountR * i * colorDir[0]));
            int g = Math.max(0, Math.min(255, first.getGreen() + amountG * i * colorDir[1]));
            int b = Math.max(0, Math.min(255, first.getBlue() + amountB * i * colorDir[2]));
            
            colors[i] = ChatColor.of(new Color(r, g, b));
        }
        
        return colors;
    }

    public static ChatColor getColor(String hex) {
        return ChatColor.of(new Color(Integer.parseInt(hex, 16)));
    }
    
    public static boolean isPlaceholderAPIAvailable() {
        return placeholderAPIAvailable;
    }
}
333 linesGNU GENERAL PUBLIC LICENSE · Version 3, 29 June 2007 · UTF-8 · Read only