两个问题:
- 单个 Section 解析失败会导致整个模型加载中断
format=31 模型被错误地按 format=32 解析,导致 Metadata Section 偏移
这导致我在游玩某个服务器时超过90%模型解析错误
日志大量输出:
[265��2026 22:48:38.682] [YSM-Model-Parse-Thread/ERROR] [yes_steve_model/]: [YSM] Failed to parse and load model: �Ȼ�����/�������sfw.ysm
java.lang.RuntimeException: VarInt too big
at rip.ysm.security.YSMByteBuf.readVarInt(YSMByteBuf.java:63) ~[openysm-forge-2.6.6.jar%23372!/:?]
at rip.ysm.security.YSMByteBuf.readString(YSMByteBuf.java:106) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.resource.YSMBinaryDeserializer.parseYSMJson(YSMBinaryDeserializer.java:657) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.resource.YSMBinaryDeserializer.deserializeModern(YSMBinaryDeserializer.java:407) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.resource.YSMBinaryDeserializer.deserializeInternal(YSMBinaryDeserializer.java:37) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.resource.YSMBinaryDeserializer.deserializeKeepOpen(YSMBinaryDeserializer.java:58) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.client.ClientModelManager.parseAndLoadModel(ClientModelManager.java:469) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.client.ClientModelManager.lambda$handlePacket05$4(ClientModelManager.java:449) ~[openysm-forge-2.6.6.jar%23372!/:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) ~[?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[?:?]
at java.lang.Thread.run(Thread.java:1583) ~[?:?]
[265��2026 22:48:40.656] [YSM-Model-Parse-Thread/ERROR] [yes_steve_model/]: [YSM] Failed to parse and load model: ������Ϸ/ħ��_������ϣ��1.0.ysm
java.lang.IndexOutOfBoundsException: readerIndex(3386154) + length(1097349022) exceeds writerIndex(3416447): UnpooledHeapByteBuf(ridx: 3386154, widx: 3416447, cap: 3416447/3416447)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1442) ~[netty-buffer-4.1.82.Final.jar%23100!/:4.1.82.Final]
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1428) ~[netty-buffer-4.1.82.Final.jar%23100!/:4.1.82.Final]
at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:895) ~[netty-buffer-4.1.82.Final.jar%23100!/:4.1.82.Final]
at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:903) ~[netty-buffer-4.1.82.Final.jar%23100!/:4.1.82.Final]
at io.netty.buffer.SwappedByteBuf.readBytes(SwappedByteBuf.java:659) ~[netty-buffer-4.1.82.Final.jar%23100!/:4.1.82.Final]
at rip.ysm.security.YSMByteBuf.readString(YSMByteBuf.java:109) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.resource.YSMBinaryDeserializer.parseYSMJson(YSMBinaryDeserializer.java:657) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.resource.YSMBinaryDeserializer.deserializeModern(YSMBinaryDeserializer.java:407) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.resource.YSMBinaryDeserializer.deserializeInternal(YSMBinaryDeserializer.java:37) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.resource.YSMBinaryDeserializer.deserializeKeepOpen(YSMBinaryDeserializer.java:58) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.client.ClientModelManager.parseAndLoadModel(ClientModelManager.java:469) ~[openysm-forge-2.6.6.jar%23372!/:?]
at com.elfmcys.yesstevemodel.client.ClientModelManager.lambda$handlePacket05$4(ClientModelManager.java:449) ~[openysm-forge-2.6.6.jar%23372!/:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) ~[?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[?:?]
at java.lang.Thread.run(Thread.java:1583) ~[?:?]
Bug 1:Section 解析缺少隔离导致连锁失败
现象
服务器下发模型数据后,大量模型无法加载。
日志中出现:
- 98 个模型解析失败
- 193 个 Section 级错误
- 常见异常:
VarInt too big
Buffer underflow
错误大多发生在 parseYSMJson()。
根因
deserializeModern() 以单一代码流顺序解析所有 Section:
Sounds → Functions → Language → SubEntities
→ Animations → Controllers → Textures
→ Geometry → Metadata
任意早期 Section 解析失败,都会直接中断整个反序列化流程。
即使异常被外层捕获,readerIndex 已经停留在错误位置,后续 Section 会继续基于错误偏移读取数据,最终导致连锁解析失败。
修复
为每个 Section 增加独立的 try-catch(YSMParseException)。
单个 Section 失败时仅跳过当前 Section,不再影响后续解析。
try {
parseSoundFiles();
} catch (YSMParseException e) {
YesSteveModel.LOGGER.error(
"[YSM] Parse error in sound files, skipping section",
e
);
}
其余 Section 同样独立包裹。
效果
修复前:
修复后:
- 部分模型可正常加载核心内容
- 仅损坏 Section 被跳过
Bug 2:Format 硬编码导致 Metadata Section 偏移
现象
修复 Bug 1 后,部分模型仍在 Metadata Section 解析失败。
典型错误:
VarInt too big (position=70)
根因
ClientModelManager.parseAndLoadModel() 硬编码使用 format=32:
new YSMBinaryDeserializer(decompressed, 32);
但在 YSM 二进制格式中,format >= 32 比 format=31 多一个 Metadata 字段:
if (format >= 32) {
model.properties.mergeMultilineExpr =
reader.readVarInt() != 0;
}
在我的实际使用场景中,服务器有时会下发format=31的模型,导致:
当实际模型为 format=31 时,解析器会额外读取一个 VarInt,导致后续 Metadata 字段全部偏移。
受影响字段包括:
guiForeground
guiBackground
- avatar list
最终触发解析异常。
修复
缓存文件 Header 的第 5 个 VarInt 即为 Format 版本号。
新增:
public static int readFormatFromCache(byte[] cacheFileData) {
try (YSMByteBuf buf =
new YSMByteBuf(Unpooled.wrappedBuffer(cacheFileData))) {
buf.readVarInt(); // 1
buf.readVarInt(); // 2
buf.readVarInt(); // 3
buf.readVarInt(); // 4
return buf.readVarInt(); // 5 = format version
} catch (Exception e) {
return 32; // fallback
}
}
调用方改为动态传入实际 Format:
int formatVersion =
YsmCrypt.readFormatFromCache(fileBytes);
parseAndLoadModel(
decompressed,
modelId,
isAuth,
formatVersion
);
效果
- 所有测试模型均可正常加载,无 YSM 解析报错
- 额外:新藤原妹红.ysm在这种情况下可以正常加载,无黑模错误
两个问题:
format=31模型被错误地按format=32解析,导致 Metadata Section 偏移这导致我在游玩某个服务器时超过90%模型解析错误
日志大量输出:
Bug 1:Section 解析缺少隔离导致连锁失败
现象
服务器下发模型数据后,大量模型无法加载。
日志中出现:
VarInt too bigBuffer underflow错误大多发生在
parseYSMJson()。根因
deserializeModern()以单一代码流顺序解析所有 Section:任意早期 Section 解析失败,都会直接中断整个反序列化流程。
即使异常被外层捕获,
readerIndex已经停留在错误位置,后续 Section 会继续基于错误偏移读取数据,最终导致连锁解析失败。修复
为每个 Section 增加独立的
try-catch(YSMParseException)。单个 Section 失败时仅跳过当前 Section,不再影响后续解析。
其余 Section 同样独立包裹。
效果
修复前:
修复后:
Bug 2:Format 硬编码导致 Metadata Section 偏移
现象
修复 Bug 1 后,部分模型仍在 Metadata Section 解析失败。
典型错误:
根因
ClientModelManager.parseAndLoadModel()硬编码使用format=32:但在 YSM 二进制格式中,
format >= 32比format=31多一个 Metadata 字段:在我的实际使用场景中,服务器有时会下发
format=31的模型,导致:当实际模型为
format=31时,解析器会额外读取一个VarInt,导致后续 Metadata 字段全部偏移。受影响字段包括:
guiForegroundguiBackground最终触发解析异常。
修复
缓存文件 Header 的第 5 个
VarInt即为 Format 版本号。新增:
调用方改为动态传入实际 Format:
效果