1pub(crate) mod lex;
2pub(crate) mod parse;
3pub(crate) mod token;
4pub use token::Channel;
5
6#[derive(Debug, Clone, PartialEq, Default)]
11pub struct RawBms {
12 raw_bms: BmsBlock,
13 all_wav_files: HashSet<String>,
14}
15
16#[derive(Debug, Clone, PartialEq, Default)]
17pub(crate) struct BmsBlock(Vec<BmsElement>);
18#[derive(Debug, Clone, PartialEq)]
19pub(crate) enum BmsElement {
20 Command(token::Command),
21 Random(BmsRandomBlock),
22 Switch(BmsSwitchBlock),
23}
24#[derive(Debug, Clone, PartialEq)]
25pub(crate) struct BmsRandomBlock(RandomValue, Vec<BmsRandomElement>);
26#[derive(Debug, Clone, PartialEq)]
27pub(crate) enum BmsRandomElement {
28 Block(BmsBlock),
29 IfBlock(BmsIfBlock),
30}
31#[derive(Debug, Clone, Default, PartialEq)]
32pub(crate) struct BmsIfBlock {
33 pub(crate) r#if: Vec<(u128, BmsBlock)>,
34 pub(crate) r#else: Option<BmsBlock>,
35}
36#[derive(Debug, Clone, PartialEq)]
37pub(crate) struct BmsSwitchBlock(
38 RandomValue,
39 Vec<BmsCaseBlock>,
40 std::collections::HashSet<u128>,
41);
42#[derive(Debug, Clone, PartialEq)]
43pub(crate) struct BmsCaseBlock(SwitchLabel, BmsBlock, bool);
44#[derive(Debug, Clone, PartialEq)]
45pub(crate) enum RandomValue {
46 Max(u128),
47 Set(u128),
48}
49#[derive(Debug, Clone, PartialEq)]
50pub(crate) enum SwitchLabel {
51 Case(u128),
52 Default,
53}
54impl BmsBlock {
55 pub(crate) fn get_token_vec<'a, Rng: rand::RngCore>(
56 &'a self,
57 output: &mut Vec<&'a token::Command>,
58 rng: &mut Rng,
59 ) {
60 for e in &self.0 {
61 e.get_token_vec(output, rng);
62 }
63 }
64}
65impl BmsElement {
66 fn get_token_vec<'a, Rng: rand::RngCore>(
67 &'a self,
68 output: &mut Vec<&'a token::Command>,
69 rng: &mut Rng,
70 ) {
71 match self {
72 BmsElement::Command(c) => {
73 output.push(c);
74 }
75 BmsElement::Random(rb) => {
76 rb.get_token_vec(output, rng);
77 }
78 BmsElement::Switch(sb) => {
79 sb.get_token_vec(output, rng);
80 }
81 }
82 }
83}
84impl BmsRandomBlock {
85 fn get_token_vec<'a, Rng: rand::RngCore>(
86 &'a self,
87 output: &mut Vec<&'a token::Command>,
88 rng: &mut Rng,
89 ) {
90 use rand::Rng;
91 let n = match self.0 {
92 RandomValue::Max(n) => rng.random_range(1..=n),
93 RandomValue::Set(n) => n,
94 };
95 for e in &self.1 {
96 e.get_token_vec(output, rng, n);
97 }
98 }
99}
100impl BmsRandomElement {
101 fn get_token_vec<'a, Rng: rand::RngCore>(
102 &'a self,
103 output: &mut Vec<&'a token::Command>,
104 rng: &mut Rng,
105 n: u128,
106 ) {
107 match self {
108 BmsRandomElement::Block(b) => {
109 b.get_token_vec(output, rng);
110 }
111 BmsRandomElement::IfBlock(ib) => {
112 ib.get_token_vec(output, rng, n);
113 }
114 }
115 }
116}
117impl BmsIfBlock {
118 fn get_token_vec<'a, Rng: rand::RngCore>(
119 &'a self,
120 output: &mut Vec<&'a token::Command>,
121 rng: &mut Rng,
122 n: u128,
123 ) {
124 for (i, b) in &self.r#if {
125 if *i == n {
126 b.get_token_vec(output, rng);
127 return;
128 }
129 }
130 if let Some(b) = &self.r#else {
131 b.get_token_vec(output, rng);
132 }
133 }
134}
135impl BmsSwitchBlock {
136 fn get_token_vec<'a, Rng: rand::RngCore>(
137 &'a self,
138 output: &mut Vec<&'a token::Command>,
139 rng: &mut Rng,
140 ) {
141 use rand::Rng;
142 let n = match self.0 {
143 RandomValue::Max(n) => rng.random_range(1..=n),
144 RandomValue::Set(n) => n,
145 };
146 let mut flag = false;
147 for e in &self.1 {
148 if match &e.0 {
149 SwitchLabel::Case(i) => *i == n,
150 SwitchLabel::Default => !self.2.contains(&n),
151 } {
152 flag = true;
153 }
154 if flag {
155 e.1.get_token_vec(output, rng);
156 }
157 if flag && e.2 {
158 return;
159 }
160 }
161 }
162}
163
164use std::collections::{HashMap, HashSet};
165impl RawBms {
166 pub fn parse(source: &str) -> RawBms {
167 use token::*;
168 use winnow::prelude::*;
169 let token_stream = lex::lex(source);
170 let all_wav_files = token_stream
171 .iter()
172 .filter_map(|t| {
173 if let Token::Command(Command::Wav(_, file)) = t {
174 Some(file.clone())
175 }
176 else {
177 None
178 }
179 })
180 .collect::<HashSet<_>>();
181 RawBms {
182 raw_bms: parse::block
183 .parse_next(&mut token_stream.as_slice())
184 .unwrap(),
185 all_wav_files,
186 }
187 }
188 pub fn all_wav_files(&self) -> &HashSet<String> {
189 &self.all_wav_files
190 }
191 #[allow(deprecated)]
192 pub fn make_bms(&self, mut rng: impl rand::RngCore) -> Bms<'_> {
193 use token::Command::*;
194 let mut commands = vec![];
195 self.raw_bms.get_token_vec(&mut commands, &mut rng);
196
197 let base62 = commands.iter().any(|c| matches!(c, Base62));
198
199 let mut bms = Bms {
200 main_data: Vec::with_capacity(1000),
201 ..Default::default()
202 };
203
204 let convert_channel_vec = |ch_vec: &[Channel]| {
205 ch_vec
206 .iter()
207 .map(|ch| ch.to_base_36_or_62(base62))
208 .collect::<Vec<_>>()
209 };
210 for c in commands {
211 match c {
212 MainData(measure, data) => {
213 if bms.main_data.len() <= *measure {
214 bms.main_data
215 .resize_with(measure + 1, Default::default);
216 }
217 let measure = &mut bms.main_data[*measure];
218 use token::MainDataValue::*;
219 #[rustfmt::skip]
220 match data {
221 Bgm(data) =>
222 measure.bgm.push(convert_channel_vec(data)),
223 Length(n) =>
224 measure.length = *n,
225 Bga(data) =>
226 measure.bga.push(convert_channel_vec(data)),
227 Bpm(data) =>
228 measure.bpm.push(data),
229 BgaPoor(data) =>
230 measure.bga_poor.push(convert_channel_vec(data)),
231 BgaLayer(data) =>
232 measure.bga_layer.push(convert_channel_vec(data)),
233 ExBpm(data) =>
234 measure.ex_bpm.push(convert_channel_vec(data)),
235 Stop(data) =>
236 measure.stop.push(convert_channel_vec(data)),
237 BgaLayer2(data) =>
238 measure.bga_layer2.push(convert_channel_vec(data)),
239 ExRank(data) =>
240 measure.ex_rank.push(convert_channel_vec(data)),
241 BgaAlpha(data) =>
242 measure.bga_alpha.push(data),
243 BgaLayerAlpha(data) =>
244 measure.bga_layer_alpha.push(data),
245 BgaLayer2Alpha(data) =>
246 measure.bga_layer2_alpha.push(data),
247 BgaPoorAlpha(data) =>
248 measure.bga_poor_alpha.push(data),
249 Note(ch, data) =>
250 measure.notes.entry(*ch).or_default().push(convert_channel_vec(data)),
251 InvisibleNote(ch, data) =>
252 measure.invisible_notes.entry(*ch).or_default().push(convert_channel_vec(data)),
253 LongNote(ch, data) =>
254 measure.long_notes.entry(*ch).or_default().push(convert_channel_vec(data)),
255 Text(data) =>
256 measure.text.push(convert_channel_vec(data)),
257 BgaArgb(data) =>
258 measure.bga_argb.push(convert_channel_vec(data)),
259 BgaLayerArgb(data) =>
260 measure.bga_layer_argb.push(convert_channel_vec(data)),
261 BgaLayer2Argb(data) =>
262 measure.bga_layer2_argb.push(convert_channel_vec(data)),
263 BgaPoorArgb(data) =>
264 measure.bga_poor_argb.push(convert_channel_vec(data)),
265 SwitchBga(data) =>
266 measure.switch_bga.push(convert_channel_vec(data)),
267 Option(data) =>
268 measure.option.push(convert_channel_vec(data)),
269 Landmine(ch, data) =>
270 measure.landmine.entry(*ch).or_default().push(data),
271 Scroll(data) =>
272 measure.scroll.push(convert_channel_vec(data)),
273 Speed(data) =>
274 measure.speed.push(convert_channel_vec(data)),
275 Other(ch, data) =>
276 measure.other.push((*ch, data)),
277 };
278 }
279 Player(n) => {
280 bms.player = Some(match n {
281 1 => PlayType::SinglePlay,
282 2 => PlayType::CouplePlay,
283 3 => PlayType::DoublePlay,
284 4 => PlayType::BattlePlay,
285 _ => unreachable!(),
286 });
287 }
288 Rank(n) => bms.rank = Some(*n),
289 DefExRank(n) => bms.def_ex_rank = Some(*n),
290 ExRank(ch, n) => {
291 bms.ex_rank.insert(ch.to_base_36_or_62(base62), *n);
292 }
293 Total(n) => bms.total = Some(*n),
294 VolumeWav(n) => bms.volume_wav = Some(*n),
295 StageFile(s) => bms.stage_file = Some(s),
296 Banner(s) => bms.banner = Some(s),
297 BackBmp(s) => bms.back_bmp = Some(s),
298 CharacterFile(s) => bms.character_file = Some(s),
299 PlayLevel(n) => bms.play_level = Some(*n),
300 Difficulty(n) => bms.difficulty = Some(*n),
301 Title(s) => bms.title = Some(s),
302 SubTitle(s) => bms.sub_title.push(s),
303 Artist(s) => bms.artist = Some(s),
304 SubArtist(s) => bms.sub_artist.push(s),
305 Maker(s) => bms.maker = Some(s),
306 Genre(s) => bms.genre = Some(s),
307 Comment(s) => bms.comment.push(s),
308 Text(ch, s) => {
309 bms.text.insert(ch.to_base_36_or_62(base62), s);
310 }
311 PathWav(s) => bms.path_wav = Some(s),
312 Bpm(n) => bms.bpm = Some(*n),
313 ExBpm(ch, n) => {
314 bms.ex_bpm.insert(ch.to_base_36_or_62(base62), *n);
315 }
316 BaseBpm(n) => bms.base_bpm = Some(*n),
317 Stop(ch, n) => {
318 bms.stop.insert(ch.to_base_36_or_62(base62), *n);
319 }
320 Stp(x, y, z) => bms.stp.push((*x, *y, *z)),
321 LnMode(n) => bms.ln_mode = Some(*n),
322 LnType(n) => bms.ln_type = Some(*n),
323 LnObject(ch) => {
324 bms.ln_object.insert(ch.to_base_36_or_62(base62));
325 }
326 OctFp => bms.oct_fp = true,
327 Option(opt) => bms.option.push(opt),
328 ChangeOption(ch, opt) => {
329 bms.change_option.insert(ch.to_base_36_or_62(base62), opt);
330 }
331 Wav(ch, s) => {
332 bms.wav.insert(ch.to_base_36_or_62(base62), s);
333 }
334 WavCommand(opt, ch, v) => {
335 bms.wav_command.push((
336 *opt,
337 ch.to_base_36_or_62(base62),
338 *v,
339 ));
340 }
341 ExWav(ch, opt, s) => {
342 bms.ex_wav.insert(ch.to_base_36_or_62(base62), (opt, s));
343 }
344 Cdda(n) => bms.cdda = Some(*n),
345 MidiFile(s) => bms.midi_file = Some(s),
346 Bmp(ch, s) => {
347 bms.bmp.insert(ch.to_base_36_or_62(base62), s);
348 }
349 ExBmp(ch, argb, s) => {
350 bms.ex_bmp.insert(ch.to_base_36_or_62(base62), (argb, s));
351 }
352 Bga(ch, bmp, pos) => {
353 bms.bga.insert(
354 ch.to_base_36_or_62(base62),
355 (bmp.to_base_36_or_62(base62), pos),
356 );
357 }
358 AtBga(ch, bmp, pos) => {
359 bms.at_bga.insert(
360 ch.to_base_36_or_62(base62),
361 (bmp.to_base_36_or_62(base62), pos),
362 );
363 }
364 PoorBga(n) => bms.poor_bga = Some(*n),
365 SwitchBga(ch, fr, time, line, r#loop, argb, data) => {
366 bms.switch_bga.insert(
367 ch.to_base_36_or_62(base62),
368 (*fr, *time, line.to_base_36(), *r#loop, argb, data),
369 );
370 }
371 Argb(ch, argb) => {
372 bms.argb.insert(ch.to_base_36_or_62(base62), argb);
373 }
374 VideoFile(s) => bms.video_file = Some(s),
375 VideoFps(n) => bms.video_fps = Some(*n),
376 VideoColors(n) => bms.video_colors = Some(*n),
377 VideoDelay(n) => bms.video_delay = Some(*n),
378 Movie(s) => bms.movie = Some(s),
379 Seek(ch, n) => {
380 bms.seek.insert(ch.to_base_36_or_62(base62), *n);
381 }
382 ExCharacter(sprite_num, bmp, trim_rect, offset, abs_pos) => {
383 bms.ex_character = Some(super::bms::ExCharacter {
384 sprite_num: *sprite_num,
385 bmp: *bmp,
386 trim_rect,
387 offset: offset.as_ref(),
388 abs_pos: abs_pos.as_ref(),
389 });
390 }
391 Url(s) => bms.url = Some(s),
392 Email(s) => bms.email = Some(s),
393 Scroll(ch, n) => {
394 bms.scroll.insert(ch.to_base_36_or_62(base62), *n);
395 }
396 Speed(ch, n) => {
397 bms.speed.insert(ch.to_base_36_or_62(base62), *n);
398 }
399 Preview(s) => bms.preview = Some(s),
400 Other(command, value) => {
401 bms.other.push((command, value));
402 }
403 _ => (),
404 }
405 }
406 bms
407 }
408}
409
410#[derive(Default, Debug, PartialEq)]
412pub struct Bms<'a> {
413 pub main_data: Vec<MainData<'a>>,
423 pub rank: Option<i32>,
427 pub def_ex_rank: Option<f64>,
432 pub total: Option<f64>,
436 pub volume_wav: Option<f64>,
438 pub stage_file: Option<&'a str>,
440 pub banner: Option<&'a str>,
442 pub back_bmp: Option<&'a str>,
447 pub play_level: Option<i32>,
449 pub difficulty: Option<i32>,
463 pub title: Option<&'a str>,
465 pub sub_title: Vec<&'a str>,
467 pub artist: Option<&'a str>,
469 pub sub_artist: Vec<&'a str>,
471 pub genre: Option<&'a str>,
473 pub bpm: Option<f64>,
477 pub ex_bpm: HashMap<usize, f64>,
482 pub stop: HashMap<usize, f64>,
486 pub ln_mode: Option<i32>,
494 pub ln_type: Option<i32>,
510 pub ln_object: HashSet<usize>,
514 pub wav: HashMap<usize, &'a str>,
518 pub bmp: HashMap<usize, &'a str>,
522 pub url: Option<&'a str>,
524 pub email: Option<&'a str>,
526 pub scroll: HashMap<usize, f64>,
528 pub speed: HashMap<usize, f64>,
532 pub preview: Option<&'a str>,
537
538 pub ex_rank: HashMap<usize, f64>,
543 pub character_file: Option<&'a str>,
544 pub maker: Option<&'a str>,
546 pub comment: Vec<&'a str>,
548 pub text: HashMap<usize, &'a str>,
550 pub path_wav: Option<&'a str>,
552 pub stp: Vec<(usize, u32, f64)>,
558 pub oct_fp: bool,
560 pub option: Vec<&'a str>,
562 pub change_option: HashMap<usize, &'a str>,
566 pub wav_command: Vec<(i32, usize, f64)>,
576 pub ex_wav: HashMap<usize, (&'a [Option<f64>; 3], &'a str)>,
577 pub cdda: Option<u32>,
578 pub midi_file: Option<&'a str>,
579 pub ex_bmp: HashMap<usize, (&'a [u8; 4], &'a str)>,
580 pub bga: HashMap<usize, (usize, &'a [[f64; 2]; 3])>,
581 pub at_bga: HashMap<usize, (usize, &'a [[f64; 2]; 3])>,
582 pub poor_bga: Option<i32>,
583 pub argb: HashMap<usize, &'a [u8; 4]>,
584 pub video_file: Option<&'a str>,
585 pub video_fps: Option<f64>,
586 pub video_colors: Option<u32>,
587 pub video_delay: Option<u32>,
588 pub movie: Option<&'a str>,
589 pub ex_character: Option<ExCharacter<'a>>,
590
591 #[deprecated]
596 pub player: Option<PlayType>,
597 #[deprecated]
601 pub base_bpm: Option<f64>,
602 #[deprecated]
606 pub switch_bga:
607 HashMap<usize, (f64, f64, usize, bool, &'a [u8; 4], &'a [Channel])>,
608 #[deprecated]
612 pub seek: HashMap<usize, f64>,
613
614 pub other: Vec<(&'a str, &'a str)>,
616}
617
618#[derive(Debug, PartialEq)]
624pub struct MainData<'a> {
625 pub bgm: Vec<Vec<usize>>,
627 pub length: f64,
631 pub bpm: Vec<&'a [Option<f64>]>,
635 pub bga: Vec<Vec<usize>>,
637 pub bga_poor: Vec<Vec<usize>>,
639 pub bga_layer: Vec<Vec<usize>>,
641 pub ex_bpm: Vec<Vec<usize>>,
643 pub stop: Vec<Vec<usize>>,
645 pub bga_layer2: Vec<Vec<usize>>,
647 pub bga_alpha: Vec<&'a [u8]>,
649 pub bga_layer_alpha: Vec<&'a [u8]>,
651 pub bga_layer2_alpha: Vec<&'a [u8]>,
653 pub bga_poor_alpha: Vec<&'a [u8]>,
655 pub notes: HashMap<usize, Vec<Vec<usize>>>,
659 pub invisible_notes: HashMap<usize, Vec<Vec<usize>>>,
663 pub long_notes: HashMap<usize, Vec<Vec<usize>>>,
667 pub text: Vec<Vec<usize>>,
669 pub ex_rank: Vec<Vec<usize>>,
671 pub bga_argb: Vec<Vec<usize>>,
673 pub bga_layer_argb: Vec<Vec<usize>>,
675 pub bga_layer2_argb: Vec<Vec<usize>>,
677 pub bga_poor_argb: Vec<Vec<usize>>,
679 pub switch_bga: Vec<Vec<usize>>,
681 pub option: Vec<Vec<usize>>,
683 pub landmine: HashMap<usize, Vec<&'a [f64]>>,
685 pub scroll: Vec<Vec<usize>>,
687 pub speed: Vec<Vec<usize>>,
689
690 pub other: Vec<(usize, &'a str)>,
692}
693impl Default for MainData<'_> {
694 fn default() -> Self {
695 MainData {
696 bgm: vec![],
697 length: 1.0,
698 bpm: vec![],
699 bga: vec![],
700 bga_poor: vec![],
701 bga_layer: vec![],
702 ex_bpm: vec![],
703 stop: vec![],
704 bga_layer2: vec![],
705 bga_alpha: vec![],
706 bga_layer_alpha: vec![],
707 bga_layer2_alpha: vec![],
708 bga_poor_alpha: vec![],
709 notes: HashMap::new(),
710 invisible_notes: HashMap::new(),
711 long_notes: HashMap::new(),
712 text: vec![],
713 ex_rank: vec![],
714 bga_argb: vec![],
715 bga_layer_argb: vec![],
716 bga_layer2_argb: vec![],
717 bga_poor_argb: vec![],
718 switch_bga: vec![],
719 option: vec![],
720 landmine: HashMap::new(),
721 scroll: vec![],
722 speed: vec![],
723 other: vec![],
724 }
725 }
726}
727
728#[derive(Debug, PartialEq)]
730pub struct ExCharacter<'a> {
731 pub sprite_num: u32,
732 pub bmp: usize,
733 pub trim_rect: &'a [[f64; 2]; 2],
734 pub offset: Option<&'a [f64; 2]>,
735 pub abs_pos: Option<&'a [f64; 2]>,
736}
737
738#[derive(Debug, PartialEq)]
740pub enum PlayType {
741 SinglePlay,
742 CouplePlay,
743 DoublePlay,
744 BattlePlay,
745}