Skip to content

Commit a9a83a1

Browse files
committed
[+] UGC AirCrush
1 parent afd485b commit a9a83a1

3 files changed

Lines changed: 31 additions & 16 deletions

File tree

generator/chu/UgcGenerator.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ private static string Serialize(ChuChart ugc, List<Alert> alerts)
100100
var marker = (n.Type == "AHX") ? 'c' : 's';
101101
sb.AppendLine($"#{durTicks}>{marker}");
102102
}
103+
else if (n.Type is "ALD" && durTicks > 0)
104+
sb.AppendLine($"#{durTicks}>c{IToH36(n.EndCell)}{IToH36(n.EndWidth)}{EncodeAirHeight(n.EndHeight)}");
103105
}
104106
return sb.ToString();
105107
}
@@ -150,7 +152,10 @@ private static bool IsSlideContinueSegments(ChuNote n) // Air Slide的前驱只
150152
=> (IsSlide(n) && IsSlide(n.Previous)) || (IsAirSlide(n) && IsAirSlide(n.Previous));
151153
private static char SlideFollowerMarker(string t) => t is "SLC" or "SXC" or "ASC" ? 'c' : 's';
152154

153-
private static string EncodeAirHeight(decimal value) => IToH36((int)Math.Round(C2U_Height(value) * 10));
155+
private static string EncodeAirHeight(decimal value) => IToH36((int)Math.Round(C2U_Height(value) * 10)).PadLeft(2, '0');
156+
157+
private static string CrushColor(string t) => C2U_AirColor.GetValueOrDefault(t, t.Length > 0 ? t[..1] : "0");
158+
private static string CrushInterval(int crushInterval) => crushInterval > 10000 ? "$" : crushInterval.ToString();
154159

155160
private static string UCode(ChuNote n)
156161
{
@@ -169,7 +174,7 @@ private static string UCode(ChuNote n)
169174
"AIR" or "AUR" or "AUL" or "ADW" or "ADR" or "ADL" => $"a{c}{w}{C2U_AirDirections[n.Type]}{C2U_AirColor.GetValueOrDefault(n.Tag, "N")}",
170175
// AIR-HOLD (v8): #BarTick:H x w c + 子行 #OffsetTick:s / :c(见 Umiguri Chart v8 doc)
171176
"AHD" or "AHX" => $"H{c}{w}{C2U_AirColor.GetValueOrDefault(n.Tag, "N")}",
172-
"ALD" => "", // TODO
177+
"ALD" => $"C{c}{w}{EncodeAirHeight(n.Height)}{CrushColor(n.Tag)},{CrushInterval(n.CrushInterval)}",
173178
_ => ""
174179
};
175180
}

parser/chu/UgcParser.cs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -364,14 +364,6 @@ private void ParseHeightAndColor(ChuNote n, string str, List<Alert> alerts, int
364364
else if (int.TryParse(intervalStr, out var interval)) n.CrushInterval = interval;
365365
else alerts.Add(new Alert(Warning, "解析Air-Crush的interval属性失败!", n.Time, null, lineNum, FormatNoteRef(n, str)));
366366
}
367-
else if (noteType is "C" && str.Length == 2 && Version < 8)
368-
{
369-
var intervalStr = str.Last();
370-
str = str[..^1] + "N";
371-
if (intervalStr == 'Z') n.CrushInterval = 38400;
372-
else if (TryHToI(intervalStr, out var interval)) n.CrushInterval = interval;
373-
else alerts.Add(new Alert(Warning, "解析Air-Crush的interval属性失败!", n.Time, null, lineNum, FormatNoteRef(n, str)));
374-
}
375367

376368
// 剩的部分都满足:最后一位是颜色,前面是高度
377369
if (str.Length > 0)
@@ -544,25 +536,42 @@ private void ParseAirNote(string code, ChuNote note, List<Alert> alerts, int lin
544536
ParseHeightAndColor(note, mainPart[2..], alerts, lineNum, "a");
545537
}
546538

547-
private static int ParseAirCrushNote(string[] lines, int idx, string code, ChuNote previousNote, List<Alert> alerts, ChuChart chart)
539+
private int ParseAirCrushNote(string[] lines, int idx, string code, ChuNote note, List<Alert> alerts, ChuChart chart)
548540
{
549-
// TODO 尚未实现,所以先给个警告
550-
alerts.Add(new Alert(Warning, "当前版本尚未实现对Air-Crush(UMIGURI的':C'或':T'音符)的解析。") { Line = idx, RelevantNote = lines[idx] });
541+
note.Type = "ALD";
542+
ParseCellWidth(code, 1, note, alerts, idx + 1, chart);
543+
if (code.Length <= 3) alerts.Add(new Alert(Warning, "AirCrush缺少参数!", note.Time, (double)chart.ToSecond(note.Time), idx+1, lines[idx]));
544+
else ParseHeightAndColor(note, code[3..], alerts, idx+1, "C");
551545

552546
bool foundFirst = false;
547+
bool intervalSet = Version >= 8;
553548
while (idx + 1 < lines.Length)
554-
{ // 循环处理所有的跟随行。idx始终指向上一条已经处理完的行。
549+
{
555550
var nextLine = lines[idx + 1].Trim();
556-
if (!TryParseFollowerLine(nextLine, out var marker, out var duration, out _, out _, out _, false))
551+
if (!TryParseFollowerLine(nextLine, out var marker, out var endTick, out var endCell, out var endWidth, out var endHeight, Version >= 8))
557552
{
558553
if (nextLine.StartsWith('\'') || nextLine.StartsWith('@')) { idx++; continue; }
559554
break;
560555
}
561556

562-
// TODO 尚未实现
557+
if (Version >= 8 && marker != "c")
558+
alerts.Add(new Alert(Warning, $"Air-Crush(v8)子行标记应为 'c',实际为 '{marker}'", note.Time, (double)chart.ToSecond(note.Time), idx + 1, nextLine));
559+
560+
if (Version <= 6 && !intervalSet && marker == "s")
561+
{
562+
note.CrushInterval = endTick;
563+
intervalSet = true;
564+
}
565+
566+
note.Duration = new Rational(endTick, RSL);
567+
if (endCell != null) note.EndCell = endCell.Value;
568+
if (endWidth != null) note.EndWidth = endWidth.Value;
569+
if (endHeight != null) note.EndHeight = U2C_Height(endHeight.Value);
570+
563571
idx++;
564572
foundFirst = true;
565573
}
574+
chart.Notes.Add(note);
566575

567576
if (!foundFirst)
568577
alerts.Add(new Alert(Warning, $"air-crush 音符缺少时长跟随行") { Line = idx + 1, RelevantNote = lines[idx] });

tests/chu/ChuTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ private static bool DurationsEquivalent(ChuNote e, ChuNote a)
109109
private static bool TagsEquivalent(ChuNote e, ChuNote a)
110110
{
111111
if (e.Tag == a.Tag) return true;
112+
if (e.Type == "ALD") return true; // C2S的ALD行,根据观测,是不支持颜色tag的。因此不要比较
112113
if (ChuUtils.IsGeneralizedAir(e))
113114
{
114115
if ((e.Tag == "DEF" && a.Tag == "") || (e.Tag == "" && a.Tag == "DEF"))

0 commit comments

Comments
 (0)