-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Refactor hit windows class structure to reduce rigidity #33875
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This change pulls back a significant degree of overspecialisation and rigidity in the class structure of `HitWindows` to make subsequent changes to hit windows, whose purpose is to improve replay playback accuracy, possible to do cleanly. Notably: - `HitWindows` is full abstract now. In a few use cases, and as a reference for ruleset implementors, `DefaultHitWindows` is provided as a separate class instead. This fixes the weirdness wherein `HitWindows` always declared 6 fields for result types but some of them would never be set to a non-zero value or read. - `HitWindow.GetRanges()` is deleted because it is overspecialised and prevents being able to adjust hitwindows by ±0.5ms cleanly which will be required later. The fallout of this is that the assertion that used `GetRanges()` in the `HitWindows` ctor must use something else now, and the closest thing to it was `GetAllAvailableWindows()`, which didn't return the miss window - so I made it return the miss window and fixed the one consumer that didn't want it (bar hit error meter) to skip it. - Diff also contains some clean-up around `DifficultyRange` to unify handling of it.
{ | ||
Debug.Assert(GetRanges().Any(r => r.Result == HitResult.Miss), $"{nameof(GetRanges)} should always contain {nameof(HitResult.Miss)}"); | ||
Debug.Assert(GetRanges().Any(r => r.Result != HitResult.Miss), $"{nameof(GetRanges)} should always contain at least one result type other than {nameof(HitResult.Miss)}."); | ||
var availableWindows = GetAllAvailableWindows(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might seem pedantic, but I'd want to avoid this call here in release builds since it is being constructed at least once per hitobject.
diff --git a/osu.Game/Rulesets/Scoring/HitWindows.cs b/osu.Game/Rulesets/Scoring/HitWindows.cs
index e1429f32b2..9463fd391b 100644
--- a/osu.Game/Rulesets/Scoring/HitWindows.cs
+++ b/osu.Game/Rulesets/Scoring/HitWindows.cs
@@ -21,10 +21,17 @@ public abstract class HitWindows
public static HitWindows Empty { get; } = new EmptyHitWindows();
protected HitWindows()
+ {
+ ensureValidHitWindows();
+ }
+
+ [Conditional("DEBUG")]
+ private void ensureValidHitWindows()
{
var availableWindows = GetAllAvailableWindows();
Debug.Assert(availableWindows.Any(r => r.result == HitResult.Miss), $"{nameof(GetAllAvailableWindows)} should always contain {nameof(HitResult.Miss)}");
- Debug.Assert(availableWindows.Any(r => r.result != HitResult.Miss), $"{nameof(GetAllAvailableWindows)} should always contain at least one result type other than {nameof(HitResult.Miss)}.");
+ Debug.Assert(availableWindows.Any(r => r.result != HitResult.Miss),
+ $"{nameof(GetAllAvailableWindows)} should always contain at least one result type other than {nameof(HitResult.Miss)}.");
}
/// <summary>
maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, applied (with an extra .ToList()
to shut a multiple enumeration inspection up) in 55ff5a7.
Split out from #33078
This change pulls back a significant degree of overspecialisation and rigidity in the class structure of
HitWindows
to make subsequent changes to hit windows, whose purpose is to improve replay playback accuracy, possible to do cleanly.Notably:
HitWindows
is full abstract now. In a few use cases, and as a reference for ruleset implementors,DefaultHitWindows
is provided as a separate class instead.This fixes the weirdness wherein
HitWindows
always declared 6 fields for result types but some of them would never be set to a non-zero value or read.HitWindow.GetRanges()
is deleted because it is overspecialised and prevents being able to adjust hitwindows by ±0.5ms cleanly which will be required later.The fallout of this is that the assertion that used
GetRanges()
in theHitWindows
ctor must use something else now, and the closest thing to it wasGetAllAvailableWindows()
, which didn't return the miss window - so I made it return the miss window and fixed the only one consumer that didn't want it (bar hit error meter) to skip it.Diff also contains some clean-up around
DifficultyRange
to unify handling of it.