Galacticraft 封包层:3 个枚举式包表,共 80 个包类型

事实基准:/Users/evlos/a/mirror/Galacticraft(master,minecraftVersion = 1.7.10)逐行读源码。 方向与载荷类型都写死在枚举构造参数里,不是靠 ID 猜的。

封包架构:枚举即「方向 + 载荷类型签名」

core/network/PacketSimple.java:105 起:

public enum EnumSimplePacket {
    // spotless:off
    // SERVER
    S_RESPAWN_PLAYER(Side.SERVER, String.class),                          // :109
    S_TELEPORT_ENTITY(Side.SERVER, String.class, Boolean.class),           // :110
    S_IGNITE_ROCKET(Side.SERVER),                                          // :111
    S_OPEN_SCHEMATIC_PAGE(Side.SERVER, Integer.class),                     // :112
    ...

每个常量的构造参数就是它的完整签名:

参数 含义
第 1 个 Side.SERVER 或 Side.CLIENT —— 这个包发往哪一端
第 2…n 个 Xxx.class —— 载荷各字段的类型

⚠ 方向不是推断的,是枚举里写死的。 (这与 BuildCraft 的「按包类注册侧掩码」不同,见 BuildCraft 封包层。)

3 张包表(集合运算:逐条匹配 NAME(Side.X, ...))

包表 枚举 源码 常量数 SERVER CLIENT
核心 PacketSimple.EnumSimplePacket core/network/PacketSimple.java:105 69 30 39
小行星带 PacketSimpleAsteroids.EnumSimplePacketAsteroids planets/asteroids/network/PacketSimpleAsteroids.java:29 5 1 4
火星 PacketSimpleMars.EnumSimplePacketMars planets/mars/network/PacketSimpleMars.java:34 6 4 2
合计 — — 80 35 45

计数方法:正则 \b([A-Z][A-Z0-9_]*)\s*\(\s*Side\.(SERVER|CLIENT)([^)]*)\) 逐条匹配, 三张表内均无重名。

⚠ 80 是「枚举里声明的包类型数」,不是「switch 分支数」,也不是「实际会发出的包数」。 直接数 case 标签会得到 128(含嵌套 switch 里的重复标签), 直接数标识符会得到 140(把 SERVER / CLIENT 枚举名也数进去)。 三个数字都不等于 80。

载荷长度分布(核心 69 个,按构造参数个数统计)

载荷字段数 包类型数
0 17
1 19
2 12
3 8
4 7
5 3
6 1
10 1
11 1

⚠ 载荷长度极不均匀——从 0 字段到 11 字段。 11 字段的那个包是本 mod 里最重的单包。

小行星带 5 个:字段数 2、2、3、5、8。 火星 6 个:字段数 0、2、3、3、3、5。

关键包(按用途分类,不逐条列举 80 条)

火箭(1.7.10 火箭是 Entity,所以这些包发给实体)

包 方向 说明
S_IGNITE_ROCKET SERVER 点火
S_UPDATE_SHIP_YAW / S_UPDATE_SHIP_PITCH / S_UPDATE_SHIP_MOTION_Y SERVER 姿态 / 高度
C_DISPLAY_ROCKET_CONTROLS CLIENT 火箭控制面板
C_RESPAWN_PLAYER / S_RESPAWN_PLAYER CLIENT / SERVER 玩家重生

另有独立封包类 core/network/PacketRotateRocket.java(旋转火箭), 它不在枚举里,是单独的 IPacket 实现。

空间站

包 方向
S_BIND_SPACE_STATION_ID SERVER
C_UPDATE_SPACESTATION_LIST / C_UPDATE_SPACESTATION_DATA / C_UPDATE_SPACESTATION_CLIENT_ID CLIENT
C_UPDATE_STATION_SPIN / C_UPDATE_STATION_DATA / C_UPDATE_STATION_BOX CLIENT
S_RENAME_SPACE_STATION SERVER
C_UPDATE_WIRE_BOUNDS CLIENT

氧气 / 环境

包 方向
C_AIR_REMAINING CLIENT
C_UPDATE_OXYGEN_VALIDITY CLIENT
C_UPDATE_THERMAL_LEVEL CLIENT
C_UPDATE_ARCLAMP_FACING / S_REQUEST_ARCLAMP_FACING CLIENT / SERVER

