Skip to content

Commit e34f633

Browse files
committed
把C2sGenerator改好
1 parent d814915 commit e34f633

1 file changed

Lines changed: 91 additions & 70 deletions

File tree

‎generator/chu/C2sGenerator.cs‎

Lines changed: 91 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ private string Serialize(ChuChart chart, List<Alert> alerts)
6969
List<string> resultLines = [];
7070
foreach (var n in chart.Notes)
7171
{
72-
var line = FormatNote(n, alerts);
73-
if (line != null) resultLines.Add(line);
72+
var lines = FormatNote(n, alerts);
73+
resultLines.AddRange(lines);
7474
}
7575

7676
foreach (var line in resultLines.Concat(slaLines).OrderBy(_lineOrder))
@@ -87,82 +87,103 @@ private string Serialize(ChuChart chart, List<Alert> alerts)
8787
}
8888
}
8989

90-
private static string AirColorTag(ChuNote n, List<Alert> alerts)
90+
private List<string> FormatNote(ChuNote n, List<Alert> alerts)
9191
{
92-
if (C2sAllowedColors.Contains(n.Tag)) return n.Tag;
93-
else
92+
var (m, o) = Utils.BarAndTick(n.Time, RSL);
93+
List<List<string>> results = [];
94+
95+
if (n.Type is ChuNoteType.Tap or ChuNoteType.Flick or ChuNoteType.Mine)
9496
{
95-
if (n.Tag != "") alerts.Add(new Alert(Alert.LEVEL.Warning, string.Format(Locale.C2SUnsupportedAirColor, "C2S Generator", n.Type, n.Tag), n.Time));
96-
return "DEF";
97+
var name = n.Type switch
98+
{
99+
ChuNoteType.Tap => n.IsAir ? n.AirDirection.ToString()
100+
: (n.IsEx ? "CHR" : "TAP"),
101+
ChuNoteType.Flick => "FLK",
102+
ChuNoteType.Mine => "MNE",
103+
_ => throw Utils.Fail(),
104+
};
105+
List<string> r = [name, m.ToString(), o.ToString(), n.Cell.ToString(), n.Width.ToString()];
106+
107+
if (n.Type == ChuNoteType.Tap && n.IsEx) r.Add(ExDirections_ToUgc[n.Ex!.Value]); // CHR
108+
else if (n.Type == ChuNoteType.Flick) r.Add(n.Ex == ExDirection.RS ? "R" : "L"); // FLK
109+
else if (n.IsAir)
110+
{ // AIR
111+
var targetStr = AsC2sPreviousStr(n.TargetNote);
112+
Utils.Assert(targetStr != null, "MuConvert内部错误:Air音符的TargetNote出现了不合法的类型!");
113+
r.AddRange(targetStr!, AirColor_ToUgc(n));
114+
}
115+
116+
results.Add(r);
117+
if (n.SpeedGroup != 0) // 分音符变速组 SLA 的处理
118+
results.Add(["SLA", ..r[1..5], "1", n.SpeedGroup.ToString()]);
97119
}
98-
}
99-
private static string AirCrushColorTag(ChuNote n, List<Alert> alerts)
100-
{
101-
if (C2sAllowedCrushColors.Contains(n.Tag)) return n.Tag;
102120
else
103121
{
104-
if (n.Tag != "") alerts.Add(new Alert(Alert.LEVEL.Warning, string.Format(Locale.C2SUnsupportedAirColor, "C2S Generator", n.Type, n.Tag), n.Time));
105-
return "DEF";
106-
}
107-
}
108-
109-
private static string FLKTag(ChuNote n) => n.Tag is "L" or "R" ? n.Tag : "L";
110-
111-
private string? FormatNote(ChuNote n, List<Alert> alerts)
112-
{
113-
var (m, o) = Utils.BarAndTick(n.Time, RSL);
114-
var durTicks = Utils.Tick(n.Duration, RSL);
115-
if (IsChainContinueSegments(n))
116-
{ // 特殊地,对于slide的后续段:为了保证能接上,必须保证start tick接在前一个音符的endTime的后面,duration也采用end-start的方式计算durTicks。否则可能会,因为舍入的误差,造成没有办法接起来。
117-
(m, o) = Utils.BarAndTick(n.Previous!.EndTime, RSL);
118-
durTicks = Utils.Tick(n.EndTime, RSL) - Utils.Tick(n.Previous!.EndTime, RSL);
119-
}
120-
var result = n.Type switch
121-
{
122-
"TAP" or "CHR" => $"{n.Type}\t{m}\t{o}\t{n.Cell}\t{n.Width}",
123-
"HLD" or "HXD" => $"{n.Type}\t{m}\t{o}\t{n.Cell}\t{n.Width}\t{durTicks}",
124-
"SLD" or "SLC" or "SXD" or "SXC" => $"{n.Type}\t{m}\t{o}\t{n.Cell}\t{n.Width}\t{durTicks}\t{n.EndCell}\t{n.EndWidth}\tSLD",
125-
"FLK" => $"FLK\t{m}\t{o}\t{n.Cell}\t{n.Width}\t{FLKTag(n)}",
126-
"AIR" or "AUR" or "AUL" or "ADW" or "ADR" or "ADL" =>
127-
$"{n.Type}\t{m}\t{o}\t{n.Cell}\t{n.Width}\t{n.TargetNote}\t{AirColorTag(n, alerts)}",
128-
"AHD" or "AHX" => $"{n.Type}\t{m}\t{o}\t{n.Cell}\t{n.Width}\t{n.TargetNote}\t{durTicks}\t{AirColorTag(n, alerts)}",
129-
"ASD" or "ASC" => FormatAsdAsc(n, m, o, durTicks, alerts),
130-
"ALD" => FormatAld(n, m, o, durTicks, alerts),
131-
"MNE" => $"MNE\t{m}\t{o}\t{n.Cell}\t{n.Width}",
132-
_ => alert(),
133-
};
134-
if (result == null) return null;
135-
if (n.Type is "CHR" or "HXD" or "SXD" or "SXC") result += $"\t{n.Tag}";
136-
137-
#region 分音符变速组 SLA 的处理
138-
if (n.SpeedGroup != 0)
139-
{
140-
slaLines.Add($"SLA\t{m}\t{o}\t{n.Cell}\t{n.Width}\t1\t{n.SpeedGroup}");
141-
if (durTicks > 0)
122+
var name = (n.Type, n.IsAir) switch
123+
{
124+
(ChuNoteType.Hold, true) => n.IsEx ? "AHX" : "AHD",
125+
(ChuNoteType.Hold, false) => n.IsEx ? "HXD" : "HLD",
126+
(ChuNoteType.Slide, true) => "ASD",
127+
(ChuNoteType.Slide, false) => n.IsEx ? "SXD" : "SLD",
128+
(ChuNoteType.Crush, true) => "ALD",
129+
_ => throw Utils.Fail(),
130+
};
131+
132+
var start = (n.Time, n.Cell, n.Width, n.Height);
133+
foreach (var seg in n.Segments)
142134
{
143-
var (endM, endO) = Utils.BarAndTick(n.EndTime, RSL);
144-
var (endC, endW) = IsSlide(n) || IsAirSlide(n) || IsAirCrush(n) ? (n.EndCell, n.EndWidth) : (n.Cell, n.Width);
145-
slaLines.Add($"SLA\t{endM}\t{endO}\t{endC}\t{endW}\t1\t{n.SpeedGroup}");
135+
// 必备的:name bar tick cell width
136+
var (sB, sT) = Utils.BarAndTick(start.Time, RSL);
137+
List<string> r = [name, sB.ToString(), sT.ToString(), start.Cell.ToString(), start.Width.ToString()];
138+
139+
// 前驱targetNote 或 crushInterval
140+
if (NeedsTargetNote(n))
141+
{
142+
var targetStr = AsC2sPreviousStr(n.TargetNote);
143+
Utils.Assert(targetStr != null, "MuConvert内部错误:Air音符的TargetNote出现了不合法的类型!");
144+
r.Add(targetStr!);
145+
}
146+
else if (n.Type == ChuNoteType.Crush)
147+
r.Add(Utils.Tick(n.CrushInterval ?? 100, RSL).ToString());
148+
149+
// Air且不是Air-Hold的情况,这里要加上height
150+
if (n.IsAir && n.Type != ChuNoteType.Hold)
151+
r.Add($"{n.Height:F1}");
152+
153+
// 持续时间
154+
// 为了保持两段之间紧密相接,durTicks必须通过end和start的tick直接作差得到,不能把seg.Length直接转tick,
155+
// 不然可能会由于舍入误差,导致差1tick接不上等情况。
156+
var endTime = start.Time + seg.Length;
157+
var durTicks = Utils.Tick(endTime, RSL) - Utils.Tick(start.Time, RSL);
158+
r.Add(durTicks.ToString());
159+
160+
// 结束的 cell width [height]
161+
if (n.Type is ChuNoteType.Slide or ChuNoteType.Crush)
162+
{
163+
r.AddRange([seg.EndCell.ToString(), seg.EndWidth.ToString()]);
164+
if (n.IsAir) r.Add($"{seg.EndHeight:F1}");
165+
}
166+
167+
// 颜色
168+
if (n.IsAir) r.Add(n.Color.ToString());
169+
else if (n.Type == ChuNoteType.Slide) r.Add("SLD"); // C2S 1.13版本以上,Slide在最后,还需要加一个”SLD“后缀
170+
171+
// Ex音符的话,要加上Ex方向
172+
if (n.IsEx) r.Add(ExDirections_ToUgc[n.Ex!.Value]);
173+
174+
results.Add(r);
175+
start = (endTime, seg.EndCell, seg.EndWidth, seg.EndHeight);
176+
if (n.SpeedGroup != 0) // 分音符变速组 SLA 的处理
177+
results.Add(["SLA", ..r[1..5], "1", n.SpeedGroup.ToString()]);
178+
}
179+
if (n.SpeedGroup != 0)
180+
{ // 分音符变速组 SLA 的处理:参照PenguinTools的实现,要把最后一段的结束点,也加到SLA上
181+
var (sB, sT) = Utils.BarAndTick(start.Time, RSL); // 这里的start.Time,其实是最后一段的endTime
182+
List<string> sParts = [sB.ToString(), sT.ToString(), start.Cell.ToString(), start.Width.ToString()]; // start.Cell/Width,实际上也是最后一段的endCell/endWidth
183+
results.Add(["SLA", ..sParts, "1", n.SpeedGroup.ToString()]);
146184
}
147185
}
148-
#endregion
149186

150-
return result;
151-
152-
string? alert()
153-
{
154-
alerts.Add(new Alert(Alert.LEVEL.Warning, Locale.C2SUnknownNoteType, n.Time));
155-
return null;
156-
}
157-
}
158-
159-
private static string FormatAsdAsc(ChuNote n, int m, int o, int durTicks, List<Alert> alerts)
160-
{
161-
return FormattableString.Invariant($"{n.Type}\t{m}\t{o}\t{n.Cell}\t{n.Width}\t{n.TargetNote}\t{n.Height:F1}\t{durTicks}\t{n.EndCell}\t{n.EndWidth}\t{n.EndHeight:F1}\t{AirColorTag(n, alerts)}");
162-
}
163-
164-
private static string FormatAld(ChuNote n, int m, int o, int durTicks, List<Alert> alerts)
165-
{
166-
return FormattableString.Invariant($"ALD\t{m}\t{o}\t{n.Cell}\t{n.Width}\t{Utils.Tick(n.CrushInterval, RSL)}\t{n.Height:F1}\t{durTicks}\t{n.EndCell}\t{n.EndWidth}\t{n.EndHeight:F1}\t{AirCrushColorTag(n, alerts)}");
187+
return results.Select(x=>string.Join('\t', x)).ToList();
167188
}
168189
}

0 commit comments

Comments
 (0)