diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 54ed7ba626..2844d84f31 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -8,6 +8,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Logging; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -39,6 +40,14 @@ namespace osu.Game.Screens.Play Precision = 0.1, }; + /// + /// Whether the audio playback is within acceptable ranges. + /// Will become false if audio playback is not going as expected. + /// + public IBindable PlaybackRateValid => playbackRateValid; + + private readonly Bindable playbackRateValid = new Bindable(true); + private readonly WorkingBeatmap beatmap; private Track track; @@ -128,6 +137,7 @@ namespace osu.Game.Screens.Play { // Safety in case the clock is seeked while stopped. LastStopTime = null; + elapsedValidationTime = null; base.Seek(time); } @@ -197,6 +207,51 @@ namespace osu.Game.Screens.Play addAdjustmentsToTrack(); } + protected override void Update() + { + base.Update(); + checkPlaybackValidity(); + } + + #region Clock validation (ensure things are running correctly for local gameplay) + + private double elapsedGameplayClockTime; + private double? elapsedValidationTime; + private int playbackDiscrepancyCount; + + private const int allowed_playback_discrepancies = 5; + + private void checkPlaybackValidity() + { + if (GameplayClock.IsRunning) + { + elapsedGameplayClockTime += GameplayClock.ElapsedFrameTime; + + elapsedValidationTime ??= elapsedGameplayClockTime; + elapsedValidationTime += GameplayClock.Rate * Time.Elapsed; + + if (Math.Abs(elapsedGameplayClockTime - elapsedValidationTime!.Value) > 300) + { + if (playbackDiscrepancyCount++ > allowed_playback_discrepancies) + { + if (playbackRateValid.Value) + { + playbackRateValid.Value = false; + Logger.Log("System audio playback is not working as expected. Some online functionality will not work.\n\nPlease check your audio drivers.", level: LogLevel.Important); + } + } + else + { + Logger.Log($"Playback discrepancy detected ({playbackDiscrepancyCount} of allowed {allowed_playback_discrepancies}): {elapsedGameplayClockTime:N1} vs {elapsedValidationTime:N1}"); + } + + elapsedValidationTime = null; + } + } + } + + #endregion + private bool speedAdjustmentsApplied; private void addAdjustmentsToTrack() diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 785164178a..f88526b8f9 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -208,6 +208,14 @@ namespace osu.Game.Screens.Play private Task submitScore(Score score) { + var masterClock = GameplayClockContainer as MasterGameplayClockContainer; + + if (masterClock?.PlaybackRateValid.Value != true) + { + Logger.Log("Score submission cancelled due to audio playback rate discrepancy."); + return Task.CompletedTask; + } + // token may be null if the request failed but gameplay was still allowed (see HandleTokenRetrievalFailure). if (token == null) {