1
+ package net .matrixcreations .libraries ;
2
+
3
+ import net .kyori .adventure .text .Component ;
4
+ import net .kyori .adventure .text .TextComponent ;
5
+ import net .kyori .adventure .text .format .TextColor ;
6
+ import net .kyori .adventure .text .format .TextDecoration ;
7
+ import net .kyori .adventure .text .serializer .legacy .LegacyComponentSerializer ;
8
+
9
+ import java .util .List ;
10
+ import java .util .regex .Matcher ;
11
+ import java .util .regex .Pattern ;
12
+ import java .util .stream .Collectors ;
13
+
14
+ public class ColorUtils {
15
+
16
+ private static final Pattern HEX_PATTERN = Pattern .compile ("&#([A-Fa-f0-9]{6})" );
17
+ private static final Pattern GRADIENT_PATTERN = Pattern .compile ("<GRADIENT:#([A-Fa-f0-9]{6})>(.*?)</GRADIENT:#([A-Fa-f0-9]{6})>" );
18
+ private static final Pattern SOLID_PATTERN = Pattern .compile ("<SOLID:#([A-Fa-f0-9]{6})>(.*?)(?:</SOLID>|$)" );
19
+ private static final Pattern LEGACY_PATTERN = Pattern .compile ("&([0-9a-fk-or])" );
20
+
21
+ public static String process (String text ) {
22
+ text = processGradients (text );
23
+ text = processSolidColors (text );
24
+ text = processHexColors (text );
25
+ return processLegacyCodes (text );
26
+ }
27
+
28
+ public static List <String > process (List <String > texts ) {
29
+ return texts .stream ().map (ColorUtils ::process ).collect (Collectors .toList ());
30
+ }
31
+
32
+ private static String processGradients (String text ) {
33
+ Matcher matcher = GRADIENT_PATTERN .matcher (text );
34
+ StringBuffer buffer = new StringBuffer ();
35
+
36
+ while (matcher .find ()) {
37
+ String startColor = matcher .group (1 );
38
+ String content = matcher .group (2 );
39
+ String endColor = matcher .group (3 );
40
+
41
+ String gradientText = applyGradient (content , startColor , endColor );
42
+ matcher .appendReplacement (buffer , Matcher .quoteReplacement (gradientText ));
43
+ }
44
+
45
+ matcher .appendTail (buffer );
46
+ return buffer .toString ();
47
+ }
48
+
49
+ private static String processSolidColors (String text ) {
50
+ Matcher matcher = SOLID_PATTERN .matcher (text );
51
+ StringBuffer buffer = new StringBuffer ();
52
+
53
+ while (matcher .find ()) {
54
+ String hexColor = matcher .group (1 );
55
+ String content = matcher .group (2 );
56
+
57
+ String solidColorText = applySolidColor (content , hexColor );
58
+ matcher .appendReplacement (buffer , Matcher .quoteReplacement (solidColorText ));
59
+ }
60
+
61
+ matcher .appendTail (buffer );
62
+ return buffer .toString ();
63
+ }
64
+
65
+ private static String processHexColors (String text ) {
66
+ Matcher matcher = HEX_PATTERN .matcher (text );
67
+ StringBuffer buffer = new StringBuffer ();
68
+
69
+ while (matcher .find ()) {
70
+ String hexColor = matcher .group (1 );
71
+ String replacement = "§x§" + String .join ("§" , hexColor .split ("" ));
72
+ matcher .appendReplacement (buffer , replacement );
73
+ }
74
+
75
+ matcher .appendTail (buffer );
76
+ return buffer .toString ();
77
+ }
78
+
79
+ private static String processLegacyCodes (String text ) {
80
+ return text .replace ('&' , '§' );
81
+ }
82
+
83
+ private static String applyGradient (String text , String startColor , String endColor ) {
84
+ TextColor start = TextColor .fromHexString ("#" + startColor );
85
+ TextColor end = TextColor .fromHexString ("#" + endColor );
86
+
87
+ StringBuilder result = new StringBuilder ();
88
+ boolean isBold = text .contains ("§l" ) || text .contains ("&l" );
89
+ boolean isItalic = text .contains ("§o" ) || text .contains ("&o" );
90
+ boolean isUnderlined = text .contains ("§n" ) || text .contains ("&n" );
91
+ boolean isStrikethrough = text .contains ("§m" ) || text .contains ("&m" );
92
+ boolean isObfuscated = text .contains ("§k" ) || text .contains ("&k" );
93
+
94
+ // Remove formatting markers from the actual text before processing
95
+ text = text .replace ("§l" , "" ).replace ("&l" , "" );
96
+ text = text .replace ("§o" , "" ).replace ("&o" , "" );
97
+ text = text .replace ("§n" , "" ).replace ("&n" , "" );
98
+ text = text .replace ("§m" , "" ).replace ("&m" , "" );
99
+ text = text .replace ("§k" , "" ).replace ("&k" , "" );
100
+
101
+ int length = text .length ();
102
+ for (int i = 0 ; i < length ; i ++) {
103
+ float ratio = (float ) i / length ; // Changed ratio calculation
104
+ TextColor color = interpolateColor (start , end , ratio );
105
+
106
+ TextComponent .Builder component = Component .text ()
107
+ .content (String .valueOf (text .charAt (i )))
108
+ .color (color );
109
+
110
+ if (isBold ) component .decorate (TextDecoration .BOLD );
111
+ if (isItalic ) component .decorate (TextDecoration .ITALIC );
112
+ if (isUnderlined ) component .decorate (TextDecoration .UNDERLINED );
113
+ if (isStrikethrough ) component .decorate (TextDecoration .STRIKETHROUGH );
114
+ if (isObfuscated ) component .decorate (TextDecoration .OBFUSCATED );
115
+
116
+ result .append (LegacyComponentSerializer .legacySection ().serialize (component .build ()));
117
+ }
118
+
119
+ return result .toString ();
120
+ }
121
+
122
+
123
+ private static String applySolidColor (String text , String hexColor ) {
124
+ TextColor color = TextColor .fromHexString ("#" + hexColor );
125
+
126
+ boolean isBold = text .contains ("§l" ) || text .contains ("&l" );
127
+ boolean isItalic = text .contains ("§o" ) || text .contains ("&o" );
128
+ boolean isUnderlined = text .contains ("§n" ) || text .contains ("&n" );
129
+ boolean isStrikethrough = text .contains ("§m" ) || text .contains ("&m" );
130
+ boolean isObfuscated = text .contains ("§k" ) || text .contains ("&k" );
131
+
132
+ text = text .replace ("§l" , "" ).replace ("&l" , "" );
133
+ text = text .replace ("§o" , "" ).replace ("&o" , "" );
134
+ text = text .replace ("§n" , "" ).replace ("&n" , "" );
135
+ text = text .replace ("§m" , "" ).replace ("&m" , "" );
136
+ text = text .replace ("§k" , "" ).replace ("&k" , "" );
137
+
138
+ TextComponent .Builder component = Component .text ()
139
+ .content (text )
140
+ .color (color );
141
+
142
+ if (isBold ) component .decorate (TextDecoration .BOLD );
143
+ if (isItalic ) component .decorate (TextDecoration .ITALIC );
144
+ if (isUnderlined ) component .decorate (TextDecoration .UNDERLINED );
145
+ if (isStrikethrough ) component .decorate (TextDecoration .STRIKETHROUGH );
146
+ if (isObfuscated ) component .decorate (TextDecoration .OBFUSCATED );
147
+
148
+ return LegacyComponentSerializer .legacySection ().serialize (component .build ());
149
+ }
150
+
151
+ private static TextColor interpolateColor (TextColor start , TextColor end , float ratio ) {
152
+ int red = (int ) (start .red () + (end .red () - start .red ()) * ratio );
153
+ int green = (int ) (start .green () + (end .green () - start .green ()) * ratio );
154
+ int blue = (int ) (start .blue () + (end .blue () - start .blue ()) * ratio );
155
+
156
+ return TextColor .color (red , green , blue );
157
+ }
158
+ }
0 commit comments