Exemple #1
0
        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));
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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));
        }
Exemple #4
0
        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));
        }
Exemple #5
0
        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));
        }
Exemple #6
0
        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);
        }
Exemple #7
0
        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);
        }
Exemple #8
0
        /// <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);
        }
Exemple #9
0
        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);
        }
Exemple #10
0
        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));
        }
Exemple #11
0
        /// <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);
            });
        }
Exemple #12
0
        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));
        }
Exemple #13
0
        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);
        }
Exemple #14
0
        /// <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);
            }
        }