RankHub
各游戏

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

CHUNITHM

chunithm 的 Profile 与 Score 格式:好友码身份、player.native 的原生块、原样存储的成绩对象、BEST30/SELECTION10/NEW20 三个分组桶,以及它和官方 50 张平均口径的差距。

本页是 chunithm(中二节奏)在 RankHub 上的字段级格式说明。它属于「本地游戏」族 (chunithm / orzmic):成绩是上游原始对象,服务端不做结构归一、也不代算任何评分。

从落雪(LXNS)迁过来?

通用差异(三种鉴权、success/code 包络、端点、限速)先看 如果你熟悉落雪查分器 API 的开发;本页只讲 chunithm 的字段与桶。

机器可读版本

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

chunithm 的评分由上游给

chunithm 的单曲 rating 与档案 rating 都不是服务端算的:单曲值随成绩原样入库, 总分用上游快照里算好的值。所以文档里的公式只解释「这个数是什么」, 不能据此断言 RankHub 会复算它。

Profile 格式

身份字段(建档用)

字段类型必填说明示例
friendCodestring是街机侧好友码(不是 LXNS 的 id);上游原生是整数,wire 上为字符串"123456789012345"
  • 建档走 POST /v1/games/chunithm/profiles:只落库。
  • 该好友码已有未解绑档案 ⇒ 409。
  • chunithm 没有 externalId 这个身份字段(那是 orzmic 的):对外身份就是 friendCode。
  • name 也是建档必填项,但它是统一字段(player.name)而不是身份键,所以不在上表;10 个游戏一致。

统一字段(player)

字段类型可空单位说明
namestring可空—显示名(取 player.name,回落 userName / playerName / friend_code)
ratingnumber可空Rating(小数,展示 2 位、向下截断)总分;取快照 summary.rating,回落 player.rating

原生字段(player.native)

player.native 是三个顶层键,其中两个是嵌套的原生 JSON(不摊平):

键类型单位 / 取值语义可空
externalIdstring—档案的身份列原值(好友码的字符串形式)可空
playerobject嵌套对象原生玩家块原样(常见内部键:name、level、rating、rating_possession、friend_code、class_emblem、over_power、over_power_progress、reborn_count、currency、total_play_count、trophy、character、name_plate、map_icon、upload_time)可空
summaryobject嵌套对象快照构建时算出的汇总(score_count、rating、best30_total、selection10_total、new20_total),三个 *_total 都是组内 rating 之和可空

player / summary 的内部键属于上游数据,不逐个声明为 nativeFields: 它们是嵌套 JSON,键集合可能随上游版本变化。对外契约只有这三个顶层键。

Score 格式

成绩键与比较值

项值说明
keyFieldssongId / difficulty一条成绩 = 曲目 + 难度;写入方必须给出 difficulty,缺了会把多个难度并成一键
compareFieldscore「只升不降」按分数比较(0~1,010,000),更差不改并进 ignored
ratingFieldrating单曲 Rating,上游/调用方给的原值;服务端不代算
  • 推成绩时 scores[].bucket 决定落哪个桶:best30 / selection10 / new20,缺省 best30。
  • songId 的读取有候选键:song_id / id / music_id / songId;score 取 score,回落 achievement。

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

统一字段

chunithm 会填的统一字段:

字段类型单位 / 量纲可空说明
scoreIdstring—否成绩行 id
songIdstring—否曲目 id(候选键命中值;都不命中时回落行 id)
songNamestring—可空曲名(title,回落 song_name)
difficultystring难度标识可空难度(difficulty,回落 difficulty_name;原生 level_index 0~5)
achievementsnumber与 score 同量纲(0~1,010,000,不是百分比)可空达成率位;本地游戏没有独立达成率字段,填的是 score
scorenumber0~1,010,000可空分数(比较值)
ratingnumber小数可空单曲 Rating(上游算好的值)
rankstring14 值评级枚举(sssp~d)可空评级
playTimestring—恒 null本地游戏不映射游玩时间(原生 play_time 留在 native 里)

恒为 null 的字段:type(非 maimai)、levelIndex(本地族没有下标)、level、fc / fs (full_combo / full_chain 只在 native 里)、dxScore / dxStar。

原生字段(score.native)

chunithm 的 score.native 没有固定字段集合:它是整份原生成绩对象原样透传, 键名可能随上游版本变化。

所以本页不列 score.native 字段表(nativeFields 为空数组;注意这与 maimai 的「native 恒 null」不同—— chunithm 的 native 有值,只是键集合不固定)。

成绩对象的候选键

服务端会按下面这些候选键读取(命中即用):

用途候选键落到统一字段
曲目 idsong_id / id / music_id / songIdsongId
曲名title / song_namesongName
难度difficulty / difficulty_name(原生成绩对象里更常见的是 level_index 0~5)difficulty
分数score / achievementscore 与 achievements
单曲评分ratingrating
评级rankrank

