Skip to content

Instantly share code, notes, and snippets.

@DragonHunt3r
Last active April 22, 2019 11:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DragonHunt3r/f754e8d063ec3af7fb8d047781f3c027 to your computer and use it in GitHub Desktop.
Save DragonHunt3r/f754e8d063ec3af7fb8d047781f3c027 to your computer and use it in GitHub Desktop.
Minecraft ChatColor optimizer
public class ColorOptimizer {
/**
* Matches text until next color code.
* &a&lSome&b&oText -> &a&lSome, &b&oText
*/
private static final Pattern SPLIT_PATTERN = Pattern.compile("(" + ChatColor.COLOR_CHAR + "[0-9A-Fa-fK-Ok-oRr])+(.*?)(?=(?:" + ChatColor.COLOR_CHAR + "[0-9A-Fa-fK-Ok-oRr])|$)");
/**
* Matches any color.
*/
private static final Pattern COLOR = Pattern.compile("(" + ChatColor.COLOR_CHAR + "[0-9A-Fa-f])");
/**
* Matches any modifier.
*/
private static final Pattern MODIFIER = Pattern.compile("(" + ChatColor.COLOR_CHAR + "[K-Ok-oRr])");
/**
* Matches any color or modifier.
*/
private static final Pattern ALL = Pattern.compile("(" + ChatColor.COLOR_CHAR + "[0-9A-Fa-fK-Ok-oRr])");
/**
* &r (reset) color code.
*/
private static final String RESET = color("&r");
/**
* Private constructor to prevent initializing.
* @throws AssertionError when called.
*/
private ColorOptimizer() {
throw new AssertionError();
}
/**
* Optimize the chat colors in the input.
* @param string input.
* @return optimized text.
*/
public static String optimize(String string) {
StringBuilder builder = new StringBuilder();
String currentColor = null;
List<String> currentModifiers = null;
Matcher matcher = SPLIT_PATTERN.matcher(color("&f" + string));
while (matcher.find()) {
// Fixes duplicate color codes.
// &a&l&b&oabc -> &b&oabc
String split = matcher.group().replaceAll("(.*(" + ChatColor.COLOR_CHAR + "[0-9A-Fa-f])+)", "$2");
String color = getColor(split);
List<String> modifiers = getModifiers(split);
String text = getText(split);
// If reset (&r) was used.
if (modifiers != null && modifiers.contains(RESET)) {
String newText = "";
for (String modifier : modifiers) {
newText += modifier;
}
// Color resets because of the reset code (&r).
currentColor = null;
// Modifiers reset because of the reset core (&r).
modifiers.remove(RESET);
currentModifiers = modifiers;
builder.append(newText).append(text);
continue;
}
// If a color was found.
if (color != null) {
// If the color is different.
if (!color.equalsIgnoreCase(currentColor)) {
currentColor = color;
currentModifiers = modifiers;
builder.append(split);
continue;
}
// If the color is the same, remove color from String.
split = split.replace(color, "");
}
if (modifiers == null) {
builder.append(split);
continue;
}
String newText = "";
// Remove all modifiers that already apply from the new modifiers.
if (currentModifiers != null) {
currentModifiers.forEach(modifier -> modifiers.remove(modifier));
currentModifiers.addAll(modifiers);
}
else {
currentModifiers = modifiers;
}
for (String modifier : modifiers) {
newText += modifier;
}
builder.append(newText).append(text);
}
return builder.toString();
}
/**
* Color input text.
* @see ChatColor#translateAlternateColorCodes(char, String)
* @param text input.
* @return colored text.
*/
public static String color(String text) {
return ChatColor.translateAlternateColorCodes('&', text);
}
/**
* Uncolor input text.
* Does the opposite of {@link #color(String)}
* @param text input.
* @return uncolored text.
*/
public static String uncolor(String text) {
char[] array = text.toCharArray();
for (int i = 0; i < array.length - 1; i++) {
if (array[i] == ChatColor.COLOR_CHAR && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(array[i + 1]) != -1) {
array[i] = '&';
array[i + 1] = Character.toLowerCase(array[i + 1]);
}
}
return new String(array);
}
/**
* Get the color of a String.
* &a&labc -> &a
* {@link #COLOR}
* @param string input.
* @return the color of the string or null if no color was found.
*/
private static String getColor(String string) {
Matcher match = COLOR.matcher(string);
return match.find() ? match.group() : null;
}
/**
* Get the modifiers of a String.
* &5&labc -> &l
* &5&l&oabc -> &l, &o
* &5&l&r&o -> &o
* {@link #MODIFIER}
* @param string input.
* @return a list with all modifiers of the string or null if no modifiers were found.
*/
private static List<String> getModifiers(String string) {
List<String> list = new ArrayList<String>();
Matcher match = MODIFIER.matcher(string);
while (match.find()) {
String group = match.group().toLowerCase();
// Reset modifiers at &r (reset)
if (group.equals(RESET)) {
list.clear();
}
if (!list.contains(group)) {
list.add(group);
}
}
return list.isEmpty() ? null : list;
}
/**
* Get the text part of a String.
* &5&labc -> abc
* {@link #ALL}
* @param string input.
* @return the text part of the string.
*/
private static String getText(String string) {
return ALL.matcher(string).replaceAll("");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment