diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
index 77d7de989a..e4ad49ea50 100644
--- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
@@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Catch.Objects
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
}
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
public enum FruitVisualRepresentation
diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
index 0c82cf7bbc..bdba813eed 100644
--- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
@@ -101,6 +101,6 @@ namespace osu.Game.Rulesets.Mania.Objects
public override Judgement CreateJudgement() => new HoldNoteJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
index d0125f8793..ac6697a6dc 100644
--- a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
+++ b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
@@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Mania.Objects
{
public override Judgement CreateJudgement() => new HoldNoteTickJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs
index a794e57c9e..a277517f9f 100644
--- a/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs
+++ b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs
@@ -30,6 +30,6 @@ namespace osu.Game.Rulesets.Osu.Objects
public override Judgement CreateJudgement() => new OsuJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs
index 3ed1f2cdde..9bed123465 100644
--- a/osu.Game.Rulesets.Osu/Objects/Slider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs
@@ -205,6 +205,6 @@ namespace osu.Game.Rulesets.Osu.Objects
public override Judgement CreateJudgement() => new OsuJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
index 7e540a577b..14c3369967 100644
--- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
@@ -25,6 +25,6 @@ namespace osu.Game.Rulesets.Osu.Objects
public override Judgement CreateJudgement() => new OsuSliderTailJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs
index af7cf5b144..a49f4cef8b 100644
--- a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs
+++ b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs
@@ -32,6 +32,6 @@ namespace osu.Game.Rulesets.Osu.Objects
public override Judgement CreateJudgement() => new OsuJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs
index 2e7b763966..2441a1449d 100644
--- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs
@@ -33,6 +33,6 @@ namespace osu.Game.Rulesets.Osu.Objects
public override Judgement CreateJudgement() => new OsuJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs
index 4e02c76a8b..8956ca9c19 100644
--- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs
@@ -88,6 +88,6 @@ namespace osu.Game.Rulesets.Taiko.Objects
public override Judgement CreateJudgement() => new TaikoDrumRollJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs
index c466ca7c8a..8a8be3e38d 100644
--- a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs
@@ -27,6 +27,6 @@ namespace osu.Game.Rulesets.Taiko.Objects
public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs
index d660149528..72a04698be 100644
--- a/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs
@@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Taiko.Objects
{
public override Judgement CreateJudgement() => new TaikoStrongJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs
index f96c033dce..e60984596d 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs
@@ -35,6 +35,6 @@ namespace osu.Game.Rulesets.Taiko.Objects
public override Judgement CreateJudgement() => new TaikoSwellJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
index 68212e8f12..91f4d3dbe7 100644
--- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
@@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Taiko.Objects
{
public override Judgement CreateJudgement() => new TaikoSwellTickJudgement();
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs
index a99fac09cc..eb8652443f 100644
--- a/osu.Game/Rulesets/Objects/HitObject.cs
+++ b/osu.Game/Rulesets/Objects/HitObject.cs
@@ -66,7 +66,6 @@ namespace osu.Game.Rulesets.Objects
///
/// The hit windows for this .
///
- [CanBeNull]
public HitWindows HitWindows { get; set; }
private readonly List nestedHitObjects = new List();
@@ -113,10 +112,7 @@ namespace osu.Game.Rulesets.Objects
nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
foreach (var h in nestedHitObjects)
- {
- h.HitWindows = HitWindows;
h.ApplyDefaults(controlPointInfo, difficulty);
- }
}
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
@@ -147,7 +143,7 @@ namespace osu.Game.Rulesets.Objects
/// This will only be invoked if hasn't been set externally (e.g. from a .
///
///
- [CanBeNull]
+ [NotNull]
protected virtual HitWindows CreateHitWindows() => new HitWindows();
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs
index 609bdd571a..883ef55df0 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs
@@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
public float X { get; set; }
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs
index 350ee3185d..69e6f8379d 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs
@@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
public double Duration => EndTime - StartTime;
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs
index e372fbd273..4486c5d906 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs
@@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
public float X { get; set; }
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs
index 067377d300..c6d1f1922c 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs
@@ -17,6 +17,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
public float X { get; set; }
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs
index c9851a0074..e40b5b4505 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs
@@ -22,6 +22,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
public int ComboOffset { get; set; }
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs
index 1c1180702b..a163329d47 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs
@@ -22,6 +22,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
public int ComboOffset { get; set; }
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs
index bc94ea1803..5d96a61633 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
public float Y => Position.Y;
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
public bool NewCombo { get; set; }
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs
index 709345170f..efb9810927 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs
@@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
///
internal sealed class ConvertHit : HitObject
{
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs
index c173b3e11a..b365fd34ae 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs
@@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
///
internal sealed class ConvertSlider : Legacy.ConvertSlider
{
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs
index 9a35ad2776..840ba51ac2 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs
@@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
public double Duration => EndTime - StartTime;
- protected override HitWindows CreateHitWindows() => null;
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Scoring/HitWindows.cs b/osu.Game/Rulesets/Scoring/HitWindows.cs
index efc4cd9f5c..9e7e594104 100644
--- a/osu.Game/Rulesets/Scoring/HitWindows.cs
+++ b/osu.Game/Rulesets/Scoring/HitWindows.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
@@ -30,6 +31,17 @@ namespace osu.Game.Rulesets.Scoring
private double meh;
private double miss;
+ ///
+ /// An empty with only and .
+ /// No time values are provided (meaning instantaneous hit or miss).
+ ///
+ public static HitWindows Empty => new EmptyHitWindows();
+
+ public HitWindows()
+ {
+ Debug.Assert(GetRanges().Length >= 1, $"{nameof(HitWindows)}");
+ }
+
///
/// Retrieves the with the largest hit window that produces a successful hit.
///
@@ -168,6 +180,29 @@ namespace osu.Game.Rulesets.Scoring
/// Defaults are provided but can be overridden to customise for a ruleset.
///
protected virtual DifficultyRange[] GetRanges() => base_ranges;
+
+ public class EmptyHitWindows : HitWindows
+ {
+ private static readonly DifficultyRange[] ranges =
+ {
+ new DifficultyRange(HitResult.Perfect, 0, 0, 0),
+ new DifficultyRange(HitResult.Miss, 0, 0, 0),
+ };
+
+ public override bool IsHitResultAllowed(HitResult result)
+ {
+ switch (result)
+ {
+ case HitResult.Great:
+ case HitResult.Miss:
+ return true;
+ }
+
+ return false;
+ }
+
+ protected override DifficultyRange[] GetRanges() => ranges;
+ }
}
public struct DifficultyRange
diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs
index d68b0e94c5..d5b3df27df 100644
--- a/osu.Game/Rulesets/UI/DrawableRuleset.cs
+++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs
@@ -426,11 +426,11 @@ namespace osu.Game.Rulesets.UI
{
foreach (var h in Objects)
{
- if (h.HitWindows != null)
+ if (h.HitWindows.WindowFor(HitResult.Miss) > 0)
return h.HitWindows;
foreach (var n in h.NestedHitObjects)
- if (n.HitWindows != null)
+ if (h.HitWindows.WindowFor(HitResult.Miss) > 0)
return n.HitWindows;
}
diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs
index 920d11c910..54556f8648 100644
--- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs
+++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs
@@ -48,7 +48,7 @@ namespace osu.Game.Screens.Play.HUD
private void onNewJudgement(JudgementResult result)
{
- if (result.HitObject.HitWindows == null)
+ if (result.HitObject.HitWindows.WindowFor(HitResult.Miss) == 0)
return;
foreach (var c in Children)