diff --git a/MaiChartManager/Controllers/Charts/ImportChartController.cs b/MaiChartManager/Controllers/Charts/ImportChartController.cs index 186c5dc..b065440 100644 --- a/MaiChartManager/Controllers/Charts/ImportChartController.cs +++ b/MaiChartManager/Controllers/Charts/ImportChartController.cs @@ -76,13 +76,6 @@ public ImportChartCheckResult ImportChartCheck(IFormFile file, [FromForm] bool i } # endregion - if (targetLevelMap.Count == 0) // 没有能够被映射的谱面 - { - errors.Add(new ImportChartMessage(Locale.MusicNoCharts, MessageLevel.Fatal)); - fatal = true; - return new ImportChartCheckResult(!fatal, errors, new Dictionary(), false, title, 0, null); - } - var first = maiData.First; var isDx = false; List resultCharts = []; @@ -118,8 +111,13 @@ public ImportChartCheckResult ImportChartCheck(IFormFile file, [FromForm] bool i { // ↓ 此处的参数应该不会影响 check 的结果 var (chart, alerts1) = new SimaiParser(false, maiData.ClockCount).Parse(data.Inote); - resultCharts.Add(chart); alerts.AddRange(alerts1); + if (chart.TotalNotes == 0) + { + errors.Add(new ImportChartMessage(string.Format(Locale.ChartNoNotes, lv), MessageLevel.Warning)); + continue; + } + resultCharts.Add(chart); var (_, alerts2) = new MA2Generator().Generate(chart); alerts.AddRange(alerts2); isDx = isDx || chart.IsDxChart; @@ -135,6 +133,12 @@ public ImportChartCheckResult ImportChartCheck(IFormFile file, [FromForm] bool i if (m != null) errors.Add(m); } } + + if ((StaticSettings.Config.UseLegacyMaiLib ? legacyCharts.Count : resultCharts.Count) == 0) // 没有解析成功的谱面 + { + errors.Add(new ImportChartMessage(Locale.MusicNoCharts, MessageLevel.Fatal)); + fatal = true; + } Dictionary chartPaddingsSec = new(); if (!fatal && resultCharts.Count > 0) diff --git a/MaiChartManager/Controllers/Charts/Services/MaidataImportService.cs b/MaiChartManager/Controllers/Charts/Services/MaidataImportService.cs index 82b3dc0..695f666 100644 --- a/MaiChartManager/Controllers/Charts/Services/MaidataImportService.cs +++ b/MaiChartManager/Controllers/Charts/Services/MaidataImportService.cs @@ -1,4 +1,4 @@ -using MaiChartManager.Models; +using MaiChartManager.Models; using MaiChartManager.Utils; using MuConvert.mai; using MuConvert.utils; @@ -185,14 +185,9 @@ public ImportChartResult ImportMaidata( var lineNoDict = GetLevelLineNo(maiDataText); var targetLevelMap = MapMaidataLevelToGame(maiData); - if (targetLevelMap.Count == 0) // 没有能够被映射的谱面 - { - errors.Add(new ImportChartMessage(Locale.MusicNoCharts, MessageLevel.Fatal)); - return new ImportChartResult(errors, true); - } // 先执行第一步:Parser,因为可能涉及对Chart做出调整 - List<(int lv, int targetLevel, MaidataLevel data, MaiChart chart, List alerts)> parserOutput = []; + List<(int lv, int targetLevel, MaidataLevel data, MaiChart? chart, List alerts)> parserOutput = []; foreach (var (lv, data) in maiData.Levels) { if (!targetLevelMap.ContainsKey(lv)) continue; @@ -204,17 +199,28 @@ public ImportChartResult ImportMaidata( { var parser = new SimaiParser(!isUtage && lv is 2 or 3, maiData.ClockCount); var (chart, alerts) = parser.Parse(data.Inote); + if (chart.TotalNotes == 0) + { + errors.Add(new ImportChartMessage(string.Format(Locale.ChartNoNotes, lv), MessageLevel.Warning)); + chart = null; + } parserOutput.Add((lv, targetLevel, data, chart, alerts)); } catch (ConversionException e) { - parserOutput.Add((lv, targetLevel, data, null!, e.Alerts)); + parserOutput.Add((lv, targetLevel, data, null, e.Alerts)); MergeAlertsIntoImportChartMessages(); return new ImportChartResult(errors, true); } } - var chartPaddingDict = CalcChartPadding(parserOutput.Select(x=>x.chart).ToList()); + var validCharts = parserOutput.Where(x=> x.chart != null).Select(x => x.chart!).ToList(); + if (validCharts.Count == 0) + { + errors.Add(new ImportChartMessage(Locale.MusicNoCharts, MessageLevel.Fatal)); + return new ImportChartResult(errors, true); + } + var chartPaddingDict = CalcChartPadding(validCharts); var chartPadding = chartPaddingDict[shift]; // 当前所选择的模式所具体对应的chartPadding foreach (var c in music.Charts) { c.Enable = false; } // 先把所有难度标记为关闭(马上后面"第二步"的逻辑,会对存在的难度打开) @@ -223,22 +229,13 @@ public ImportChartResult ImportMaidata( // 再执行第二步 foreach (var (lv, targetLevel, data, chart, alerts) in parserOutput) { + if (chart == null) continue; var targetChart = music.Charts[targetLevel]; targetChart.Path = $"{id:000000}_0{targetLevel}.ma2"; #region 计算等级(定数)相关 - var levelNumStr = data.Level; - if (!string.IsNullOrWhiteSpace(levelNumStr)) - { - if (isUtage && !char.IsDigit(levelNumStr[0])) - { - music.UtageKanji = levelNumStr.Substring(0, 1); - levelNumStr = levelNumStr.Substring(1).Replace("?", ""); // 为了处理类似“奏13+?”这种情况,留下13+给后面的逻辑处理 - } - levelNumStr = levelNumStr.Replace("+", ".7"); - } - - float.TryParse(levelNumStr, out var levelNum); + MaiUtils.ParseLevelStr(data.Level, out var levelNum, out var utageKanji); + if (isUtage) music.UtageKanji = utageKanji; targetChart.LevelId = MaiUtils.GetLevelId((int)(levelNum * 10)); // 忽略定数 if (!ignoreLevelNum) diff --git a/MaiChartManager/Locale.Designer.cs b/MaiChartManager/Locale.Designer.cs index 4d05054..5eb7b54 100644 --- a/MaiChartManager/Locale.Designer.cs +++ b/MaiChartManager/Locale.Designer.cs @@ -214,6 +214,15 @@ internal static string ChartMaiLibParseError { } } + /// + /// Looks up a localized string similar to Chart difficulty {0} has no notes. This difficulty will not be imported.. + /// + internal static string ChartNoNotes { + get { + return ResourceManager.GetString("ChartNoNotes", resourceCulture); + } + } + /// /// Looks up a localized string similar to It looks like some notes were lost! This is likely a bug. We'd really appreciate it if you could provide the chart file!. /// diff --git a/MaiChartManager/Locale.resx b/MaiChartManager/Locale.resx index e2c2e0d..d16b23f 100644 --- a/MaiChartManager/Locale.resx +++ b/MaiChartManager/Locale.resx @@ -206,6 +206,9 @@ If you notice any issues with the conversion result, you can try testing it in A Failed to parse chart difficulty {0} + + + Chart difficulty {0} has no notes. This difficulty will not be imported. Chart parsing failed (global) diff --git a/MaiChartManager/Locale.zh-hans.resx b/MaiChartManager/Locale.zh-hans.resx index 721d3a6..5fde1bf 100644 --- a/MaiChartManager/Locale.zh-hans.resx +++ b/MaiChartManager/Locale.zh-hans.resx @@ -198,6 +198,9 @@ 谱面难度 {0} 解析失败 + + + 谱面难度 {0} 中没有音符。将不会导入此难度。 谱面解析失败(大) diff --git a/MaiChartManager/Locale.zh-hant.resx b/MaiChartManager/Locale.zh-hant.resx index 5f3b3bb..4d7ea64 100644 --- a/MaiChartManager/Locale.zh-hant.resx +++ b/MaiChartManager/Locale.zh-hant.resx @@ -198,6 +198,9 @@ 譜面難度 {0} 解析失敗 + + + 譜面難度 {0} 中沒有音符。將不會匯入此難度。 譜面解析失敗(大) diff --git a/MaiChartManager/Utils/MaiUtils.cs b/MaiChartManager/Utils/MaiUtils.cs index d8a1101..ebe7638 100644 --- a/MaiChartManager/Utils/MaiUtils.cs +++ b/MaiChartManager/Utils/MaiUtils.cs @@ -1,7 +1,32 @@ -namespace MaiChartManager.Utils; +using System.Text.RegularExpressions; -public static class MaiUtils +namespace MaiChartManager.Utils; + +public static partial class MaiUtils { + [GeneratedRegex(@"^-?\d+(\.\d+)?")] + private static partial Regex LeadingFloatRegex(); + + // 尝试解析字符串开头的浮点数部分,忽略后续无法解析的字符(如 "13?" -> 13)。 + public static bool ParseLevelStr(string? input, out float value, out string utageKanji) + { + utageKanji = ""; + value = 0; + input = input?.Trim(); + if (string.IsNullOrWhiteSpace(input)) return false; + + if (!char.IsDigit(input[0])) + { // 如果不以数字开头,说明是utageKanji的情况 + utageKanji = input.Substring(0, 1); + input = input.Substring(1); + } + input = input.Replace("+", ".7"); + + var match = LeadingFloatRegex().Match(input); // 结尾有可能会有一个?,或者是其他的什么东西。为了让这些东西不要影响处理,所以通过正则匹配开头的数字部分,不然如果直接送进float.TryParse的话,类似"13?"这种的就解析不出来、返回false了。 + if (!match.Success) return false; + return float.TryParse(match.Value, System.Globalization.CultureInfo.InvariantCulture, out value); + } + public static int GetLevelId(int levelX10) { return levelX10 switch diff --git a/MuConvert b/MuConvert index 7dbc2a0..578c749 160000 --- a/MuConvert +++ b/MuConvert @@ -1 +1 @@ -Subproject commit 7dbc2a00947528b82f1ce273f186b400007dae03 +Subproject commit 578c749153ab9d1fa4bc9fbce2ee38df0f996cd6