diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index bf1f508d7b0a..ba0c47dc8b36 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs @@ -15,14 +15,12 @@ public partial class ClicksPerSecondCalculator : Component [Resolved] private IGameplayClock gameplayClock { get; set; } = null!; - [Resolved(canBeNull: true)] - private DrawableRuleset? drawableRuleset { get; set; } + [Resolved] + private IFrameStableClock? frameStableClock { get; set; } public int Value { get; private set; } - // Even though `FrameStabilityContainer` caches as a `GameplayClock`, we need to check it directly via `drawableRuleset` - // as this calculator is not contained within the `FrameStabilityContainer` and won't see the dependency. - private IGameplayClock clock => drawableRuleset?.FrameStableClock ?? gameplayClock; + private IGameplayClock clock => frameStableClock ?? gameplayClock; public ClicksPerSecondCalculator() { diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 4504745eb90e..c5f5de6f4803 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -25,10 +25,15 @@ public abstract partial class SongProgress : OverlayContainer, ISkinnableDrawabl [Resolved] protected IGameplayClock GameplayClock { get; private set; } = null!; - [Resolved(canBeNull: true)] - private DrawableRuleset? drawableRuleset { get; set; } + [Resolved] + private IFrameStableClock? frameStableClock { get; set; } + + /// + /// The reference clock is used to accurately tell the current playfield's time (including catch-up lag). + /// However, if none is available (i.e. used in tests), we fall back to the gameplay clock. + /// + protected IClock FrameStableClock => frameStableClock ?? GameplayClock; - private IClock? referenceClock; private IEnumerable? objects; public IEnumerable Objects @@ -58,12 +63,11 @@ protected override void LoadComplete() protected virtual void UpdateObjects(IEnumerable objects) { } [BackgroundDependencyLoader] - private void load() + private void load(DrawableRuleset? drawableRuleset) { if (drawableRuleset != null) { Objects = drawableRuleset.Objects; - referenceClock = drawableRuleset.FrameStableClock; } } @@ -74,9 +78,7 @@ protected override void Update() if (objects == null) return; - // The reference clock is used to accurately tell the playfield's time. This is obtained from the drawable ruleset. - // However, if no drawable ruleset is available (i.e. used in tests), we fall back to the gameplay clock. - double currentTime = referenceClock?.CurrentTime ?? GameplayClock.CurrentTime; + double currentTime = FrameStableClock.CurrentTime; bool isInIntro = currentTime < FirstHitTime; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 05133fba3560..d3ab936a384e 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -225,6 +225,7 @@ private void load(AudioManager audio, OsuConfigManager config, OsuGameBase game, DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, gameplayMods); dependencies.CacheAs(DrawableRuleset); + dependencies.CacheAs(DrawableRuleset.FrameStableClock); ScoreProcessor = ruleset.CreateScoreProcessor(); ScoreProcessor.Mods.Value = gameplayMods;