Skip to content

Commit fa9dbcb

Browse files
committed
[F] UGCParser对Slide的解析
1 parent 54bc9f4 commit fa9dbcb

2 files changed

Lines changed: 57 additions & 44 deletions

File tree

generator/chu/C2sGenerator.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ public class C2sGenerator : IGenerator<ChuChart>
1111
public (string, List<Alert>) Generate(ChuChart chart)
1212
{
1313
var alerts = new List<Alert>();
14-
var text = Serialize(chart);
14+
var text = Serialize(chart, alerts);
1515
return (text, alerts);
1616
}
1717

18-
private static string Serialize(ChuChart chart)
18+
private static string Serialize(ChuChart chart, List<Alert> alerts)
1919
{
2020
chart.Sort();
2121

@@ -58,13 +58,16 @@ private static string Serialize(ChuChart chart)
5858
sb.AppendLine();
5959

6060
foreach (var n in chart.Notes)
61-
sb.AppendLine(FormatNote(n, RSL));
61+
{
62+
var line = FormatNote(n, RSL, alerts);
63+
if (line != null) sb.AppendLine(line);
64+
}
6265

6366
sb.AppendLine();
6467
return sb.ToString();
6568
}
6669

67-
private static string FormatNote(ChuNote n, int tpm)
70+
private static string? FormatNote(ChuNote n, int tpm, List<Alert> alerts)
6871
{
6972
var (m, o) = Utils.BarAndTick(n.Time, tpm);
7073
var durTicks = Utils.Tick(n.Duration, tpm);
@@ -86,8 +89,14 @@ private static string FormatNote(ChuNote n, int tpm)
8689
"ASD" or "ASC" => FormatAsdAsc(n, m, o, durTicks),
8790
"ALD" => FormatAld(n, m, o),
8891
"MNE" => $"MNE\t{m}\t{o}\t{n.Cell}\t{n.Width}",
89-
_ => $"TAP\t{m}\t{o}\t{n.Cell}\t{n.Width}"
92+
_ => alert(),
9093
};
94+
95+
string? alert()
96+
{
97+
alerts.Add(new Alert(Alert.LEVEL.Warning, Locale.C2SUnknownNoteType, n.Time));
98+
return null;
99+
}
91100
}
92101

93102
private static string FormatAsdAsc(ChuNote n, int m, int o, int durTicks)

parser/chu/UgcParser.cs

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ private static int ParseNoteLine(string[] lines, int idx, ChuChart chart, List<A
267267
return idx;
268268
}
269269

