1#![allow(dead_code)]
2pub(crate) mod lex;
3pub(crate) mod parse;
4pub(crate) mod token;
5pub use token::Channel;
6
7#[derive(Debug, Clone, PartialEq, Default)]
12pub struct RawBms {
13 raw_bms: BmsBlock,
14 all_wav_files: HashSet<String>,
15}
16
17#[derive(Debug, Clone, PartialEq, Default)]
18pub(crate) struct BmsBlock(Vec<BmsElement>);
19#[derive(Debug, Clone, PartialEq)]
20pub(crate) enum BmsElement {
21 Command(token::Command),
22 Random(BmsRandomBlock),
23 Switch(BmsSwitchBlock),
24}
25#[derive(Debug, Clone, PartialEq)]
26pub(crate) struct BmsRandomBlock(RandomValue, Vec<BmsRandomElement>);
27#[derive(Debug, Clone, PartialEq)]
28pub(crate) enum BmsRandomElement {
29 Block(BmsBlock),
30 IfBlock(BmsIfBlock),
31}
32#[derive(Debug, Clone, Default, PartialEq)]
33pub(crate) struct BmsIfBlock {
34 pub(crate) r#if: Vec<(u128, BmsBlock)>,
35 pub(crate) r#else: Option<BmsBlock>,
36}
37#[derive(Debug, Clone, PartialEq)]
38pub(crate) struct BmsSwitchBlock(
39 RandomValue,
40 Vec<BmsCaseBlock>,
41 std::collections::HashSet<u128>,
42);
43#[derive(Debug, Clone, PartialEq)]
44pub(crate) struct BmsCaseBlock(SwitchLabel, BmsBlock, bool);
45#[derive(Debug, Clone, PartialEq)]
46pub(crate) enum RandomValue {
47 Max(u128),
48 Set(u128),
49}
50#[derive(Debug, Clone, PartialEq)]
51pub(crate) enum SwitchLabel {
52 Case(u128),
53 Default,
54}
55impl BmsBlock {
56 pub(crate) fn get_token_vec<'a, Rng: rand::RngCore>(
57 &'a self,
58 output: &mut Vec<&'a token::Command>,
59 rng: &mut Rng,
60 ) {
61 for e in &self.0 {
62 e.get_token_vec(output, rng);
63 }
64 }
65}
66impl BmsElement {
67 fn get_token_vec<'a, Rng: rand::RngCore>(
68 &'a self,
69 output: &mut Vec<&'a token::Command>,
70 rng: &mut Rng,
71 ) {
72 match self {
73 BmsElement::Command(c) => {
74 output.push(c);
75 }
76 BmsElement::Random(rb) => {
77 rb.get_token_vec(output, rng);
78 }
79 BmsElement::Switch(sb) => {
80 sb.get_token_vec(output, rng);
81 }
82 }
83 }
84}
85impl BmsRandomBlock {
86 fn get_token_vec<'a, Rng: rand::RngCore>(
87 &'a self,
88 output: &mut Vec<&'a token::Command>,
89 rng: &mut Rng,
90 ) {
91 use rand::Rng;
92 let n = match self.0 {
93 RandomValue::Max(n) => rng.random_range(1..=n),
94 RandomValue::Set(n) => n,
95 };
96 for e in &self.1 {
97 e.get_token_vec(output, rng, n);
98 }
99 }
100}
101impl BmsRandomElement {
102 fn get_token_vec<'a, Rng: rand::RngCore>(
103 &'a self,
104 output: &mut Vec<&'a token::Command>,
105 rng: &mut Rng,
106 n: u128,
107 ) {
108 match self {
109 BmsRandomElement::Block(b) => {
110 b.get_token_vec(output, rng);
111 }
112 BmsRandomElement::IfBlock(ib) => {
113 ib.get_token_vec(output, rng, n);
114 }
115 }
116 }
117}
118impl BmsIfBlock {
119 fn get_token_vec<'a, Rng: rand::RngCore>(
120 &'a self,
121 output: &mut Vec<&'a token::Command>,
122 rng: &mut Rng,
123 n: u128,
124 ) {
125 for (i, b) in &self.r#if {
126 if *i == n {
127 b.get_token_vec(output, rng);
128 return;
129 }
130 }
131 if let Some(b) = &self.r#else {
132 b.get_token_vec(output, rng);
133 }
134 }
135}
136impl BmsSwitchBlock {
137 fn get_token_vec<'a, Rng: rand::RngCore>(
138 &'a self,
139 output: &mut Vec<&'a token::Command>,
140 rng: &mut Rng,
141 ) {
142 use rand::Rng;
143 let n = match self.0 {
144 RandomValue::Max(n) => rng.random_range(1..=n),
145 RandomValue::Set(n) => n,
146 };
147 let mut flag = false;
148 for e in &self.1 {
149 if match &e.0 {
150 SwitchLabel::Case(i) => *i == n,
151 SwitchLabel::Default => !self.2.contains(&n),
152 } {
153 flag = true;
154 }
155 if flag {
156 e.1.get_token_vec(output, rng);
157 }
158 if flag && e.2 {
159 return;
160 }
161 }
162 }
163}
164
165use std::collections::{HashMap, HashSet};
166impl RawBms {
167 pub fn parse(source: &str) -> RawBms {
168 use token::*;
169 use winnow::prelude::*;
170 let token_stream = lex::lex(source);
171 let all_wav_files = token_stream
172 .iter()
173 .filter_map(|t| {
174 if let Token::Command(Command::Wav(_, file)) = t {
175 Some(file.clone())
176 }
177 else {
178 None
179 }
180 })
181 .collect::<HashSet<_>>();
182 RawBms {
183 raw_bms: parse::block
184 .parse_next(&mut token_stream.as_slice())
185 .unwrap(),
186 all_wav_files,
187 }
188 }
189 pub fn all_wav_files(&self) -> &HashSet<String> {
190 &self.all_wav_files
191 }
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.deprecated.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.uncommon
292 .ex_rank
293 .insert(ch.to_base_36_or_62(base62), *n);
294 }
295 Total(n) => bms.total = Some(*n),
296 VolumeWav(n) => bms.volume_wav = Some(*n),
297 StageFile(s) => bms.stage_file = Some(s),
298 Banner(s) => bms.banner = Some(s),
299 BackBmp(s) => bms.back_bmp = Some(s),
300 CharacterFile(s) => bms.uncommon.character_file = Some(s),
301 PlayLevel(n) => bms.play_level = Some(*n),
302 Difficulty(n) => bms.difficulty = Some(*n),
303 Title(s) => bms.title = Some(s),
304 SubTitle(s) => bms.sub_title.push(s),
305 Artist(s) => bms.artist = Some(s),
306 SubArtist(s) => bms.sub_artist.push(s),
307 Maker(s) => bms.uncommon.maker = Some(s),
308 Genre(s) => bms.genre = Some(s),
309 Comment(s) => bms.uncommon.comment.push(s),
310 Text(ch, s) => {
311 bms.uncommon.text.insert(ch.to_base_36_or_62(base62), s);
312 }
313 PathWav(s) => bms.uncommon.path_wav = Some(s),
314 Bpm(n) => bms.bpm = Some(*n),
315 ExBpm(ch, n) => {
316 bms.ex_bpm.insert(ch.to_base_36_or_62(base62), *n);
317 }
318 BaseBpm(n) => bms.deprecated.base_bpm = Some(*n),
319 Stop(ch, n) => {
320 bms.stop.insert(ch.to_base_36_or_62(base62), *n);
321 }
322 Stp(x, y, z) => bms.uncommon.stp.push((*x, *y, *z)),
323 LnMode(n) => bms.ln_mode = Some(*n),
324 LnType(n) => bms.ln_type = Some(*n),
325 LnObject(ch) => {
326 bms.ln_object.insert(ch.to_base_36_or_62(base62));
327 }
328 OctFp => bms.uncommon.oct_fp = true,
329 Option(name, opt) => bms.uncommon.option.push((name, opt)),
330 ChangeOption(ch, name, opt) => {
331 bms.uncommon
332 .change_option
333 .insert(ch.to_base_36_or_62(base62), (name, opt));
334 }
335 Wav(ch, s) => {
336 bms.wav.insert(ch.to_base_36_or_62(base62), s);
337 }
338 WavCommand(opt, ch, v) => {
339 bms.uncommon.wav_command.push((
340 *opt,
341 ch.to_base_36_or_62(base62),
342 *v,
343 ));
344 }
345 ExWav(ch, opt, s) => {
346 bms.uncommon
347 .ex_wav
348 .insert(ch.to_base_36_or_62(base62), (opt, s));
349 }
350 Cdda(n) => bms.uncommon.cdda = Some(*n),
351 MidiFile(s) => bms.uncommon.midi_file = Some(s),
352 Bmp(ch, s) => {
353 bms.bmp.insert(ch.to_base_36_or_62(base62), s);
354 }
355 ExBmp(ch, argb, s) => {
356 bms.uncommon
357 .ex_bmp
358 .insert(ch.to_base_36_or_62(base62), (argb, s));
359 }
360 Bga(ch, bmp, pos) => {
361 bms.uncommon.bga.insert(
362 ch.to_base_36_or_62(base62),
363 (bmp.to_base_36_or_62(base62), pos),
364 );
365 }
366 AtBga(ch, bmp, pos) => {
367 bms.uncommon.at_bga.insert(
368 ch.to_base_36_or_62(base62),
369 (bmp.to_base_36_or_62(base62), pos),
370 );
371 }
372 PoorBga(n) => bms.uncommon.poor_bga = Some(*n),
373 SwitchBga(ch, fr, time, line, r#loop, argb, data) => {
374 bms.deprecated.switch_bga.insert(
375 ch.to_base_36_or_62(base62),
376 (*fr, *time, line.to_base_36(), *r#loop, argb, data),
377 );
378 }
379 Argb(ch, argb) => {
380 bms.uncommon.argb.insert(ch.to_base_36_or_62(base62), argb);
381 }
382 VideoFile(s) => bms.uncommon.video_file = Some(s),
383 VideoFps(n) => bms.uncommon.video_fps = Some(*n),
384 VideoColors(n) => bms.uncommon.video_colors = Some(*n),
385 VideoDelay(n) => bms.uncommon.video_delay = Some(*n),
386 Movie(s) => bms.uncommon.movie = Some(s),
387 Seek(ch, n) => {
388 bms.deprecated.seek.insert(ch.to_base_36_or_62(base62), *n);
389 }
390 ExCharacter(sprite_num, bmp, trim_rect, offset, abs_pos) => {
391 bms.uncommon.ex_character = Some(super::bms::ExCharacter {
392 sprite_num: *sprite_num,
393 bmp: *bmp,
394 trim_rect,
395 offset: offset.as_ref(),
396 abs_pos: abs_pos.as_ref(),
397 });
398 }
399 Url(s) => bms.url = Some(s),
400 Email(s) => bms.email = Some(s),
401 Scroll(ch, n) => {
402 bms.scroll.insert(ch.to_base_36_or_62(base62), *n);
403 }
404 Speed(ch, n) => {
405 bms.speed.insert(ch.to_base_36_or_62(base62), *n);
406 }
407 Preview(s) => bms.preview = Some(s),
408 Other(command, value) => {
409 bms.uncommon.other.push((command, value));
410 }
411 _ => (),
412 }
413 }
414 bms
415 }
416}
417
418#[derive(Default, Debug, PartialEq)]
420pub struct Bms<'a> {
421 pub main_data: Vec<MainData<'a>>,
431 pub rank: Option<i32>,
435 pub def_ex_rank: Option<f64>,
440 pub total: Option<f64>,
444 pub volume_wav: Option<f64>,
446 pub stage_file: Option<&'a str>,
448 pub banner: Option<&'a str>,
450 pub back_bmp: Option<&'a str>,
455 pub play_level: Option<i32>,
457 pub difficulty: Option<i32>,
471 pub title: Option<&'a str>,
473 pub sub_title: Vec<&'a str>,
475 pub artist: Option<&'a str>,
477 pub sub_artist: Vec<&'a str>,
479 pub genre: Option<&'a str>,
481 pub bpm: Option<f64>,
485 pub ex_bpm: HashMap<usize, f64>,
490 pub stop: HashMap<usize, f64>,
494 pub ln_mode: Option<i32>,
502 pub ln_type: Option<i32>,
518 pub ln_object: HashSet<usize>,
522 pub wav: HashMap<usize, &'a str>,
526 pub bmp: HashMap<usize, &'a str>,
530 pub url: Option<&'a str>,
532 pub email: Option<&'a str>,
534 pub scroll: HashMap<usize, f64>,
536 pub speed: HashMap<usize, f64>,
540 pub preview: Option<&'a str>,
545 pub uncommon: UncommonHeader<'a>,
547 pub deprecated: DeprecatedHeader<'a>,
549}
550
551#[derive(Debug, PartialEq)]
557pub struct MainData<'a> {
558 pub bgm: Vec<Vec<usize>>,
560 pub length: f64,
564 pub bpm: Vec<&'a [Option<f64>]>,
568 pub bga: Vec<Vec<usize>>,
570 pub bga_poor: Vec<Vec<usize>>,
572 pub bga_layer: Vec<Vec<usize>>,
574 pub ex_bpm: Vec<Vec<usize>>,
576 pub stop: Vec<Vec<usize>>,
578 pub bga_layer2: Vec<Vec<usize>>,
580 pub bga_alpha: Vec<&'a [u8]>,
582 pub bga_layer_alpha: Vec<&'a [u8]>,
584 pub bga_layer2_alpha: Vec<&'a [u8]>,
586 pub bga_poor_alpha: Vec<&'a [u8]>,
588 pub notes: HashMap<usize, Vec<Vec<usize>>>,
592 pub invisible_notes: HashMap<usize, Vec<Vec<usize>>>,
596 pub long_notes: HashMap<usize, Vec<Vec<usize>>>,
600 pub text: Vec<Vec<usize>>,
602 pub ex_rank: Vec<Vec<usize>>,
604 pub bga_argb: Vec<Vec<usize>>,
606 pub bga_layer_argb: Vec<Vec<usize>>,
608 pub bga_layer2_argb: Vec<Vec<usize>>,
610 pub bga_poor_argb: Vec<Vec<usize>>,
612 pub switch_bga: Vec<Vec<usize>>,
614 pub option: Vec<Vec<usize>>,
616 pub landmine: HashMap<usize, Vec<&'a [f64]>>,
618 pub scroll: Vec<Vec<usize>>,
620 pub speed: Vec<Vec<usize>>,
622
623 pub other: Vec<(usize, &'a str)>,
625}
626impl Default for MainData<'_> {
627 fn default() -> Self {
628 MainData {
629 bgm: vec![],
630 length: 1.0,
631 bpm: vec![],
632 bga: vec![],
633 bga_poor: vec![],
634 bga_layer: vec![],
635 ex_bpm: vec![],
636 stop: vec![],
637 bga_layer2: vec![],
638 bga_alpha: vec![],
639 bga_layer_alpha: vec![],
640 bga_layer2_alpha: vec![],
641 bga_poor_alpha: vec![],
642 notes: HashMap::new(),
643 invisible_notes: HashMap::new(),
644 long_notes: HashMap::new(),
645 text: vec![],
646 ex_rank: vec![],
647 bga_argb: vec![],
648 bga_layer_argb: vec![],
649 bga_layer2_argb: vec![],
650 bga_poor_argb: vec![],
651 switch_bga: vec![],
652 option: vec![],
653 landmine: HashMap::new(),
654 scroll: vec![],
655 speed: vec![],
656 other: vec![],
657 }
658 }
659}
660
661#[derive(Default, Debug, PartialEq)]
663pub struct UncommonHeader<'a> {
664 pub ex_rank: HashMap<usize, f64>,
668 pub character_file: Option<&'a str>,
669 pub maker: Option<&'a str>,
671 pub comment: Vec<&'a str>,
673 pub text: HashMap<usize, &'a str>,
675 pub path_wav: Option<&'a str>,
677 pub stp: Vec<(usize, u32, f64)>,
678 pub oct_fp: bool,
679 pub option: Vec<(&'a str, &'a str)>,
680 pub change_option: HashMap<usize, (&'a str, &'a str)>,
681 pub wav_command: Vec<(i32, usize, f64)>,
682 pub ex_wav: HashMap<usize, (&'a [Option<f64>; 3], &'a str)>,
683 pub cdda: Option<u32>,
684 pub midi_file: Option<&'a str>,
685 pub ex_bmp: HashMap<usize, (&'a [u8; 4], &'a str)>,
686 pub bga: HashMap<usize, (usize, &'a [[f64; 2]; 3])>,
687 pub at_bga: HashMap<usize, (usize, &'a [[f64; 2]; 3])>,
688 pub poor_bga: Option<i32>,
689 pub argb: HashMap<usize, &'a [u8; 4]>,
690 pub video_file: Option<&'a str>,
691 pub video_fps: Option<f64>,
692 pub video_colors: Option<u32>,
693 pub video_delay: Option<u32>,
694 pub movie: Option<&'a str>,
695 pub ex_character: Option<ExCharacter<'a>>,
696 pub other: Vec<(&'a str, &'a str)>,
698}
699
700#[derive(Debug, PartialEq)]
702pub struct ExCharacter<'a> {
703 pub sprite_num: u32,
704 pub bmp: usize,
705 pub trim_rect: &'a [[f64; 2]; 2],
706 pub offset: Option<&'a [f64; 2]>,
707 pub abs_pos: Option<&'a [f64; 2]>,
708}
709
710#[derive(Default, Debug, PartialEq)]
712pub struct DeprecatedHeader<'a> {
713 pub player: Option<PlayType>,
717 pub base_bpm: Option<f64>,
721 pub switch_bga:
725 HashMap<usize, (f64, f64, usize, bool, &'a [u8; 4], &'a [Channel])>,
726 pub seek: HashMap<usize, f64>,
730}
731
732#[derive(Debug, PartialEq)]
734pub enum PlayType {
735 SinglePlay,
736 CouplePlay,
737 DoublePlay,
738 BattlePlay,
739}