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 new(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 new_with_stack(source: &str, stack_size: usize) -> RawBms {
190 let source = source.to_string();
191 std::thread::Builder::new()
192 .stack_size(stack_size)
193 .spawn(move || RawBms::new(&source))
194 .unwrap()
195 .join()
196 .unwrap()
197 }
198 pub fn drop_with_stack(self, stack_size: usize) {
199 std::thread::Builder::new()
200 .stack_size(stack_size)
201 .spawn(move || drop(self))
202 .unwrap()
203 .join()
204 .unwrap();
205 }
206 pub fn all_wav_files(&self) -> &HashSet<String> {
207 &self.all_wav_files
208 }
209 pub fn make_bms(&self, mut rng: impl rand::RngCore) -> Bms {
210 use token::Command::*;
211 let mut commands = vec![];
212 self.raw_bms.get_token_vec(&mut commands, &mut rng);
213
214 let base62 = commands.iter().any(|c| matches!(c, Base62));
215
216 let mut bms = Bms {
217 main_data: Vec::with_capacity(1000),
218 ..Default::default()
219 };
220
221 let convert_channel_vec = |ch_vec: &[Channel]| {
222 ch_vec
223 .iter()
224 .map(|ch| ch.to_base_36_or_62(base62))
225 .collect::<Vec<_>>()
226 };
227 for c in commands {
228 match c {
229 MainData(measure, data) => {
230 if bms.main_data.len() <= *measure {
231 bms.main_data
232 .resize_with(measure + 1, Default::default);
233 }
234 let measure = &mut bms.main_data[*measure];
235 use token::MainDataValue::*;
236 #[rustfmt::skip]
237 match data {
238 Bgm(data) =>
239 measure.bgm.push(convert_channel_vec(data)),
240 Length(n) =>
241 measure.length = *n,
242 Bga(data) =>
243 measure.bga.push(convert_channel_vec(data)),
244 Bpm(data) =>
245 measure.bpm.push(data),
246 BgaPoor(data) =>
247 measure.bga_poor.push(convert_channel_vec(data)),
248 BgaLayer(data) =>
249 measure.bga_layer.push(convert_channel_vec(data)),
250 ExBpm(data) =>
251 measure.ex_bpm.push(convert_channel_vec(data)),
252 Stop(data) =>
253 measure.stop.push(convert_channel_vec(data)),
254 BgaLayer2(data) =>
255 measure.bga_layer2.push(convert_channel_vec(data)),
256 ExRank(data) =>
257 measure.ex_rank.push(convert_channel_vec(data)),
258 BgaAlpha(data) =>
259 measure.bga_alpha.push(data),
260 BgaLayerAlpha(data) =>
261 measure.bga_layer_alpha.push(data),
262 BgaLayer2Alpha(data) =>
263 measure.bga_layer2_alpha.push(data),
264 BgaPoorAlpha(data) =>
265 measure.bga_poor_alpha.push(data),
266 Note(ch, data) =>
267 measure.note.entry(*ch).or_default().push(convert_channel_vec(data)),
268 InvisibleNote(ch, data) =>
269 measure.invisible_note.entry(*ch).or_default().push(convert_channel_vec(data)),
270 LongNote(ch, data) =>
271 measure.long_note.entry(*ch).or_default().push(convert_channel_vec(data)),
272 Text(data) =>
273 measure.text.push(convert_channel_vec(data)),
274 BgaArgb(data) =>
275 measure.bga_argb.push(convert_channel_vec(data)),
276 BgaLayerArgb(data) =>
277 measure.bga_layer_argb.push(convert_channel_vec(data)),
278 BgaLayer2Argb(data) =>
279 measure.bga_layer2_argb.push(convert_channel_vec(data)),
280 BgaPoorArgb(data) =>
281 measure.bga_poor_argb.push(convert_channel_vec(data)),
282 SwitchBga(data) =>
283 measure.switch_bga.push(convert_channel_vec(data)),
284 Option(data) =>
285 measure.option.push(convert_channel_vec(data)),
286 Landmine(ch, data) =>
287 measure.landmine.entry(*ch).or_default().push(data),
288 Scroll(data) =>
289 measure.scroll.push(convert_channel_vec(data)),
290 Speed(data) =>
291 measure.speed.push(convert_channel_vec(data)),
292 Other(ch, data) =>
293 measure.other.push((*ch, data)),
294 };
295 }
296 Player(n) => {
297 bms.deprecated.player = Some(match n {
298 1 => PlayType::SinglePlay,
299 2 => PlayType::CouplePlay,
300 3 => PlayType::DoublePlay,
301 4 => PlayType::BattlePlay,
302 _ => unreachable!(),
303 });
304 }
305 Rank(n) => bms.rank = Some(*n),
306 DefExRank(n) => bms.def_ex_rank = Some(*n),
307 ExRank(ch, n) => {
308 bms.uncommon
309 .ex_rank
310 .insert(ch.to_base_36_or_62(base62), *n);
311 }
312 Total(n) => bms.total = Some(*n),
313 VolumeWav(n) => bms.volume_wav = Some(*n),
314 StageFile(s) => bms.stage_file = Some(s),
315 Banner(s) => bms.banner = Some(s),
316 BackBmp(s) => bms.back_bmp = Some(s),
317 CharacterFile(s) => bms.uncommon.character_file = Some(s),
318 PlayLevel(n) => bms.play_level = Some(*n),
319 Difficulty(n) => bms.difficulty = Some(*n),
320 Title(s) => bms.title = Some(s),
321 SubTitle(s) => bms.sub_title.push(s),
322 Artist(s) => bms.artist = Some(s),
323 SubArtist(s) => bms.sub_artist.push(s),
324 Maker(s) => bms.uncommon.maker = Some(s),
325 Genre(s) => bms.genre = Some(s),
326 Comment(s) => bms.uncommon.comment.push(s),
327 Text(ch, s) => {
328 bms.uncommon.text.insert(ch.to_base_36_or_62(base62), s);
329 }
330 PathWav(s) => bms.uncommon.path_wav = Some(s),
331 Bpm(n) => bms.bpm = Some(*n),
332 ExBpm(ch, n) => {
333 bms.ex_bpm.insert(ch.to_base_36_or_62(base62), *n);
334 }
335 BaseBpm(n) => bms.deprecated.base_bpm = Some(*n),
336 Stop(ch, n) => {
337 bms.stop.insert(ch.to_base_36_or_62(base62), *n);
338 }
339 Stp(x, y, z) => bms.uncommon.stp.push((*x, *y, *z)),
340 LnMode(n) => bms.ln_mode = Some(*n),
341 LnType(n) => bms.ln_type = Some(*n),
342 LnObject(ch) => {
343 bms.ln_object.insert(ch.to_base_36_or_62(base62));
344 }
345 OctFp => bms.uncommon.oct_fp = true,
346 Option(name, opt) => bms.uncommon.option.push((name, opt)),
347 ChangeOption(ch, name, opt) => {
348 bms.uncommon
349 .change_option
350 .insert(ch.to_base_36_or_62(base62), (name, opt));
351 }
352 Wav(ch, s) => {
353 bms.wav.insert(ch.to_base_36_or_62(base62), s);
354 }
355 WavCommand(opt, ch, v) => {
356 bms.uncommon.wav_command.push((
357 *opt,
358 ch.to_base_36_or_62(base62),
359 *v,
360 ));
361 }
362 ExWav(ch, opt, s) => {
363 bms.uncommon
364 .ex_wav
365 .insert(ch.to_base_36_or_62(base62), (opt, s));
366 }
367 Cdda(n) => bms.uncommon.cdda = Some(*n),
368 MidiFile(s) => bms.uncommon.midi_file = Some(s),
369 Bmp(ch, s) => {
370 bms.bmp.insert(ch.to_base_36_or_62(base62), s);
371 }
372 ExBmp(ch, argb, s) => {
373 bms.uncommon
374 .ex_bmp
375 .insert(ch.to_base_36_or_62(base62), (argb, s));
376 }
377 Bga(ch, bmp, pos) => {
378 bms.uncommon.bga.insert(
379 ch.to_base_36_or_62(base62),
380 (bmp.to_base_36_or_62(base62), pos),
381 );
382 }
383 AtBga(ch, bmp, pos) => {
384 bms.uncommon.at_bga.insert(
385 ch.to_base_36_or_62(base62),
386 (bmp.to_base_36_or_62(base62), pos),
387 );
388 }
389 PoorBga(n) => bms.uncommon.poor_bga = Some(*n),
390 SwitchBga(ch, fr, time, line, r#loop, argb, data) => {
391 bms.deprecated.switch_bga.insert(
392 ch.to_base_36_or_62(base62),
393 (*fr, *time, line.to_base_36(), *r#loop, argb, data),
394 );
395 }
396 Argb(ch, argb) => {
397 bms.uncommon.argb.insert(ch.to_base_36_or_62(base62), argb);
398 }
399 VideoFile(s) => bms.uncommon.video_file = Some(s),
400 VideoFps(n) => bms.uncommon.video_fps = Some(*n),
401 VideoColors(n) => bms.uncommon.video_colors = Some(*n),
402 VideoDelay(n) => bms.uncommon.video_delay = Some(*n),
403 Movie(s) => bms.uncommon.movie = Some(s),
404 Seek(ch, n) => {
405 bms.deprecated.seek.insert(ch.to_base_36_or_62(base62), *n);
406 }
407 ExCharacter(sprite_num, bmp, trim_rect, offset, abs_pos) => {
408 bms.uncommon.ex_character = Some(super::bms::ExCharacter {
409 sprite_num: *sprite_num,
410 bmp: *bmp,
411 trim_rect,
412 offset: offset.as_ref(),
413 abs_pos: abs_pos.as_ref(),
414 });
415 }
416 Url(s) => bms.url = Some(s),
417 Email(s) => bms.email = Some(s),
418 Scroll(ch, n) => {
419 bms.scroll.insert(ch.to_base_36_or_62(base62), *n);
420 }
421 Speed(ch, n) => {
422 bms.speed.insert(ch.to_base_36_or_62(base62), *n);
423 }
424 Preview(s) => bms.preview = Some(s),
425 Other(command, value) => {
426 bms.uncommon.other.push((command, value));
427 }
428 _ => (),
429 }
430 }
431 bms
432 }
433}
434
435#[derive(Default, Debug, PartialEq)]
437pub struct Bms<'a> {
438 pub main_data: Vec<MainData<'a>>,
448 pub rank: Option<i32>,
452 pub def_ex_rank: Option<f64>,
456 pub total: Option<f64>,
463 pub volume_wav: Option<f64>,
465 pub stage_file: Option<&'a str>,
467 pub banner: Option<&'a str>,
469 pub back_bmp: Option<&'a str>,
474 pub play_level: Option<i32>,
476 pub difficulty: Option<i32>,
490 pub title: Option<&'a str>,
492 pub sub_title: Vec<&'a str>,
494 pub artist: Option<&'a str>,
496 pub sub_artist: Vec<&'a str>,
498 pub genre: Option<&'a str>,
500 pub bpm: Option<f64>,
504 pub ex_bpm: HashMap<usize, f64>,
509 pub stop: HashMap<usize, f64>,
513 pub ln_mode: Option<i32>,
521 pub ln_type: Option<i32>,
536 pub ln_object: HashSet<usize>,
540 pub wav: HashMap<usize, &'a str>,
544 pub bmp: HashMap<usize, &'a str>,
548 pub url: Option<&'a str>,
550 pub email: Option<&'a str>,
552 pub scroll: HashMap<usize, f64>,
554 pub speed: HashMap<usize, f64>,
558 pub preview: Option<&'a str>,
562 pub uncommon: UncommonHeader<'a>,
564 pub deprecated: DeprecatedHeader<'a>,
566}
567
568#[derive(Debug, PartialEq)]
570pub struct MainData<'a> {
571 pub bgm: Vec<Vec<usize>>,
572 pub length: f64,
573 pub bpm: Vec<&'a [Option<f64>]>,
574 pub bga: Vec<Vec<usize>>,
575 pub bga_poor: Vec<Vec<usize>>,
576 pub bga_layer: Vec<Vec<usize>>,
577 pub ex_bpm: Vec<Vec<usize>>,
578 pub stop: Vec<Vec<usize>>,
579 pub bga_layer2: Vec<Vec<usize>>,
580 pub bga_alpha: Vec<&'a [u8]>,
581 pub bga_layer_alpha: Vec<&'a [u8]>,
582 pub bga_layer2_alpha: Vec<&'a [u8]>,
583 pub bga_poor_alpha: Vec<&'a [u8]>,
584 pub note: HashMap<usize, Vec<Vec<usize>>>,
585 pub invisible_note: HashMap<usize, Vec<Vec<usize>>>,
586 pub long_note: HashMap<usize, Vec<Vec<usize>>>,
587 pub text: Vec<Vec<usize>>,
588 pub ex_rank: Vec<Vec<usize>>,
589 pub bga_argb: Vec<Vec<usize>>,
590 pub bga_layer_argb: Vec<Vec<usize>>,
591 pub bga_layer2_argb: Vec<Vec<usize>>,
592 pub bga_poor_argb: Vec<Vec<usize>>,
593 pub switch_bga: Vec<Vec<usize>>,
594 pub option: Vec<Vec<usize>>,
595 pub landmine: HashMap<usize, Vec<&'a [f64]>>,
596 pub scroll: Vec<Vec<usize>>,
597 pub speed: Vec<Vec<usize>>,
598
599 pub other: Vec<(usize, &'a str)>,
600}
601impl Default for MainData<'_> {
602 fn default() -> Self {
603 MainData {
604 bgm: vec![],
605 length: 1.0,
606 bpm: vec![],
607 bga: vec![],
608 bga_poor: vec![],
609 bga_layer: vec![],
610 ex_bpm: vec![],
611 stop: vec![],
612 bga_layer2: vec![],
613 bga_alpha: vec![],
614 bga_layer_alpha: vec![],
615 bga_layer2_alpha: vec![],
616 bga_poor_alpha: vec![],
617 note: HashMap::new(),
618 invisible_note: HashMap::new(),
619 long_note: HashMap::new(),
620 text: vec![],
621 ex_rank: vec![],
622 bga_argb: vec![],
623 bga_layer_argb: vec![],
624 bga_layer2_argb: vec![],
625 bga_poor_argb: vec![],
626 switch_bga: vec![],
627 option: vec![],
628 landmine: HashMap::new(),
629 scroll: vec![],
630 speed: vec![],
631 other: vec![],
632 }
633 }
634}
635
636#[derive(Default, Debug, PartialEq)]
638pub struct UncommonHeader<'a> {
639 pub ex_rank: HashMap<usize, f64>,
643 pub character_file: Option<&'a str>,
644 pub maker: Option<&'a str>,
646 pub comment: Vec<&'a str>,
648 pub text: HashMap<usize, &'a str>,
650 pub path_wav: Option<&'a str>,
652 pub stp: Vec<(usize, u32, f64)>,
653 pub oct_fp: bool,
654 pub option: Vec<(&'a str, &'a str)>,
655 pub change_option: HashMap<usize, (&'a str, &'a str)>,
656 pub wav_command: Vec<(i32, usize, f64)>,
657 pub ex_wav: HashMap<usize, (&'a [Option<f64>; 3], &'a str)>,
658 pub cdda: Option<u32>,
659 pub midi_file: Option<&'a str>,
660 pub ex_bmp: HashMap<usize, (&'a [u8; 4], &'a str)>,
661 pub bga: HashMap<usize, (usize, &'a [[f64; 2]; 3])>,
662 pub at_bga: HashMap<usize, (usize, &'a [[f64; 2]; 3])>,
663 pub poor_bga: Option<i32>,
664 pub argb: HashMap<usize, &'a [u8; 4]>,
665 pub video_file: Option<&'a str>,
666 pub video_fps: Option<f64>,
667 pub video_colors: Option<u32>,
668 pub video_delay: Option<u32>,
669 pub movie: Option<&'a str>,
670 pub ex_character: Option<ExCharacter<'a>>,
671 pub other: Vec<(&'a str, &'a str)>,
673}
674
675#[derive(Debug, PartialEq)]
677pub struct ExCharacter<'a> {
678 pub sprite_num: u32,
679 pub bmp: usize,
680 pub trim_rect: &'a [[f64; 2]; 2],
681 pub offset: Option<&'a [f64; 2]>,
682 pub abs_pos: Option<&'a [f64; 2]>,
683}
684
685#[derive(Default, Debug, PartialEq)]
687pub struct DeprecatedHeader<'a> {
688 pub player: Option<PlayType>,
692 pub base_bpm: Option<f64>,
696 pub switch_bga:
700 HashMap<usize, (f64, f64, usize, bool, &'a [u8; 4], &'a [Channel])>,
701 pub seek: HashMap<usize, f64>,
705}
706
707#[derive(Debug, PartialEq)]
709pub enum PlayType {
710 SinglePlay,
711 CouplePlay,
712 DoublePlay,
713 BattlePlay,
714}