270-
var note = new ChuNote
270+
ChuNote? note = new ChuNote
271271
{
272272
Time = measure + new Rational(tick, RSL),
273273
};
@@ -277,7 +277,10 @@ private static int ParseNoteLine(string[] lines, int idx, ChuChart chart, List<A
277277
switch (typeChar)
278278
{
279279
case 't':
280-
ParseTapNote(code, note, alerts, lineNum, chart);
280+
ParseTapNote(code, note, alerts, lineNum, chart, false);
281+
break;
282+
case 'x':
283+
ParseTapNote(code, note, alerts, lineNum, chart, true);
281284
break;
282285

283286
case 'h':
@@ -286,25 +289,23 @@ private static int ParseNoteLine(string[] lines, int idx, ChuChart chart, List<A
286289

287290
case 's':
288291
idx = ParseSlideNote(lines, idx, code, note, alerts, chart);
292+
note = null; // ParseSlideNote中,会自己构造note并自己添加进chart。因此这里默认的统一note不应被添加进chart。
289293
break;
290294

291295
case 'a':
292296
ParseAirNote(code, note, alerts, lineNum, chart);
293297
break;
294298

295-
case 'x':
296-
ParseChrNote(code, note, alerts, lineNum, chart);
297-
break;
298-
299299
case 'f':
300300
note.Type = "FLK";
301301
ParseCellWidth(code, 1, note, alerts, lineNum, chart);
302302
if (code.Length > 3)
303303
note.Tag = code[3..];
304304
break;
305305

306-
case 'c':
307-
return idx; // Margrete Air Crush, silently skip
306+
case 'c': // Umiguri的CLICK音符,疑似在C2s中是没有对应的。这个音符没有Cell和Width,除了Type什么都没有,所以直接存下来就可以了。
307+
note.Type = "CLICK";
308+
break;
308309

309310
case 'd':
310311
note.Type = "MNE";
@@ -316,14 +317,20 @@ private static int ParseNoteLine(string[] lines, int idx, ChuChart chart, List<A
316317
return idx;
317318
}
318319

319-
chart.Notes.Add(note);
320+
if (note != null) chart.Notes.Add(note);
320321
return idx;
321322
}
322323

323-
private static void ParseTapNote(string code, ChuNote note, List<Alert> alerts, int lineNum, ChuChart chart)
324+
private static void ParseTapNote(string code, ChuNote note, List<Alert> alerts, int lineNum, ChuChart chart, bool isCHR)
324325
{
325326
note.Type = "TAP";
326327
ParseCellWidth(code, 1, note, alerts, lineNum, chart);
328+
if (isCHR)
329+
{
330+
note.Type = "CHR";
331+
var extraRaw = code.Length > 3 ? code[3..] : "";
332+
note.Tag = ChrExtras.GetValueOrDefault(extraRaw, extraRaw);
333+
}
327334
}
328335

329336
private static int ParseHoldNote(string[] lines, int idx, string code, ChuNote note, List<Alert> alerts, ChuChart chart)
@@ -335,7 +342,7 @@ private static int ParseHoldNote(string[] lines, int idx, string code, ChuNote n
335342
while (idx + 1 < lines.Length)
336343
{
337344
var nextLine = lines[idx + 1].Trim();
338-
if (!TryParseFollowerLine(nextLine, out var duration, out _, out _))
345+
if (!TryParseFollowerLine(nextLine, out _, out var duration, out _, out _))
339346
{
340347
if (nextLine.StartsWith('\'') || nextLine.StartsWith('@')) { idx++; continue; }
341348
break;
@@ -351,48 +358,59 @@ private static int ParseHoldNote(string[] lines, int idx, string code, ChuNote n
351358
return idx;
352359
}
353360

354-
private static int ParseSlideNote(string[] lines, int idx, string code, ChuNote note, List<Alert> alerts, ChuChart chart)
361+
private static int ParseSlideNote(string[] lines, int idx, string code, ChuNote previousNote, List<Alert> alerts, ChuChart chart)
355362
{
356-
note.Type = "SLD";
357-
ParseCellWidth(code, 1, note, alerts, idx + 1, chart);
363+
// 注:一开始从外面传进来的previousNote,最后并不会被添加进chart里,只是作为第一段的起点参照而已。
364+
var startTime = previousNote.Time;
365+
ParseCellWidth(code, 1, previousNote, alerts, idx + 1, chart);
366+
previousNote.EndCell = previousNote.Cell;
367+
previousNote.EndWidth = previousNote.Width;
358368

359369
bool foundFirst = false;
360370
while (idx + 1 < lines.Length)
361-
{
371+
{ // 循环处理所有的跟随行。idx始终指向上一条已经处理完的行。
362372
var nextLine = lines[idx + 1].Trim();
363-
if (!TryParseFollowerLine(nextLine, out var duration, out var endCell, out var endWidth))
373+
if (!TryParseFollowerLine(nextLine, out var marker, out var duration, out var endCell, out var endWidth, true))
364374
{
365375
if (nextLine.StartsWith('\'') || nextLine.StartsWith('@')) { idx++; continue; }
366376
break;
367377
}
368378

369-
note.Duration += new Rational(duration, RSL);
370-
note.EndCell = endCell;
371-
note.EndWidth = endWidth;
379+
var segmentEnd = startTime + new Rational(duration, RSL);
380+
var note = new ChuNote
381+
{
382+
Type = marker == "s" ? "SLD" : "SLC",
383+
Time = previousNote.EndTime, Cell = previousNote.EndCell, Width = previousNote.EndWidth,
384+
Duration = segmentEnd - previousNote.EndTime,
385+
EndCell = endCell, EndWidth = endWidth,
386+
TargetNote = "SLD"
387+
};
388+
chart.Notes.Add(note);
389+
previousNote = note;
372390
idx++;
373391
foundFirst = true;
374392
}
375393

376394
if (!foundFirst)
377-
alerts.Add(new Alert(Warning, $"SLD 音符缺少时长跟随行") { Line = idx + 1, RelevantNote = FormatNoteRef(note, chart) });
395+
alerts.Add(new Alert(Warning, $"SLD 音符缺少时长跟随行") { Line = idx + 1, RelevantNote = FormatNoteRef(previousNote, chart) });
378396

379397
return idx;
380398
}
381399

382-
private static bool TryParseFollowerLine(string line, out int duration, out int endCell, out int endWidth, bool requireEndCellWidth = false)
400+
private static bool TryParseFollowerLine(string line, out string marker, out int duration, out int endCell, out int endWidth, bool requireEndCellWidth = false)
383401
{
384402
duration = 0;
385403
endCell = 0;
386404
endWidth = 1;
405+
marker = "";
387406

388407
if (!line.StartsWith('#')) return false;
389408

390409
// support both >s (SLD) and >c (SLC) follower lines
391-
int gtIdx = -1;
392-
int markerLen = 0;
393-
if (line.Contains(">s")) { gtIdx = line.IndexOf(">s", StringComparison.Ordinal); markerLen = 2; }
394-
else if (line.Contains(">c")) { gtIdx = line.IndexOf(">c", StringComparison.Ordinal); markerLen = 2; }
410+
int gtIdx = line.IndexOfAny(['>', ':']);
395411
if (gtIdx < 1) return false;
412+
marker = line[gtIdx+1].ToString();
413+
int markerLen = 2;
396414

397415
var durationStr = line[1..gtIdx];
398416
if (!int.TryParse(durationStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out duration)) return false;
@@ -467,20 +485,6 @@ private static void ParseAirNote(string code, ChuNote note, List<Alert> alerts,
467485
}
468486
}
469487

470-
private static void ParseChrNote(string code, ChuNote note, List<Alert> alerts, int lineNum, ChuChart chart)
471-
{
472-
note.Type = "CHR";
473-
if (code.Length < 3)
474-
{
475-
alerts.Add(new Alert(Warning, $"CHR 音符代码过短: {code}") { Line = lineNum });
476-
return;
477-
}
478-
479-
ParseCellWidth(code, 1, note, alerts, lineNum, chart);
480-
var extraRaw = code.Length > 3 ? code[3..] : "";
481-
note.Tag = ChrExtras.GetValueOrDefault(extraRaw, extraRaw);
482-
}
483-
484488
private static int HexCharToInt(char c)
485489
{
486490
return c switch

0 commit comments

Comments
 (0)