public override bool OnExiting(IScreen next) { screenSuspension?.Expire(); if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed) { // proceed to result screen if beatmap already finished playing completionProgressDelegate.RunTask(); return(true); } // ValidForResume is false when restarting if (ValidForResume) { if (pauseCooldownActive && !GameplayClockContainer.IsPaused.Value) { // still want to block if we are within the cooldown period and not already paused. return(true); } } // GameplayClockContainer performs seeks / start / stop operations on the beatmap's track. // as we are no longer the current screen, we cannot guarantee the track is still usable. GameplayClockContainer?.StopUsingBeatmapClock(); musicController.ResetTrackAdjustments(); fadeOut(); return(base.OnExiting(next)); }
protected override bool OnExiting(Screen next) { if (onCompletionEvent != null) { // Proceed to result screen if beatmap already finished playing onCompletionEvent.RunTask(); return(true); } if ((!AllowPause || HasFailed || !ValidForResume || pauseContainer?.IsPaused != false || RulesetContainer?.HasReplayLoaded != false) && (!pauseContainer?.IsResuming ?? true)) { // In the case of replays, we may have changed the playback rate. applyRateFromMods(); fadeOut(); return(base.OnExiting(next)); } if (LoadedBeatmapSuccessfully) { pauseContainer?.Pause(); } return(true); }
public override bool OnExiting(IScreen next) { if (onCompletionEvent != null) { // Proceed to result screen if beatmap already finished playing onCompletionEvent.RunTask(); return(true); } if (canPause) { Pause(); return(true); } if (pauseCooldownActive && !GameplayClockContainer.IsPaused.Value) { // still want to block if we are within the cooldown period and not already paused. return(true); } if (HasFailed && ValidForResume && !FailOverlay.IsPresent) // ValidForResume is false when restarting { failAnimation.FinishTransforms(true); return(true); } GameplayClockContainer.ResetLocalAdjustments(); fadeOut(); return(base.OnExiting(next)); }
public override bool OnExiting(IScreen next) { if (onCompletionEvent != null) { // Proceed to result screen if beatmap already finished playing onCompletionEvent.RunTask(); return(true); } if (canPause) { Pause(); return(true); } if (pauseCooldownActive && !GameplayClockContainer.IsPaused.Value) { // still want to block if we are within the cooldown period and not already paused. return(true); } GameplayClockContainer.ResetLocalAdjustments(); fadeOut(); return(base.OnExiting(next)); }
public override bool OnExiting(IScreen next) { screenSuspension?.Expire(); if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed) { // proceed to result screen if beatmap already finished playing completionProgressDelegate.RunTask(); return(true); } // EndPlaying() is typically called from ReplayRecorder.Dispose(). Disposal is currently asynchronous. // To resolve test failures, forcefully end playing synchronously when this screen exits. // Todo: Replace this with a more permanent solution once osu-framework has a synchronous cleanup method. spectatorClient.EndPlaying(); // GameplayClockContainer performs seeks / start / stop operations on the beatmap's track. // as we are no longer the current screen, we cannot guarantee the track is still usable. (GameplayClockContainer as MasterGameplayClockContainer)?.StopUsingBeatmapClock(); musicController.ResetTrackAdjustments(); fadeOut(); return(base.OnExiting(next)); }
public void TestRepeatAlreadyCompletedSchedule() { int invocations = 0; var del = new ScheduledDelegate(() => invocations++); del.RunTask(); Assert.AreEqual(1, invocations); Assert.Throws <InvalidOperationException>(() => scheduler.Add(del)); scheduler.Update(); Assert.AreEqual(1, invocations); }
public void TestInvokeBeforeScheduleUpdate() { int invocations = 0; ScheduledDelegate del; scheduler.Add(del = new ScheduledDelegate(() => invocations++)); Assert.AreEqual(0, invocations); del.RunTask(); Assert.AreEqual(1, invocations); scheduler.Update(); Assert.AreEqual(1, invocations); }
/// <summary> /// Seeks to a specific time in gameplay, bypassing frame stability. /// </summary> /// <remarks> /// Intermediate hitobject judgements may not be applied or reverted correctly during this seek. /// </remarks> /// <param name="time">The destination time to seek to.</param> internal void NonFrameStableSeek(double time) { if (frameStablePlaybackResetDelegate?.Cancelled == false && !frameStablePlaybackResetDelegate.Completed) { frameStablePlaybackResetDelegate.RunTask(); } bool wasFrameStable = DrawableRuleset.FrameStablePlayback; DrawableRuleset.FrameStablePlayback = false; Seek(time); // Delay resetting frame-stable playback for one frame to give the FrameStabilityContainer a chance to seek. frameStablePlaybackResetDelegate = ScheduleAfterChildren(() => DrawableRuleset.FrameStablePlayback = wasFrameStable); }
protected void SetGameplayStartTime(double time) { if (frameStablePlaybackResetDelegate?.Cancelled == false && !frameStablePlaybackResetDelegate.Completed) { frameStablePlaybackResetDelegate.RunTask(); } bool wasFrameStable = DrawableRuleset.FrameStablePlayback; DrawableRuleset.FrameStablePlayback = false; GameplayClockContainer.StartTime = time; GameplayClockContainer.Reset(); // Delay resetting frame-stable playback for one frame to give the FrameStabilityContainer a chance to seek. frameStablePlaybackResetDelegate = ScheduleAfterChildren(() => DrawableRuleset.FrameStablePlayback = wasFrameStable); }
public override bool OnExiting(IScreen next) { screenSuspension?.Expire(); if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed) { // proceed to result screen if beatmap already finished playing completionProgressDelegate.RunTask(); return(true); } // GameplayClockContainer performs seeks / start / stop operations on the beatmap's track. // as we are no longer the current screen, we cannot guarantee the track is still usable. (GameplayClockContainer as MasterGameplayClockContainer)?.StopUsingBeatmapClock(); musicController.ResetTrackAdjustments(); fadeOut(); return(base.OnExiting(next)); }
/// <summary> /// Seeks to a specific time in gameplay, bypassing frame stability. /// </summary> /// <remarks> /// Intermediate hitobject judgements may not be applied or reverted correctly during this seek. /// </remarks> /// <param name="time">The destination time to seek to.</param> internal void NonFrameStableSeek(double time) { // TODO: This schedule should not be required and is a temporary hotfix. // See https://github.com/ppy/osu/issues/17267 for the issue. // See https://github.com/ppy/osu/pull/17302 for a better fix which needs some more time. ScheduleAfterChildren(() => { if (frameStablePlaybackResetDelegate?.Cancelled == false && !frameStablePlaybackResetDelegate.Completed) { frameStablePlaybackResetDelegate.RunTask(); } bool wasFrameStable = DrawableRuleset.FrameStablePlayback; DrawableRuleset.FrameStablePlayback = false; Seek(time); // Delay resetting frame-stable playback for one frame to give the FrameStabilityContainer a chance to seek. frameStablePlaybackResetDelegate = ScheduleAfterChildren(() => DrawableRuleset.FrameStablePlayback = wasFrameStable); }); }
public override bool OnExiting(IScreen next) { if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed) { // proceed to result screen if beatmap already finished playing completionProgressDelegate.RunTask(); return(true); } // ValidForResume is false when restarting if (ValidForResume) { if (pauseCooldownActive && !GameplayClockContainer.IsPaused.Value) { // still want to block if we are within the cooldown period and not already paused. return(true); } } GameplayClockContainer.ResetLocalAdjustments(); fadeOut(); return(base.OnExiting(next)); }
public override bool OnExiting(IScreen next) { if (onCompletionEvent != null) { // Proceed to result screen if beatmap already finished playing onCompletionEvent.RunTask(); return(true); } if ((!AllowPause || HasFailed || !ValidForResume || PausableGameplayContainer?.IsPaused.Value != false || RulesetContainer?.HasReplayLoaded.Value != false) && (!PausableGameplayContainer?.IsResuming ?? true)) { gameplayClockContainer.ResetLocalAdjustments(); fadeOut(); return(base.OnExiting(next)); } if (LoadedBeatmapSuccessfully) { PausableGameplayContainer?.Pause(); } return(true); }
/// <summary> /// Selection has been changed as the result of a user interaction. /// </summary> private void performUpdateSelected() { var beatmap = beatmapNoDebounce; var ruleset = rulesetNoDebounce; selectionChangedDebounce?.Cancel(); if (beatmapNoDebounce == null) { run(); } else { selectionChangedDebounce = Scheduler.AddDelayed(run, 200); } void run() { // clear pending task immediately to track any potential nested debounce operation. selectionChangedDebounce = null; Logger.Log($"updating selection with beatmap:{beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ID.ToString() ?? "null"}"); if (transferRulesetValue()) { Mods.Value = Array.Empty <Mod>(); // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). if (beatmap != null && !Carousel.SelectBeatmap(beatmap, false)) { beatmap = null; } } if (selectionChangedDebounce != null) { // a new nested operation was started; switch to it for further selection. // this avoids having two separate debounces trigger from the same source. selectionChangedDebounce.RunTask(); return; } // We may be arriving here due to another component changing the bindable Beatmap. // In these cases, the other component has already loaded the beatmap, so we don't need to do so again. if (!EqualityComparer <BeatmapInfo> .Default.Equals(beatmap, Beatmap.Value.BeatmapInfo)) { Logger.Log($"beatmap changed from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap}\""); WorkingBeatmap previous = Beatmap.Value; Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, previous); if (beatmap != null) { if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID) { sampleChangeDifficulty.Play(); } else { sampleChangeBeatmap.Play(); } } } if (this.IsCurrentScreen()) { ensurePlayingSelected(); } updateComponentFromBeatmap(Beatmap.Value); } }