diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java index 81122adc0..39e40997e 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java @@ -106,10 +106,17 @@ private boolean checkBrackets(Optional brackets) { return brackets.isPresent() && brackets.get().length() != 2; } + // 0 message, 1 prefix, 2 brackets, 3 color, 4 range, 5 utf8Support @LuaFunction(mainThread = true) public final MethodResult sendFormattedMessage(@NotNull IArguments arguments) throws LuaException { return withChatOperation(ignored -> { + boolean useUTF8 = arguments.optBoolean(5, false); + String message = arguments.getString(0); + if (useUTF8) { + message = StringUtil.byteStringToUTF8(message); + } + int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get(); int range = arguments.optInt(4, -1); ResourceKey dimension = getLevel().dimension(); @@ -117,13 +124,28 @@ public final MethodResult sendFormattedMessage(@NotNull IArguments arguments) th if (component == null) return MethodResult.of(null, "incorrect json"); - if (checkBrackets(arguments.optString(2))) + Optional brackets = arguments.optString(2); + if (useUTF8) { + brackets = brackets.map(StringUtil::byteStringToUTF8); + } + + if (checkBrackets(brackets)) return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)"); + Optional prefix = arguments.optString(1); + if (useUTF8) { + prefix = prefix.map(StringUtil::byteStringToUTF8); + } + + String bracketColor = arguments.optString(3, ""); + if (useUTF8) { + bracketColor = StringUtil.byteStringToUTF8(bracketColor); + } + MutableComponent preparedMessage = appendPrefix( - StringUtil.convertAndToSectionMark(arguments.optString(1, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), - arguments.optString(2, "[]"), - StringUtil.convertAndToSectionMark(arguments.optString(3, "")) + StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), + brackets.orElse("[]"), + StringUtil.convertAndToSectionMark(bracketColor) ).append(component); for (ServerPlayer player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers()) { if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension) @@ -135,20 +157,43 @@ public final MethodResult sendFormattedMessage(@NotNull IArguments arguments) th }); } + // 0 message, 1 prefix, 2 brackets, 3 color, 4 range, 5 utf8Support @LuaFunction(mainThread = true) public final MethodResult sendMessage(@NotNull IArguments arguments) throws LuaException { return withChatOperation(ignored -> { + boolean useUTF8 = arguments.optBoolean(5, false); + String message = arguments.getString(0); + if (useUTF8) { + message = StringUtil.byteStringToUTF8(message); + } + int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get(); int range = arguments.optInt(4, -1); ResourceKey dimension = getLevel().dimension(); - if (checkBrackets(arguments.optString(2))) + + Optional brackets = arguments.optString(2); + if (useUTF8) { + brackets = brackets.map(StringUtil::byteStringToUTF8); + } + + if (checkBrackets(brackets)) return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)"); + Optional prefix = arguments.optString(1); + if (useUTF8) { + prefix = prefix.map(StringUtil::byteStringToUTF8); + } + + String bracketColor = arguments.optString(3, ""); + if (useUTF8) { + bracketColor = StringUtil.byteStringToUTF8(bracketColor); + } + MutableComponent preparedMessage = appendPrefix( - StringUtil.convertAndToSectionMark(arguments.optString(1, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), - arguments.optString(2, "[]"), - StringUtil.convertAndToSectionMark(arguments.optString(3, "")) + StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), + brackets.orElse("[]"), + StringUtil.convertAndToSectionMark(bracketColor) ).append(message); for (ServerPlayer player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers()) { if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension) @@ -160,10 +205,17 @@ public final MethodResult sendMessage(@NotNull IArguments arguments) throws LuaE }); } + // 0 message, 1 playerName, 2 prefix, 3 brackets, 4 color, 5 range, 6 utf8Support @LuaFunction(mainThread = true) public final MethodResult sendFormattedMessageToPlayer(@NotNull IArguments arguments) throws LuaException { return withChatOperation(ignored -> { + boolean useUTF8 = arguments.optBoolean(6, false); + String message = arguments.getString(0); + if (useUTF8) { + message = StringUtil.byteStringToUTF8(message); + } + String playerName = arguments.getString(1); int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get(); int range = arguments.optInt(5, -1); @@ -176,13 +228,28 @@ public final MethodResult sendFormattedMessageToPlayer(@NotNull IArguments argum if (component == null) return MethodResult.of(null, "incorrect json"); - if (checkBrackets(arguments.optString(3))) + Optional brackets = arguments.optString(3); + if (useUTF8) { + brackets = brackets.map(StringUtil::byteStringToUTF8); + } + + if (checkBrackets(brackets)) return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)"); + Optional prefix = arguments.optString(2); + if (useUTF8) { + prefix = prefix.map(StringUtil::byteStringToUTF8); + } + + String bracketColor = arguments.optString(4, ""); + if (useUTF8) { + bracketColor = StringUtil.byteStringToUTF8(bracketColor); + } + MutableComponent preparedMessage = appendPrefix( - StringUtil.convertAndToSectionMark(arguments.optString(2, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), - arguments.optString(3, "[]"), - StringUtil.convertAndToSectionMark(arguments.optString(4, "")) + StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), + brackets.orElse("[]"), + StringUtil.convertAndToSectionMark(bracketColor) ).append(component); if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension) return MethodResult.of(false, "NOT_SAME_DIMENSION"); @@ -194,11 +261,22 @@ public final MethodResult sendFormattedMessageToPlayer(@NotNull IArguments argum } + // 0 message, 1 title, 2 playerName, 3 prefix, 4 brackets, 5 bracket color, 6 range, 7 utf8Support @LuaFunction(mainThread = true) public final MethodResult sendFormattedToastToPlayer(@NotNull IArguments arguments) throws LuaException { return withChatOperation(ignored -> { + boolean useUTF8 = arguments.optBoolean(7, false); + String message = arguments.getString(0); + if (useUTF8) { + message = StringUtil.byteStringToUTF8(message); + } + String title = arguments.getString(1); + if (useUTF8) { + title = StringUtil.byteStringToUTF8(title); + } + String playerName = arguments.getString(2); int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get(); int range = arguments.optInt(6, -1); @@ -215,13 +293,28 @@ public final MethodResult sendFormattedToastToPlayer(@NotNull IArguments argumen if (titleComponent == null) return MethodResult.of(null, "incorrect json for title"); - if (checkBrackets(arguments.optString(4))) + Optional brackets = arguments.optString(4); + if (useUTF8) { + brackets = brackets.map(StringUtil::byteStringToUTF8); + } + + if (checkBrackets(brackets)) return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ,,,)"); + Optional prefix = arguments.optString(3); + if (useUTF8) { + prefix = prefix.map(StringUtil::byteStringToUTF8); + } + + String bracketColor = arguments.optString(5, ""); + if (useUTF8) { + bracketColor = StringUtil.byteStringToUTF8(bracketColor); + } + MutableComponent preparedMessage = appendPrefix( - StringUtil.convertAndToSectionMark(arguments.optString(3, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), - arguments.optString(4, "[]"), - StringUtil.convertAndToSectionMark(arguments.optString(5, "")) + StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), + brackets.orElse("[]"), + StringUtil.convertAndToSectionMark(bracketColor) ).append(messageComponent); if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension) @@ -236,10 +329,17 @@ public final MethodResult sendFormattedToastToPlayer(@NotNull IArguments argumen }); } + // 0 message, 1 playerName, 2 prefix, 3 brackets, 4 bracket color, 5 range, 6 utf8Support @LuaFunction(mainThread = true) public final MethodResult sendMessageToPlayer(@NotNull IArguments arguments) throws LuaException { return withChatOperation(ignored -> { + boolean useUTF8 = arguments.optBoolean(6, false); + String message = arguments.getString(0); + if (useUTF8) { + message = StringUtil.byteStringToUTF8(message); + } + String playerName = arguments.getString(1); int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get(); int range = arguments.optInt(5, -1); @@ -248,13 +348,28 @@ public final MethodResult sendMessageToPlayer(@NotNull IArguments arguments) thr if (player == null) return MethodResult.of(null, "incorrect player name/uuid"); - if (checkBrackets(arguments.optString(3))) + Optional brackets = arguments.optString(3); + if (useUTF8) { + brackets = brackets.map(StringUtil::byteStringToUTF8); + } + + if (checkBrackets(brackets)) return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)"); + Optional prefix = arguments.optString(2); + if (useUTF8) { + prefix = prefix.map(StringUtil::byteStringToUTF8); + } + + String bracketColor = arguments.optString(4, ""); + if (useUTF8) { + bracketColor = StringUtil.byteStringToUTF8(bracketColor); + } + MutableComponent preparedMessage = appendPrefix( - StringUtil.convertAndToSectionMark(arguments.optString(2, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), - arguments.optString(3, "[]"), - StringUtil.convertAndToSectionMark(arguments.optString(4, "")) + StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), + brackets.orElse("[]"), + StringUtil.convertAndToSectionMark(bracketColor) ).append(message); if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension) return MethodResult.of(false, "NOT_SAME_DIMENSION"); @@ -265,11 +380,22 @@ public final MethodResult sendMessageToPlayer(@NotNull IArguments arguments) thr }); } + // 0 message, 1 title, 2 playerName, 3 prefix, 4 brackets, 5 bracket color, 6 range, 7 utf8Support @LuaFunction(mainThread = true) public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throws LuaException { return withChatOperation(ignored -> { + boolean useUTF8 = arguments.optBoolean(7, false); + String message = arguments.getString(0); + if (useUTF8) { + message = StringUtil.byteStringToUTF8(message); + } + String title = arguments.getString(1); + if (useUTF8) { + title = StringUtil.byteStringToUTF8(title); + } + String playerName = arguments.getString(2); int maxRange = APConfig.PERIPHERALS_CONFIG.chatBoxMaxRange.get(); int range = arguments.optInt(6, -1); @@ -278,13 +404,28 @@ public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throw if (player == null) return MethodResult.of(null, "incorrect player name/uuid"); - if (checkBrackets(arguments.optString(4))) + Optional brackets = arguments.optString(4); + if (useUTF8) { + brackets = brackets.map(StringUtil::byteStringToUTF8); + } + + if (checkBrackets(brackets)) return MethodResult.of(null, "incorrect bracket string (e.g. [], {}, <>, ...)"); + Optional prefix = arguments.optString(3); + if (useUTF8) { + prefix = prefix.map(StringUtil::byteStringToUTF8); + } + + String bracketColor = arguments.optString(5, ""); + if (useUTF8) { + bracketColor = StringUtil.byteStringToUTF8(bracketColor); + } + MutableComponent preparedMessage = appendPrefix( - StringUtil.convertAndToSectionMark(arguments.optString(3, APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), - arguments.optString(4, "[]"), - StringUtil.convertAndToSectionMark(arguments.optString(5, "")) + StringUtil.convertAndToSectionMark(prefix.orElse(APConfig.PERIPHERALS_CONFIG.defaultChatBoxPrefix.get())), + brackets.orElse("[]"), + StringUtil.convertAndToSectionMark(bracketColor) ).append(message); if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.level().dimension() != dimension) @@ -300,9 +441,11 @@ public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throw public void update() { lastConsumedMessage = Events.traverseChatMessages(lastConsumedMessage, message -> { + String messageUtf8 = StringUtil.utf8ToByteString(message.message()); for (IComputerAccess computer : getConnectedComputers()) { - computer.queueEvent("chat", message.username(), message.message(), message.uuid(), message.isHidden()); + computer.queueEvent("chat", message.username(), message.message(), message.uuid(), message.isHidden(), messageUtf8); } }); + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/util/StringUtil.java b/src/main/java/de/srendi/advancedperipherals/common/util/StringUtil.java index f166eda25..54c954304 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/util/StringUtil.java +++ b/src/main/java/de/srendi/advancedperipherals/common/util/StringUtil.java @@ -1,4 +1,5 @@ package de.srendi.advancedperipherals.common.util; +import java.nio.charset.StandardCharsets; public class StringUtil { private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); @@ -31,4 +32,32 @@ public static String toHexString(byte[] bytes) { public static String convertAndToSectionMark(String str) { return str == null ? null : str.replaceAll("(? + * Lua encodes bytes as 8bit ASCII (latin1) strings. + * To convert this to a UTF-8 string, we need to interpret the byte string as ISO-8859-1 to get each individual byte, + * then convert that to a UTF-8 string. + * + * @param asciiByteString the utf encoded string sourced from lua. + * @return A String, with all characters correctly interpreted as UTF-8. + */ + public static String byteStringToUTF8(String asciiByteString) { + return new String(asciiByteString.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); + } + + /** + * Converts from a UTF-8 string to a lua-sourced byte string. + *

+ * Lua enforces that all characters in any string passed to it are valid latin1 characters (0-255) + *

+ * to get around this, we first convert the UTF-8 string to bytes, which are interpreted as characters separately. + * + * @param utf8String the utf encoded string sourced from lua. + * @return a string, with all multibyte sequence characters split into their individual byte characters. + */ + public static String utf8ToByteString(String utf8String) { + return new String(utf8String.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); + } }