Skip to content

Commit db1354f

Browse files
committed
text chat/render utility
1 parent 320d010 commit db1354f

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package com.falsepattern.lib.text;
2+
3+
import lombok.NonNull;
4+
import lombok.val;
5+
import net.minecraft.client.gui.FontRenderer;
6+
import net.minecraft.util.ChatComponentText;
7+
import net.minecraft.util.ChatStyle;
8+
import net.minecraft.util.EnumChatFormatting;
9+
10+
import java.awt.Color;
11+
import java.lang.reflect.Field;
12+
import java.util.*;
13+
14+
/**
15+
* Universal escape sequence-based text rendering and chat messages.
16+
*/
17+
public final class FormattedText {
18+
private static final Map<Character, EnumChatFormatting> reverseMap = new HashMap<>();
19+
private static final Map<EnumChatFormatting, Color> colorMap = new HashMap<>();
20+
21+
private static final char ESCAPE = '\u00a7';
22+
static {
23+
for (val value: EnumChatFormatting.values()) {
24+
reverseMap.put(value.getFormattingCode(), value);
25+
if (value.isColor()) {
26+
final int rgb;
27+
switch (value.getFormattingCode()) {
28+
default: rgb = 0x000000; break;
29+
case '1': rgb = 0x0000AA; break;
30+
case '2': rgb = 0x00AA00; break;
31+
case '3': rgb = 0x00AAAA; break;
32+
case '4': rgb = 0xAA0000; break;
33+
case '5': rgb = 0xAA00AA; break;
34+
case '6': rgb = 0xFFAA00; break;
35+
case '7': rgb = 0xAAAAAA; break;
36+
case '8': rgb = 0x555555; break;
37+
case '9': rgb = 0x5555FF; break;
38+
case 'a': rgb = 0x55FF55; break;
39+
case 'b': rgb = 0x55FFFF; break;
40+
case 'c': rgb = 0xFF5555; break;
41+
case 'd': rgb = 0xFF55FF; break;
42+
case 'e': rgb = 0xFFFF55; break;
43+
case 'f': rgb = 0xFFFFFF; break;
44+
}
45+
colorMap.put(value, new Color(rgb));
46+
}
47+
try {
48+
Field colorF = Color.class.getDeclaredField(value.getFriendlyName());
49+
colorMap.put(value, (Color)colorF.get(null));
50+
} catch (NoSuchFieldException | IllegalAccessException ignored) {}
51+
}
52+
}
53+
54+
private final String text;
55+
56+
private final EnumChatFormatting colorStyle;
57+
private final Set<EnumChatFormatting> fancyStyles = new HashSet<>();
58+
59+
private final List<FormattedText> siblings = new ArrayList<>();
60+
61+
private final boolean endLine;
62+
63+
private FormattedText(@NonNull String text, @NonNull EnumChatFormatting colorStyle, @NonNull Set<EnumChatFormatting> fancyStyles, boolean endLine) {
64+
this.text = text;
65+
this.fancyStyles.addAll(fancyStyles);
66+
this.colorStyle = colorStyle;
67+
this.endLine = endLine;
68+
}
69+
70+
public static FormattedText parse(String text) {
71+
EnumChatFormatting currentColorStyle = EnumChatFormatting.WHITE;
72+
val currentFancyStyle = new HashSet<EnumChatFormatting>();
73+
FormattedText result = null;
74+
val accumulator = new StringBuilder();
75+
int length = text.length();
76+
boolean format = false;
77+
for (int i = 0; i < length; i++) {
78+
char c = text.charAt(i);
79+
if (format) {
80+
val f = reverseMap.get(c);
81+
if (f == null)
82+
continue;
83+
if (f == EnumChatFormatting.RESET) {
84+
currentColorStyle = EnumChatFormatting.WHITE;
85+
currentFancyStyle.clear();
86+
} else if (f.isColor()) {
87+
currentColorStyle = f;
88+
} else if (f.isFancyStyling()) {
89+
currentFancyStyle.add(f);
90+
}
91+
format = false;
92+
continue;
93+
}
94+
if (c == ESCAPE || c == '\n') {
95+
format = c == ESCAPE;
96+
val txt = new FormattedText(accumulator.toString(), currentColorStyle, currentFancyStyle, c == '\n');
97+
if (result == null)
98+
result = txt;
99+
else
100+
result.siblings.add(txt);
101+
accumulator.setLength(0);
102+
continue;
103+
}
104+
accumulator.append(c);
105+
}
106+
if (accumulator.length() > 0) {
107+
val txt = new FormattedText(accumulator.toString(), currentColorStyle, currentFancyStyle, true);
108+
if (result == null)
109+
result = txt;
110+
else
111+
result.siblings.add(txt);
112+
}
113+
return result;
114+
}
115+
116+
public ChatComponentText toChatText() {
117+
val result = new ChatComponentText(endLine ? text + "\n" : "");
118+
val style = new ChatStyle();
119+
if (colorStyle != null) {
120+
style.setColor(colorStyle);
121+
}
122+
for (val fancyStyle: fancyStyles) {
123+
switch (fancyStyle) {
124+
case OBFUSCATED:
125+
style.setObfuscated(true);
126+
break;
127+
case BOLD:
128+
style.setBold(true);
129+
break;
130+
case STRIKETHROUGH:
131+
style.setStrikethrough(true);
132+
break;
133+
case UNDERLINE:
134+
style.setUnderlined(true);
135+
break;
136+
case ITALIC:
137+
style.setItalic(true);
138+
break;
139+
}
140+
}
141+
result.setChatStyle(style);
142+
for (val sibling: siblings) {
143+
result.appendSibling(sibling.toChatText());
144+
}
145+
return result;
146+
}
147+
148+
public void draw(FontRenderer renderer, int x, int y) {
149+
draw(renderer, x, y, false);
150+
}
151+
152+
public void drawWithShadow(FontRenderer renderer, int x, int y) {
153+
draw(renderer, x, y, true);
154+
}
155+
156+
public void draw(FontRenderer renderer, int x, int y, boolean shadow) {
157+
x += renderer.drawString(text, x, y, colorMap.get(colorStyle).getRGB(), shadow);
158+
if (endLine)
159+
y += renderer.FONT_HEIGHT;
160+
for (val sibling: siblings) {
161+
x += renderer.drawString(sibling.text, x, y, colorMap.get(sibling.colorStyle).getRGB(), shadow);
162+
}
163+
}
164+
}

0 commit comments

Comments
 (0)