diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs index c7f1eabab235..0f47c3cd27bd 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs @@ -1,14 +1,18 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Tests.Resources; @@ -52,6 +56,39 @@ public void TestTooShortToDisplay() AddAssert("No calibration button", () => !offsetControl.ChildrenOfType().Any()); } + [Test] + public void TestNotEnoughTimedHitEvents() + { + AddStep("Set short reference score", () => + { + List hitEvents = + [ + // 10 events total. one of them (head circle) being timed / having hitwindows, rest having no hitwindows + new HitEvent(30, 1, HitResult.LargeTickHit, new SliderHeadCircle { ClassicSliderBehaviour = true }, null, null), + new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null), + new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null), + new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null), + new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null), + new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null), + new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null), + new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null), + new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null), + new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null), + ]; + + foreach (var ev in hitEvents) + ev.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + offsetControl.ReferenceScore.Value = new ScoreInfo + { + HitEvents = hitEvents, + BeatmapInfo = Beatmap.Value.BeatmapInfo, + }; + }); + + AddAssert("No calibration button", () => !offsetControl.ChildrenOfType().Any()); + } + [Test] public void TestScoreFromDifferentBeatmap() { diff --git a/osu.Game/Rulesets/Scoring/HitEventExtensions.cs b/osu.Game/Rulesets/Scoring/HitEventExtensions.cs index 6e2852676a81..fc4eef13ba29 100644 --- a/osu.Game/Rulesets/Scoring/HitEventExtensions.cs +++ b/osu.Game/Rulesets/Scoring/HitEventExtensions.cs @@ -30,7 +30,7 @@ public static class HitEventExtensions foreach (var e in hitEvents) { - if (!affectsUnstableRate(e)) + if (!AffectsUnstableRate(e)) continue; count++; @@ -57,7 +57,7 @@ public static class HitEventExtensions /// public static double? CalculateAverageHitError(this IEnumerable hitEvents) { - double[] timeOffsets = hitEvents.Where(affectsUnstableRate).Select(ev => ev.TimeOffset).ToArray(); + double[] timeOffsets = hitEvents.Where(AffectsUnstableRate).Select(ev => ev.TimeOffset).ToArray(); if (timeOffsets.Length == 0) return null; @@ -65,6 +65,6 @@ public static class HitEventExtensions return timeOffsets.Average(); } - private static bool affectsUnstableRate(HitEvent e) => !(e.HitObject.HitWindows is HitWindows.EmptyHitWindows) && e.Result.IsHit(); + public static bool AffectsUnstableRate(HitEvent e) => !(e.HitObject.HitWindows is HitWindows.EmptyHitWindows) && e.Result.IsHit(); } } diff --git a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs index f312fb0ec5a9..74b887481f12 100644 --- a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs +++ b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs @@ -195,7 +195,10 @@ private void scoreChanged(ValueChangedEvent score) }, }; - if (hitEvents.Count < 10) + // affecting unstable rate here is used as a substitute of determining if a hit event represents a *timed* hit event, + // i.e. an user input that the user had to *time to the track*, + // i.e. one that it *makes sense to use* when doing anything with timing and offsets. + if (hitEvents.Count(HitEventExtensions.AffectsUnstableRate) < 10) { referenceScoreContainer.AddRange(new Drawable[] {