Skip to content

Commit ba1bbcc

Browse files
committed
[F&R] 1. 现在的ugcgenerator缺少SflEvent的生成/写出。
2. 现在的ugcparser,@SPDMOD的解析是错的。 3. 抽取TryParseUgcMeasureTick方法
1 parent 84a39e5 commit ba1bbcc

5 files changed

Lines changed: 58 additions & 19 deletions

File tree

chart/chu/ChuNote.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class ChuNote: BaseNote
1515
/** 宽度 (1–16) */
1616
public int Width { get; set; } = 1;
1717
/** HLD/SLD/AHD/ASD等的 持续时长 */
18-
public Rational Duration { get; set; } = 0;
18+
public Rational Duration { get; set => field = value.CanonicalForm; } = 0;
1919
/** SLD 终点列 */
2020
public int EndCell { get; set; }
2121
/** SLD 终点宽度 */
@@ -27,5 +27,5 @@ public class ChuNote: BaseNote
2727
/** ASD/ASC/ALD上具有的、目前含义还不明确的字段,统一收集到这个里面。 */
2828
public List<int> ExtraData = [];
2929

30-
public override Rational EndTime => Time + Duration;
30+
public override Rational EndTime => (Time + Duration).CanonicalForm;
3131
}

generator/chu/C2sGenerator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ private static C2sChart ConvertToC2s(IChuChart chart, List<Alert> alerts)
3333
};
3434
result.BpmList.AddRange(ugc.BpmList);
3535
result.MetList.AddRange(ugc.MetList);
36+
result.SflList.AddRange(ugc.SflList);
3637
result.Notes = ugc.Notes;
3738
return result;
3839
}

generator/chu/UgcGenerator.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ private static UgcChart ConvertToUgc(IChuChart chart, List<Alert> alerts)
3636
};
3737
result.BpmList.AddRange(c2s.BpmList);
3838
result.MetList.AddRange(c2s.MetList);
39+
result.SflList.AddRange(c2s.SflList);
3940
result.Notes = c2s.Notes;
4041
return result;
4142
}
@@ -70,6 +71,13 @@ private static string Serialize(UgcChart ugc)
7071
sb.AppendLine($"@BPM\t{m}'{o}\t{b.Bpm:F5}");
7172
}
7273
sb.AppendLine("@TIL\t0\t0'0\t1.00000");
74+
75+
foreach (var s in ugc.SflList.OrderBy(x => x.Time))
76+
{
77+
var (m, o) = Utils.BarAndTick(s.Time, tpm);
78+
sb.AppendLine($"@SPDMOD\t{m}'{o}\t{s.Multiplier:0.00000}");
79+
}
80+
7381
sb.AppendLine("@MAINTIL\t0");
7482
sb.AppendLine("@ENDHEAD");
7583
sb.AppendLine();

parser/chu/UgcParser.cs

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,26 @@ public class UgcParser : IParser<UgcChart>
6161
}
6262
}
6363

64+
FinalizeUgcSflDurations(chart);
6465
return (chart, alerts);
6566
}
6667

