Skip to content

模型解析中的 Section 连锁失败与 Format 偏移导致的加载错误 #8

@cyhqw

Description

@cyhqw

两个问题:

  1. 单个 Section 解析失败会导致整个模型加载中断
  2. 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 同样独立包裹。

效果

修复前:

  • 98 个模型全部加载失败

修复后:

  • 部分模型可正常加载核心内容
  • 仅损坏 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 >= 32format=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在这种情况下可以正常加载,无黑模错误

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions