From 430bacf91722a182472f6ab45a931aea2b808ab9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 13:50:53 +0900 Subject: [PATCH 01/32] Add initial layout of comparison screens --- .../Settings/TestSceneLatencyComparer.cs | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs new file mode 100644 index 0000000000..cf9a01f0b1 --- /dev/null +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs @@ -0,0 +1,261 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Framework.Input.Events; +using osu.Framework.Screens; +using osu.Game.Screens; +using osuTK; +using osuTK.Graphics; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Settings +{ + public class TestSceneLatencyComparer : ScreenTestScene + { + [Test] + public void TestBasic() + { + AddStep("Load screen", () => LoadScreen(new LatencyComparerScreen())); + } + } + + public class LatencyComparerScreen : OsuScreen + { + private FrameSync previousFrameSyncMode; + + public override bool HideOverlaysOnEnter => true; + + public override bool CursorVisible => false; + + [Resolved] + private FrameworkConfigManager config { get; set; } = null!; + + public LatencyComparerScreen() + { + InternalChildren = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.Absolute, 100), + new Dimension(), + new Dimension(GridSizeMode.Absolute, 100), + }, + Content = new[] + { + new Drawable[] + { + // header content + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new LatencyArea(10) + { + Width = 0.5f, + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + }, + new LatencyArea(0) + { + Width = 0.5f, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }, + new Box + { + Colour = Color4.Black, + Width = 50, + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + } + }, + }, + new Drawable[] + { + // footer content + }, + } + } + }; + } + + public override void OnEntering(ScreenTransitionEvent e) + { + base.OnEntering(e); + + previousFrameSyncMode = config.Get(FrameworkSetting.FrameSync); + config.SetValue(FrameworkSetting.FrameSync, FrameSync.Unlimited); + // host.AllowBenchmarkUnlimitedFrames = true; + } + + public override bool OnExiting(ScreenExitEvent e) + { + // host.AllowBenchmarkUnlimitedFrames = false; + config.SetValue(FrameworkSetting.FrameSync, previousFrameSyncMode); + return base.OnExiting(e); + } + + public class LatencyArea : CompositeDrawable + { + private readonly int inducedLatency; + + public LatencyArea(int inducedLatency) + { + this.inducedLatency = inducedLatency; + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = Color4.Blue, + RelativeSizeAxes = Axes.Both, + }, + new LatencyMovableBox + { + RelativeSizeAxes = Axes.Both, + }, + new LatencyCursorContainer + { + RelativeSizeAxes = Axes.Both, + } + }; + } + + private long frameCount; + + public override bool UpdateSubTree() + { + if (inducedLatency > 0 && ++frameCount % inducedLatency != 0) + return false; + + return base.UpdateSubTree(); + } + + public class LatencyMovableBox : CompositeDrawable + { + private Box box = null!; + private InputManager inputManager = null!; + + public LatencyMovableBox() + { + Masking = true; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + + InternalChild = box = new Box + { + Size = new Vector2(40), + Position = DrawSize / 2, + Origin = Anchor.Centre, + }; + } + + protected override bool OnHover(HoverEvent e) => false; + + private double? lastFrameTime; + + protected override void Update() + { + base.Update(); + + if (!IsHovered) + return; + + if (lastFrameTime != null) + { + float movementAmount = (float)(Clock.CurrentTime - lastFrameTime); + + foreach (var key in inputManager.CurrentState.Keyboard.Keys) + { + switch (key) + { + case Key.Up: + box.Y -= movementAmount; + break; + + case Key.Down: + box.Y += movementAmount; + break; + + case Key.Left: + box.X -= movementAmount; + break; + + case Key.Right: + box.X += movementAmount; + break; + } + } + } + + lastFrameTime = Clock.CurrentTime; + } + } + + public class LatencyCursorContainer : CompositeDrawable + { + private readonly Circle cursor; + private InputManager inputManager = null!; + + public LatencyCursorContainer() + { + Masking = true; + + InternalChild = cursor = new Circle + { + Size = new Vector2(40), + Origin = Anchor.Centre, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + } + + protected override bool OnHover(HoverEvent e) => false; + + protected override void Update() + { + if (IsHovered) + { + cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position); + cursor.Alpha = 1; + } + else + { + cursor.Alpha = 0; + } + + base.Update(); + } + } + } + } +} From 0adeccbf03fa872b0d937f4a0ce3142324809ede Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 14:40:21 +0900 Subject: [PATCH 02/32] Add full latency testing flow --- .../Settings/TestSceneLatencyComparer.cs | 242 ----------- osu.Game/Screens/LatencyComparerScreen.cs | 385 ++++++++++++++++++ 2 files changed, 385 insertions(+), 242 deletions(-) create mode 100644 osu.Game/Screens/LatencyComparerScreen.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs index cf9a01f0b1..8a5db7bd95 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs @@ -4,18 +4,7 @@ #nullable enable using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Configuration; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; -using osu.Framework.Input.Events; -using osu.Framework.Screens; using osu.Game.Screens; -using osuTK; -using osuTK.Graphics; -using osuTK.Input; namespace osu.Game.Tests.Visual.Settings { @@ -27,235 +16,4 @@ namespace osu.Game.Tests.Visual.Settings AddStep("Load screen", () => LoadScreen(new LatencyComparerScreen())); } } - - public class LatencyComparerScreen : OsuScreen - { - private FrameSync previousFrameSyncMode; - - public override bool HideOverlaysOnEnter => true; - - public override bool CursorVisible => false; - - [Resolved] - private FrameworkConfigManager config { get; set; } = null!; - - public LatencyComparerScreen() - { - InternalChildren = new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.Absolute, 100), - new Dimension(), - new Dimension(GridSizeMode.Absolute, 100), - }, - Content = new[] - { - new Drawable[] - { - // header content - }, - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new LatencyArea(10) - { - Width = 0.5f, - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - }, - new LatencyArea(0) - { - Width = 0.5f, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - }, - new Box - { - Colour = Color4.Black, - Width = 50, - RelativeSizeAxes = Axes.Y, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }, - } - }, - }, - new Drawable[] - { - // footer content - }, - } - } - }; - } - - public override void OnEntering(ScreenTransitionEvent e) - { - base.OnEntering(e); - - previousFrameSyncMode = config.Get(FrameworkSetting.FrameSync); - config.SetValue(FrameworkSetting.FrameSync, FrameSync.Unlimited); - // host.AllowBenchmarkUnlimitedFrames = true; - } - - public override bool OnExiting(ScreenExitEvent e) - { - // host.AllowBenchmarkUnlimitedFrames = false; - config.SetValue(FrameworkSetting.FrameSync, previousFrameSyncMode); - return base.OnExiting(e); - } - - public class LatencyArea : CompositeDrawable - { - private readonly int inducedLatency; - - public LatencyArea(int inducedLatency) - { - this.inducedLatency = inducedLatency; - RelativeSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - new Box - { - Colour = Color4.Blue, - RelativeSizeAxes = Axes.Both, - }, - new LatencyMovableBox - { - RelativeSizeAxes = Axes.Both, - }, - new LatencyCursorContainer - { - RelativeSizeAxes = Axes.Both, - } - }; - } - - private long frameCount; - - public override bool UpdateSubTree() - { - if (inducedLatency > 0 && ++frameCount % inducedLatency != 0) - return false; - - return base.UpdateSubTree(); - } - - public class LatencyMovableBox : CompositeDrawable - { - private Box box = null!; - private InputManager inputManager = null!; - - public LatencyMovableBox() - { - Masking = true; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - inputManager = GetContainingInputManager(); - - InternalChild = box = new Box - { - Size = new Vector2(40), - Position = DrawSize / 2, - Origin = Anchor.Centre, - }; - } - - protected override bool OnHover(HoverEvent e) => false; - - private double? lastFrameTime; - - protected override void Update() - { - base.Update(); - - if (!IsHovered) - return; - - if (lastFrameTime != null) - { - float movementAmount = (float)(Clock.CurrentTime - lastFrameTime); - - foreach (var key in inputManager.CurrentState.Keyboard.Keys) - { - switch (key) - { - case Key.Up: - box.Y -= movementAmount; - break; - - case Key.Down: - box.Y += movementAmount; - break; - - case Key.Left: - box.X -= movementAmount; - break; - - case Key.Right: - box.X += movementAmount; - break; - } - } - } - - lastFrameTime = Clock.CurrentTime; - } - } - - public class LatencyCursorContainer : CompositeDrawable - { - private readonly Circle cursor; - private InputManager inputManager = null!; - - public LatencyCursorContainer() - { - Masking = true; - - InternalChild = cursor = new Circle - { - Size = new Vector2(40), - Origin = Anchor.Centre, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - inputManager = GetContainingInputManager(); - } - - protected override bool OnHover(HoverEvent e) => false; - - protected override void Update() - { - if (IsHovered) - { - cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position); - cursor.Alpha = 1; - } - else - { - cursor.Alpha = 0; - } - - base.Update(); - } - } - } - } } diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs new file mode 100644 index 0000000000..b247337e4e --- /dev/null +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -0,0 +1,385 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Framework.Input.Events; +using osu.Framework.Screens; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osu.Game.Overlays.Settings; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Screens +{ + public class LatencyComparerScreen : OsuScreen + { + private FrameSync previousFrameSyncMode; + + private readonly OsuSpriteText statusText; + + public override bool HideOverlaysOnEnter => true; + + public override bool CursorVisible => false; + + public override float BackgroundParallaxAmount => 0; + + private readonly Container latencyAreaContainer; + + [Cached] + private readonly OverlayColourProvider overlayColourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); + + [Resolved] + private FrameworkConfigManager config { get; set; } = null!; + + public LatencyComparerScreen() + { + InternalChildren = new Drawable[] + { + latencyAreaContainer = new Container + { + RelativeSizeAxes = Axes.Both, + }, + // Make sure the edge between the two comparisons can't be used to ascertain latency. + new Box + { + Name = "separator", + Colour = ColourInfo.GradientHorizontal(overlayColourProvider.Background6, overlayColourProvider.Background6.Opacity(0)), + Width = 50, + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopLeft, + }, + new Box + { + Name = "separator", + Colour = ColourInfo.GradientHorizontal(overlayColourProvider.Background6.Opacity(0), overlayColourProvider.Background6), + Width = 50, + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopRight, + }, + statusText = new OsuSpriteText + { + Font = OsuFont.Default.With(size: 40), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + }; + } + + public override void OnEntering(ScreenTransitionEvent e) + { + base.OnEntering(e); + + previousFrameSyncMode = config.Get(FrameworkSetting.FrameSync); + config.SetValue(FrameworkSetting.FrameSync, FrameSync.Unlimited); + // host.AllowBenchmarkUnlimitedFrames = true; + } + + public override bool OnExiting(ScreenExitEvent e) + { + // host.AllowBenchmarkUnlimitedFrames = false; + config.SetValue(FrameworkSetting.FrameSync, previousFrameSyncMode); + return base.OnExiting(e); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + loadNextRound(); + } + + private int round; + + private const int rounds_to_complete = 10; + + private int correctCount; + + private void recordResult(bool correct) + { + if (correct) + correctCount++; + + if (round < rounds_to_complete) + loadNextRound(); + else + { + showResults(); + } + } + + private void loadNextRound() + { + round++; + statusText.Text = $"Round {round} of {rounds_to_complete}"; + + latencyAreaContainer.Clear(); + + const int induced_latency = 1; + + int betterSide = RNG.Next(0, 2); + + latencyAreaContainer.Add(new LatencyArea(betterSide == 1 ? induced_latency : 0) + { + Width = 0.5f, + ReportBetter = () => recordResult(betterSide == 0) + }); + + latencyAreaContainer.Add(new LatencyArea(betterSide == 0 ? induced_latency : 0) + { + Width = 0.5f, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + ReportBetter = () => recordResult(betterSide == 1) + }); + } + + private void showResults() + { + AddInternal(new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + Colour = overlayColourProvider.Background1, + RelativeSizeAxes = Axes.Both, + }, + + new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 40)) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + TextAnchor = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = $"You scored {correctCount} out of {rounds_to_complete} ({(float)correctCount / rounds_to_complete:P0})!" + } + } + }); + } + + public class LatencyArea : CompositeDrawable + { + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + public Action? ReportBetter { get; set; } + + private Drawable background = null!; + + private readonly int inducedLatency; + + public LatencyArea(int inducedLatency) + { + this.inducedLatency = inducedLatency; + + RelativeSizeAxes = Axes.Both; + Masking = true; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + InternalChildren = new[] + { + background = new Box + { + Colour = overlayColourProvider.Background6, + RelativeSizeAxes = Axes.Both, + }, + new LatencyMovableBox + { + RelativeSizeAxes = Axes.Both, + }, + new LatencyCursorContainer + { + RelativeSizeAxes = Axes.Both, + }, + new Button + { + Text = "Feels better", + Y = 20, + Width = 0.8f, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Action = () => ReportBetter?.Invoke(), + }, + }; + + base.LoadComplete(); + this.FadeInFromZero(500, Easing.OutQuint); + } + + public class Button : SettingsButton + { + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + Height = 50; + SpriteText.Colour = overlayColourProvider.Background6; + SpriteText.Font = OsuFont.TorusAlternate.With(size: 34); + } + } + + protected override bool OnHover(HoverEvent e) + { + background.FadeColour(overlayColourProvider.Background4, 200, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + background.FadeColour(overlayColourProvider.Background6, 200, Easing.OutQuint); + base.OnHoverLost(e); + } + + private long frameCount; + + public override bool UpdateSubTree() + { + if (inducedLatency > 0 && ++frameCount % inducedLatency != 0) + return false; + + return base.UpdateSubTree(); + } + + public class LatencyMovableBox : CompositeDrawable + { + private Box box = null!; + private InputManager inputManager = null!; + + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + + InternalChild = box = new Box + { + Size = new Vector2(40), + RelativePositionAxes = Axes.Both, + Position = new Vector2(0.5f), + Origin = Anchor.Centre, + Colour = overlayColourProvider.Colour1, + }; + } + + protected override bool OnHover(HoverEvent e) => false; + + private double? lastFrameTime; + + protected override void Update() + { + base.Update(); + + if (!IsHovered) + { + lastFrameTime = null; + return; + } + + if (lastFrameTime != null) + { + float movementAmount = (float)(Clock.CurrentTime - lastFrameTime) / 400; + + foreach (var key in inputManager.CurrentState.Keyboard.Keys) + { + switch (key) + { + case Key.Up: + box.Y = MathHelper.Clamp(box.Y - movementAmount, 0.1f, 0.9f); + break; + + case Key.Down: + box.Y = MathHelper.Clamp(box.Y + movementAmount, 0.1f, 0.9f); + break; + + case Key.Z: + case Key.Left: + box.X = MathHelper.Clamp(box.X - movementAmount, 0.1f, 0.9f); + break; + + case Key.X: + case Key.Right: + box.X = MathHelper.Clamp(box.X + movementAmount, 0.1f, 0.9f); + break; + } + } + } + + lastFrameTime = Clock.CurrentTime; + } + } + + public class LatencyCursorContainer : CompositeDrawable + { + private Circle cursor = null!; + private InputManager inputManager = null!; + + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + public LatencyCursorContainer() + { + Masking = true; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + InternalChild = cursor = new Circle + { + Size = new Vector2(40), + Origin = Anchor.Centre, + Colour = overlayColourProvider.Colour2, + }; + + inputManager = GetContainingInputManager(); + } + + protected override bool OnHover(HoverEvent e) => false; + + protected override void Update() + { + if (IsHovered) + { + cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position); + cursor.Alpha = 1; + } + else + { + cursor.Alpha = 0; + } + + base.Update(); + } + } + } + } +} From 20cfa5d83fbe783e3f0520c216c871ccc27d17c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 14:40:28 +0900 Subject: [PATCH 03/32] Add button to access latency comparer from game --- .../Sections/DebugSettings/GeneralSettings.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs index 8833420523..318cdbd6a7 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs @@ -30,13 +30,18 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings { LabelText = DebugSettingsStrings.BypassFrontToBackPass, Current = config.GetBindable(DebugSetting.BypassFrontToBackPass) + }, + new SettingsButton + { + Text = DebugSettingsStrings.ImportFiles, + Action = () => performer?.PerformFromScreen(menu => menu.Push(new FileImportScreen())) + }, + new SettingsButton + { + Text = @"Run latency comparer", + Action = () => performer?.PerformFromScreen(menu => menu.Push(new LatencyComparerScreen())) } }; - Add(new SettingsButton - { - Text = DebugSettingsStrings.ImportFiles, - Action = () => performer?.PerformFromScreen(menu => menu.Push(new FileImportScreen())) - }); } } } From c323c67d7d20da709af17d690d4abe52a17edb0b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 14:51:16 +0900 Subject: [PATCH 04/32] Allow increasing confidence by playing longer --- osu.Game/Screens/LatencyComparerScreen.cs | 123 ++++++++++++++-------- 1 file changed, 80 insertions(+), 43 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index b247337e4e..c39760e5be 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens { private FrameSync previousFrameSyncMode; - private readonly OsuSpriteText statusText; + private readonly OsuTextFlowContainer statusText; public override bool HideOverlaysOnEnter => true; @@ -37,7 +37,9 @@ namespace osu.Game.Screens public override float BackgroundParallaxAmount => 0; - private readonly Container latencyAreaContainer; + private readonly Container mainArea; + + private readonly Container resultsArea; [Cached] private readonly OverlayColourProvider overlayColourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); @@ -49,7 +51,12 @@ namespace osu.Game.Screens { InternalChildren = new Drawable[] { - latencyAreaContainer = new Container + new Box + { + Colour = overlayColourProvider.Background6, + RelativeSizeAxes = Axes.Both, + }, + mainArea = new Container { RelativeSizeAxes = Axes.Both, }, @@ -72,11 +79,17 @@ namespace osu.Game.Screens Anchor = Anchor.TopCentre, Origin = Anchor.TopRight, }, - statusText = new OsuSpriteText + statusText = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 40)) { - Font = OsuFont.Default.With(size: 40), Anchor = Anchor.Centre, Origin = Anchor.Centre, + TextAnchor = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + resultsArea = new Container + { + RelativeSizeAxes = Axes.Both, }, }; } @@ -109,13 +122,14 @@ namespace osu.Game.Screens private const int rounds_to_complete = 10; private int correctCount; + private int targetRoundCount = rounds_to_complete; private void recordResult(bool correct) { if (correct) correctCount++; - if (round < rounds_to_complete) + if (round < targetRoundCount) loadNextRound(); else { @@ -126,21 +140,21 @@ namespace osu.Game.Screens private void loadNextRound() { round++; - statusText.Text = $"Round {round} of {rounds_to_complete}"; + statusText.Text = $"Round {round} of {targetRoundCount}"; - latencyAreaContainer.Clear(); + mainArea.Clear(); const int induced_latency = 1; int betterSide = RNG.Next(0, 2); - latencyAreaContainer.Add(new LatencyArea(betterSide == 1 ? induced_latency : 0) + mainArea.Add(new LatencyArea(betterSide == 1 ? induced_latency : 0) { Width = 0.5f, ReportBetter = () => recordResult(betterSide == 0) }); - latencyAreaContainer.Add(new LatencyArea(betterSide == 0 ? induced_latency : 0) + mainArea.Add(new LatencyArea(betterSide == 0 ? induced_latency : 0) { Width = 0.5f, Anchor = Anchor.TopRight, @@ -151,25 +165,27 @@ namespace osu.Game.Screens private void showResults() { - AddInternal(new Container + mainArea.Clear(); + + statusText.Text = $"You scored {correctCount} out of {targetRoundCount} ({(float)correctCount / targetRoundCount:P0})!"; + + resultsArea.Add(new Container { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new Box - { - Colour = overlayColourProvider.Background1, - RelativeSizeAxes = Axes.Both, - }, - - new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 40)) + new Button { + Text = "Increase confidence", Anchor = Anchor.Centre, Origin = Anchor.Centre, - TextAnchor = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Text = $"You scored {correctCount} out of {rounds_to_complete} ({(float)correctCount / rounds_to_complete:P0})!" + Y = 100, + Action = () => + { + resultsArea.Clear(); + targetRoundCount += rounds_to_complete; + loadNextRound(); + } } } }); @@ -186,6 +202,12 @@ namespace osu.Game.Screens private readonly int inducedLatency; + private Container interactivePieces = null!; + + private Button button = null!; + + private long frameCount; + public LatencyArea(int inducedLatency) { this.inducedLatency = inducedLatency; @@ -205,17 +227,26 @@ namespace osu.Game.Screens Colour = overlayColourProvider.Background6, RelativeSizeAxes = Axes.Both, }, - new LatencyMovableBox + interactivePieces = new Container { RelativeSizeAxes = Axes.Both, + Alpha = 0, + Children = new Drawable[] + { + new LatencyMovableBox + { + RelativeSizeAxes = Axes.Both, + }, + new LatencyCursorContainer + { + RelativeSizeAxes = Axes.Both, + }, + } }, - new LatencyCursorContainer - { - RelativeSizeAxes = Axes.Both, - }, - new Button + button = new Button { Text = "Feels better", + Alpha = 0, Y = 20, Width = 0.8f, Anchor = Anchor.TopCentre, @@ -226,20 +257,11 @@ namespace osu.Game.Screens base.LoadComplete(); this.FadeInFromZero(500, Easing.OutQuint); - } - public class Button : SettingsButton - { - [Resolved] - private OverlayColourProvider overlayColourProvider { get; set; } = null!; - - protected override void LoadComplete() + using (BeginDelayedSequence(500)) { - base.LoadComplete(); - - Height = 50; - SpriteText.Colour = overlayColourProvider.Background6; - SpriteText.Font = OsuFont.TorusAlternate.With(size: 34); + interactivePieces.FadeIn(500, Easing.OutQuint); + button.FadeIn(500, Easing.OutQuint); } } @@ -255,11 +277,9 @@ namespace osu.Game.Screens base.OnHoverLost(e); } - private long frameCount; - public override bool UpdateSubTree() { - if (inducedLatency > 0 && ++frameCount % inducedLatency != 0) + if (background?.Alpha == 1 && inducedLatency > 0 && ++frameCount % inducedLatency != 0) return false; return base.UpdateSubTree(); @@ -367,6 +387,8 @@ namespace osu.Game.Screens protected override void Update() { + cursor.Colour = inputManager.CurrentState.Mouse.IsPressed(MouseButton.Left) ? overlayColourProvider.Content1 : overlayColourProvider.Colour2; + if (IsHovered) { cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position); @@ -381,5 +403,20 @@ namespace osu.Game.Screens } } } + + public class Button : SettingsButton + { + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + Height = 100; + SpriteText.Colour = overlayColourProvider.Background6; + SpriteText.Font = OsuFont.TorusAlternate.With(size: 34); + } + } } } From 3bd8bbd297b623bc53e1b974afa2067ba92e4005 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 15:21:19 +0900 Subject: [PATCH 05/32] Add explanatory text --- osu.Game/Screens/LatencyComparerScreen.cs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index c39760e5be..75bf7795ce 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -17,7 +17,6 @@ using osu.Framework.Screens; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Overlays.Settings; using osuTK; @@ -37,6 +36,8 @@ namespace osu.Game.Screens public override float BackgroundParallaxAmount => 0; + private readonly OsuTextFlowContainer explanatoryText; + private readonly Container mainArea; private readonly Container resultsArea; @@ -79,6 +80,20 @@ namespace osu.Game.Screens Anchor = Anchor.TopCentre, Origin = Anchor.TopRight, }, + explanatoryText = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 20)) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + TextAnchor = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Y = 200, + Text = @"Welcome to the latency comparer! +Use the arrow keys or Z/X to move the square. +You can click the targets but you don't have to. +Do whatever you need to try and perceive the difference in latency, then choose your best side. +", + }, statusText = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 40)) { Anchor = Anchor.Centre, @@ -126,6 +141,8 @@ namespace osu.Game.Screens private void recordResult(bool correct) { + explanatoryText.FadeOut(500, Easing.OutQuint); + if (correct) correctCount++; @@ -198,7 +215,7 @@ namespace osu.Game.Screens public Action? ReportBetter { get; set; } - private Drawable background = null!; + private Drawable? background; private readonly int inducedLatency; From a175defefd3bc40d98d916de5608da9b656742fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 18:11:54 +0900 Subject: [PATCH 06/32] Add difficulty levels --- osu.Game/Screens/LatencyComparerScreen.cs | 110 ++++++++++++++-------- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index 75bf7795ce..689729fa68 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -4,6 +4,7 @@ #nullable enable using System; +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; @@ -45,9 +46,20 @@ namespace osu.Game.Screens [Cached] private readonly OverlayColourProvider overlayColourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); + [Resolved] + private OsuColour colours { get; set; } = null!; + [Resolved] private FrameworkConfigManager config { get; set; } = null!; + private const int rounds_to_complete = 5; + + private int round; + private int correctCount; + private int targetRoundCount = rounds_to_complete; + + private int difficulty = 1; + public LatencyComparerScreen() { InternalChildren = new Drawable[] @@ -82,12 +94,11 @@ namespace osu.Game.Screens }, explanatoryText = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 20)) { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, TextAnchor = Anchor.TopCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Y = 200, Text = @"Welcome to the latency comparer! Use the arrow keys or Z/X to move the square. You can click the targets but you don't have to. @@ -96,9 +107,10 @@ Do whatever you need to try and perceive the difference in latency, then choose }, statusText = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 40)) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, TextAnchor = Anchor.TopCentre, + Y = 200, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, @@ -132,13 +144,6 @@ Do whatever you need to try and perceive the difference in latency, then choose loadNextRound(); } - private int round; - - private const int rounds_to_complete = 10; - - private int correctCount; - private int targetRoundCount = rounds_to_complete; - private void recordResult(bool correct) { explanatoryText.FadeOut(500, Easing.OutQuint); @@ -157,21 +162,21 @@ Do whatever you need to try and perceive the difference in latency, then choose private void loadNextRound() { round++; - statusText.Text = $"Round {round} of {targetRoundCount}"; + statusText.Text = $"Difficulty {difficulty}\nRound {round} of {targetRoundCount}"; mainArea.Clear(); - const int induced_latency = 1; + const int induced_latency = 500; int betterSide = RNG.Next(0, 2); - mainArea.Add(new LatencyArea(betterSide == 1 ? induced_latency : 0) + mainArea.Add(new LatencyArea(betterSide == 1 ? induced_latency / difficulty : 0) { Width = 0.5f, ReportBetter = () => recordResult(betterSide == 0) }); - mainArea.Add(new LatencyArea(betterSide == 0 ? induced_latency : 0) + mainArea.Add(new LatencyArea(betterSide == 0 ? induced_latency / difficulty : 0) { Width = 0.5f, Anchor = Anchor.TopRight, @@ -186,28 +191,70 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.Text = $"You scored {correctCount} out of {targetRoundCount} ({(float)correctCount / targetRoundCount:P0})!"; - resultsArea.Add(new Container + resultsArea.Add(new FillFlowContainer { RelativeSizeAxes = Axes.Both, + Y = 100, + Spacing = new Vector2(20), Children = new Drawable[] { new Button { - Text = "Increase confidence", + Text = "Increase confidence at current level", Anchor = Anchor.Centre, Origin = Anchor.Centre, - Y = 100, Action = () => { resultsArea.Clear(); targetRoundCount += rounds_to_complete; loadNextRound(); } + }, + new Button + { + Text = "Increase difficulty", + BackgroundColour = colours.Red2, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Action = () => + { + changeDifficulty(difficulty + 1); + } + }, + new Button + { + Text = "Decrease difficulty", + BackgroundColour = colours.Green, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Enabled = { Value = difficulty > 1 }, + Action = () => + { + resultsArea.Clear(); + correctCount = 0; + targetRoundCount = rounds_to_complete; + difficulty--; + loadNextRound(); + } } } }); } + private void changeDifficulty(int diff) + { + Debug.Assert(diff > 0); + + resultsArea.Clear(); + + correctCount = 0; + round = 0; + + targetRoundCount = rounds_to_complete; + difficulty = diff; + loadNextRound(); + } + public class LatencyArea : CompositeDrawable { [Resolved] @@ -219,10 +266,6 @@ Do whatever you need to try and perceive the difference in latency, then choose private readonly int inducedLatency; - private Container interactivePieces = null!; - - private Button button = null!; - private long frameCount; public LatencyArea(int inducedLatency) @@ -244,10 +287,9 @@ Do whatever you need to try and perceive the difference in latency, then choose Colour = overlayColourProvider.Background6, RelativeSizeAxes = Axes.Both, }, - interactivePieces = new Container + new Container { RelativeSizeAxes = Axes.Both, - Alpha = 0, Children = new Drawable[] { new LatencyMovableBox @@ -260,10 +302,9 @@ Do whatever you need to try and perceive the difference in latency, then choose }, } }, - button = new Button + new Button { Text = "Feels better", - Alpha = 0, Y = 20, Width = 0.8f, Anchor = Anchor.TopCentre, @@ -271,15 +312,6 @@ Do whatever you need to try and perceive the difference in latency, then choose Action = () => ReportBetter?.Invoke(), }, }; - - base.LoadComplete(); - this.FadeInFromZero(500, Easing.OutQuint); - - using (BeginDelayedSequence(500)) - { - interactivePieces.FadeIn(500, Easing.OutQuint); - button.FadeIn(500, Easing.OutQuint); - } } protected override bool OnHover(HoverEvent e) @@ -344,7 +376,11 @@ Do whatever you need to try and perceive the difference in latency, then choose { float movementAmount = (float)(Clock.CurrentTime - lastFrameTime) / 400; - foreach (var key in inputManager.CurrentState.Keyboard.Keys) + var buttons = inputManager.CurrentState.Keyboard.Keys; + + box.Colour = buttons.HasAnyButtonPressed ? overlayColourProvider.Content1 : overlayColourProvider.Colour1; + + foreach (var key in buttons) { switch (key) { From 3fc8ac0ec72f51c47dab588acbea8679f66b90bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 18:27:42 +0900 Subject: [PATCH 07/32] Add key bindings everywhere --- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- osu.Game/Screens/LatencyComparerScreen.cs | 56 +++++++++++++------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 08514d94c3..044df13152 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface /// public class OsuButton : Button { - public LocalisableString Text + public virtual LocalisableString Text { get => SpriteText?.Text ?? default; set diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index 689729fa68..b61905a1e7 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -14,8 +14,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Framework.Utils; +using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Overlays; @@ -170,13 +172,13 @@ Do whatever you need to try and perceive the difference in latency, then choose int betterSide = RNG.Next(0, 2); - mainArea.Add(new LatencyArea(betterSide == 1 ? induced_latency / difficulty : 0) + mainArea.Add(new LatencyArea(Key.Number1, betterSide == 1 ? induced_latency / difficulty : 0) { Width = 0.5f, ReportBetter = () => recordResult(betterSide == 0) }); - mainArea.Add(new LatencyArea(betterSide == 0 ? induced_latency / difficulty : 0) + mainArea.Add(new LatencyArea(Key.Number2, betterSide == 0 ? induced_latency / difficulty : 0) { Width = 0.5f, Anchor = Anchor.TopRight, @@ -198,7 +200,7 @@ Do whatever you need to try and perceive the difference in latency, then choose Spacing = new Vector2(20), Children = new Drawable[] { - new Button + new Button(Key.R) { Text = "Increase confidence at current level", Anchor = Anchor.Centre, @@ -210,32 +212,22 @@ Do whatever you need to try and perceive the difference in latency, then choose loadNextRound(); } }, - new Button + new Button(Key.I) { Text = "Increase difficulty", BackgroundColour = colours.Red2, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Action = () => - { - changeDifficulty(difficulty + 1); - } + Action = () => changeDifficulty(difficulty + 1) }, - new Button + new Button(Key.D) { Text = "Decrease difficulty", BackgroundColour = colours.Green, Anchor = Anchor.Centre, Origin = Anchor.Centre, + Action = () => changeDifficulty(difficulty - 1), Enabled = { Value = difficulty > 1 }, - Action = () => - { - resultsArea.Clear(); - correctCount = 0; - targetRoundCount = rounds_to_complete; - difficulty--; - loadNextRound(); - } } } }); @@ -264,12 +256,14 @@ Do whatever you need to try and perceive the difference in latency, then choose private Drawable? background; + private readonly Key key; private readonly int inducedLatency; private long frameCount; - public LatencyArea(int inducedLatency) + public LatencyArea(Key key, int inducedLatency) { + this.key = key; this.inducedLatency = inducedLatency; RelativeSizeAxes = Axes.Both; @@ -302,7 +296,7 @@ Do whatever you need to try and perceive the difference in latency, then choose }, } }, - new Button + new Button(key) { Text = "Feels better", Y = 20, @@ -459,6 +453,30 @@ Do whatever you need to try and perceive the difference in latency, then choose public class Button : SettingsButton { + private readonly Key key; + + public Button(Key key) + { + this.key = key; + } + + public override LocalisableString Text + { + get => base.Text; + set => base.Text = $"{value} (Press {key.ToString().Replace("Number", string.Empty)})"; + } + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (!e.Repeat && e.Key == key) + { + TriggerClick(); + return true; + } + + return base.OnKeyDown(e); + } + [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } = null!; From c0e88d957730239a3a7ad6c24bbecaf1e43a0432 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 19:03:26 +0900 Subject: [PATCH 08/32] Add better messaging and pass/fail cutoff --- osu.Game/Screens/LatencyComparerScreen.cs | 89 +++++++++++++++++++++-- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index b61905a1e7..31d2a56770 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -15,9 +15,10 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Framework.Platform; +using osu.Framework.Platform.Windows; using osu.Framework.Screens; using osu.Framework.Utils; -using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Overlays; @@ -30,6 +31,7 @@ namespace osu.Game.Screens public class LatencyComparerScreen : OsuScreen { private FrameSync previousFrameSyncMode; + private double previousActiveHz; private readonly OsuTextFlowContainer statusText; @@ -45,6 +47,11 @@ namespace osu.Game.Screens private readonly Container resultsArea; + /// + /// The rate at which the game host should attempt to run. + /// + private const int target_host_update_frames = 4000; + [Cached] private readonly OverlayColourProvider overlayColourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); @@ -62,6 +69,9 @@ namespace osu.Game.Screens private int difficulty = 1; + [Resolved] + private GameHost host { get; set; } = null!; + public LatencyComparerScreen() { InternalChildren = new Drawable[] @@ -128,7 +138,9 @@ Do whatever you need to try and perceive the difference in latency, then choose base.OnEntering(e); previousFrameSyncMode = config.Get(FrameworkSetting.FrameSync); + previousActiveHz = host.UpdateThread.ActiveHz; config.SetValue(FrameworkSetting.FrameSync, FrameSync.Unlimited); + host.UpdateThread.ActiveHz = target_host_update_frames; // host.AllowBenchmarkUnlimitedFrames = true; } @@ -136,6 +148,7 @@ Do whatever you need to try and perceive the difference in latency, then choose { // host.AllowBenchmarkUnlimitedFrames = false; config.SetValue(FrameworkSetting.FrameSync, previousFrameSyncMode); + host.UpdateThread.ActiveHz = previousActiveHz; return base.OnExiting(e); } @@ -191,7 +204,33 @@ Do whatever you need to try and perceive the difference in latency, then choose { mainArea.Clear(); - statusText.Text = $"You scored {correctCount} out of {targetRoundCount} ({(float)correctCount / targetRoundCount:P0})!"; + var displayMode = host.Window.CurrentDisplayMode.Value; + + string exclusive = "unknown"; + + if (host.Window is WindowsWindow windowsWindow) + exclusive = windowsWindow.FullscreenCapability.ToString(); + + statusText.Clear(); + + float successRate = (float)correctCount / targetRoundCount; + bool isPass = successRate > 0.8f; + + statusText.AddParagraph($"You scored {correctCount} out of {targetRoundCount} ({successRate:P0})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); + + statusText.AddParagraph($"Level {difficulty} (comparing {host.UpdateThread.Clock.FramesPerSecond:N0}hz and {mapDifficultyToTargetFrameRate(difficulty):N0}hz)", + cp => cp.Font = OsuFont.Default.With(size: 15)); + + statusText.AddParagraph($"Refresh rate: {displayMode.RefreshRate:N0} ExclusiveFullscren: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); + + string cannotIncreaseReason = string.Empty; + + if (!isPass) + cannotIncreaseReason = "You didn't score high enough (over 80% required)!"; + else if (mapDifficultyToTargetFrameRate(difficulty + 1) > target_host_update_frames) + cannotIncreaseReason = "You've reached the limits of this comparison mode."; + else if (mapDifficultyToTargetFrameRate(difficulty + 1) < host.UpdateThread.ActiveHz) + cannotIncreaseReason = "Game is not running fast enough to test this level"; resultsArea.Add(new FillFlowContainer { @@ -205,6 +244,7 @@ Do whatever you need to try and perceive the difference in latency, then choose Text = "Increase confidence at current level", Anchor = Anchor.Centre, Origin = Anchor.Centre, + TooltipText = "The longer you chain, the more sure you will be!", Action = () => { resultsArea.Clear(); @@ -218,16 +258,17 @@ Do whatever you need to try and perceive the difference in latency, then choose BackgroundColour = colours.Red2, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Action = () => changeDifficulty(difficulty + 1) + Action = () => changeDifficulty(difficulty + 1), + Enabled = { Value = string.IsNullOrEmpty(cannotIncreaseReason) }, + TooltipText = cannotIncreaseReason }, new Button(Key.D) { - Text = "Decrease difficulty", + Text = difficulty == 1 ? "Restart" : "Decrease difficulty", BackgroundColour = colours.Green, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Action = () => changeDifficulty(difficulty - 1), - Enabled = { Value = difficulty > 1 }, + Action = () => changeDifficulty(Math.Max(difficulty - 1, 1)), } } }); @@ -247,6 +288,42 @@ Do whatever you need to try and perceive the difference in latency, then choose loadNextRound(); } + private static int mapDifficultyToTargetFrameRate(int difficulty) + { + switch (difficulty) + { + case 1: + return 15; + + case 2: + return 30; + + case 3: + return 45; + + case 4: + return 60; + + case 5: + return 120; + + case 6: + return 240; + + case 7: + return 480; + + case 8: + return 720; + + case 9: + return 960; + + default: + return 1000 + ((difficulty - 10) * 500); + } + } + public class LatencyArea : CompositeDrawable { [Resolved] From 2e7a96621896904db8976b75575ed6700b9a05c3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 19:31:56 +0900 Subject: [PATCH 09/32] Add proper frame rate limiting and fix mouse cursor missing at results --- osu.Game/Screens/LatencyComparerScreen.cs | 50 ++++++++++++----------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index 31d2a56770..405b13cfc1 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -37,7 +37,7 @@ namespace osu.Game.Screens public override bool HideOverlaysOnEnter => true; - public override bool CursorVisible => false; + public override bool CursorVisible => mainArea.Count == 0; public override float BackgroundParallaxAmount => 0; @@ -181,17 +181,15 @@ Do whatever you need to try and perceive the difference in latency, then choose mainArea.Clear(); - const int induced_latency = 500; - int betterSide = RNG.Next(0, 2); - mainArea.Add(new LatencyArea(Key.Number1, betterSide == 1 ? induced_latency / difficulty : 0) + mainArea.Add(new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(difficulty) : 0) { Width = 0.5f, ReportBetter = () => recordResult(betterSide == 0) }); - mainArea.Add(new LatencyArea(Key.Number2, betterSide == 0 ? induced_latency / difficulty : 0) + mainArea.Add(new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(difficulty) : 0) { Width = 0.5f, Anchor = Anchor.TopRight, @@ -218,7 +216,7 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.AddParagraph($"You scored {correctCount} out of {targetRoundCount} ({successRate:P0})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); - statusText.AddParagraph($"Level {difficulty} (comparing {host.UpdateThread.Clock.FramesPerSecond:N0}hz and {mapDifficultyToTargetFrameRate(difficulty):N0}hz)", + statusText.AddParagraph($"Level {difficulty} (comparing {mapDifficultyToTargetFrameRate(difficulty):N0}hz with {host.UpdateThread.Clock.FramesPerSecond:N0}hz)", cp => cp.Font = OsuFont.Default.With(size: 15)); statusText.AddParagraph($"Refresh rate: {displayMode.RefreshRate:N0} ExclusiveFullscren: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); @@ -229,7 +227,7 @@ Do whatever you need to try and perceive the difference in latency, then choose cannotIncreaseReason = "You didn't score high enough (over 80% required)!"; else if (mapDifficultyToTargetFrameRate(difficulty + 1) > target_host_update_frames) cannotIncreaseReason = "You've reached the limits of this comparison mode."; - else if (mapDifficultyToTargetFrameRate(difficulty + 1) < host.UpdateThread.ActiveHz) + else if (mapDifficultyToTargetFrameRate(difficulty + 1) > Clock.FramesPerSecond) cannotIncreaseReason = "Game is not running fast enough to test this level"; resultsArea.Add(new FillFlowContainer @@ -244,13 +242,14 @@ Do whatever you need to try and perceive the difference in latency, then choose Text = "Increase confidence at current level", Anchor = Anchor.Centre, Origin = Anchor.Centre, - TooltipText = "The longer you chain, the more sure you will be!", Action = () => { resultsArea.Clear(); targetRoundCount += rounds_to_complete; loadNextRound(); - } + }, + TooltipText = isPass ? "The longer you chain, the more sure you will be!" : "You've reached your limits", + Enabled = { Value = string.IsNullOrEmpty(cannotIncreaseReason) }, }, new Button(Key.I) { @@ -334,14 +333,12 @@ Do whatever you need to try and perceive the difference in latency, then choose private Drawable? background; private readonly Key key; - private readonly int inducedLatency; + private readonly int targetFrameRate; - private long frameCount; - - public LatencyArea(Key key, int inducedLatency) + public LatencyArea(Key key, int targetFrameRate) { this.key = key; - this.inducedLatency = inducedLatency; + this.targetFrameRate = targetFrameRate; RelativeSizeAxes = Axes.Both; Masking = true; @@ -358,6 +355,15 @@ Do whatever you need to try and perceive the difference in latency, then choose Colour = overlayColourProvider.Background6, RelativeSizeAxes = Axes.Both, }, + new Button(key) + { + Text = "Feels better", + Y = 20, + Width = 0.8f, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Action = () => ReportBetter?.Invoke(), + }, new Container { RelativeSizeAxes = Axes.Both, @@ -373,15 +379,6 @@ Do whatever you need to try and perceive the difference in latency, then choose }, } }, - new Button(key) - { - Text = "Feels better", - Y = 20, - Width = 0.8f, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Action = () => ReportBetter?.Invoke(), - }, }; } @@ -397,11 +394,16 @@ Do whatever you need to try and perceive the difference in latency, then choose base.OnHoverLost(e); } + private double lastFrameTime; + public override bool UpdateSubTree() { - if (background?.Alpha == 1 && inducedLatency > 0 && ++frameCount % inducedLatency != 0) + double elapsed = Clock.CurrentTime - lastFrameTime; + if (targetFrameRate > 0 && elapsed < 1000.0 / targetFrameRate) return false; + lastFrameTime = Clock.CurrentTime; + return base.UpdateSubTree(); } From 43a04010a784c3284a15a1c38afc0a0266b2fc5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 19:43:33 +0900 Subject: [PATCH 10/32] Add display of polling rate --- osu.Game/Screens/LatencyComparerScreen.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index 405b13cfc1..ba3355110d 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -69,6 +69,9 @@ namespace osu.Game.Screens private int difficulty = 1; + private double lastPoll; + private int pollingMax; + [Resolved] private GameHost host { get; set; } = null!; @@ -133,6 +136,14 @@ Do whatever you need to try and perceive the difference in latency, then choose }; } + protected override bool OnMouseMove(MouseMoveEvent e) + { + if (lastPoll > 0) + pollingMax = (int)Math.Max(pollingMax, 1000 / (Clock.CurrentTime - lastPoll)); + lastPoll = Clock.CurrentTime; + return base.OnMouseMove(e); + } + public override void OnEntering(ScreenTransitionEvent e) { base.OnEntering(e); @@ -217,9 +228,9 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.AddParagraph($"You scored {correctCount} out of {targetRoundCount} ({successRate:P0})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); statusText.AddParagraph($"Level {difficulty} (comparing {mapDifficultyToTargetFrameRate(difficulty):N0}hz with {host.UpdateThread.Clock.FramesPerSecond:N0}hz)", - cp => cp.Font = OsuFont.Default.With(size: 15)); + cp => cp.Font = OsuFont.Default.With(size: 24)); - statusText.AddParagraph($"Refresh rate: {displayMode.RefreshRate:N0} ExclusiveFullscren: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); + statusText.AddParagraph($"Input: {pollingMax}hz Monitor: {displayMode.RefreshRate:N0}hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); string cannotIncreaseReason = string.Empty; @@ -281,6 +292,8 @@ Do whatever you need to try and perceive the difference in latency, then choose correctCount = 0; round = 0; + pollingMax = 0; + lastPoll = 0; targetRoundCount = rounds_to_complete; difficulty = diff; From 146225d87eca2222979b892d01074643c2c5b00d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 20:02:26 +0900 Subject: [PATCH 11/32] Fix multiple issues with layout and text --- osu.Game/Screens/LatencyComparerScreen.cs | 27 +++++++++++++++++------ 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index ba3355110d..0af0ab8419 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Localisation; @@ -125,7 +126,7 @@ Do whatever you need to try and perceive the difference in latency, then choose Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, TextAnchor = Anchor.TopCentre, - Y = 200, + Y = 150, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, @@ -225,12 +226,21 @@ Do whatever you need to try and perceive the difference in latency, then choose float successRate = (float)correctCount / targetRoundCount; bool isPass = successRate > 0.8f; - statusText.AddParagraph($"You scored {correctCount} out of {targetRoundCount} ({successRate:P0})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); - - statusText.AddParagraph($"Level {difficulty} (comparing {mapDifficultyToTargetFrameRate(difficulty):N0}hz with {host.UpdateThread.Clock.FramesPerSecond:N0}hz)", + statusText.AddParagraph($"You scored {correctCount} out of {targetRoundCount} ({successRate:0%})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); + statusText.AddParagraph($"Level {difficulty} ({mapDifficultyToTargetFrameRate(difficulty):N0} hz)", cp => cp.Font = OsuFont.Default.With(size: 24)); - statusText.AddParagraph($"Input: {pollingMax}hz Monitor: {displayMode.RefreshRate:N0}hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); + statusText.AddParagraph(string.Empty); + statusText.AddParagraph(string.Empty); + statusText.AddIcon(isPass ? FontAwesome.Regular.CheckCircle : FontAwesome.Regular.TimesCircle, cp => cp.Colour = isPass ? colours.Green : colours.Red); + statusText.AddParagraph(string.Empty); + + statusText.AddParagraph($"Polling: {pollingMax} hz Monitor: {displayMode.RefreshRate:N0} hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); + + statusText.AddParagraph($"Input: {host.InputThread.Clock.FramesPerSecond} hz " + + $"Update: {host.UpdateThread.Clock.FramesPerSecond} hz " + + $"Draw: {host.DrawThread.Clock.FramesPerSecond} hz" + , cp => cp.Font = OsuFont.Default.With(size: 15)); string cannotIncreaseReason = string.Empty; @@ -243,9 +253,12 @@ Do whatever you need to try and perceive the difference in latency, then choose resultsArea.Add(new FillFlowContainer { - RelativeSizeAxes = Axes.Both, - Y = 100, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, Spacing = new Vector2(20), + Padding = new MarginPadding(20), Children = new Drawable[] { new Button(Key.R) From 00a6cbe53f623fc4e1cc058e305ba526895a7813 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 20:03:49 +0900 Subject: [PATCH 12/32] Allow using J/K to move box as well --- osu.Game/Screens/LatencyComparerScreen.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index 0af0ab8419..3cbce0e995 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -116,7 +116,7 @@ namespace osu.Game.Screens RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Text = @"Welcome to the latency comparer! -Use the arrow keys or Z/X to move the square. +Use the arrow keys, Z/X/J/K to move the square. You can click the targets but you don't have to. Do whatever you need to try and perceive the difference in latency, then choose your best side. ", @@ -483,10 +483,12 @@ Do whatever you need to try and perceive the difference in latency, then choose { switch (key) { + case Key.K: case Key.Up: box.Y = MathHelper.Clamp(box.Y - movementAmount, 0.1f, 0.9f); break; + case Key.J: case Key.Down: box.Y = MathHelper.Clamp(box.Y + movementAmount, 0.1f, 0.9f); break; From 60d7060baa9737fc05267b7790aec6c7c1f083cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 20:28:42 +0900 Subject: [PATCH 13/32] Add tab focus support --- osu.Game/Screens/LatencyComparerScreen.cs | 68 ++++++++++++++++++----- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index 3cbce0e995..6758908c3e 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -5,7 +5,9 @@ using System; using System.Diagnostics; +using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -44,7 +46,7 @@ namespace osu.Game.Screens private readonly OsuTextFlowContainer explanatoryText; - private readonly Container mainArea; + private readonly Container mainArea; private readonly Container resultsArea; @@ -85,7 +87,7 @@ namespace osu.Game.Screens Colour = overlayColourProvider.Background6, RelativeSizeAxes = Axes.Both, }, - mainArea = new Container + mainArea = new Container { RelativeSizeAxes = Axes.Both, }, @@ -118,6 +120,7 @@ namespace osu.Game.Screens Text = @"Welcome to the latency comparer! Use the arrow keys, Z/X/J/K to move the square. You can click the targets but you don't have to. +Use the Tab key to change focus. Do whatever you need to try and perceive the difference in latency, then choose your best side. ", }, @@ -171,6 +174,20 @@ Do whatever you need to try and perceive the difference in latency, then choose loadNextRound(); } + protected override bool OnKeyDown(KeyDownEvent e) + { + switch (e.Key) + { + case Key.Tab: + var firstArea = mainArea.FirstOrDefault(a => !a.IsActiveArea.Value); + if (firstArea != null) + firstArea.IsActiveArea.Value = true; + return true; + } + + return base.OnKeyDown(e); + } + private void recordResult(bool correct) { explanatoryText.FadeOut(500, Easing.OutQuint); @@ -198,7 +215,8 @@ Do whatever you need to try and perceive the difference in latency, then choose mainArea.Add(new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(difficulty) : 0) { Width = 0.5f, - ReportBetter = () => recordResult(betterSide == 0) + ReportBetter = () => recordResult(betterSide == 0), + IsActiveArea = { Value = true } }); mainArea.Add(new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(difficulty) : 0) @@ -208,6 +226,15 @@ Do whatever you need to try and perceive the difference in latency, then choose Origin = Anchor.TopRight, ReportBetter = () => recordResult(betterSide == 1) }); + + foreach (var area in mainArea) + { + area.IsActiveArea.BindValueChanged(active => + { + if (active.NewValue) + mainArea.Children.First(a => a != area).IsActiveArea.Value = false; + }); + } } private void showResults() @@ -361,6 +388,8 @@ Do whatever you need to try and perceive the difference in latency, then choose private readonly Key key; private readonly int targetFrameRate; + public readonly BindableBool IsActiveArea = new BindableBool(); + public LatencyArea(Key key, int targetFrameRate) { this.key = key; @@ -395,31 +424,30 @@ Do whatever you need to try and perceive the difference in latency, then choose RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new LatencyMovableBox + new LatencyMovableBox(IsActiveArea) { RelativeSizeAxes = Axes.Both, }, - new LatencyCursorContainer + new LatencyCursorContainer(IsActiveArea) { RelativeSizeAxes = Axes.Both, }, } }, }; + + IsActiveArea.BindValueChanged(active => + { + background.FadeColour(active.NewValue ? overlayColourProvider.Background4 : overlayColourProvider.Background6, 200, Easing.OutQuint); + }, true); } protected override bool OnHover(HoverEvent e) { - background.FadeColour(overlayColourProvider.Background4, 200, Easing.OutQuint); + IsActiveArea.Value = true; return base.OnHover(e); } - protected override void OnHoverLost(HoverLostEvent e) - { - background.FadeColour(overlayColourProvider.Background6, 200, Easing.OutQuint); - base.OnHoverLost(e); - } - private double lastFrameTime; public override bool UpdateSubTree() @@ -438,9 +466,16 @@ Do whatever you need to try and perceive the difference in latency, then choose private Box box = null!; private InputManager inputManager = null!; + private readonly BindableBool isActive; + [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } = null!; + public LatencyMovableBox(BindableBool isActive) + { + this.isActive = isActive; + } + protected override void LoadComplete() { base.LoadComplete(); @@ -465,7 +500,7 @@ Do whatever you need to try and perceive the difference in latency, then choose { base.Update(); - if (!IsHovered) + if (!isActive.Value) { lastFrameTime = null; return; @@ -515,11 +550,14 @@ Do whatever you need to try and perceive the difference in latency, then choose private Circle cursor = null!; private InputManager inputManager = null!; + private readonly BindableBool isActive; + [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } = null!; - public LatencyCursorContainer() + public LatencyCursorContainer(BindableBool isActive) { + this.isActive = isActive; Masking = true; } @@ -543,7 +581,7 @@ Do whatever you need to try and perceive the difference in latency, then choose { cursor.Colour = inputManager.CurrentState.Mouse.IsPressed(MouseButton.Left) ? overlayColourProvider.Content1 : overlayColourProvider.Colour2; - if (IsHovered) + if (isActive.Value) { cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position); cursor.Alpha = 1; From f2524fc3d7e7ad8515d12cbce8f4a3bf17bbb677 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 20:42:19 +0900 Subject: [PATCH 14/32] Increase separator width --- osu.Game/Screens/LatencyComparerScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index 6758908c3e..75e6643e32 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -96,7 +96,7 @@ namespace osu.Game.Screens { Name = "separator", Colour = ColourInfo.GradientHorizontal(overlayColourProvider.Background6, overlayColourProvider.Background6.Opacity(0)), - Width = 50, + Width = 100, RelativeSizeAxes = Axes.Y, Anchor = Anchor.TopCentre, Origin = Anchor.TopLeft, @@ -105,7 +105,7 @@ namespace osu.Game.Screens { Name = "separator", Colour = ColourInfo.GradientHorizontal(overlayColourProvider.Background6.Opacity(0), overlayColourProvider.Background6), - Width = 50, + Width = 100, RelativeSizeAxes = Axes.Y, Anchor = Anchor.TopCentre, Origin = Anchor.TopRight, From 0561e9cc751915a5bab9cb6434eff0842e5e7449 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 20:45:37 +0900 Subject: [PATCH 15/32] Fix mouse focus not always working --- osu.Game/Screens/LatencyComparerScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index 75e6643e32..0a966502b5 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -442,10 +442,10 @@ Do whatever you need to try and perceive the difference in latency, then choose }, true); } - protected override bool OnHover(HoverEvent e) + protected override bool OnMouseMove(MouseMoveEvent e) { IsActiveArea.Value = true; - return base.OnHover(e); + return base.OnMouseMove(e); } private double lastFrameTime; From c1ef59ab03fa2d4c2e496378dc20a36182e53a46 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 22:52:24 +0900 Subject: [PATCH 16/32] Add more comprehensive certification flow (and remove "difficulty" terminology) --- osu.Game/Screens/LatencyComparerScreen.cs | 122 +++++++++++++++------- 1 file changed, 87 insertions(+), 35 deletions(-) diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index 0a966502b5..c1e514687a 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -13,6 +13,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input; @@ -24,6 +25,7 @@ using osu.Framework.Screens; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Overlays.Settings; using osuTK; @@ -66,11 +68,13 @@ namespace osu.Game.Screens private const int rounds_to_complete = 5; + private const int rounds_to_complete_certified = 20; + private int round; private int correctCount; private int targetRoundCount = rounds_to_complete; - private int difficulty = 1; + private int difficultyLevel = 1; private double lastPoll; private int pollingMax; @@ -124,6 +128,10 @@ Use the Tab key to change focus. Do whatever you need to try and perceive the difference in latency, then choose your best side. ", }, + resultsArea = new Container + { + RelativeSizeAxes = Axes.Both, + }, statusText = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 40)) { Anchor = Anchor.TopCentre, @@ -133,10 +141,6 @@ Do whatever you need to try and perceive the difference in latency, then choose RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, - resultsArea = new Container - { - RelativeSizeAxes = Axes.Both, - }, }; } @@ -206,20 +210,20 @@ Do whatever you need to try and perceive the difference in latency, then choose private void loadNextRound() { round++; - statusText.Text = $"Difficulty {difficulty}\nRound {round} of {targetRoundCount}"; + statusText.Text = $"Level {difficultyLevel}\nRound {round} of {targetRoundCount}"; mainArea.Clear(); int betterSide = RNG.Next(0, 2); - mainArea.Add(new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(difficulty) : 0) + mainArea.Add(new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(difficultyLevel) : 0) { Width = 0.5f, ReportBetter = () => recordResult(betterSide == 0), IsActiveArea = { Value = true } }); - mainArea.Add(new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(difficulty) : 0) + mainArea.Add(new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(difficultyLevel) : 0) { Width = 0.5f, Anchor = Anchor.TopRight, @@ -251,10 +255,10 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.Clear(); float successRate = (float)correctCount / targetRoundCount; - bool isPass = successRate > 0.8f; + bool isPass = successRate == 1; statusText.AddParagraph($"You scored {correctCount} out of {targetRoundCount} ({successRate:0%})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); - statusText.AddParagraph($"Level {difficulty} ({mapDifficultyToTargetFrameRate(difficulty):N0} hz)", + statusText.AddParagraph($"Level {difficultyLevel} ({mapDifficultyToTargetFrameRate(difficultyLevel):N0} hz)", cp => cp.Font = OsuFont.Default.With(size: 24)); statusText.AddParagraph(string.Empty); @@ -262,6 +266,12 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.AddIcon(isPass ? FontAwesome.Regular.CheckCircle : FontAwesome.Regular.TimesCircle, cp => cp.Colour = isPass ? colours.Green : colours.Red); statusText.AddParagraph(string.Empty); + if (!isPass && difficultyLevel > 1) + { + statusText.AddParagraph("To complete certification, decrease the difficulty level until you can get 20 tests correct in a row!", cp => cp.Font = OsuFont.Default.With(size: 24)); + statusText.AddParagraph(string.Empty); + } + statusText.AddParagraph($"Polling: {pollingMax} hz Monitor: {displayMode.RefreshRate:N0} hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); statusText.AddParagraph($"Input: {host.InputThread.Clock.FramesPerSecond} hz " @@ -269,13 +279,55 @@ Do whatever you need to try and perceive the difference in latency, then choose + $"Draw: {host.DrawThread.Clock.FramesPerSecond} hz" , cp => cp.Font = OsuFont.Default.With(size: 15)); + int certificationRemaining = !isPass ? rounds_to_complete_certified : rounds_to_complete_certified - correctCount; + + if (isPass && certificationRemaining <= 0) + { + Drawable background; + Drawable certifiedText; + + resultsArea.AddRange(new[] + { + background = new Box + { + Colour = overlayColourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + (certifiedText = new OsuSpriteText + { + Alpha = 0, + Font = OsuFont.TorusAlternate.With(size: 80, weight: FontWeight.Bold), + Text = "Certified!", + Blending = BlendingParameters.Additive, + }).WithEffect(new GlowEffect + { + Colour = overlayColourProvider.Colour1, + }).With(e => + { + e.Anchor = Anchor.Centre; + e.Origin = Anchor.Centre; + }) + }); + + background.FadeInFromZero(1000, Easing.OutQuint); + + certifiedText.FadeInFromZero(500, Easing.InQuint); + + certifiedText + .ScaleTo(10) + .ScaleTo(1, 600, Easing.InQuad) + .Then() + .ScaleTo(1.05f, 10000, Easing.OutQuint); + return; + } + string cannotIncreaseReason = string.Empty; if (!isPass) - cannotIncreaseReason = "You didn't score high enough (over 80% required)!"; - else if (mapDifficultyToTargetFrameRate(difficulty + 1) > target_host_update_frames) + cannotIncreaseReason = "You didn't get a perfect score."; + else if (mapDifficultyToTargetFrameRate(difficultyLevel + 1) > target_host_update_frames) cannotIncreaseReason = "You've reached the limits of this comparison mode."; - else if (mapDifficultyToTargetFrameRate(difficulty + 1) > Clock.FramesPerSecond) + else if (mapDifficultyToTargetFrameRate(difficultyLevel + 1) > Clock.FramesPerSecond) cannotIncreaseReason = "Game is not running fast enough to test this level"; resultsArea.Add(new FillFlowContainer @@ -288,9 +340,27 @@ Do whatever you need to try and perceive the difference in latency, then choose Padding = new MarginPadding(20), Children = new Drawable[] { + new Button(Key.Enter) + { + Text = "Continue to next level", + BackgroundColour = colours.Red2, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Action = () => changeDifficulty(difficultyLevel + 1), + Enabled = { Value = string.IsNullOrEmpty(cannotIncreaseReason) }, + TooltipText = cannotIncreaseReason + }, + new Button(Key.D) + { + Text = difficultyLevel == 1 ? "Retry" : "Return to last level", + BackgroundColour = colours.Green, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Action = () => changeDifficulty(Math.Max(difficultyLevel - 1, 1)), + }, new Button(Key.R) { - Text = "Increase confidence at current level", + Text = $"Continue towards certification at this level ({certificationRemaining} more)", Anchor = Anchor.Centre, Origin = Anchor.Centre, Action = () => @@ -299,27 +369,9 @@ Do whatever you need to try and perceive the difference in latency, then choose targetRoundCount += rounds_to_complete; loadNextRound(); }, - TooltipText = isPass ? "The longer you chain, the more sure you will be!" : "You've reached your limits", - Enabled = { Value = string.IsNullOrEmpty(cannotIncreaseReason) }, + TooltipText = isPass ? $"Chain {rounds_to_complete_certified} to confirm your perception!" : "You've reached your limits. Go to the previous level to complete certification!", + Enabled = { Value = isPass }, }, - new Button(Key.I) - { - Text = "Increase difficulty", - BackgroundColour = colours.Red2, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Action = () => changeDifficulty(difficulty + 1), - Enabled = { Value = string.IsNullOrEmpty(cannotIncreaseReason) }, - TooltipText = cannotIncreaseReason - }, - new Button(Key.D) - { - Text = difficulty == 1 ? "Restart" : "Decrease difficulty", - BackgroundColour = colours.Green, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Action = () => changeDifficulty(Math.Max(difficulty - 1, 1)), - } } }); } @@ -336,7 +388,7 @@ Do whatever you need to try and perceive the difference in latency, then choose lastPoll = 0; targetRoundCount = rounds_to_complete; - difficulty = diff; + difficultyLevel = diff; loadNextRound(); } From 058760253a225bcbc90e1248960d0fd3e7696fbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 23:02:15 +0900 Subject: [PATCH 17/32] Add test coverage of certification flow --- .../Settings/TestSceneLatencyComparer.cs | 44 +++++++++++++++++-- osu.Game/Screens/LatencyComparerScreen.cs | 9 ++-- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs index 8a5db7bd95..4706ecb149 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs @@ -3,17 +3,55 @@ #nullable enable +using System.Linq; using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Graphics.UserInterface; using osu.Game.Screens; +using osuTK.Input; namespace osu.Game.Tests.Visual.Settings { public class TestSceneLatencyComparer : ScreenTestScene { - [Test] - public void TestBasic() + private LatencyComparerScreen latencyComparer = null!; + + public override void SetUpSteps() { - AddStep("Load screen", () => LoadScreen(new LatencyComparerScreen())); + base.SetUpSteps(); + AddStep("Load screen", () => LoadScreen(latencyComparer = new LatencyComparerScreen())); + } + + [Test] + public void TestCertification() + { + for (int i = 0; i < 4; i++) + { + clickCorrectUntilResults(); + AddAssert("check at results", () => !latencyComparer.ChildrenOfType().Any()); + AddStep("hit c to continue", () => InputManager.Key(Key.C)); + } + + AddAssert("check at results", () => !latencyComparer.ChildrenOfType().Any()); + + AddAssert("check no buttons", () => !latencyComparer.ChildrenOfType().Any()); + } + + private void clickCorrectUntilResults() + { + AddUntilStep("click correct button until results", () => + { + var latencyArea = latencyComparer + .ChildrenOfType() + .SingleOrDefault(a => a.TargetFrameRate == 0); + + // reached results + if (latencyArea == null) + return true; + + latencyArea.ChildrenOfType().Single().TriggerClick(); + return false; + }); } } } diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/LatencyComparerScreen.cs index c1e514687a..45e62646b1 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/LatencyComparerScreen.cs @@ -358,7 +358,7 @@ Do whatever you need to try and perceive the difference in latency, then choose Origin = Anchor.Centre, Action = () => changeDifficulty(Math.Max(difficultyLevel - 1, 1)), }, - new Button(Key.R) + new Button(Key.C) { Text = $"Continue towards certification at this level ({certificationRemaining} more)", Anchor = Anchor.Centre, @@ -438,14 +438,15 @@ Do whatever you need to try and perceive the difference in latency, then choose private Drawable? background; private readonly Key key; - private readonly int targetFrameRate; + + public readonly int TargetFrameRate; public readonly BindableBool IsActiveArea = new BindableBool(); public LatencyArea(Key key, int targetFrameRate) { this.key = key; - this.targetFrameRate = targetFrameRate; + TargetFrameRate = targetFrameRate; RelativeSizeAxes = Axes.Both; Masking = true; @@ -505,7 +506,7 @@ Do whatever you need to try and perceive the difference in latency, then choose public override bool UpdateSubTree() { double elapsed = Clock.CurrentTime - lastFrameTime; - if (targetFrameRate > 0 && elapsed < 1000.0 / targetFrameRate) + if (TargetFrameRate > 0 && elapsed < 1000.0 / TargetFrameRate) return false; lastFrameTime = Clock.CurrentTime; From 95dea00725ed8c4c669a54d517a95405449d14f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 23:10:08 +0900 Subject: [PATCH 18/32] Tidy up code and namespaces --- .../Settings/TestSceneLatencyComparer.cs | 8 +- .../Sections/DebugSettings/GeneralSettings.cs | 1 + osu.Game/Screens/Utility/ButtonWithKeyBind.cs | 53 +++ osu.Game/Screens/Utility/LatencyArea.cs | 239 +++++++++++ .../{ => Utility}/LatencyComparerScreen.cs | 379 +++--------------- 5 files changed, 355 insertions(+), 325 deletions(-) create mode 100644 osu.Game/Screens/Utility/ButtonWithKeyBind.cs create mode 100644 osu.Game/Screens/Utility/LatencyArea.cs rename osu.Game/Screens/{ => Utility}/LatencyComparerScreen.cs (59%) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs index 4706ecb149..e4b9b21470 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs @@ -7,7 +7,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens; +using osu.Game.Screens.Utility; using osuTK.Input; namespace osu.Game.Tests.Visual.Settings @@ -28,11 +28,11 @@ namespace osu.Game.Tests.Visual.Settings for (int i = 0; i < 4; i++) { clickCorrectUntilResults(); - AddAssert("check at results", () => !latencyComparer.ChildrenOfType().Any()); + AddAssert("check at results", () => !latencyComparer.ChildrenOfType().Any()); AddStep("hit c to continue", () => InputManager.Key(Key.C)); } - AddAssert("check at results", () => !latencyComparer.ChildrenOfType().Any()); + AddAssert("check at results", () => !latencyComparer.ChildrenOfType().Any()); AddAssert("check no buttons", () => !latencyComparer.ChildrenOfType().Any()); } @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("click correct button until results", () => { var latencyArea = latencyComparer - .ChildrenOfType() + .ChildrenOfType() .SingleOrDefault(a => a.TargetFrameRate == 0); // reached results diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs index 318cdbd6a7..80e5235449 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs @@ -9,6 +9,7 @@ using osu.Framework.Screens; using osu.Game.Localisation; using osu.Game.Screens; using osu.Game.Screens.Import; +using osu.Game.Screens.Utility; namespace osu.Game.Overlays.Settings.Sections.DebugSettings { diff --git a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs new file mode 100644 index 0000000000..20e39ffa6a --- /dev/null +++ b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs @@ -0,0 +1,53 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable +using osu.Framework.Allocation; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Overlays; +using osu.Game.Overlays.Settings; +using osuTK.Input; + +namespace osu.Game.Screens.Utility +{ + public class ButtonWithKeyBind : SettingsButton + { + private readonly Key key; + + public ButtonWithKeyBind(Key key) + { + this.key = key; + } + + public override LocalisableString Text + { + get => base.Text; + set => base.Text = $"{value} (Press {key.ToString().Replace("Number", string.Empty)})"; + } + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (!e.Repeat && e.Key == key) + { + TriggerClick(); + return true; + } + + return base.OnKeyDown(e); + } + + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + Height = 100; + SpriteText.Colour = overlayColourProvider.Background6; + SpriteText.Font = OsuFont.TorusAlternate.With(size: 34); + } + } +} diff --git a/osu.Game/Screens/Utility/LatencyArea.cs b/osu.Game/Screens/Utility/LatencyArea.cs new file mode 100644 index 0000000000..a82efa1e26 --- /dev/null +++ b/osu.Game/Screens/Utility/LatencyArea.cs @@ -0,0 +1,239 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable +using System; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Framework.Input.Events; +using osu.Game.Overlays; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Screens.Utility +{ + public class LatencyArea : CompositeDrawable + { + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + public Action? ReportUserBest { get; set; } + + private Drawable? background; + + private readonly Key key; + + public readonly int TargetFrameRate; + + public readonly BindableBool IsActiveArea = new BindableBool(); + + public LatencyArea(Key key, int targetFrameRate) + { + this.key = key; + TargetFrameRate = targetFrameRate; + + RelativeSizeAxes = Axes.Both; + Masking = true; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + InternalChildren = new[] + { + background = new Box + { + Colour = overlayColourProvider.Background6, + RelativeSizeAxes = Axes.Both, + }, + new ButtonWithKeyBind(key) + { + Text = "Feels better", + Y = 20, + Width = 0.8f, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Action = () => ReportUserBest?.Invoke(), + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new LatencyMovableBox(IsActiveArea) + { + RelativeSizeAxes = Axes.Both, + }, + new LatencyCursorContainer(IsActiveArea) + { + RelativeSizeAxes = Axes.Both, + }, + } + }, + }; + + IsActiveArea.BindValueChanged(active => + { + background.FadeColour(active.NewValue ? overlayColourProvider.Background4 : overlayColourProvider.Background6, 200, Easing.OutQuint); + }, true); + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + IsActiveArea.Value = true; + return base.OnMouseMove(e); + } + + private double lastFrameTime; + + public override bool UpdateSubTree() + { + double elapsed = Clock.CurrentTime - lastFrameTime; + if (TargetFrameRate > 0 && elapsed < 1000.0 / TargetFrameRate) + return false; + + lastFrameTime = Clock.CurrentTime; + + return base.UpdateSubTree(); + } + + public class LatencyMovableBox : CompositeDrawable + { + private Box box = null!; + private InputManager inputManager = null!; + + private readonly BindableBool isActive; + + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + public LatencyMovableBox(BindableBool isActive) + { + this.isActive = isActive; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + + InternalChild = box = new Box + { + Size = new Vector2(40), + RelativePositionAxes = Axes.Both, + Position = new Vector2(0.5f), + Origin = Anchor.Centre, + Colour = overlayColourProvider.Colour1, + }; + } + + protected override bool OnHover(HoverEvent e) => false; + + private double? lastFrameTime; + + protected override void Update() + { + base.Update(); + + if (!isActive.Value) + { + lastFrameTime = null; + return; + } + + if (lastFrameTime != null) + { + float movementAmount = (float)(Clock.CurrentTime - lastFrameTime) / 400; + + var buttons = inputManager.CurrentState.Keyboard.Keys; + + box.Colour = buttons.HasAnyButtonPressed ? overlayColourProvider.Content1 : overlayColourProvider.Colour1; + + foreach (var key in buttons) + { + switch (key) + { + case Key.K: + case Key.Up: + box.Y = MathHelper.Clamp(box.Y - movementAmount, 0.1f, 0.9f); + break; + + case Key.J: + case Key.Down: + box.Y = MathHelper.Clamp(box.Y + movementAmount, 0.1f, 0.9f); + break; + + case Key.Z: + case Key.Left: + box.X = MathHelper.Clamp(box.X - movementAmount, 0.1f, 0.9f); + break; + + case Key.X: + case Key.Right: + box.X = MathHelper.Clamp(box.X + movementAmount, 0.1f, 0.9f); + break; + } + } + } + + lastFrameTime = Clock.CurrentTime; + } + } + + public class LatencyCursorContainer : CompositeDrawable + { + private Circle cursor = null!; + private InputManager inputManager = null!; + + private readonly BindableBool isActive; + + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + public LatencyCursorContainer(BindableBool isActive) + { + this.isActive = isActive; + Masking = true; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + InternalChild = cursor = new Circle + { + Size = new Vector2(40), + Origin = Anchor.Centre, + Colour = overlayColourProvider.Colour2, + }; + + inputManager = GetContainingInputManager(); + } + + protected override bool OnHover(HoverEvent e) => false; + + protected override void Update() + { + cursor.Colour = inputManager.CurrentState.Mouse.IsPressed(MouseButton.Left) ? overlayColourProvider.Content1 : overlayColourProvider.Colour2; + + if (isActive.Value) + { + cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position); + cursor.Alpha = 1; + } + else + { + cursor.Alpha = 0; + } + + base.Update(); + } + } + } +} diff --git a/osu.Game/Screens/LatencyComparerScreen.cs b/osu.Game/Screens/Utility/LatencyComparerScreen.cs similarity index 59% rename from osu.Game/Screens/LatencyComparerScreen.cs rename to osu.Game/Screens/Utility/LatencyComparerScreen.cs index 45e62646b1..1e859a2956 100644 --- a/osu.Game/Screens/LatencyComparerScreen.cs +++ b/osu.Game/Screens/Utility/LatencyComparerScreen.cs @@ -7,7 +7,6 @@ using System; using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -16,9 +15,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; -using osu.Framework.Input; using osu.Framework.Input.Events; -using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Framework.Platform.Windows; using osu.Framework.Screens; @@ -27,11 +24,10 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; -using osu.Game.Overlays.Settings; using osuTK; using osuTK.Input; -namespace osu.Game.Screens +namespace osu.Game.Screens.Utility { public class LatencyComparerScreen : OsuScreen { @@ -174,7 +170,6 @@ Do whatever you need to try and perceive the difference in latency, then choose protected override void LoadComplete() { base.LoadComplete(); - loadNextRound(); } @@ -192,55 +187,6 @@ Do whatever you need to try and perceive the difference in latency, then choose return base.OnKeyDown(e); } - private void recordResult(bool correct) - { - explanatoryText.FadeOut(500, Easing.OutQuint); - - if (correct) - correctCount++; - - if (round < targetRoundCount) - loadNextRound(); - else - { - showResults(); - } - } - - private void loadNextRound() - { - round++; - statusText.Text = $"Level {difficultyLevel}\nRound {round} of {targetRoundCount}"; - - mainArea.Clear(); - - int betterSide = RNG.Next(0, 2); - - mainArea.Add(new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(difficultyLevel) : 0) - { - Width = 0.5f, - ReportBetter = () => recordResult(betterSide == 0), - IsActiveArea = { Value = true } - }); - - mainArea.Add(new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(difficultyLevel) : 0) - { - Width = 0.5f, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - ReportBetter = () => recordResult(betterSide == 1) - }); - - foreach (var area in mainArea) - { - area.IsActiveArea.BindValueChanged(active => - { - if (active.NewValue) - mainArea.Children.First(a => a != area).IsActiveArea.Value = false; - }); - } - } - private void showResults() { mainArea.Clear(); @@ -340,7 +286,7 @@ Do whatever you need to try and perceive the difference in latency, then choose Padding = new MarginPadding(20), Children = new Drawable[] { - new Button(Key.Enter) + new ButtonWithKeyBind(Key.Enter) { Text = "Continue to next level", BackgroundColour = colours.Red2, @@ -350,7 +296,7 @@ Do whatever you need to try and perceive the difference in latency, then choose Enabled = { Value = string.IsNullOrEmpty(cannotIncreaseReason) }, TooltipText = cannotIncreaseReason }, - new Button(Key.D) + new ButtonWithKeyBind(Key.D) { Text = difficultyLevel == 1 ? "Retry" : "Return to last level", BackgroundColour = colours.Green, @@ -358,7 +304,7 @@ Do whatever you need to try and perceive the difference in latency, then choose Origin = Anchor.Centre, Action = () => changeDifficulty(Math.Max(difficultyLevel - 1, 1)), }, - new Button(Key.C) + new ButtonWithKeyBind(Key.C) { Text = $"Continue towards certification at this level ({certificationRemaining} more)", Anchor = Anchor.Centre, @@ -376,9 +322,9 @@ Do whatever you need to try and perceive the difference in latency, then choose }); } - private void changeDifficulty(int diff) + private void changeDifficulty(int difficulty) { - Debug.Assert(diff > 0); + Debug.Assert(difficulty > 0); resultsArea.Clear(); @@ -388,10 +334,61 @@ Do whatever you need to try and perceive the difference in latency, then choose lastPoll = 0; targetRoundCount = rounds_to_complete; - difficultyLevel = diff; + difficultyLevel = difficulty; + loadNextRound(); } + private void loadNextRound() + { + round++; + statusText.Text = $"Level {difficultyLevel}\nRound {round} of {targetRoundCount}"; + + mainArea.Clear(); + + int betterSide = RNG.Next(0, 2); + + mainArea.AddRange(new[] + { + new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(difficultyLevel) : 0) + { + Width = 0.5f, + IsActiveArea = { Value = true }, + ReportUserBest = () => recordResult(betterSide == 0), + }, + new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(difficultyLevel) : 0) + { + Width = 0.5f, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + ReportUserBest = () => recordResult(betterSide == 1) + } + }); + + foreach (var area in mainArea) + { + area.IsActiveArea.BindValueChanged(active => + { + if (active.NewValue) + mainArea.Children.First(a => a != area).IsActiveArea.Value = false; + }); + } + } + + private void recordResult(bool correct) + { + // Fading this out will improve the frame rate after the first round due to less text on screen. + explanatoryText.FadeOut(500, Easing.OutQuint); + + if (correct) + correctCount++; + + if (round < targetRoundCount) + loadNextRound(); + else + showResults(); + } + private static int mapDifficultyToTargetFrameRate(int difficulty) { switch (difficulty) @@ -427,265 +424,5 @@ Do whatever you need to try and perceive the difference in latency, then choose return 1000 + ((difficulty - 10) * 500); } } - - public class LatencyArea : CompositeDrawable - { - [Resolved] - private OverlayColourProvider overlayColourProvider { get; set; } = null!; - - public Action? ReportBetter { get; set; } - - private Drawable? background; - - private readonly Key key; - - public readonly int TargetFrameRate; - - public readonly BindableBool IsActiveArea = new BindableBool(); - - public LatencyArea(Key key, int targetFrameRate) - { - this.key = key; - TargetFrameRate = targetFrameRate; - - RelativeSizeAxes = Axes.Both; - Masking = true; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - InternalChildren = new[] - { - background = new Box - { - Colour = overlayColourProvider.Background6, - RelativeSizeAxes = Axes.Both, - }, - new Button(key) - { - Text = "Feels better", - Y = 20, - Width = 0.8f, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Action = () => ReportBetter?.Invoke(), - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new LatencyMovableBox(IsActiveArea) - { - RelativeSizeAxes = Axes.Both, - }, - new LatencyCursorContainer(IsActiveArea) - { - RelativeSizeAxes = Axes.Both, - }, - } - }, - }; - - IsActiveArea.BindValueChanged(active => - { - background.FadeColour(active.NewValue ? overlayColourProvider.Background4 : overlayColourProvider.Background6, 200, Easing.OutQuint); - }, true); - } - - protected override bool OnMouseMove(MouseMoveEvent e) - { - IsActiveArea.Value = true; - return base.OnMouseMove(e); - } - - private double lastFrameTime; - - public override bool UpdateSubTree() - { - double elapsed = Clock.CurrentTime - lastFrameTime; - if (TargetFrameRate > 0 && elapsed < 1000.0 / TargetFrameRate) - return false; - - lastFrameTime = Clock.CurrentTime; - - return base.UpdateSubTree(); - } - - public class LatencyMovableBox : CompositeDrawable - { - private Box box = null!; - private InputManager inputManager = null!; - - private readonly BindableBool isActive; - - [Resolved] - private OverlayColourProvider overlayColourProvider { get; set; } = null!; - - public LatencyMovableBox(BindableBool isActive) - { - this.isActive = isActive; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - inputManager = GetContainingInputManager(); - - InternalChild = box = new Box - { - Size = new Vector2(40), - RelativePositionAxes = Axes.Both, - Position = new Vector2(0.5f), - Origin = Anchor.Centre, - Colour = overlayColourProvider.Colour1, - }; - } - - protected override bool OnHover(HoverEvent e) => false; - - private double? lastFrameTime; - - protected override void Update() - { - base.Update(); - - if (!isActive.Value) - { - lastFrameTime = null; - return; - } - - if (lastFrameTime != null) - { - float movementAmount = (float)(Clock.CurrentTime - lastFrameTime) / 400; - - var buttons = inputManager.CurrentState.Keyboard.Keys; - - box.Colour = buttons.HasAnyButtonPressed ? overlayColourProvider.Content1 : overlayColourProvider.Colour1; - - foreach (var key in buttons) - { - switch (key) - { - case Key.K: - case Key.Up: - box.Y = MathHelper.Clamp(box.Y - movementAmount, 0.1f, 0.9f); - break; - - case Key.J: - case Key.Down: - box.Y = MathHelper.Clamp(box.Y + movementAmount, 0.1f, 0.9f); - break; - - case Key.Z: - case Key.Left: - box.X = MathHelper.Clamp(box.X - movementAmount, 0.1f, 0.9f); - break; - - case Key.X: - case Key.Right: - box.X = MathHelper.Clamp(box.X + movementAmount, 0.1f, 0.9f); - break; - } - } - } - - lastFrameTime = Clock.CurrentTime; - } - } - - public class LatencyCursorContainer : CompositeDrawable - { - private Circle cursor = null!; - private InputManager inputManager = null!; - - private readonly BindableBool isActive; - - [Resolved] - private OverlayColourProvider overlayColourProvider { get; set; } = null!; - - public LatencyCursorContainer(BindableBool isActive) - { - this.isActive = isActive; - Masking = true; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - InternalChild = cursor = new Circle - { - Size = new Vector2(40), - Origin = Anchor.Centre, - Colour = overlayColourProvider.Colour2, - }; - - inputManager = GetContainingInputManager(); - } - - protected override bool OnHover(HoverEvent e) => false; - - protected override void Update() - { - cursor.Colour = inputManager.CurrentState.Mouse.IsPressed(MouseButton.Left) ? overlayColourProvider.Content1 : overlayColourProvider.Colour2; - - if (isActive.Value) - { - cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position); - cursor.Alpha = 1; - } - else - { - cursor.Alpha = 0; - } - - base.Update(); - } - } - } - - public class Button : SettingsButton - { - private readonly Key key; - - public Button(Key key) - { - this.key = key; - } - - public override LocalisableString Text - { - get => base.Text; - set => base.Text = $"{value} (Press {key.ToString().Replace("Number", string.Empty)})"; - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - if (!e.Repeat && e.Key == key) - { - TriggerClick(); - return true; - } - - return base.OnKeyDown(e); - } - - [Resolved] - private OverlayColourProvider overlayColourProvider { get; set; } = null!; - - protected override void LoadComplete() - { - base.LoadComplete(); - - Height = 100; - SpriteText.Colour = overlayColourProvider.Background6; - SpriteText.Font = OsuFont.TorusAlternate.With(size: 34); - } - } } } From 1a1dfaeae66628ff4b8a8cab18b6477cade2c0c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 23:25:45 +0900 Subject: [PATCH 19/32] Update framework --- osu.Android.props | 2 +- osu.Game/Screens/Utility/LatencyComparerScreen.cs | 4 ++-- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index aad8cf10d0..155a21bacb 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/Screens/Utility/LatencyComparerScreen.cs b/osu.Game/Screens/Utility/LatencyComparerScreen.cs index 1e859a2956..b25e6ee901 100644 --- a/osu.Game/Screens/Utility/LatencyComparerScreen.cs +++ b/osu.Game/Screens/Utility/LatencyComparerScreen.cs @@ -156,12 +156,12 @@ Do whatever you need to try and perceive the difference in latency, then choose previousActiveHz = host.UpdateThread.ActiveHz; config.SetValue(FrameworkSetting.FrameSync, FrameSync.Unlimited); host.UpdateThread.ActiveHz = target_host_update_frames; - // host.AllowBenchmarkUnlimitedFrames = true; + host.AllowBenchmarkUnlimitedFrames = true; } public override bool OnExiting(ScreenExitEvent e) { - // host.AllowBenchmarkUnlimitedFrames = false; + host.AllowBenchmarkUnlimitedFrames = false; config.SetValue(FrameworkSetting.FrameSync, previousFrameSyncMode); host.UpdateThread.ActiveHz = previousActiveHz; return base.OnExiting(e); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 63b8cf4cb5..b6218c5950 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index a0fafa635b..ba57aba01b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 9da99a0ddfe730b96db3375636b903217cfe0e01 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 23:34:19 +0900 Subject: [PATCH 20/32] Rename to latency certifier --- ...parer.cs => TestSceneLatencyCertifierScreen.cs} | 14 +++++++------- .../Sections/DebugSettings/GeneralSettings.cs | 2 +- ...ComparerScreen.cs => LatencyCertifierScreen.cs} | 7 +++---- 3 files changed, 11 insertions(+), 12 deletions(-) rename osu.Game.Tests/Visual/Settings/{TestSceneLatencyComparer.cs => TestSceneLatencyCertifierScreen.cs} (68%) rename osu.Game/Screens/Utility/{LatencyComparerScreen.cs => LatencyCertifierScreen.cs} (98%) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs similarity index 68% rename from osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs rename to osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs index e4b9b21470..687d7c490c 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneLatencyComparer.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs @@ -12,14 +12,14 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Settings { - public class TestSceneLatencyComparer : ScreenTestScene + public class TestSceneLatencyCertifierScreen : ScreenTestScene { - private LatencyComparerScreen latencyComparer = null!; + private LatencyCertifierScreen latencyCertifier = null!; public override void SetUpSteps() { base.SetUpSteps(); - AddStep("Load screen", () => LoadScreen(latencyComparer = new LatencyComparerScreen())); + AddStep("Load screen", () => LoadScreen(latencyCertifier = new LatencyCertifierScreen())); } [Test] @@ -28,20 +28,20 @@ namespace osu.Game.Tests.Visual.Settings for (int i = 0; i < 4; i++) { clickCorrectUntilResults(); - AddAssert("check at results", () => !latencyComparer.ChildrenOfType().Any()); + AddAssert("check at results", () => !latencyCertifier.ChildrenOfType().Any()); AddStep("hit c to continue", () => InputManager.Key(Key.C)); } - AddAssert("check at results", () => !latencyComparer.ChildrenOfType().Any()); + AddAssert("check at results", () => !latencyCertifier.ChildrenOfType().Any()); - AddAssert("check no buttons", () => !latencyComparer.ChildrenOfType().Any()); + AddAssert("check no buttons", () => !latencyCertifier.ChildrenOfType().Any()); } private void clickCorrectUntilResults() { AddUntilStep("click correct button until results", () => { - var latencyArea = latencyComparer + var latencyArea = latencyCertifier .ChildrenOfType() .SingleOrDefault(a => a.TargetFrameRate == 0); diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs index 80e5235449..cd8cf8f64f 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings new SettingsButton { Text = @"Run latency comparer", - Action = () => performer?.PerformFromScreen(menu => menu.Push(new LatencyComparerScreen())) + Action = () => performer?.PerformFromScreen(menu => menu.Push(new LatencyCertifierScreen())) } }; } diff --git a/osu.Game/Screens/Utility/LatencyComparerScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs similarity index 98% rename from osu.Game/Screens/Utility/LatencyComparerScreen.cs rename to osu.Game/Screens/Utility/LatencyCertifierScreen.cs index b25e6ee901..157998184c 100644 --- a/osu.Game/Screens/Utility/LatencyComparerScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -29,7 +29,7 @@ using osuTK.Input; namespace osu.Game.Screens.Utility { - public class LatencyComparerScreen : OsuScreen + public class LatencyCertifierScreen : OsuScreen { private FrameSync previousFrameSyncMode; private double previousActiveHz; @@ -78,7 +78,7 @@ namespace osu.Game.Screens.Utility [Resolved] private GameHost host { get; set; } = null!; - public LatencyComparerScreen() + public LatencyCertifierScreen() { InternalChildren = new Drawable[] { @@ -117,9 +117,8 @@ namespace osu.Game.Screens.Utility TextAnchor = Anchor.TopCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Text = @"Welcome to the latency comparer! + Text = @"Welcome to the latency certifier! Use the arrow keys, Z/X/J/K to move the square. -You can click the targets but you don't have to. Use the Tab key to change focus. Do whatever you need to try and perceive the difference in latency, then choose your best side. ", From b924aa3296bbc6ccb9c6cf0f1f4140580ffc833b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Jun 2022 00:36:19 +0900 Subject: [PATCH 21/32] Fix tests failing when run headless --- .../Visual/Settings/TestSceneLatencyCertifierScreen.cs | 3 ++- osu.Game/Screens/Utility/LatencyCertifierScreen.cs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs index 687d7c490c..6d8c6d3c54 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs @@ -19,7 +19,9 @@ namespace osu.Game.Tests.Visual.Settings public override void SetUpSteps() { base.SetUpSteps(); + AddStep("Load screen", () => LoadScreen(latencyCertifier = new LatencyCertifierScreen())); + AddUntilStep("wait for load", () => latencyCertifier.IsLoaded); } [Test] @@ -33,7 +35,6 @@ namespace osu.Game.Tests.Visual.Settings } AddAssert("check at results", () => !latencyCertifier.ChildrenOfType().Any()); - AddAssert("check no buttons", () => !latencyCertifier.ChildrenOfType().Any()); } diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index 157998184c..568e477d8f 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -190,7 +190,7 @@ Do whatever you need to try and perceive the difference in latency, then choose { mainArea.Clear(); - var displayMode = host.Window.CurrentDisplayMode.Value; + var displayMode = host.Window?.CurrentDisplayMode.Value; string exclusive = "unknown"; @@ -217,7 +217,7 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.AddParagraph(string.Empty); } - statusText.AddParagraph($"Polling: {pollingMax} hz Monitor: {displayMode.RefreshRate:N0} hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); + statusText.AddParagraph($"Polling: {pollingMax} hz Monitor: {displayMode?.RefreshRate ?? 0:N0} hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); statusText.AddParagraph($"Input: {host.InputThread.Clock.FramesPerSecond} hz " + $"Update: {host.UpdateThread.Clock.FramesPerSecond} hz " From 70ebfbcf5e9372658a500a8d861dfa5bc22f7e81 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Jun 2022 19:26:24 +0900 Subject: [PATCH 22/32] Add recommendation text and adjust weightings to read better --- .../Screens/Utility/LatencyCertifierScreen.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index 568e477d8f..2fb673c537 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -213,16 +213,16 @@ Do whatever you need to try and perceive the difference in latency, then choose if (!isPass && difficultyLevel > 1) { - statusText.AddParagraph("To complete certification, decrease the difficulty level until you can get 20 tests correct in a row!", cp => cp.Font = OsuFont.Default.With(size: 24)); + statusText.AddParagraph("To complete certification, decrease the difficulty level until you can get 20 tests correct in a row!", cp => cp.Font = OsuFont.Default.With(size: 24, weight: FontWeight.SemiBold)); statusText.AddParagraph(string.Empty); } - statusText.AddParagraph($"Polling: {pollingMax} hz Monitor: {displayMode?.RefreshRate ?? 0:N0} hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15)); + statusText.AddParagraph($"Polling: {pollingMax} hz Monitor: {displayMode?.RefreshRate ?? 0:N0} hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15, weight: FontWeight.SemiBold)); statusText.AddParagraph($"Input: {host.InputThread.Clock.FramesPerSecond} hz " + $"Update: {host.UpdateThread.Clock.FramesPerSecond} hz " + $"Draw: {host.DrawThread.Clock.FramesPerSecond} hz" - , cp => cp.Font = OsuFont.Default.With(size: 15)); + , cp => cp.Font = OsuFont.Default.With(size: 15, weight: FontWeight.SemiBold)); int certificationRemaining = !isPass ? rounds_to_complete_certified : rounds_to_complete_certified - correctCount; @@ -247,11 +247,20 @@ Do whatever you need to try and perceive the difference in latency, then choose }).WithEffect(new GlowEffect { Colour = overlayColourProvider.Colour1, + PadExtent = true }).With(e => { e.Anchor = Anchor.Centre; e.Origin = Anchor.Centre; - }) + }), + new OsuSpriteText + { + Text = $"You should use a frame limiter with update rate of {mapDifficultyToTargetFrameRate(difficultyLevel + 1)} hz (or fps) for best results!", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Torus.With(size: 24, weight: FontWeight.SemiBold), + Y = 80, + } }); background.FadeInFromZero(1000, Easing.OutQuint); From c625c929e5974f0b544758eb72a422a4cbf2def2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 14:16:56 +0900 Subject: [PATCH 23/32] Update button text to match new terminology --- .../Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs index cd8cf8f64f..2b845e9d6b 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings }, new SettingsButton { - Text = @"Run latency comparer", + Text = @"Run latency certifier", Action = () => performer?.PerformFromScreen(menu => menu.Push(new LatencyCertifierScreen())) } }; From 613814c26cbec49a6c8b2952864c560b1a0dd49a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 14:18:35 +0900 Subject: [PATCH 24/32] Make `TargetFrameRate` nullable --- osu.Game/Screens/Utility/LatencyArea.cs | 7 ++++--- osu.Game/Screens/Utility/LatencyCertifierScreen.cs | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Utility/LatencyArea.cs b/osu.Game/Screens/Utility/LatencyArea.cs index a82efa1e26..a2991d3fa8 100644 --- a/osu.Game/Screens/Utility/LatencyArea.cs +++ b/osu.Game/Screens/Utility/LatencyArea.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. #nullable enable + using System; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -27,11 +28,11 @@ namespace osu.Game.Screens.Utility private readonly Key key; - public readonly int TargetFrameRate; + public readonly int? TargetFrameRate; public readonly BindableBool IsActiveArea = new BindableBool(); - public LatencyArea(Key key, int targetFrameRate) + public LatencyArea(Key key, int? targetFrameRate) { this.key = key; TargetFrameRate = targetFrameRate; @@ -94,7 +95,7 @@ namespace osu.Game.Screens.Utility public override bool UpdateSubTree() { double elapsed = Clock.CurrentTime - lastFrameTime; - if (TargetFrameRate > 0 && elapsed < 1000.0 / TargetFrameRate) + if (TargetFrameRate.HasValue && elapsed < 1000.0 / TargetFrameRate) return false; lastFrameTime = Clock.CurrentTime; diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index 2fb673c537..a5ed573d88 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -358,13 +358,13 @@ Do whatever you need to try and perceive the difference in latency, then choose mainArea.AddRange(new[] { - new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(difficultyLevel) : 0) + new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(difficultyLevel) : (int?)null) { Width = 0.5f, IsActiveArea = { Value = true }, ReportUserBest = () => recordResult(betterSide == 0), }, - new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(difficultyLevel) : 0) + new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(difficultyLevel) : (int?)null) { Width = 0.5f, Anchor = Anchor.TopRight, From 69b856bd58d37f18433ae95363d5416c5581c7e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 14:23:24 +0900 Subject: [PATCH 25/32] Rename rounds variables to hopefully read better --- .../Screens/Utility/LatencyCertifierScreen.cs | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index a5ed573d88..2602238820 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -66,9 +66,9 @@ namespace osu.Game.Screens.Utility private const int rounds_to_complete_certified = 20; - private int round; - private int correctCount; - private int targetRoundCount = rounds_to_complete; + private int attemptsAtCurrentDifficulty; + private int correctAtCurrentDifficulty; + private int totalRoundForNextResultsScreen = rounds_to_complete; private int difficultyLevel = 1; @@ -199,10 +199,10 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.Clear(); - float successRate = (float)correctCount / targetRoundCount; + float successRate = (float)correctAtCurrentDifficulty / totalRoundForNextResultsScreen; bool isPass = successRate == 1; - statusText.AddParagraph($"You scored {correctCount} out of {targetRoundCount} ({successRate:0%})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); + statusText.AddParagraph($"You scored {correctAtCurrentDifficulty} out of {totalRoundForNextResultsScreen} ({successRate:0%})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); statusText.AddParagraph($"Level {difficultyLevel} ({mapDifficultyToTargetFrameRate(difficultyLevel):N0} hz)", cp => cp.Font = OsuFont.Default.With(size: 24)); @@ -213,18 +213,20 @@ Do whatever you need to try and perceive the difference in latency, then choose if (!isPass && difficultyLevel > 1) { - statusText.AddParagraph("To complete certification, decrease the difficulty level until you can get 20 tests correct in a row!", cp => cp.Font = OsuFont.Default.With(size: 24, weight: FontWeight.SemiBold)); + statusText.AddParagraph("To complete certification, decrease the difficulty level until you can get 20 tests correct in a row!", + cp => cp.Font = OsuFont.Default.With(size: 24, weight: FontWeight.SemiBold)); statusText.AddParagraph(string.Empty); } - statusText.AddParagraph($"Polling: {pollingMax} hz Monitor: {displayMode?.RefreshRate ?? 0:N0} hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15, weight: FontWeight.SemiBold)); + statusText.AddParagraph($"Polling: {pollingMax} hz Monitor: {displayMode?.RefreshRate ?? 0:N0} hz Exclusive: {exclusive}", + cp => cp.Font = OsuFont.Default.With(size: 15, weight: FontWeight.SemiBold)); statusText.AddParagraph($"Input: {host.InputThread.Clock.FramesPerSecond} hz " + $"Update: {host.UpdateThread.Clock.FramesPerSecond} hz " + $"Draw: {host.DrawThread.Clock.FramesPerSecond} hz" , cp => cp.Font = OsuFont.Default.With(size: 15, weight: FontWeight.SemiBold)); - int certificationRemaining = !isPass ? rounds_to_complete_certified : rounds_to_complete_certified - correctCount; + int certificationRemaining = !isPass ? rounds_to_complete_certified : rounds_to_complete_certified - correctAtCurrentDifficulty; if (isPass && certificationRemaining <= 0) { @@ -320,7 +322,7 @@ Do whatever you need to try and perceive the difference in latency, then choose Action = () => { resultsArea.Clear(); - targetRoundCount += rounds_to_complete; + totalRoundForNextResultsScreen += rounds_to_complete; loadNextRound(); }, TooltipText = isPass ? $"Chain {rounds_to_complete_certified} to confirm your perception!" : "You've reached your limits. Go to the previous level to complete certification!", @@ -336,12 +338,13 @@ Do whatever you need to try and perceive the difference in latency, then choose resultsArea.Clear(); - correctCount = 0; - round = 0; + correctAtCurrentDifficulty = 0; + attemptsAtCurrentDifficulty = 0; + pollingMax = 0; lastPoll = 0; - targetRoundCount = rounds_to_complete; + totalRoundForNextResultsScreen = rounds_to_complete; difficultyLevel = difficulty; loadNextRound(); @@ -349,8 +352,8 @@ Do whatever you need to try and perceive the difference in latency, then choose private void loadNextRound() { - round++; - statusText.Text = $"Level {difficultyLevel}\nRound {round} of {targetRoundCount}"; + attemptsAtCurrentDifficulty++; + statusText.Text = $"Level {difficultyLevel}\nRound {attemptsAtCurrentDifficulty} of {totalRoundForNextResultsScreen}"; mainArea.Clear(); @@ -389,9 +392,9 @@ Do whatever you need to try and perceive the difference in latency, then choose explanatoryText.FadeOut(500, Easing.OutQuint); if (correct) - correctCount++; + correctAtCurrentDifficulty++; - if (round < targetRoundCount) + if (attemptsAtCurrentDifficulty < totalRoundForNextResultsScreen) loadNextRound(); else showResults(); From 5b8bd24140e08e468e751e5746c65b2349cf2603 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 14:25:15 +0900 Subject: [PATCH 26/32] Simplify text when reaching maximum supported level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Screens/Utility/LatencyCertifierScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index 2602238820..678a2855a7 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -282,7 +282,7 @@ Do whatever you need to try and perceive the difference in latency, then choose if (!isPass) cannotIncreaseReason = "You didn't get a perfect score."; else if (mapDifficultyToTargetFrameRate(difficultyLevel + 1) > target_host_update_frames) - cannotIncreaseReason = "You've reached the limits of this comparison mode."; + cannotIncreaseReason = "You've reached the maximum level."; else if (mapDifficultyToTargetFrameRate(difficultyLevel + 1) > Clock.FramesPerSecond) cannotIncreaseReason = "Game is not running fast enough to test this level"; From f71343c880294fa905bd728fe288ea8db5fff0fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 14:28:46 +0900 Subject: [PATCH 27/32] Fix box colour getting stuck when changing active mode --- osu.Game/Screens/Utility/LatencyArea.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Utility/LatencyArea.cs b/osu.Game/Screens/Utility/LatencyArea.cs index a2991d3fa8..2ef48bb571 100644 --- a/osu.Game/Screens/Utility/LatencyArea.cs +++ b/osu.Game/Screens/Utility/LatencyArea.cs @@ -145,6 +145,7 @@ namespace osu.Game.Screens.Utility if (!isActive.Value) { lastFrameTime = null; + box.Colour = overlayColourProvider.Colour1; return; } From eb16de9c718b7374753ba5f8ab55a273f7d40af7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 14:38:04 +0900 Subject: [PATCH 28/32] Use upper-case "Hz" --- osu.Game/Screens/Utility/LatencyCertifierScreen.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index 678a2855a7..41952faf25 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -203,7 +203,7 @@ Do whatever you need to try and perceive the difference in latency, then choose bool isPass = successRate == 1; statusText.AddParagraph($"You scored {correctAtCurrentDifficulty} out of {totalRoundForNextResultsScreen} ({successRate:0%})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); - statusText.AddParagraph($"Level {difficultyLevel} ({mapDifficultyToTargetFrameRate(difficultyLevel):N0} hz)", + statusText.AddParagraph($"Level {difficultyLevel} ({mapDifficultyToTargetFrameRate(difficultyLevel):N0} Hz)", cp => cp.Font = OsuFont.Default.With(size: 24)); statusText.AddParagraph(string.Empty); @@ -218,12 +218,12 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.AddParagraph(string.Empty); } - statusText.AddParagraph($"Polling: {pollingMax} hz Monitor: {displayMode?.RefreshRate ?? 0:N0} hz Exclusive: {exclusive}", + statusText.AddParagraph($"Polling: {pollingMax} Hz Monitor: {displayMode?.RefreshRate ?? 0:N0} Hz Exclusive: {exclusive}", cp => cp.Font = OsuFont.Default.With(size: 15, weight: FontWeight.SemiBold)); - statusText.AddParagraph($"Input: {host.InputThread.Clock.FramesPerSecond} hz " - + $"Update: {host.UpdateThread.Clock.FramesPerSecond} hz " - + $"Draw: {host.DrawThread.Clock.FramesPerSecond} hz" + statusText.AddParagraph($"Input: {host.InputThread.Clock.FramesPerSecond} Hz " + + $"Update: {host.UpdateThread.Clock.FramesPerSecond} Hz " + + $"Draw: {host.DrawThread.Clock.FramesPerSecond} Hz" , cp => cp.Font = OsuFont.Default.With(size: 15, weight: FontWeight.SemiBold)); int certificationRemaining = !isPass ? rounds_to_complete_certified : rounds_to_complete_certified - correctAtCurrentDifficulty; @@ -257,7 +257,7 @@ Do whatever you need to try and perceive the difference in latency, then choose }), new OsuSpriteText { - Text = $"You should use a frame limiter with update rate of {mapDifficultyToTargetFrameRate(difficultyLevel + 1)} hz (or fps) for best results!", + Text = $"You should use a frame limiter with update rate of {mapDifficultyToTargetFrameRate(difficultyLevel + 1)} Hz (or fps) for best results!", Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.Torus.With(size: 24, weight: FontWeight.SemiBold), From 7d8601090336f41df99676b0b8fc79e35be20225 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 14:41:22 +0900 Subject: [PATCH 29/32] Fix test regression --- .../Visual/Settings/TestSceneLatencyCertifierScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs index 6d8c6d3c54..dd287c4f6a 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Settings { var latencyArea = latencyCertifier .ChildrenOfType() - .SingleOrDefault(a => a.TargetFrameRate == 0); + .SingleOrDefault(a => a.TargetFrameRate == null); // reached results if (latencyArea == null) From 5541ebc76b438d0caa56060a73b9e3078b743258 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 15:02:26 +0900 Subject: [PATCH 30/32] Revert `OsuButton` changes --- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- osu.Game/Screens/Utility/ButtonWithKeyBind.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 044df13152..08514d94c3 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface /// public class OsuButton : Button { - public virtual LocalisableString Text + public LocalisableString Text { get => SpriteText?.Text ?? default; set diff --git a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs index 20e39ffa6a..ef87e0bca7 100644 --- a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs +++ b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Utility this.key = key; } - public override LocalisableString Text + public new LocalisableString Text { get => base.Text; set => base.Text = $"{value} (Press {key.ToString().Replace("Number", string.Empty)})"; From e0644f27262daa99187180a74211cfe8dcbf42be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 15:19:10 +0900 Subject: [PATCH 31/32] Simplify flow of progression to be linear --- .../TestSceneLatencyCertifierScreen.cs | 34 ++- .../Screens/Utility/LatencyCertifierScreen.cs | 204 ++++++++++-------- 2 files changed, 142 insertions(+), 96 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs index dd287c4f6a..81faf31c69 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs @@ -29,22 +29,46 @@ namespace osu.Game.Tests.Visual.Settings { for (int i = 0; i < 4; i++) { - clickCorrectUntilResults(); - AddAssert("check at results", () => !latencyCertifier.ChildrenOfType().Any()); - AddStep("hit c to continue", () => InputManager.Key(Key.C)); + int difficulty = i + 1; + + checkDifficulty(difficulty); + clickUntilResults(true); + continueFromResults(); } + checkDifficulty(5); + clickUntilResults(false); + continueFromResults(); + checkDifficulty(4); + + clickUntilResults(false); + continueFromResults(); + checkDifficulty(3); + + clickUntilResults(true); AddAssert("check at results", () => !latencyCertifier.ChildrenOfType().Any()); AddAssert("check no buttons", () => !latencyCertifier.ChildrenOfType().Any()); + checkDifficulty(3); } - private void clickCorrectUntilResults() + private void continueFromResults() + { + AddAssert("check at results", () => !latencyCertifier.ChildrenOfType().Any()); + AddStep("hit enter to continue", () => InputManager.Key(Key.Enter)); + } + + private void checkDifficulty(int difficulty) + { + AddAssert($"difficulty is {difficulty}", () => latencyCertifier.DifficultyLevel == difficulty); + } + + private void clickUntilResults(bool clickCorrect) { AddUntilStep("click correct button until results", () => { var latencyArea = latencyCertifier .ChildrenOfType() - .SingleOrDefault(a => a.TargetFrameRate == null); + .SingleOrDefault(a => clickCorrect ? a.TargetFrameRate == null : a.TargetFrameRate != null); // reached results if (latencyArea == null) diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index 41952faf25..0a9d98450f 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -66,11 +66,17 @@ namespace osu.Game.Screens.Utility private const int rounds_to_complete_certified = 20; + /// + /// Whether we are now in certification mode and decreasing difficulty. + /// + private bool isCertifying; + + private int totalRoundForNextResultsScreen => isCertifying ? rounds_to_complete_certified : rounds_to_complete; + private int attemptsAtCurrentDifficulty; private int correctAtCurrentDifficulty; - private int totalRoundForNextResultsScreen = rounds_to_complete; - private int difficultyLevel = 1; + public int DifficultyLevel { get; private set; } = 1; private double lastPoll; private int pollingMax; @@ -199,11 +205,11 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.Clear(); - float successRate = (float)correctAtCurrentDifficulty / totalRoundForNextResultsScreen; + float successRate = (float)correctAtCurrentDifficulty / attemptsAtCurrentDifficulty; bool isPass = successRate == 1; - statusText.AddParagraph($"You scored {correctAtCurrentDifficulty} out of {totalRoundForNextResultsScreen} ({successRate:0%})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); - statusText.AddParagraph($"Level {difficultyLevel} ({mapDifficultyToTargetFrameRate(difficultyLevel):N0} Hz)", + statusText.AddParagraph($"You scored {correctAtCurrentDifficulty} out of {attemptsAtCurrentDifficulty} ({successRate:0%})!", cp => cp.Colour = isPass ? colours.Green : colours.Red); + statusText.AddParagraph($"Level {DifficultyLevel} ({mapDifficultyToTargetFrameRate(DifficultyLevel):N0} Hz)", cp => cp.Font = OsuFont.Default.With(size: 24)); statusText.AddParagraph(string.Empty); @@ -211,9 +217,9 @@ Do whatever you need to try and perceive the difference in latency, then choose statusText.AddIcon(isPass ? FontAwesome.Regular.CheckCircle : FontAwesome.Regular.TimesCircle, cp => cp.Colour = isPass ? colours.Green : colours.Red); statusText.AddParagraph(string.Empty); - if (!isPass && difficultyLevel > 1) + if (!isPass && DifficultyLevel > 1) { - statusText.AddParagraph("To complete certification, decrease the difficulty level until you can get 20 tests correct in a row!", + statusText.AddParagraph("To complete certification, the difficulty level will now decrease until you can get 20 rounds correct in a row!", cp => cp.Font = OsuFont.Default.With(size: 24, weight: FontWeight.SemiBold)); statusText.AddParagraph(string.Empty); } @@ -226,67 +232,22 @@ Do whatever you need to try and perceive the difference in latency, then choose + $"Draw: {host.DrawThread.Clock.FramesPerSecond} Hz" , cp => cp.Font = OsuFont.Default.With(size: 15, weight: FontWeight.SemiBold)); - int certificationRemaining = !isPass ? rounds_to_complete_certified : rounds_to_complete_certified - correctAtCurrentDifficulty; - - if (isPass && certificationRemaining <= 0) + if (isCertifying && isPass) { - Drawable background; - Drawable certifiedText; - - resultsArea.AddRange(new[] - { - background = new Box - { - Colour = overlayColourProvider.Background4, - RelativeSizeAxes = Axes.Both, - }, - (certifiedText = new OsuSpriteText - { - Alpha = 0, - Font = OsuFont.TorusAlternate.With(size: 80, weight: FontWeight.Bold), - Text = "Certified!", - Blending = BlendingParameters.Additive, - }).WithEffect(new GlowEffect - { - Colour = overlayColourProvider.Colour1, - PadExtent = true - }).With(e => - { - e.Anchor = Anchor.Centre; - e.Origin = Anchor.Centre; - }), - new OsuSpriteText - { - Text = $"You should use a frame limiter with update rate of {mapDifficultyToTargetFrameRate(difficultyLevel + 1)} Hz (or fps) for best results!", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.Torus.With(size: 24, weight: FontWeight.SemiBold), - Y = 80, - } - }); - - background.FadeInFromZero(1000, Easing.OutQuint); - - certifiedText.FadeInFromZero(500, Easing.InQuint); - - certifiedText - .ScaleTo(10) - .ScaleTo(1, 600, Easing.InQuad) - .Then() - .ScaleTo(1.05f, 10000, Easing.OutQuint); + showCertifiedScreen(); return; } string cannotIncreaseReason = string.Empty; - if (!isPass) - cannotIncreaseReason = "You didn't get a perfect score."; - else if (mapDifficultyToTargetFrameRate(difficultyLevel + 1) > target_host_update_frames) + if (mapDifficultyToTargetFrameRate(DifficultyLevel + 1) > target_host_update_frames) cannotIncreaseReason = "You've reached the maximum level."; - else if (mapDifficultyToTargetFrameRate(difficultyLevel + 1) > Clock.FramesPerSecond) + else if (mapDifficultyToTargetFrameRate(DifficultyLevel + 1) > Clock.FramesPerSecond) cannotIncreaseReason = "Game is not running fast enough to test this level"; - resultsArea.Add(new FillFlowContainer + FillFlowContainer buttonFlow; + + resultsArea.Add(buttonFlow = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -294,42 +255,104 @@ Do whatever you need to try and perceive the difference in latency, then choose Origin = Anchor.BottomLeft, Spacing = new Vector2(20), Padding = new MarginPadding(20), - Children = new Drawable[] + }); + + if (isPass) + { + buttonFlow.Add(new ButtonWithKeyBind(Key.Enter) { - new ButtonWithKeyBind(Key.Enter) + Text = "Continue to next level", + BackgroundColour = colours.Green, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Action = () => changeDifficulty(DifficultyLevel + 1), + Enabled = { Value = string.IsNullOrEmpty(cannotIncreaseReason) }, + TooltipText = cannotIncreaseReason + }); + } + else + { + if (DifficultyLevel == 1) + { + buttonFlow.Add(new ButtonWithKeyBind(Key.Enter) { - Text = "Continue to next level", - BackgroundColour = colours.Red2, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Action = () => changeDifficulty(difficultyLevel + 1), - Enabled = { Value = string.IsNullOrEmpty(cannotIncreaseReason) }, - TooltipText = cannotIncreaseReason - }, - new ButtonWithKeyBind(Key.D) - { - Text = difficultyLevel == 1 ? "Retry" : "Return to last level", - BackgroundColour = colours.Green, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Action = () => changeDifficulty(Math.Max(difficultyLevel - 1, 1)), - }, - new ButtonWithKeyBind(Key.C) - { - Text = $"Continue towards certification at this level ({certificationRemaining} more)", + Text = "Retry", + TooltipText = "Are you even trying..?", + BackgroundColour = colours.Pink2, Anchor = Anchor.Centre, Origin = Anchor.Centre, Action = () => { - resultsArea.Clear(); - totalRoundForNextResultsScreen += rounds_to_complete; - loadNextRound(); + isCertifying = false; + changeDifficulty(1); }, - TooltipText = isPass ? $"Chain {rounds_to_complete_certified} to confirm your perception!" : "You've reached your limits. Go to the previous level to complete certification!", - Enabled = { Value = isPass }, - }, + }); + } + else + { + buttonFlow.Add(new ButtonWithKeyBind(Key.Enter) + { + Text = "Begin certification at last level", + BackgroundColour = colours.Yellow, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Action = () => + { + isCertifying = true; + changeDifficulty(DifficultyLevel - 1); + }, + TooltipText = isPass ? $"Chain {rounds_to_complete_certified} rounds to confirm your perception!" : "You've reached your limits. Go to the previous level to complete certification!", + }); + } + } + } + + private void showCertifiedScreen() + { + Drawable background; + Drawable certifiedText; + + resultsArea.AddRange(new[] + { + background = new Box + { + Colour = overlayColourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + (certifiedText = new OsuSpriteText + { + Alpha = 0, + Font = OsuFont.TorusAlternate.With(size: 80, weight: FontWeight.Bold), + Text = "Certified!", + Blending = BlendingParameters.Additive, + }).WithEffect(new GlowEffect + { + Colour = overlayColourProvider.Colour1, + PadExtent = true + }).With(e => + { + e.Anchor = Anchor.Centre; + e.Origin = Anchor.Centre; + }), + new OsuSpriteText + { + Text = $"You should use a frame limiter with update rate of {mapDifficultyToTargetFrameRate(DifficultyLevel + 1)} Hz (or fps) for best results!", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Torus.With(size: 24, weight: FontWeight.SemiBold), + Y = 80, } }); + + background.FadeInFromZero(1000, Easing.OutQuint); + + certifiedText.FadeInFromZero(500, Easing.InQuint); + + certifiedText + .ScaleTo(10) + .ScaleTo(1, 600, Easing.InQuad) + .Then() + .ScaleTo(1.05f, 10000, Easing.OutQuint); } private void changeDifficulty(int difficulty) @@ -344,8 +367,7 @@ Do whatever you need to try and perceive the difference in latency, then choose pollingMax = 0; lastPoll = 0; - totalRoundForNextResultsScreen = rounds_to_complete; - difficultyLevel = difficulty; + DifficultyLevel = difficulty; loadNextRound(); } @@ -353,7 +375,7 @@ Do whatever you need to try and perceive the difference in latency, then choose private void loadNextRound() { attemptsAtCurrentDifficulty++; - statusText.Text = $"Level {difficultyLevel}\nRound {attemptsAtCurrentDifficulty} of {totalRoundForNextResultsScreen}"; + statusText.Text = $"Level {DifficultyLevel}\nRound {attemptsAtCurrentDifficulty} of {totalRoundForNextResultsScreen}"; mainArea.Clear(); @@ -361,13 +383,13 @@ Do whatever you need to try and perceive the difference in latency, then choose mainArea.AddRange(new[] { - new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(difficultyLevel) : (int?)null) + new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(DifficultyLevel) : (int?)null) { Width = 0.5f, IsActiveArea = { Value = true }, ReportUserBest = () => recordResult(betterSide == 0), }, - new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(difficultyLevel) : (int?)null) + new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(DifficultyLevel) : (int?)null) { Width = 0.5f, Anchor = Anchor.TopRight, From 936b38e0c54f878442dae0b670148f16931d0ff0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Jun 2022 16:13:53 +0900 Subject: [PATCH 32/32] Reduce test coverage to a point where headless tests will run correctly --- .../TestSceneLatencyCertifierScreen.cs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs index 81faf31c69..af6681e9cf 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs @@ -27,28 +27,19 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestCertification() { - for (int i = 0; i < 4; i++) - { - int difficulty = i + 1; - - checkDifficulty(difficulty); - clickUntilResults(true); - continueFromResults(); - } - - checkDifficulty(5); - clickUntilResults(false); + checkDifficulty(1); + clickUntilResults(true); continueFromResults(); - checkDifficulty(4); + checkDifficulty(2); clickUntilResults(false); continueFromResults(); - checkDifficulty(3); + checkDifficulty(1); clickUntilResults(true); AddAssert("check at results", () => !latencyCertifier.ChildrenOfType().Any()); AddAssert("check no buttons", () => !latencyCertifier.ChildrenOfType().Any()); - checkDifficulty(3); + checkDifficulty(1); } private void continueFromResults()