所有控制与游戏数据默认使用同一个 IPv4 UDP 42056 端点。多字节整数采用网络字节序。
每个数据报由 40 字节头、可变负载和 16 字节认证标签组成。
| 字段 | 类型 | 含义 |
|---|---|---|
| magic | 4 bytes | 固定为 C6R1 |
| version | u8 | 协议版本 1 |
| kind | u8 | 控制或数据消息类型 |
| flags | u16 | 已认证、广播、已分片 |
| room_id | u64 | 服务端生成的房间标识 |
| source_member | u8 | 发送者 ID 2..9;服务端控制消息为 0 |
| target_member | u8 | 接收者 ID;广播转发前为 255 |
| fragment_index/count | u16/u16 | 从零开始的分片位置和总数 |
| source_port/target_port | u16/u16 | 原始 Civ 6 UDP 源端口和目标端口 |
| payload_len | u16 | 当前帧的负载长度 |
| sequence | u64 | 会话内防重放序列号 |
| packet_id | u32 | 原始 UDP 数据报标识 |
| payload | bytes | JSON 控制消息或 Civ 6 UDP 负载分片 |
| tag | 16 bytes | HMAC-SHA256 的前 16 字节 |
CREATE、JOIN、WELCOME 和初始 ERROR 不认证。WELCOME 返回随机 32 字节成员令牌;之后的每个帧都使用该令牌签名。中转服验证 256 包滑动重放窗口,并使用接收者令牌重新签名转发帧。
- 房主通过
CREATE发送请求 ID 和昵称。 - 中转服通过
WELCOME返回 10 位房间码、房间 ID、成员 ID、令牌和成员列表。 - 其他客户端通过
JOIN和房间码加入,并取得各自凭据。 PEERS通知成员变化;PING/PONG保持 NAT 映射并测量 RTT。- 目标为
255的DATA转发给房间内其他在线成员;普通目标只转发给对应成员。 LEAVE移除普通成员;房主LEAVE关闭整个房间。
外层 UDP 数据报最大为 1200 字节。更大的游戏 UDP 数据报只做分片和两秒内的乱序重组,不提供可靠重传,保持 UDP 语义。
- 发往
255.255.255.255:62900–62999的发现包被复制到中转房间,同时原包继续进入真实 LAN。 - 房间成员在每台客户端上被映射到一个无冲突的 RFC1918
/24虚拟前缀,成员 ID 对应最后一个字节。 - 发往虚拟成员地址的 UDP 单播被捕获而不会进入默认网关。
- 接收端保留原 UDP 端口,以发送者虚拟地址为源地址构造 IPv4/UDP 包并注入 inbound 网络路径。
- 每 5 秒发送保活。
- 30 秒未收到认证包后成员显示离线。
- 成员 ID 保留 60 秒;认证流量可以更新 NAT 端点。
- 房主主动离开或超时后关闭房间。
- 每个房间最多 8 人,服务端最多保存 1024 个内存房间。
- 单成员限制为 5000 包/秒和 10 Mbps;创建/加入请求另有按来源地址限流。
协议可防止离线路令牌猜测、伪造认证包和重放。初始握手和游戏负载不加密,中转服可以看到负载。因此 v1 仅面向熟人使用的自建中转服,不适合作为公开多租户服务。