Store Result.TimeAbsolute separately from offset

Calculating from TimeOffset is bad because it loses precision.
The result time won't change anymore
even If `HitObject.GetEndTime()` changes later.
This commit is contained in:
ekrctb
2023-01-24 15:35:06 +09:00
parent cc87923179
commit efef97d5be
4 changed files with 20 additions and 10 deletions

View File

@ -33,16 +33,19 @@ namespace osu.Game.Rulesets.Judgements
public readonly Judgement Judgement; public readonly Judgement Judgement;
/// <summary> /// <summary>
/// The offset from a perfect hit at which this <see cref="JudgementResult"/> occurred. /// The offset of <see cref="TimeAbsolute"/> from the end time of <see cref="HitObject"/>, clamped by <see cref="DrawableHitObject.MaximumJudgementOffset"/>.
/// Populated when this <see cref="JudgementResult"/> is applied via <see cref="DrawableHitObject.ApplyResult"/>. /// Populated when this <see cref="JudgementResult"/> is applied via <see cref="DrawableHitObject.ApplyResult"/>.
/// </summary> /// </summary>
public double TimeOffset { get; internal set; } public double TimeOffset { get; internal set; }
/// <summary> /// <summary>
/// The absolute time at which this <see cref="JudgementResult"/> occurred. /// The absolute time at which this <see cref="JudgementResult"/> occurred.
/// Equal to the (end) time of the <see cref="HitObject"/> + <see cref="TimeOffset"/>. /// Populated when this <see cref="JudgementResult"/> is applied via <see cref="DrawableHitObject.ApplyResult"/>.
/// </summary> /// </summary>
public double TimeAbsolute => HitObject.GetEndTime() + TimeOffset; /// <remarks>
/// This is initially set to the end time of <see cref="HitObject"/>.
/// </remarks>
public double TimeAbsolute { get; internal set; }
/// <summary> /// <summary>
/// The combo prior to this <see cref="JudgementResult"/> occurring. /// The combo prior to this <see cref="JudgementResult"/> occurring.
@ -83,6 +86,14 @@ namespace osu.Game.Rulesets.Judgements
{ {
HitObject = hitObject; HitObject = hitObject;
Judgement = judgement; Judgement = judgement;
Reset();
}
internal void Reset()
{
Type = HitResult.None;
TimeOffset = 0;
TimeAbsolute = HitObject.GetEndTime();
} }
public override string ToString() => $"{Type} (Score:{Judgement.NumericResultFor(this)} HP:{Judgement.HealthIncreaseFor(this)} {Judgement})"; public override string ToString() => $"{Type} (Score:{Judgement.NumericResultFor(this)} HP:{Judgement.HealthIncreaseFor(this)} {Judgement})";

View File

@ -7,15 +7,14 @@ namespace osu.Game.Rulesets.Judgements
{ {
internal class JudgementResultEntry internal class JudgementResultEntry
{ {
public readonly double Time; public double Time => Result.TimeAbsolute;
public readonly HitObjectLifetimeEntry HitObjectEntry; public readonly HitObjectLifetimeEntry HitObjectEntry;
public readonly JudgementResult Result; public readonly JudgementResult Result;
public JudgementResultEntry(double time, HitObjectLifetimeEntry hitObjectEntry, JudgementResult result) public JudgementResultEntry(HitObjectLifetimeEntry hitObjectEntry, JudgementResult result)
{ {
Time = time;
HitObjectEntry = hitObjectEntry; HitObjectEntry = hitObjectEntry;
Result = result; Result = result;
} }

View File

@ -673,7 +673,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
$"{GetType().ReadableName()} applied an invalid hit result (was: {Result.Type}, expected: [{Result.Judgement.MinResult} ... {Result.Judgement.MaxResult}])."); $"{GetType().ReadableName()} applied an invalid hit result (was: {Result.Type}, expected: [{Result.Judgement.MinResult} ... {Result.Judgement.MaxResult}]).");
} }
Result.TimeOffset = Math.Min(MaximumJudgementOffset, Time.Current - HitObject.GetEndTime()); Result.TimeAbsolute = Time.Current;
Result.TimeOffset = Math.Min(MaximumJudgementOffset, Result.TimeAbsolute - HitObject.GetEndTime());
if (Result.HasResult) if (Result.HasResult)
updateState(Result.IsHit ? ArmedState.Hit : ArmedState.Miss); updateState(Result.IsHit ? ArmedState.Hit : ArmedState.Miss);

View File

@ -455,7 +455,7 @@ namespace osu.Game.Rulesets.UI
private void onNewResult(DrawableHitObject drawable, JudgementResult result) private void onNewResult(DrawableHitObject drawable, JudgementResult result)
{ {
// Not using result.TimeAbsolute because that might change and also there is a potential precision issue. // Not using result.TimeAbsolute because that might change and also there is a potential precision issue.
judgementResults.Push(new JudgementResultEntry(Time.Current, drawable.Entry.AsNonNull(), result)); judgementResults.Push(new JudgementResultEntry(drawable.Entry.AsNonNull(), result));
NewResult?.Invoke(drawable, result); NewResult?.Invoke(drawable, result);
} }
@ -466,8 +466,7 @@ namespace osu.Game.Rulesets.UI
RevertResult?.Invoke(result); RevertResult?.Invoke(result);
entry.HitObjectEntry.OnRevertResult(); entry.HitObjectEntry.OnRevertResult();
result.TimeOffset = 0; result.Reset();
result.Type = HitResult.None;
} }
#region Editor logic #region Editor logic