1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 22:33:05 +08:00

Fix key counters appearing negative on intense beatmaps

When `FrameStabilityContainer` decides it needs multiple updates on the same frame, it ends up with an elapsed time of zero. This was interacting badly with the condition used in `RulesetInputManager` to govern playback direction.

I have changed this to use `Rate` as exposed by the frame stable clock.

- Closes #6198.
This commit is contained in:
Dean Herbert 2019-10-03 15:00:47 +08:00
parent cbdf42cd7b
commit b28689c774
2 changed files with 17 additions and 15 deletions

View File

@ -47,6 +47,11 @@ namespace osu.Game.Rulesets.UI
private IFrameBasedClock parentGameplayClock; private IFrameBasedClock parentGameplayClock;
/// <summary>
/// The current direction of playback to be exposed to frame stable children.
/// </summary>
private int direction;
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(GameplayClock clock) private void load(GameplayClock clock)
{ {
@ -111,16 +116,12 @@ namespace osu.Game.Rulesets.UI
validState = true; validState = true;
manualClock.Rate = parentGameplayClock.Rate;
manualClock.IsRunning = parentGameplayClock.IsRunning;
var newProposedTime = parentGameplayClock.CurrentTime; var newProposedTime = parentGameplayClock.CurrentTime;
try try
{ {
if (!FrameStablePlayback) if (!FrameStablePlayback)
{ {
manualClock.CurrentTime = newProposedTime;
requireMoreUpdateLoops = false; requireMoreUpdateLoops = false;
return; return;
} }
@ -128,9 +129,9 @@ namespace osu.Game.Rulesets.UI
{ {
// On the first update, frame-stability seeking would result in unexpected/unwanted behaviour. // On the first update, frame-stability seeking would result in unexpected/unwanted behaviour.
// Instead we perform an initial seek to the proposed time. // Instead we perform an initial seek to the proposed time.
manualClock.CurrentTime = newProposedTime;
// do a second process to clear out ElapsedTime // process frame (in addition to finally clause) to clear out ElapsedTime
manualClock.CurrentTime = newProposedTime;
framedClock.ProcessFrame(); framedClock.ProcessFrame();
firstConsumption = false; firstConsumption = false;
@ -144,11 +145,7 @@ namespace osu.Game.Rulesets.UI
: Math.Max(newProposedTime, manualClock.CurrentTime - sixty_frame_time); : Math.Max(newProposedTime, manualClock.CurrentTime - sixty_frame_time);
} }
if (!isAttached) if (isAttached)
{
manualClock.CurrentTime = newProposedTime;
}
else
{ {
double? newTime = ReplayInputHandler.SetFrameFromTime(newProposedTime); double? newTime = ReplayInputHandler.SetFrameFromTime(newProposedTime);
@ -156,9 +153,7 @@ namespace osu.Game.Rulesets.UI
{ {
// we shouldn't execute for this time value. probably waiting on more replay data. // we shouldn't execute for this time value. probably waiting on more replay data.
validState = false; validState = false;
requireMoreUpdateLoops = true; requireMoreUpdateLoops = true;
manualClock.CurrentTime = newProposedTime;
return; return;
} }
@ -169,6 +164,13 @@ namespace osu.Game.Rulesets.UI
} }
finally finally
{ {
if (newProposedTime != manualClock.CurrentTime)
direction = newProposedTime > manualClock.CurrentTime ? 1 : -1;
manualClock.CurrentTime = newProposedTime;
manualClock.Rate = Math.Abs(parentGameplayClock.Rate) * direction;
manualClock.IsRunning = parentGameplayClock.IsRunning;
// The manual clock time has changed in the above code. The framed clock now needs to be updated // The manual clock time has changed in the above code. The framed clock now needs to be updated
// to ensure that the its time is valid for our children before input is processed // to ensure that the its time is valid for our children before input is processed
framedClock.ProcessFrame(); framedClock.ProcessFrame();

View File

@ -137,9 +137,9 @@ namespace osu.Game.Rulesets.UI
{ {
} }
public bool OnPressed(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnPressed(action, Clock.ElapsedFrameTime > 0)); public bool OnPressed(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnPressed(action, Clock.Rate >= 0));
public bool OnReleased(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnReleased(action, Clock.ElapsedFrameTime > 0)); public bool OnReleased(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnReleased(action, Clock.Rate >= 0));
} }
#endregion #endregion