Song 歌曲格式
本文档详细介绍 RhythMC 歌曲的完整格式,基于实际反序列化器实现。
如果你是想手动添加解锁规则,而不是只看字段定义,请直接看 docs/unlock-method-guide.md。
目录结构
song_folder/
├── manifest.yml # 歌曲信息 (YAML)
├── world.rmcc # 主世界谱面 (JSON)
├── nether.rmcc # 下界谱面 (JSON)
├── end.rmcc # 末地谱面 (JSON)
└── void.rmcc # 虚空谱面 (JSON)
manifest.yml
格式:YAML
name: 歌曲名称
composer: 作曲家
icon: STONE
alias: 别名
length: 180000
respack_sha1: "0000000000000000000000000000000000000000"
description: "描述"
song_id: 1
version: "1.0"
comments:
- 评论1
- 评论2
player-alias:
- 玩家别名
tags:
- rhythmc:series.maimai
- rhythmc:story.chapter1
unlockSong:
- type: regular
unlockWorld:
- type: permission
value: rhythmc:chart.world
unlockNether:
- type: money
value: 500
unlockVoid:
- type: songacc
song: thisDef
value: 98
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| name | String | Unknown Title | 歌曲名称 |
| composer | String | Unknown Composer | 作曲家 |
| icon | Material | NOTE_BLOCK | 物品图标 |
| alias | String | "" | 别名 |
| length | int | 0 | 歌曲时长(毫秒) |
| respack_sha1 | String (hex) | "" | 资源包SHA1 |
| description | String | "" | 描述 |
| song_id | int | 0 | 歌曲ID |
| version | String | "1.0" | 版本 |
| comments | List | [] | 谱师评论 |
| player-alias | List | [] | 玩家别名 |
| tags | List<Key> | [] | 精选集/分类标签键,建议直接填写 namespace:path 形式的收藏品 Key,例如版本、种类、剧情线等 |
| unlockSong | List | [] | 整首歌解锁条件,作用于 RawSong |
| unlockWorld | List | [] | world.rmcc 难度解锁条件 |
| unlockNether | List | [] | nether.rmcc 难度解锁条件 |
| unlockVoid | List | [] | void.rmcc 难度解锁条件 |
tags 约定
tags会在反序列化时解析为Key列表,而不是普通字符串。- 推荐直接复用服务端
collections里的tag定义,这样同一个 Key 可以同时承担歌曲精选集分类、显示文案和解锁逻辑条件。 - 典型写法:
tags:
- rhythmc:version.maimai_dx
- rhythmc:category.story
- rhythmc:type.original
Level 谱面 (world.rmcc / nether.rmcc / end.rmcc / void.rmcc)
格式:JSON
每个世界结构相同:
{
"meta": { ... },
"tracks": [ ... ],
"effects": [ ... ]
}
旧版解锁字段
- Song/Chart 仍以
SongManifest内的旧字段为准:unlockSong、unlockWorld、unlockNether、unlockVoid。 - 客户端会在反序列化时把这些旧配置转换成统一的
CommonUnlockMethod,但 chart 文件本身不再作为解锁配置入口。 - 当前内置兼容类型:
regular: 直接解锁permission: 要求玩家拥有指定权限,字段通常写在valuemoney: 要求player.wattHour >= valuesongacc: 要求player.songRecords.<levelId>.acc >= value * 10000
songacc.song支持数字 levelId,或thisDef表示当前难度自身。
Meta
{
"uid": 1,
"initialArena": "arenaName",
"offset": 0,
"level": 12.5,
"charters": ["谱师名"],
"comments": ["注释"],
"bpms": [
{ "beat": 0, "bpm": 120 }
]
}
| 字段 | 类型 | 说明 |
|---|---|---|
| uid | int | 难度ID (对应 Java 字段 levelId) |
| initialArena | String | 初始地图名称 (对应 Java 字段 Arena 对象) |
| offset | long | 时间偏移(毫秒) |
| level | double | 难度等级 |
| charters | List | 谱师列表 |
| comments | List | 注释 |
| bpms | List | BPM事件列表 |
BPM
{ "beat": 0, "bpm": 120 }
| 字段 | 类型 | 说明 |
|---|---|---|
| beat | double | 起始拍数 |
| bpm | double | BPM值 |
Track
{
"id": 0,
"speedEvents": [],
"xTransformEvents": [],
"yTransformEvents": [],
"zTransformEvents": [],
"xRotateEvents": [],
"yRotateEvents": [],
"zRotateEvents": [],
"xScaleEvents": [],
"yScaleEvents": [],
"zScaleEvents": [],
"notes": []
}
Note
重要:位置、缩放、旋转均为数组格式:
{
"noteType": 0,
"beat": 4.0,
"pos": [0, 0, 0],
"scale": [1, 1, 1],
"rotation": [0, 0, 0],
"holdGroup": -1
}
| 字段 | 类型 | 说明 |
|---|---|---|
| noteType | int | 音符类型 (0=TAP, 1=LOOK, 2=HOLD, 3=DODGE) |
| beat | double | 拍数位置 |
| pos | double[3] | [X, Y, Z] 坐标 (数组格式) |
| scale | float[3] | [X, Y, Z] 缩放 (数组格式) |
| rotation | float[3] | [X, Y, Z] 旋转角度 (数组格式) |
| holdGroup | int | 长押组ID (-1表示非长押) |
NumEvent
{
"startBeat": 0,
"endBeat": 4,
"startValue": 1,
"endValue": 2,
"easingType": 0
}
| 字段 | 类型 | 说明 |
|---|---|---|
| startBeat | double | 起始拍数 |
| endBeat | double | 结束拍数 |
| startValue | double | 起始值 |
| endValue | double | 结束值 |
| easingType | int | 缓动函数ID |
缓动函数 ID 对照表
| ID | 名称 | 说明 |
|---|---|---|
| 0 | LINEAR | 线性变化 |
| 1 | IN_SINE | 正弦加速进入 |
| 2 | OUT_SINE | 正弦减速离开 |
| 3 | IN_OUT_SINE | 正弦加速进入、减速离开 |
| 4 | IN_QUAD | 二次加速进入 |
| 5 | OUT_QUAD | 二次减速离开 |
| 6 | IN_OUT_QUAD | 二次加速进入、减速离开 |
| 7 | IN_CUBIC | 三次加速进入 |
| 8 | OUT_CUBIC | 三次减速离开 |
| 9 | IN_OUT_CUBIC | 三次加速进入、减速离开 |
| 10 | IN_QUART | 四次加速进入 |
| 11 | OUT_QUART | 四次减速离开 |
| 12 | IN_OUT_QUART | 四次加速进入、减速离开 |
| 13 | IN_QUINT | 五次加速进入 |
| 14 | OUT_QUINT | 五次减速离开 |
| 15 | IN_OUT_QUINT | 五次加速进入、减速离开 |
| 16 | IN_EXPO | 指数加速进入 |
| 17 | OUT_EXPO | 指数减速离开 |
| 18 | IN_OUT_EXPO | 指数加速进入、减速离开 |
| 19 | IN_CIRC | 圆形加速进入 |
| 20 | OUT_CIRC | 圆形减速离开 |
| 21 | IN_OUT_CIRC | 圆形加速进入、减速离开 |
| 22 | IN_BACK | 回退加速进入 |
| 23 | OUT_BACK | 回退加速离开 |
| 24 | IN_OUT_BACK | 回退加速进入、离开 |
| 25 | IN_ELASTIC | 弹性加速进入 |
| 26 | OUT_ELASTIC | 弹性减速离开 |
| 27 | IN_OUT_ELASTIC | 弹性加速进入、减速离开 |
| 28 | IN_BOUNCE | 弹跳进入 |
| 29 | OUT_BOUNCE | 弹跳离开 |
| 30 | IN_OUT_BOUNCE | 弹跳进入、离开 |
| 31 | IN_SQUARE | 平方加速进入 |
| 32 | OUT_SQUARE | 平方减速离开 |
| 33 | IN_OUT_SQUARE | 平方加速进入、减速离开 |
Effect
{
"effectType": "HOLOGRAM",
"beat": 4.0,
"properties": { ... }
}
| 字段 | 类型 | 说明 |
|---|---|---|
| effectType | String | 效果类型名称 |
| beat | double | 触发拍数 |
| properties | JSONObject | 效果参数 |
效果类型 (String)
| 类型 | 说明 |
|---|---|
| HOLOGRAM | 全息图 |
| REMOVE_HOLOGRAM | 移除全息图 |
| TITLE | 标题显示 |
| FIREWORK | 烟花 |
| TIME | 时间控制 |
| EFFECT | 药水效果 |
| CLEAR_EFFECT | 清除药水效果 |
| WEATHER | 天气 |
| ARENA | 切换地图 |
| TEXT_DISPLAY | 文本显示 |
| TEXT_DISPLAY_EFFECT | 文本显示效果 |
| TEXT_DISPLAY_SYNC_TRACK | 文本跟随轨道 |
| TEXT_DISPLAY_DESYNC_TRACK | 文本分离轨道 |
| HIDE_NOTES | 隐藏音符 |
| GLOW_COLOR | 发光颜色 |
| MESSAGE | 消息 |
| TEXT_DISPLAY_REMOVE | 移除文本显示 |
完整示例
manifest.yml
name: Example Song
composer: Example Artist
icon: MUSIC_DISC
alias: example
length: 120000
description: "An example song"
song_id: 1
version: "1.0"
comments: []
player-alias: []
tags:
- demo
unlockSong: []
unlockWorld: []
unlockNether: []
unlockVoid: []
world.rmcc
{
"meta": {
"uid": 1,
"initialArena": "arena1",
"offset": 0,
"level": 10.0,
"charters": ["Charter"],
"comments": [],
"bpms": [
{ "beat": 0, "bpm": 120 }
]
},
"tracks": [
{
"id": 0,
"speedEvents": [],
"xTransformEvents": [],
"yTransformEvents": [],
"zTransformEvents": [],
"xRotateEvents": [],
"yRotateEvents": [],
"zRotateEvents": [],
"xScaleEvents": [],
"yScaleEvents": [],
"zScaleEvents": [],
"notes": [
{
"noteType": 0,
"beat": 4.0,
"pos": [0, 0, 0],
"scale": [1, 1, 1],
"rotation": [0, 0, 0],
"holdGroup": -1
}
]
}
],
"effects": []
}