原生成绩对象里还可能带:over_power、clear、full_combo(AJC/AJ/FC)、full_chain (fullchain=铂、fullchain2=金,字面与语义顺序不一致)、play_time、upload_time、 last_played_time、level。这些都只在 native 里,不进统一字段。

评分语义与量纲

单曲 Rating 不是乘法,而是「定数 + 分数档加成」的分段线性函数(现行 VERSE 口径):

分数段单曲 Rating
≥ 1,009,000(SSS+)c + 2.15(封顶)
1,007,500 ~ 1,008,999(SSS)c + 2.0 + (s - 1,007,500) / 10,000
1,005,000 ~ 1,007,499(SS+)c + 1.5 + (s - 1,005,000) / 5,000
1,000,000 ~ 1,004,999(SS)c + 1.0 + (s - 1,000,000) / 10,000
975,000 ~ 999,999(S)c + (s - 975,000) / 25,000
925,000 ~ 974,999(AA)c - 3.0 + ((s - 925,000) / 50,000) × 3
900,000 ~ 924,999(A)c - 5.0 + ((s - 900,000) / 25,000) × 2
800,000 ~ 899,999(BBB)((c - 5.0) / 2) × (1 + (s - 800,000) / 100,000)
500,000 ~ 799,999(C~BB)((s - 500,000) / 300,000) × ((c - 5.0) / 2)
< 500,000(D)0
  • s = 分数(0~1,010,000,1,010,000 是 All Justice Critical 理论值);c = 谱面定数。
  • 单曲上限 c + 2.15(1,009,000 分起不再增长);低分可能算出负数,最终 max(0, ·)。
  • 精度:单曲值展示向下截断到 2 位小数;总分是否同样截断未见官方说明(未知项)。
  • 官方总分口径(VERSE 起):BEST 30 + NEW 20 共 50 张谱面(互不重复)的单曲值算术平均, 分母恒 50;旧制为 BEST 30 + RECENT 10,分母 40。

RankHub 的桶合计是「和」,不是官方的「平均」

buckets[].total 与 totals.total 都是组内 rating 之和(服务端按条相加), 不是官方「50 张平均」的 Rating。两者量级差约 50 倍,不要把 total 当玩家 Rating 展示。

最佳成绩桶

chunithm 的桶直接来自上游快照分组(组名即 key),服务端不重算成员:

keylabel成员规则totals 键
best30BEST30上游 bests 组原样total
selection10SELECTION10上游 selections 组原样。官方语义是「Best30 之外的候选成绩」,不是独立评分桶total
new20NEW20上游 new_bests 组原样(现版本新曲)total
  • 三个 key 总是存在(服务端按固定组名逐个输出),但对应数组可能为空。
  • totals.total = best30 + new20 两组 rating 之和(不含 selection10),与官方 「50 张平均」口径不同源,也不等于推成绩响应里的 rating.before / rating.after (后者把全部组一起求和,含 selection10)。
  • buckets[].total = 该桶内 rating 之和(不是条数)。
  • label 是大写形式(BEST30 / SELECTION10 / NEW20),与 key 只差大小写。 按 key 渲染、label 只作参考(展示名可自行本地化)。
  • 桶数与顺序不是契约:以响应里的 buckets 数组为准,不要按数组下标。

写入(第三方)

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

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

player 用上文的身份字段(friendCode 必填)+ name。建档不能带成绩:成绩必须用下面的端点单独推。

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

字段类型必给说明
songIdstring | number支持曲目 id,归一成字符串后作为成绩键的一半
difficultystring | number支持难度标识,归一成字符串;缺失时回落 native.difficulty,两者都没有 ⇒ 多难度塌成一条
scorenumber支持分数(0~1,010,000 量级);比较值,缺省回落 achievements 再缺省 0
ratingnumber支持单曲 Rating,调用方给;缺省落 null ⇒ 桶内改按 score 排序、合计量级会爆
bucketstring建议best30 / selection10 / new20,缺省 best30;只能是这三个固定词汇
nativeobject强烈建议上游算好的整份成绩对象,原样存进档案;缺 difficulty 时从它取
playTimestring不读取本地游戏落库不带时间
curl -sS -X POST https://api.rankhub.cc/v1/games/chunithm/profiles/$PROFILE_ID/scores \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "scores": [
      {
        "songId": "3",
        "difficulty": "4",
        "score": 1010000,
        "rating": 16.15,
        "bucket": "best30",
        "native": { "id": 3, "level_index": 4, "score": 1010000, "rating": 16.15, "clear": "clear" }
      }
    ]
  }'

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

原生数据(native)

chunithm 的 native 只用于 profile:player.native 里除身份字段外的键会原样写进档案的玩家块,读回在 player.native.player。 成绩不做 native → 字段的换算(scores[].native 只是原样存储的原始成绩对象)。

