BuildCraft 封包层:5 个频道 + 14 个包 ID

事实基准:/Users/evlos/a/mirror/BuildCraft(master,minecraftVersion = 1.7.10)逐行读源码。

频道(集合运算:恰好 5 个)

频道名前缀来自 core/DefaultProps.java:15:

public static final String NET_CHANNEL_NAME = "BC";
频道名 注册模块 ChannelHandler PacketHandler 源码
BC-CORE BuildCraft|Core coreChannelHandler core.network.PacketHandlerCore BuildCraftCore.java:506
BC-ENERGY BuildCraft|Energy new ChannelHandler() new PacketHandler() BuildCraftEnergy.java:452
BC-FACTORY BuildCraft|Factory new ChannelHandler() new PacketHandler() BuildCraftFactory.java:157
BC-SILICON BuildCraft|Silicon new ChannelHandler() new PacketHandlerSilicon BuildCraftSilicon.java:139-141
BC-TRANSPORT BuildCraft|Transport new ChannelHandler() new PacketHandlerTransport BuildCraftTransport.java:529-530

⚠ 一仓 7 个 modid,但只有 5 个网络频道—— BuildCraft|Builders 与 BuildCraft|Robotics 没有自己的频道: Builders 的数据走 BC-CORE,Robotics 的数据也走 BC-CORE。 按 modid 数推断频道数即为 7,是错的。

包 ID(core/network/PacketIds.java,集合运算:恰好 14 个)

ID 常量 语义 行
0 TILE_UPDATE TileEntity 整体更新 :11
1 COMMAND ICommandReceiver 命令 :12
2 PIPE_TRAVELER 管道中的物品移动 :13
3 PIPE_LIQUID 管道流体同步 :14
4 PIPE_POWER 管道能量同步 :15
5 PIPE_ITEMSTACK_REQUEST 管道物品请求 :16
6 PIPE_ITEMSTACK 管道物品同步 :17
7 ENTITY_UPDATE 实体更新 :18
31 DIAMOND_PIPE_SELECT 钻石管道选槽 :20
32 EMERALD_PIPE_SELECT 翡翠管道选槽 :21
40 TABLET_MESSAGE 平板消息 :23
70 ADVANCED_WORKBENCH_SETSLOT 高级工作台设槽 :25
80 GUI_RETURN GUI 返回 :27
81 GUI_WIDGET GUI 控件 :28
100 STATE_UPDATE 状态更新 :30

⚠ ID 不连续——分成 0–7、31–32、40、70、80–81、100 几段。 「最大 ID = 100,所以有 101 个包」是典型的枚举虚高; 实际只有 14 个常量。 ⚠ 同样,不能因为 ID 是 100 就断言「包 ID 有 101 种」。

承载数据的包类(core/lib/network/,9 个)

类 用途
Packet(:27 处 PacketHandler extends SimpleChannelInboundHandler<Packet>) 封包基类,携带 int getID()
PacketCoordinates 坐标基类
PacketTileUpdate Tile 更新(ID 0)
PacketEntityUpdate 实体更新(ID 7)
PacketTileState Tile 状态(ID 100)
PacketNBT NBT 负载
PacketSlotChange 单槽变化
PacketGuiReturn GUI 返回(ID 80)
PacketGuiWidget GUI 控件(ID 81)

基础分派(core/lib/network/PacketHandler.java:27)

PacketHandler extends SimpleChannelInboundHandler<Packet>(:27), channelRead0 里取 int packetID = packet.getID()(:69)后 switch(:71):

case 行 处理
PacketIds.TILE_UPDATE :72 Tile 更新
PacketIds.ENTITY_UPDATE :77 实体更新
PacketIds.COMMAND :82 命令
PacketIds.STATE_UPDATE :87 状态更新
PacketIds.GUI_RETURN :100 GUI 返回
PacketIds.GUI_WIDGET :105 GUI 控件

⚠ 基础 PacketHandler 只处理 6 个 ID; 其余 8 个(管道 5 个、管道选择 2 个、平板 1 个)由各模块自己的 PacketHandlerCore / PacketHandlerSilicon / PacketHandlerTransport 扩展处理。 BC-ENERGY 与 BC-FACTORY 直接用基础 PacketHandler。

方向:按包类声明,不按包 ID

⚠ 重要纠正:方向不是按 PacketIds 的 ID 判的。 core/lib/network/ChannelHandler.java 用的是**「包类 → 侧掩码」**的注册表:

  • discriminators(:121):byte 判别值 → Class<? extends Packet>
  • sides(:129 使用):每个判别值对应一个侧掩码,取值 CLIENT_ONLY / SERVER_ONLY / 两者

判定逻辑 ChannelHandler.java:126-129:

int expectedSide = ctx.channel().attr(NetworkRegistry.CHANNEL_SOURCE).get() == Side.CLIENT
        ? CLIENT_ONLY : SERVER_ONLY;
if ((expectedSide & sides.get(discriminator)) != expectedSide) {
    logForgedPackets(player, clazz.getSimpleName(), payload.slice());   // :131 记为伪造包
}
事实 含义
判别值是 byte(:120 payload.readByte()) 传输线上传的是判别值,不是 PacketIds 的 int
未注册的判别值抛 NullPointerException :122-124「Undefined message for discriminator」
侧不匹配的包不抛异常,只记 logForgedPackets :129-131,属防御性日志

PacketHandler.channelRead0 里的 int packetID = packet.getID()(:69) 是读出载荷后才拿到的第二层分派,与「方向」是两件事。

⚠ 因此本条目不逐包断言方向—— PacketIds 只是 ID 常量表,方向由各 Packet 子类注册时的 sides 掩码决定, 逐包方向需回 ChannelHandler 的注册处核对,本条目不编造。

载荷读取路径

步骤 行 行为
读判别值 ChannelHandler.java:120 payload.readByte()
查类 :121 discriminators.get(discriminator)
侧校验 :126-131 不匹配则 logForgedPackets
反序列化 :134-135 newMsg.readData(payload.slice())

ChannelHandler extends MessageToMessageCodec(:34 导入), 出站方向在 encode 中对称处理(:108 附近用 INBOUNDPACKETTRACKER 追踪原始包)。

与 TileEntity 的关系

相关条目