68+
private static void FinalizeUgcSflDurations(UgcChart chart)
69+
{
70+
if (chart.SflList.Count == 0) return;
71+
chart.SflList = chart.SflList.OrderBy(s => s.Time).ToList();
72+
var endTime = Utils.Max(chart.SflList[^1].Time, chart.Notes.Max(x=>x.EndTime));
73+
74+
for (var i = 0; i < chart.SflList.Count; i++)
75+
{
76+
var t = chart.SflList[i].Time;
77+
var dur = (i < chart.SflList.Count - 1 ? chart.SflList[i+1].Time : endTime) - t;
78+
chart.SflList[i] = chart.SflList[i] with { Duration = dur.CanonicalForm };
79+
}
80+
81+
chart.SflList = chart.SflList.Where(x => x.Multiplier != 1).ToList(); // 倍率为1的,没必要放进来的
82+
}
83+
6784
private static void ParseHeaderLine(string line, UgcChart chart, List<Alert> alerts, int lineNum)
6885
{
6986
if (!line.StartsWith('@'))
@@ -154,10 +171,7 @@ private static void ParseHeaderLine(string line, UgcChart chart, List<Alert> ale
154171
{
155172
var measureOffset = bpmPart[..bpmSpaceIdx];
156173
var bpmValueStr = bpmPart[(bpmSpaceIdx + 1)..];
157-
var apostropheIdx = measureOffset.IndexOf('\'');
158-
if (apostropheIdx > 0
159-
&& int.TryParse(measureOffset[..apostropheIdx], NumberStyles.Integer, CultureInfo.InvariantCulture, out var bpmMeasure)
160-
&& int.TryParse(measureOffset[(apostropheIdx + 1)..], NumberStyles.Integer, CultureInfo.InvariantCulture, out var bpmOffset)
174+
if (TryParseUgcMeasureTick(measureOffset, out var bpmMeasure, out var bpmOffset)
161175
&& decimal.TryParse(bpmValueStr, NumberStyles.Float, CultureInfo.InvariantCulture, out var bpmValue))
162176
{
163177
var tpm = chart.TicksPerBeat * 4;
@@ -182,20 +196,40 @@ private static void ParseHeaderLine(string line, UgcChart chart, List<Alert> ale
182196
break;
183197

184198
case "@SPDMOD":
199+
{
200+
var parts = value.Split('\t', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
201+
if (parts.Length >= 2
202+
&& TryParseUgcMeasureTick(parts[0], out var meas, out var tick)
203+
&& decimal.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var mult))
185204
{
186-
var parts = value.Split(['\t', ' '], StringSplitOptions.RemoveEmptyEntries);
187-
if (parts.Length >= 2 && int.TryParse(parts[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var tilMeasure)
188-
&& double.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var tilMult))
189-
chart.SflList.Add((tilMeasure, Rational.Zero, (decimal)tilMult));
205+
var tpm = chart.TicksPerBeat * 4;
206+
chart.SflList.Add((meas + new Rational(tick, tpm), Rational.Zero, mult));
190207
}
208+
else
209+
alerts.Add(new Alert(Warning, $"@SPDMOD 格式错误: {line}") { Line = lineNum });
191210
break;
211+
}
192212

193213
default:
194214
alerts.Add(new Alert(Info, $"未知头部标签: {tag}") { Line = lineNum });
195215
break;
196216
}
197217
}
198218

219+
/** UGC 时刻字符串 measure'tick(@BPM、@SPDMOD、音符行 #m't 共用)。 */
220+
private static bool TryParseUgcMeasureTick(string measureTick, out int measure, out int tick)
221+
{
222+
measure = 0;
223+
tick = 0;
224+
measureTick = measureTick.Trim();
225+
var ap = measureTick.IndexOf('\'');
226+
if (ap <= 0)
227+
return false;
228+
229+
return int.TryParse(measureTick[..ap], NumberStyles.Integer, CultureInfo.InvariantCulture, out measure)
230+
&& int.TryParse(measureTick[(ap + 1)..], NumberStyles.Integer, CultureInfo.InvariantCulture, out tick);
231+
}
232+
199233
private static int ParseNoteLine(string[] lines, int idx, UgcChart chart, List<Alert> alerts)
200234
{
201235
var line = lines[idx];
@@ -219,21 +253,15 @@ private static int ParseNoteLine(string[] lines, int idx, UgcChart chart, List<A
219253
var prefix = line[..colonIdx];
220254
var code = line[(colonIdx + 1)..];
221255
var hashIdx = prefix.IndexOf('#');
222-
var apostropheIdx = prefix.IndexOf('\'');
223-
if (hashIdx < 0 || apostropheIdx < 0 || apostropheIdx <= hashIdx + 1)
256+
if (hashIdx < 0)
224257
{
225258
alerts.Add(new Alert(Warning, $"音符行前缀格式错误: {line}") { Line = lineNum });
226259
return idx;
227260
}
228261

229-
if (!int.TryParse(prefix[(hashIdx + 1)..apostropheIdx], NumberStyles.Integer, CultureInfo.InvariantCulture, out var measure))
230-
{
231-
alerts.Add(new Alert(Warning, $"无法解析 measure: {line}") { Line = lineNum });
232-
return idx;
233-
}
234-
if (!int.TryParse(prefix[(apostropheIdx + 1)..], NumberStyles.Integer, CultureInfo.InvariantCulture, out var tick))
262+
if (!TryParseUgcMeasureTick(prefix[(hashIdx + 1)..], out var measure, out var tick))
235263
{
236-
alerts.Add(new Alert(Warning, $"无法解析 tick: {line}") { Line = lineNum });
264+
alerts.Add(new Alert(Warning, $"无法解析 measure'tick: {line}") { Line = lineNum });
237265
return idx;
238266
}
239267

utils/Utils.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ internal static Exception Fail(string msg = "")
2828

2929
public static BigInteger Max(BigInteger a, BigInteger b) => a > b ? a : b;
3030

31+
public static Rational Max(Rational a, Rational b) => a > b ? a : b;
32+
3133
public static Rational Min(Rational a, Rational b) => a < b ? a : b;
3234

3335
private static readonly Dictionary<string, int> _simaiLexerMap = Enumerable.Range(1, L.ruleNames.Length)

0 commit comments

Comments
 (0)