diff --git a/osu.Game.Rulesets.Osu/UI/StartTimeOrderedHitPolicy.cs b/osu.Game.Rulesets.Osu/UI/StartTimeOrderedHitPolicy.cs index 2b24fb93986c..973ca1106232 100644 --- a/osu.Game.Rulesets.Osu/UI/StartTimeOrderedHitPolicy.cs +++ b/osu.Game.Rulesets.Osu/UI/StartTimeOrderedHitPolicy.cs @@ -30,7 +30,7 @@ public ClickAction CheckHittable(DrawableHitObject hitObject, double time, HitRe DrawableHitObject? blockingObject = null; - foreach (var obj in enumerateHitObjectsUpTo(hitObject.HitObject.StartTime)) + foreach (var obj in enumerateTopLevelAliveObjectsUpTo(hitObject.HitObject.StartTime)) { if (hitObjectCanBlockFutureHits(obj)) blockingObject = obj; @@ -60,7 +60,7 @@ public void HandleHit(DrawableHitObject hitObject) throw new InvalidOperationException($"A {hitObject} was hit before it became hittable!"); // Miss all hitobjects prior to the hit one. - foreach (var obj in enumerateHitObjectsUpTo(hitObject.HitObject.StartTime)) + foreach (var obj in enumerateTopLevelAliveObjectsUpTo(hitObject.HitObject.StartTime)) { if (obj.Judged) continue; @@ -77,7 +77,7 @@ public void HandleHit(DrawableHitObject hitObject) private static bool hitObjectCanBlockFutureHits(DrawableHitObject hitObject) => hitObject is DrawableHitCircle; - private IEnumerable enumerateHitObjectsUpTo(double targetTime) + private IEnumerable enumerateTopLevelAliveObjectsUpTo(double targetTime) { foreach (var obj in HitObjectContainer!.AliveObjects) { @@ -85,14 +85,6 @@ private IEnumerable enumerateHitObjectsUpTo(double targetTime yield break; yield return obj; - - foreach (var nestedObj in obj.NestedHitObjects) - { - if (nestedObj.HitObject.StartTime >= targetTime) - break; - - yield return nestedObj; - } } } } diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index ba48abf407ea..f86a26b54530 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -126,7 +126,8 @@ protected override void Update() // In the case there are no non-judged objects, the last hit object should be used instead. if (candidate == null) { - mostValidObject = hitObjectContainer.Entries.LastOrDefault(); + var (_, lastEntry) = getEntryBounds(); + mostValidObject = lastEntry; } else { @@ -136,7 +137,8 @@ protected override void Update() } else { - mostValidObject ??= hitObjectContainer.Entries.FirstOrDefault(); + var (firstEntry, _) = getEntryBounds(); + mostValidObject ??= firstEntry; } } } @@ -177,6 +179,23 @@ protected override void Update() return best ?? mostValidObject.HitObject; } + private (HitObjectLifetimeEntry? first, HitObjectLifetimeEntry? last) getEntryBounds() + { + HitObjectLifetimeEntry? first = null; + HitObjectLifetimeEntry? last = null; + + foreach (var entry in hitObjectContainer.Entries) + { + if (first == null || entry.HitObject.StartTime < first.HitObject.StartTime) + first = entry; + + if (last == null || entry.HitObject.StartTime > last.HitObject.StartTime) + last = entry; + } + + return (first, last); + } + private bool isAlreadyHit(HitObjectLifetimeEntry h) => h.AllJudged; private bool isCloseEnoughToCurrentTime(HitObject h) => getReferenceTime() >= h.StartTime - h.HitWindows.WindowFor(HitResult.Miss) * 2;