Appearance
俄罗斯方块相关 API
面向官方服 api.php 的 JSON 协议:活动初始化、开局、结算与 sign。正文外层的 URL 公参 + body 编码、响应解码 与 《客户端 API》 一致,本节只写 tetris / hdCommon 业务树。
1. 模块与调用顺序
典型一条龙(具体 act_id、返回路径以你当前包体为准):
hdCommon.hdGetInitInfo(可选但常见):拉活动静态配置、关卡列表等。tetris.start:选关卡stage_id,服务端下发本局game_key。- 客户端本地对局,产生战报
battle_seq等。 tetris.finish:带上战报、game_key、sign等提交结算。
与「方块」同活动链上,抓包里常出现 hdGetInitInfo + tetris.start + tetris.finish 组合。
2. 活动初始化:hdCommon.hdGetInitInfo
用于取活动维度数据(商店、任务、关卡元数据等),act_id 与包内活动配置一致。示例形状:
json
{
"hdCommon": {
"hdGetInitInfo": {
"act_id": 4300
}
}
}act_id:活动 ID,须与当前开放方块活动一致;换包或换活动需改抓包对照。- 返回结构一般落在
a.hdCommon或并列的a.tetris等分支下,解析时以实际 JSON 为准。
3. 开局:tetris.start
3.1 请求体
json
{
"tetris": {
"start": {
"stage_id": 19
}
}
}| 字段 | 类型 | 说明 |
|---|---|---|
tetris.start.stage_id | number | 关卡 ID,与配置表、活动数据一致。 |
3.2 返回里要留什么给 finish
结算必须带 game_key,且与 stage_id 为同一局 start 的返回。
抓包/对照实现里,常见路径形如:
text
a.tetris.start_challenge.game_key(不同版本可能挂在 a.tetris.* 其它节点;以你包内 start 响应为准。)
其它字段(如本局种子、时限等)若客户端逻辑依赖,一并从 start 响应里取,勿手写。
4. 结算:tetris.finish
4.1 请求体骨架
json
{
"tetris": {
"finish": {
"stage_id": 19,
"game_key": "<与 start 一致>",
"battle_seq": { },
"cost_time": 192,
"remain_hp": 35,
"star": 3,
"kill_exp": 30,
"skill_used": [],
"is_win": 1,
"t": 1777672274,
"sign": "<见第 5 节>"
}
}
}4.2 tetris.finish 顶层字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
stage_id | number | 须与本次 start 一致。 |
game_key | string | 须与本次 start 返回一致;参与 sign 计算。 |
battle_seq | object | 战报序列,结构大、不参与下文「排序键 sign」拼接串(见第 5 节)。 |
cost_time | number | 本局耗时(秒或包内约定单位),须在合理区间,且与 battle_seq 时长逻辑大致自洽。 |
remain_hp | number | 结算时城门/基地剩余血量等,上限常可与 battle_seq.gate_hp_max 对齐。 |
star | number | 星级评价。 |
kill_exp | number | 击杀经验类统计。 |
skill_used | array | 本局使用技能列表;空数组常见。不参与排序 sign 串。 |
is_win | number | 是否胜利,1 / 0 等以包为准。 |
t | number | 时间戳;常见为 Unix 秒 Math.floor(Date.now()/1000),不要带毫秒,否则易与客户端不一致。 |
sign | string | 小写 32 位 MD5 十六进制;算法见第 5 节。 |
4.3 battle_seq 子结构(示例级说明)
战报用于复现对局统计,字段名与数组长度以当前包为准。下面是与抓包/对照实现常见对齐的形状示例(数值仅作类型参考):
json
{
"tetris_soldier_num": [1, 1, 2, 2, 1],
"my_spawn_count": 52,
"enemy_spawn_count": 30,
"my_die_count": 40,
"enemy_die_count": 30,
"enemy_kill_ids": [401, 401, 402, 403],
"gate_hp_max": 35,
"gate_damage_total": 0,
"gate_hit_times": 0,
"round_total": 3,
"create_soldier": {
"1": { "soldier_num": 13, "soldier_attack": 78 },
"2": { "soldier_num": 6, "soldier_attack": 82 }
}
}| 字段 | 说明 |
|---|---|
tetris_soldier_num | 与回合/出兵相关的整数序列,长度与规则由客户端生成。 |
my_spawn_count / enemy_spawn_count | 双方出兵次数类统计。 |
my_die_count / enemy_die_count | 死亡统计。 |
enemy_kill_ids | 击杀单位 id 序列。 |
gate_hp_max | 城门血量上限;常与 remain_hp 一致或为其上界。 |
gate_damage_total / gate_hit_times | 承伤、受击次数。 |
round_total | 回合数。 |
create_soldier | 按槽位/类型 id(字符串 key)统计生成兵力与攻击力。 |
服务端可能对 cost_time、spawn/die 计数、gate 相关 做一致性校验;伪造数据易导致失败或风控,复现协议时尽量 录真实 battle_seq 再改少量标量 做实验。
5. sign 计算(重点)
5.1 不参与拼接的键(客户端反编译逻辑)
对 tetris.finish 这一层对象(即上表「顶层字段」那一层,不要把整个 battle_seq 拆进排序里)做 sign 时,常见实现会 跳过:
md5(若存在占位)battle_seq(整块对象不参与拼串)skill_used
其余标量字段进入「键排序 → k=v 拼接」流程;battle_seq 仍要作为 JSON 字段出现在请求体里,只是不算进 MD5 明文串。
5.2 类型与 k=v 规则(build 伪代码)
对参与签名的每个 key o,取值为 i:
number→String(i),拼接为o=123(无引号)。string→JSON.stringify(i),拼接为o="abc"(带双引号)。- 其它类型 → 客户端实现常直接
return,不参与(以你反编译为准)。
排序规则:Object.keys(对象).sort() 后按序拼接,用 & 连接。
javascript
function build(t) {
const parts = []
Object.keys(t).sort().forEach(function (o) {
if (o === 'md5' || o === 'battle_seq' || o === 'skill_used') return
const i = t[o]
if (i == null) return
let n
if (typeof i === 'number') n = String(i)
else if (typeof i === 'string') n = JSON.stringify(i)
else return
parts.push(o + '=' + n)
})
return parts.join('&')
}5.3 最终 MD5
记 game_key 为 start 下发的原始字符串(无额外引号):
text
plain = build(finish对象) + game_key
sign = MD5(plain) // 小写 hex,与 md5 库默认一致注意:build 对 string 类型的 game_key 会产出 game_key="xxx"(xxx 两侧双引号来自 JSON.stringify)。MD5 的输入明文为:
text
plain = <build 输出的整段 & 拼接> + <start 下发的 game_key 原始值,不再加引号>示意:
text
...&game_key="19_23"&is_win=1&...&t=1777672274
19_23第二行即再拼接一次的 game_key 本体(与 start 返回字符串逐字符相同)。对 plain 全文做一次 MD5(小写 hex),写入 tetris.finish.sign。
示例拼串(仅演示形态,勿照抄数值):
text
cost_time=192&game_key="19_23"&is_win=1&kill_exp=30&remain_hp=35&stage_id=19&star=3&t=17776722745.4 与「固定顺序拼串」的对照
部分对照实现为调试方便,会用固定键序直接拼一段与 build 等价的串(例如按 cost_time → game_key(带引号)→ is_win → … → t)。若你本地算签与服不一致,依次检查:
t是否秒级、是否与客户端发包时间一致。game_key在拼串里是否带双引号、末尾再拼的裸game_key是否完全一致。- 是否误把
battle_seq或skill_used编进排序串。 JSON.stringify与键序:若你走JSON.stringify(body)+salt算 URL 的sg,与这里finish子对象上的build不是同一套规则,勿混用。