Skip to content

Commit b1c7439

Browse files
Backport Chat Box UTF-8 support to 1.20.1 (#820)
1 parent 5159860 commit b1c7439

2 files changed

Lines changed: 197 additions & 25 deletions

File tree

src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java

Lines changed: 168 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -106,24 +106,46 @@ private boolean checkBrackets(Optional<String> brackets) {
106106
return brackets.isPresent() && brackets.get().length() != 2;
107107
}
108108

109+
// 0 message, 1 prefix, 2 brackets, 3 color, 4 range, 5 utf8Support
109110
@LuaFunction(mainThread = true)
110111
public final MethodResult sendFormattedMessage(@NotNull IArguments arguments) throws LuaException {
111112
return withChatOperation(ignored -> {
113+
boolean useUTF8 = arguments.optBoolean(5, false);
114+
112115
String message = arguments.getString(0);
116+
if (useUTF8) {
117+
message = StringUtil.byteStringToUTF8(message);
118+
}
119+
113120
int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get();
114121
int range = arguments.optInt(4, -1);
115122
ResourceKey<Level> dimension = getLevel().dimension();
116123
MutableComponent component = Component.Serializer.fromJson(message);
117124
if (component == null)
118125
return MethodResult.of(null, "incorrect json");
119126

120-
if (checkBrackets(arguments.optString(2)))
127+
Optional<String> brackets = arguments.optString(2);
128+
if (useUTF8) {
129+
brackets = brackets.map(StringUtil::byteStringToUTF8);
130+
}
131+
132+
if (checkBrackets(brackets))
121133
return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)");
122134

135+
Optional<String> prefix = arguments.optString(1);
136+
if (useUTF8) {
137+
prefix = prefix.map(StringUtil::byteStringToUTF8);
138+
}
139+
140+
String bracketColor = arguments.optString(3, "");
141+
if (useUTF8) {
142+
bracketColor = StringUtil.byteStringToUTF8(bracketColor);
143+
}
144+
123145
MutableComponent preparedMessage = appendPrefix(
124-
StringUtil.convertAndToSectionMark(arguments.optString(1, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
125-
arguments.optString(2, "[]"),
126-
StringUtil.convertAndToSectionMark(arguments.optString(3, ""))
146+
StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
147+
brackets.orElse("[]"),
148+
StringUtil.convertAndToSectionMark(bracketColor)
127149
).append(component);
128150
for (ServerPlayer player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers()) {
129151
if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension)
@@ -135,20 +157,43 @@ public final MethodResult sendFormattedMessage(@NotNull IArguments arguments) th
135157
});
136158
}
137159

160+
// 0 message, 1 prefix, 2 brackets, 3 color, 4 range, 5 utf8Support
138161
@LuaFunction(mainThread = true)
139162
public final MethodResult sendMessage(@NotNull IArguments arguments) throws LuaException {
140163
return withChatOperation(ignored -> {
164+
boolean useUTF8 = arguments.optBoolean(5, false);
165+
141166
String message = arguments.getString(0);
167+
if (useUTF8) {
168+
message = StringUtil.byteStringToUTF8(message);
169+
}
170+
142171
int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get();
143172
int range = arguments.optInt(4, -1);
144173
ResourceKey<Level> dimension = getLevel().dimension();
145-
if (checkBrackets(arguments.optString(2)))
174+
175+
Optional<String> brackets = arguments.optString(2);
176+
if (useUTF8) {
177+
brackets = brackets.map(StringUtil::byteStringToUTF8);
178+
}
179+
180+
if (checkBrackets(brackets))
146181
return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)");
147182

183+
Optional<String> prefix = arguments.optString(1);
184+
if (useUTF8) {
185+
prefix = prefix.map(StringUtil::byteStringToUTF8);
186+
}
187+
188+
String bracketColor = arguments.optString(3, "");
189+
if (useUTF8) {
190+
bracketColor = StringUtil.byteStringToUTF8(bracketColor);
191+
}
192+
148193
MutableComponent preparedMessage = appendPrefix(
149-
StringUtil.convertAndToSectionMark(arguments.optString(1, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
150-
arguments.optString(2, "[]"),
151-
StringUtil.convertAndToSectionMark(arguments.optString(3, ""))
194+
StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
195+
brackets.orElse("[]"),
196+
StringUtil.convertAndToSectionMark(bracketColor)
152197
).append(message);
153198
for (ServerPlayer player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers()) {
154199
if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension)
@@ -160,10 +205,17 @@ public final MethodResult sendMessage(@NotNull IArguments arguments) throws LuaE
160205
});
161206
}
162207

208+
// 0 message, 1 playerName, 2 prefix, 3 brackets, 4 color, 5 range, 6 utf8Support
163209
@LuaFunction(mainThread = true)
164210
public final MethodResult sendFormattedMessageToPlayer(@NotNull IArguments arguments) throws LuaException {
165211
return withChatOperation(ignored -> {
212+
boolean useUTF8 = arguments.optBoolean(6, false);
213+
166214
String message = arguments.getString(0);
215+
if (useUTF8) {
216+
message = StringUtil.byteStringToUTF8(message);
217+
}
218+
167219
String playerName = arguments.getString(1);
168220
int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get();
169221
int range = arguments.optInt(5, -1);
@@ -176,13 +228,28 @@ public final MethodResult sendFormattedMessageToPlayer(@NotNull IArguments argum
176228
if (component == null)
177229
return MethodResult.of(null, "incorrect json");
178230

179-
if (checkBrackets(arguments.optString(3)))
231+
Optional<String> brackets = arguments.optString(3);
232+
if (useUTF8) {
233+
brackets = brackets.map(StringUtil::byteStringToUTF8);
234+
}
235+
236+
if (checkBrackets(brackets))
180237
return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)");
181238

239+
Optional<String> prefix = arguments.optString(2);
240+
if (useUTF8) {
241+
prefix = prefix.map(StringUtil::byteStringToUTF8);
242+
}
243+
244+
String bracketColor = arguments.optString(4, "");
245+
if (useUTF8) {
246+
bracketColor = StringUtil.byteStringToUTF8(bracketColor);
247+
}
248+
182249
MutableComponent preparedMessage = appendPrefix(
183-
StringUtil.convertAndToSectionMark(arguments.optString(2, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
184-
arguments.optString(3, "[]"),
185-
StringUtil.convertAndToSectionMark(arguments.optString(4, ""))
250+
StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
251+
brackets.orElse("[]"),
252+
StringUtil.convertAndToSectionMark(bracketColor)
186253
).append(component);
187254
if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension)
188255
return MethodResult.of(false, "NOT_SAME_DIMENSION");
@@ -194,11 +261,22 @@ public final MethodResult sendFormattedMessageToPlayer(@NotNull IArguments argum
194261
}
195262

196263

264+
// 0 message, 1 title, 2 playerName, 3 prefix, 4 brackets, 5 bracket color, 6 range, 7 utf8Support
197265
@LuaFunction(mainThread = true)
198266
public final MethodResult sendFormattedToastToPlayer(@NotNull IArguments arguments) throws LuaException {
199267
return withChatOperation(ignored -> {
268+
boolean useUTF8 = arguments.optBoolean(7, false);
269+
200270
String message = arguments.getString(0);
271+
if (useUTF8) {
272+
message = StringUtil.byteStringToUTF8(message);
273+
}
274+
201275
String title = arguments.getString(1);
276+
if (useUTF8) {
277+
title = StringUtil.byteStringToUTF8(title);
278+
}
279+
202280
String playerName = arguments.getString(2);
203281
int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get();
204282
int range = arguments.optInt(6, -1);
@@ -215,13 +293,28 @@ public final MethodResult sendFormattedToastToPlayer(@NotNull IArguments argumen
215293
if (titleComponent == null)
216294
return MethodResult.of(null, "incorrect json for title");
217295

218-
if (checkBrackets(arguments.optString(4)))
296+
Optional<String> brackets = arguments.optString(4);
297+
if (useUTF8) {
298+
brackets = brackets.map(StringUtil::byteStringToUTF8);
299+
}
300+
301+
if (checkBrackets(brackets))
219302
return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ,,,)");
220303

304+
Optional<String> prefix = arguments.optString(3);
305+
if (useUTF8) {
306+
prefix = prefix.map(StringUtil::byteStringToUTF8);
307+
}
308+
309+
String bracketColor = arguments.optString(5, "");
310+
if (useUTF8) {
311+
bracketColor = StringUtil.byteStringToUTF8(bracketColor);
312+
}
313+
221314
MutableComponent preparedMessage = appendPrefix(
222-
StringUtil.convertAndToSectionMark(arguments.optString(3, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
223-
arguments.optString(4, "[]"),
224-
StringUtil.convertAndToSectionMark(arguments.optString(5, ""))
315+
StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
316+
brackets.orElse("[]"),
317+
StringUtil.convertAndToSectionMark(bracketColor)
225318
).append(messageComponent);
226319

227320
if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension)
@@ -236,10 +329,17 @@ public final MethodResult sendFormattedToastToPlayer(@NotNull IArguments argumen
236329
});
237330
}
238331

332+
// 0 message, 1 playerName, 2 prefix, 3 brackets, 4 bracket color, 5 range, 6 utf8Support
239333
@LuaFunction(mainThread = true)
240334
public final MethodResult sendMessageToPlayer(@NotNull IArguments arguments) throws LuaException {
241335
return withChatOperation(ignored -> {
336+
boolean useUTF8 = arguments.optBoolean(6, false);
337+
242338
String message = arguments.getString(0);
339+
if (useUTF8) {
340+
message = StringUtil.byteStringToUTF8(message);
341+
}
342+
243343
String playerName = arguments.getString(1);
244344
int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get();
245345
int range = arguments.optInt(5, -1);
@@ -248,13 +348,28 @@ public final MethodResult sendMessageToPlayer(@NotNull IArguments arguments) thr
248348
if (player == null)
249349
return MethodResult.of(null, "incorrect player name/uuid");
250350

251-
if (checkBrackets(arguments.optString(3)))
351+
Optional<String> brackets = arguments.optString(3);
352+
if (useUTF8) {
353+
brackets = brackets.map(StringUtil::byteStringToUTF8);
354+
}
355+
356+
if (checkBrackets(brackets))
252357
return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)");
253358

359+
Optional<String> prefix = arguments.optString(2);
360+
if (useUTF8) {
361+
prefix = prefix.map(StringUtil::byteStringToUTF8);
362+
}
363+
364+
String bracketColor = arguments.optString(4, "");
365+
if (useUTF8) {
366+
bracketColor = StringUtil.byteStringToUTF8(bracketColor);
367+
}
368+
254369
MutableComponent preparedMessage = appendPrefix(
255-
StringUtil.convertAndToSectionMark(arguments.optString(2, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
256-
arguments.optString(3, "[]"),
257-
StringUtil.convertAndToSectionMark(arguments.optString(4, ""))
370+
StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
371+
brackets.orElse("[]"),
372+
StringUtil.convertAndToSectionMark(bracketColor)
258373
).append(message);
259374
if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension)
260375
return MethodResult.of(false, "NOT_SAME_DIMENSION");
@@ -265,11 +380,22 @@ public final MethodResult sendMessageToPlayer(@NotNull IArguments arguments) thr
265380
});
266381
}
267382

383+
// 0 message, 1 title, 2 playerName, 3 prefix, 4 brackets, 5 bracket color, 6 range, 7 utf8Support
268384
@LuaFunction(mainThread = true)
269385
public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throws LuaException {
270386
return withChatOperation(ignored -> {
387+
boolean useUTF8 = arguments.optBoolean(7, false);
388+
271389
String message = arguments.getString(0);
390+
if (useUTF8) {
391+
message = StringUtil.byteStringToUTF8(message);
392+
}
393+
272394
String title = arguments.getString(1);
395+
if (useUTF8) {
396+
title = StringUtil.byteStringToUTF8(title);
397+
}
398+
273399
String playerName = arguments.getString(2);
274400
int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get();
275401
int range = arguments.optInt(6, -1);
@@ -278,13 +404,28 @@ public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throw
278404
if (player == null)
279405
return MethodResult.of(null, "incorrect player name/uuid");
280406

281-
if (checkBrackets(arguments.optString(4)))
407+
Optional<String> brackets = arguments.optString(4);
408+
if (useUTF8) {
409+
brackets = brackets.map(StringUtil::byteStringToUTF8);
410+
}
411+
412+
if (checkBrackets(brackets))
282413
return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)");
283414

415+
Optional<String> prefix = arguments.optString(3);
416+
if (useUTF8) {
417+
prefix = prefix.map(StringUtil::byteStringToUTF8);
418+
}
419+
420+
String bracketColor = arguments.optString(5, "");
421+
if (useUTF8) {
422+
bracketColor = StringUtil.byteStringToUTF8(bracketColor);
423+
}
424+
284425
MutableComponent preparedMessage = appendPrefix(
285-
StringUtil.convertAndToSectionMark(arguments.optString(3, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
286-
arguments.optString(4, "[]"),
287-
StringUtil.convertAndToSectionMark(arguments.optString(5, ""))
426+
StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())),
427+
brackets.orElse("[]"),
428+
StringUtil.convertAndToSectionMark(bracketColor)
288429
).append(message);
289430

290431
if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension)
@@ -300,9 +441,11 @@ public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throw
300441

301442
public void update() {
302443
lastConsumedMessage = Events.traverseChatMessages(lastConsumedMessage, message -> {
444+
String messageUtf8 = StringUtil.utf8ToByteString(message.message());
303445
for (IComputerAccess computer : getConnectedComputers()) {
304-
computer.queueEvent("chat", message.username(), message.message(), message.uuid(), message.isHidden());
446+
computer.queueEvent("chat", message.username(), message.message(), message.uuid(), message.isHidden(), messageUtf8);
305447
}
306448
});
449+
307450
}
308451
}

src/main/java/de/srendi/advancedperipherals/common/util/StringUtil.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
package de.srendi.advancedperipherals.common.util;
2+
import java.nio.charset.StandardCharsets;
23

34
public class StringUtil {
45
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
@@ -31,4 +32,32 @@ public static String toHexString(byte[] bytes) {
3132
public static String convertAndToSectionMark(String str) {
3233
return str == null ? null : str.replaceAll("(?<!\\\\)&(?=[0-9a-z])", "\u00a7").replaceAll("\\\\&", "&");
3334
}
35+
36+
/**
37+
* Converts from a lua-sourced byte string to a UTF-8 string.
38+
* </p>
39+
* Lua encodes bytes as 8bit ASCII (latin1) strings.
40+
* To convert this to a UTF-8 string, we need to interpret the byte string as ISO-8859-1 to get each individual byte,
41+
* then convert that to a UTF-8 string.
42+
*
43+
* @param asciiByteString the utf encoded string sourced from lua.
44+
* @return A String, with all characters correctly interpreted as UTF-8.
45+
*/
46+
public static String byteStringToUTF8(String asciiByteString) {
47+
return new String(asciiByteString.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
48+
}
49+
50+
/**
51+
* Converts from a UTF-8 string to a lua-sourced byte string.
52+
* </p>
53+
* Lua enforces that all characters in any string passed to it are valid latin1 characters (0-255)
54+
* </p>
55+
* to get around this, we first convert the UTF-8 string to bytes, which are interpreted as characters separately.
56+
*
57+
* @param utf8String the utf encoded string sourced from lua.
58+
* @return a string, with all multibyte sequence characters split into their individual byte characters.
59+
*/
60+
public static String utf8ToByteString(String utf8String) {
61+
return new String(utf8String.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
62+
}
3463
}

0 commit comments

Comments
 (0)