1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 15:07:44 +08:00

Fix spinner ticks not playing samples correctly sometimes

Noticed this during work on https://github.com/ppy/osu/pull/25185.

In some circumstances, it seemed that spinner bonus ticks (and mostly
them specifically) would not always play with the correct volume.
Hours of debugging later pointed at a trace at
`DrawableAudioWrapper.refreshLayoutFromParent()` not firing sometimes.

Initially I thought it to be some sort of framework bug, but after
preparing a diff and running final checks, I noticed that sometimes
the sample was being played *by a `PoolableSkinnableSample` that wasn't
loaded*. And determining why *that* is the case turned out with this
diff.

As it happens, spinner ticks get assigned a start time proportionally,
i.e. the 1st of 10 ticks is placed at 10% of the duration, the 2nd
at 20%, and so on. The start time generally shouldn't matter,
because the spinner is manually judging the ticks. *However*, the ticks
*still* receive a lifetime start / end in the same way normal objects
do, which means that in some cases they can *not be alive* when they're
hit, which means that the `DrawableAudioWrapper` flow *hasn't had
a chance to run*, and rightly so.

To fix, ensure that all spinner ticks are alive throughout the entirety
of the spinner's duration.
This commit is contained in:
Bartłomiej Dach 2023-10-23 21:26:25 +02:00
parent fc1254ba47
commit cfd8d05fde
No known key found for this signature in database

View File

@ -4,6 +4,8 @@
#nullable disable
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@ -25,6 +27,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Origin = Anchor.Centre;
}
protected override void OnApply()
{
base.OnApply();
// the tick can be theoretically judged at any point in the spinner's duration,
// so it must be alive throughout the spinner's entire lifetime.
// this mostly matters for correct sample playback.
LifetimeStart = DrawableSpinner.HitObject.StartTime;
}
protected override void UpdateHitStateTransforms(ArmedState state)
{
base.UpdateHitStateTransforms(state);
// the tick can be theoretically judged at any point in the spinner's duration,
// so it must be alive throughout the spinner's entire lifetime (or until hit, whichever applies).
// this mostly matters for correct sample playback.
LifetimeEnd = (Result?.IsHit == true ? Result.TimeAbsolute : DrawableSpinner.HitObject.GetEndTime()) + (Samples?.Length ?? 0);
}
/// <summary>
/// Apply a judgement result.
/// </summary>