Skip to content

俄罗斯方块相关 API

面向官方服 api.php 的 JSON 协议:活动初始化、开局、结算与 sign。正文外层的 URL 公参 + body 编码、响应解码《客户端 API》 一致,本节只写 tetris / hdCommon 业务树。


1. 模块与调用顺序

典型一条龙(具体 act_id、返回路径以你当前包体为准):

  1. hdCommon.hdGetInitInfo(可选但常见):拉活动静态配置、关卡列表等。
  2. tetris.start:选关卡 stage_id,服务端下发本局 game_key
  3. 客户端本地对局,产生战报 battle_seq 等。
  4. tetris.finish:带上战报、game_keysign 等提交结算。

与「方块」同活动链上,抓包里常出现 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_idnumber关卡 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_idnumber须与本次 start 一致。
game_keystring须与本次 start 返回一致;参与 sign 计算。
battle_seqobject战报序列,结构大、不参与下文「排序键 sign」拼接串(见第 5 节)。
cost_timenumber本局耗时(秒或包内约定单位),须在合理区间,且与 battle_seq 时长逻辑大致自洽。
remain_hpnumber结算时城门/基地剩余血量等,上限常可与 battle_seq.gate_hp_max 对齐。
starnumber星级评价。
kill_expnumber击杀经验类统计。
skill_usedarray本局使用技能列表;空数组常见。不参与排序 sign 串。
is_winnumber是否胜利,1 / 0 等以包为准。
tnumber时间戳;常见为 Unix 秒 Math.floor(Date.now()/1000)不要带毫秒,否则易与客户端不一致。
signstring小写 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_timespawn/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

  • numberString(i),拼接为 o=123(无引号)。
  • stringJSON.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_keystart 下发的原始字符串(无额外引号):

text
plain = build(finish对象) + game_key
sign  = MD5(plain)   // 小写 hex,与 md5 库默认一致

注意buildstring 类型的 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=1777672274

5.4 与「固定顺序拼串」的对照

部分对照实现为调试方便,会用固定键序直接拼一段与 build 等价的串(例如按 cost_timegame_key(带引号)→ is_win → … → t)。若你本地算签与服不一致,依次检查:

  1. t 是否秒级、是否与客户端发包时间一致。
  2. game_key 在拼串里是否带双引号、末尾再拼的裸 game_key 是否完全一致。
  3. 是否误把 battle_seqskill_used 编进排序串
  4. JSON.stringify 与键序:若你走 JSON.stringify(body)+salt 算 URL 的 sg,与这里 finish 子对象上的 build 不是同一套规则,勿混用。