emu.grasscutter.utils.objects.text.Style Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of grasscutter Show documentation
Show all versions of grasscutter Show documentation
A server software reimplementation for an anime game.
package emu.grasscutter.utils.objects.text;
import java.awt.*;
import java.util.*;
import lombok.*;
/* Text style container. */
@Builder
@Data
public final class Style {
private static final Map unity = new HashMap<>();
private static final Map ansi = new HashMap<>();
static {
// Add the Minecraft color codes to the color map.
unity.put('0', "#000000"); // Black
unity.put('1', "#0000AA"); // Dark Blue
unity.put('2', "#00AA00"); // Dark Green
unity.put('3', "#00AAAA"); // Dark Aqua
unity.put('4', "#AA0000"); // Dark Red
unity.put('5', "#AA00AA"); // Dark Purple
unity.put('6', "#FFAA00"); // Gold
unity.put('7', "#AAAAAA"); // Gray
unity.put('8', "#555555"); // Dark Gray
unity.put('9', "#5555FF"); // Blue
unity.put('a', "#55FF55"); // Green
unity.put('b', "#55FFFF"); // Aqua
unity.put('c', "#FF5555"); // Red
unity.put('d', "#FF55FF"); // Light Purple
unity.put('e', "#FFFF55"); // Yellow
unity.put('f', "#FFFFFF"); // White
ansi.put('0', "\u001B[30m"); // Black
ansi.put('1', "\u001B[34m"); // Dark Blue
ansi.put('2', "\u001B[32m"); // Dark Green
ansi.put('3', "\u001B[36m"); // Dark Aqua
ansi.put('4', "\u001B[31m"); // Dark Red
ansi.put('5', "\u001B[35m"); // Dark Purple
ansi.put('6', "\u001B[33m"); // Gold
ansi.put('7', "\u001B[37m"); // Gray
ansi.put('8', "\u001B[90m"); // Dark Gray
ansi.put('9', "\u001B[94m"); // Blue
ansi.put('a', "\u001B[92m"); // Green
ansi.put('b', "\u001B[96m"); // Aqua
ansi.put('c', "\u001B[91m"); // Red
ansi.put('d', "\u001B[95m"); // Light Purple
ansi.put('e', "\u001B[93m"); // Yellow
ansi.put('f', "\u001B[97m"); // White
}
@Builder.Default private int size = -1; // Unity only.
@Builder.Default private boolean bold = false; // Unity only.
@Builder.Default private boolean italic = false; // Unity only.
@Builder.Default private Color color = null;
/**
* Replaces detected sequences of &color with the specified text.
*
* @param input The input text.
* @return The replaced text.
*/
private String replaceUnity(String input) {
// Thanks ChatGPT! (from ChatGPT)
// Check if the input string is null or empty
if (input == null || input.isEmpty()) {
return "";
}
var output = new StringBuilder();
var i = 0;
while (i < input.length()) {
var c = input.charAt(i);
if (c == '&') {
// Check if the Minecraft color code is valid
if (i + 1 < input.length() && unity.containsKey(input.charAt(i + 1))) {
// Append the Unity color code
output.append("");
// Move the index past the Minecraft color code
i += 2;
// Find the end of the color code span
var end = input.indexOf('&', i);
if (end == -1) {
end = input.length();
}
// Append the text within the color code span
output.append(input, i, end);
// Append the closing tag for the Unity color code
output.append(" ");
// Move the index to the end of the color code span
i = end;
} else {
// Invalid Minecraft color code, treat it as regular text
output.append(c);
i++;
}
} else {
// Append regular text
output.append(c);
i++;
}
}
return output.toString();
}
/**
* Replaces detected sequences of &color with the specified text.
*
* @param input The input text.
* @return The replaced text.
*/
private String replaceTerminal(String input) {
// Check if the input string is null or empty
if (input == null || input.isEmpty()) {
return "";
}
var output = new StringBuilder();
var i = 0;
while (i < input.length()) {
var c = input.charAt(i);
if (c == '&') {
// Check if the Minecraft color code is valid
if (i + 1 < input.length() && ansi.containsKey(input.charAt(i + 1))) {
// Append the ANSI escape code
output.append(ansi.get(input.charAt(i + 1)));
// Move the index past the Minecraft color code
i += 2;
// Find the end of the color code span
var end = input.indexOf('&', i);
if (end == -1) {
end = input.length();
}
// Append the text within the color code span
output.append(input, i, end);
// Reset the color back to default
output.append("\u001B[0m");
// Move the index to the end of the color code span
i = end;
} else {
// Invalid Minecraft color code, treat it as regular text
output.append(c);
i++;
}
} else {
// Append regular text
output.append(c);
i++;
}
}
return output.toString();
}
/**
* Wraps the text in the style. Formatted for Unity clients.
*
* @param text The text to wrap.
* @return The wrapped text.
*/
public String toUnity(String text) {
var builder = new StringBuilder();
// Set the size.
if (this.size != -1) {
builder.append("");
}
// Set the color.
if (this.color != null) {
builder
.append("");
}
// Set the boldness.
if (this.bold) builder.append("");
// Set the italicness.
if (this.italic) builder.append("");
// Append the text.
builder.append(this.replaceUnity(text));
// Close the tags.
if (this.italic) builder.append("");
if (this.bold) builder.append("");
if (this.color != null) builder.append(" ");
if (this.size != -1) builder.append(" ");
return builder.toString();
}
/**
* Wraps the text in the style. Formatted for terminal clients.
*
* @param text The text to wrap.
* @return The wrapped text.
*/
public String toTerminal(String text) {
// Check for color.
if (this.color == null) return this.replaceTerminal(text);
// Convert the color to an ANSI color.
var ansiColor =
this.color.getRed() > 127
? this.color.getGreen() > 127
? this.color.getBlue() > 127 ? 15 : 11
: this.color.getBlue() > 127 ? 13 : 9
: this.color.getGreen() > 127
? this.color.getBlue() > 127 ? 14 : 10
: this.color.getBlue() > 127 ? 12 : 8;
// Return the text with the ANSI color.
// Reset the color at the end.
return "\u001B[38;5;" + ansiColor + "m" + this.replaceTerminal(text) + "\u001B[0m";
}
}