/// <summary> /// Handles changes in player state which may progress the completion of gameplay / this screen's lifetime. /// </summary> /// <exception cref="InvalidOperationException">Thrown if this method is called more than once without changing state.</exception> private void scoreCompletionChanged(ValueChangedEvent <bool> completed) { // If this player instance is in the middle of an exit, don't attempt any kind of state update. if (!this.IsCurrentScreen()) { return; } // Special case to handle rewinding post-completion. This is the only way already queued forward progress can be cancelled. // TODO: Investigate whether this can be moved to a RewindablePlayer subclass or similar. // Currently, even if this scenario is hit, prepareScoreForDisplay has already been queued (and potentially run). // In scenarios where rewinding is possible (replay, spectating) this is a non-issue as no submission/import work is done, // but it still doesn't feel right that this exists here. if (!completed.NewValue) { resultsDisplayDelegate?.Cancel(); resultsDisplayDelegate = null; GameplayState.HasPassed = false; ValidForResume = true; skipOutroOverlay.Hide(); return; } // Only show the completion screen if the player hasn't failed if (HealthProcessor.HasFailed) { return; } GameplayState.HasPassed = true; // Setting this early in the process means that even if something were to go wrong in the order of events following, there // is no chance that a user could return to the (already completed) Player instance from a child screen. ValidForResume = false; // Ensure we are not writing to the replay any more, as we are about to consume and store the score. DrawableRuleset.SetRecordTarget(null); if (!Configuration.ShowResults) { return; } prepareScoreForDisplayTask ??= Task.Run(prepareScoreForResults); bool storyboardHasOutro = DimmableStoryboard.ContentDisplayed && !DimmableStoryboard.HasStoryboardEnded.Value; if (storyboardHasOutro) { // if the current beatmap has a storyboard, the progression to results will be handled by the storyboard ending // or the user pressing the skip outro button. skipOutroOverlay.Show(); return; } progressToResults(true); }
/// <summary> /// Run any recording / playback setup for replays. /// </summary> protected virtual void PrepareReplay() { DrawableRuleset.SetRecordTarget(recordingScore = new Score()); ScoreProcessor.NewJudgement += result => ScoreProcessor.PopulateScore(recordingScore.ScoreInfo); }
/// <summary> /// Run any recording / playback setup for replays. /// </summary> protected virtual void PrepareReplay() { DrawableRuleset.SetRecordTarget(recordingReplay = new Replay()); }
/// <summary> /// Run any recording / playback setup for replays. /// </summary> protected virtual void PrepareReplay() { DrawableRuleset.SetRecordTarget(Score); }
/// <summary> /// Handles changes in player state which may progress the completion of gameplay / this screen's lifetime. /// </summary> /// <param name="skipStoryboardOutro">If in a state where a storyboard outro is to be played, offers the choice of skipping beyond it.</param> /// <exception cref="InvalidOperationException">Thrown if this method is called more than once without changing state.</exception> private void updateCompletionState(bool skipStoryboardOutro = false) { // screen may be in the exiting transition phase. if (!this.IsCurrentScreen()) { return; } if (!ScoreProcessor.HasCompleted.Value) { completionProgressDelegate?.Cancel(); completionProgressDelegate = null; ValidForResume = true; skipOutroOverlay.Hide(); return; } if (completionProgressDelegate != null) { throw new InvalidOperationException($"{nameof(updateCompletionState)} was fired more than once"); } // Only show the completion screen if the player hasn't failed if (HealthProcessor.HasFailed) { return; } ValidForResume = false; // ensure we are not writing to the replay any more, as we are about to consume and store the score. DrawableRuleset.SetRecordTarget(null); if (!Configuration.ShowResults) { return; } prepareScoreForDisplayTask ??= Task.Run(async() => { PrepareScoreForResults(); try { await PrepareScoreForResultsAsync(Score).ConfigureAwait(false); } catch (Exception ex) { Logger.Error(ex, "Score preparation failed!"); } try { await ImportScore(Score).ConfigureAwait(false); } catch (Exception ex) { Logger.Error(ex, "Score import failed!"); } return(Score.ScoreInfo); }); if (skipStoryboardOutro) { scheduleCompletion(); return; } bool storyboardHasOutro = DimmableStoryboard.ContentDisplayed && !DimmableStoryboard.HasStoryboardEnded.Value; if (storyboardHasOutro) { skipOutroOverlay.Show(); return; } using (BeginDelayedSequence(RESULTS_DISPLAY_DELAY)) scheduleCompletion(); }