diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
index f009c10a9c..1f05d66b86 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Catch.Beatmaps
{
@@ -38,5 +39,25 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
}
};
}
+
+ ///
+ /// Enumerate all s, sorted by their start times.
+ ///
+ ///
+ /// If multiple objects have the same start time, the ordering is preserved (it is a stable sorting).
+ ///
+ public static IEnumerable GetPalpableObjects(IEnumerable hitObjects)
+ {
+ return hitObjects.SelectMany(selectPalpableObjects).OrderBy(h => h.StartTime);
+
+ IEnumerable selectPalpableObjects(HitObject h)
+ {
+ if (h is PalpableCatchHitObject palpable)
+ yield return palpable;
+
+ foreach (var nested in h.NestedHitObjects.OfType())
+ yield return nested;
+ }
+ }
}
}
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
index c51d3d5c70..32134912f1 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
@@ -192,24 +191,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
private static void initialiseHyperDash(IBeatmap beatmap)
{
- List palpableObjects = new List();
-
- foreach (var currentObject in beatmap.HitObjects)
- {
- if (currentObject is Fruit fruitObject)
- palpableObjects.Add(fruitObject);
-
- if (currentObject is JuiceStream)
- {
- foreach (var juice in currentObject.NestedHitObjects)
- {
- if (juice is PalpableCatchHitObject palpableObject && !(juice is TinyDroplet))
- palpableObjects.Add(palpableObject);
- }
- }
- }
-
- palpableObjects = palpableObjects.OrderBy(h => h.StartTime).ToList();
+ var palpableObjects = CatchBeatmap.GetPalpableObjects(beatmap.HitObjects)
+ .Where(h => h is Fruit || (h is Droplet && h is not TinyDroplet))
+ .ToArray();
double halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.Difficulty) / 2;
@@ -221,7 +205,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
int lastDirection = 0;
double lastExcess = halfCatcherWidth;
- for (int i = 0; i < palpableObjects.Count - 1; i++)
+ for (int i = 0; i < palpableObjects.Length - 1; i++)
{
var currentObject = palpableObjects[i];
var nextObject = palpableObjects[i + 1];
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
index 42cfde268e..959f4830dd 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Difficulty.Preprocessing;
using osu.Game.Rulesets.Catch.Difficulty.Skills;
using osu.Game.Rulesets.Catch.Mods;
@@ -54,13 +55,10 @@ namespace osu.Game.Rulesets.Catch.Difficulty
List objects = new List();
// In 2B beatmaps, it is possible that a normal Fruit is placed in the middle of a JuiceStream.
- foreach (var hitObject in beatmap.HitObjects
- .SelectMany(obj => obj is JuiceStream stream ? stream.NestedHitObjects.AsEnumerable() : new[] { obj })
- .Cast()
- .OrderBy(x => x.StartTime))
+ foreach (var hitObject in CatchBeatmap.GetPalpableObjects(beatmap.HitObjects))
{
// We want to only consider fruits that contribute to the combo.
- if (hitObject is BananaShower || hitObject is TinyDroplet)
+ if (hitObject is Banana || hitObject is TinyDroplet)
continue;
if (lastObject != null)