魔兽争霸III数据包规范
2012-09-11 10:02
525 查看
1. 本文涉及的数据包种类
a) 魔兽争霸III拥有以下类型的数据包
i. 局域网UDP数据包。
这类数据包都用于在游戏准备阶段广播/检测游戏信息。
ii. 游戏中TCP数据包。
这类数据包在游戏准备阶段和实际游戏阶段都会被用到。
我会分两部分来介绍这类数据包。
iii. Battle.net TCP/UDP 数据包。
有时间的话,我会用一份单独的doc文档来介绍这部分。
目前可暂且参考 http://www.bnetdocs.org.
b) 本规范中仅讨论前二类数据包。
2. 数据包头
魔兽争霸III中使用的所有数据包都拥有四字节的包头,具体如下表:
3. 局域网UDP数据包
a) 操作码0x2F
这种数据包用于查询局域网游戏,它可用于两种场合:1.应答0x31或0x32数据包以查询指定游戏的信息。2.玩家进入局域网游戏界面时发送。向255.255.255.255广播以查询所有可加入的游戏。
b) 操作码0x30
用于应答UDP 0x2F数据包,该数据包包含完整的游戏信息。
附注(编码字符串):
所有值为偶数的字节都+1。因此所有编码后的字节都是奇数。并用一个控制字节来保存接下去7字节的转换方式。
因为所有空字节都会变成1,因此编码字符串内不会包含空字节。但空字节用于表征字符串的结束。
编码字符串以一个控制字节开头。
控制字节中第1-7位(不包括第0位)分别依次对应控制字节后的7个字节。
第0位无作用,永远设为1。
解码方式如下:
如果对应位为'1',那么该字符不作修改。
如果对应位为'0',那么该字符的值要减去1。
解码完一个控制字节其后的七个字节后,接下去的字节又是一个新的控制字节。
重复操作直到数据流中出现NULL字符。
用C语言解码的样例:
char* EncodedString;
char* DecodedString;
char mask;
int pos=0, dpos=0;
while (EncodedString[pos] != 0)
{
if (pos%8 == 0) mask=EncodedString[pos];
else
{
if ((mask & (0x1 << (pos%8))) == 0)
DecodedString[dpos++] = EncodedString[pos] - 1;
else
DecodedString[dpos++] = EncodedString[pos];
}
pos++;
}
编码方案的另一种理解方式如下:
每个字符的第0位都移到控制字节,然后本身设为1。
解码后字符串的结构:
关于SHA-1哈希和地图校验的算法,我会在另一篇文章里讨论。
c) 操作码0x31
主机建立游戏后会向255.255.255.255广播该数据包。
d) 操作码0x32
游戏内玩家数发生变更后会向255.255.255.255广播该数据包。
e) 操作码0x33
游戏取消后会向255.255.255.255广播该数据包。
4. 游戏准备阶段的TCP包
a) 操作码0x01
保持连接存活,也用于游戏进行中。
b) 操作码0x04
向新加入的玩家发送,告诉他们各个玩家位置的状态及他们所处的位置。
c) 操作码0x06
向新加入的玩家发送,告诉他们已经在游戏中的玩家列表,每个对应玩家会发一个0x06的包。
d) 操作码0x07
玩家离开游戏时向所有玩家发送。也用于游戏进行中。
e) 操作码0x08
当玩家的地图载入完成后向所有玩家发送(此时主机将会从客户端处收到0x23数据包),这样所有玩家的读取界面上,该玩家的姓名板背景会变成绿色。
f) 操作码0x09
和0x04基本相同,但缺少最后两段。当任何玩家位相关信息发生改变时向所有玩家发送。(比如说正在下载地图,玩家改变位置等等。)
g) 操作码0x0A
只包含4字节的包头,当主机按下开始游戏,并开始倒数5秒时发送。
h) 操作码0x0B
只包含4字节的包头,当5秒计时结束时发送,提醒所有玩家进入载入界面。
i) 操作码0x0F
向聊天信息的接收者发送。
如果是私密/小队频道的聊天,而且发送者和接收者可通过TCP连接,那么这个数据包是直接发送的。
否则玩家会先向主机发送一个0x28数据包,主机再发给所有接收者。
注意某些平台会阻断客户端之间的连接,因此所有聊天信息都要通过主机来传递,这就存在潜在的安全问题,可能导致私聊信息泄露。
j) 操作码0x1B
只包含4字节的包头,向玩家发布,告诉他们你已断开游戏,即使是主动退出游戏的情况。同样适用于游戏进行阶段。
k) 操作码0x1E
这是当一个玩家加入游戏的时候向主机发送的第一份数据包,包含了该玩家的信息。
l) 操作码0x21
向主机发送主动离开游戏的信息(主机总是会回复0x1B以断开游戏)。同样适用于游戏进行中。
m) 操作码0x23
只包含4字节的包头。告诉主机当前玩家已完成游戏载入。
n) 操作码0x28
该数据包有2个功能:
i. 请求主机转发聊天信息。主机会把此信息转发给目标玩家。同样适用于游戏进行阶段。
ii. 在游戏准备阶段对玩家位进行变更。
当聊天信息标志 = 0x10或0x20:
当聊天信息标志 = 0x11-0x14:
o) 操作码0x3D
由主机发送,询问加入的玩家是否拥有当前地图。
客户端将回复0x42数据包。
p) 操作码0x3F
当目标玩家没有地图(即玩家向主机发送的0x42数据包中可用地图大小<实际地图大小)的时候发送,客户端能够互相直接连接时也会互相发送。(我注意到可能存在一种操作码0x3E用于向非主机玩家查询地图,但尚未测试。)
q) 操作码0x42
向主机发送,报告自己是否有地图或地图下载进度。
r) 操作码0x43
向玩家发送地图数据,即传图。
s) 操作码0x44
应答0x43数据包,并汇报已下载地图尺寸以示接受。
注意地图发送者并不会等收到这个包后再发送下一个0x43传图包。
t) 操作码0x45
该数据包用于回复0x3F数据包,以拒绝从目标玩家处下载地图。
u) 操作码0x46
用于应答0x01保持连接存活的数据包。同样适用于游戏进行阶段。
5. 游戏中TCP数据包
a) 操作码0x0C
游戏数据包,每100毫秒向局域网中所有玩家发送(战网上是250毫秒,有工具可以调整这个值。)。
如果游戏数据超过1446字节,整段数据将被分割成若干个0x48数据包,并以一个0x0C数据包结尾。这是为了避免某些路由的最大传输单位限制。
游戏数据与录像数据相同因此其格式可以参考以下文档:
http://www.repking.com.cn/w3g_actions.txt
http://www.repking.com.cn/w3g_format.txt
b) 操作码0x0E
这种数据包很少见,只在游戏不同步时发送。尚需进一步研究。
c) 操作码0x14
向玩家发送,告诉他们:你已经被主机踢了。(比如主机离开游戏)
d) 操作码0x48
就是缺少游戏已用时间的游戏数据包,用于游戏数据分多个包发送的情况。
e) 操作码0x26
当玩家进行了一些操作时发送给主机。主机会收集所有玩家的操作并发回包含所有玩家操作的0x0C/0x48数据包作为应答。
f) 操作码0x27
同步数据包,当收到0x0C游戏数据包时发送给主机。
主机将在本地计算哈希值,并与每个玩家的0x27数据包比较。一旦不同步现象产生,即0x27数据包的哈希值与主机计算不符,该玩家将立刻被断开。
a) 魔兽争霸III拥有以下类型的数据包
i. 局域网UDP数据包。
这类数据包都用于在游戏准备阶段广播/检测游戏信息。
ii. 游戏中TCP数据包。
这类数据包在游戏准备阶段和实际游戏阶段都会被用到。
我会分两部分来介绍这类数据包。
iii. Battle.net TCP/UDP 数据包。
有时间的话,我会用一份单独的doc文档来介绍这部分。
目前可暂且参考 http://www.bnetdocs.org.
b) 本规范中仅讨论前二类数据包。
2. 数据包头
魔兽争霸III中使用的所有数据包都拥有四字节的包头,具体如下表:
字节 / 类型 | 用途 |
1 / uint8 | 魔数标志位。 0xF7 – 局域网UDP或游戏中TCP数据包(本文中所有数据包都采用这个标志) 0xFF -- Battle.net战网数据包 |
1 / uint8 | 操作码。详情参考第3、4、5部分。 |
2 / uint16 | 数据包长度(包括4字节的包头部分)。 |
a) 操作码0x2F
这种数据包用于查询局域网游戏,它可用于两种场合:1.应答0x31或0x32数据包以查询指定游戏的信息。2.玩家进入局域网游戏界面时发送。向255.255.255.255广播以查询所有可加入的游戏。
字节 / 类型 | 用途 |
4 / uint32 | 以低位在前的方式表示游戏类型。 'W3XP' = TFT 'WAR3' = ROC |
4 / uint32 | 游戏版本。 比如War3 1.24,这里就填24。 |
4 / uint32 | 游戏ID, 广播时置零。 |
用于应答UDP 0x2F数据包,该数据包包含完整的游戏信息。
字节 / 类型 | 用途 |
4 / uint32 | 以低位在前的方式表示操作系统信息。 'IX86' = Windows 'XMAC' = Mac OS X |
4 / uint32 | 以低位在前的方式表示游戏类型。 |
4 / uint32 | 游戏ID。 |
4 / uint32 | 系统时钟(比如Windows就用GetTickCount()来获得)。 |
N/以'\0'结束的字符串 | 这是一个经过编码的字符串,包含着大量重要的游戏信息。参考附注。 |
4 / uint32 | 玩家位置数。 |
4 / uint32 | 游戏标志。据我所知 0x01 = 剧情游戏;0x09 = 自定义游戏。 |
4 / uint32 | 游戏内玩家数。 |
4 / uint32 | 非电脑玩家位置数。 综上所述,我们可以得出这样的公式:显示的游戏内玩家数=游戏内玩家数+(位置数-非电脑位置数) |
4 / uint32 | 未知。通常是0-0x80 |
2 / uint16 | 以低位在前方式表示用于侦听连接的TCP游戏端口。 |
所有值为偶数的字节都+1。因此所有编码后的字节都是奇数。并用一个控制字节来保存接下去7字节的转换方式。
因为所有空字节都会变成1,因此编码字符串内不会包含空字节。但空字节用于表征字符串的结束。
编码字符串以一个控制字节开头。
控制字节中第1-7位(不包括第0位)分别依次对应控制字节后的7个字节。
第0位无作用,永远设为1。
解码方式如下:
如果对应位为'1',那么该字符不作修改。
如果对应位为'0',那么该字符的值要减去1。
解码完一个控制字节其后的七个字节后,接下去的字节又是一个新的控制字节。
重复操作直到数据流中出现NULL字符。
用C语言解码的样例:
char* EncodedString;
char* DecodedString;
char mask;
int pos=0, dpos=0;
while (EncodedString[pos] != 0)
{
if (pos%8 == 0) mask=EncodedString[pos];
else
{
if ((mask & (0x1 << (pos%8))) == 0)
DecodedString[dpos++] = EncodedString[pos] - 1;
else
DecodedString[dpos++] = EncodedString[pos];
}
pos++;
}
编码方案的另一种理解方式如下:
每个字符的第0位都移到控制字节,然后本身设为1。
解码后字符串的结构:
字节 / 类型 | 用途 |
4 / uint32 | 游戏设置。 |
1 / uint8 | 永远为0。 |
2 / uint16 | 地图宽度。 |
2 / uint16 | 地图高度。 |
4 / uint32 | 地图本地校验码。 |
N/以'\0'结束的字符串 | 地图名。 |
N/以'\0'结束的字符串 | 主机用户名。 |
1 / uint8 | 永远为0(也算个以'\0'结束的字符串?) |
20 / uint8[20] | 地图本地SHA-1哈希值,这一段是1.23版后添加的,以防止地图互通。 |
c) 操作码0x31
主机建立游戏后会向255.255.255.255广播该数据包。
字节 / 类型 | 用途 |
4 / uint32 | 以低位在前的方式表示游戏类型。 |
4 / uint32 | 游戏版本。 |
4 / uint32 | 游戏ID(初始为1,随着逐个游戏的创建而自增)。 |
游戏内玩家数发生变更后会向255.255.255.255广播该数据包。
字节 / 类型 | 用途 |
4 / uint32 | 游戏ID。 |
4 / uint32 | 显示的游戏内玩家数。 |
4 / uint32 | 玩家位置总数。 |
游戏取消后会向255.255.255.255广播该数据包。
字节 / 类型 | 用途 |
4 / uint32 | 游戏ID |
a) 操作码0x01
保持连接存活,也用于游戏进行中。
字节 / 类型 | 用途 |
4 / uint32 | 系统时钟(比如Windows就用GetTickCount()来获得)。 |
向新加入的玩家发送,告诉他们各个玩家位置的状态及他们所处的位置。
字节 / 类型 | 用途 |
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()获得的目标玩家地址。 |
向新加入的玩家发送,告诉他们已经在游戏中的玩家列表,每个对应玩家会发一个0x06的包。
字节 / 类型 | 用途 |
4 / uint32 | 始终为0x02,可能是sockaddr_in的结尾数字? |
1 / uint8 | 在玩家位信息中显示的玩家ID。 |
N/以'\0'结束的字符串 | 玩家名。最长16字节(包括结尾的'\0')。 |
1 / uint8 | 后续的额外字节数。局域网游戏中总是1。 |
N / uint8 | 额外字节。局域网游戏中总是一个\0字节。 |
16 / sockaddr_in | 从getpeername()获得的该玩家地址。 |
16 / sockaddr_in | 从NAT路由(如果有)获得的该玩家地址(似乎只用于Battle.net战网)。 |
玩家离开游戏时向所有玩家发送。也用于游戏进行中。
字节 / 类型 | 用途 |
1 / uint8 | 玩家ID。 |
4 / uint32 | 离开原因标志。这部分还需进一步研究。 |
当玩家的地图载入完成后向所有玩家发送(此时主机将会从客户端处收到0x23数据包),这样所有玩家的读取界面上,该玩家的姓名板背景会变成绿色。
字节 / 类型 | 用途 |
1 / uint8 | 玩家ID。 |
和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 | 地图开始位置数。 |
只包含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'结束的字符串 | 聊天字符串。 |
只包含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结构。 |
向主机发送主动离开游戏的信息(主机总是会回复0x1B以断开游戏)。同样适用于游戏进行中。
字节 / 类型 | 用途 |
4 / uint32 | 理由标志。还需进一步研究。 |
只包含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 – 游戏进行阶段的聊天 |
字节 / 类型 | 用途 |
4 / uint32 | 发送目标标志。 0x00 – 向所有玩家发送 0x01 – 向盟友发送 0x02 – 向OB/裁判发送 0x03-0x0E – 向特定玩家发送(玩家ID=值-2) 当聊天信息标志为0x10(即游戏准备阶段)时,这段信息将被排除。 |
N/以'\0'结束的字符串 | 聊天字符串。 |
字节 / 类型 | 用途 |
1 / uint8 | 数据。 聊天信息标志 = 0x11: 小队 聊天信息标志 = 0x12: 颜色 聊天信息标志 = 0x13: 种族 聊天信息标志 = 0x14: 生命百分比 参考0x04/0x09玩家位信息部分。 |
由主机发送,询问加入的玩家是否拥有当前地图。
客户端将回复0x42数据包。
字节 / 类型 | 用途 |
4 / uint32 | 地图ID(?) |
N/以'\0'结束的字符串 | 地图路径 |
4 / uint32 | 地图大小(单位为字节)。 |
4 / uint32 | 整个地图文件的CRC32。 |
4 / uint32 | 地图本地校验码。 |
20 / uint8[20] | 地图本地SHA-1哈希值,这一段是1.23版后添加的,以防止地图互通。 |
当目标玩家没有地图(即玩家向主机发送的0x42数据包中可用地图大小<实际地图大小)的时候发送,客户端能够互相直接连接时也会互相发送。(我注意到可能存在一种操作码0x3E用于向非主机玩家查询地图,但尚未测试。)
字节 / 类型 | 用途 |
4 / uint32 | 地图ID(?) |
1 / uint8 | 玩家ID |
向主机发送,报告自己是否有地图或地图下载进度。
字节 / 类型 | 用途 |
4 / uint32 | 地图ID(?) |
1 / uint8 | 下载源玩家ID或主机ID |
4 / uint32 | 可用地图尺寸(下载进度) |
向玩家发送地图数据,即传图。
字节 / 类型 | 用途 |
1 / uint8 | 目标玩家ID |
1 / uint8 | 源玩家ID |
4 / uint32 | 地图ID(?) |
4 / uint32 | 地图文件偏移,用于写入数据。 |
4 / uint32 | 后面这段数据的CRC32。 |
N / uint8 | 地图数据。 |
应答0x43数据包,并汇报已下载地图尺寸以示接受。
注意地图发送者并不会等收到这个包后再发送下一个0x43传图包。
字节 / 类型 | 用途 |
1 / uint8 | 目标玩家ID |
1 / uint8 | 源玩家ID |
4 / uint32 | 地图ID(?) |
4 / uint32 | 已下载的地图尺寸。 |
该数据包用于回复0x3F数据包,以拒绝从目标玩家处下载地图。
字节 / 类型 | 用途 |
1 / uint8 | 目标玩家ID |
1 / uint8 | 源玩家ID |
4 / uint32 | 地图ID(?) |
用于应答0x01保持连接存活的数据包。同样适用于游戏进行阶段。
字节 / 类型 | 用途 |
4 / uint32 | 与0x01数据包的值相同。 |
a) 操作码0x0C
游戏数据包,每100毫秒向局域网中所有玩家发送(战网上是250毫秒,有工具可以调整这个值。)。
字节 / 类型 | 用途 |
2 / uint16 | 游戏已用时间,单位是毫秒。 |
2 / uint16 | 下一段数据的CRC32的低16位。 注意:如果游戏数据为空,这段数据本身也会被排除,这样整个包就只有6字节。 |
N / uint8 | 游戏数据。 |
游戏数据与录像数据相同因此其格式可以参考以下文档:
http://www.repking.com.cn/w3g_actions.txt
http://www.repking.com.cn/w3g_format.txt
b) 操作码0x0E
这种数据包很少见,只在游戏不同步时发送。尚需进一步研究。
c) 操作码0x14
向玩家发送,告诉他们:你已经被主机踢了。(比如主机离开游戏)
字节 / 类型 | 用途 |
1 / uint8 | 玩家ID |
就是缺少游戏已用时间的游戏数据包,用于游戏数据分多个包发送的情况。
字节 / 类型 | 用途 |
2 / uint16 | 游戏已用时间,单位是毫秒。这里始终是0。 |
2 / uint16 | 下一段数据的CRC32的低16位。 注意:如果游戏数据为空,这段数据本身也会被排除,这样整个包就只有6字节。 |
N / uint8 | 游戏数据。 |
当玩家进行了一些操作时发送给主机。主机会收集所有玩家的操作并发回包含所有玩家操作的0x0C/0x48数据包作为应答。
字节 / 类型 | 用途 |
N / uint8 | 玩家操作数据,参考0x0C以获得更多信息。 |
同步数据包,当收到0x0C游戏数据包时发送给主机。
字节 / 类型 | 用途 |
4 / uint32 | 同步哈希值。 |
相关文章推荐
- 开源项目之魔兽争霸III外挂程序 Warkeys
- 魔兽争霸III 1.20, 1.21 1.22 需要特定语言版本之Window 解决办法
- 魔兽争霸III 1.20, 1.21 1.22 需要特定语言版本之Window 解决办法
- 魔兽争霸III - 十大魔法排行榜
- 魔兽争霸war3心得体会(二):狗转蜘蛛,DK光环+游侠二发
- 魔兽争霸war3心得体会(三):UD内战
- 工具接口标准(TIS)可执行链接格式(ELF)规范-卷III-操作系统特性(Operating System Specific)-对象文件
- 魔兽争霸war3心得体会(二):狗转蜘蛛,DK光环+游侠二发
- 魔兽争霸war3心得体会(二):狗转蜘蛛,DK光环+游侠二发
- 魔兽争霸——《冰封王座》2007魔兽比赛背景音乐下载
- 魔兽争霸war3心得体会(一):UD的冰甲蜘蛛流
- 魔兽争霸作弊秘籍
- 魔兽争霸-提高你20%的微操水平(转帖)
- 魔兽争霸war3心得体会(二):狗转蜘蛛,DK光环+游侠二发
- 魔兽争霸Trigger学习教程(0)
- 工具接口标准(TIS)可执行链接格式(ELF)规范-卷III-操作系统特性-程序加载和动态链接(一)
- 魔兽争霸显血改键工具 1.4
- 魔兽争霸war3在笔记本电脑windows7 无法全屏 解决方案
- 基于 Unity3D 的 MOBA 游戏架构 - 开始:魔兽争霸 3(一)
- 魔兽争霸之PHP设计模式-工厂模式[Factory]