Minecraft服务端发送login success及join game数据包触发越界异常原因排查
可能的原因如下:
- 协议版本不匹配
你使用的Join Game包字段结构和客户端运行的Minecraft版本不对应,不同版本的数据包字段顺序、字段数量差异很大:比如1.19版本新增了enforcesSecureChat布尔字段,1.20.2版本调整了维度相关字段的顺序和结构,只要实际写入的字节长度和客户端预期的长度不符,就会触发越界异常。 - Login Success包字段缺失
如果你的客户端版本高于等于1.19.1,ClientboundLoginSuccessPacket除了UUID和用户名外,还需要追加写入属性数组:先写一个VarInt类型的属性数量,再跟着对应数量的属性条目。你当前的实现只写了两个字段,高版本客户端会继续读取后续不存在的字节,直接抛出越界。
另外如果客户端版本低于1.16,UUID需要以无分隔符的字符串格式写入,而非两个long值,也会导致字段长度错位。 - 数据包头部错误
Minecraft所有数据包的结构为VarInt(包总长度) + VarInt(包ID) + 包内容,如果出现以下情况都会导致解析错误:- 漏写了长度前缀或者包ID
- 计算包长度时没有把包ID的长度计入
- 长度计算错误,导致客户端读取的字节数超过了实际发送的包大小
- Join Game包字段错误
- 你连续两次写入了
packet.gameMode,第二个字段实际应为前一个游戏模式,虽然值相同不会直接导致长度错误,但如果存在其他字段顺序错位(比如维度Codec和维度NBT顺序写反、NBT序列化时没有正确写入结束标记),会导致客户端读NBT时超出包边界 - 你写入的维度数量固定为1,如果版本要求的维度列表结构不对,比如需要先传维度注册表再传当前维度,也会导致长度错位
- 你连续两次写入了
- 状态切换错误
切换协议状态为PLAY的时机必须是发送完Login Success包之后,如果提前切换,会导致Login Success包用错包ID;同时发送Join Game包时必须使用PLAY状态下对应的包ID,状态不匹配导致包ID错误,客户端会按照错误的包结构解析,触发越界。 - VarInt序列化错误
你用到的所有VarInt类型(包括字符串长度、viewDistance、maxPlayers等字段)如果序列化实现有问题,比如大数值的VarInt少写了字节,会导致所有后续字段的位置全部错位,最终读超出界。
内容的提问来源于stack exchange,提问作者Cororo
相关产品推荐
相关产品推荐

