RankHub
各游戏

API 目前处于 Early Preview 阶段, 可能存在诸多不完善与错误之处,欢迎加群交流反馈:加入官方交流群(1073434398)

Phigros

phigros 的 Profile 与 Score 格式:objectId 身份、acc/rks 的量纲、score.native 只有 constant/artist、以及 phi + Best 30 双桶与「分母恒 30」的评分口径。

本页是 phigros 在 RankHub 上的字段级格式说明。phigros 有一条区别于其他游戏的硬约定: rating(单曲 rks)由调用方给——服务端只做上界校验与「只升不降」合并,不代算。

从 phi-plugin 过来?

存档结构、单曲 rks、(φ3+best27)/30 与推送字段的对应关系见 如果你熟悉使用 phi-plugin 进行开发;本页只列字段定义。

机器可读版本

GET /v1/games/phigros/format 返回与本页一致的格式数据(同一份字段表)。 文档可能滞后,以端点返回为准。

acc 是 0\~100,不是 0\~1

phigros 的 achievements 装的是 acc(百分数 0~100);单曲 rks 只吃 acc、不吃 score。 把 acc 当 0~1 会让 rks 计算与展示全部错位。

Profile 格式

身份字段(建档用)

字段类型必填说明示例
objectIdstring是玩家唯一 id(云存档账号维度)"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
shortIdstring否短 id(展示/检索用)"P123456"
  • 建档走 POST /v1/games/phigros/profiles:只落库。
  • 同一 objectId 已有未解绑档案 ⇒ 409(… is already linked)。
  • 字段式建档不写 session_token_ciphertext ⇒ syncCapable: false;只有用户在 RankHub 取值以字段为准。
  • name 也是建档必填项,但它是统一字段(player.name)而不是身份键,所以不在上表;10 个游戏一致。

统一字段(player)

字段类型可空单位说明
namestring可空—显示名(优先 nickname,回落 username)
ratingnumber可空rks(小数 2 位,展示四舍五入)取档案 summary.rks:导入路径下是游戏自己算的 rks;每次推成绩后会被服务端按 Best 30 口径重算的值覆盖

GET .../bests 里的两个 totals 键都源自 summary.rks:totals.officialRks 读的是存下来的那一份, totals.rks 是每次请求现算的(calculated rks)。所以「official」指的是「已落库的值」, 不是「永远等于游戏内显示」——导入时两者可能不等,推过成绩后通常收敛。

原生字段(player.native)

原生字段(wire 键)类型单位 / 取值语义可空
objectIdstring—玩家唯一 id(原生 object_id)可空
shortIdstring—短 id(原生 short_id)可空
challengeModeRanknumber整数课题模式(Challenge Mode)RANK可空
gameVersionstring—快照时的游戏版本号可空

档案里还有 avatar / avatarName / backgroundSongId 等展示字段,不在 player.native 里; summary 里的 levels(各难度通关/FC/ϕ 计数)、save_version、level_records 也不透传到 wire。

Score 格式

成绩键与比较值

项值说明
keyFieldssongId / difficulty一条成绩 = 曲目 + 难度;difficulty 是 EZ / HD / IN / AT / Legacy 字符串
compareFieldscore「只升不降」按得分比较(0~1,000,000)
ratingFieldrating单曲评分字段是统一 rating(原生字段 rks)。值由调用方给,服务端不代算
  • difficulty 是 5 值枚举,不是数字;推成绩时写 "IN" 这类字符串,或写数字下标 (EZ=0、HD=1、IN=2、AT=3、Legacy=4),认不出来直接 400。
  • 比较值用 score(不是 acc):同样 acc 可以对应不同 score(连击分不同)。

本页 keyFields / compareField / ratingField 里的名字都是 v1 wire 字段名(GameScoreDto 的顶层字段);游戏原生列名写在说明列。

统一字段

phigros 会填的统一字段:

