summaryrefslogtreecommitdiff
path: root/lib/simfile.dart
blob: 2174de99e0092968ed015521f843b335575077ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import 'dart:ffi';
import 'dart:io';

enum Difficulty { Beginner, Easy, Medium, Hard, Challenge, Edit }

// These are the standard note values:
//
//     0 – No note
//     1 – Normal note
//     2 – Hold head
//     3 – Hold/Roll tail
//     4 – Roll head
//     M – Mine (or other negative note)
//
// Later versions of StepMania accept other note values which may not work in older versions:
//
//     K – Automatic keysound
//     L – Lift note
//     F – Fake note

RegExp noteTypes = RegExp(r'^([012345MKLF]+)\s*([,;])?');

class Chart {
  String? chartType;
  // Description/author
  String? author;
  // Difficulty (one of Beginner, Easy, Medium, Hard, Challenge, Edit)
  Difficulty? difficulty;
  // Numerical meter
  int? numericalMeter;
  // Groove radar values, generated by the program
  String? radarValues;

  List<List<String>>? measures;
}

class Simfile {
  String path;
  String? lines;

  // tags of simfile
  Map<String, String> tags = {};

  Chart? chartSimplest;

  Map<double, double> bpms = {};
  double offset = 0;

  Simfile(this.path);

  void load() {
    lines = File(path).readAsStringSync();

    RegExp commentsRegExp = RegExp(r'//.*$');
    lines = lines?.replaceAll(commentsRegExp, '');
    RegExp fieldDataRegExp = RegExp(r'#([^;]+):([^;]*);');

    for (final fieldData in fieldDataRegExp.allMatches(lines!)) {
      List<String> keys =
          fieldData[1]!.split(':').map((key) => key.trim()).toList();
      String value = fieldData[2]!;
      if (keys[0] == "BPMS") {
        for (final pairRaw in value.split(',')) {
          List<String> pair = pairRaw.split('=');
          if (pair.length != 2) {
            continue;
          }
          double time = double.parse(pair[0]);
          double bpm = double.parse(pair[1]);
          bpms[time] = bpm;
        }
      }

      if (keys[0] == "OFFSET") {
        offset = double.parse(value);
      }

      if (keys[0] != "NOTES") {
        tags[keys[0]] = value;
        continue;
      }

      Chart chart = Chart();
      chart.chartType = keys[1];
      chart.author = keys[2];
      chart.difficulty = Difficulty.values.byName(keys[3]);
      chart.numericalMeter = int.parse(keys[4]);
      chart.radarValues = keys[5];

      if (chartSimplest == null ||
          (chart.difficulty!.index <= chartSimplest!.difficulty!.index &&
              chart.numericalMeter! <= chartSimplest!.numericalMeter!)) {
        List<List<String>> measures = [];
        for (final measureRaw in value.split(',')) {
          List<String> measure = [];
          for (final noteRaw in measureRaw.split('\n')) {
            String note = noteRaw.trim();
            if (noteTypes.hasMatch(note)) {
              measure.add(note);
            }
          }
          measures.add(measure);
        }
        chart.measures = measures;
        chartSimplest = chart;
      }
    }
  }
}