|
楼主 |
发表于 2010-2-4 13:58:02
|
显示全部楼层
1. 游戏准备阶段的TCP包
a) 操作码0x01
保持连接存活,也用于游戏进行中。
字节 / 类型
| 用途
| 4 / uint32
| 系统时钟(比如Windows就用GetTickCount()来获得)。
|
b) 操作码0x04
向新加入的玩家发送,告诉他们各个玩家位置的状态及他们所处的位置。
字节 / 类型
| 用途
| 2 / uint16
| 接下去5段信息的总长度(到“开始位置数”为止,不包括本段的2个字节。)
| 1 / uint8
| 玩家位记录的条数,这里记为RN。
| 9 * RN / 玩家位记录 * RN
| 每条玩家位记录代表每个玩家位的详细信息。每条记录的结构如下:
uint8 玩家ID。0为电脑,0xFF为空。
uint8 地图下载进度。0-100,0xFF代表'?'。
uint8 玩家位状态。0-空,1-关闭,2-已有玩家。
uint8 是否电脑。0-活人,1-电脑。
uint8 队伍。0-11,12代表ob/裁判。
uint8 颜色。0-11,12代表ob/裁判。
uint8 种族。
0x01-人类,0x02-兽人,
0x04-暗夜精灵,0x08-亡灵,
0x20-随机,0x40-地图未指定。
uint8 AI等级。0-简单,1-普通,2-疯狂
uint8 生命百分比。
通常为50,60,70,80,90,100。用GHost++可设为其他值。
| 4 / uint32
| 游戏的初始随机种子。
| 1 / uint8
| 队伍和种族锁定标记:
0x01 – 队伍已锁定
0x02 – 种族已锁定
0x04 – 种族为随机(无法与0x02共用)
| 1 / uint8
| 地图开始位置数。
| 1 / uint8
| 为新加入玩家分配的玩家位。
| 16 / sockaddr_in
| 主机用getpeername()获得的目标玩家地址。
|
c) 操作码0x06
向新加入的玩家发送,告诉他们已经在游戏中的玩家列表,每个对应玩家会发一个0x06的包。
字节 / 类型
| 用途
| 4 / uint32
| 始终为0x02,可能是sockaddr_in的结尾数字?
| 1 / uint8
| 在玩家位信息中显示的玩家ID。
| N/以'\\0'结束的字符串
| 玩家名。最长16字节(包括结尾的'\\0')。
| 1 / uint8
| 后续的额外字节数。局域网游戏中总是1。
| N / uint8[N]
| 额外字节。局域网游戏中总是一个\\0字节。
| 16 / sockaddr_in
| 从getpeername()获得的该玩家地址。
| 16 / sockaddr_in
| 从NAT路由(如果有)获得的该玩家地址(似乎只用于Battle.net战网)。
|
d) 操作码0x07
玩家离开游戏时向所有玩家发送。也用于游戏进行中。
字节 / 类型
| 用途
| 1 / uint8
| 玩家ID。
| 4 / uint32
| 离开原因标志。这部分还需进一步研究。
|
e) 操作码0x08
当玩家的地图载入完成后向所有玩家发送(此时主机将会从客户端处收到0x23数据包),这样所有玩家的读取界面上,该玩家的姓名板背景会变成绿色。
字节 / 类型
| 用途
| 1 / uint8
| 玩家ID。
|
f) 操作码0x09
和0x04基本相同,但缺少最后两段。当任何玩家位相关信息发生改变时向所有玩家发送。(比如说正在下载地图,玩家改变位置等等。)
字节 / 类型
| 用途
| 2 / uint16
| 接下去5段信息的总长度(到“开始位置数”为止,不包括本段的2个字节。)
| 1 / uint8
| 玩家位记录的条数,这里记为RN。
| 9 * RN / 玩家位记录 * RN
| 每条玩家位记录代表每个玩家位的详细信息。每条记录的结构如下:
uint8 玩家ID。0为电脑,0xFF为空。
uint8 地图下载进度。0-100,0xFF代表'?'。
uint8 玩家位状态。0-空,1-关闭,2-已有玩家。
uint8 是否电脑。0-活人,1-电脑。
uint8 队伍。0-11,12代表ob/裁判。
uint8 颜色。0-11,12代表ob/裁判。
uint8 种族。
0x01-人类,0x02-兽人,
0x04-暗夜精灵,0x08-亡灵,
0x20-随机,0x40-地图未指定。
uint8 AI等级。0-简单,1-普通,2-疯狂
uint8 生命百分比。
通常为50,60,70,80,90,100。用GHost++可设为其他值。
| 4 / uint32
| 游戏的初始随机种子。
| 1 / uint8
| 队伍和种族锁定标记:
0x01 – 队伍已锁定
0x02 – 种族已锁定
0x04 – 种族为随机(无法与0x02共用)
| 1 / uint8
| 地图开始位置数。
|
g) 操作码0x0A
只包含4字节的包头,当主机按下开始游戏,并开始倒数5秒时发送。
h) 操作码0x0B
只包含4字节的包头,当5秒计时结束时发送,提醒所有玩家进入载入界面。
i) 操作码0x0F
向聊天信息的接收者发送。
如果是私密/小队频道的聊天,而且发送者和接收者可通过TCP连接,那么这个数据包是直接发送的。
否则玩家会先向主机发送一个0x28数据包,主机再发给所有接收者。
注意某些平台会阻断客户端之间的连接,因此所有聊天信息都要通过主机来传递,这就存在潜在的安全问题,可能导致私聊信息泄露。
字节 / 类型
| 用途
| 1 / uint8
| 需发送聊天信息的目标玩家数,这里记为PN
| PN / uint8 * PN
| 每个uint8保存一个目标玩家ID。
| 1 / uint8
| 聊天信息发送者的玩家ID
| 1 / uint8
| 聊天信息标志。
0x10-准备阶段,0x20-游戏阶段
| 4 / uint32
| 发送目标标志。
0x00 – 向所有玩家发送
0x01 – 向盟友发送
0x02 – 向OB/裁判发送
0x03-0x0E – 向特定玩家发送(玩家ID=值-2)
当聊天信息标志为0x10(即游戏准备阶段)时,这段信息将被排除。
| N/以'\\0'结束的字符串
| 聊天字符串。
|
j) 操作码0x1B
只包含4字节的包头,向玩家发布,告诉他们你已断开游戏,即使是主动退出游戏的情况。同样适用于游戏进行阶段。
k) 操作码0x1E
这是当一个玩家加入游戏的时候向主机发送的第一份数据包,包含了该玩家的信息。
字节 / 类型
| 用途
| 4 / uint32
| 游戏ID。
| 4 / uint32
| 游戏开始后经过的毫秒数。
| 1 / uint8
| 始终为0。
| 2 / uint16
| 客户端的游戏端口。用于地图信息交换、直接私聊、主机变更等等。
| 4 / uint32
| 客户端会话计数器。初始值为1,每加入一个游戏都会自增。
| N/以'\\0'结束的字符串
| 用户名。
| 2 / uint16
| 可用的公共端口。这里记为P。
| 16 * P / sockaddr_in * P
| 每个公共端口都有一个套接字sockaddr_in结构。
|
l) 操作码0x21
向主机发送主动离开游戏的信息(主机总是会回复0x1B以断开游戏)。同样适用于游戏进行中。
字节 / 类型
| 用途
| 4 / uint32
| 理由标志。还需进一步研究。
|
m) 操作码0x23
只包含4字节的包头。告诉主机当前玩家已完成游戏载入。
n) 操作码0x28
该数据包有2个功能:
i. 请求主机转发聊天信息。主机会把此信息转发给目标玩家。同样适用于游戏进行阶段。
ii. 在游戏准备阶段对玩家位进行变更。
字节 / 类型
| 用途
| 1 / uint8
| 需要发送聊天信息的玩家总数,这里记为PN
| PN / uint8 * PN
| 每个uint8保存一个需发送聊天信息的玩家ID。
| 1 / uint8
| 聊天信息发送者的玩家ID。
| 1 / uint8
| 聊天信息标志。
0x10 – 游戏准备阶段的聊天
0x11 – 变更小队
0x12 – 变更颜色
0x13 – 变更种族
0x14 – 变更生命百分比
0x20 – 游戏进行阶段的聊天
| 当聊天信息标志 = 0x10或0x20:
字节 / 类型
| 用途
| 4 / uint32
| 发送目标标志。
0x00 – 向所有玩家发送
0x01 – 向盟友发送
0x02 – 向OB/裁判发送
0x03-0x0E – 向特定玩家发送(玩家ID=值-2)
当聊天信息标志为0x10(即游戏准备阶段)时,这段信息将被排除。
| N/以'\\0'结束的字符串
| 聊天信息。
| 当聊天信息标志 = 0x11-0x14:
字节 / 类型
| 用途
| 1 / uint8
| 数据。
聊天信息标志 = 0x11: 小队
聊天信息标志 = 0x12: 颜色
聊天信息标志 = 0x13: 种族
聊天信息标志 = 0x14: 生命百分比
参考0x04/0x09玩家位信息部分。
|
o) 操作码0x3D
由主机发送,询问加入的玩家是否拥有当前地图。
客户端将回复0x42数据包。
字节 / 类型
| 用途
| 4 / uint32
| 地图ID(?)
| N/以'\\0'结束的字符串
| 地图路径
| 4 / uint32
| 地图大小(单位为字节)。
| 4 / uint32
| 整个地图文件的CRC32。
| 4 / uint32
| 地图本地校验码。
| 20 / uint8[20]
| 地图本地SHA-1哈希值,这一段是1.23版后添加的,以防止地图互通。
|
p) 操作码0x3F
当目标玩家没有地图(即玩家向主机发送的0x42数据包中可用地图大小<实际地图大小)的时候发送,客户端能够互相直接连接时也会互相发送。(我注意到可能存在一种操作码0x3E用于向非主机玩家查询地图,但尚未测试。)
字节 / 类型
| 用途
| 4 / uint32
| 地图ID(?)
| 1 / uint8
| 玩家ID
|
q) 操作码0x42
向主机发送,报告自己是否有地图或地图下载进度。
字节 / 类型
| 用途
| 4 / uint32
| 地图ID(?)
| 1 / uint8
| 下载源玩家ID或主机ID
| 4 / uint32
| 可用地图尺寸(下载进度)
|
r) 操作码0x43
向玩家发送地图数据,即传图。
字节 / 类型
| 用途
| 1 / uint8
| 目标玩家ID
| 1 / uint8
| 源玩家ID
| 4 / uint32
| 地图ID(?)
| 4 / uint32
| 地图文件偏移,用于写入数据。
| 4 / uint32
| 后面这段数据的CRC32。
| N / uint8[N]
| 地图数据。
|
s) 操作码0x44
应答0x43数据包,并汇报已下载地图尺寸以示接受。
注意地图发送者并不会等收到这个包后再发送下一个0x43传图包。
字节 / 类型
| 用途
| 1 / uint8
| 目标玩家ID
| 1 / uint8
| 源玩家ID
| 4 / uint32
| 地图ID(?)
| 4 / uint32
| 已下载的地图尺寸。
|
t) 操作码0x45
该数据包用于回复0x3F数据包,以拒绝从目标玩家处下载地图。
字节 / 类型
| 用途
| 1 / uint8
| 目标玩家ID
| 1 / uint8
| 源玩家ID
| 4 / uint32
| 地图ID(?)
|
u) 操作码0x46
用于应答0x01保持连接存活的数据包。同样适用于游戏进行阶段。
字节 / 类型
| 用途
| 4 / uint32
| 与0x01数据包的值相同。
|
|
|