字段类型单位 / 量纲可空说明
scoreIdstring—否成绩行 id
songIdstring—否曲目 id(存档 rawId 归一化 .0 后缀后的 id)
songNamestring—可空曲名(来自曲库)
difficultystringEZ / HD / IN / AT / Legacy可空难度(键之一)
levelIndexnumber0~4可空难度的数字形式(与 difficulty 同源)
achievementsnumber百分数 0~100可空准确率 acc(不是 0~1)
scorenumber0~1,000,000可空得分(比较值)
ratingnumber小数,单曲 rks可空单曲 rks(调用方给 / 本地算)
rankstringϕ / V / S / A / B / C / F可空评级(原生字段名就叫 rating)
fcstring只有 "fc" 一个取值可空全连标记:fc 为真时给 "fc",否则 null
playTimestring—恒 null存档不带游玩时间

恒为 null 的字段:type(非 maimai)、level、fs、dxScore / dxStar。

原生字段(score.native)

phigros 的 score.native 只有两个键(其余原生字段都进了统一字段):

原生字段(wire 键)类型单位 / 取值语义可空
constantnumber1.0~16.x谱面定数(来自曲库,不在存档里);单曲 rks 的乘数可空
artiststring—曲师可空

原生成绩里还有 rks、acc、fc、rating(评级字母)、chart.level(定数)等, 它们分别落到 rating / achievements / fc / rank / native.constant;song_name 落到 songName。

评分语义与量纲

单曲 rks 由「acc + 谱面定数」唯一决定:

single_rks =
    acc < 70   ->  0
    acc >= 70  ->  ((acc - 55) / 45) ^ 2 × constant
量量纲说明
acc百分数 0~100(2 位小数)acc = 100 ⇒ single_rks = constant;acc = 70 ⇒ 约 0.111 × constant
constant1.0~16.x谱面定数(游戏内谱面卡片直接显示的那个一位小数)
single_rks小数单曲值;SP / Legacy 谱面历史上统一按 0 处理(是否仍适用未见现行官方说明)
player.rating(官方 rks)小数,展示 2 位(四舍五入)(P1 + P2 + P3 + ΣB27) / 30:ϕ 曲中定数最高的 3 首 + 单曲 rks 前 27,分母恒 30
  • P1~P3 与 B27 可以重叠(同一首既评 ϕ 又进前 27 会被算两次),所以「分母 30」不等于 「30 首不同曲子」;没有 ϕ 成绩时前三项记 0,仍除以 30。
  • 总分口径按 v3.11.0 起的 30 项平均(ϕ 曲定数前 3 + 单曲 rks 前 27);旧档案无法从字段上区分分母 20 的旧口径。
  • 官方从未发布 rks 白皮书:上表是官方版本说明 + 社区复算的口径(证据等级 community)。

最佳成绩桶

GET /v1/games/phigros/profiles/{profileId}/bests 返回两个桶(可能重叠):

keylabel成员规则totals 键
phiϕ全部成绩中评级为 ϕ 的,按单曲 rks 降序取前 3 条(最多 3 条)rks / officialRks
best30Best 30全部成绩按单曲 rks 降序取前 27 条(桶名叫 best30,实际只有 27 条)同上
  • totals.rks = 服务端按上面的 30 项平均重算的 rks(round3)。
  • totals.officialRks = 档案里游戏自己算的 rks(player.rating 同源)。
  • buckets[].total = 桶内 rating 之和,不是 rks。
  • 两个桶可以重叠:同一首既是 ϕ 又在前 27 时会同时出现在两个桶里(这正是官方口径)。

写入(第三方)

写入只有两种形状:RankHub 格式(上文两张统一字段表里的字段)与游戏原生格式(native)。 共享字段、批量上限与失败语义见写入格式;本节只列 phigros 真正会读的字段。

建档(POST /v1/games/phigros/profiles)

player 用上文的身份字段(objectId 必填,shortId 可选)+ name。可以同时带 scores[], 返回的 player.rating 以落库后的汇总(rks)为准。身份重复 ⇒ 409。

推成绩(POST .../profiles/{profileId}/scores)

