From d0f30b7b422afe385fd1fc0de7a28684bf0ab7ef Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 13 Apr 2021 14:29:47 +0900 Subject: [PATCH] Delay map completion one frame after the last judgment This is a workaround of a timing issue. KeyCounter is disabled while break time (`HasCompleted == true`). When the last keypress is exactly at the same time the map ends, the last frame was considered in a break time while forward play but considered not in a break time while rewinding. This inconsistency made the last keypress not decremented in the key counter when a replay is rewound. The situation regularly happens in osu!standard because the map ends right after the player hits the last hit circle. It was caught by `TestSceneGameplayRewinding`. This commit makes the update of the map completion delayed one frame. The problematic keypress frame is now processed strictly before the map completion, and the map completion status is correctly rewound before the keypress frame. --- osu.Game/Rulesets/Scoring/JudgementProcessor.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs index 8aef615b5f..201a05e569 100644 --- a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs +++ b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs @@ -28,6 +28,8 @@ namespace osu.Game.Rulesets.Scoring /// public int JudgedHits { get; private set; } + private JudgementResult lastAppliedResult; + private readonly BindableBool hasCompleted = new BindableBool(); /// @@ -53,12 +55,11 @@ namespace osu.Game.Rulesets.Scoring public void ApplyResult(JudgementResult result) { JudgedHits++; + lastAppliedResult = result; ApplyResultInternal(result); NewJudgement?.Invoke(result); - - updateHasCompleted(); } /// @@ -69,8 +70,6 @@ namespace osu.Game.Rulesets.Scoring { JudgedHits--; - updateHasCompleted(); - RevertResultInternal(result); } @@ -134,6 +133,10 @@ namespace osu.Game.Rulesets.Scoring } } - private void updateHasCompleted() => hasCompleted.Value = JudgedHits == MaxHits; + protected override void Update() + { + base.Update(); + hasCompleted.Value = JudgedHits == MaxHits && (JudgedHits == 0 || lastAppliedResult.TimeAbsolute < Clock.CurrentTime); + } } }