Skip to content

Commit 7886879

Browse files
committed
[O&F] 进行了许多修复和优化
1. 增加了对“误把?、@等星星头修饰符写到星星体修饰区”的情况的兼容和支持(解析并给警告) 2. 优化了修饰符处理的逻辑,SimaiParser会尽全力接受和存储修饰符,而由MA2Generator对不合规的修饰符(如绝赞touch)给予警告 3. 修复了Strict模式下,Antlr自带BailErrorAStrategy不会调用ErrorListener的问题 4. 优化了一些i18n key 5. 优化了MA2Generator给出警告时的展示
1 parent 98df2d6 commit 7886879

13 files changed

Lines changed: 212 additions & 77 deletions

chart/Note.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,22 @@ protected Note(Chart chart, Rational time)
6262
return result;
6363
}
6464
}
65+
66+
internal virtual string DebuggerDisplay() => "";
6567
}
6668

6769
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
6870
public class Tap(Chart chart, Rational time) : Note(chart, time)
6971
{
70-
internal string DebuggerDisplay() => $"{Key}{Modifiers}";
72+
public Tap(Tap inTake): this(inTake.Chart, inTake.Time) // 拷贝构造函数
73+
{
74+
IsBreak = inTake.IsBreak;
75+
IsEx = inTake.IsEx;
76+
FalseEachIdx = inTake.FalseEachIdx;
77+
Key = inTake.Key;
78+
}
79+
80+
internal override string DebuggerDisplay() => $"{Key}{Modifiers}";
7181
}
7282

7383
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
@@ -77,7 +87,7 @@ public class Hold : Tap
7787

7888
public Hold(Chart chart, Rational time) : base(chart, time) { Duration = new Duration(this); }
7989

80-
private new string DebuggerDisplay() => $"{Key}h{Modifiers}{Duration.DebuggerDisplay()}";
90+
internal override string DebuggerDisplay() => $"{Key}h{Modifiers}{Duration.DebuggerDisplay()}";
8191
}
8292

8393
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
@@ -112,7 +122,7 @@ public string TouchArea
112122

113123
public override string Modifiers => base.Modifiers + (IsFirework ? "f" : "");
114124

115-
private string DebuggerDisplay() => $"{TouchArea}{Modifiers}";
125+
internal override string DebuggerDisplay() => $"{TouchArea}{Modifiers}";
116126
}
117127

118128
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
@@ -122,7 +132,7 @@ public class TouchHold : Touch
122132

123133
public TouchHold(Chart chart, Rational time) : base(chart, time) { Duration = new Duration(this); }
124134

125-
private string DebuggerDisplay() => $"{TouchArea}h{Modifiers}{Duration.DebuggerDisplay()}";
135+
internal override string DebuggerDisplay() => $"{TouchArea}h{Modifiers}{Duration.DebuggerDisplay()}";
126136
}
127137

128138
// 仅用于内部实现某些trick时使用的“伪音符”。用户在正常的谱面中是不会看到这个的。

chart/Slide.cs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,11 @@
44

55
namespace MuConvert.chart;
66

7-
public class Star(Chart chart, Rational time) : Tap(chart, time)
7+
public class Star : Tap
88
{
9-
public Star(Tap inTake): this(inTake.Chart, inTake.Time) // 拷贝构造函数
10-
{
11-
IsBreak = inTake.IsBreak;
12-
IsEx = inTake.IsEx;
13-
FalseEachIdx = inTake.FalseEachIdx;
14-
Key = inTake.Key;
15-
}
9+
public Star(Chart chart, Rational time): base(chart, time) {}
10+
11+
public Star(Tap inTake): base(inTake) {} // 拷贝构造函数
1612
}
1713

