mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 19:42:55 +08:00
Move judgement result revert logic to Playfield
Previously, some judgement results were not reverted when the source DHO is not alive (e.g. frames skipped in editor). Now, all results are reverted in the exact reverse order.
This commit is contained in:
parent
f7c4199a77
commit
812a4b412a
@ -74,12 +74,12 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
});
|
||||
AddStep("revert second result", () =>
|
||||
{
|
||||
catcher.OnRevertResult(drawableObject2, result2);
|
||||
catcher.OnRevertResult(result2);
|
||||
});
|
||||
checkHyperDash(true);
|
||||
AddStep("revert first result", () =>
|
||||
{
|
||||
catcher.OnRevertResult(drawableObject1, result1);
|
||||
catcher.OnRevertResult(result1);
|
||||
});
|
||||
checkHyperDash(false);
|
||||
}
|
||||
@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
checkState(CatcherAnimationState.Kiai);
|
||||
AddStep("revert result", () =>
|
||||
{
|
||||
catcher.OnRevertResult(drawableObject, result);
|
||||
catcher.OnRevertResult(result);
|
||||
});
|
||||
checkState(CatcherAnimationState.Idle);
|
||||
}
|
||||
|
@ -63,12 +63,12 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
updateCombo(result.ComboAtJudgement + 1, judgedObject.AccentColour.Value);
|
||||
}
|
||||
|
||||
public void OnRevertResult(DrawableCatchHitObject judgedObject, JudgementResult result)
|
||||
public void OnRevertResult(JudgementResult result)
|
||||
{
|
||||
if (!result.Type.AffectsCombo() || !result.HasResult)
|
||||
return;
|
||||
|
||||
updateCombo(result.ComboAtJudgement, judgedObject.AccentColour.Value);
|
||||
updateCombo(result.ComboAtJudgement, null);
|
||||
}
|
||||
|
||||
private void updateCombo(int newCombo, Color4? hitObjectColour)
|
||||
|
@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||
=> CatcherArea.OnNewResult((DrawableCatchHitObject)judgedObject, result);
|
||||
|
||||
private void onRevertResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||
=> CatcherArea.OnRevertResult((DrawableCatchHitObject)judgedObject, result);
|
||||
private void onRevertResult(JudgementResult result)
|
||||
=> CatcherArea.OnRevertResult(result);
|
||||
}
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
}
|
||||
}
|
||||
|
||||
public void OnRevertResult(DrawableCatchHitObject drawableObject, JudgementResult result)
|
||||
public void OnRevertResult(JudgementResult result)
|
||||
{
|
||||
var catchResult = (CatchJudgementResult)result;
|
||||
|
||||
@ -268,8 +268,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
SetHyperDashState();
|
||||
}
|
||||
|
||||
caughtObjectContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject, false);
|
||||
droppedObjectTarget.RemoveAll(d => d.HitObject == drawableObject.HitObject, false);
|
||||
caughtObjectContainer.RemoveAll(d => d.HitObject == result.HitObject, false);
|
||||
droppedObjectTarget.RemoveAll(d => d.HitObject == result.HitObject, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -73,10 +73,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
comboDisplay.OnNewResult(hitObject, result);
|
||||
}
|
||||
|
||||
public void OnRevertResult(DrawableCatchHitObject hitObject, JudgementResult result)
|
||||
public void OnRevertResult(JudgementResult result)
|
||||
{
|
||||
comboDisplay.OnRevertResult(hitObject, result);
|
||||
Catcher.OnRevertResult(hitObject, result);
|
||||
comboDisplay.OnRevertResult(result);
|
||||
Catcher.OnRevertResult(result);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
|
26
osu.Game/Rulesets/Judgements/JudgementResultEntry.cs
Normal file
26
osu.Game/Rulesets/Judgements/JudgementResultEntry.cs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Judgements
|
||||
{
|
||||
internal class JudgementResultEntry : IComparable<JudgementResultEntry>
|
||||
{
|
||||
public readonly double Time;
|
||||
|
||||
public readonly HitObjectLifetimeEntry HitObjectEntry;
|
||||
|
||||
public readonly JudgementResult Result;
|
||||
|
||||
public JudgementResultEntry(double time, HitObjectLifetimeEntry hitObjectEntry, JudgementResult result)
|
||||
{
|
||||
Time = time;
|
||||
HitObjectEntry = hitObjectEntry;
|
||||
Result = result;
|
||||
}
|
||||
|
||||
public int CompareTo(JudgementResultEntry? other) => Time.CompareTo(other?.Time);
|
||||
}
|
||||
}
|
@ -82,6 +82,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// <summary>
|
||||
/// Invoked by this or a nested <see cref="DrawableHitObject"/> prior to a <see cref="JudgementResult"/> being reverted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is only invoked if this <see cref="DrawableHitObject"/> is alive when the result is reverted.
|
||||
/// </remarks>
|
||||
public event Action<DrawableHitObject, JudgementResult> OnRevertResult;
|
||||
|
||||
/// <summary>
|
||||
@ -222,6 +225,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
ensureEntryHasResult();
|
||||
|
||||
entry.RevertResult += onRevertResult;
|
||||
|
||||
foreach (var h in HitObject.NestedHitObjects)
|
||||
{
|
||||
var pooledDrawableNested = pooledObjectProvider?.GetPooledDrawableRepresentation(h, this);
|
||||
@ -234,7 +239,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
OnNestedDrawableCreated?.Invoke(drawableNested);
|
||||
|
||||
drawableNested.OnNewResult += onNewResult;
|
||||
drawableNested.OnRevertResult += onRevertResult;
|
||||
drawableNested.ApplyCustomUpdateState += onApplyCustomUpdateState;
|
||||
|
||||
// This is only necessary for non-pooled DHOs. For pooled DHOs, this is handled inside GetPooledDrawableRepresentation().
|
||||
@ -309,7 +313,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
foreach (var obj in nestedHitObjects)
|
||||
{
|
||||
obj.OnNewResult -= onNewResult;
|
||||
obj.OnRevertResult -= onRevertResult;
|
||||
obj.ApplyCustomUpdateState -= onApplyCustomUpdateState;
|
||||
}
|
||||
|
||||
@ -318,6 +321,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
HitObject.DefaultsApplied -= onDefaultsApplied;
|
||||
|
||||
entry.RevertResult -= onRevertResult;
|
||||
|
||||
OnFree();
|
||||
|
||||
ParentHitObject = null;
|
||||
@ -366,7 +371,11 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
private void onNewResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnNewResult?.Invoke(drawableHitObject, result);
|
||||
|
||||
private void onRevertResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnRevertResult?.Invoke(drawableHitObject, result);
|
||||
private void onRevertResult()
|
||||
{
|
||||
updateState(ArmedState.Idle);
|
||||
OnRevertResult?.Invoke(this, Result);
|
||||
}
|
||||
|
||||
private void onApplyCustomUpdateState(DrawableHitObject drawableHitObject, ArmedState state) => ApplyCustomUpdateState?.Invoke(drawableHitObject, state);
|
||||
|
||||
@ -578,26 +587,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (Result != null && Result.HasResult)
|
||||
{
|
||||
double endTime = HitObject.GetEndTime();
|
||||
|
||||
if (Result.TimeOffset + endTime > Time.Current)
|
||||
{
|
||||
OnRevertResult?.Invoke(this, Result);
|
||||
|
||||
Result.TimeOffset = 0;
|
||||
Result.Type = HitResult.None;
|
||||
|
||||
updateState(ArmedState.Idle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool UpdateSubTreeMasking(Drawable source, RectangleF maskingBounds) => false;
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Performance;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
@ -26,6 +27,8 @@ namespace osu.Game.Rulesets.Objects
|
||||
|
||||
private readonly IBindable<double> startTimeBindable = new BindableDouble();
|
||||
|
||||
internal event Action? RevertResult;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="HitObjectLifetimeEntry"/>.
|
||||
/// </summary>
|
||||
@ -95,5 +98,7 @@ namespace osu.Game.Rulesets.Objects
|
||||
/// Set <see cref="LifetimeEntry.LifetimeStart"/> using <see cref="InitialLifetimeOffset"/>.
|
||||
/// </summary>
|
||||
internal void SetInitialLifetime() => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset;
|
||||
|
||||
internal void OnRevertResult() => RevertResult?.Invoke();
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.UI
|
||||
playfield = new Lazy<Playfield>(() => CreatePlayfield().With(p =>
|
||||
{
|
||||
p.NewResult += (_, r) => NewResult?.Invoke(r);
|
||||
p.RevertResult += (_, r) => RevertResult?.Invoke(r);
|
||||
p.RevertResult += r => RevertResult?.Invoke(r);
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -28,11 +28,6 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
public event Action<DrawableHitObject, JudgementResult> NewResult;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="DrawableHitObject"/> judgement is reverted.
|
||||
/// </summary>
|
||||
public event Action<DrawableHitObject, JudgementResult> RevertResult;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="HitObject"/> becomes used by a <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
@ -111,7 +106,6 @@ namespace osu.Game.Rulesets.UI
|
||||
private void addDrawable(DrawableHitObject drawable)
|
||||
{
|
||||
drawable.OnNewResult += onNewResult;
|
||||
drawable.OnRevertResult += onRevertResult;
|
||||
|
||||
bindStartTime(drawable);
|
||||
AddInternal(drawable);
|
||||
@ -120,7 +114,6 @@ namespace osu.Game.Rulesets.UI
|
||||
private void removeDrawable(DrawableHitObject drawable)
|
||||
{
|
||||
drawable.OnNewResult -= onNewResult;
|
||||
drawable.OnRevertResult -= onRevertResult;
|
||||
|
||||
unbindStartTime(drawable);
|
||||
|
||||
@ -154,7 +147,6 @@ namespace osu.Game.Rulesets.UI
|
||||
#endregion
|
||||
|
||||
private void onNewResult(DrawableHitObject d, JudgementResult r) => NewResult?.Invoke(d, r);
|
||||
private void onRevertResult(DrawableHitObject d, JudgementResult r) => RevertResult?.Invoke(d, r);
|
||||
|
||||
#region Comparator + StartTime tracking
|
||||
|
||||
|
@ -22,6 +22,8 @@ using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osu.Game.Rulesets.Objects.Pooling;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
@ -35,9 +37,9 @@ namespace osu.Game.Rulesets.UI
|
||||
public event Action<DrawableHitObject, JudgementResult> NewResult;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="DrawableHitObject"/> judgement is reverted.
|
||||
/// Invoked when a judgement result is reverted.
|
||||
/// </summary>
|
||||
public event Action<DrawableHitObject, JudgementResult> RevertResult;
|
||||
public event Action<JudgementResult> RevertResult;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DrawableHitObject"/> contained in this Playfield.
|
||||
@ -98,6 +100,8 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager();
|
||||
|
||||
private readonly Stack<JudgementResultEntry> judgementResults;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Playfield"/>.
|
||||
/// </summary>
|
||||
@ -107,14 +111,15 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
hitObjectContainerLazy = new Lazy<HitObjectContainer>(() => CreateHitObjectContainer().With(h =>
|
||||
{
|
||||
h.NewResult += (d, r) => NewResult?.Invoke(d, r);
|
||||
h.RevertResult += (d, r) => RevertResult?.Invoke(d, r);
|
||||
h.NewResult += onNewResult;
|
||||
h.HitObjectUsageBegan += o => HitObjectUsageBegan?.Invoke(o);
|
||||
h.HitObjectUsageFinished += o => HitObjectUsageFinished?.Invoke(o);
|
||||
}));
|
||||
|
||||
entryManager.OnEntryAdded += onEntryAdded;
|
||||
entryManager.OnEntryRemoved += onEntryRemoved;
|
||||
|
||||
judgementResults = new Stack<JudgementResultEntry>();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -224,7 +229,7 @@ namespace osu.Game.Rulesets.UI
|
||||
otherPlayfield.DisplayJudgements.BindTo(DisplayJudgements);
|
||||
|
||||
otherPlayfield.NewResult += (d, r) => NewResult?.Invoke(d, r);
|
||||
otherPlayfield.RevertResult += (d, r) => RevertResult?.Invoke(d, r);
|
||||
otherPlayfield.RevertResult += r => RevertResult?.Invoke(r);
|
||||
otherPlayfield.HitObjectUsageBegan += h => HitObjectUsageBegan?.Invoke(h);
|
||||
otherPlayfield.HitObjectUsageFinished += h => HitObjectUsageFinished?.Invoke(h);
|
||||
|
||||
@ -252,6 +257,10 @@ namespace osu.Game.Rulesets.UI
|
||||
updatable.Update(this);
|
||||
}
|
||||
}
|
||||
|
||||
// When rewinding, revert future judgements in the reverse order.
|
||||
while (judgementResults.Count > 0 && Time.Current < judgementResults.Peek().Time)
|
||||
revertResult(judgementResults.Pop());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -443,6 +452,25 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
#endregion
|
||||
|
||||
private void onNewResult(DrawableHitObject drawable, JudgementResult result)
|
||||
{
|
||||
// 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));
|
||||
|
||||
NewResult?.Invoke(drawable, result);
|
||||
}
|
||||
|
||||
private void revertResult(JudgementResultEntry entry)
|
||||
{
|
||||
var result = entry.Result;
|
||||
RevertResult?.Invoke(result);
|
||||
|
||||
result.TimeOffset = 0;
|
||||
result.Type = HitResult.None;
|
||||
|
||||
entry.HitObjectEntry.OnRevertResult();
|
||||
}
|
||||
|
||||
#region Editor logic
|
||||
|
||||
/// <summary>
|
||||
|
Loading…
Reference in New Issue
Block a user