可写字段 / 不可改

位置可写
player.native(profile)name + 其余任意键(除身份 friend_code):原样进档案玩家块;PATCH .../profiles/{profileId} 的 native 同样生效
scores[].native(score)无:不做字段换算,仅原样存储(唯一例外:顶层没给 difficulty 时用它当成绩键)
  • 不可改:身份字段 friend_code(与现值不同 ⇒ 400 common.invalidArgument); 成绩唯一键 songId + difficulty —— 本游戏没有 native 换算,这两个只能由顶层字段给。

本游戏的写入规则

  • 必给:songId + difficulty + rating + score;rating 尤其重要,缺了合计会用 score 兜底。
  • 比较值是 score:新值不高于现值 ⇒ 不覆盖,回 improved: false + ignored(not-improved)。
  • 谁算分:服务端不算分(chunithm 属于「调用方给」族)。单曲 Rating 用你给的 rating,总分是桶内求和。
  • 桶:bucket 只接受 best30 / selection10 / new20(缺省 best30);拼错 ⇒ 400。
  • 两处合计口径不同:推成绩响应的 rating.before / after 把全部组(含 selection10)求和; 读侧 totals.total 只加 best30 + new20。两者不能互相校对,也都不是官方 Rating。

从 LXNS 迁移

落雪 API 的通用差异(认证、包络、端点、限速)见如果你熟悉落雪查分器 API 的开发。 这里只保留 chunithm 最容易被迁移写错的一处:Rating 由哪几个桶构成。

Player 字段对照

LXNS PlayerRankHub位置
nameplayer.name统一字段
rating(float,官方 Rating)player.rating统一字段,取快照里算好的值;与 LXNS 的官方 Rating 可能因口径不同而不同
friend_code(int)friendCode(string)建档身份字段
level / rating_possession / class_emblem / reborn_count / over_power / over_power_progress / currency / total_currency / total_play_count / trophy / character / name_plate / map_icon全部保留在 player.native.player(整份 LXNS Player 原样)原生块;不进统一字段
upload_time无对应lastSyncedAt 只表示"RankHub 自己同步过",第三方档案为 null

Score 字段对照

LXNS ScoreRankHub说明
id(int)songId(string)WORLD'S END 难度时 LXNS 用 origin_id,迁移时要按此取值
song_namesongName
levellevel
level_index(0~5)difficulty(string)0~5:BASIC/ADVANCED/EXPERT/MASTER/ULTIMA/WORLD'S END
score(int)score(统一字段)比较值;achievements 也等于它
rating(float)rating(统一字段)写入必须给;RankHub 不代算
rankrank枚举相同
clear / full_combo / full_chain / over_power只存在于 score.native(原样)统一字段没有对应;写侧放进 native
play_time / upload_time / last_played_time读侧 playTime 目前为 null中二成绩是"每谱面最佳",没有逐次时间
整个对象score.native原样透传(所以迁移时 native 可以直接用 LXNS 的 Score)

Rating 构成对照(最容易踩)

LXNS 字段RankHub 桶说明
bestskey="best30"旧版本 Best 30(评分对象曲)
selectionskey="selection10"候选集:Best30 之外、理论能进 Best30 的成绩;不是独立评分桶
new_bestskey="new20"当前版本 Best 20(新曲)
RatingTrend.recents_rating(2026 起)没有对应桶迁移时不要把它塞进 new20

注意:RankHub 的 totals.total 是 best30 + new20 的桶内求和,不是官方「50 张平均」的 Rating; 两者量级不同(见「最佳成绩桶」)。

消费者注意事项

  1. 桶合计不是玩家 Rating:buckets[].total / totals.total 是「和」;官方是「50 张平均」。
  2. 两处合计口径不同:totals.total 只加 best30 + new20,而推成绩响应的 rating.before / rating.after 把全部组(含 selection10)一起求和。 两者不能互相校对,也都不是官方 Rating。
  3. achievements 与 score 同值:本地游戏没有独立达成率字段,两者都填分数 (0~1,010,000)。不要把它当百分比。
  4. rating 不是服务端算的:它是调用方给的值,服务端只存不算;缺 rating 时合计会 按 score 兜底(量级会爆),所以推成绩时务必给 rating。
  5. difficulty 必须显式给:成绩键是 songId + difficulty;不传会被并成一键,多个难度塌成一条。
  6. playTime 恒 null:原生 play_time 留在 native 里,统一字段不映射。
  7. full_combo / full_chain 只在 native:且 fullchain=铂、fullchain2=金, 枚举字面与语义顺序不一致,不要按字面推断高低。
  8. score.native 没有固定字段集合:键名由数据源决定,读之前先判空、再按候选键取。

相关

本页内容

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