bms_utils/
bmson.rs

1use serde::{Deserialize, Serialize};
2
3impl std::str::FromStr for Bmson {
4    type Err = serde_json::Error;
5    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
6        serde_json::from_str(s)
7    }
8}
9impl Bmson {
10    /// 文字列からBmsonを解析
11    pub fn parse(source: &str) -> serde_json::Result<Bmson> {
12        serde_json::from_str(source)
13    }
14    /// BmsonからJson形式の文字列に変換
15    pub fn to_string(&self) -> serde_json::Result<String> {
16        serde_json::to_string(self)
17    }
18    /// BmsonからJson形式の文字列に変換
19    ///
20    /// 改行やインデントが適切にされている
21    pub fn to_string_pretty(&self) -> serde_json::Result<String> {
22        serde_json::to_string_pretty(self)
23    }
24}
25
26/// Bmson本体
27#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
28pub struct Bmson {
29    /// Bmsonのバージョン
30    pub version: String,
31    /// 譜面の情報
32    pub info: BmsonInfo,
33    /// 小節線
34    pub lines: Option<Vec<BarLine>>,
35    /// BPMイベント
36    pub bpm_events: Option<Vec<BpmEvent>>,
37    /// 譜面停止イベント
38    pub stop_events: Option<Vec<StopEvent>>,
39    /// 音声チャンネル
40    pub sound_channels: Option<Vec<SoundChannel>>,
41    /// BGA情報
42    pub bga: Bga,
43    /// スクロール速度イベント(beatoraja拡張)
44    pub scroll_events: Option<Vec<ScrollEvent>>,
45    /// 地雷チャンネル(beatoraja拡張)
46    pub mine_channels: Option<Vec<MineChannel>>,
47    /// 不可視ノートチャンネル(beatoraja拡張)
48    pub key_channels: Option<Vec<KeyChannel>>,
49}
50
51/// ヘッダー
52#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
53pub struct BmsonInfo {
54    /// タイトル
55    pub title: String,
56    /// サブタイトル
57    #[serde(default)]
58    pub subtitle: String,
59    /// アーティスト
60    pub artist: String,
61    /// サブアーティスト
62    pub subartists: Option<Vec<String>>,
63    /// ジャンル
64    pub genre: String,
65    /// プレイ方法のヒント
66    ///
67    /// beat-7k・popn-5k・generic-nkeysなど
68    #[serde(default = "default_mode_hint")]
69    pub mode_hint: String,
70    /// 難易度
71    ///
72    /// HYPER・FOUR DIMENSIONSなど
73    pub chart_name: String,
74    /// レベル
75    pub level: u32,
76    /// 初期BPM
77    ///
78    /// 曲選択画面の表示などにも使う
79    pub init_bpm: f64,
80    /// 判定幅
81    ///
82    /// 100を初期値とする
83    #[serde(default = "default_judge_rank")]
84    pub judge_rank: f64,
85    /// ゲージ増加の総数
86    ///
87    /// 全て最良判定のときのゲージの増加量
88    ///
89    /// 某ゲームでは、総ノーツ数をnとしたとき、7.605 * n / (0.01 * n + 6.5) となる
90    #[serde(default = "default_total")]
91    pub total: f64,
92    /// 背景画像
93    pub back_image: Option<String>,
94    /// アイキャッチ画像
95    pub eyecatch_image: Option<String>,
96    /// タイトル画像
97    pub title_image: Option<String>,
98    /// バナー画像
99    pub banner_image: Option<String>,
100    /// プレビュー音声
101    pub preview_music: Option<String>,
102    /// 分解能
103    ///
104    /// 四分音符1つに対応するパルス数
105    ///
106    /// 240が初期値
107    #[serde(default = "default_resolution")]
108    pub resolution: u32,
109    /// ロングノートの種類(beatoraja拡張)
110    pub ln_type: Option<LongNoteType>,
111}
112fn default_mode_hint() -> String {
113    "beat-7k".to_string()
114}
115fn default_judge_rank() -> f64 {
116    100.
117}
118fn default_total() -> f64 {
119    100.
120}
121fn default_resolution() -> u32 {
122    240
123}
124
125/// 小節線イベント
126#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
127pub struct BarLine {
128    /// イベント時刻(パルス数)
129    pub y: u32,
130}
131
132/// サウンドチャンネル
133#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
134pub struct SoundChannel {
135    /// ファイル名
136    pub name: String,
137    /// ノーツ
138    pub notes: Vec<Note>,
139}
140
141/// サウンドノート
142#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
143pub struct Note {
144    /// 演奏レーン
145    ///
146    /// 0 or NullでBGM
147    pub x: Option<u32>,
148    /// 演奏時刻(パルス数)
149    pub y: u32,
150    /// 長さ(パルス数)
151    ///
152    /// 0で普通のノート
153    pub l: u32,
154    /// 続行フラグ
155    ///
156    /// trueでそのまま、falseで音声の最初へもどす
157    pub c: bool,
158    /// ロングノートの種類(beatoraja拡張)
159    pub t: Option<LongNoteType>,
160    /// 終端フラグ(beatoraja拡張)
161    ///
162    /// trueでかつロングノートの終点に配置される場合、終端音として鳴らす
163    pub up: Option<bool>,
164}
165
166/// BPM変化イベント
167#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
168pub struct BpmEvent {
169    /// イベント時刻(パルス数)
170    pub y: u32,
171    /// BPM
172    pub bpm: f64,
173}
174
175/// 譜面停止イベント
176#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
177pub struct StopEvent {
178    /// イベント時刻(パルス数)
179    pub y: u32,
180    /// 停止時間(パルス数)
181    pub duration: u32,
182}
183
184/// BGAデータ
185#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
186pub struct Bga {
187    /// 画像データ
188    pub bga_header: Vec<BgaHeader>,
189    /// BGAイベント
190    pub bga_events: Vec<BgaEvent>,
191    /// レイヤーイベント
192    pub layer_events: Vec<BgaEvent>,
193    /// POORイベント
194    pub poor_events: Vec<BgaEvent>,
195}
196
197/// 画像ファイル
198#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
199pub struct BgaHeader {
200    /// 画像のID
201    pub id: u32,
202    /// 画像ファイル
203    pub name: String,
204}
205
206/// BGAイベント
207#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
208pub struct BgaEvent {
209    /// イベント時刻(パルス数)
210    pub y: u32,
211    /// 画像のID
212    pub id: u32,
213}
214
215/// ロングノートの種類(beatoraja拡張)
216#[derive(
217    serde_repr::Deserialize_repr,
218    serde_repr::Serialize_repr,
219    Clone,
220    Debug,
221    PartialEq,
222)]
223#[repr(u8)]
224pub enum LongNoteType {
225    /// 未設定
226    None = 0,
227    /// ロングノート
228    ///
229    /// 始点と終点の判定の悪い方の判定になる
230    ///
231    /// ただし、終点のLATE側の判定を除く
232    LongNote = 1,
233    /// チャージノート
234    ///
235    /// 始点と終点の両方の判定がある
236    ///
237    /// 始点を押さなかった場合、終点は見逃したことになる
238    ChargeNote = 2,
239    /// ヘルチャージノート
240    ///
241    /// チャージノートに加え、押している間にも16分間隔でロングノート終点と同じ判定が加わる
242    ///
243    /// 16分間隔の判定は、一度離すと再度押すまで始点の判定になる
244    ///
245    /// ヘルチャージノーツの終点は普通の判定と同じ
246    HellChargeNote = 3,
247}
248
249/// スクロール速度設定イベント(beatoraja拡張)
250#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
251pub struct ScrollEvent {
252    /// イベント時刻(パルス数)
253    pub y: f64,
254    /// スクロール速度倍率
255    pub rate: f64,
256}
257
258/// 地雷チャンネル(beatoraja拡張)
259#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
260pub struct MineChannel {
261    /// ファイル名
262    pub name: String,
263    /// ノーツ
264    pub notes: Vec<MineNote>,
265}
266
267/// 地雷ノート(beatoraja拡張)
268#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
269pub struct MineNote {
270    /// 演奏レーン
271    ///
272    /// 0 or NullでBGM
273    pub x: Option<u32>,
274    /// 設置時刻(パルス数)
275    pub y: u32,
276    /// ダメージ
277    ///
278    /// %で指定
279    pub damage: f64,
280}
281
282/// 不可視チャンネル(beatoraja拡張)
283#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
284pub struct KeyChannel {
285    /// ファイル名
286    pub name: String,
287    /// ノーツ
288    pub notes: Vec<KeyNote>,
289}
290
291/// 不可視ノート(beatoraja拡張)
292#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
293pub struct KeyNote {
294    /// 演奏レーン
295    ///
296    /// 0 or NullでBGM
297    pub x: Option<u32>,
298    /// 演奏時刻(パルス数)
299    pub y: u32,
300}