API 目前处于 Early Preview 阶段, 可能存在诸多不完善与错误之处,欢迎加群交流反馈:加入官方交流群(1073434398)
Arcaea
arcaea 的 Profile 与 Score 格式:arcaeaId/character 身份、player/native 的 potential 统计、score.native 的判定位图字段、服务端算的单曲潜力值与 Best 50 桶。
本页是 arcaea 在 RankHub 上的字段级格式说明。arcaea 与 maimai 一样属于
服务端算分族:单曲潜力值(ptt)由服务端按 score + 曲库定数重算,不看调用方传的 rating。
机器可读版本
GET /v1/games/arcaea/format 返回与本页一致的格式数据(同一份字段表)。
文档可能滞后,以端点返回为准。
arcaea 的评分由服务端算
推成绩时 scores[].rating 对 arcaea 无效:服务端用 score(与 clearType)从曲库定数重算单曲 ptt。
另外 arcaea 的 achievements 恒为 null:它没有「达成率」这个统一字段的对应概念。
Profile 格式
身份字段(建档用)
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
arcaeaId | number | 是 | Arcaea ID(9 位数字) | 123456789 |
character | string | 是 | 当前搭档 id(与曲库 characters 对照校验);空串 ⇒ 该游戏既有服务返回 400 | "character_1" |
friendCode | string | 否 | 9 位好友码(好友码导入链路的标识,也是身份列之一) | "123456789" |
character虽然来自「玩家资料」而不是「账号标识」,但建档必须有它(既有服务校验), 所以它是身份字段而不是可选展示字段。syncCapable恒为false。name也是建档必填项,但它是统一字段(player.name)而不是身份键,所以不在上表;10 个游戏一致。
统一字段(player)
| 字段 | 类型 | 可空 | 单位 | 说明 |
|---|---|---|---|---|
name | string | 可空 | — | 显示名 |
rating | number | 可空 | Potential(小数 3 位) | 取 potential.potential;不是桶内合计(见「最佳成绩桶」) |
原生字段(player.native)
| 原生字段(wire 键) | 类型 | 单位 / 取值 | 语义 | 可空 |
|---|---|---|---|---|
arcaeaId | number | 9 位 | Arcaea ID(原生 arcaea_id) | 可空 |
course | number | 整数 | course 值;语义未在代码/文档里定义(只做透传) | 可空 |
character | string | 搭档 id | 当前搭档(原生是整数,wire 上是字符串) | 可空 |
friendCode | string | 9 位数字 | 好友码(原生 friend_code) | 可空 |
b30Avg | number | Potential | 「前 30 平均值」;原生没有这个指标,是 RankHub 自己算的 | 可空 |
b50Avg | number | Potential | 「前 50 平均值」;同样是 RankHub 自算 | 可空 |
avatar/nameplate是档案里的可空展示字段,不在player.native里。potential.potential走统一字段player.rating;其余 potential 统计(b10_avg、speculate_r10_avg、max_potential)只在bests.totals里出现,不重复进native。
Score 格式
成绩键与比较值
| 项 | 值 | 说明 |
|---|---|---|
keyFields | songId / difficulty | 一条成绩 = 曲目 + 难度(难度是 0~5 的数字,wire 上 difficulty 是它的字符串形式) |
compareField | score | 「只升不降」按得分比较(0~10,000,000+) |
ratingField | rating | 单曲评分字段是统一 rating(原生字段 potential)。值由服务端算:上游自 v4.4.6 起不再返回单曲 ptt |
difficulty取值:0=PST、1=PRS、2=FTR、3=BYD、4=ETR、5=INS。- wire 上
difficulty是数字的字符串(如"2"),levelIndex是同一个数字的数值形式; 要按难度过滤(?difficulty=2)时传"2"。 - 比
score时不要用achievements:arcaea 的achievements恒null。
本页
keyFields/compareField/ratingField里的名字都是 v1 wire 字段名(GameScoreDto的顶层字段);游戏原生列名写在说明列。
统一字段
arcaea 会填的统一字段:
| 字段 | 类型 | 单位 / 量纲 | 可空 | 说明 |
|---|---|---|---|---|
scoreId | string | — | 否 | 成绩行 id |
songId | string | — | 否 | 曲目 id(曲库 songlist 的 id) |
difficulty | string | "0"~"5" | 可空 | 难度(数字串) |
levelIndex | number | 0~5 | 可空 | 难度下标(数值形式) |
score | number | 0~10,000,000+ | 可空 | 得分(比较值);全大 Pure 时可超过 1,000 万 |
rating | number | 小数,3 位 | 可空 | 单曲潜力值(服务端算) |
rank | string | EX+ / EX / AA / A / B / C / D | 可空 | 评级(按 score 分档,服务端算) |
playTime | string(RFC3339) | — | 可空 | 游玩时间(原生 Unix 秒) |
恒为 null 的字段:achievements(arcaea 没有达成率概念)、songName、type、level、
fc / fs(全连语义在 native.clearType 里)、dxScore / dxStar。
原生字段(score.native)
arcaea 的 score.native 是固定的 9 个键:
| 原生字段(wire 键) | 类型 | 单位 / 取值 | 语义 | 可空 |
|---|---|---|---|---|
scoreBelowMax | number | 整数 | 「距理论值的差值」(原生 score_below_max);理论值 = 1,000 万 + 大 Pure 数,所以不等于 10,000,000 - score | 可空 |
clearType | number | 0~5 | 本次通关类型:0=Track Lost、1=Normal Clear、2=Full Recall、3=Pure Memory、4=Easy Clear、5=Hard Clear。决定 +0.2 通关奖励 | 可空 |
bestClearType | number | 0~5 | 该谱面历史最高通关类型;与 clearType 混用会算错单曲 ptt | 可空 |
shinyPerfectCount | number | 0~物量 | 大 Pure(Shiny Pure)数 | 可空 |
perfectCount | number | 0~物量 | 小 Pure 数 | 可空 |
nearCount | number | 0~物量 | Far 数(原生字段名用 near 而不是 far) | 可空 |
missCount | number | 0~物量 | Lost 数 | 可空 |
health | number | 0~100 | 结算剩余回忆率(%) | 可空 |
constant | number | 1.0~12.0,精度 0.1 | 谱面定数(服务端算分用;来自曲库,不在成绩里) | 可空 |
评分语义与量纲
单曲潜力值(现行移动版口径)分三段 + 通关奖励,结果 round3(3 位小数):
base(S, C) =
S >= 10,000,000 -> C + 2
9,800,000 <= S < 10,000,000 -> C + 1 + (S - 9,800,000) / 200,000
S < 9,800,000 -> max(0, C + (S - 9,500,000) / 300,000)
chart_ptt = round3( base(S, C) + clear_bonus )
clear_bonus = 0.2 若 clearType 不是 0(即通关:Full Recall / Pure Memory / Normal / Easy / Hard Clear)
= 0.0 若 clearType = 0(Track Lost)| 量 | 量纲 | 说明 |
|---|---|---|
score | 读侧 0~10,000,000+;写侧硬上限 10,010,000 | 每个大 Pure 额外 +1 分,所以理论上限 = 1,000 万 + 大 Pure 数 |
constant(谱面定数) | 1.0~12.0,精度 0.1 | 来自曲库;查不到定数时回落到上游给的单曲 ptt |
chart_ptt | 小数,3 位 | 单曲值;通关奖励是逐次成绩绑定的,不看该谱面的历史最高通关状态 |
player.rating(总分) | 小数,3 位 | 现行口径 (ΣB50 + ΣB10) / 60:前 50 名单曲值之和 + 前 10 名的额外一份,除以 60 |
- 算分口径按移动版现行版本(Best 50 + Best 10,分母 60);历史档案无法从字段上区分旧口径(Best 30 + Recent 10)。
- 官方从未公开 potential 公式:上表是社区口径(证据等级
community),不是官方规范。
最佳成绩桶
GET /v1/games/arcaea/profiles/{profileId}/bests 返回一个桶:
| key | label | 成员规则 | totals 键 |
|---|---|---|---|
best50 | Best 50 | 全部谱面按单曲 potential 降序取前 50 条(同一谱面不重复;同曲不同难度可各占一格) | potential / b30Avg / b50Avg / maxPotential |
totals.potential= 档案的 potential(round3);不等于buckets[0].total。buckets[0].total= 桶内 50 条rating的和,不是 potential。totals.b30Avg/b50Avg/maxPotential都是原生没有的派生指标:b30Avg= 前 30 之和 / 30、b50Avg= 前 50 之和 / 50;maxPotential仍按旧口径(Σ前30 + Σ前10) / 40计算,与totals.potential不同源。- 桶内排序:
potential降序 →score降序 →songId升序 →difficulty升序。
写入(第三方)
写入只有两种形状:RankHub 格式(上文两张统一字段表里的字段)与游戏原生格式(native)。
共享字段、批量上限与失败语义见写入格式;本节只列 arcaea 真正会读的字段。
建档(POST /v1/games/arcaea/profiles)
player 用上文的身份字段(arcaeaId、character 必填,friendCode 可选)+ name,可另给 course / avatar / nameplate
与 potential(snake_case 子键,缺省按 0)。可以同时带 scores[],返回的 player.rating 已是重算后的 potential。身份重复 ⇒ 409。
推成绩(POST .../profiles/{profileId}/scores)
| 字段 | 类型 | 必给 | 说明 |
|---|---|---|---|
songId | string | 支持 | 曲目字符串 id(如 "tiferet");难度是成绩键的另一半 |
difficulty | integer | 支持 | 0~5(PST/PRS/FTR/BYD/ETR/INS) |
score | integer | 支持 | 0~10,010,000,整数;比较值,小数或越界 ⇒ 400 |
clearType | integer | 建议 | 0~5,缺省 0 且会按 0 参与单曲 ptt 计算 |
bestClearType | integer | 建议 | 0~5,必须 ≥ clearType,否则 422 |
scoreBelowMax | integer | 可选 | 0~11,000,000;独立字段,不与 score 做加和校验 |
shinyPerfectCount / perfectCount / nearCount / missCount | integer | 可选 | 缺省 0(大 Pure / Pure / Far / Lost 计数) |
health | integer | 可选 | 缺省 0;只做透传,不参与算分 |
playTime | string | 可选 | RFC3339;晚于服务端 5 分钟以上 ⇒ 422 |
rating | number | 不要给 | 被忽略:单曲 ptt 由服务端用 score + 定数算(maimai / arcaea 属于这一类) |
curl -sS -X POST https://api.rankhub.cc/v1/games/arcaea/profiles/$PROFILE_ID/scores \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"scores": [
{
"songId": "tiferet",
"difficulty": 2,
"score": 9968755,
"scoreBelowMax": 31245,
"shinyPerfectCount": 984,
"perfectCount": 97,
"nearCount": 3,
"missCount": 2,
"clearType": 3,
"bestClearType": 3,
"health": 100
}
]
}'以上为示意数据:字段真实,数值虚构。
原生数据(native)
player.native / scores[].native 是游戏原生格式:与顶层同名字段同时出现时 native 优先(浅合并)。
只给 native 时,顶层的 name / arcaeaId / character 可以省略。
建档(player.native)
native 键 | 类型 | 必填 | 换算 |
|---|---|---|---|
name | string(非空) | 支持 | → name |
arcaea_id | integer 1~999999999(数字串也收) | 支持 | → arcaeaId |
character | string(非空) | 支持 | → character |
course | integer ≥0 | 可选 | → course |
friend_code | string | 可选 | → friendCode |
avatar / nameplate | string | 可选 | → 同名字段 |
potential.potential / .b30_avg / .b50_avg / .b10_avg / .speculate_r10_avg / .max_potential | number | 可选 | → potential.*(键名保持 snake_case;整体替换顶层 potential,缺的子键按 0) |
推成绩(scores[].native)
native 键 | 类型 | 必填 | 换算 |
|---|---|---|---|
song_id | string 或 number(非空) | 支持 | → songId(统一成字符串) |
difficulty | integer 0~5 | 支持 | → difficulty |
score | integer 0~10,010,000 | 支持 | → score(比较值) |
score_below_max | integer 0~11,000,000 | 可选 | → scoreBelowMax |
shiny_perfect_count / perfect_count / near_count / miss_count | integer 0~100,000 | 可选 | → 同名统一字段 |
clear_type / best_clear_type | integer 0~5 | 可选 | → clearType / bestClearType |
time_played | integer(毫秒时间戳) | 可选 | → playTime(RFC3339) |
health / potential | — | — | 不读:不参与换算(单曲 ptt 由服务端算) |
可写字段 / 不可改
| 位置 | 可写 |
|---|---|
player.native(profile) | name、course、avatar、nameplate(PATCH .../profiles/{profileId} 的 native 同样生效) |
scores[].native(score,除唯一键) | score、score_below_max、clear_type / best_clear_type、四个判定计数、time_played |
potential不属于可写字段:它是服务端算分汇总,只能在建档时随player.native一起给。- 不可改:身份字段
arcaea_id/character/friend_code(与现值不同 ⇒400 common.invalidArgument); 成绩唯一键song_id+difficulty(native里必须给,换了就是另一条成绩)。
本游戏的写入规则
- 必给:
songId+difficulty+score;clearType/bestClearType建议给(缺省0会参与算分)。 - 比较值是
score:新值不更高 ⇒ 不覆盖,回improved: false+ignored(notImproved)。 - 谁算分:单曲 ptt 与 potential 都由服务端算(
maimai/arcaea属于这一类),scores[].rating被忽略。 scoreBelowMax独立:只校验取值域0~11,000,000,不与score做加和;读侧它是「距理论值的差值」,不要反推score。- 建档身份:
character缺 / 空 ⇒400 character is required;同一身份重复建档 ⇒409。
消费者注意事项
achievements恒null:arcaea 没有达成率字段;要准度信息请读native的四个计数。difficulty是数字串("2"),不是FTR这类标签;标签映射见本页「成绩键」段。score可能超过 1,000 万(每个大 Pure +1 分)。任何「分数 ≤ 10,000,000」的假设都会错。- 通关奖励看
clearType,不是bestClearType:单曲 ptt 与「本次成绩」的通关状态绑定, 用历史最高通关类型会系统性偏高。 totals.potential与buckets[].total不是一个数:前者是按 Best 50 口径算的 potential, 后者是桶内合计(和)。maxPotential是旧口径派生值,不要拿它跟potential比大小。b30Avg/b50Avg/maxPotential原生都没有:它们是 RankHub 自算的展示字段, 跨客户端比对时不要假设其他数据源也有。native.scoreBelowMax不是10,000,000 - score:理论值含大 Pure 加分, 两者在满分级成绩上会不一致。syncCapable恒false,不是漏实现。