From 19e3c5d33c5495cc17180932806db5e3a1c34c14 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 13:59:24 +0900 Subject: [PATCH 1/7] Adjust song select background dimming to be more evenly applied --- osu.Game/Screens/Select/SongSelect.cs | 2 ++ osu.Game/Screens/Select/WedgeBackground.cs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 8786821c77..5c4a42852c 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -767,6 +767,8 @@ namespace osu.Game.Screens.Select { backgroundModeBeatmap.Beatmap = beatmap; backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; + backgroundModeBeatmap.IgnoreUserSettings.Value = true; + backgroundModeBeatmap.DimWhenUserSettingsIgnored.Value = 0.4f; backgroundModeBeatmap.FadeColour(Color4.White, 250); }); diff --git a/osu.Game/Screens/Select/WedgeBackground.cs b/osu.Game/Screens/Select/WedgeBackground.cs index da12c1a67a..fd4b91bf5f 100644 --- a/osu.Game/Screens/Select/WedgeBackground.cs +++ b/osu.Game/Screens/Select/WedgeBackground.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.Both, Size = new Vector2(1, 0.5f), - Colour = Color4.Black.Opacity(0.5f), + Colour = Color4.Black.Opacity(0.2f), Shear = new Vector2(0.15f, 0), EdgeSmoothness = new Vector2(2, 0), }, @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Select RelativePositionAxes = Axes.Y, Size = new Vector2(1, -0.5f), Position = new Vector2(0, 1), - Colour = Color4.Black.Opacity(0.5f), + Colour = Color4.Black.Opacity(0.2f), Shear = new Vector2(-0.15f, 0), EdgeSmoothness = new Vector2(2, 0), }, From 9ed068c1e67e870f49163620cf95697c5426a108 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 14:16:34 +0900 Subject: [PATCH 2/7] Only apply dim changes when background blur is disabled --- osu.Game/Graphics/Containers/UserDimContainer.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 16 +++++++++++++--- osu.Game/Screens/Select/WedgeBackground.cs | 9 +++------ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs index 25830c9d54..6f6292c3b2 100644 --- a/osu.Game/Graphics/Containers/UserDimContainer.cs +++ b/osu.Game/Graphics/Containers/UserDimContainer.cs @@ -21,7 +21,7 @@ namespace osu.Game.Graphics.Containers /// public const float BREAK_LIGHTEN_AMOUNT = 0.3f; - protected const double BACKGROUND_FADE_DURATION = 800; + public const double BACKGROUND_FADE_DURATION = 800; /// /// Whether or not user-configured settings relating to brightness of elements should be ignored diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 5c4a42852c..8546dfeeaa 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -31,6 +31,7 @@ using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; @@ -148,7 +149,7 @@ namespace osu.Game.Screens.Select if (!this.IsCurrentScreen()) return; - ApplyToBackground(b => b.BlurAmount.Value = e.NewValue ? BACKGROUND_BLUR : 0); + ApplyToBackground(applyBlurToBackground); }); LoadComponentAsync(Carousel = new BeatmapCarousel @@ -194,6 +195,7 @@ namespace osu.Game.Screens.Select { ParallaxAmount = 0.005f, RelativeSizeAxes = Axes.Both, + Alpha = 0, Anchor = Anchor.Centre, Origin = Anchor.Centre, Child = new WedgeBackground @@ -766,10 +768,10 @@ namespace osu.Game.Screens.Select ApplyToBackground(backgroundModeBeatmap => { backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; backgroundModeBeatmap.IgnoreUserSettings.Value = true; - backgroundModeBeatmap.DimWhenUserSettingsIgnored.Value = 0.4f; backgroundModeBeatmap.FadeColour(Color4.White, 250); + + applyBlurToBackground(backgroundModeBeatmap); }); beatmapInfoWedge.Beatmap = beatmap; @@ -787,6 +789,14 @@ namespace osu.Game.Screens.Select } } + private void applyBlurToBackground(BackgroundScreenBeatmap backgroundModeBeatmap) + { + backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; + backgroundModeBeatmap.DimWhenUserSettingsIgnored.Value = configBackgroundBlur.Value ? 0 : 0.4f; + + wedgeBackground.FadeTo(configBackgroundBlur.Value ? 0.5f : 0.2f, UserDimContainer.BACKGROUND_FADE_DURATION, Easing.OutQuint); + } + private readonly WeakReference lastTrack = new WeakReference(null); /// diff --git a/osu.Game/Screens/Select/WedgeBackground.cs b/osu.Game/Screens/Select/WedgeBackground.cs index fd4b91bf5f..2e2b43cd70 100644 --- a/osu.Game/Screens/Select/WedgeBackground.cs +++ b/osu.Game/Screens/Select/WedgeBackground.cs @@ -1,14 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osuTK; using osuTK.Graphics; -using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Select { @@ -22,7 +19,7 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.Both, Size = new Vector2(1, 0.5f), - Colour = Color4.Black.Opacity(0.2f), + Colour = Color4.Black, Shear = new Vector2(0.15f, 0), EdgeSmoothness = new Vector2(2, 0), }, @@ -32,7 +29,7 @@ namespace osu.Game.Screens.Select RelativePositionAxes = Axes.Y, Size = new Vector2(1, -0.5f), Position = new Vector2(0, 1), - Colour = Color4.Black.Opacity(0.2f), + Colour = Color4.Black, Shear = new Vector2(-0.15f, 0), EdgeSmoothness = new Vector2(2, 0), }, From 9d02a2ef0e8a17398459403ac71353d4688ad4ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 17:37:46 +0900 Subject: [PATCH 3/7] Apply NRT to `GamepleSampleTriggerSource` tests --- .../Gameplay/TestSceneGameplaySampleTriggerSource.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index e184d50d7c..a9b469fd86 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Game.Audio; @@ -20,10 +18,10 @@ namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneGameplaySampleTriggerSource : PlayerTestScene { - private TestGameplaySampleTriggerSource sampleTriggerSource; + private TestGameplaySampleTriggerSource sampleTriggerSource = null!; protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); - private Beatmap beatmap; + private Beatmap beatmap = null!; protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { @@ -80,7 +78,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestCorrectHitObject() { - HitObjectLifetimeEntry nextObjectEntry = null; + HitObjectLifetimeEntry? nextObjectEntry = null; AddAssert("no alive objects", () => getNextAliveObject() == null); @@ -103,7 +101,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("hit first hitobject", () => { InputManager.Click(MouseButton.Left); - return nextObjectEntry.Result?.HasResult == true; + return nextObjectEntry?.Result?.HasResult == true; }); AddAssert("check correct object after hit", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[1]); @@ -115,7 +113,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("check correct object after none alive", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); } - private DrawableHitObject getNextAliveObject() => + private DrawableHitObject? getNextAliveObject() => Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.FirstOrDefault(); [Test] From 979c079f8b5f852575e9722303173d28facbd31a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 17:58:32 +0900 Subject: [PATCH 4/7] Refactor `GameplaySampleTriggerSource` test to not be realtime dependent --- .../TestSceneGameplaySampleTriggerSource.cs | 79 +++++++++++++------ 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index a9b469fd86..e7bdf7b9ba 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -1,8 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Diagnostics; using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Timing; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -12,6 +16,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.UI; +using osu.Game.Storyboards; using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay @@ -23,6 +28,12 @@ namespace osu.Game.Tests.Visual.Gameplay private Beatmap beatmap = null!; + [Resolved] + private AudioManager audio { get; set; } = null!; + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null) + => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audio); + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { beatmap = new Beatmap @@ -37,12 +48,13 @@ namespace osu.Game.Tests.Visual.Gameplay const double start_offset = 8000; const double spacing = 2000; + // intentionally start objects a bit late so we can test the case of no alive objects. double t = start_offset; + beatmap.HitObjects.AddRange(new[] { new HitCircle { - // intentionally start objects a bit late so we can test the case of no alive objects. StartTime = t += spacing, Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) } }, @@ -78,41 +90,64 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestCorrectHitObject() { - HitObjectLifetimeEntry? nextObjectEntry = null; + waitForAliveObjectIndex(null); - AddAssert("no alive objects", () => getNextAliveObject() == null); + seekBeforeIndex(0); + waitForAliveObjectIndex(0); + checkValidObjectIndex(0); - AddAssert("check initially correct object", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[0]); + AddAssert("first object not hit", () => getNextAliveObject()?.Entry?.Result?.HasResult != true); - AddUntilStep("get next object", () => + AddStep("hit first object", () => { - var nextDrawableObject = getNextAliveObject(); + var next = getNextAliveObject(); - if (nextDrawableObject != null) + if (next != null) { - nextObjectEntry = nextDrawableObject.Entry; - InputManager.MoveMouseTo(nextDrawableObject.ScreenSpaceDrawQuad.Centre); - return true; + Debug.Assert(next.Entry?.Result?.HasResult != true); + + InputManager.MoveMouseTo(next.ScreenSpaceDrawQuad.Centre); + InputManager.Click(MouseButton.Left); } - - return false; }); - AddUntilStep("hit first hitobject", () => - { - InputManager.Click(MouseButton.Left); - return nextObjectEntry?.Result?.HasResult == true; - }); + AddAssert("first object hit", () => getNextAliveObject()?.Entry?.Result?.HasResult == true); - AddAssert("check correct object after hit", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[1]); + checkValidObjectIndex(1); - AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[2]); - AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); + // Still object 1 as it's not hit yet. + seekBeforeIndex(1); + waitForAliveObjectIndex(1); + checkValidObjectIndex(1); - AddUntilStep("no alive objects", () => getNextAliveObject() == null); - AddAssert("check correct object after none alive", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); + seekBeforeIndex(2); + waitForAliveObjectIndex(2); + checkValidObjectIndex(2); + + seekBeforeIndex(3); + waitForAliveObjectIndex(3); + checkValidObjectIndex(3); + + AddStep("Seek into future", () => Beatmap.Value.Track.Seek(beatmap.HitObjects.Last().GetEndTime() + 10000)); + + waitForAliveObjectIndex(null); + checkValidObjectIndex(3); } + private void seekBeforeIndex(int index) => + AddStep($"seek to just before object {index}", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[index].StartTime - 100)); + + private void waitForAliveObjectIndex(int? index) + { + if (index == null) + AddUntilStep("wait for no alive objects", getNextAliveObject, () => Is.Null); + else + AddUntilStep($"wait for next alive to be {index}", () => getNextAliveObject()?.HitObject, () => Is.EqualTo(beatmap.HitObjects[index.Value])); + } + + private void checkValidObjectIndex(int index) => + AddAssert($"check valid object is {index}", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[index])); + private DrawableHitObject? getNextAliveObject() => Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.FirstOrDefault(); From 394d368f165431e7bb58bc4d365ee7f7fbb6614b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 18:45:22 +0900 Subject: [PATCH 5/7] Fix song select potentially updating background parameters when not the current screen --- .../Screens/Play/ScreenWithBeatmapBackground.cs | 11 ++++++++--- osu.Game/Screens/Select/SongSelect.cs | 16 ++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index d6c8a0ad6a..a5d1961bd8 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -1,9 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; +using System.Diagnostics; +using osu.Framework.Screens; using osu.Game.Screens.Backgrounds; namespace osu.Game.Screens.Play @@ -12,6 +12,11 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - public void ApplyToBackground(Action action) => base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b)); + public void ApplyToBackground(Action action) + { + Debug.Assert(this.IsCurrentScreen()); + + base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b)); + } } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 8546dfeeaa..8a9a20261e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -765,14 +765,18 @@ namespace osu.Game.Screens.Select /// The working beatmap. private void updateComponentFromBeatmap(WorkingBeatmap beatmap) { - ApplyToBackground(backgroundModeBeatmap => + // If not the current screen, this will be applied in OnResuming. + if (this.IsCurrentScreen()) { - backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.IgnoreUserSettings.Value = true; - backgroundModeBeatmap.FadeColour(Color4.White, 250); + ApplyToBackground(backgroundModeBeatmap => + { + backgroundModeBeatmap.Beatmap = beatmap; + backgroundModeBeatmap.IgnoreUserSettings.Value = true; + backgroundModeBeatmap.FadeColour(Color4.White, 250); - applyBlurToBackground(backgroundModeBeatmap); - }); + applyBlurToBackground(backgroundModeBeatmap); + }); + } beatmapInfoWedge.Beatmap = beatmap; From 5bdc5dfadde8c7b4d32abbd81e2555718f803366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 16 Feb 2023 19:02:51 +0100 Subject: [PATCH 6/7] Add one more assert to keep coverage from previous implementation --- .../Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index e7bdf7b9ba..6770309a7d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -91,6 +91,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestCorrectHitObject() { waitForAliveObjectIndex(null); + checkValidObjectIndex(0); seekBeforeIndex(0); waitForAliveObjectIndex(0); From ad5132ed4194380bae37331b2746333a5acead3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 16 Feb 2023 20:47:51 +0100 Subject: [PATCH 7/7] Remove redundant conditional access qualifier It is impossible for the callback passed to `ApplyToBackground()` to receive a null reference. See `OsuScreen.ApplyToBackground()` - if the background to call the callback on were `null`, then an `InvalidOperationException` would be thrown instead. --- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index d9062da8aa..4f7e4add32 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -417,7 +417,7 @@ namespace osu.Game.Screens.Play lowPassFilter.CutoffTo(1000, 650, Easing.OutQuint); highPassFilter.CutoffTo(300).Then().CutoffTo(0, 1250); // 1250 is to line up with the appearance of MetadataInfo (750 delay + 500 fade-in) - ApplyToBackground(b => b?.FadeColour(Color4.White, 800, Easing.OutQuint)); + ApplyToBackground(b => b.FadeColour(Color4.White, 800, Easing.OutQuint)); } protected virtual void ContentOut()