字段类型必给说明
songIdstring支持曲目 id(曲名式字符串,如 "Introduction")
difficultystring | integer支持EZ / HD / IN / AT / Legacy(大小写不敏感),或下标 0~4;非法 ⇒ 400
scorenumber支持0~1,000,000;比较值,缺省 0
accuracynumber支持百分数 0~100(缺省回落 achievements,再缺省 0)
ratingnumber支持单曲 rks,调用方给;缺省落 0,服务端不复算(phigros 不属于服务端算分族)
constantnumber可选谱面定数,0~100,缺省 0
artiststring可选曲师(展示用)
rankstring可选评级字母 ϕ / V / S / A / B / C / F
fullComboboolean可选全连标记;也可改用 fc(存在性即全连)
curl -sS -X POST https://api.rankhub.cc/v1/games/phigros/profiles/$PROFILE_ID/scores \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "scores": [
      {
        "songId": "Introduction",
        "difficulty": "IN",
        "score": 1000000,
        "accuracy": 100,
        "rating": 15.3,
        "constant": 15.3,
        "artist": "Sample Artist",
        "rank": "ϕ",
        "fullCombo": true
      }
    ]
  }'

以上为示意数据:字段真实,数值虚构。

原生数据(native)

player.native / scores[].native 是游戏原生格式:与顶层同名字段同时出现时 native 优先(浅合并)。 只给 native 时,顶层的 name / objectId 可以省略。

建档(player.native)

native 键类型必填换算
object_idstring(非空)支持→ objectId
nickname / usernamestring二者至少一个→ name(优先 nickname,再 username)
short_idstring可选→ shortId

推成绩(scores[].native)

native 键类型必填换算
song_idstring(非空)支持→ songId
difficultystring:EZ / HD / IN / AT / Legacy支持→ difficulty(大小写敏感,按原值比对)
scoreinteger 0~1,000,000支持→ score(比较值)
accnumber 0~100(百分数)支持→ accuracy 和 achievements
constantnumber 0~100可选→ constant
rksnumber 0~100可选→ rating(不给不代算:继续用顶层 rating)
fcboolean(也收 1 / "1" / "true")可选true ⇒ fullCombo + fc: "fc"
ratingstring:ϕ / V / S / A / B / C / F可选→ rank(评级字母,不是分数)
artiststring可选→ artist

可写字段 / 不可改

位置可写
player.native(profile)name、challenge_mode_rank、game_version(PATCH .../profiles/{profileId} 的 native 同样生效)
scores[].native(score,除唯一键)score、acc、constant、rks、fc、rating(→ rank)、artist
  • 不可改:身份字段 object_id / short_id(与现值不同 ⇒ 400 common.invalidArgument); 成绩唯一键 song_id + difficulty(native 里必须给,换了就是另一条成绩)。

本游戏的写入规则

  • 必给:songId + difficulty + score + accuracy + rating;只有 difficulty 缺失 / 非法会直接 400。
  • 比较值是 score:新值不高于现值 ⇒ 不覆盖,回 improved: false + ignored(notImproved)。
  • 谁算分:单曲 rks 由调用方给(rating,服务端不复算、不与 acc × constant 对账);总分由服务端重算。
  • difficulty 是 5 值枚举,accuracy 是百分数 0~100(不是 0~1)—— 量纲写错会直接算错 rks。

消费者注意事项

  1. achievements 是 acc,量纲 0~100(百分数)。它不是 0~1,也不是评级。
  2. rank 装的是评级字母(ϕ / V / S / A / B / C / F),不是分数档位字符串; 最低档的实现值是 F(社区文本常写 False),跨源比对时要归一。
  3. ϕ 的码位不统一:实现里用 ϕ(U+03D5),社区文本常用 φ(U+03C6)/ Φ(U+03A6)。 严格字符串比较会漏掉全部 ϕ,导致「前三」恒为 0。
  4. rating 由调用方给:推成绩时 scores[].rating 会原样入库并参与总分, 服务端不复算、也不与 acc × constant 对账。错的值会一路算进 totals.rks。
  5. phi 桶的成员是按单曲 rks 排序取的,而官方口径是按定数取前三;定数高但 acc 略低的 ϕ 曲可能落在不同位置。
  6. best30 只有 27 条:不要按 30 硬编码长度;phi 最多 3 条。
  7. 两个 rks 并存:player.rating 与 totals.officialRks 读同一份 summary.rks (导入时是游戏算的,推成绩后被服务端重算值覆盖),totals.rks 是请求时现算的。 两者不等是正常现象,展示时选一个并标注用的是哪一个。
  8. playTime 恒 null:phigros 的存档不带游玩时间。

相关

本页内容

官方交流群二维码官方交流群问题反馈 · 版本资讯 · 成绩交流群号 1073434398