diff --git a/osu.Game/Rulesets/Judgements/JudgementResult.cs b/osu.Game/Rulesets/Judgements/JudgementResult.cs index 6749fd7932..bf29919e34 100644 --- a/osu.Game/Rulesets/Judgements/JudgementResult.cs +++ b/osu.Game/Rulesets/Judgements/JudgementResult.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using JetBrains.Annotations; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -33,19 +34,30 @@ namespace osu.Game.Rulesets.Judgements public readonly Judgement Judgement; /// - /// The offset of from the end time of , clamped by . - /// Populated when this is applied via . - /// - public double TimeOffset { get; internal set; } - - /// - /// The absolute time at which this occurred. + /// The time at which this occurred. /// Populated when this is applied via . /// /// - /// This is initially set to the end time of . + /// This is used instead of to check whether this should be reverted. /// - public double TimeAbsolute { get; internal set; } + internal double? RawTime { get; set; } + + /// + /// The offset of from the end time of , clamped by . + /// + public double TimeOffset + { + get => RawTime != null ? Math.Min(RawTime.Value - HitObject.GetEndTime(), HitObject.MaximumJudgementOffset) : 0; + internal set => RawTime = HitObject.GetEndTime() + value; + } + + /// + /// The absolute time at which this occurred, clamped by the end time of plus . + /// + /// + /// The end time of is returned if this result is not populated yet. + /// + public double TimeAbsolute => RawTime != null ? Math.Min(RawTime.Value, HitObject.GetEndTime() + HitObject.MaximumJudgementOffset) : HitObject.GetEndTime(); /// /// The combo prior to this occurring. @@ -92,8 +104,7 @@ namespace osu.Game.Rulesets.Judgements internal void Reset() { Type = HitResult.None; - TimeOffset = 0; - TimeAbsolute = HitObject.GetEndTime(); + RawTime = null; } public override string ToString() => $"{Type} (Score:{Judgement.NumericResultFor(this)} HP:{Judgement.HealthIncreaseFor(this)} {Judgement})"; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index d30fc00bfc..f7c6340419 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -661,7 +661,7 @@ namespace osu.Game.Rulesets.Objects.Drawables $"{GetType().ReadableName()} applied an invalid hit result (was: {Result.Type}, expected: [{Result.Judgement.MinResult} ... {Result.Judgement.MaxResult}])."); } - Result.TimeOffset = Math.Min(HitObject.MaximumJudgementOffset, Time.Current - HitObject.GetEndTime()); + Result.RawTime = Time.Current; if (Result.HasResult) updateState(Result.IsHit ? ArmedState.Hit : ArmedState.Miss); diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 5d6a8de33c..b1c3b78e67 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -258,8 +258,16 @@ namespace osu.Game.Rulesets.UI } // When rewinding, revert future judgements in the reverse order. - while (judgedEntries.Count > 0 && Time.Current < judgedEntries.Peek().Result.AsNonNull().TimeAbsolute) + while (judgedEntries.Count > 0) + { + var result = judgedEntries.Peek().Result; + Debug.Assert(result?.RawTime != null); + + if (Time.Current >= result.RawTime.Value) + break; + revertResult(judgedEntries.Pop()); + } } /// @@ -453,7 +461,7 @@ namespace osu.Game.Rulesets.UI private void onNewResult(DrawableHitObject drawable, JudgementResult result) { - Debug.Assert(result != null && drawable.Entry?.Result == result); + Debug.Assert(result != null && drawable.Entry?.Result == result && result.RawTime != null); judgedEntries.Push(drawable.Entry.AsNonNull()); NewResult?.Invoke(drawable, result);