1814
/**
@@ -75,7 +71,7 @@ public override Duration Duration
7571
}
7672
}
7773

78-
internal string DebuggerDisplay()
74+
internal override string DebuggerDisplay()
7975
{
8076
string result;
8177
if (SharedHeadWith != null) result = "*";

chart/Statistics.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ namespace MuConvert.chart;
55

66
public class Statistics
77
{
8-
private readonly Dictionary<string, int> _data = [];
9-
public IReadOnlyDictionary<string, int> Data => _data;
8+
public readonly Dictionary<string, int> Data = [];
109

1110
// 烟花数量
1211
public int Firework { get; private set; } = 0;
@@ -35,7 +34,7 @@ private void AddNote(Note note)
3534
else throw Utils.Fail();
3635

3736
var res = prefix + type;
38-
_data[res] = _data.GetValueOrDefault(res) + 1;
37+
Data[res] = Data.GetValueOrDefault(res) + 1;
3938

4039
// TTM_EACHPAIRS 双押数量
4140
if (note is Tap)
@@ -58,26 +57,26 @@ private void AddNote(Note note)
5857
}
5958
}
6059

61-
internal Statistics(Chart chart)
60+
public Statistics(Chart chart)
6261
{
6362
foreach (var note in chart.Notes) AddNote(note);
6463
}
6564

6665
// 音符总数(总物量)
67-
public int Total => _data.Values.Sum();
66+
public int Total => Data.Values.Sum();
6867

6968
// 返回按音符类型分组的数量。所返回的字典中会包含的key:TAP,STR,HLD,SLD,TTP,THO
70-
public Dictionary<string, int> ByNoteType => _data.GroupBy(x => x.Key[2..5])
69+
public Dictionary<string, int> ByNoteType => Data.GroupBy(x => x.Key[2..5])
7170
.ToDictionary(x => x.Key, x => x.Sum(v => v.Value))
7271
.EnsureKeys(["TAP", "STR", "HLD", "SLD", "TTP", "THO"]);
7372

7473
// 返回按音符的修饰符分组的数量。所返回的字典中会包含的key:NM,BR,EX,BX
75-
public Dictionary<string, int> ByModifiers => _data.GroupBy(x => x.Key[..2])
74+
public Dictionary<string, int> ByModifiers => Data.GroupBy(x => x.Key[..2])
7675
.ToDictionary(x => x.Key, x => x.Sum(v => v.Value))
7776
.EnsureKeys(["NM", "BR", "EX", "BX"]);
7877

7978
// 返回按游戏结算画面上屏判定表分类的数量。所返回的字典中会包含的key:TAP,HOLD,SLIDE,TOUCH,BREAK
80-
public Dictionary<string, int> ByScoring => _data.GroupBy(x =>
79+
public Dictionary<string, int> ByScoring => Data.GroupBy(x =>
8180
{
8281
if (x.Key[0] == 'B') return "BREAK";
8382
var type = x.Key[2..5];
@@ -91,10 +90,10 @@ internal Statistics(Chart chart)
9190
.EnsureKeys(["TAP","HOLD","SLIDE","TOUCH","BREAK"]);
9291

9392
// 绝赞总数
94-
public int Break => _data.Where(x=>x.Key[0] == 'B').Sum(x=>x.Value);
93+
public int Break => Data.Where(x=>x.Key[0] == 'B').Sum(x=>x.Value);
9594

9695
// 保护套总数
97-
public int EX => _data.Where(x=>x.Key[1] == 'X').Sum(x=>x.Value);
96+
public int EX => Data.Where(x=>x.Key[1] == 'X').Sum(x=>x.Value);
9897

9998
// 修正物量(Slide算3个,Hold算2个,Break算5个)
10099
public int WeightedNoteCount {
@@ -118,7 +117,7 @@ public override string ToString()
118117
List<string> r = [$"Tap: {t["TAP"]}", $"Hold: {t["HLD"]}", $"Star: {t["STR"]}",
119118
$"Slide: {t["SLD"]}", $"Touch: {t["TTP"]}", $"Touch Hold: {t["THO"]}",
120119
$"Total: {Total}",
121-
$"Break: {ByModifiers["BR"] + ByModifiers["BX"]}", $"Ex: {ByModifiers["EX"] + ByModifiers["BX"]}",
120+
$"Break: {m["BR"] + m["BX"]}", $"Ex: {m["EX"] + m["BX"]}",
122121
$"Firework: {Firework}"];
123122
return string.Join(", ", r);
124123
}

generator/MA2Generator.cs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ protected int T(Rational r, int offset = 0)
7474
protected int T(int bar, int tick) => bar * RSL + tick;
7575
protected int T(MA2Line ma2Line) => T(ma2Line.Bar, ma2Line.Tick);
7676

77-
protected void Warn(string description, Note note, MA2Line? ma2Line = null)
77+
protected void Warn(string description, Note note)
7878
{
79-
alerts.Add(new Alert(Warning, description, (chart, note.Time), lines.Count + 1, ma2Line?.ToString()));
79+
alerts.Add(new Alert(Warning, description, (chart, note.Time), null, note.DebuggerDisplay()));
8080
}
8181

8282
protected virtual MA2Line? AddTap(Tap tap, int bar, int tick)
@@ -103,7 +103,6 @@ protected bool hasSameTimeTap(MA2Line ma2Line)
103103
for (int i = lines.Count - 1; i >=0 ; i--)
104104
{
105105
var l = lines[i];
106-
var lT = l.Bar * RSL + l.Tick;
107106
if (T(l) < curT) break;
108107
if (T(l) == curT && l.Key == ma2Line.Key && // 同一时间、同一键位、都是广义tap
109108
_broadTap.Contains(l.Name[^3..]) && _broadTap.Contains(ma2Line.Name[^3..])) return true;
@@ -119,8 +118,7 @@ protected virtual List<MA2Line> AddSlide(Slide slide, int bar, int tick)
119118
var headTap = AddTap(slide.OwnHead, bar, tick);
120119
if (headTap != null)
121120
{
122-
if (hasSameTimeTap(headTap))
123-
alerts.Add(new Alert(Warning, Locale.SimultaneousSlideHead, (chart, slide.OwnHead.Time), null, slide.DebuggerDisplay()));
121+
if (hasSameTimeTap(headTap)) Warn(Locale.SimultaneousSlideHead, slide);
124122
else result.Add(headTap);
125123
}
126124
}
@@ -179,6 +177,7 @@ protected virtual List<MA2Line> AddSlide(Slide slide, int bar, int tick)
179177
while (tick >= RSL) { tick -= RSL; bar++; }
180178
}
181179

180+
if (slide.IsEx) Warn(Locale.ExSlideIn105, slide);
182181
return result;
183182
}
184183

@@ -198,7 +197,8 @@ protected virtual List<MA2Line> AddSlide(Slide slide, int bar, int tick)
198197
extras.Add(area.ToString());
199198
extras.Add(touch.IsFirework ? "1" : "0");
200199
extras.Add(touch.TouchSize);
201-
200+
201+
if (touch.IsBreak || touch.IsEx) Warn(Locale.SpecialTouchIn105, touch);
202202
return new MA2Line(prefix + name, bar, tick, key, string.Join("\t", extras));
203203
}
204204

@@ -261,10 +261,17 @@ protected void GenerateNotes(StringBuilder result)
261261
result.AppendLine();
262262
}
263263

264-
protected void GenerateStatistics(StringBuilder result)
264+
protected void GenerateStatistics(StringBuilder result, Statistics stats)
265265
{
266+
// 首先,把MA2中不合规的音符进行转写
267+
foreach (var (k, v) in statsRewrite())
268+
{
269+
if (!stats.Data.ContainsKey(k)) continue;
270+
stats.Data[v] = stats.Data.GetValueOrDefault(v) + stats.Data.GetValueOrDefault(k);
271+
stats.Data.Remove(k);
272+
}
273+
266274
// 统计段
267-
var stats = chart.Statistics;
268275
foreach (var (k, v) in statsNameConversion())
269276
{
270277
result.AppendLine($"T_REC_{k}\t{stats.Data.GetValueOrDefault(v)}");
@@ -318,11 +325,18 @@ protected void GenerateStatistics(StringBuilder result)
318325
GenerateFileHead(result);
319326
GenerateBPM(result);
320327
GenerateNotes(result);
321-
GenerateStatistics(result);
328+
GenerateStatistics(result, chart.Statistics);
322329

323330
return (result.ToString(), alerts);
324331
}
325332

333+
protected virtual Dictionary<string, string> statsRewrite() => new()
334+
{
335+
["BRTTP"] = "NMTTP", ["EXTTP"] = "NMTTP", ["BXTTP"] = "NMTTP",
336+
["BRTHO"] = "NMTHO", ["EXTHO"] = "NMTHO", ["BXTHO"] = "NMTHO",
337+
["EXSLD"] = "NMSLD", ["BXSLD"] = "BRSLD",
338+
};
339+
326340
protected virtual Dictionary<string, string> statsNameConversion() => new()
327341
{
328342
["TAP"] = "NMTAP", ["BRK"] = "BRTAP", ["XTP"] = "EXTAP", ["BXX"] = "BXTAP",

generator/MA2_103Generator.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using MuConvert.chart;
22
using MuConvert.utils;
3-
using static MuConvert.utils.Alert.LEVEL;
43

54
namespace MuConvert.generator;
65

@@ -19,13 +18,13 @@ public MA2_103Generator(bool isUtage = false): base(isUtage)
1918

2019
if (mod == "BX")
2120
{ // 给个警告,还原为BR
22-
Warn(Locale.BreakExIn103, tap, line);
23-
mod = tap is not Hold ? "BR" : "NM";
21+
Warn(Locale.BreakExIn103, tap);
22+
mod = tap is not Hold ? "BR" : "EX";
2423
}
2524
if (mod == "BR")
2625
{
2726
if (tap is Star) name = "BST";
28-
else if (tap is Hold) Warn(Locale.BreakHoldOrSlideIn103, tap, line); // 给个警告。mod不用动,反正等会会忽略
27+
else if (tap is Hold) Warn(Locale.BreakHoldOrSlideIn103, tap); // 给个警告。mod不用动,反正等会会忽略
2928
else name = "BRK";
3029
}
3130
else if (mod == "EX")
@@ -45,8 +44,7 @@ protected override List<MA2Line> AddSlide(Slide slide, int bar, int tick)
4544
var headTap = AddTap(slide.OwnHead, bar, tick);
4645
if (headTap != null)
4746
{
48-
if (hasSameTimeTap(headTap))
49-
alerts.Add(new Alert(Warning, Locale.SimultaneousSlideHead, (chart, slide.OwnHead.Time), null, slide.DebuggerDisplay()));
47+
if (hasSameTimeTap(headTap)) Warn(Locale.SimultaneousSlideHead, slide);
5048
else result.Add(headTap);
5149
}
5250
}
@@ -58,8 +56,8 @@ protected override List<MA2Line> AddSlide(Slide slide, int bar, int tick)
5856
var r = new MA2Line(name, bar, tick, seg.StartKey - 1, string.Join("\t", [waitTime, len, seg.EndKey - 1]));
5957
result.Add(r);
6058

61-
if (slide.IsBreak) Warn(Locale.BreakHoldOrSlideIn103, slide, r);
62-
if (slide.segments.Count > 1) Warn(Locale.ConnectingSlideIn103, slide, r);
59+
if (slide.IsBreak) Warn(Locale.BreakHoldOrSlideIn103, slide);
60+
if (slide.segments.Count > 1) Warn(Locale.ConnectingSlideIn103, slide);
6361
return result;
6462
}
6563

@@ -70,11 +68,13 @@ protected override List<MA2Line> AddSlide(Slide slide, int bar, int tick)
7068
return line with { Name = line.Name[2..5] };
7169
}
7270

73-
protected override Dictionary<string, string> statsNameConversion() => new()
71+
protected override Dictionary<string, string> statsRewrite() => base.statsRewrite().Concat(new Dictionary<string, string>
7472
{
75-
["TAP"] = "NMTAP", ["BRK"] = "BRTAP", ["XTP"] = "EXTAP",
76-
["HLD"] = "NMHLD", ["XHO"] = "EXHLD",
77-
["STR"] = "NMSTR", ["BST"] = "BRSTR", ["XST"] = "EXSTR",
78-
["TTP"] = "NMTTP", ["THO"] = "NMTHO", ["SLD"] = "NMSLD",
79-
};
73+
["BXTAP"] = "BRTAP", ["BRHLD"] = "NMHLD", ["BXHLD"] = "EXHLD", ["BXSTR"] = "BRSTR",
74+
["BRSLD"] = "NMSLD", ["BXSLD"] = "NMSLD",
75+
});
76+
77+
protected override Dictionary<string, string> statsNameConversion() => base.statsNameConversion().RemoveRange([
78+
"BXX", "BHO", "BXH", "XBS", "BSL"
79+
]);
8080
}

i18n/Locale.Designer.cs

Lines changed: 24 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)