mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 22:27:25 +08:00
Change KPS Counter implementation base and add better replay integration
The counter implementaiton is now list based, and will not invalidate previous hits by removing them but by testing if they are within the 1 second span, allowing better integration with replays and spectators.
This commit is contained in:
parent
2df24019fd
commit
89855cc1d6
@ -1,17 +1,24 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Framework.Logging;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -19,37 +26,71 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
public class KeysPerSecondCounter : RollingCounter<int>, ISkinnableDrawable
|
public class KeysPerSecondCounter : RollingCounter<int>, ISkinnableDrawable
|
||||||
{
|
{
|
||||||
private static Queue<DateTime>? timestamps;
|
private static List<double> timestamps;
|
||||||
|
private static double maxTime = double.NegativeInfinity;
|
||||||
|
|
||||||
private static event Action? onNewInput;
|
private static event Action onNewInput;
|
||||||
private readonly TimeSpan refreshSpan = TimeSpan.FromSeconds(1);
|
|
||||||
|
|
||||||
|
private const int invalidation_timeout = 1000;
|
||||||
private const float alpha_when_invalid = 0.3f;
|
private const float alpha_when_invalid = 0.3f;
|
||||||
|
|
||||||
private readonly Bindable<bool> valid = new Bindable<bool>();
|
private readonly Bindable<bool> valid = new Bindable<bool>();
|
||||||
|
|
||||||
|
private static GameplayClock gameplayClock;
|
||||||
|
private static IClock referenceClock;
|
||||||
|
|
||||||
|
private static IClock clock => referenceClock ?? gameplayClock;
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private DrawableRuleset drawableRuleset { get; set; }
|
||||||
|
|
||||||
|
[SettingSource("Smoothing time", "How smooth the counter should change\nThe more it is smooth, the less it's accurate.")]
|
||||||
|
public BindableNumber<double> SmoothingTime { get; } = new BindableNumber<double>(350)
|
||||||
|
{
|
||||||
|
MaxValue = 1000,
|
||||||
|
MinValue = 0
|
||||||
|
};
|
||||||
|
|
||||||
public static void AddTimestamp()
|
public static void AddTimestamp()
|
||||||
{
|
{
|
||||||
timestamps?.Enqueue(DateTime.Now);
|
Logger.Log($"Input timestamp attempt C: {clock.CurrentTime}ms | GC: {gameplayClock.CurrentTime} | RC: {referenceClock?.CurrentTime ?? -1} | Max: {maxTime})", level: LogLevel.Debug);
|
||||||
|
|
||||||
|
if (clock.CurrentTime >= maxTime)
|
||||||
|
{
|
||||||
|
Logger.Log("Input timestamp added.", level: LogLevel.Debug);
|
||||||
|
timestamps?.Add(clock.CurrentTime);
|
||||||
|
maxTime = timestamps?.Max() ?? clock.CurrentTime;
|
||||||
|
}
|
||||||
|
|
||||||
onNewInput?.Invoke();
|
onNewInput?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override double RollingDuration => 250;
|
public static void Reset()
|
||||||
|
{
|
||||||
|
timestamps?.Clear();
|
||||||
|
maxTime = int.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override double RollingDuration => SmoothingTime.Value;
|
||||||
|
|
||||||
public bool UsesFixedAnchor { get; set; }
|
public bool UsesFixedAnchor { get; set; }
|
||||||
|
|
||||||
public KeysPerSecondCounter()
|
public KeysPerSecondCounter()
|
||||||
{
|
{
|
||||||
timestamps ??= new Queue<DateTime>();
|
timestamps ??= new List<double>();
|
||||||
Current.Value = 0;
|
Current.Value = 0;
|
||||||
onNewInput += updateCounter;
|
onNewInput += updateCounter;
|
||||||
|
Scheduler.AddOnce(updateCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours, GameplayClock clock)
|
||||||
{
|
{
|
||||||
|
gameplayClock = clock;
|
||||||
Colour = colours.BlueLighter;
|
Colour = colours.BlueLighter;
|
||||||
valid.BindValueChanged(e =>
|
valid.BindValueChanged(e =>
|
||||||
DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint));
|
DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint));
|
||||||
|
referenceClock = drawableRuleset?.FrameStableClock;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -61,21 +102,15 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
if (timestamps != null)
|
base.Update();
|
||||||
{
|
|
||||||
if (timestamps.TryPeek(out var earliest) && DateTime.Now - earliest >= refreshSpan)
|
|
||||||
timestamps.Dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCounter();
|
updateCounter();
|
||||||
|
|
||||||
base.Update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateCounter()
|
private void updateCounter()
|
||||||
{
|
{
|
||||||
valid.Value = timestamps != null;
|
valid.Value = timestamps != null && MathHelper.ApproximatelyEquivalent(gameplayClock.CurrentTime, referenceClock.CurrentTime, 500);
|
||||||
Current.Value = timestamps?.Count ?? 0;
|
Current.Value = timestamps?.Count(timestamp => clock.CurrentTime - timestamp is >= 0 and <= invalidation_timeout) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IHasText CreateText() => new TextComponent
|
protected override IHasText CreateText() => new TextComponent
|
||||||
|
@ -11,6 +11,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -65,6 +66,7 @@ namespace osu.Game.Screens.Play
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
|
KeysPerSecondCounter.Reset();
|
||||||
config.BindWith(OsuSetting.KeyOverlay, configVisibility);
|
config.BindWith(OsuSetting.KeyOverlay, configVisibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ using osu.Game.Rulesets.Scoring;
|
|||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Scoring.Legacy;
|
using osu.Game.Scoring.Legacy;
|
||||||
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -1044,6 +1045,9 @@ namespace osu.Game.Screens.Play
|
|||||||
musicController.ResetTrackAdjustments();
|
musicController.ResetTrackAdjustments();
|
||||||
|
|
||||||
fadeOut();
|
fadeOut();
|
||||||
|
|
||||||
|
KeysPerSecondCounter.Reset();
|
||||||
|
|
||||||
return base.OnExiting(e);
|
return base.OnExiting(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user