From adf83a67a62279ef109a6a936ff33fbd165e6a2f Mon Sep 17 00:00:00 2001 From: Catnies Date: Thu, 26 Jun 2025 07:01:50 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E6=94=B9=E8=BF=9BSNBTReader,=20=E6=95=B0?= =?UTF-8?q?=E5=AD=97=E7=B1=BB=E5=9E=8B=E5=90=8E=E7=BC=80b,s,l,f,d=E5=BF=BD?= =?UTF-8?q?=E7=95=A5=E5=A4=A7=E5=B0=8F=E5=86=99.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/net/momirealms/craftengine/core/util/SNBTReader.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java index c42e99e8b..802751f1a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java @@ -161,6 +161,7 @@ public final class SNBTReader extends DefaultStringReader { if (tokenLength > 1) { // 至少有1个字符,给了后缀的可能性 char lastChar = charAt(tokenStart + tokenLength - 1); + if (lastChar < 'a') lastChar = (char) (lastChar + 32); // 强制转小写进行匹配. try { switch (lastChar) { case BYTE_SUFFIX -> { From 85db623bf2a8ba4530273080b963f4c5a98dad54 Mon Sep 17 00:00:00 2001 From: Catnies Date: Thu, 26 Jun 2025 07:16:20 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E6=94=B9=E8=BF=9BSNBTReader,=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81null=E5=80=BC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/net/momirealms/craftengine/core/util/SNBTReader.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java index 802751f1a..d95bce0d7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java @@ -149,12 +149,13 @@ public final class SNBTReader extends DefaultStringReader { } } int tokenLength = getCursor() - tokenStart - lastWhitespace; // 计算值长度需要再减去尾部空格. - if (tokenLength == 0) throw new IllegalArgumentException("Empty value at position " + tokenStart); + if (tokenLength == 0) return null; // 如果值长度为0则返回null. if (contentHasWhitespace) return substring(tokenStart, tokenStart + tokenLength); // 如果值的中间有空格, 一定是字符串, 可直接返回. // 布尔值检查 if (tokenLength == 4) { if (matchesAt(tokenStart, "true")) return Boolean.TRUE; + if (matchesAt(tokenStart, "null")) return null; // 支持 {key:null}. } else if (tokenLength == 5) { if (matchesAt(tokenStart, "false")) return Boolean.FALSE; } From 16d4198d4189fa29f1d9dc56bf7f2c9ee2d2dc5e Mon Sep 17 00:00:00 2001 From: Catnies Date: Thu, 26 Jun 2025 07:21:02 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E6=94=AF=E6=8C=81=20Byte,=20Int,=20Long=20?= =?UTF-8?q?=E7=9A=84=E6=95=B0=E7=BB=84=E8=A7=A3=E6=9E=90.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/util/SNBTReader.java | 78 ++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java index d95bce0d7..ec6fbc279 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java @@ -16,6 +16,11 @@ public final class SNBTReader extends DefaultStringReader { private static final char KEY_VALUE_SEPARATOR = ':'; private static final char ELEMENT_SEPARATOR = ','; + private static final char ARRAY_DELIMITER = ';'; + private static final char BYTE_ARRAY = 'b'; + private static final char INT_ARRAY = 'i'; + private static final char LONG_ARRAY = 'l'; + // 数字类型后缀 private static final char BYTE_SUFFIX = 'b'; private static final char SHORT_SUFFIX = 's'; @@ -81,9 +86,31 @@ public final class SNBTReader extends DefaultStringReader { } // 解析列表值 [1, 2, 3] - private List parseList() { + private Object parseList() { skip(); // 跳过 '[' skipWhitespace(); + + // 检查接下来的2个非空格字符, 确认是否要走数组解析. + if (canRead()) { + setMarker(cursor); // 记录指针, 尝试解析数组. + char typeChar = peek(); + if (typeChar < 'a') typeChar = (char) (typeChar + 32); // 强制转小写进行匹配. + if (typeChar == BYTE_ARRAY || typeChar == INT_ARRAY || typeChar == LONG_ARRAY) { + skip(); + skipWhitespace(); + if (canRead() && peek() == ARRAY_DELIMITER) { // 下一个必须是 ';' + skip(); + return switch (typeChar){ // 解析并返回数组喵 + case BYTE_ARRAY -> parseArray(Byte.class); + case INT_ARRAY -> parseArray(Integer.class); + case LONG_ARRAY -> parseArray(Long.class); + default -> throw new IllegalArgumentException("Unknown typed-array prefix: " + typeChar); + }; + } + } + restore(); // 复原指针. + } + List elementList = new ArrayList<>(); if (canRead() && peek() != LIST_END) { @@ -100,6 +127,55 @@ public final class SNBTReader extends DefaultStringReader { return elementList; } + // 解析数组 [I; 11, 41, 54] + // ArrayType -> B, I, L. + private Object parseArray(Class arrayType) { + skipWhitespace(); + // 用来暂存解析出的数字 + List elements = new ArrayList<>(); + if (canRead() && peek() != LIST_END) { + do { + Object element = parseValue(); + + // 1.21.6的SNBT原版是支持 {key:[B;1,2b,0xFF]} 这种奇葩写法的, 越界部分会被自动舍弃, 如0xff的byte值为-1. + // 如果需要和原版对齐, 那么只需要判断是否是数字就行了. + // if (!(element instanceof Number number)) + // throw new IllegalArgumentException("Error element type at pos " + getCursor()); + if (!arrayType.isInstance(element)) + throw new IllegalArgumentException("Error element type at pos " + getCursor()); + + elements.add((Number) element); // 校验通过后加入 + skipWhitespace(); + } while (canRead() && peek() == ELEMENT_SEPARATOR && ++cursor > 0 /* 跳过 ',' */); + } + + if (!canRead() || peek() != LIST_END) + throw new IllegalArgumentException("Expected ']' at position " + getCursor()); + + skip(); // 跳过 ']' + + // 根据数组类型创建并返回对应的数组 + // 构造并返回真正的 Java 数组 + return switch (arrayType.getSimpleName()) { + case "Byte" -> { + byte[] arr = new byte[elements.size()]; + for (int i = 0; i < arr.length; i++) arr[i] = elements.get(i).byteValue(); + yield arr; + } + case "Integer" -> { + int[] arr = new int[elements.size()]; + for (int i = 0; i < arr.length; i++) arr[i] = elements.get(i).intValue(); + yield arr; + } + case "Long" -> { + long[] arr = new long[elements.size()]; + for (int i = 0; i < arr.length; i++) arr[i] = elements.get(i).longValue(); + yield arr; + } + default -> throw new IllegalArgumentException("Unknown typed-array prefix: " + getCursor()); + }; + } + // 解析Key值 private String parseKey() { skipWhitespace(); From 982cf7980e69aa7c68565b1abf15b5a49b20299b Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 27 Jun 2025 01:43:03 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E6=94=AF=E6=8C=81=200xff=20=E7=AD=89?= =?UTF-8?q?=E5=8D=81=E5=85=AD=E8=BF=9B=E5=88=B6=E5=86=99=E6=B3=95.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/util/SNBTReader.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java index ec6fbc279..0f8f1b851 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java @@ -226,7 +226,20 @@ public final class SNBTReader extends DefaultStringReader { } int tokenLength = getCursor() - tokenStart - lastWhitespace; // 计算值长度需要再减去尾部空格. if (tokenLength == 0) return null; // 如果值长度为0则返回null. - if (contentHasWhitespace) return substring(tokenStart, tokenStart + tokenLength); // 如果值的中间有空格, 一定是字符串, 可直接返回. + String fullString = substring(tokenStart, tokenStart + tokenLength); + if (contentHasWhitespace) return fullString; // 如果值的中间有空格, 一定是字符串, 可直接返回. + + // 十六进制处理 + String fullHex = fullString.toLowerCase(); + boolean negativeHex = fullHex.startsWith("-0x"); + boolean positiveHex = fullHex.startsWith("0x"); + if (negativeHex || positiveHex) { + String hexDigits = fullHex.substring(negativeHex ? 3 : 2); // 去掉 0x / -0x + if (hexDigits.isEmpty()) return fullString; // 没值了代表这是个字符串. + long value = Long.parseLong(hexDigits, 16); + if (negativeHex) value = -value; + return (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) ? (int) value : value; // 默认返回的还是Int类型的喵. + } // 布尔值检查 if (tokenLength == 4) { @@ -257,7 +270,6 @@ public final class SNBTReader extends DefaultStringReader { return Double.parseDouble(substring(tokenStart, tokenStart + tokenLength)); } default -> { - String fullString = substring(tokenStart, tokenStart + tokenLength); try { double d = Double.parseDouble(fullString); if (d % 1 != 0 || fullString.contains(".") || fullString.contains("e")) { From 2b4ed81b72fe3bb3aba36de47459fbb225ba31bb Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 27 Jun 2025 02:30:30 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=89=E5=85=83?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84=E7=B1=BB=E5=9E=8B=E5=BC=BA=E8=BD=AC?= =?UTF-8?q?=E9=97=AE=E9=A2=98.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/net/momirealms/craftengine/core/util/SNBTReader.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java index 0f8f1b851..5d609538f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java @@ -238,7 +238,9 @@ public final class SNBTReader extends DefaultStringReader { if (hexDigits.isEmpty()) return fullString; // 没值了代表这是个字符串. long value = Long.parseLong(hexDigits, 16); if (negativeHex) value = -value; - return (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) ? (int) value : value; // 默认返回的还是Int类型的喵. + // 默认返回的还是Int类型的, 三元坑我喵. + if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) return (int) value; + else return value; } // 布尔值检查 From d09a632804b2b010b7801522ad851a36bf95593b Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 27 Jun 2025 03:16:17 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E5=BF=BD=E7=95=A5=E5=A4=A7=E5=B0=8F?= =?UTF-8?q?=E5=86=99=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/momirealms/craftengine/core/util/SNBTReader.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java index 5d609538f..822e01203 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/SNBTReader.java @@ -93,8 +93,7 @@ public final class SNBTReader extends DefaultStringReader { // 检查接下来的2个非空格字符, 确认是否要走数组解析. if (canRead()) { setMarker(cursor); // 记录指针, 尝试解析数组. - char typeChar = peek(); - if (typeChar < 'a') typeChar = (char) (typeChar + 32); // 强制转小写进行匹配. + char typeChar = Character.toLowerCase(peek()); if (typeChar == BYTE_ARRAY || typeChar == INT_ARRAY || typeChar == LONG_ARRAY) { skip(); skipWhitespace(); @@ -253,7 +252,7 @@ public final class SNBTReader extends DefaultStringReader { if (tokenLength > 1) { // 至少有1个字符,给了后缀的可能性 char lastChar = charAt(tokenStart + tokenLength - 1); - if (lastChar < 'a') lastChar = (char) (lastChar + 32); // 强制转小写进行匹配. + lastChar = Character.toLowerCase(lastChar); // 强制转小写进行匹配. try { switch (lastChar) { case BYTE_SUFFIX -> {