From 535d9f5b589f6987d7ca337d24ef5b238f338c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 30 Jun 2025 11:50:31 +0200 Subject: [PATCH] Read & output combo indices in timestamps in catch editor Addresses https://github.com/ppy/osu/discussions/33912 for catch specifically. Code copy-pasted from osu! ruleset. I'm leaving taiko be because new combo still doesn't make any sense in taiko. It'd probably either have to be object index in beatmap period instead of index in combo, or the `kdkdkdkdkkkdkdkkkdkkdkd` notation people use. --- .../Edit/CatchHitObjectComposer.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index dfe9dc9dd8..370eb37d16 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -219,5 +220,40 @@ namespace osu.Game.Rulesets.Catch.Edit distanceSnapGrid.StartTime = sourceHitObject.GetEndTime(); distanceSnapGrid.StartX = sourceHitObject.EffectiveX; } + + #region Clipboard handling + + public override string ConvertSelectionToString() + => string.Join(',', EditorBeatmap.SelectedHitObjects.Cast().OrderBy(h => h.StartTime).Select(h => (h.IndexInCurrentCombo + 1).ToString())); + + // 1,2,3,4 ... + private static readonly Regex selection_regex = new Regex(@"^\d+(,\d+)*$", RegexOptions.Compiled); + + public override void SelectFromTimestamp(double timestamp, string objectDescription) + { + if (!selection_regex.IsMatch(objectDescription)) + return; + + List remainingHitObjects = EditorBeatmap.HitObjects.Cast().Where(h => h.StartTime >= timestamp).ToList(); + string[] splitDescription = objectDescription.Split(','); + + for (int i = 0; i < splitDescription.Length; i++) + { + if (!int.TryParse(splitDescription[i], out int combo) || combo < 1) + continue; + + CatchHitObject? current = remainingHitObjects.FirstOrDefault(h => h.IndexInCurrentCombo + 1 == combo); + + if (current == null) + continue; + + EditorBeatmap.SelectedHitObjects.Add(current); + + if (i < splitDescription.Length - 1) + remainingHitObjects = remainingHitObjects.Where(h => h != current && h.StartTime >= current.StartTime).ToList(); + } + } + + #endregion } }