网络封包(Network Messages)

基本信息

属性 值
通道 net/NetworkHandler.java 的 NetworkHandler.instance
类型 cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
通道名 Hodgepodge.MODID = hodgepodge(NetworkHandler.java:12)
注册时机 Hodgepodge.java:81 —— NetworkHandler.init()(FMLPreInitEvent 阶段)
封包总数 3(ID 0、1、2),全部单向:S2C
关联 Speedups 配置、Coremod 引导

功能

Hodgepodge 只有 3 个自研封包,且都走 FML 的 SimpleNetworkWrapper(registerMessage(消息类, 处理类, id, side))。三者全部注册为 Side.CLIENT —— 即服务端发、客户端收,没有反向通道。

Hodgepodge 不注册方块 / 物品 / TileEntity,因此没有方块实体同步封包。第 1 号封包虽然是实体描述封包,但它是批量转发原版 S35PacketUpdateTileEntity 的透传容器,不新增实体类型。

明细

ID 0 —— MessageConfigSync(配置同步)

属性 值
源文件 net/MessageConfigSync.java
载荷 2 个 boolean,共 2 字节
发送时机 玩家登录时,HodgepodgeEventHandler.java:50
触发 @SubscribeEvent onPlayerLogin(PlayerEvent.PlayerLoggedInEvent)

同步两个由服务端决定、客户端不能自行开启的开关:

字段 源配置 客户端行为
longerSentMessages TweaksConfig.longerSentMessages 直接覆盖客户端值
fastBlockPlacingServerSide TweaksConfig.fastBlockPlacingServerSide 为 false 时才强制关闭 fastBlockPlacing 与 fastBlockPlacingServerSide

处理端逻辑(MessageConfigSync.java:47-56):

TweaksConfig.longerSentMessages = message.isLongerSentMessages();
if (!message.isFastBlockPlacingServerSide()) {
    TweaksConfig.fastBlockPlacing = false;
    TweaksConfig.fastBlockPlacingServerSide = false;
}

注意单向覆盖:fastBlockPlacingServerSide 为 true 时客户端值不变(保留玩家自己的本地设置)。

向后兼容的读法

fromBytes 对第二个布尔做了容错(:20-30):

longerSentMessages = buf.readBoolean();
if (buf.readableBytes() < 1) {
    fastBlockPlacingServerSide = true;   // 旧服务端只发 1 字节
} else {
    fastBlockPlacingServerSide = buf.readBoolean();
}

源码注释:«Ensures clients with the setting can still join servers without the setting (servers running older versions of the mod)»。即第二个字段是后加的,用剩余可读字节数判断对端是否为旧版。

ID 1 —— BatchedDescriptionPacket / BatchedDescriptionHandler(方块实体描述批处理)

属性 值
源文件 hax/TileEntityDescriptionBatcher.java:122-137(封包)、:139-174(处理)
载荷 拼接后的 ByteBuf(多个原版 S35PacketUpdateTileEntity 的字节流)
发送时机 服务端 tick END 阶段 flushMessages(TickEvent.ServerTickEvent)(:100-109)
门控 SpeedupsConfig.batchDescriptionPacketsMixins(Mixin 侧,需重启)+ batchDescriptionPacketsCode(代码侧,不需重启)

send()(:111-120)把该玩家本 tick 累积的 ByteBuf 拷进新缓冲再发出并清空原缓冲。

处理端有两条路径,由 SpeedupsConfig.asyncBatchedNBTParsing 决定:

路径 行为
关闭(默认) parseAndHandle(message.data, client) —— 同线程直接解析并逐个 client.handleUpdateTileEntity(packet)
打开 先把字节拷进 byte[](注释:原缓冲可能被复用),提交 AsyncNBTParser,解析完再 Minecraft.func_152344_a(...) 回主线程逐个处理

非客户端连接时打 ERROR 后忽略(:143-149):Received BatchedDescriptionPacket while not playing: ignoring it。

ID 2 —— MessageChangeDifficulty(难度同步)

属性 值
源文件 net/MessageChangeDifficulty.java(37 行,全文)
载荷 1 个 byte(EnumDifficulty 的 id)
发送时机 服务端难度变化时
发送方 mixins/early/minecraft/MixinMinecraftServer_UpdateClientDifficulty.java:28
发送范围 sendToDimension(...) —— 只发给该维度的玩家
门控 FixesConfig.updateClientDifficultyOnServer

onMessage 只有一行(:32-36):Minecraft.getMinecraft().theWorld.difficultySetting = message.difficulty;

对应 FixesConfig.updateClientDifficultyOnServer 的描述:«Updates the difficulty on every connected client when the difficulty of the server changes via /difficulty or the difficulty button.» —— 原版 1.7.10 中客户端难度不随服务端更新。

数值

项 值
封包 ID 范围 0 – 2(3 个)
方向 全部 S2C
SimpleNetworkWrapper 实例数 1(NetworkHandler.instance)
通道名 hodgepodge

相关条目