GUI

包 方向
C_CLOSE_GUI CLIENT
C_OPEN_PARACHEST_GUI CLIENT
C_OPEN_SPACE_RACE_GUI / C_OPEN_JOIN_RACE_GUI CLIENT
S_OPEN_SCHEMATIC_PAGE SERVER
S_OPEN_FUEL_GUI SERVER
S_OPEN_EXTENDED_INVENTORY SERVER
S_ON_ADVANCED_GUI_CLICKED_INT / S_ON_ADVANCED_GUI_CLICKED_STRING SERVER

装备 / 随身界面:48 个,但在另一张表里

装备包不在 EnumSimplePacket 里,而是独立的 GCPlayerHandler.EnumModelPacket(core/entities/player/GCPlayerHandler.java:1085), 由 PacketSimple 通过 fromOrdinal((Integer) this.data.get(1))(:398)在载荷里再套一层分派。

前缀 数量 覆盖
ADD* 20 面罩、齿轮、左右各 6 个罐位、降落伞、频率模块、4 件热能服
REMOVE* 10 降落伞、频率模块、4 件热能服、左右罐(合并为 REMOVE_LEFT_TANK / REMOVE_RIGHT_TANK)
SHOW* 9 面罩、齿轮、左右罐、频率模块、4 件热能服
HIDE* 9 同 SHOW*
合计 48

⚠ 命名不统一:多数是驼峰(ADDMASK / HIDEGEAR / SHOWLEFTTANK), 少数带下划线(ADD_PARACHUTE / REMOVE_THERMAL_BOOTS / REMOVE_LEFT_TANK)—— 按「驼峰前缀」分组会漏掉下划线那批。

⚠ ADD 有 20 个而 REMOVE 只有 10 个——因为罐位是成对的 (ADDLEFTGRAYTANK…ADDRIGHTGREENTANK 各 6 个 = 12 个 ADD), 而移除只需一个 REMOVE_LEFT_TANK / REMOVE_RIGHT_TANK 即可。 两者数量不对称,不是漏写。

双重分派(易漏)

装备包走两层:

  1. 外层 EnumSimplePacket(如 C_UPDATE_GEAR_SLOT,Side.CLIENT)——方向与封装;
  2. 内层 EnumModelPacket(48 个之一)——具体动作。

⚠ 只统计 EnumSimplePacket 会漏掉这 48 个; 只统计 ADDMASK 之类的标识符又会漏掉外层 69 个。 两个枚举是嵌套关系,不是并列。

其它封包类(不在枚举里)

类 用途 源码
PacketRotateRocket 火箭旋转 core/network/PacketRotateRocket.java
PacketDynamic 动态载荷(实体 / TileEntity 通用) core/network/PacketDynamic.java:20
PacketDynamicInventory 动态背包 core/network/PacketDynamicInventory.java
PacketEntityUpdate 实体更新 core/network/PacketEntityUpdate.java
PacketControllableEntity 可控实体 core/network/PacketControllableEntity.java

PacketDynamic 的判别式是 int 0 / 1(core/network/PacketDynamic.java:54、:57、:87、:100):

判别值 目标 处理
0 Entity entity instanceof IPacketReceiver(:94)
1 TileEntity tile instanceof IPacketReceiver(:110)

服务端侧还有 if (side == Side.SERVER && player instanceof EntityPlayerMP) 守卫(:140、:156)。

接收端

core/network/GalacticraftPacketHandler.java:14:

public class GalacticraftPacketHandler extends SimpleChannelInboundHandler<IPacket> {

IPacket 的两个方向方法是 handleClientSide / handleServerSide, 由 PacketDynamic.handleClientSide(:251 附近)等实现。

独立频道(与包表无关)

core/GalacticraftCore.java:242:

ConnectionPacket.bus = NetworkRegistry.INSTANCE.newEventDrivenChannel(ConnectionPacket.CHANNEL);

⚠ GC 另有一个 FML handshake 频道(ConnectionPacket.CHANNEL), 用于 mod 列表握手,与 80 个游戏包是两条独立通道。

相关条目