From 0e0ab66148ec99a0458b5102541e1a58206a2887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 20 Nov 2023 21:27:24 +0900 Subject: [PATCH] Simplify parsing code Less methods, less smeared around logic, saner data types. --- osu.Game/Localisation/EditorStrings.cs | 5 --- .../Rulesets/Edit/EditorTimestampParser.cs | 41 ++++++++++++------- osu.Game/Screens/Edit/Editor.cs | 29 +++---------- 3 files changed, 32 insertions(+), 43 deletions(-) diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index 227dbc5e0c..e762455e8b 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -129,11 +129,6 @@ namespace osu.Game.Localisation /// public static LocalisableString FailedToProcessTimestamp => new TranslatableString(getKey(@"failed_to_process_timestamp"), @"Failed to process timestamp"); - /// - /// "The timestamp was too long to process" - /// - public static LocalisableString TooLongTimestamp => new TranslatableString(getKey(@"too_long_timestamp"), @"The timestamp was too long to process"); - private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Rulesets/Edit/EditorTimestampParser.cs b/osu.Game/Rulesets/Edit/EditorTimestampParser.cs index e36822cc63..bdfdce432e 100644 --- a/osu.Game/Rulesets/Edit/EditorTimestampParser.cs +++ b/osu.Game/Rulesets/Edit/EditorTimestampParser.cs @@ -2,8 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; -using System.Linq; +using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; namespace osu.Game.Rulesets.Edit @@ -12,26 +11,40 @@ namespace osu.Game.Rulesets.Edit { // 00:00:000 (...) - test // original osu-web regex: https://github.com/ppy/osu-web/blob/3b1698639244cfdaf0b41c68bfd651ea729ec2e3/resources/js/utils/beatmapset-discussion-helper.ts#L78 - public static readonly Regex TIME_REGEX = new Regex(@"\b(((\d{2,}):([0-5]\d)[:.](\d{3}))(\s\([^)]+\))?)"); + public static readonly Regex TIME_REGEX = new Regex(@"\b(((?\d{2,}):(?[0-5]\d)[:.](?\d{3}))(?\s\([^)]+\))?)", RegexOptions.Compiled); - public static string[] GetRegexGroups(string timestamp) + public static bool TryParse(string timestamp, [NotNullWhen(true)] out TimeSpan? parsedTime, out string? parsedSelection) { Match match = TIME_REGEX.Match(timestamp); - string[] result = match.Success - ? match.Groups.Values.Where(x => x is not Match && !x.Value.Contains(':')).Select(x => x.Value).ToArray() - : Array.Empty(); + if (!match.Success) + { + parsedTime = null; + parsedSelection = null; + return false; + } - return result; - } + bool result = true; - public static double GetTotalMilliseconds(params string[] timesGroup) - { - int[] times = timesGroup.Select(int.Parse).ToArray(); + result &= int.TryParse(match.Groups[@"minutes"].Value, out int timeMin); + result &= int.TryParse(match.Groups[@"seconds"].Value, out int timeSec); + result &= int.TryParse(match.Groups[@"milliseconds"].Value, out int timeMsec); - Debug.Assert(times.Length == 3); + // somewhat sane limit for timestamp duration (10 hours). + result &= timeMin < 600; - return (times[0] * 60 + times[1]) * 1000 + times[2]; + if (!result) + { + parsedTime = null; + parsedSelection = null; + return false; + } + + parsedTime = TimeSpan.FromMinutes(timeMin) + TimeSpan.FromSeconds(timeSec) + TimeSpan.FromMilliseconds(timeMsec); + parsedSelection = match.Groups[@"selection"].Value.Trim(); + if (!string.IsNullOrEmpty(parsedSelection)) + parsedSelection = parsedSelection[1..^1]; + return true; } } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 03d3e3a1f8..c38e88cd02 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -1141,9 +1141,7 @@ namespace osu.Game.Screens.Edit public void HandleTimestamp(string timestamp) { - string[] groups = EditorTimestampParser.GetRegexGroups(timestamp); - - if (groups.Length != 4 || string.IsNullOrEmpty(groups[0])) + if (!EditorTimestampParser.TryParse(timestamp, out var timeSpan, out string selection)) { Schedule(() => notifications?.Post(new SimpleNotification { @@ -1153,31 +1151,14 @@ namespace osu.Game.Screens.Edit return; } - string timeMin = groups[0]; - string timeSec = groups[1]; - string timeMss = groups[2]; - string objectsGroup = groups[3].Replace("(", "").Replace(")", "").Trim(); - - // Currently, lazer chat highlights infinite-long editor links like `10000000000:00:000 (1)` - // Limit timestamp link length at 30000 min (50 hr) to avoid parsing issues - if (string.IsNullOrEmpty(timeMin) || timeMin.Length > 5 || double.Parse(timeMin) > 30_000) - { - Schedule(() => notifications?.Post(new SimpleNotification - { - Icon = FontAwesome.Solid.ExclamationTriangle, - Text = EditorStrings.TooLongTimestamp - })); - return; - } - editorBeatmap.SelectedHitObjects.Clear(); if (clock.IsRunning) clock.Stop(); - double position = EditorTimestampParser.GetTotalMilliseconds(timeMin, timeSec, timeMss); + double position = timeSpan.Value.TotalMilliseconds; - if (string.IsNullOrEmpty(objectsGroup)) + if (string.IsNullOrEmpty(selection)) { clock.SeekSmoothlyTo(position); return; @@ -1194,8 +1175,8 @@ namespace osu.Game.Screens.Edit if (Mode.Value != EditorScreenMode.Compose) Mode.Value = EditorScreenMode.Compose; - // Let the Ruleset handle selection - currentScreen.Dependencies.Get().SelectHitObjects(position, objectsGroup); + // Delegate handling the selection to the ruleset. + currentScreen.Dependencies.Get().SelectHitObjects(position, selection); } public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime);