diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs
index f7f62d2af0..b28e3355a4 100644
--- a/osu.Game/Rulesets/UI/DrawableRuleset.cs
+++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs
@@ -30,6 +30,7 @@ using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
+using osu.Game.Screens.Play.HUD.KPSCounter;
using osuTK;
namespace osu.Game.Rulesets.UI
@@ -38,7 +39,7 @@ namespace osu.Game.Rulesets.UI
/// Displays an interactive ruleset gameplay instance.
///
/// The type of HitObject contained by this DrawableRuleset.
- public abstract class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter
+ public abstract class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter, ICanAttachKpsCalculator
where TObject : HitObject
{
public override event Action NewResult;
@@ -340,6 +341,8 @@ namespace osu.Game.Rulesets.UI
public void Attach(KeyCounterDisplay keyCounter) =>
(KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(keyCounter);
+ public void Attach(KeysPerSecondCalculator kps) => (KeyBindingInputManager as ICanAttachKpsCalculator)?.Attach(kps);
+
///
/// Creates a key conversion input manager. An exception will be thrown if a valid is not returned.
///
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index 7c37913576..23e64153eb 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -20,11 +20,12 @@ using osu.Game.Input.Bindings;
using osu.Game.Input.Handlers;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play;
+using osu.Game.Screens.Play.HUD.KPSCounter;
using static osu.Game.Input.Handlers.ReplayInputHandler;
namespace osu.Game.Rulesets.UI
{
- public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler, IHasRecordingHandler
+ public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler, IHasRecordingHandler, ICanAttachKpsCalculator
where T : struct
{
public readonly KeyBindingContainer KeyBindingContainer;
@@ -186,6 +187,35 @@ namespace osu.Game.Rulesets.UI
#endregion
+ #region KPS Counter Attachment
+
+ public void Attach(KeysPerSecondCalculator kps)
+ {
+ var listener = new ActionListener();
+
+ KeyBindingContainer.Add(listener);
+
+ kps.Listener = listener;
+ }
+
+ public class ActionListener : KeysPerSecondCalculator.InputListener, IKeyBindingHandler
+ {
+ public override event Action OnNewInput;
+
+ public bool OnPressed(KeyBindingPressEvent e)
+ {
+ OnNewInput?.Invoke();
+
+ return false;
+ }
+
+ public void OnReleased(KeyBindingReleaseEvent e)
+ {
+ }
+ }
+
+ #endregion
+
protected virtual KeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
=> new RulesetKeyBindingContainer(ruleset, variant, unique);
@@ -229,6 +259,11 @@ namespace osu.Game.Rulesets.UI
void Attach(KeyCounterDisplay keyCounter);
}
+ public interface ICanAttachKpsCalculator
+ {
+ void Attach(KeysPerSecondCalculator keysPerSecondCalculator);
+ }
+
public class RulesetInputManagerInputState : InputState
where T : struct
{
diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs
index 3c0d585984..96a6d5b8eb 100644
--- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs
+++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs
@@ -4,55 +4,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
using osu.Framework.Timing;
-using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
namespace osu.Game.Screens.Play.HUD.KPSCounter
{
- public class KeysPerSecondCalculator
+ public class KeysPerSecondCalculator : Component
{
- public static void AddInput()
- {
- onNewInput?.Invoke();
- }
-
private readonly List timestamps;
- private GameplayClock? gameplayClock;
- private DrawableRuleset? drawableRuleset;
- public GameplayClock? GameplayClock
+ private InputListener? listener;
+
+ [Resolved]
+ private GameplayClock? gameplayClock { get; set; }
+
+ [Resolved(canBeNull: true)]
+ private DrawableRuleset? drawableRuleset { get; set; }
+
+ public InputListener Listener
{
- get => gameplayClock;
set
{
onResetRequested?.Invoke();
-
- if (value != null)
- {
- gameplayClock = value;
- }
+ listener = value;
+ listener.OnNewInput += addTimestamp;
}
}
- public DrawableRuleset? DrawableRuleset
- {
- get => drawableRuleset;
- set
- {
- onResetRequested?.Invoke();
-
- if (value != null)
- {
- drawableRuleset = value;
- baseRate = (drawableRuleset.Mods.FirstOrDefault(m => m is ModRateAdjust) as ModRateAdjust)?.SpeedChange.Value
- ?? 1;
- }
- }
- }
-
- private static event Action? onNewInput;
- private static event Action? onResetRequested;
+ private event Action? onResetRequested;
private IClock? workingClock => drawableRuleset?.FrameStableClock;
@@ -81,8 +62,8 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter
public KeysPerSecondCalculator()
{
+ RelativeSizeAxes = Axes.Both;
timestamps = new List();
- onNewInput += addTimestamp;
onResetRequested += cleanUp;
}
@@ -90,6 +71,9 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter
{
timestamps.Clear();
maxTime = double.NegativeInfinity;
+
+ if (listener != null)
+ listener.OnNewInput -= addTimestamp;
}
private void addTimestamp()
@@ -111,5 +95,21 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter
double relativeTime = workingClock.CurrentTime - timestamp;
return relativeTime >= 0 && relativeTime <= span;
}
+
+ ~KeysPerSecondCalculator()
+ {
+ cleanUp();
+ }
+
+ public abstract class InputListener : Component
+ {
+ protected InputListener()
+ {
+ RelativeSizeAxes = Axes.Both;
+ Depth = float.MinValue;
+ }
+
+ public abstract event Action? OnNewInput;
+ }
}
}
diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs
index ad7b6c8f5c..d6f1d19770 100644
--- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs
+++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs
@@ -22,21 +22,15 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter
private readonly Bindable valid = new Bindable();
- private static readonly KeysPerSecondCalculator calculator = new KeysPerSecondCalculator();
-
[Resolved]
- private GameplayClock? gameplayClock
- {
- get => calculator.GameplayClock;
- set => calculator.GameplayClock = value;
- }
+ private KeysPerSecondCalculator? calculator { get; set; }
+
+ // This is to force the skin editor to show the component only in a Gameplay context
+ [Resolved]
+ private GameplayClock? gameplayClock { get; set; }
[Resolved(canBeNull: true)]
- private DrawableRuleset? drawableRuleset
- {
- get => calculator.DrawableRuleset;
- set => calculator.DrawableRuleset = value;
- }
+ private DrawableRuleset? drawableRuleset { get; set; }
protected override double RollingDuration => 350;
@@ -59,8 +53,8 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter
{
base.Update();
- valid.Value = calculator.Ready;
- Current.Value = calculator.Ready ? calculator.Value : 0;
+ valid.Value = calculator != null && calculator.Ready;
+ Current.Value = calculator != null ? calculator.Ready ? calculator.Value : 0 : 0;
}
protected override IHasText CreateText() => new TextComponent
diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs
index 8f80644d52..1c28e04950 100644
--- a/osu.Game/Screens/Play/HUDOverlay.cs
+++ b/osu.Game/Screens/Play/HUDOverlay.cs
@@ -22,6 +22,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play.HUD;
+using osu.Game.Screens.Play.HUD.KPSCounter;
using osu.Game.Skinning;
using osuTK;
@@ -49,6 +50,9 @@ namespace osu.Game.Screens.Play
public readonly HoldForMenuButton HoldToQuit;
public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
+ [Cached]
+ private readonly KeysPerSecondCalculator keysPerSecondCalculator;
+
public Bindable ShowHealthBar = new Bindable(true);
private readonly DrawableRuleset drawableRuleset;
@@ -122,7 +126,8 @@ namespace osu.Game.Screens.Play
KeyCounter = CreateKeyCounter(),
HoldToQuit = CreateHoldForMenuButton(),
}
- }
+ },
+ keysPerSecondCalculator = new KeysPerSecondCalculator()
};
}
@@ -260,6 +265,7 @@ namespace osu.Game.Screens.Play
protected virtual void BindDrawableRuleset(DrawableRuleset drawableRuleset)
{
(drawableRuleset as ICanAttachKeyCounter)?.Attach(KeyCounter);
+ (drawableRuleset as ICanAttachKpsCalculator)?.Attach(keysPerSecondCalculator);
replayLoaded.BindTo(drawableRuleset.HasReplayLoaded);
}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 044c9ee24e..1e5ada5295 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -10,7 +10,6 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
-using osu.Game.Screens.Play.HUD.KPSCounter;
using osuTK;
using osuTK.Graphics;
@@ -56,7 +55,6 @@ namespace osu.Game.Screens.Play
public void Increment()
{
- KeysPerSecondCalculator.AddInput();
if (!IsCounting)
return;