From 41cb6749c883ea23807849c0d6b2f406df66d495 Mon Sep 17 00:00:00 2001 From: P0nk Date: Wed, 8 Sep 2021 08:24:52 +0200 Subject: [PATCH] Make packet charset configurable Better support for different language clients such as Thai or Korean --- config.yaml | 1 + src/main/java/config/ServerConfig.java | 4 +- .../constants/string/CharsetConstants.java | 73 ++++++++++++------- src/main/java/net/packet/ByteBufInPacket.java | 3 +- .../java/net/packet/ByteBufOutPacket.java | 5 +- src/main/java/net/packet/Packet.java | 5 -- src/main/java/tools/HexTool.java | 14 ++-- .../java/net/packet/ByteBufInPacketTest.java | 3 +- 8 files changed, 62 insertions(+), 46 deletions(-) diff --git a/config.yaml b/config.yaml index 18eaa55d96..811dcd19de 100644 --- a/config.yaml +++ b/config.yaml @@ -307,6 +307,7 @@ server: #Miscellaneous Configuration TIMEZONE: GMT-3 + PACKET_CHARSET: US_ASCII # Defaults to US_ASCII if not set USE_DISPLAY_NUMBERS_WITH_COMMA: true #Enforce comma on displayed strings (use this when USE_UNITPRICE_WITH_COMMA is active and you still want to display comma-separated values). USE_UNITPRICE_WITH_COMMA: true #Set this accordingly with the layout of the unitPrices on Item.wz XML's, whether it's using commas or dots to represent fractions. MAX_MONITORED_BUFFSTATS: 5 #Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires. diff --git a/src/main/java/config/ServerConfig.java b/src/main/java/config/ServerConfig.java index 34beaea4df..3bf11c561f 100644 --- a/src/main/java/config/ServerConfig.java +++ b/src/main/java/config/ServerConfig.java @@ -1,6 +1,7 @@ package config; -import java.util.*; +import java.util.HashMap; +import java.util.Map; public class ServerConfig { //Thread Tracker Configuration @@ -153,6 +154,7 @@ public class ServerConfig { //Miscellaneous Configuration public String TIMEZONE; + public String PACKET_CHARSET; public boolean USE_DISPLAY_NUMBERS_WITH_COMMA; public boolean USE_UNITPRICE_WITH_COMMA; public byte MAX_MONITORED_BUFFSTATS; diff --git a/src/main/java/constants/string/CharsetConstants.java b/src/main/java/constants/string/CharsetConstants.java index 45c9c6ce4e..d6870e2632 100644 --- a/src/main/java/constants/string/CharsetConstants.java +++ b/src/main/java/constants/string/CharsetConstants.java @@ -12,37 +12,56 @@ package constants.string; * MapleStory Server * CharsetConstants */ - + +import config.YamlConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Optional; + public class CharsetConstants { - - public static MapleLanguageType MAPLE_TYPE = MapleLanguageType.LANGUAGE_US; - - public enum MapleLanguageType { - LANGUAGE_PT_BR(1, "ISO-8859-1"), - LANGUAGE_US(2, "US-ASCII"); - final byte type; - final String ascii; - - private MapleLanguageType(int type, String ascii) { - this.type = (byte) type; - this.ascii = ascii; + private static final Logger log = LoggerFactory.getLogger(CharsetConstants.class); + public static final Charset PACKET_CHARSET = loadCharset(); + + private enum Language { + LANGUAGE_US("US-ASCII"), + LANGUAGE_PT_BR("ISO-8859-1"), + LANGUAGE_THAI("TIS620"), + LANGUAGE_KOREAN("MS949"); + + private final String charset; + + Language(String charset) { + this.charset = charset; } - - public String getAscii() { - return ascii; + + public String getCharset() { + return charset; } - - public byte getType() { - return type; - } - - public static MapleLanguageType getByType(byte type) { - for (MapleLanguageType l : MapleLanguageType.values()) { - if (l.getType() == type) { - return l; - } + + public static Language fromCharset(String charset) { + Optional language = Arrays.stream(values()) + .filter(l -> l.charset.equals(charset)) + .findAny(); + if (language.isEmpty()) { + log.warn("Charset {} was not found, defaulting to US-ASCII", charset); + return LANGUAGE_US; } - return LANGUAGE_PT_BR; + + return language.get(); } } + + private static Charset loadCharset() { + String configCharset = YamlConfig.config.server.PACKET_CHARSET; + if (configCharset != null) { + Language language = Language.fromCharset(configCharset); + return Charset.forName(language.getCharset()); + } + + return StandardCharsets.US_ASCII; + } } \ No newline at end of file diff --git a/src/main/java/net/packet/ByteBufInPacket.java b/src/main/java/net/packet/ByteBufInPacket.java index 136761ec7e..d682e9f357 100644 --- a/src/main/java/net/packet/ByteBufInPacket.java +++ b/src/main/java/net/packet/ByteBufInPacket.java @@ -1,5 +1,6 @@ package net.packet; +import constants.string.CharsetConstants; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; @@ -49,7 +50,7 @@ public class ByteBufInPacket implements InPacket { short length = readShort(); byte[] stringBytes = new byte[length]; byteBuf.readBytes(stringBytes); - return new String(stringBytes, STRING_CHARSET); + return new String(stringBytes, CharsetConstants.PACKET_CHARSET); } @Override diff --git a/src/main/java/net/packet/ByteBufOutPacket.java b/src/main/java/net/packet/ByteBufOutPacket.java index 46189fbaaf..866588c41d 100644 --- a/src/main/java/net/packet/ByteBufOutPacket.java +++ b/src/main/java/net/packet/ByteBufOutPacket.java @@ -1,5 +1,6 @@ package net.packet; +import constants.string.CharsetConstants; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; @@ -77,12 +78,12 @@ public class ByteBufOutPacket implements OutPacket { @Override public void writeString(String value) { writeShort((short) value.length()); - writeBytes(value.getBytes(STRING_CHARSET)); + writeBytes(value.getBytes(CharsetConstants.PACKET_CHARSET)); } @Override public void writeFixedString(String value) { - writeBytes(value.getBytes(STRING_CHARSET)); + writeBytes(value.getBytes(CharsetConstants.PACKET_CHARSET)); } @Override diff --git a/src/main/java/net/packet/Packet.java b/src/main/java/net/packet/Packet.java index 79f257cd38..8e1b7cfb99 100644 --- a/src/main/java/net/packet/Packet.java +++ b/src/main/java/net/packet/Packet.java @@ -1,10 +1,5 @@ package net.packet; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - public interface Packet { - Charset STRING_CHARSET = StandardCharsets.US_ASCII; - byte[] getBytes(); } diff --git a/src/main/java/tools/HexTool.java b/src/main/java/tools/HexTool.java index f23e2ac5fc..0a2d4f0cf1 100644 --- a/src/main/java/tools/HexTool.java +++ b/src/main/java/tools/HexTool.java @@ -43,7 +43,7 @@ public class HexTool { } return hexed.substring(0, hexed.length() - 1); } - + public static String toCompressedString(byte[] bytes) { StringBuilder hexed = new StringBuilder(); for (byte aByte : bytes) { @@ -87,8 +87,8 @@ public class HexTool { } return baos.toByteArray(); } - - public static final String toStringFromAscii(final byte[] bytes) { + + public static String toStringFromAscii(final byte[] bytes) { byte[] ret = new byte[bytes.length]; for (int x = 0; x < bytes.length; x++) { if (bytes[x] < 32 && bytes[x] >= 0) { @@ -98,12 +98,8 @@ public class HexTool { ret[x] = (byte) chr; } } - String encode = CharsetConstants.MAPLE_TYPE.getAscii(); - try { - String str = new String(ret, encode); - return str; - } catch (Exception e) {} - return ""; + + return new String(ret, CharsetConstants.PACKET_CHARSET); } /** diff --git a/src/test/java/net/packet/ByteBufInPacketTest.java b/src/test/java/net/packet/ByteBufInPacketTest.java index 2a4b5eab2c..8c4b287cf3 100644 --- a/src/test/java/net/packet/ByteBufInPacketTest.java +++ b/src/test/java/net/packet/ByteBufInPacketTest.java @@ -1,5 +1,6 @@ package net.packet; +import constants.string.CharsetConstants; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import net.opcodes.SendOpcode; @@ -82,7 +83,7 @@ class ByteBufInPacketTest { void readString() { final String writtenString = "You have gained experience (+3200)"; byteBuf.writeShortLE(writtenString.length()); - byte[] writtenStringBytes = writtenString.getBytes(Packet.STRING_CHARSET); + byte[] writtenStringBytes = writtenString.getBytes(CharsetConstants.PACKET_CHARSET); byteBuf.writeBytes(writtenStringBytes); String readString = inPacket.readString();