From ec2b9165d59a1ebdba6a2703cfa908f406ec931f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 May 2023 16:33:58 +0900 Subject: [PATCH 01/14] Adjust `BeatDivisorControl` test to show control mmuch larger --- osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs index 56b16301be..c3d5ecac5c 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs @@ -42,7 +42,8 @@ namespace osu.Game.Tests.Visual.Editing { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(90, 90) + Size = new Vector2(90, 90), + Scale = new Vector2(3), } }; }); From 87ff28b0220c40691eab57038f98f366b2601986 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 May 2023 16:34:10 +0900 Subject: [PATCH 02/14] Update beat divisor control to show ticks in more visually correct locations As proposed in https://github.com/ppy/osu/discussions/23527. --- .../Edit/Compose/Components/BeatDivisorControl.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 9f422d5aa9..3bfe81e6a7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -410,6 +410,16 @@ namespace osu.Game.Screens.Edit.Compose.Components }); } + // Add a fake 1/1 at the end to give context. + AddInternal(new Tick(1) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.Centre, + Depth = float.MaxValue, + Alpha = 0.05f, + Colour = BindableBeatDivisor.GetColourFor(1, colours), + }); + AddInternal(marker = new Marker()); CurrentNumber.ValueChanged += moveMarker; CurrentNumber.TriggerChange(); @@ -483,7 +493,7 @@ namespace osu.Game.Screens.Edit.Compose.Components OnUserChange(Current.Value); } - private float getMappedPosition(float divisor) => MathF.Pow((divisor - 1) / (beatDivisor.ValidDivisors.Value.Presets.Last() - 1), 0.90f); + private float getMappedPosition(float divisor) => 1 - 1 / divisor; private partial class Tick : Circle { From ebda35c3c9a896861ec526bad90ebc2e154b3131 Mon Sep 17 00:00:00 2001 From: Johannes vd Berg Date: Tue, 23 May 2023 12:57:25 +0200 Subject: [PATCH 03/14] Add ghost ticks to exhibit current divisor on `BeatDivisorControl` --- .../Compose/Components/BeatDivisorControl.cs | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 3bfe81e6a7..431fb2f659 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -398,28 +398,25 @@ namespace osu.Game.Screens.Edit.Compose.Components ClearInternal(); CurrentNumber.ValueChanged -= moveMarker; - foreach (int divisor in beatDivisor.ValidDivisors.Value.Presets) + int largestDivisor = beatDivisor.ValidDivisors.Value.Presets.Max(); + for (int tickIndex = 0; tickIndex <= largestDivisor; tickIndex++) { - AddInternal(new Tick(divisor) + int divisor = largestDivisor; + foreach (int validDivisor in beatDivisor.ValidDivisors.Value.Presets) + { + if (divisor > validDivisor && (tickIndex * validDivisor) % largestDivisor == 0) + divisor = validDivisor; + } + bool solidTick = divisor * (largestDivisor - tickIndex) == largestDivisor; + AddInternal(new Tick(solidTick, divisor) { Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, RelativePositionAxes = Axes.Both, Colour = BindableBeatDivisor.GetColourFor(divisor, colours), - X = getMappedPosition(divisor), + X = tickIndex / (float)largestDivisor, }); } - - // Add a fake 1/1 at the end to give context. - AddInternal(new Tick(1) - { - Anchor = Anchor.CentreRight, - Origin = Anchor.Centre, - Depth = float.MaxValue, - Alpha = 0.05f, - Colour = BindableBeatDivisor.GetColourFor(1, colours), - }); - AddInternal(marker = new Marker()); CurrentNumber.ValueChanged += moveMarker; CurrentNumber.TriggerChange(); @@ -428,6 +425,12 @@ namespace osu.Game.Screens.Edit.Compose.Components private void moveMarker(ValueChangedEvent divisor) { marker.MoveToX(getMappedPosition(divisor.NewValue), 100, Easing.OutQuint); + + foreach (Tick child in InternalChildren.OfType()) + { + float newAlpha = child.Solid ? 1f : divisor.NewValue % child.Divisor == 0 ? 0.2f : 0f; + child.FadeTo(newAlpha); + } } protected override void UpdateValue(float value) @@ -497,8 +500,12 @@ namespace osu.Game.Screens.Edit.Compose.Components private partial class Tick : Circle { - public Tick(int divisor) + public bool Solid; + public int Divisor; + public Tick(bool solid, int divisor) { + Solid = solid; + Divisor = divisor; Size = new Vector2(6f, 12) * BindableBeatDivisor.GetSize(divisor); InternalChild = new Box { RelativeSizeAxes = Axes.Both }; } From 37a796306d65a5c940d8cd715021083bdef9990a Mon Sep 17 00:00:00 2001 From: Gyoshi Date: Tue, 23 May 2023 14:30:35 +0200 Subject: [PATCH 04/14] Small format & comment --- .../Screens/Edit/Compose/Components/BeatDivisorControl.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 431fb2f659..04cc736e7d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -402,13 +402,15 @@ namespace osu.Game.Screens.Edit.Compose.Components for (int tickIndex = 0; tickIndex <= largestDivisor; tickIndex++) { int divisor = largestDivisor; + // Find lowest divisor that the tick fits into foreach (int validDivisor in beatDivisor.ValidDivisors.Value.Presets) { if (divisor > validDivisor && (tickIndex * validDivisor) % largestDivisor == 0) divisor = validDivisor; } - bool solidTick = divisor * (largestDivisor - tickIndex) == largestDivisor; - AddInternal(new Tick(solidTick, divisor) + + bool isSolidTick = divisor * (largestDivisor - tickIndex) == largestDivisor; + AddInternal(new Tick(isSolidTick, divisor) { Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, @@ -417,6 +419,7 @@ namespace osu.Game.Screens.Edit.Compose.Components X = tickIndex / (float)largestDivisor, }); } + AddInternal(marker = new Marker()); CurrentNumber.ValueChanged += moveMarker; CurrentNumber.TriggerChange(); From 1b32370c6a489ec618e7022b197f3c82518a183a Mon Sep 17 00:00:00 2001 From: Gyoshi Date: Tue, 23 May 2023 15:05:38 +0200 Subject: [PATCH 05/14] Remove duplicate code by making `GetDivisorForBeatIndex` method more general --- osu.Game/Screens/Edit/BindableBeatDivisor.cs | 7 +++++-- .../Screens/Edit/Compose/Components/BeatDivisorControl.cs | 8 +------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs index aa8e202e22..f1b97571bd 100644 --- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs +++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs @@ -154,12 +154,15 @@ namespace osu.Game.Screens.Edit /// /// The 0-based beat index. /// The beat divisor. + /// The list of valid divisors which can be chosen from. Assumes ordered from low to high. /// The applicable divisor. - public static int GetDivisorForBeatIndex(int index, int beatDivisor) + public static int GetDivisorForBeatIndex(int index, int beatDivisor, int[] validDivisors = null) { + validDivisors ??= PREDEFINED_DIVISORS; + int beat = index % beatDivisor; - foreach (int divisor in PREDEFINED_DIVISORS) + foreach (int divisor in validDivisors) { if ((beat * divisor) % beatDivisor == 0) return divisor; diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 04cc736e7d..2dd5791943 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -401,13 +401,7 @@ namespace osu.Game.Screens.Edit.Compose.Components int largestDivisor = beatDivisor.ValidDivisors.Value.Presets.Max(); for (int tickIndex = 0; tickIndex <= largestDivisor; tickIndex++) { - int divisor = largestDivisor; - // Find lowest divisor that the tick fits into - foreach (int validDivisor in beatDivisor.ValidDivisors.Value.Presets) - { - if (divisor > validDivisor && (tickIndex * validDivisor) % largestDivisor == 0) - divisor = validDivisor; - } + int divisor = BindableBeatDivisor.GetDivisorForBeatIndex(tickIndex, largestDivisor, (int[])beatDivisor.ValidDivisors.Value.Presets); bool isSolidTick = divisor * (largestDivisor - tickIndex) == largestDivisor; AddInternal(new Tick(isSolidTick, divisor) From 7b1e8ede54498bf66d54965769220dc626240c1f Mon Sep 17 00:00:00 2001 From: Gyoshi Date: Tue, 23 May 2023 15:11:27 +0200 Subject: [PATCH 06/14] Small format --- osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 2dd5791943..1af7d25dcd 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -402,8 +402,8 @@ namespace osu.Game.Screens.Edit.Compose.Components for (int tickIndex = 0; tickIndex <= largestDivisor; tickIndex++) { int divisor = BindableBeatDivisor.GetDivisorForBeatIndex(tickIndex, largestDivisor, (int[])beatDivisor.ValidDivisors.Value.Presets); - bool isSolidTick = divisor * (largestDivisor - tickIndex) == largestDivisor; + AddInternal(new Tick(isSolidTick, divisor) { Anchor = Anchor.CentreLeft, From 921d7e4d89351a50fe6ec4e65f1ec01b3d650a36 Mon Sep 17 00:00:00 2001 From: Gyoshi Date: Tue, 23 May 2023 16:46:08 +0200 Subject: [PATCH 07/14] More fitting tests for new layout --- .../Editing/TestSceneBeatDivisorControl.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs index c3d5ecac5c..b74e9f436b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs @@ -65,17 +65,24 @@ namespace osu.Game.Tests.Visual.Editing InputManager.MoveMouseTo(tickMarkerHead.ScreenSpaceDrawQuad.Centre); InputManager.PressButton(MouseButton.Left); }); - AddStep("move to 8 and release", () => + AddStep("move to 1", () => InputManager.MoveMouseTo(getPositionForDivisor(1))); + AddStep("move to 16 and release", () => { - InputManager.MoveMouseTo(tickSliderBar.ScreenSpaceDrawQuad.Centre); + InputManager.MoveMouseTo(getPositionForDivisor(16)); InputManager.ReleaseButton(MouseButton.Left); }); - AddAssert("divisor is 8", () => bindableBeatDivisor.Value == 8); + AddAssert("divisor is 16", () => bindableBeatDivisor.Value == 16); AddStep("hold marker", () => InputManager.PressButton(MouseButton.Left)); - AddStep("move to 16", () => InputManager.MoveMouseTo(getPositionForDivisor(16))); - AddStep("move to ~10 and release", () => + AddStep("move to ~6 and release", () => + { + InputManager.MoveMouseTo(getPositionForDivisor(6)); + InputManager.ReleaseButton(MouseButton.Left); + }); + AddAssert("divisor clamped to 8", () => bindableBeatDivisor.Value == 8); + AddStep("move to ~10 and click", () => { InputManager.MoveMouseTo(getPositionForDivisor(10)); + InputManager.PressButton(MouseButton.Left); InputManager.ReleaseButton(MouseButton.Left); }); AddAssert("divisor clamped to 8", () => bindableBeatDivisor.Value == 8); From fa00f8b92a56db6669835efa70131e69308c9f67 Mon Sep 17 00:00:00 2001 From: Gyoshi Date: Tue, 23 May 2023 16:46:40 +0200 Subject: [PATCH 08/14] replace manual code with existing method --- .../Visual/Editing/TestSceneBeatDivisorControl.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs index b74e9f436b..a4b36ef93a 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs @@ -90,12 +90,11 @@ namespace osu.Game.Tests.Visual.Editing private Vector2 getPositionForDivisor(int divisor) { - float relativePosition = (float)Math.Clamp(divisor, 0, 16) / 16; - var sliderDrawQuad = tickSliderBar.ScreenSpaceDrawQuad; - return new Vector2( - sliderDrawQuad.TopLeft.X + sliderDrawQuad.Width * relativePosition, - sliderDrawQuad.Centre.Y - ); + float localX = 1 - 1 / (float)divisor; + return tickSliderBar.ToScreenSpace(new Vector2( + localX, + 0.5f + )); } [Test] From b5f8093941873b6aa95bc62a61f7eb5d29e9ce52 Mon Sep 17 00:00:00 2001 From: Gyoshi Date: Tue, 23 May 2023 17:59:07 +0200 Subject: [PATCH 09/14] Use `RangePadding` to align mouse with slider --- osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs | 4 ++-- .../Screens/Edit/Compose/Components/BeatDivisorControl.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs index a4b36ef93a..353acfa4ba 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs @@ -90,10 +90,10 @@ namespace osu.Game.Tests.Visual.Editing private Vector2 getPositionForDivisor(int divisor) { - float localX = 1 - 1 / (float)divisor; + float localX = (1 - 1 / (float)divisor) * tickSliderBar.UsableWidth + tickSliderBar.RangePadding; return tickSliderBar.ToScreenSpace(new Vector2( localX, - 0.5f + tickSliderBar.DrawHeight / 2 )); } diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 3bfe81e6a7..cec9806e94 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -383,7 +383,8 @@ namespace osu.Game.Screens.Edit.Compose.Components { CurrentNumber.BindTo(this.beatDivisor = beatDivisor); - Padding = new MarginPadding { Horizontal = 5 }; + RangePadding = 5; + Padding = new MarginPadding { Horizontal = RangePadding }; } protected override void LoadComplete() From c5ef3ae1811f9216c2023c92de67ae2d548f4a66 Mon Sep 17 00:00:00 2001 From: Gyoshi Date: Tue, 23 May 2023 18:44:20 +0200 Subject: [PATCH 10/14] Code styling --- .../Screens/Edit/Compose/Components/BeatDivisorControl.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 1af7d25dcd..4c3c9872a0 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -425,7 +425,7 @@ namespace osu.Game.Screens.Edit.Compose.Components foreach (Tick child in InternalChildren.OfType()) { - float newAlpha = child.Solid ? 1f : divisor.NewValue % child.Divisor == 0 ? 0.2f : 0f; + float newAlpha = child.IsSolid ? 1f : divisor.NewValue % child.Divisor == 0 ? 0.2f : 0f; child.FadeTo(newAlpha); } } @@ -497,11 +497,11 @@ namespace osu.Game.Screens.Edit.Compose.Components private partial class Tick : Circle { - public bool Solid; + public bool IsSolid; public int Divisor; - public Tick(bool solid, int divisor) + public Tick(bool isSolid, int divisor) { - Solid = solid; + IsSolid = isSolid; Divisor = divisor; Size = new Vector2(6f, 12) * BindableBeatDivisor.GetSize(divisor); InternalChild = new Box { RelativeSizeAxes = Axes.Both }; From 7fe19d1992633fc13e3cf68c35fb21e3734d39dd Mon Sep 17 00:00:00 2001 From: Gyoshi Date: Tue, 23 May 2023 18:45:49 +0200 Subject: [PATCH 11/14] `Last` instead of `Max` divisor to match code elsewhere --- osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 4c3c9872a0..4982ab9ef2 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -398,7 +398,7 @@ namespace osu.Game.Screens.Edit.Compose.Components ClearInternal(); CurrentNumber.ValueChanged -= moveMarker; - int largestDivisor = beatDivisor.ValidDivisors.Value.Presets.Max(); + int largestDivisor = beatDivisor.ValidDivisors.Value.Presets.Last(); for (int tickIndex = 0; tickIndex <= largestDivisor; tickIndex++) { int divisor = BindableBeatDivisor.GetDivisorForBeatIndex(tickIndex, largestDivisor, (int[])beatDivisor.ValidDivisors.Value.Presets); From 561b759bf980216beca1ff2639da1018bc05c742 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 May 2023 13:49:29 +0900 Subject: [PATCH 12/14] Tidy up implementation and ensure non-solid ticks start at zero alpha --- .../Compose/Components/BeatDivisorControl.cs | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 07330a6e10..432c5ea280 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -400,12 +400,13 @@ namespace osu.Game.Screens.Edit.Compose.Components CurrentNumber.ValueChanged -= moveMarker; int largestDivisor = beatDivisor.ValidDivisors.Value.Presets.Last(); + for (int tickIndex = 0; tickIndex <= largestDivisor; tickIndex++) { int divisor = BindableBeatDivisor.GetDivisorForBeatIndex(tickIndex, largestDivisor, (int[])beatDivisor.ValidDivisors.Value.Presets); bool isSolidTick = divisor * (largestDivisor - tickIndex) == largestDivisor; - AddInternal(new Tick(isSolidTick, divisor) + AddInternal(new Tick(divisor, isSolidTick) { Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, @@ -424,10 +425,9 @@ namespace osu.Game.Screens.Edit.Compose.Components { marker.MoveToX(getMappedPosition(divisor.NewValue), 100, Easing.OutQuint); - foreach (Tick child in InternalChildren.OfType()) + foreach (Tick tick in InternalChildren.OfType().Where(t => !t.AlwaysDisplayed)) { - float newAlpha = child.IsSolid ? 1f : divisor.NewValue % child.Divisor == 0 ? 0.2f : 0f; - child.FadeTo(newAlpha); + tick.FadeTo(divisor.NewValue % tick.Divisor == 0 ? 0.2f : 0f, 100, Easing.OutQuint); } } @@ -498,13 +498,18 @@ namespace osu.Game.Screens.Edit.Compose.Components private partial class Tick : Circle { - public bool IsSolid; - public int Divisor; - public Tick(bool isSolid, int divisor) + public readonly bool AlwaysDisplayed; + + public readonly int Divisor; + + public Tick(int divisor, bool alwaysDisplayed) { - IsSolid = isSolid; + AlwaysDisplayed = alwaysDisplayed; Divisor = divisor; + Size = new Vector2(6f, 12) * BindableBeatDivisor.GetSize(divisor); + Alpha = alwaysDisplayed ? 1 : 0; + InternalChild = new Box { RelativeSizeAxes = Axes.Both }; } } From 6ec4ecfdd734d7db0cd430055e6c01b5753540d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 24 May 2023 22:17:51 +0200 Subject: [PATCH 13/14] Mention fallback default in `GetDivisorForBeatIndex()` --- osu.Game/Screens/Edit/BindableBeatDivisor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs index f1b97571bd..1da224d850 100644 --- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs +++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs @@ -154,7 +154,7 @@ namespace osu.Game.Screens.Edit /// /// The 0-based beat index. /// The beat divisor. - /// The list of valid divisors which can be chosen from. Assumes ordered from low to high. + /// The list of valid divisors which can be chosen from. Assumes ordered from low to high. Defaults to if omitted. /// The applicable divisor. public static int GetDivisorForBeatIndex(int index, int beatDivisor, int[] validDivisors = null) { From 058edb5d5fe4e5003b045f4aeeabb187a977661f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 May 2023 17:15:31 +0900 Subject: [PATCH 14/14] Centralise beatmap playable duration and bounds lookups --- .../UserInterface/TestSceneSegmentedGraph.cs | 4 +- osu.Game/Beatmaps/BeatmapUpdater.cs | 18 +------- osu.Game/Beatmaps/IBeatmap.cs | 44 +++++++++++++++++++ .../Play/HUD/ArgonSongProgressGraph.cs | 4 +- .../Play/HUD/DefaultSongProgressGraph.cs | 4 +- osu.Game/Screens/Play/HUD/SongProgress.cs | 8 ++-- 6 files changed, 55 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSegmentedGraph.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSegmentedGraph.cs index 1144b9053d..320ec48e07 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSegmentedGraph.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSegmentedGraph.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; +using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu; @@ -137,8 +138,7 @@ namespace osu.Game.Tests.Visual.UserInterface if (!objects.Any()) return; - double firstHit = objects.First().StartTime; - double lastHit = objects.Max(o => o.GetEndTime()); + (double firstHit, double lastHit) = BeatmapExtensions.CalculatePlayableBounds(objects); if (lastHit == 0) lastHit = objects.Last().StartTime; diff --git a/osu.Game/Beatmaps/BeatmapUpdater.cs b/osu.Game/Beatmaps/BeatmapUpdater.cs index af9f32f834..046adb8327 100644 --- a/osu.Game/Beatmaps/BeatmapUpdater.cs +++ b/osu.Game/Beatmaps/BeatmapUpdater.cs @@ -3,7 +3,6 @@ using System; using System.Diagnostics; -using System.Linq; using System.Threading.Tasks; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Logging; @@ -11,7 +10,6 @@ using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Database; using osu.Game.Online.API; -using osu.Game.Rulesets.Objects; namespace osu.Game.Beatmaps { @@ -74,7 +72,7 @@ namespace osu.Game.Beatmaps var calculator = ruleset.CreateDifficultyCalculator(working); beatmap.StarRating = calculator.Calculate().StarRating; - beatmap.Length = calculateLength(working.Beatmap); + beatmap.Length = working.Beatmap.CalculatePlayableLength(); beatmap.BPM = 60000 / working.Beatmap.GetMostCommonBeatLength(); } @@ -82,20 +80,6 @@ namespace osu.Game.Beatmaps workingBeatmapCache.Invalidate(beatmapSet); }); - private double calculateLength(IBeatmap b) - { - if (!b.HitObjects.Any()) - return 0; - - var lastObject = b.HitObjects.Last(); - - //TODO: this isn't always correct (consider mania where a non-last object may last for longer than the last in the list). - double endTime = lastObject.GetEndTime(); - double startTime = b.HitObjects.First().StartTime; - - return endTime - startTime; - } - #region Implementation of IDisposable public void Dispose() diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index f6771f7adf..671f5ce8db 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -104,6 +104,19 @@ namespace osu.Game.Beatmaps } } + /// + /// Find the total milliseconds between the first and last hittable objects. + /// + /// + /// This is cached to , so using that is preferrable when available. + /// + public static double CalculatePlayableLength(this IBeatmap beatmap) => CalculatePlayableLength(beatmap.HitObjects); + + /// + /// Find the timestamps in milliseconds of the start and end of the playable region. + /// + public static (double start, double end) CalculatePlayableBounds(this IBeatmap beatmap) => CalculatePlayableBounds(beatmap.HitObjects); + /// /// Find the absolute end time of the latest in a beatmap. Will throw if beatmap contains no objects. /// @@ -114,5 +127,36 @@ namespace osu.Game.Beatmaps /// It's not super efficient so calls should be kept to a minimum. /// public static double GetLastObjectTime(this IBeatmap beatmap) => beatmap.HitObjects.Max(h => h.GetEndTime()); + + #region Helper methods + + /// + /// Find the total milliseconds between the first and last hittable objects. + /// + /// + /// This is cached to , so using that is preferrable when available. + /// + public static double CalculatePlayableLength(IEnumerable objects) + { + (double start, double end) = CalculatePlayableBounds(objects); + + return end - start; + } + + /// + /// Find the timestamps in milliseconds of the start and end of the playable region. + /// + public static (double start, double end) CalculatePlayableBounds(IEnumerable objects) + { + if (!objects.Any()) + return (0, 0); + + double lastObjectTime = objects.Max(o => o.GetEndTime()); + double firstObjectTime = objects.First().StartTime; + + return (firstObjectTime, lastObjectTime); + } + + #endregion } } diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs index 0899476ed4..63ab9d15e0 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; using osu.Game.Graphics.UserInterface; @@ -26,8 +27,7 @@ namespace osu.Game.Screens.Play.HUD if (!objects.Any()) return; - double firstHit = objects.First().StartTime; - double lastHit = objects.Max(o => o.GetEndTime()); + (double firstHit, double lastHit) = BeatmapExtensions.CalculatePlayableBounds(objects); if (lastHit == 0) lastHit = objects.Last().StartTime; diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgressGraph.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgressGraph.cs index bee5978817..047c64a4a4 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgressGraph.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgressGraph.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Collections.Generic; using System.Diagnostics; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HUD @@ -26,8 +27,7 @@ namespace osu.Game.Screens.Play.HUD if (!objects.Any()) return; - double firstHit = objects.First().StartTime; - double lastHit = objects.Max(o => o.GetEndTime()); + (double firstHit, double lastHit) = BeatmapExtensions.CalculatePlayableBounds(objects); if (lastHit == 0) lastHit = objects.Last().StartTime; diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index ebe2fb83e6..4391193df8 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -2,12 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; using osu.Game.Skinning; @@ -52,9 +52,9 @@ namespace osu.Game.Screens.Play.HUD set { objects = value; - FirstHitTime = objects.FirstOrDefault()?.StartTime ?? 0; - //TODO: this isn't always correct (consider mania where a non-last object may last for longer than the last in the list). - LastHitTime = objects.LastOrDefault()?.GetEndTime() ?? 0; + + (FirstHitTime, LastHitTime) = BeatmapExtensions.CalculatePlayableBounds(objects); + UpdateObjects(objects); } }