From ee945c9b58a8463598685a53fb4ba38cacf71efe Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Wed, 14 Dec 2022 10:34:21 -0500 Subject: [PATCH 001/121] disable mouse input to touchscreen controls --- .../UI/CatchTouchInputMapper.cs | 24 ------------------- osu.Game.Rulesets.Mania/UI/Column.cs | 12 ---------- .../UI/DrumTouchInputArea.cs | 18 -------------- 3 files changed, 54 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index d23913136d..55a90d62e5 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -106,41 +106,17 @@ namespace osu.Game.Rulesets.Catch.UI return false; } - protected override bool OnMouseDown(MouseDownEvent e) - { - return updateAction(e.Button, getTouchCatchActionFromInput(e.ScreenSpaceMousePosition)); - } - protected override bool OnTouchDown(TouchDownEvent e) { return updateAction(e.Touch.Source, getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position)); } - protected override bool OnMouseMove(MouseMoveEvent e) - { - Show(); - - TouchCatchAction? action = getTouchCatchActionFromInput(e.ScreenSpaceMousePosition); - - // multiple mouse buttons may be pressed and handling the same action. - foreach (MouseButton button in e.PressedButtons) - updateAction(button, action); - - return false; - } - protected override void OnTouchMove(TouchMoveEvent e) { updateAction(e.Touch.Source, getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position)); base.OnTouchMove(e); } - protected override void OnMouseUp(MouseUpEvent e) - { - updateAction(e.Button, null); - base.OnMouseUp(e); - } - protected override void OnTouchUp(TouchUpEvent e) { updateAction(e.Touch.Source, null); diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 6a31fb3fda..f355c43ad0 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -206,18 +206,6 @@ namespace osu.Game.Rulesets.Mania.UI keyBindingContainer = maniaInputManager?.KeyBindingContainer; } - protected override bool OnMouseDown(MouseDownEvent e) - { - keyBindingContainer?.TriggerPressed(column.Action.Value); - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - keyBindingContainer?.TriggerReleased(column.Action.Value); - base.OnMouseUp(e); - } - protected override bool OnTouchDown(TouchDownEvent e) { keyBindingContainer?.TriggerPressed(column.Action.Value); diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index ab8c0a484e..0232c10d65 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -107,24 +107,6 @@ namespace osu.Game.Rulesets.Taiko.UI return false; } - protected override bool OnMouseDown(MouseDownEvent e) - { - if (!validMouse(e)) - return false; - - handleDown(e.Button, e.ScreenSpaceMousePosition); - return true; - } - - protected override void OnMouseUp(MouseUpEvent e) - { - if (!validMouse(e)) - return; - - handleUp(e.Button); - base.OnMouseUp(e); - } - protected override bool OnTouchDown(TouchDownEvent e) { handleDown(e.Touch.Source, e.ScreenSpaceTouchDownPosition); From f5cc2f6ed5e3597d032c638bbf498f7a5d818f77 Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Wed, 14 Dec 2022 11:19:16 -0500 Subject: [PATCH 002/121] remove unnecessary using --- osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 55a90d62e5..10e43cf74a 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -11,7 +11,6 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; using osuTK; -using osuTK.Input; namespace osu.Game.Rulesets.Catch.UI { From c1647440641abe58d4ef1abf834e8f936d0877a2 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 16 Dec 2022 01:03:30 +0900 Subject: [PATCH 003/121] Add ability to set preview time --- .../Summary/Parts/PreviewTimePart.cs | 31 +++++++++++++++++++ .../Timelines/Summary/SummaryTimeline.cs | 8 +++++ osu.Game/Screens/Edit/Editor.cs | 12 +++++++ osu.Game/Screens/Edit/EditorBeatmap.cs | 5 +++ 4 files changed, 56 insertions(+) create mode 100644 osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs new file mode 100644 index 0000000000..a09d93fd5a --- /dev/null +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs @@ -0,0 +1,31 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Graphics; +using osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations; + +namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts +{ + public partial class PreviewTimePart : TimelinePart + { + protected override void LoadBeatmap(EditorBeatmap beatmap) + { + base.LoadBeatmap(beatmap); + Add(new PreviewTimeVisualisation(beatmap.PreviewTime)); + } + + private partial class PreviewTimeVisualisation : PointVisualisation + { + public PreviewTimeVisualisation(BindableInt time) + : base(time.Value) + { + time.BindValueChanged(s => X = s.NewValue); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) => Colour = colours.Lime; + } + } +} diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs index 7f762b9d50..41377bcb18 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs @@ -41,6 +41,14 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary RelativeSizeAxes = Axes.Both, Height = 0.35f }, + new PreviewTimePart + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Y = -10, + Height = 0.35f + }, new Container { Name = "centre line", diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index f3f2b8ad6b..16fff76ac7 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -322,6 +322,13 @@ namespace osu.Game.Screens.Edit State = { BindTarget = editorHitMarkers }, } } + }, + new MenuItem("Timing") + { + Items = new MenuItem[] + { + new EditorMenuItem("Set Current Position as Preview Point", MenuItemType.Standard, SetCurrectTimeAsPreview) + } } } }, @@ -801,6 +808,11 @@ namespace osu.Game.Screens.Edit protected void Redo() => changeHandler?.RestoreState(1); + protected void SetCurrectTimeAsPreview() + { + editorBeatmap.PreviewTime.Value = (int)clock.CurrentTime; + } + private void resetTrack(bool seekToStart = false) { Beatmap.Value.Track.Stop(); diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index e204b44db3..0a0557a992 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -86,6 +86,8 @@ namespace osu.Game.Screens.Edit [Resolved] private EditorClock editorClock { get; set; } + public BindableInt PreviewTime; + private readonly IBeatmapProcessor beatmapProcessor; private readonly Dictionary> startTimeBindables = new Dictionary>(); @@ -107,6 +109,9 @@ namespace osu.Game.Screens.Edit foreach (var obj in HitObjects) trackStartTime(obj); + + PreviewTime = new BindableInt(playableBeatmap.Metadata.PreviewTime); + PreviewTime.BindValueChanged(s => this.beatmapInfo.Metadata.PreviewTime = s.NewValue); } /// From 984f0b5fa961e5ed54dbbac132f39273fa2e7e8f Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 16 Dec 2022 01:35:54 +0900 Subject: [PATCH 004/121] Add test for set preview point --- .../Visual/Editing/TestScenePreviewTime.cs | 23 +++++++++++++++++++ osu.Game/Tests/Visual/EditorTestScene.cs | 2 ++ 2 files changed, 25 insertions(+) create mode 100644 osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs diff --git a/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs new file mode 100644 index 0000000000..f95851f646 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; + +namespace osu.Game.Tests.Visual.Editing +{ + public partial class TestScenePreviewTime : EditorTestScene + { + protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); + + [Test] + public void TestSetPreviewTimingPoint() + { + AddStep("seek to 1000", () => EditorClock.Seek(1000)); + AddAssert("time is 1000", () => EditorClock.CurrentTime == 1000); + AddStep("set current time as preview point", () => Editor.SetCurrectTimeAsPreview()); + AddAssert("preview time is 1000", () => EditorBeatmap.PreviewTime.Value == 1000); + } + } +} diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 833c12ba54..9944a561ca 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -102,6 +102,8 @@ namespace osu.Game.Tests.Visual public new void Redo() => base.Redo(); + public new void SetCurrectTimeAsPreview() => base.SetCurrectTimeAsPreview(); + public new bool Save() => base.Save(); public new void Cut() => base.Cut(); From f0246df1a9751da8826b215a69725f14571572f5 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 16 Dec 2022 09:58:58 +0900 Subject: [PATCH 005/121] only get; --- osu.Game/Screens/Edit/EditorBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 0a0557a992..1059654077 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -86,7 +86,7 @@ namespace osu.Game.Screens.Edit [Resolved] private EditorClock editorClock { get; set; } - public BindableInt PreviewTime; + public BindableInt PreviewTime { get; } private readonly IBeatmapProcessor beatmapProcessor; From 79e27c2d9d7dbeb1444de238a72686cb90c26053 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 16 Dec 2022 10:44:07 +0900 Subject: [PATCH 006/121] `PreviewTimePart` will not show if preview time is -1 --- .../Visual/Editing/TestScenePreviewTime.cs | 14 +++++++++++++- .../Timelines/Summary/Parts/PreviewTimePart.cs | 4 ++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs index f95851f646..213eb4b175 100644 --- a/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs +++ b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs @@ -1,9 +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.Linq; using NUnit.Framework; +using osu.Framework.Testing; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts; namespace osu.Game.Tests.Visual.Editing { @@ -12,12 +15,21 @@ namespace osu.Game.Tests.Visual.Editing protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); [Test] - public void TestSetPreviewTimingPoint() + public void TestSceneSetPreviewTimingPoint() { AddStep("seek to 1000", () => EditorClock.Seek(1000)); AddAssert("time is 1000", () => EditorClock.CurrentTime == 1000); AddStep("set current time as preview point", () => Editor.SetCurrectTimeAsPreview()); AddAssert("preview time is 1000", () => EditorBeatmap.PreviewTime.Value == 1000); } + + [Test] + public void TestScenePreviewTimeline() + { + AddStep("set preview time to -1", () => EditorBeatmap.PreviewTime.Value = -1); + AddAssert("preview time line should not show", () => Editor.ChildrenOfType().Single().Alpha == 0); + AddStep("set preview time to 1000", () => EditorBeatmap.PreviewTime.Value = 1000); + AddAssert("preview time line should show", () => Editor.ChildrenOfType().Single().Alpha == 1); + } } } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs index a09d93fd5a..6149900fdc 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs @@ -14,6 +14,10 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { base.LoadBeatmap(beatmap); Add(new PreviewTimeVisualisation(beatmap.PreviewTime)); + beatmap.PreviewTime.BindValueChanged(s => + { + Alpha = s.NewValue == -1 ? 0 : 1; + }, true); } private partial class PreviewTimeVisualisation : PointVisualisation From a4d28aff6d73d28515c5a158d8a8152ac6be7eef Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 16 Dec 2022 10:48:56 +0900 Subject: [PATCH 007/121] fix typo --- osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 4 ++-- osu.Game/Tests/Visual/EditorTestScene.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs index 213eb4b175..ad49f3ac0a 100644 --- a/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs +++ b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Editing { AddStep("seek to 1000", () => EditorClock.Seek(1000)); AddAssert("time is 1000", () => EditorClock.CurrentTime == 1000); - AddStep("set current time as preview point", () => Editor.SetCurrectTimeAsPreview()); + AddStep("set current time as preview point", () => Editor.SetCurrentTimeAsPreview()); AddAssert("preview time is 1000", () => EditorBeatmap.PreviewTime.Value == 1000); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 16fff76ac7..62bb7d3133 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -327,7 +327,7 @@ namespace osu.Game.Screens.Edit { Items = new MenuItem[] { - new EditorMenuItem("Set Current Position as Preview Point", MenuItemType.Standard, SetCurrectTimeAsPreview) + new EditorMenuItem("Set Current Position as Preview Point", MenuItemType.Standard, SetCurrentTimeAsPreview) } } } @@ -808,7 +808,7 @@ namespace osu.Game.Screens.Edit protected void Redo() => changeHandler?.RestoreState(1); - protected void SetCurrectTimeAsPreview() + protected void SetCurrentTimeAsPreview() { editorBeatmap.PreviewTime.Value = (int)clock.CurrentTime; } diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 9944a561ca..9c8ac65add 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual public new void Redo() => base.Redo(); - public new void SetCurrectTimeAsPreview() => base.SetCurrectTimeAsPreview(); + public new void SetCurrentTimeAsPreview() => base.SetCurrentTimeAsPreview(); public new bool Save() => base.Save(); From 01f09529a825d80c8e6ccb390b644b7586234a70 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 18 Dec 2022 22:52:21 -0800 Subject: [PATCH 008/121] Link beatmap set genre and language to listing filters --- osu.Game/Online/Chat/MessageFormatter.cs | 2 ++ osu.Game/OsuGame.cs | 12 ++++++++++++ .../BeatmapListing/BeatmapListingFilterControl.cs | 7 +++++++ osu.Game/Overlays/BeatmapListingOverlay.cs | 12 ++++++++++++ osu.Game/Overlays/BeatmapSet/MetadataSection.cs | 10 ++++++++++ 5 files changed, 43 insertions(+) diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index b9bca9dc20..523185a7cb 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -341,6 +341,8 @@ namespace osu.Game.Online.Chat OpenWiki, Custom, OpenChangelog, + FilterBeatmapSetGenre, + FilterBeatmapSetLanguage, } public class Link : IComparable diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index a0a45e18a8..4c47eda38b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -356,6 +356,14 @@ namespace osu.Game SearchBeatmapSet(argString); break; + case LinkAction.FilterBeatmapSetGenre: + FilterBeatmapSetGenre(argString); + break; + + case LinkAction.FilterBeatmapSetLanguage: + FilterBeatmapSetLanguage(argString); + break; + case LinkAction.OpenEditorTimestamp: case LinkAction.JoinMultiplayerMatch: case LinkAction.Spectate: @@ -460,6 +468,10 @@ namespace osu.Game /// The query to search for. public void SearchBeatmapSet(string query) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithSearch(query)); + public void FilterBeatmapSetGenre(string genre) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithGenreFilter(genre)); + + public void FilterBeatmapSetLanguage(string language) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithLanguageFilter(language)); + /// /// Show a wiki's page as an overlay /// diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index c5c252fb5d..5eb1ff7024 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -145,6 +146,12 @@ namespace osu.Game.Overlays.BeatmapListing public void Search(string query) => Schedule(() => searchControl.Query.Value = query); + public void FilterGenre(string genre) + => Schedule(() => searchControl.Genre.Value = genre.DehumanizeTo()); + + public void FilterLanguage(string language) + => Schedule(() => searchControl.Language.Value = language.DehumanizeTo()); + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index d6d4f1a67b..010499df6f 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -110,6 +110,18 @@ namespace osu.Game.Overlays ScrollFlow.ScrollToStart(); } + public void ShowWithGenreFilter(string genre) + { + ShowWithSearch(string.Empty); + filterControl.FilterGenre(genre); + } + + public void ShowWithLanguageFilter(string language) + { + ShowWithSearch(string.Empty); + filterControl.FilterLanguage(language); + } + protected override BeatmapListingHeader CreateHeader() => new BeatmapListingHeader(); protected override Color4 BackgroundColour => ColourProvider.Background6; diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs index 6390c52ff3..caf1b7197c 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using Humanizer; using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -12,6 +13,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; +using osu.Game.Overlays.BeatmapListing; using osuTK; using osuTK.Graphics; @@ -116,6 +118,14 @@ namespace osu.Game.Overlays.BeatmapSet break; + case MetadataType.Genre: + loaded.AddLink(text.DehumanizeTo().GetLocalisableDescription(), LinkAction.FilterBeatmapSetGenre, text); + break; + + case MetadataType.Language: + loaded.AddLink(text.DehumanizeTo().GetLocalisableDescription(), LinkAction.FilterBeatmapSetLanguage, text); + break; + default: loaded.AddText(text); break; From 1d39e8d0cecc26b4d5d89d392c48e8319b82156f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 21 Dec 2022 10:18:47 -0800 Subject: [PATCH 009/121] Refactor `MetadataSection` to use generics and inheritance --- osu.Game/Overlays/BeatmapSet/Info.cs | 10 +- .../Overlays/BeatmapSet/MetadataSection.cs | 98 +++++++------------ .../BeatmapSet/MetadataSectionDescription.cs | 21 ++++ .../BeatmapSet/MetadataSectionGenre.cs | 25 +++++ .../BeatmapSet/MetadataSectionLanguage.cs | 25 +++++ .../BeatmapSet/MetadataSectionSource.cs | 25 +++++ .../BeatmapSet/MetadataSectionTags.cs | 35 +++++++ osu.Game/Screens/Select/BeatmapDetails.cs | 12 +-- 8 files changed, 180 insertions(+), 71 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs create mode 100644 osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs create mode 100644 osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs create mode 100644 osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs create mode 100644 osu.Game/Overlays/BeatmapSet/MetadataSectionTags.cs diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 514a4ea8cd..a5ebc6c1e4 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.BeatmapSet Child = new Container { RelativeSizeAxes = Axes.Both, - Child = new MetadataSection(MetadataType.Description), + Child = new MetadataSectionDescription(), }, }, new Container @@ -78,10 +78,10 @@ namespace osu.Game.Overlays.BeatmapSet Direction = FillDirection.Full, Children = new[] { - source = new MetadataSection(MetadataType.Source), - genre = new MetadataSection(MetadataType.Genre) { Width = 0.5f }, - language = new MetadataSection(MetadataType.Language) { Width = 0.5f }, - tags = new MetadataSection(MetadataType.Tags), + source = new MetadataSectionSource(), + genre = new MetadataSectionGenre { Width = 0.5f }, + language = new MetadataSectionLanguage { Width = 0.5f }, + tags = new MetadataSectionTags(), }, }, }, diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs index caf1b7197c..6af77f975e 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs @@ -1,10 +1,7 @@ // 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 Humanizer; using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -12,27 +9,45 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Online.Chat; -using osu.Game.Overlays.BeatmapListing; using osuTK; using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet { - public partial class MetadataSection : Container + public abstract partial class MetadataSection : MetadataSection + { + public override string Text + { + set + { + if (string.IsNullOrEmpty(value)) + { + this.FadeOut(TRANSITION_DURATION); + return; + } + + base.Text = value; + } + } + + protected MetadataSection(MetadataType type, Action? searchAction = null) + : base(type, searchAction) + { + } + } + + public abstract partial class MetadataSection : Container { private readonly FillFlowContainer textContainer; - private readonly MetadataType type; - private TextFlowContainer textFlow; + private TextFlowContainer? textFlow; - private readonly Action searchAction; + protected readonly Action? SearchAction; - private const float transition_duration = 250; + protected const float TRANSITION_DURATION = 250; - public MetadataSection(MetadataType type, Action searchAction = null) + protected MetadataSection(MetadataType type, Action? searchAction = null) { - this.type = type; - this.searchAction = searchAction; + SearchAction = searchAction; Alpha = 0; @@ -55,7 +70,7 @@ namespace osu.Game.Overlays.BeatmapSet AutoSizeAxes = Axes.Y, Child = new OsuSpriteText { - Text = this.type.GetLocalisableDescription(), + Text = type.GetLocalisableDescription(), Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14), }, }, @@ -63,23 +78,23 @@ namespace osu.Game.Overlays.BeatmapSet }; } - public string Text + public virtual T Text { set { - if (string.IsNullOrEmpty(value)) + if (value == null) { - this.FadeOut(transition_duration); + this.FadeOut(TRANSITION_DURATION); return; } - this.FadeIn(transition_duration); + this.FadeIn(TRANSITION_DURATION); setTextAsync(value); } } - private void setTextAsync(string text) + private void setTextAsync(T text) { LoadComponentAsync(new LinkFlowContainer(s => s.Font = s.Font.With(size: 14)) { @@ -90,52 +105,15 @@ namespace osu.Game.Overlays.BeatmapSet { textFlow?.Expire(); - switch (type) - { - case MetadataType.Tags: - string[] tags = text.Split(" "); - - for (int i = 0; i <= tags.Length - 1; i++) - { - string tag = tags[i]; - - if (searchAction != null) - loaded.AddLink(tag, () => searchAction(tag)); - else - loaded.AddLink(tag, LinkAction.SearchBeatmapSet, tag); - - if (i != tags.Length - 1) - loaded.AddText(" "); - } - - break; - - case MetadataType.Source: - if (searchAction != null) - loaded.AddLink(text, () => searchAction(text)); - else - loaded.AddLink(text, LinkAction.SearchBeatmapSet, text); - - break; - - case MetadataType.Genre: - loaded.AddLink(text.DehumanizeTo().GetLocalisableDescription(), LinkAction.FilterBeatmapSetGenre, text); - break; - - case MetadataType.Language: - loaded.AddLink(text.DehumanizeTo().GetLocalisableDescription(), LinkAction.FilterBeatmapSetLanguage, text); - break; - - default: - loaded.AddText(text); - break; - } + AddMetadata(text, loaded); textContainer.Add(textFlow = loaded); // fade in if we haven't yet. - textContainer.FadeIn(transition_duration); + textContainer.FadeIn(TRANSITION_DURATION); }); } + + protected abstract void AddMetadata(T text, LinkFlowContainer loaded); } } diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs new file mode 100644 index 0000000000..a9503cded3 --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Game.Graphics.Containers; + +namespace osu.Game.Overlays.BeatmapSet +{ + public partial class MetadataSectionDescription : MetadataSection + { + public MetadataSectionDescription(Action? searchAction = null) + : base(MetadataType.Description, searchAction) + { + } + + protected override void AddMetadata(string text, LinkFlowContainer loaded) + { + loaded.AddText(text); + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs new file mode 100644 index 0000000000..eaf2c9721f --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using Humanizer; +using osu.Framework.Extensions; +using osu.Game.Graphics.Containers; +using osu.Game.Online.Chat; +using osu.Game.Overlays.BeatmapListing; + +namespace osu.Game.Overlays.BeatmapSet +{ + public partial class MetadataSectionGenre : MetadataSection + { + public MetadataSectionGenre(Action? searchAction = null) + : base(MetadataType.Genre, searchAction) + { + } + + protected override void AddMetadata(string text, LinkFlowContainer loaded) + { + loaded.AddLink(text.DehumanizeTo().GetLocalisableDescription(), LinkAction.FilterBeatmapSetGenre, text); + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs new file mode 100644 index 0000000000..6c68a5d682 --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using Humanizer; +using osu.Framework.Extensions; +using osu.Game.Graphics.Containers; +using osu.Game.Online.Chat; +using osu.Game.Overlays.BeatmapListing; + +namespace osu.Game.Overlays.BeatmapSet +{ + public partial class MetadataSectionLanguage : MetadataSection + { + public MetadataSectionLanguage(Action? searchAction = null) + : base(MetadataType.Language, searchAction) + { + } + + protected override void AddMetadata(string text, LinkFlowContainer loaded) + { + loaded.AddLink(text.DehumanizeTo().GetLocalisableDescription(), LinkAction.FilterBeatmapSetLanguage, text); + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs new file mode 100644 index 0000000000..6deb866f19 --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Game.Graphics.Containers; +using osu.Game.Online.Chat; + +namespace osu.Game.Overlays.BeatmapSet +{ + public partial class MetadataSectionSource : MetadataSection + { + public MetadataSectionSource(Action? searchAction = null) + : base(MetadataType.Source, searchAction) + { + } + + protected override void AddMetadata(string text, LinkFlowContainer loaded) + { + if (SearchAction != null) + loaded.AddLink(text, () => SearchAction(text)); + else + loaded.AddLink(text, LinkAction.SearchBeatmapSet, text); + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionTags.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionTags.cs new file mode 100644 index 0000000000..1b384fcdd3 --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionTags.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Game.Graphics.Containers; +using osu.Game.Online.Chat; + +namespace osu.Game.Overlays.BeatmapSet +{ + public partial class MetadataSectionTags : MetadataSection + { + public MetadataSectionTags(Action? searchAction = null) + : base(MetadataType.Tags, searchAction) + { + } + + protected override void AddMetadata(string text, LinkFlowContainer loaded) + { + string[] tags = text.Split(" "); + + for (int i = 0; i <= tags.Length - 1; i++) + { + string tag = tags[i]; + + if (SearchAction != null) + loaded.AddLink(tag, () => SearchAction(tag)); + else + loaded.AddLink(tag, LinkAction.SearchBeatmapSet, tag); + + if (i != tags.Length - 1) + loaded.AddText(" "); + } + } + } +} diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 0a14df6480..b158bef8dc 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -141,9 +141,9 @@ namespace osu.Game.Screens.Select LayoutEasing = Easing.OutQuad, Children = new[] { - description = new MetadataSection(MetadataType.Description, searchOnSongSelect), - source = new MetadataSection(MetadataType.Source, searchOnSongSelect), - tags = new MetadataSection(MetadataType.Tags, searchOnSongSelect), + description = new MetadataSectionDescription(searchOnSongSelect), + source = new MetadataSectionSource(searchOnSongSelect), + tags = new MetadataSectionTags(searchOnSongSelect), }, }, }, @@ -187,9 +187,9 @@ namespace osu.Game.Screens.Select private void updateStatistics() { advanced.BeatmapInfo = BeatmapInfo; - description.Text = BeatmapInfo?.DifficultyName; - source.Text = BeatmapInfo?.Metadata.Source; - tags.Text = BeatmapInfo?.Metadata.Tags; + description.Text = BeatmapInfo?.DifficultyName ?? string.Empty; + source.Text = BeatmapInfo?.Metadata.Source ?? string.Empty; + tags.Text = BeatmapInfo?.Metadata.Tags ?? string.Empty; // failTimes may have been previously fetched if (ratings != null && failTimes != null) From e1e6d76f308e6187246ba415f5188ccd7595f058 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 21 Dec 2022 11:02:04 -0800 Subject: [PATCH 010/121] Check id for genre/language instead and fallback to name if not defined --- .../Visual/Online/TestSceneBeatmapSetOverlay.cs | 2 ++ osu.Game/OsuGame.cs | 9 +++++---- .../BeatmapListing/BeatmapListingFilterControl.cs | 9 ++++----- osu.Game/Overlays/BeatmapListingOverlay.cs | 4 ++-- osu.Game/Overlays/BeatmapSet/Info.cs | 11 +++++++---- .../Overlays/BeatmapSet/MetadataSectionGenre.cs | 15 ++++++++++----- .../BeatmapSet/MetadataSectionLanguage.cs | 15 ++++++++++----- 7 files changed, 40 insertions(+), 25 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 3335f69dbb..7d978b9726 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -54,6 +54,8 @@ namespace osu.Game.Tests.Visual.Online { overlay.ShowBeatmapSet(new APIBeatmapSet { + Genre = new BeatmapSetOnlineGenre { Id = 15, Name = "Future genre" }, + Language = new BeatmapSetOnlineLanguage { Id = 15, Name = "Future language" }, OnlineID = 1235, Title = @"an awesome beatmap", Artist = @"naru narusegawa", diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4c47eda38b..508281164f 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -46,6 +46,7 @@ using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays; +using osu.Game.Overlays.BeatmapListing; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Toolbar; @@ -357,11 +358,11 @@ namespace osu.Game break; case LinkAction.FilterBeatmapSetGenre: - FilterBeatmapSetGenre(argString); + FilterBeatmapSetGenre((SearchGenre)link.Argument); break; case LinkAction.FilterBeatmapSetLanguage: - FilterBeatmapSetLanguage(argString); + FilterBeatmapSetLanguage((SearchLanguage)link.Argument); break; case LinkAction.OpenEditorTimestamp: @@ -468,9 +469,9 @@ namespace osu.Game /// The query to search for. public void SearchBeatmapSet(string query) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithSearch(query)); - public void FilterBeatmapSetGenre(string genre) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithGenreFilter(genre)); + public void FilterBeatmapSetGenre(SearchGenre genre) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithGenreFilter(genre)); - public void FilterBeatmapSetLanguage(string language) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithLanguageFilter(language)); + public void FilterBeatmapSetLanguage(SearchLanguage language) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithLanguageFilter(language)); /// /// Show a wiki's page as an overlay diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index 5eb1ff7024..37a29b1c50 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -146,11 +145,11 @@ namespace osu.Game.Overlays.BeatmapListing public void Search(string query) => Schedule(() => searchControl.Query.Value = query); - public void FilterGenre(string genre) - => Schedule(() => searchControl.Genre.Value = genre.DehumanizeTo()); + public void FilterGenre(SearchGenre genre) + => Schedule(() => searchControl.Genre.Value = genre); - public void FilterLanguage(string language) - => Schedule(() => searchControl.Language.Value = language.DehumanizeTo()); + public void FilterLanguage(SearchLanguage language) + => Schedule(() => searchControl.Language.Value = language); protected override void LoadComplete() { diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 010499df6f..73961487ed 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -110,13 +110,13 @@ namespace osu.Game.Overlays ScrollFlow.ScrollToStart(); } - public void ShowWithGenreFilter(string genre) + public void ShowWithGenreFilter(SearchGenre genre) { ShowWithSearch(string.Empty); filterControl.FilterGenre(genre); } - public void ShowWithLanguageFilter(string language) + public void ShowWithLanguageFilter(SearchLanguage language) { ShowWithSearch(string.Empty); filterControl.FilterLanguage(language); diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index a5ebc6c1e4..8a1384f0d3 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; @@ -34,7 +35,9 @@ namespace osu.Game.Overlays.BeatmapSet public Info() { - MetadataSection source, tags, genre, language; + MetadataSection source, tags; + MetadataSectionGenre genre; + MetadataSectionLanguage language; OsuSpriteText notRankedPlaceholder; RelativeSizeAxes = Axes.X; @@ -76,7 +79,7 @@ namespace osu.Game.Overlays.BeatmapSet RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Full, - Children = new[] + Children = new Drawable[] { source = new MetadataSectionSource(), genre = new MetadataSectionGenre { Width = 0.5f }, @@ -120,8 +123,8 @@ namespace osu.Game.Overlays.BeatmapSet { source.Text = b.NewValue?.Source ?? string.Empty; tags.Text = b.NewValue?.Tags ?? string.Empty; - genre.Text = b.NewValue?.Genre.Name ?? string.Empty; - language.Text = b.NewValue?.Language.Name ?? string.Empty; + genre.Text = b.NewValue?.Genre ?? new BeatmapSetOnlineGenre { Id = 1 }; + language.Text = b.NewValue?.Language ?? new BeatmapSetOnlineLanguage { Id = 1 }; bool setHasLeaderboard = b.NewValue?.Status > 0; successRate.Alpha = setHasLeaderboard ? 1 : 0; notRankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1; diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs index eaf2c9721f..0e045b2bf1 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs @@ -2,24 +2,29 @@ // See the LICENCE file in the repository root for full licence text. using System; -using Humanizer; using osu.Framework.Extensions; +using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Online.Chat; using osu.Game.Overlays.BeatmapListing; namespace osu.Game.Overlays.BeatmapSet { - public partial class MetadataSectionGenre : MetadataSection + public partial class MetadataSectionGenre : MetadataSection { - public MetadataSectionGenre(Action? searchAction = null) + public MetadataSectionGenre(Action? searchAction = null) : base(MetadataType.Genre, searchAction) { } - protected override void AddMetadata(string text, LinkFlowContainer loaded) + protected override void AddMetadata(BeatmapSetOnlineGenre text, LinkFlowContainer loaded) { - loaded.AddLink(text.DehumanizeTo().GetLocalisableDescription(), LinkAction.FilterBeatmapSetGenre, text); + var genre = (SearchGenre)text.Id; + + if (Enum.IsDefined(genre)) + loaded.AddLink(genre.GetLocalisableDescription(), LinkAction.FilterBeatmapSetGenre, genre); + else + loaded.AddText(text.Name); } } } diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs index 6c68a5d682..6e59818b93 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs @@ -2,24 +2,29 @@ // See the LICENCE file in the repository root for full licence text. using System; -using Humanizer; using osu.Framework.Extensions; +using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Online.Chat; using osu.Game.Overlays.BeatmapListing; namespace osu.Game.Overlays.BeatmapSet { - public partial class MetadataSectionLanguage : MetadataSection + public partial class MetadataSectionLanguage : MetadataSection { - public MetadataSectionLanguage(Action? searchAction = null) + public MetadataSectionLanguage(Action? searchAction = null) : base(MetadataType.Language, searchAction) { } - protected override void AddMetadata(string text, LinkFlowContainer loaded) + protected override void AddMetadata(BeatmapSetOnlineLanguage text, LinkFlowContainer loaded) { - loaded.AddLink(text.DehumanizeTo().GetLocalisableDescription(), LinkAction.FilterBeatmapSetLanguage, text); + var language = (SearchLanguage)text.Id; + + if (Enum.IsDefined(language)) + loaded.AddLink(language.GetLocalisableDescription(), LinkAction.FilterBeatmapSetLanguage, language); + else + loaded.AddText(text.Name); } } } From 66a02374dae305eefddbb04b9864482457246622 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 22 Dec 2022 01:23:24 +0300 Subject: [PATCH 011/121] Clear cached waveform on track change in editor --- osu.Game/Beatmaps/WorkingBeatmap.cs | 8 +++++++- osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 393c4ba892..f454f08e87 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -48,7 +48,7 @@ namespace osu.Game.Beatmaps private readonly object beatmapFetchLock = new object(); - private readonly Lazy waveform; + private Lazy waveform; private readonly Lazy storyboard; private readonly Lazy skin; private Track track; // track is not Lazy as we allow transferring and loading multiple times. @@ -329,6 +329,12 @@ namespace osu.Game.Beatmaps #endregion + public void InvalidateWaveform() + { + if (waveform.IsValueCreated) + waveform = new Lazy(GetWaveform); + } + public override string ToString() => BeatmapInfo.ToString(); public abstract Stream GetStream(string storagePath); diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index ca0f50cd34..01217021fd 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Edit.Setup } working.Value.Metadata.AudioFile = destination.Name; - + working.Value.InvalidateWaveform(); editorBeatmap.SaveState(); music.ReloadCurrentTrack(); From 7089bb6c2399ccb6c511acb6465b8ce3053b54c5 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 22 Dec 2022 01:23:59 +0300 Subject: [PATCH 012/121] Listen for track reload in timeline --- .../Compose/Components/Timeline/Timeline.cs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 45f902d0de..d135d108de 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -15,6 +15,7 @@ using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics; +using osu.Game.Overlays; using osu.Game.Rulesets.Edit; using osuTK; using osuTK.Input; @@ -35,14 +36,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public readonly Bindable TicksVisible = new Bindable(); - public readonly IBindable Beatmap = new Bindable(); - [Resolved] private EditorClock editorClock { get; set; } [Resolved] private EditorBeatmap editorBeatmap { get; set; } + [Resolved] + private MusicController musicController { get; set; } + /// /// The timeline's scroll position in the last frame. /// @@ -139,11 +141,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline waveformOpacity = config.GetBindable(OsuSetting.EditorWaveformOpacity); - Beatmap.BindTo(beatmap); - Beatmap.BindValueChanged(b => - { - waveform.Waveform = b.NewValue.Waveform; - }, true); + musicController.TrackChanged += onTrackReload; + waveform.Waveform = beatmap.Value.Waveform; Zoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom); } @@ -181,6 +180,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private void updateWaveformOpacity() => waveform.FadeTo(WaveformVisible.Value ? waveformOpacity.Value : 0, 200, Easing.OutQuint); + private void onTrackReload(WorkingBeatmap beatmap, TrackChangeDirection tcd) + { + waveform.Waveform = beatmap.Waveform; + } + protected override void Update() { base.Update(); @@ -321,5 +325,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline double time = TimeAtPosition(Content.ToLocalSpace(screenSpacePosition).X); return new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(time)); } + + protected override void Dispose(bool isDisposing) + { + musicController.TrackChanged -= onTrackReload; + base.Dispose(isDisposing); + } } } From a18ece8610acee982222a611212345971b45632d Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 22 Dec 2022 01:24:23 +0300 Subject: [PATCH 013/121] Listen for track reload in timing screen --- .../Screens/Edit/Timing/TapTimingControl.cs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 09b3851333..10db426416 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; @@ -29,9 +30,13 @@ namespace osu.Game.Screens.Edit.Timing [Resolved] private Bindable selectedGroup { get; set; } = null!; + [Resolved] + private MusicController musicController { get; set; } = null!; + private readonly BindableBool isHandlingTapping = new BindableBool(); private MetronomeDisplay metronome = null!; + private Container waveformContainer = null!; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuColour colours) @@ -88,7 +93,11 @@ namespace osu.Game.Screens.Edit.Timing Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, }, - new WaveformComparisonDisplay(), + waveformContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Child = new WaveformComparisonDisplay(), + } } }, } @@ -179,6 +188,13 @@ namespace osu.Game.Screens.Edit.Timing if (handling.NewValue) start(); }, true); + + musicController.TrackChanged += onTrackReload; + } + + private void onTrackReload(WorkingBeatmap beatmap, TrackChangeDirection tcd) + { + waveformContainer.Child = new WaveformComparisonDisplay(); } private void start() @@ -233,6 +249,12 @@ namespace osu.Game.Screens.Edit.Timing timing.BeatLength = 60000 / (timing.BPM + adjust); } + protected override void Dispose(bool isDisposing) + { + musicController.TrackChanged -= onTrackReload; + base.Dispose(isDisposing); + } + private partial class InlineButton : OsuButton { private readonly IconUsage icon; From f2e8776529176f7ec1ab03d12ea4eee6a5a44f18 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 22 Dec 2022 15:35:53 +0300 Subject: [PATCH 014/121] Bind to clock instead of music controller --- .../Compose/Components/Timeline/Timeline.cs | 25 +++++++------------ .../Screens/Edit/Timing/TapTimingControl.cs | 21 ++++------------ 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index d135d108de..918b5f8109 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -15,7 +16,6 @@ using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics; -using osu.Game.Overlays; using osu.Game.Rulesets.Edit; using osuTK; using osuTK.Input; @@ -42,9 +42,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline [Resolved] private EditorBeatmap editorBeatmap { get; set; } - [Resolved] - private MusicController musicController { get; set; } - /// /// The timeline's scroll position in the last frame. /// @@ -94,6 +91,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private double trackLengthForZoom; + private readonly IBindable track = new Bindable(); + [BackgroundDependencyLoader] private void load(IBindable beatmap, OsuColour colours, OsuConfigManager config) { @@ -141,7 +140,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline waveformOpacity = config.GetBindable(OsuSetting.EditorWaveformOpacity); - musicController.TrackChanged += onTrackReload; + track.BindTo(editorClock.Track); + track.BindValueChanged(_ => + { + waveform.Waveform = beatmap.Value.Waveform; + }, true); + waveform.Waveform = beatmap.Value.Waveform; Zoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom); @@ -180,11 +184,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private void updateWaveformOpacity() => waveform.FadeTo(WaveformVisible.Value ? waveformOpacity.Value : 0, 200, Easing.OutQuint); - private void onTrackReload(WorkingBeatmap beatmap, TrackChangeDirection tcd) - { - waveform.Waveform = beatmap.Waveform; - } - protected override void Update() { base.Update(); @@ -325,11 +324,5 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline double time = TimeAtPosition(Content.ToLocalSpace(screenSpacePosition).X); return new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(time)); } - - protected override void Dispose(bool isDisposing) - { - musicController.TrackChanged -= onTrackReload; - base.Dispose(isDisposing); - } } } diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 10db426416..36cd5f8b70 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -3,13 +3,13 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; @@ -30,8 +30,7 @@ namespace osu.Game.Screens.Edit.Timing [Resolved] private Bindable selectedGroup { get; set; } = null!; - [Resolved] - private MusicController musicController { get; set; } = null!; + private readonly IBindable track = new Bindable(); private readonly BindableBool isHandlingTapping = new BindableBool(); @@ -39,7 +38,7 @@ namespace osu.Game.Screens.Edit.Timing private Container waveformContainer = null!; [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, OsuColour colours) + private void load(OverlayColourProvider colourProvider, OsuColour colours, EditorClock clock) { const float padding = 10; @@ -189,12 +188,8 @@ namespace osu.Game.Screens.Edit.Timing start(); }, true); - musicController.TrackChanged += onTrackReload; - } - - private void onTrackReload(WorkingBeatmap beatmap, TrackChangeDirection tcd) - { - waveformContainer.Child = new WaveformComparisonDisplay(); + track.BindTo(clock.Track); + track.ValueChanged += _ => waveformContainer.Child = new WaveformComparisonDisplay(); } private void start() @@ -249,12 +244,6 @@ namespace osu.Game.Screens.Edit.Timing timing.BeatLength = 60000 / (timing.BPM + adjust); } - protected override void Dispose(bool isDisposing) - { - musicController.TrackChanged -= onTrackReload; - base.Dispose(isDisposing); - } - private partial class InlineButton : OsuButton { private readonly IconUsage icon; From d0645ce15173c32e45886bac43dfb5bd09df69df Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 22 Dec 2022 15:59:51 +0300 Subject: [PATCH 015/121] Rewrite waveform invalidation --- osu.Game/Beatmaps/WorkingBeatmap.cs | 23 +++++++++++-------- .../Screens/Edit/Setup/ResourcesSection.cs | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index f454f08e87..e61ec3f2a8 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -34,8 +34,6 @@ namespace osu.Game.Beatmaps // TODO: remove once the fallback lookup is not required (and access via `working.BeatmapInfo.Metadata` directly). public BeatmapMetadata Metadata => BeatmapInfo.Metadata; - public Waveform Waveform => waveform.Value; - public Storyboard Storyboard => storyboard.Value; public Texture Background => GetBackground(); // Texture uses ref counting, so we want to return a new instance every usage. @@ -48,7 +46,7 @@ namespace osu.Game.Beatmaps private readonly object beatmapFetchLock = new object(); - private Lazy waveform; + private Waveform waveform; private readonly Lazy storyboard; private readonly Lazy skin; private Track track; // track is not Lazy as we allow transferring and loading multiple times. @@ -60,7 +58,6 @@ namespace osu.Game.Beatmaps BeatmapInfo = beatmapInfo; BeatmapSetInfo = beatmapInfo.BeatmapSet ?? new BeatmapSetInfo(); - waveform = new Lazy(GetWaveform); storyboard = new Lazy(GetStoryboard); skin = new Lazy(GetSkin); } @@ -171,6 +168,18 @@ namespace osu.Game.Beatmaps #endregion + #region Waveform + + public Waveform Waveform => waveform ??= GetWaveform(); + + /// + /// Reloads waveform of beatmap's track even if one is already cached. + /// + /// Newly loaded waveform. + public Waveform LoadWaveform() => waveform = GetWaveform(); + + #endregion + #region Beatmap public virtual bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false; @@ -329,12 +338,6 @@ namespace osu.Game.Beatmaps #endregion - public void InvalidateWaveform() - { - if (waveform.IsValueCreated) - waveform = new Lazy(GetWaveform); - } - public override string ToString() => BeatmapInfo.ToString(); public abstract Stream GetStream(string storagePath); diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 01217021fd..36ac9883ba 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Edit.Setup } working.Value.Metadata.AudioFile = destination.Name; - working.Value.InvalidateWaveform(); + working.Value.LoadWaveform(); editorBeatmap.SaveState(); music.ReloadCurrentTrack(); From 20370bd5ae4c9350697c357642102861dae7efc4 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 22 Dec 2022 20:49:09 +0300 Subject: [PATCH 016/121] Invalidate waveform on track load --- osu.Game/Beatmaps/WorkingBeatmap.cs | 15 ++++++++------- osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index e61ec3f2a8..345220a3a3 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -105,7 +105,14 @@ namespace osu.Game.Beatmaps public virtual bool TrackLoaded => track != null; - public Track LoadTrack() => track = GetBeatmapTrack() ?? GetVirtualTrack(1000); + public Track LoadTrack() + { + // track could be changed, clearing waveform cache + waveform = null; + + track = GetBeatmapTrack() ?? GetVirtualTrack(1000); + return track; + } public void PrepareTrackForPreview(bool looping, double offsetFromPreviewPoint = 0) { @@ -172,12 +179,6 @@ namespace osu.Game.Beatmaps public Waveform Waveform => waveform ??= GetWaveform(); - /// - /// Reloads waveform of beatmap's track even if one is already cached. - /// - /// Newly loaded waveform. - public Waveform LoadWaveform() => waveform = GetWaveform(); - #endregion #region Beatmap diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 36ac9883ba..ca0f50cd34 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Edit.Setup } working.Value.Metadata.AudioFile = destination.Name; - working.Value.LoadWaveform(); + editorBeatmap.SaveState(); music.ReloadCurrentTrack(); From 30de9ba795a94810411db4791403c03876b13393 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 23 Dec 2022 00:35:59 +0300 Subject: [PATCH 017/121] Dispose previous waveform on track reload --- osu.Game/Beatmaps/WorkingBeatmap.cs | 9 ++++++--- .../Screens/Edit/Compose/Components/Timeline/Timeline.cs | 7 +------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 345220a3a3..ab790617bb 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -46,10 +46,11 @@ namespace osu.Game.Beatmaps private readonly object beatmapFetchLock = new object(); - private Waveform waveform; private readonly Lazy storyboard; private readonly Lazy skin; + private Track track; // track is not Lazy as we allow transferring and loading multiple times. + private Waveform waveform; // waveform is also not Lazy as the track may change. protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager audioManager) { @@ -107,10 +108,12 @@ namespace osu.Game.Beatmaps public Track LoadTrack() { - // track could be changed, clearing waveform cache + track = GetBeatmapTrack() ?? GetVirtualTrack(1000); + + // the track may have changed, recycle the current waveform. + waveform?.Dispose(); waveform = null; - track = GetBeatmapTrack() ?? GetVirtualTrack(1000); return track; } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 918b5f8109..75de15fe56 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -141,12 +141,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline waveformOpacity = config.GetBindable(OsuSetting.EditorWaveformOpacity); track.BindTo(editorClock.Track); - track.BindValueChanged(_ => - { - waveform.Waveform = beatmap.Value.Waveform; - }, true); - - waveform.Waveform = beatmap.Value.Waveform; + track.BindValueChanged(_ => waveform.Waveform = beatmap.Value.Waveform, true); Zoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom); } From f25439e359b0fb67c66b1a1e85a19fa461029a23 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 23 Dec 2022 01:54:49 +0300 Subject: [PATCH 018/121] Move track change subscription to LoadComplete --- osu.Game/Screens/Edit/Timing/TapTimingControl.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 36cd5f8b70..0d29b69d96 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -189,6 +189,10 @@ namespace osu.Game.Screens.Edit.Timing }, true); track.BindTo(clock.Track); + } + + protected override void LoadComplete() + { track.ValueChanged += _ => waveformContainer.Child = new WaveformComparisonDisplay(); } From 494886ef9277f4c9a626553fa08c21797eab362e Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 23 Dec 2022 11:11:15 -0800 Subject: [PATCH 019/121] Rename `Text` to `Metadata` --- osu.Game/Overlays/BeatmapSet/Info.cs | 8 ++++---- osu.Game/Overlays/BeatmapSet/MetadataSection.cs | 14 +++++++------- .../BeatmapSet/MetadataSectionDescription.cs | 4 ++-- .../Overlays/BeatmapSet/MetadataSectionGenre.cs | 6 +++--- .../Overlays/BeatmapSet/MetadataSectionLanguage.cs | 6 +++--- .../Overlays/BeatmapSet/MetadataSectionSource.cs | 6 +++--- .../Overlays/BeatmapSet/MetadataSectionTags.cs | 4 ++-- osu.Game/Screens/Select/BeatmapDetails.cs | 6 +++--- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 8a1384f0d3..8126db3be0 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -121,10 +121,10 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.ValueChanged += b => { - source.Text = b.NewValue?.Source ?? string.Empty; - tags.Text = b.NewValue?.Tags ?? string.Empty; - genre.Text = b.NewValue?.Genre ?? new BeatmapSetOnlineGenre { Id = 1 }; - language.Text = b.NewValue?.Language ?? new BeatmapSetOnlineLanguage { Id = 1 }; + source.Metadata = b.NewValue?.Source ?? string.Empty; + tags.Metadata = b.NewValue?.Tags ?? string.Empty; + genre.Metadata = b.NewValue?.Genre ?? new BeatmapSetOnlineGenre { Id = 1 }; + language.Metadata = b.NewValue?.Language ?? new BeatmapSetOnlineLanguage { Id = 1 }; bool setHasLeaderboard = b.NewValue?.Status > 0; successRate.Alpha = setHasLeaderboard ? 1 : 0; notRankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1; diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs index 6af77f975e..d32d8e83fb 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.BeatmapSet { public abstract partial class MetadataSection : MetadataSection { - public override string Text + public override string Metadata { set { @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet return; } - base.Text = value; + base.Metadata = value; } } @@ -78,7 +78,7 @@ namespace osu.Game.Overlays.BeatmapSet }; } - public virtual T Text + public virtual T Metadata { set { @@ -90,11 +90,11 @@ namespace osu.Game.Overlays.BeatmapSet this.FadeIn(TRANSITION_DURATION); - setTextAsync(value); + setTextFlowAsync(value); } } - private void setTextAsync(T text) + private void setTextFlowAsync(T metadata) { LoadComponentAsync(new LinkFlowContainer(s => s.Font = s.Font.With(size: 14)) { @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.BeatmapSet { textFlow?.Expire(); - AddMetadata(text, loaded); + AddMetadata(metadata, loaded); textContainer.Add(textFlow = loaded); @@ -114,6 +114,6 @@ namespace osu.Game.Overlays.BeatmapSet }); } - protected abstract void AddMetadata(T text, LinkFlowContainer loaded); + protected abstract void AddMetadata(T metadata, LinkFlowContainer loaded); } } diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs index a9503cded3..e6837951c9 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs @@ -13,9 +13,9 @@ namespace osu.Game.Overlays.BeatmapSet { } - protected override void AddMetadata(string text, LinkFlowContainer loaded) + protected override void AddMetadata(string metadata, LinkFlowContainer loaded) { - loaded.AddText(text); + loaded.AddText(metadata); } } } diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs index 0e045b2bf1..d41115f2b8 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs @@ -17,14 +17,14 @@ namespace osu.Game.Overlays.BeatmapSet { } - protected override void AddMetadata(BeatmapSetOnlineGenre text, LinkFlowContainer loaded) + protected override void AddMetadata(BeatmapSetOnlineGenre metadata, LinkFlowContainer loaded) { - var genre = (SearchGenre)text.Id; + var genre = (SearchGenre)metadata.Id; if (Enum.IsDefined(genre)) loaded.AddLink(genre.GetLocalisableDescription(), LinkAction.FilterBeatmapSetGenre, genre); else - loaded.AddText(text.Name); + loaded.AddText(metadata.Name); } } } diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs index 6e59818b93..e831b1eaca 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs @@ -17,14 +17,14 @@ namespace osu.Game.Overlays.BeatmapSet { } - protected override void AddMetadata(BeatmapSetOnlineLanguage text, LinkFlowContainer loaded) + protected override void AddMetadata(BeatmapSetOnlineLanguage metadata, LinkFlowContainer loaded) { - var language = (SearchLanguage)text.Id; + var language = (SearchLanguage)metadata.Id; if (Enum.IsDefined(language)) loaded.AddLink(language.GetLocalisableDescription(), LinkAction.FilterBeatmapSetLanguage, language); else - loaded.AddText(text.Name); + loaded.AddText(metadata.Name); } } } diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs index 6deb866f19..544dc0dfe4 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs @@ -14,12 +14,12 @@ namespace osu.Game.Overlays.BeatmapSet { } - protected override void AddMetadata(string text, LinkFlowContainer loaded) + protected override void AddMetadata(string metadata, LinkFlowContainer loaded) { if (SearchAction != null) - loaded.AddLink(text, () => SearchAction(text)); + loaded.AddLink(metadata, () => SearchAction(metadata)); else - loaded.AddLink(text, LinkAction.SearchBeatmapSet, text); + loaded.AddLink(metadata, LinkAction.SearchBeatmapSet, metadata); } } } diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionTags.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionTags.cs index 1b384fcdd3..fc16ba19d8 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSectionTags.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionTags.cs @@ -14,9 +14,9 @@ namespace osu.Game.Overlays.BeatmapSet { } - protected override void AddMetadata(string text, LinkFlowContainer loaded) + protected override void AddMetadata(string metadata, LinkFlowContainer loaded) { - string[] tags = text.Split(" "); + string[] tags = metadata.Split(" "); for (int i = 0; i <= tags.Length - 1; i++) { diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index b158bef8dc..712b610515 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -187,9 +187,9 @@ namespace osu.Game.Screens.Select private void updateStatistics() { advanced.BeatmapInfo = BeatmapInfo; - description.Text = BeatmapInfo?.DifficultyName ?? string.Empty; - source.Text = BeatmapInfo?.Metadata.Source ?? string.Empty; - tags.Text = BeatmapInfo?.Metadata.Tags ?? string.Empty; + description.Metadata = BeatmapInfo?.DifficultyName ?? string.Empty; + source.Metadata = BeatmapInfo?.Metadata.Source ?? string.Empty; + tags.Metadata = BeatmapInfo?.Metadata.Tags ?? string.Empty; // failTimes may have been previously fetched if (ratings != null && failTimes != null) From 2dbcf05fe4317713f7d0d35034deeef48ba78c83 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 23 Dec 2022 11:13:27 -0800 Subject: [PATCH 020/121] Use enum values as ids in fallback instead --- osu.Game/Overlays/BeatmapSet/Info.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 8126db3be0..d184f0d0fd 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -12,6 +12,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.BeatmapListing; namespace osu.Game.Overlays.BeatmapSet { @@ -123,8 +124,8 @@ namespace osu.Game.Overlays.BeatmapSet { source.Metadata = b.NewValue?.Source ?? string.Empty; tags.Metadata = b.NewValue?.Tags ?? string.Empty; - genre.Metadata = b.NewValue?.Genre ?? new BeatmapSetOnlineGenre { Id = 1 }; - language.Metadata = b.NewValue?.Language ?? new BeatmapSetOnlineLanguage { Id = 1 }; + genre.Metadata = b.NewValue?.Genre ?? new BeatmapSetOnlineGenre { Id = (int)SearchGenre.Unspecified }; + language.Metadata = b.NewValue?.Language ?? new BeatmapSetOnlineLanguage { Id = (int)SearchLanguage.Unspecified }; bool setHasLeaderboard = b.NewValue?.Status > 0; successRate.Alpha = setHasLeaderboard ? 1 : 0; notRankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1; From 01cf96e240d8a9d1ea99ec072797bdf10d0f6292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 26 Dec 2022 23:25:54 +0100 Subject: [PATCH 021/121] Only show global rankings on results screen when progressing from gameplay --- osu.Game/Screens/Play/Player.cs | 5 +++- osu.Game/Screens/Ranking/SoloResultsScreen.cs | 23 +++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 4306d13ac2..05133fba35 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -1159,7 +1159,10 @@ namespace osu.Game.Screens.Play /// /// The to be displayed in the results screen. /// The . - protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, true); + protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, true) + { + ShowUserStatistics = true + }; private void fadeOut(bool instant = false) { diff --git a/osu.Game/Screens/Ranking/SoloResultsScreen.cs b/osu.Game/Screens/Ranking/SoloResultsScreen.cs index 6d4feeb0db..110e813e04 100644 --- a/osu.Game/Screens/Ranking/SoloResultsScreen.cs +++ b/osu.Game/Screens/Ranking/SoloResultsScreen.cs @@ -20,6 +20,12 @@ namespace osu.Game.Screens.Ranking { public partial class SoloResultsScreen : ResultsScreen { + /// + /// Whether the user's personal statistics should be shown on the extended statistics panel + /// after clicking the score panel associated with the being presented. + /// + public bool ShowUserStatistics { get; init; } + private GetScoresRequest getScoreRequest; [Resolved] @@ -39,13 +45,22 @@ namespace osu.Game.Screens.Ranking { base.LoadComplete(); - soloStatisticsWatcher.RegisterForStatisticsUpdateAfter(Score, update => statisticsUpdate.Value = update); + if (ShowUserStatistics) + soloStatisticsWatcher.RegisterForStatisticsUpdateAfter(Score, update => statisticsUpdate.Value = update); } - protected override StatisticsPanel CreateStatisticsPanel() => new SoloStatisticsPanel(Score) + protected override StatisticsPanel CreateStatisticsPanel() { - StatisticsUpdate = { BindTarget = statisticsUpdate } - }; + if (ShowUserStatistics) + { + return new SoloStatisticsPanel(Score) + { + StatisticsUpdate = { BindTarget = statisticsUpdate } + }; + } + + return base.CreateStatisticsPanel(); + } protected override APIRequest FetchScores(Action> scoresCallback) { From 777ffcf805f07954377832a869472afee8c09a0a Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 26 Dec 2022 20:45:32 -0800 Subject: [PATCH 022/121] Highlight "open" option on external link button context menu --- osu.Game/Graphics/UserInterface/ExternalLinkButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs index efbbaaca85..4eccb37613 100644 --- a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs +++ b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs @@ -82,7 +82,7 @@ namespace osu.Game.Graphics.UserInterface if (Link != null) { - items.Add(new OsuMenuItem("Open", MenuItemType.Standard, () => host.OpenUrlExternally(Link))); + items.Add(new OsuMenuItem("Open", MenuItemType.Highlighted, () => host.OpenUrlExternally(Link))); items.Add(new OsuMenuItem("Copy URL", MenuItemType.Standard, copyUrl)); } From 182f36c434bd2b60895403cf07a1adde88912067 Mon Sep 17 00:00:00 2001 From: Berkan Diler Date: Tue, 27 Dec 2022 09:41:58 +0100 Subject: [PATCH 023/121] Use StringSplitOptions.TrimEntries for string.Split() when possible --- .../Screens/Drawings/Components/StorageBackedTeamList.cs | 8 ++++---- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 8 +------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tournament/Screens/Drawings/Components/StorageBackedTeamList.cs b/osu.Game.Tournament/Screens/Drawings/Components/StorageBackedTeamList.cs index c230607343..74afb42c1a 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/StorageBackedTeamList.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/StorageBackedTeamList.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components continue; // ReSharper disable once PossibleNullReferenceException - string[] split = line.Split(':'); + string[] split = line.Split(':', StringSplitOptions.TrimEntries); if (split.Length < 2) { @@ -55,9 +55,9 @@ namespace osu.Game.Tournament.Screens.Drawings.Components teams.Add(new TournamentTeam { - FullName = { Value = split[1].Trim(), }, - Acronym = { Value = split.Length >= 3 ? split[2].Trim() : null, }, - FlagName = { Value = split[0].Trim() } + FullName = { Value = split[1], }, + Acronym = { Value = split.Length >= 3 ? split[2] : null, }, + FlagName = { Value = split[0] } }); } } diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index a4e15f790a..704756e3dd 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -132,13 +132,7 @@ namespace osu.Game.Beatmaps.Formats protected KeyValuePair SplitKeyVal(string line, char separator = ':', bool shouldTrim = true) { - string[] split = line.Split(separator, 2); - - if (shouldTrim) - { - for (int i = 0; i < split.Length; i++) - split[i] = split[i].Trim(); - } + string[] split = line.Split(separator, 2, shouldTrim ? StringSplitOptions.TrimEntries : StringSplitOptions.None); return new KeyValuePair ( From b3e44f20bca94f78599500027eaaa7ce164f8e65 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Dec 2022 21:53:41 +0800 Subject: [PATCH 024/121] Use new lazer API endpoint This is a temporary change to target the new experimental/next deploy. The main change that should result from this is having the user profile show the pp^next values from the new domain. --- osu.Game/Online/ProductionEndpointConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/ProductionEndpointConfiguration.cs b/osu.Game/Online/ProductionEndpointConfiguration.cs index 316452280d..3a74d24b58 100644 --- a/osu.Game/Online/ProductionEndpointConfiguration.cs +++ b/osu.Game/Online/ProductionEndpointConfiguration.cs @@ -9,7 +9,7 @@ namespace osu.Game.Online { public ProductionEndpointConfiguration() { - WebsiteRootUrl = APIEndpointUrl = @"https://osu.ppy.sh"; + WebsiteRootUrl = APIEndpointUrl = @"https://lazer.ppy.sh"; APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; APIClientID = "5"; SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator"; From 61029b126d03f00bea9b7ecfa3862452fcf7c7e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Dec 2022 17:50:30 +0800 Subject: [PATCH 025/121] Add link to hard link explanation wiki page --- osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 8b85bb49a5..0f8a78453d 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -22,6 +22,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; +using osu.Game.Online.Chat; using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings.Sections.Maintenance; using osu.Game.Screens.Edit.Setup; @@ -127,7 +128,9 @@ namespace osu.Game.Overlays.FirstRunSetup if (available) { copyInformation.Text = - "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation."; + "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation. "; + + copyInformation.AddLink("Learn more about how \"hard links\" work", LinkAction.OpenWiki, @"Client/Release_stream/Lazer/File_storage#via-hard-links"); } else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import."; From 1a4489edb28c98907fda40551bd7f42f66174d2e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 27 Dec 2022 14:55:51 +0300 Subject: [PATCH 026/121] Move version pinning of system packages to `osu.Game` --- osu.Game/osu.Game.csproj | 5 +++++ osu.iOS.props | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index da14ed123f..cce3e42be4 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -43,5 +43,10 @@ + + + + + diff --git a/osu.iOS.props b/osu.iOS.props index 9b9abfc37b..6201022da1 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,10 +17,5 @@ - - - - - From e2703bba188b606760c74023f4cf7d62fdd8792a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 27 Dec 2022 19:48:18 +0100 Subject: [PATCH 027/121] Fix invalid data in test scene --- .../Visual/Ranking/TestSceneOverallRanking.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneOverallRanking.cs b/osu.Game.Tests/Visual/Ranking/TestSceneOverallRanking.cs index 2edc577a95..355a572f95 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneOverallRanking.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneOverallRanking.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Ranking new UserStatistics { GlobalRank = 12_345, - Accuracy = 0.9899, + Accuracy = 98.99, MaxCombo = 2_322, RankedScore = 23_123_543_456, TotalScore = 123_123_543_456, @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Ranking new UserStatistics { GlobalRank = 1_234, - Accuracy = 0.9907, + Accuracy = 99.07, MaxCombo = 2_352, RankedScore = 23_124_231_435, TotalScore = 123_124_231_435, @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Ranking new UserStatistics { GlobalRank = 1_234, - Accuracy = 0.9907, + Accuracy = 99.07, MaxCombo = 2_352, RankedScore = 23_124_231_435, TotalScore = 123_124_231_435, @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Ranking new UserStatistics { GlobalRank = 12_345, - Accuracy = 0.9899, + Accuracy = 98.99, MaxCombo = 2_322, RankedScore = 23_123_543_456, TotalScore = 123_123_543_456, @@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Ranking var statistics = new UserStatistics { GlobalRank = 12_345, - Accuracy = 0.9899, + Accuracy = 98.99, MaxCombo = 2_322, RankedScore = 23_123_543_456, TotalScore = 123_123_543_456, @@ -93,7 +93,7 @@ namespace osu.Game.Tests.Visual.Ranking var statistics = new UserStatistics { GlobalRank = null, - Accuracy = 0.9899, + Accuracy = 98.99, MaxCombo = 2_322, RankedScore = 23_123_543_456, TotalScore = 123_123_543_456, From e90619244da7ff3151c329193c4e80a4f602daa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 27 Dec 2022 19:51:51 +0100 Subject: [PATCH 028/121] Fix incorrect accuracy display on overall ranking view --- osu.Game/Screens/Ranking/Statistics/User/AccuracyChangeRow.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/User/AccuracyChangeRow.cs b/osu.Game/Screens/Ranking/Statistics/User/AccuracyChangeRow.cs index 0f5dd9074a..0fd666e9d0 100644 --- a/osu.Game/Screens/Ranking/Statistics/User/AccuracyChangeRow.cs +++ b/osu.Game/Screens/Ranking/Statistics/User/AccuracyChangeRow.cs @@ -16,11 +16,11 @@ namespace osu.Game.Screens.Ranking.Statistics.User protected override LocalisableString Label => UsersStrings.ShowStatsHitAccuracy; - protected override LocalisableString FormatCurrentValue(double current) => current.FormatAccuracy(); + protected override LocalisableString FormatCurrentValue(double current) => (current / 100).FormatAccuracy(); protected override int CalculateDifference(double previous, double current, out LocalisableString formattedDifference) { - double difference = current - previous; + double difference = (current - previous) / 100; if (difference < 0) formattedDifference = difference.FormatAccuracy(); From 0d78bc224826fc70deaf961ba0c4b5a997cb8e71 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Dec 2022 06:42:32 +0800 Subject: [PATCH 029/121] Fix `osu.ppy.sh` links no longer opening in-game Addresses https://github.com/ppy/osu/discussions/21838. --- osu.Game/Online/ProductionEndpointConfiguration.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/ProductionEndpointConfiguration.cs b/osu.Game/Online/ProductionEndpointConfiguration.cs index 3a74d24b58..003ec50afd 100644 --- a/osu.Game/Online/ProductionEndpointConfiguration.cs +++ b/osu.Game/Online/ProductionEndpointConfiguration.cs @@ -9,7 +9,8 @@ namespace osu.Game.Online { public ProductionEndpointConfiguration() { - WebsiteRootUrl = APIEndpointUrl = @"https://lazer.ppy.sh"; + WebsiteRootUrl = @"https://osu.ppy.sh"; + APIEndpointUrl = @"https://lazer.ppy.sh"; APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; APIClientID = "5"; SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator"; From e9d32fca18151036b7d2ba95fc7bae8f771671d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 07:28:18 +0100 Subject: [PATCH 030/121] Fix various failures in initial statistics fetch - If the local user is restricted, then attempting to fetch their data from the `/users` endpoint would result in an empty response. - Even if the user was successfully fetched, their `RulesetsStatistics` may not be populated (and instead be `null`). Curiously this was not picked up by static analysis until the first issue was fixed. Closes #21839. --- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 33344044b9..b2f371fd74 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -75,15 +75,27 @@ namespace osu.Game.Online.Solo return; var userRequest = new GetUsersRequest(new[] { localUser.OnlineID }); - userRequest.Success += response => Schedule(() => - { - latestStatistics = new Dictionary(); - foreach (var rulesetStats in response.Users.Single().RulesetsStatistics) - latestStatistics.Add(rulesetStats.Key, rulesetStats.Value); - }); + userRequest.Success += initialiseUserStatistics; api.Queue(userRequest); }); + private void initialiseUserStatistics(GetUsersResponse response) => Schedule(() => + { + var user = response.Users.SingleOrDefault(); + + // possible if the user is restricted or similar. + if (user == null) + return; + + latestStatistics = new Dictionary(); + + if (user.RulesetsStatistics != null) + { + foreach (var rulesetStats in user.RulesetsStatistics) + latestStatistics.Add(rulesetStats.Key, rulesetStats.Value); + } + }); + private void userScoreProcessed(int userId, long scoreId) { if (userId != api.LocalUser.Value?.OnlineID) From a0a26b1e8c257b40dc66ad62be754afcd8a7edda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 07:37:52 +0100 Subject: [PATCH 031/121] Ignore statistics update subscriptions with invalid score ID If score submission fails, the score will not receive a correct online ID from web, but will still be passed on to the solo statistics watcher on the results screen. This could lead to the watcher subscribing to changes with score ID equal to the default of -1. If this happened more than once, that would cause a crash due to duplicate keys in the `callbacks` dictionary. Closes #21837. --- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index b2f371fd74..235abde068 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -51,7 +51,7 @@ namespace osu.Game.Online.Solo if (!api.IsLoggedIn) return; - if (!score.Ruleset.IsLegacyRuleset()) + if (!score.Ruleset.IsLegacyRuleset() || score.OnlineID <= 0) return; var callback = new StatisticsUpdateCallback(score, onUpdateReady); From 04f9a354c3fb6e695e4cad4bfddd31b5ac8c03e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 07:49:09 +0100 Subject: [PATCH 032/121] Convert `SoloResultsScreen` to NRT --- osu.Game/Screens/Ranking/SoloResultsScreen.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Ranking/SoloResultsScreen.cs b/osu.Game/Screens/Ranking/SoloResultsScreen.cs index 110e813e04..94d333c2da 100644 --- a/osu.Game/Screens/Ranking/SoloResultsScreen.cs +++ b/osu.Game/Screens/Ranking/SoloResultsScreen.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; using System.Collections.Generic; using System.Linq; @@ -26,15 +24,15 @@ namespace osu.Game.Screens.Ranking /// public bool ShowUserStatistics { get; init; } - private GetScoresRequest getScoreRequest; + private GetScoresRequest? getScoreRequest; [Resolved] - private RulesetStore rulesets { get; set; } + private RulesetStore rulesets { get; set; } = null!; [Resolved] - private SoloStatisticsWatcher soloStatisticsWatcher { get; set; } + private SoloStatisticsWatcher soloStatisticsWatcher { get; set; } = null!; - private readonly Bindable statisticsUpdate = new Bindable(); + private readonly Bindable statisticsUpdate = new Bindable(); public SoloResultsScreen(ScoreInfo score, bool allowRetry) : base(score, allowRetry) @@ -62,7 +60,7 @@ namespace osu.Game.Screens.Ranking return base.CreateStatisticsPanel(); } - protected override APIRequest FetchScores(Action> scoresCallback) + protected override APIRequest? FetchScores(Action>? scoresCallback) { if (Score.BeatmapInfo.OnlineID <= 0 || Score.BeatmapInfo.Status <= BeatmapOnlineStatus.Pending) return null; From 3c0b8af8f1dbf19dbd9496c85d3555354fff7e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 07:50:10 +0100 Subject: [PATCH 033/121] Allow unsubscribing from solo statistics updates This is more of a safety item. To avoid potential duplicate key in dictionary errors (and also avoid being slightly memory-leaky), allow `SoloStatisticsWatcher` consumers to dispose of the subscriptions they take out. --- .../Online/TestSceneSoloStatisticsWatcher.cs | 24 ++++++++++++- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 36 +++++++++++-------- osu.Game/Screens/Ranking/SoloResultsScreen.cs | 4 ++- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs index b1badc6282..e62e53bd02 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs @@ -35,6 +35,8 @@ namespace osu.Game.Tests.Visual.Online private Action? handleGetUsersRequest; private Action? handleGetUserRequest; + private IDisposable? subscription; + private readonly Dictionary<(int userId, string rulesetName), UserStatistics> serverSideStatistics = new Dictionary<(int userId, string rulesetName), UserStatistics>(); [SetUpSteps] @@ -246,6 +248,26 @@ namespace osu.Game.Tests.Visual.Online AddAssert("values after are correct", () => update!.After.TotalScore, () => Is.EqualTo(6_000_000)); } + [Test] + public void TestStatisticsUpdateNotFiredAfterSubscriptionDisposal() + { + int userId = getUserId(); + setUpUser(userId); + + long scoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; + + SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); + AddStep("unsubscribe", () => subscription!.Dispose()); + + feignScoreProcessing(userId, ruleset, 5_000_000); + + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); + AddWaitStep("wait a bit", 5); + AddAssert("update not received", () => update == null); + } + private int nextUserId = 2000; private long nextScoreId = 50000; @@ -266,7 +288,7 @@ namespace osu.Game.Tests.Visual.Online } private void registerForUpdates(long scoreId, RulesetInfo rulesetInfo, Action onUpdateReady) => - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( + AddStep("register for updates", () => subscription = watcher.RegisterForStatisticsUpdateAfter( new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) { Ruleset = rulesetInfo, diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 235abde068..46449fea73 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -46,24 +46,30 @@ namespace osu.Game.Online.Solo /// /// The score to listen for the statistics update for. /// The callback to be invoked once the statistics update has been prepared. - public void RegisterForStatisticsUpdateAfter(ScoreInfo score, Action onUpdateReady) => Schedule(() => + /// An representing the subscription. Disposing it is equivalent to unsubscribing from future notifications. + public IDisposable RegisterForStatisticsUpdateAfter(ScoreInfo score, Action onUpdateReady) { - if (!api.IsLoggedIn) - return; - - if (!score.Ruleset.IsLegacyRuleset() || score.OnlineID <= 0) - return; - - var callback = new StatisticsUpdateCallback(score, onUpdateReady); - - if (lastProcessedScoreId == score.OnlineID) + Schedule(() => { - requestStatisticsUpdate(api.LocalUser.Value.Id, callback); - return; - } + if (!api.IsLoggedIn) + return; - callbacks.Add(score.OnlineID, callback); - }); + if (!score.Ruleset.IsLegacyRuleset() || score.OnlineID <= 0) + return; + + var callback = new StatisticsUpdateCallback(score, onUpdateReady); + + if (lastProcessedScoreId == score.OnlineID) + { + requestStatisticsUpdate(api.LocalUser.Value.Id, callback); + return; + } + + callbacks.Add(score.OnlineID, callback); + }); + + return new InvokeOnDisposal(() => Schedule(() => callbacks.Remove(score.OnlineID))); + } private void onUserChanged(APIUser? localUser) => Schedule(() => { diff --git a/osu.Game/Screens/Ranking/SoloResultsScreen.cs b/osu.Game/Screens/Ranking/SoloResultsScreen.cs index 94d333c2da..c8920a734d 100644 --- a/osu.Game/Screens/Ranking/SoloResultsScreen.cs +++ b/osu.Game/Screens/Ranking/SoloResultsScreen.cs @@ -32,6 +32,7 @@ namespace osu.Game.Screens.Ranking [Resolved] private SoloStatisticsWatcher soloStatisticsWatcher { get; set; } = null!; + private IDisposable? statisticsSubscription; private readonly Bindable statisticsUpdate = new Bindable(); public SoloResultsScreen(ScoreInfo score, bool allowRetry) @@ -44,7 +45,7 @@ namespace osu.Game.Screens.Ranking base.LoadComplete(); if (ShowUserStatistics) - soloStatisticsWatcher.RegisterForStatisticsUpdateAfter(Score, update => statisticsUpdate.Value = update); + statisticsSubscription = soloStatisticsWatcher.RegisterForStatisticsUpdateAfter(Score, update => statisticsUpdate.Value = update); } protected override StatisticsPanel CreateStatisticsPanel() @@ -75,6 +76,7 @@ namespace osu.Game.Screens.Ranking base.Dispose(isDisposing); getScoreRequest?.Cancel(); + statisticsSubscription?.Dispose(); } } } From 76367444cbebff0d893ae941df3e0179d9d9c3d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 10:36:54 +0100 Subject: [PATCH 034/121] Adjust Android package versioning to .NET 6 With .NET 6, the way Xamarin package versioning works has changed. - The `ApplicationVersion` MSBuild property aims to replace `android:versionCode` in the manifest. - The `ApplicationDisplayVersion` MSBuild property aims to replace `android:versionName` in the manifest. More about this can be read in Xamarin docs: https://github.com/xamarin/xamarin-android/blob/ec712da8c1ce03f71578e08cafb6a767cdb90cd5/Documentation/guides/OneDotNetSingleProject.md To this end: - Manual `version{Code,Name}` specs are removed from `AndroidManifest.xml`, as they were preventing MSBuild properties from functioning properly. - `Version` now defaults to 0.0.0, so that local builds don't appear like they were deployed (see `OsuGameBase.IsDeployedBuild`). - `ApplicationDisplayVersion` now defaults to `Version`. This addresses the Android portion of #21498. - `ApplicationVersion` can now be specified by command line, but still needs to be supplied manually for version detection to work correctly. See `OsuGameAndroid.AssemblyVersion` for more info. Putting the pieces together, the complete publish command to deploy a new build should look something like so: dotnet publish -f net6.0-android \ -r android-arm64 \ -c Release \ -p:Version=2022.1228.0 \ -p:ApplicationVersion=202212280 --- osu.Android/AndroidManifest.xml | 2 +- osu.Android/osu.Android.csproj | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Android/AndroidManifest.xml b/osu.Android/AndroidManifest.xml index be326be5eb..bc2f49b1a9 100644 --- a/osu.Android/AndroidManifest.xml +++ b/osu.Android/AndroidManifest.xml @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj index de53e5dd59..1507bfaa29 100644 --- a/osu.Android/osu.Android.csproj +++ b/osu.Android/osu.Android.csproj @@ -8,6 +8,9 @@ true false + 0.0.0 + 1 + $(Version) From b4c5e18da0347872e068086d6954d3321721ad1a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 28 Dec 2022 13:23:46 +0300 Subject: [PATCH 035/121] Add keywords to ease search of "first object visibility" setting --- osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs index 69e24bc616..f6b3c12487 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs @@ -27,6 +27,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { LabelText = GameplaySettingsStrings.IncreaseFirstObjectVisibility, Current = config.GetBindable(OsuSetting.IncreaseFirstObjectVisibility), + Keywords = new[] { @"approach", @"circle", @"hidden" }, }, }; } From 9021cf7be6b4b6f271f7159c215e13878f95c3ec Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Wed, 28 Dec 2022 11:42:34 +0100 Subject: [PATCH 036/121] Allow aspect ratios smaller than the default in taiko --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs index 79c5c36e08..d42aaddf9e 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Taiko.UI float height = default_relative_height; - if (LockPlayfieldAspect.Value) + if (LockPlayfieldAspect.Value && Parent.ChildSize.X / Parent.ChildSize.Y > default_aspect) height *= Math.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect; Height = height; From b2aa2e16029d984109049fce98c58466be867709 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Wed, 28 Dec 2022 13:23:07 +0100 Subject: [PATCH 037/121] Add hardlink support for Linux --- osu.Game/Database/RealmFileStore.cs | 16 +++++++++++---- osu.Game/IO/HardLinkHelper.cs | 20 ++++++++++++++----- .../FirstRunSetup/ScreenImportFromStable.cs | 2 +- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 04b503b808..49102d81e5 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -63,11 +63,19 @@ namespace osu.Game.Database private void copyToStore(RealmFile file, Stream data, bool preferHardLinks) { - if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows && data is FileStream fs && preferHardLinks) + // attempt to do a fast hard link rather than copy. + if (data is FileStream fs && preferHardLinks) { - // attempt to do a fast hard link rather than copy. - if (HardLinkHelper.CreateHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name, IntPtr.Zero)) - return; + if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows) + { + if (HardLinkHelper.CreateHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name, IntPtr.Zero)) + return; + } + else if (RuntimeInfo.OS == RuntimeInfo.Platform.Linux) + { + if (HardLinkHelper.link(fs.Name, Storage.GetFullPath(file.GetStoragePath(), true)) == 0) + return; + } } data.Seek(0, SeekOrigin.Begin); diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index 1393bf26fd..8d521bab9f 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -14,9 +14,8 @@ namespace osu.Game.IO { public static bool CheckAvailability(string testDestinationPath, string testSourcePath) { - // We can support other operating systems quite easily in the future. - // Let's handle the most common one for now, though. - if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) + // TODO: Add macOS support for hardlinks. + if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows || RuntimeInfo.OS != RuntimeInfo.Platform.Linux) return false; const string test_filename = "_hard_link_test"; @@ -26,12 +25,20 @@ namespace osu.Game.IO cleanupFiles(); + try { File.WriteAllText(testSourcePath, string.Empty); - // Test availability by creating an arbitrary hard link between the source and destination paths. - return CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero); + + bool isHardLinkAvailable = false; + + if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows) + isHardLinkAvailable = CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero); + else if (RuntimeInfo.OS == RuntimeInfo.Platform.Linux) + isHardLinkAvailable = link(testSourcePath, testDestinationPath) == 0; + + return isHardLinkAvailable; } catch { @@ -70,6 +77,9 @@ namespace osu.Game.IO return result; } + [DllImport("libc", SetLastError = true)] + public static extern int link(string oldpath, string newpath); + [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 0f8a78453d..2603a6c6c4 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -132,7 +132,7 @@ namespace osu.Game.Overlays.FirstRunSetup copyInformation.AddLink("Learn more about how \"hard links\" work", LinkAction.OpenWiki, @"Client/Release_stream/Lazer/File_storage#via-hard-links"); } - else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) + else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows || RuntimeInfo.OS != RuntimeInfo.Platform.Linux) copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import."; else { From 16165b1f67fc51ea01b906b020dc195788f99a2b Mon Sep 17 00:00:00 2001 From: BlauFx Date: Wed, 28 Dec 2022 13:58:52 +0100 Subject: [PATCH 038/121] Remove blank line --- osu.Game/IO/HardLinkHelper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index 8d521bab9f..b3eb528bbb 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -25,7 +25,6 @@ namespace osu.Game.IO cleanupFiles(); - try { File.WriteAllText(testSourcePath, string.Empty); From 5c5e84f931a45b5c35261d2e38aabc857730bc47 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Wed, 28 Dec 2022 14:06:50 +0100 Subject: [PATCH 039/121] Fix formatiing --- osu.Game/IO/HardLinkHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index b3eb528bbb..d059e8b710 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -76,7 +76,7 @@ namespace osu.Game.IO return result; } - [DllImport("libc", SetLastError = true)] + [DllImport("libc", SetLastError = true)] public static extern int link(string oldpath, string newpath); [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] From f32564652b3d07224c10cce449ba7dd28b7fecf4 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Wed, 28 Dec 2022 14:33:38 +0100 Subject: [PATCH 040/121] Mention the filesystem should be NTFS on Windows --- osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 2603a6c6c4..6e9b724774 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -136,8 +136,10 @@ namespace osu.Game.Overlays.FirstRunSetup copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import."; else { + string mentionNTFS = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? " (and the file system is NTFS)." : "."; + copyInformation.Text = - "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS). "; + $"A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install{mentionNTFS}"; copyInformation.AddLink(GeneralSettingsStrings.ChangeFolderLocation, () => { game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())); From 53bca947d13fe267260e3767c67cd6e30efd2154 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Wed, 28 Dec 2022 14:34:27 +0100 Subject: [PATCH 041/121] Move duplicated code into its own method --- osu.Game/Database/RealmFileStore.cs | 15 ++------------- osu.Game/IO/HardLinkHelper.cs | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 49102d81e5..e5ace5b346 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -64,19 +64,8 @@ namespace osu.Game.Database private void copyToStore(RealmFile file, Stream data, bool preferHardLinks) { // attempt to do a fast hard link rather than copy. - if (data is FileStream fs && preferHardLinks) - { - if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows) - { - if (HardLinkHelper.CreateHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name, IntPtr.Zero)) - return; - } - else if (RuntimeInfo.OS == RuntimeInfo.Platform.Linux) - { - if (HardLinkHelper.link(fs.Name, Storage.GetFullPath(file.GetStoragePath(), true)) == 0) - return; - } - } + if (data is FileStream fs && preferHardLinks && HardLinkHelper.AttemptHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name)) + return; data.Seek(0, SeekOrigin.Begin); diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index d059e8b710..c8fc6d9f49 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -28,16 +28,9 @@ namespace osu.Game.IO try { File.WriteAllText(testSourcePath, string.Empty); + // Test availability by creating an arbitrary hard link between the source and destination paths. - - bool isHardLinkAvailable = false; - - if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows) - isHardLinkAvailable = CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero); - else if (RuntimeInfo.OS == RuntimeInfo.Platform.Linux) - isHardLinkAvailable = link(testSourcePath, testDestinationPath) == 0; - - return isHardLinkAvailable; + return AttemptHardLink(testDestinationPath, testSourcePath); } catch { @@ -61,6 +54,18 @@ namespace osu.Game.IO } } + public static bool AttemptHardLink(string testDestinationPath, string testSourcePath) + { + bool isHardLinkAvailable = false; + + if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows) + isHardLinkAvailable = CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero); + else if (RuntimeInfo.OS == RuntimeInfo.Platform.Linux) + isHardLinkAvailable = link(testSourcePath, testDestinationPath) == 0; + + return isHardLinkAvailable; + } + // For future use (to detect if a file is a hard link with other references existing on disk). public static int GetFileLinkCount(string filePath) { From c6da7248bacc02b4879c329d68238d8865b46cd6 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Wed, 28 Dec 2022 14:40:32 +0100 Subject: [PATCH 042/121] Remove unnecessary directive --- osu.Game/Database/RealmFileStore.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index e5ace5b346..df276adbaf 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -4,7 +4,6 @@ using System; using System.IO; using System.Linq; -using osu.Framework; using osu.Framework.Extensions; using osu.Framework.IO.Stores; using osu.Framework.Logging; From d63be3ff17b8eaee6e39d757db32c8f124e4e3a6 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Wed, 28 Dec 2022 15:02:44 +0100 Subject: [PATCH 043/121] Change name of variable --- osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 6e9b724774..74c1bf955c 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -136,10 +136,10 @@ namespace osu.Game.Overlays.FirstRunSetup copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import."; else { - string mentionNTFS = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? " (and the file system is NTFS)." : "."; + string mentionNtfs = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? " (and the file system is NTFS)." : "."; copyInformation.Text = - $"A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install{mentionNTFS}"; + $"A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install{mentionNtfs}"; copyInformation.AddLink(GeneralSettingsStrings.ChangeFolderLocation, () => { game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())); From 2c346eae0d827abb91a05a3c0300a3c9e02076d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 21:19:28 +0100 Subject: [PATCH 044/121] Revert inlining of hard link creation into condition Just feels bad. Mixing data access with actual underlying logic. --- osu.Game/Database/RealmFileStore.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index df276adbaf..4f429cb20c 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -62,9 +62,12 @@ namespace osu.Game.Database private void copyToStore(RealmFile file, Stream data, bool preferHardLinks) { - // attempt to do a fast hard link rather than copy. - if (data is FileStream fs && preferHardLinks && HardLinkHelper.AttemptHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name)) - return; + if (data is FileStream fs && preferHardLinks) + { + // attempt to do a fast hard link rather than copy. + if (HardLinkHelper.AttemptHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name)) + return; + } data.Seek(0, SeekOrigin.Begin); From cadd487c75c0876ec15388f55577cbac97d2df2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 21:20:49 +0100 Subject: [PATCH 045/121] Use switch statement in `AttemptHardLink()` --- osu.Game/IO/HardLinkHelper.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index c8fc6d9f49..d6ca11a68f 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -56,14 +56,17 @@ namespace osu.Game.IO public static bool AttemptHardLink(string testDestinationPath, string testSourcePath) { - bool isHardLinkAvailable = false; + switch (RuntimeInfo.OS) + { + case RuntimeInfo.Platform.Windows: + return CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero); - if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows) - isHardLinkAvailable = CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero); - else if (RuntimeInfo.OS == RuntimeInfo.Platform.Linux) - isHardLinkAvailable = link(testSourcePath, testDestinationPath) == 0; + case RuntimeInfo.Platform.Linux: + return link(testSourcePath, testDestinationPath) == 0; - return isHardLinkAvailable; + default: + return false; + } } // For future use (to detect if a file is a hard link with other references existing on disk). From 04d4b4a6ce2a7cb5aff2bea79e8dd6378f34a833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 21:23:06 +0100 Subject: [PATCH 046/121] Rename and xmldoc hard link creation method --- osu.Game/Database/RealmFileStore.cs | 2 +- osu.Game/IO/HardLinkHelper.cs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 4f429cb20c..f75d3be725 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -65,7 +65,7 @@ namespace osu.Game.Database if (data is FileStream fs && preferHardLinks) { // attempt to do a fast hard link rather than copy. - if (HardLinkHelper.AttemptHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name)) + if (HardLinkHelper.TryCreateHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name)) return; } diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index d6ca11a68f..9c0a8fbba1 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -30,7 +30,7 @@ namespace osu.Game.IO File.WriteAllText(testSourcePath, string.Empty); // Test availability by creating an arbitrary hard link between the source and destination paths. - return AttemptHardLink(testDestinationPath, testSourcePath); + return TryCreateHardLink(testDestinationPath, testSourcePath); } catch { @@ -54,15 +54,23 @@ namespace osu.Game.IO } } - public static bool AttemptHardLink(string testDestinationPath, string testSourcePath) + /// + /// Attempts to create a hard link from to , + /// using platform-specific native methods. + /// + /// + /// Hard links are only available on Windows and Linux. + /// + /// Whether the hard link was successfully created. + public static bool TryCreateHardLink(string destinationPath, string sourcePath) { switch (RuntimeInfo.OS) { case RuntimeInfo.Platform.Windows: - return CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero); + return CreateHardLink(destinationPath, sourcePath, IntPtr.Zero); case RuntimeInfo.Platform.Linux: - return link(testSourcePath, testDestinationPath) == 0; + return link(sourcePath, destinationPath) == 0; default: return false; From d4b3965967ea155e94975409de1a5883c3981523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 21:25:24 +0100 Subject: [PATCH 047/121] Change warning message about file duplication - It was being glued in an ugly way that would have prevented sanely localising it. - Even on Linux, the filesystem (whichever one the user has chosen out of the multitude available) still needs to support hard links for them to have a chance of working. --- osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 74c1bf955c..8b1b50ed98 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -136,10 +136,9 @@ namespace osu.Game.Overlays.FirstRunSetup copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import."; else { - string mentionNtfs = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? " (and the file system is NTFS)." : "."; - - copyInformation.Text = - $"A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install{mentionNtfs}"; + copyInformation.Text = RuntimeInfo.OS == RuntimeInfo.Platform.Windows + ? "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS)." + : "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system supports hard links)."; copyInformation.AddLink(GeneralSettingsStrings.ChangeFolderLocation, () => { game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())); From 8d79fa93ac06a5913628a0eb2ba847a869fd7e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 21:58:30 +0100 Subject: [PATCH 048/121] Implement `GetFileLinkCount()` for Linux --- osu.Game/IO/HardLinkHelper.cs | 65 +++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index 9c0a8fbba1..03cb043cca 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -81,19 +81,30 @@ namespace osu.Game.IO public static int GetFileLinkCount(string filePath) { int result = 0; - SafeFileHandle handle = CreateFile(filePath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Archive, IntPtr.Zero); - ByHandleFileInformation fileInfo; + switch (RuntimeInfo.OS) + { + case RuntimeInfo.Platform.Windows: + SafeFileHandle handle = CreateFile(filePath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Archive, IntPtr.Zero); - if (GetFileInformationByHandle(handle, out fileInfo)) - result = (int)fileInfo.NumberOfLinks; - CloseHandle(handle); + ByHandleFileInformation fileInfo; + + if (GetFileInformationByHandle(handle, out fileInfo)) + result = (int)fileInfo.NumberOfLinks; + CloseHandle(handle); + break; + + case RuntimeInfo.Platform.Linux: + if (stat(filePath, out var statbuf) == 0) + result = (int)statbuf.st_nlink; + + break; + } return result; } - [DllImport("libc", SetLastError = true)] - public static extern int link(string oldpath, string newpath); + #region Windows native methods [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); @@ -129,5 +140,45 @@ namespace osu.Game.IO public readonly uint FileIndexHigh; public readonly uint FileIndexLow; } + + #endregion + + #region Linux native methods + + [DllImport("libc", SetLastError = true)] + public static extern int link(string oldpath, string newpath); + + [DllImport("libc", SetLastError = true)] + private static extern int stat(string pathname, out struct_stat statbuf); + + // ReSharper disable once InconsistentNaming + // Struct layout is likely non-portable across unices. Tread with caution. + [StructLayout(LayoutKind.Sequential)] + private struct struct_stat + { + public readonly long st_dev; + public readonly long st_ino; + public readonly long st_nlink; + public readonly int st_mode; + public readonly int st_uid; + public readonly int st_gid; + public readonly long st_rdev; + public readonly long st_size; + public readonly long st_blksize; + public readonly long st_blocks; + public readonly timespec st_atim; + public readonly timespec st_mtim; + public readonly timespec st_ctim; + } + + // ReSharper disable once InconsistentNaming + [StructLayout(LayoutKind.Sequential)] + private struct timespec + { + public readonly long tv_sec; + public readonly long tv_nsec; + } + + #endregion } } From 49b0ec9ddb43d0f507ba8155d7bec69ed7876bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 22:18:27 +0100 Subject: [PATCH 049/121] Fix broken condition --- osu.Game/IO/HardLinkHelper.cs | 2 +- osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index 03cb043cca..fef084f5f0 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -15,7 +15,7 @@ namespace osu.Game.IO public static bool CheckAvailability(string testDestinationPath, string testSourcePath) { // TODO: Add macOS support for hardlinks. - if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows || RuntimeInfo.OS != RuntimeInfo.Platform.Linux) + if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows && RuntimeInfo.OS != RuntimeInfo.Platform.Linux) return false; const string test_filename = "_hard_link_test"; diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 8b1b50ed98..0e7514a7dc 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -132,7 +132,7 @@ namespace osu.Game.Overlays.FirstRunSetup copyInformation.AddLink("Learn more about how \"hard links\" work", LinkAction.OpenWiki, @"Client/Release_stream/Lazer/File_storage#via-hard-links"); } - else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows || RuntimeInfo.OS != RuntimeInfo.Platform.Linux) + else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows && RuntimeInfo.OS != RuntimeInfo.Platform.Linux) copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import."; else { From 10c11e974de9c2533059bcd76b7abf248f497ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 22:19:49 +0100 Subject: [PATCH 050/121] Fix broken spacing --- osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 0e7514a7dc..2e3ab823f7 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -137,8 +137,8 @@ namespace osu.Game.Overlays.FirstRunSetup else { copyInformation.Text = RuntimeInfo.OS == RuntimeInfo.Platform.Windows - ? "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS)." - : "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system supports hard links)."; + ? "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS). " + : "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system supports hard links). "; copyInformation.AddLink(GeneralSettingsStrings.ChangeFolderLocation, () => { game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())); From 74bc5d46666403f54f9f6e5336c028e00cf1ff03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Dec 2022 22:38:42 +0100 Subject: [PATCH 051/121] Disable naming rule inspection on struct stat definition --- osu.Game/IO/HardLinkHelper.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index fef084f5f0..ebf2d2bd71 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -145,6 +145,8 @@ namespace osu.Game.IO #region Linux native methods +#pragma warning disable IDE1006 // Naming rule violation + [DllImport("libc", SetLastError = true)] public static extern int link(string oldpath, string newpath); @@ -179,6 +181,8 @@ namespace osu.Game.IO public readonly long tv_nsec; } +#pragma warning restore IDE1006 + #endregion } } From ffd9359f4a6c9ce223d889b87b6b936b9b8de333 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 28 Dec 2022 14:50:40 -0800 Subject: [PATCH 052/121] Add tests for chat text box saving / syncing --- .../Visual/Online/TestSceneChatOverlay.cs | 46 +++++++++++++++++++ .../Online/TestSceneStandAloneChatDisplay.cs | 32 +++++++++++-- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 8cc4eabcd7..a8369dd6d9 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -530,6 +530,52 @@ namespace osu.Game.Tests.Visual.Online }); } + [Test] + public void TestTextBoxSavePerChannel() + { + var testPMChannel = new Channel(testUser); + + AddStep("show overlay", () => chatOverlay.Show()); + joinTestChannel(0); + joinChannel(testPMChannel); + + AddAssert("listing is visible", () => listingIsVisible); + AddStep("search for 'number 2'", () => chatOverlayTextBox.Text = "number 2"); + AddAssert("'number 2' saved to selector", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == "number 2"); + + AddStep("select normal channel", () => clickDrawable(getChannelListItem(testChannel1))); + AddAssert("text box cleared on normal channel", () => chatOverlayTextBox.Text == string.Empty); + AddAssert("nothing saved on normal channel", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == string.Empty); + AddStep("type '727'", () => chatOverlayTextBox.Text = "727"); + AddAssert("'727' saved to normal channel", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == "727"); + + AddStep("select PM channel", () => clickDrawable(getChannelListItem(testPMChannel))); + AddAssert("text box cleared on PM channel", () => chatOverlayTextBox.Text == string.Empty); + AddAssert("nothing saved on PM channel", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == string.Empty); + AddStep("type 'hello'", () => chatOverlayTextBox.Text = "hello"); + AddAssert("'hello' saved to PM channel", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == "hello"); + + AddStep("select normal channel", () => clickDrawable(getChannelListItem(testChannel1))); + AddAssert("text box contains '727'", () => chatOverlayTextBox.Text == "727"); + + AddStep("select PM channel", () => clickDrawable(getChannelListItem(testPMChannel))); + AddAssert("text box contains 'hello'", () => chatOverlayTextBox.Text == "hello"); + AddStep("click close button", () => + { + ChannelListItemCloseButton closeButton = getChannelListItem(testPMChannel).ChildrenOfType().Single(); + clickDrawable(closeButton); + }); + + AddAssert("listing is visible", () => listingIsVisible); + AddAssert("text box contains 'channel 2'", () => chatOverlayTextBox.Text == "number 2"); + AddUntilStep("only channel 2 visible", () => + { + IEnumerable listingItems = chatOverlay.ChildrenOfType() + .Where(item => item.IsPresent); + return listingItems.Count() == 1 && listingItems.Single().Channel == testChannel2; + }); + } + private void joinTestChannel(int i) { AddStep($"Join test channel {i}", () => channelManager.JoinChannel(testChannels[i])); diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index ebd5e12acb..d7f79d3e30 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -50,6 +50,8 @@ namespace osu.Game.Tests.Visual.Online private ChannelManager channelManager; private TestStandAloneChatDisplay chatDisplay; + private TestStandAloneChatDisplay chatWithTextBox; + private TestStandAloneChatDisplay chatWithTextBox2; private int messageIdSequence; private Channel testChannel; @@ -78,7 +80,7 @@ namespace osu.Game.Tests.Visual.Online private void reinitialiseDrawableDisplay() { - Children = new[] + Children = new Drawable[] { chatDisplay = new TestStandAloneChatDisplay { @@ -88,13 +90,28 @@ namespace osu.Game.Tests.Visual.Online Size = new Vector2(400, 80), Channel = { Value = testChannel }, }, - new TestStandAloneChatDisplay(true) + new FillFlowContainer { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, Margin = new MarginPadding(20), - Size = new Vector2(400, 150), - Channel = { Value = testChannel }, + Children = new[] + { + chatWithTextBox = new TestStandAloneChatDisplay(true) + { + Margin = new MarginPadding(20), + Size = new Vector2(400, 150), + Channel = { Value = testChannel }, + }, + chatWithTextBox2 = new TestStandAloneChatDisplay(true) + { + Margin = new MarginPadding(20), + Size = new Vector2(400, 150), + Channel = { Value = testChannel }, + }, + } } }; } @@ -351,6 +368,13 @@ namespace osu.Game.Tests.Visual.Online checkScrolledToBottom(); } + [Test] + public void TestTextBoxSync() + { + AddStep("type 'hello' to text box 1", () => chatWithTextBox.ChildrenOfType().Single().Text = "hello"); + AddAssert("text box 2 contains 'hello'", () => chatWithTextBox2.ChildrenOfType().Single().Text == "hello"); + } + private void fillChat(int count = 10) { AddStep("fill chat", () => From c326745f96747453453f49f5d3e51e494f4682fd Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 28 Dec 2022 15:12:57 -0800 Subject: [PATCH 053/121] Save / sync chat text box messages per channel --- osu.Game/Online/Chat/Channel.cs | 5 +++++ osu.Game/Online/Chat/StandAloneChatDisplay.cs | 8 ++++++++ osu.Game/Overlays/Chat/ChatTextBar.cs | 11 ++++++++--- osu.Game/Overlays/Chat/ChatTextBox.cs | 1 - 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index 24b384b1d4..761e8aba8d 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -98,6 +98,11 @@ namespace osu.Game.Online.Chat /// public Bindable HighlightedMessage = new Bindable(); + /// + /// The current text box message while in this . + /// + public Bindable TextBoxMessage = new Bindable(string.Empty); + [JsonConstructor] public Channel() { diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 7fd6f99102..43da9a1d43 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -87,6 +87,14 @@ namespace osu.Game.Online.Chat channelManager ??= manager; } + protected override void LoadComplete() + { + base.LoadComplete(); + + if (channelManager != null) + TextBox?.Current.BindTo(channelManager.CurrentChannel.Value.TextBoxMessage); + } + protected virtual StandAloneDrawableChannel CreateDrawableChannel(Channel channel) => new StandAloneDrawableChannel(channel); diff --git a/osu.Game/Overlays/Chat/ChatTextBar.cs b/osu.Game/Overlays/Chat/ChatTextBar.cs index bcf5c1a409..682c96a695 100644 --- a/osu.Game/Overlays/Chat/ChatTextBar.cs +++ b/osu.Game/Overlays/Chat/ChatTextBar.cs @@ -128,9 +128,8 @@ namespace osu.Game.Overlays.Chat chattingTextContainer.FadeTo(showSearch ? 0 : 1); searchIconContainer.FadeTo(showSearch ? 1 : 0); - // Clear search terms if any exist when switching back to chat mode - if (!showSearch) - OnSearchTermsChanged?.Invoke(string.Empty); + if (showSearch) + OnSearchTermsChanged?.Invoke(chatTextBox.Current.Value); }, true); currentChannel.BindValueChanged(change => @@ -151,6 +150,12 @@ namespace osu.Game.Overlays.Chat chattingText.Text = ChatStrings.TalkingIn(newChannel.Name); break; } + + if (change.OldValue != null) + chatTextBox.Current.UnbindFrom(change.OldValue.TextBoxMessage); + + if (newChannel != null) + chatTextBox.Current.BindTo(newChannel.TextBoxMessage); }, true); } diff --git a/osu.Game/Overlays/Chat/ChatTextBox.cs b/osu.Game/Overlays/Chat/ChatTextBox.cs index 780c85a9c1..7cd005698e 100644 --- a/osu.Game/Overlays/Chat/ChatTextBox.cs +++ b/osu.Game/Overlays/Chat/ChatTextBox.cs @@ -24,7 +24,6 @@ namespace osu.Game.Overlays.Chat bool showSearch = change.NewValue; PlaceholderText = showSearch ? HomeStrings.SearchPlaceholder : ChatStrings.InputPlaceholder; - Text = string.Empty; }, true); } From 70dbb8edac4a2f7ed7513ade3e186cddfb95adfd Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 29 Dec 2022 01:37:37 -0800 Subject: [PATCH 054/121] Fix stand alone chat display textbox not binding to local channel --- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 43da9a1d43..0a5434822b 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -87,14 +87,6 @@ namespace osu.Game.Online.Chat channelManager ??= manager; } - protected override void LoadComplete() - { - base.LoadComplete(); - - if (channelManager != null) - TextBox?.Current.BindTo(channelManager.CurrentChannel.Value.TextBoxMessage); - } - protected virtual StandAloneDrawableChannel CreateDrawableChannel(Channel channel) => new StandAloneDrawableChannel(channel); @@ -119,8 +111,13 @@ namespace osu.Game.Online.Chat { drawableChannel?.Expire(); + if (e.OldValue != null) + TextBox?.Current.UnbindFrom(e.OldValue.TextBoxMessage); + if (e.NewValue == null) return; + TextBox?.Current.BindTo(e.NewValue.TextBoxMessage); + drawableChannel = CreateDrawableChannel(e.NewValue); drawableChannel.CreateChatLineAction = CreateMessage; drawableChannel.Padding = new MarginPadding { Bottom = postingTextBox ? text_box_height : 0 }; From cacc23204d2a94d79e947a495444d95506ce27f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 29 Dec 2022 13:16:13 +0100 Subject: [PATCH 055/121] Add failing test coverage --- osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs index 0bc42b06dd..acb68fc9cd 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs @@ -201,6 +201,22 @@ namespace osu.Game.Tests.Visual.Menus AddAssert("volume not changed", () => Audio.Volume.Value == 0.5); } + [Test] + public void TestRulesetSelectorOverflow() + { + AddStep("set toolbar width", () => + { + toolbar.RelativeSizeAxes = Axes.None; + toolbar.Width = 0; + }); + AddStep("move mouse over news toggle button", () => + { + var button = toolbar.ChildrenOfType().Single(); + InputManager.MoveMouseTo(button); + }); + AddAssert("no ruleset toggle buttons hovered", () => !toolbar.ChildrenOfType().Any(button => button.IsHovered)); + } + public partial class TestToolbar : Toolbar { public new Bindable OverlayActivationMode => base.OverlayActivationMode as Bindable; From c5f7da9a4ecb6f9d1810653d09adacbae0d877a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 29 Dec 2022 13:18:59 +0100 Subject: [PATCH 056/121] Fix hover propagating through toolbar buttons Closes #21920. Weirdly enough this was semeingly fixed once before in ancient times in 3891f467a34562d2d921fe996654802d0b29ab0b, but then unfixed again in 566e09083f06b87591c7745d82adf0d831a6066f. The second change is no longer needed since the toolbar became opaque in #9447. --- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index ea5fc5bb38..4193e52584 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -179,7 +179,7 @@ namespace osu.Game.Overlays.Toolbar HoverBackground.FadeIn(200); tooltipContainer.FadeIn(100); - return base.OnHover(e); + return true; } protected override void OnHoverLost(HoverLostEvent e) From 0fcf10e10a0bdfd121c47b81649769a3e70a92f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Dec 2022 22:35:13 +0800 Subject: [PATCH 057/121] Also support hard links on macOS --- osu.Game/IO/HardLinkHelper.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index ebf2d2bd71..619bfdad6e 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -14,8 +14,8 @@ namespace osu.Game.IO { public static bool CheckAvailability(string testDestinationPath, string testSourcePath) { - // TODO: Add macOS support for hardlinks. - if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows && RuntimeInfo.OS != RuntimeInfo.Platform.Linux) + // For simplicity, only support desktop operating systems for now. + if (!RuntimeInfo.IsDesktop) return false; const string test_filename = "_hard_link_test"; @@ -59,7 +59,7 @@ namespace osu.Game.IO /// using platform-specific native methods. /// /// - /// Hard links are only available on Windows and Linux. + /// Hard links are only available on desktop platforms. /// /// Whether the hard link was successfully created. public static bool TryCreateHardLink(string destinationPath, string sourcePath) @@ -70,6 +70,7 @@ namespace osu.Game.IO return CreateHardLink(destinationPath, sourcePath, IntPtr.Zero); case RuntimeInfo.Platform.Linux: + case RuntimeInfo.Platform.macOS: return link(sourcePath, destinationPath) == 0; default: @@ -95,6 +96,7 @@ namespace osu.Game.IO break; case RuntimeInfo.Platform.Linux: + case RuntimeInfo.Platform.macOS: if (stat(filePath, out var statbuf) == 0) result = (int)statbuf.st_nlink; From ccf713c885c1dd77155a22d95db00158f45ae6d8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Dec 2022 23:18:12 +0800 Subject: [PATCH 058/121] Fix incorrect hard link validity check in stable import screen --- osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 2e3ab823f7..0a2274575f 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -132,7 +132,7 @@ namespace osu.Game.Overlays.FirstRunSetup copyInformation.AddLink("Learn more about how \"hard links\" work", LinkAction.OpenWiki, @"Client/Release_stream/Lazer/File_storage#via-hard-links"); } - else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows && RuntimeInfo.OS != RuntimeInfo.Platform.Linux) + else if (!RuntimeInfo.IsDesktop) copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import."; else { From f7febdac5e20ba71eb1dee4c64dd1916a558135a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 29 Dec 2022 22:48:33 +0100 Subject: [PATCH 059/121] Add failing assertion --- osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs index acb68fc9cd..aef6f9ade0 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs @@ -207,7 +207,7 @@ namespace osu.Game.Tests.Visual.Menus AddStep("set toolbar width", () => { toolbar.RelativeSizeAxes = Axes.None; - toolbar.Width = 0; + toolbar.Width = 400; }); AddStep("move mouse over news toggle button", () => { @@ -215,6 +215,7 @@ namespace osu.Game.Tests.Visual.Menus InputManager.MoveMouseTo(button); }); AddAssert("no ruleset toggle buttons hovered", () => !toolbar.ChildrenOfType().Any(button => button.IsHovered)); + AddUntilStep("toolbar gradient visible", () => toolbar.ChildrenOfType().Single().Children.All(d => d.Alpha > 0)); } public partial class TestToolbar : Toolbar From bf975eb48a89707d69b62ff1e2bebd434464ad2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 29 Dec 2022 23:02:45 +0100 Subject: [PATCH 060/121] Fix toolbar gradient not showing when mouse is hovered over buttons --- osu.Game/Overlays/Toolbar/Toolbar.cs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index ac0f822f68..a559363bbf 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -13,6 +13,7 @@ using osuTK; using osu.Framework.Graphics.Shapes; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Game.Rulesets; using osu.Framework.Input.Bindings; @@ -196,6 +197,9 @@ namespace osu.Game.Overlays.Toolbar public partial class ToolbarBackground : Container { + private InputManager inputManager; + private Bindable showGradient { get; } = new BindableBool(); + private readonly Box gradientBackground; public ToolbarBackground() @@ -220,15 +224,26 @@ namespace osu.Game.Overlays.Toolbar }; } - protected override bool OnHover(HoverEvent e) + protected override void LoadComplete() { - gradientBackground.FadeIn(transition_time, Easing.OutQuint); - return true; + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + showGradient.BindValueChanged(_ => updateState(), true); } - protected override void OnHoverLost(HoverLostEvent e) + protected override void Update() { - gradientBackground.FadeOut(transition_time, Easing.OutQuint); + base.Update(); + showGradient.Value = Contains(inputManager.CurrentState.Mouse.Position); + } + + private void updateState() + { + if (showGradient.Value) + gradientBackground.FadeIn(transition_time, Easing.OutQuint); + else + gradientBackground.FadeOut(transition_time, Easing.OutQuint); } } From f625c5d7446144455f2366a252392467de2a1038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 29 Dec 2022 23:34:33 +0100 Subject: [PATCH 061/121] Fix gradient showing when toggling toolbar with mouse above window --- osu.Game/Overlays/Toolbar/Toolbar.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index a559363bbf..dbad866f74 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -235,7 +235,11 @@ namespace osu.Game.Overlays.Toolbar protected override void Update() { base.Update(); - showGradient.Value = Contains(inputManager.CurrentState.Mouse.Position); + + var currentMousePosition = inputManager.CurrentState.Mouse.Position; + // ensure that the gradient is not shown if the mouse is above the window. + // this is relevant when the background is moving due to the toolbar being toggled. + showGradient.Value = currentMousePosition.Y >= 0 && Contains(inputManager.CurrentState.Mouse.Position); } private void updateState() From 0d70f2c0fd3d070b49c6ce4225a88bed63932392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 09:07:48 +0100 Subject: [PATCH 062/121] Use alternative workaround --- osu.Game/Overlays/Toolbar/Toolbar.cs | 54 +++++++++++++++++++--------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index dbad866f74..f21ef0ee98 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -13,7 +13,6 @@ using osuTK; using osu.Framework.Graphics.Shapes; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Game.Rulesets; using osu.Framework.Input.Bindings; @@ -66,9 +65,12 @@ namespace osu.Game.Overlays.Toolbar [BackgroundDependencyLoader(true)] private void load(OsuGame osuGame) { + ToolbarBackground background; + HoverInterceptor interceptor; + Children = new Drawable[] { - new ToolbarBackground(), + background = new ToolbarBackground(), new GridContainer { RelativeSizeAxes = Axes.Both, @@ -181,9 +183,15 @@ namespace osu.Game.Overlays.Toolbar }, }, } + }, + interceptor = new HoverInterceptor + { + RelativeSizeAxes = Axes.Both } }; + ((IBindable)background.ShowGradient).BindTo(interceptor.ReceivedHover); + if (osuGame != null) OverlayActivationMode.BindTo(osuGame.OverlayActivationMode); } @@ -197,8 +205,7 @@ namespace osu.Game.Overlays.Toolbar public partial class ToolbarBackground : Container { - private InputManager inputManager; - private Bindable showGradient { get; } = new BindableBool(); + public Bindable ShowGradient { get; } = new BindableBool(); private readonly Box gradientBackground; @@ -228,29 +235,42 @@ namespace osu.Game.Overlays.Toolbar { base.LoadComplete(); - inputManager = GetContainingInputManager(); - showGradient.BindValueChanged(_ => updateState(), true); - } - - protected override void Update() - { - base.Update(); - - var currentMousePosition = inputManager.CurrentState.Mouse.Position; - // ensure that the gradient is not shown if the mouse is above the window. - // this is relevant when the background is moving due to the toolbar being toggled. - showGradient.Value = currentMousePosition.Y >= 0 && Contains(inputManager.CurrentState.Mouse.Position); + ShowGradient.BindValueChanged(_ => updateState(), true); } private void updateState() { - if (showGradient.Value) + if (ShowGradient.Value) gradientBackground.FadeIn(transition_time, Easing.OutQuint); else gradientBackground.FadeOut(transition_time, Easing.OutQuint); } } + /// + /// Whenever the mouse cursor is within the bounds of the toolbar, we want the background gradient to show, for toolbar button descriptions to be legible. + /// Unfortunately we also need to ensure that the toolbar buttons handle hover, to prevent the possibility of multiple descriptions being shown + /// due to hover events passing through multiple buttons. + /// This drawable is a workaround, that when placed front-most in the toolbar, allows to see whether hover events have been propagated through it without handling them. + /// + private partial class HoverInterceptor : Drawable + { + public IBindable ReceivedHover => receivedHover; + private readonly Bindable receivedHover = new BindableBool(); + + protected override bool OnHover(HoverEvent e) + { + receivedHover.Value = true; + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + receivedHover.Value = false; + base.OnHoverLost(e); + } + } + protected override void UpdateState(ValueChangedEvent state) { bool blockShow = hiddenByUser || OverlayActivationMode.Value == OverlayActivation.Disabled; From 3c32a50c125bf4e9b28b26298277bb80cc38cb0f Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 30 Dec 2022 21:19:46 +0900 Subject: [PATCH 063/121] add new accuracy counter display --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 14 ++++++++ .../Play/HUD/GameplayAccuracyCounter.cs | 32 ++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 4228840461..cec2b7e6b9 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -39,6 +39,16 @@ namespace osu.Game.Rulesets.Scoring /// public readonly BindableDouble Accuracy = new BindableDouble(1) { MinValue = 0, MaxValue = 1 }; + /// + /// The accuracy which increase from 0%. + /// + public readonly BindableDouble IncreaseAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; + + /// + /// The accuracy which Decrease from 100%. + /// + public readonly BindableDouble DecreaseAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; + /// /// The current combo. /// @@ -264,6 +274,10 @@ namespace osu.Game.Rulesets.Scoring private void updateScore() { Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1; + IncreaseAccuracy.Value = maximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / maximumScoringValues.BaseScore : 0; + DecreaseAccuracy.Value = maximumScoringValues.BaseScore > 0 + ? (double)(maximumScoringValues.BaseScore - (currentMaximumScoringValues.BaseScore - currentScoringValues.BaseScore)) / maximumScoringValues.BaseScore + : 1; TotalScore.Value = computeScore(Mode.Value, currentScoringValues, maximumScoringValues); } diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index 1933193515..f8848f57b9 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -4,6 +4,8 @@ #nullable disable using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Scoring; @@ -11,10 +13,38 @@ namespace osu.Game.Screens.Play.HUD { public abstract partial class GameplayAccuracyCounter : PercentageCounter { + [SettingSource("Accuracy Display Mode")] + public Bindable AccType { get; } = new Bindable(); + [BackgroundDependencyLoader] private void load(ScoreProcessor scoreProcessor) { - Current.BindTo(scoreProcessor.Accuracy); + AccType.BindValueChanged(mod => + { + Current.UnbindBindings(); + + switch (mod.NewValue) + { + case AccuracyType.Current: + Current.BindTo(scoreProcessor.Accuracy); + break; + + case AccuracyType.Increase: + Current.BindTo(scoreProcessor.IncreaseAccuracy); + break; + + case AccuracyType.Decrease: + Current.BindTo(scoreProcessor.DecreaseAccuracy); + break; + } + }, true); + } + + public enum AccuracyType + { + Current, + Increase, + Decrease } } } From a91da2284d27e5dc84c98b724cbbfae5cc4c2fad Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 30 Dec 2022 22:58:46 +0900 Subject: [PATCH 064/121] safe way to pass bindable --- .../Components/Timelines/Summary/Parts/PreviewTimePart.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs index 6149900fdc..b20f971086 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs @@ -22,10 +22,13 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts private partial class PreviewTimeVisualisation : PointVisualisation { + private BindableInt previewTime = new BindableInt(); + public PreviewTimeVisualisation(BindableInt time) : base(time.Value) { - time.BindValueChanged(s => X = s.NewValue); + previewTime.BindTo(time); + previewTime.BindValueChanged(s => X = s.NewValue); } [BackgroundDependencyLoader] From 23c485c763e91b4e7352138a0a94ec698afbb09c Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 30 Dec 2022 22:59:56 +0900 Subject: [PATCH 065/121] readonly --- .../Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs index b20f971086..bd34662969 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts private partial class PreviewTimeVisualisation : PointVisualisation { - private BindableInt previewTime = new BindableInt(); + private readonly BindableInt previewTime = new BindableInt(); public PreviewTimeVisualisation(BindableInt time) : base(time.Value) From 784fe7ecf2278bf112f4a101d37a290ad028b67f Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 30 Dec 2022 23:06:10 +0900 Subject: [PATCH 066/121] rename `AccType` to `AccuracyDisplay` --- osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index f8848f57b9..a862e5e230 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -14,12 +14,12 @@ namespace osu.Game.Screens.Play.HUD public abstract partial class GameplayAccuracyCounter : PercentageCounter { [SettingSource("Accuracy Display Mode")] - public Bindable AccType { get; } = new Bindable(); + public Bindable AccuracyDisplay { get; } = new Bindable(); [BackgroundDependencyLoader] private void load(ScoreProcessor scoreProcessor) { - AccType.BindValueChanged(mod => + AccuracyDisplay.BindValueChanged(mod => { Current.UnbindBindings(); From 8beb168be9775b93947af36ab8d2ca54cf22a536 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 30 Dec 2022 23:24:20 +0900 Subject: [PATCH 067/121] remove nullable disabled --- osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index a862e5e230..f7916d833a 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Configuration; From d60349c7c606ba8a6b27a9b38d3448b609b89c0b Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 30 Dec 2022 23:24:41 +0900 Subject: [PATCH 068/121] add description --- osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index f7916d833a..ba96260f51 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Configuration; @@ -11,7 +12,7 @@ namespace osu.Game.Screens.Play.HUD { public abstract partial class GameplayAccuracyCounter : PercentageCounter { - [SettingSource("Accuracy Display Mode")] + [SettingSource("Accuracy Display Mode", "Which Accuracy will display")] public Bindable AccuracyDisplay { get; } = new Bindable(); [BackgroundDependencyLoader] @@ -23,7 +24,7 @@ namespace osu.Game.Screens.Play.HUD switch (mod.NewValue) { - case AccuracyType.Current: + case AccuracyType.Rolling: Current.BindTo(scoreProcessor.Accuracy); break; @@ -40,8 +41,13 @@ namespace osu.Game.Screens.Play.HUD public enum AccuracyType { - Current, + [Description("Rolling")] + Rolling, + + [Description("Best achievable")] Increase, + + [Description("Worst achievable")] Decrease } } From 6d42cc5a360c4907357802e1720c2b563c0ac3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 20:30:58 +0100 Subject: [PATCH 069/121] Naming pass --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 8 +++--- .../Play/HUD/GameplayAccuracyCounter.cs | 28 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index cec2b7e6b9..c379691c52 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -42,12 +42,12 @@ namespace osu.Game.Rulesets.Scoring /// /// The accuracy which increase from 0%. /// - public readonly BindableDouble IncreaseAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; + public readonly BindableDouble MinimumAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; /// /// The accuracy which Decrease from 100%. /// - public readonly BindableDouble DecreaseAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; + public readonly BindableDouble MaximumAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; /// /// The current combo. @@ -274,8 +274,8 @@ namespace osu.Game.Rulesets.Scoring private void updateScore() { Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1; - IncreaseAccuracy.Value = maximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / maximumScoringValues.BaseScore : 0; - DecreaseAccuracy.Value = maximumScoringValues.BaseScore > 0 + MinimumAccuracy.Value = maximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / maximumScoringValues.BaseScore : 0; + MaximumAccuracy.Value = maximumScoringValues.BaseScore > 0 ? (double)(maximumScoringValues.BaseScore - (currentMaximumScoringValues.BaseScore - currentScoringValues.BaseScore)) / maximumScoringValues.BaseScore : 1; TotalScore.Value = computeScore(Mode.Value, currentScoringValues, maximumScoringValues); diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index ba96260f51..32e7827be8 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -12,8 +12,8 @@ namespace osu.Game.Screens.Play.HUD { public abstract partial class GameplayAccuracyCounter : PercentageCounter { - [SettingSource("Accuracy Display Mode", "Which Accuracy will display")] - public Bindable AccuracyDisplay { get; } = new Bindable(); + [SettingSource("Accuracy display mode", "Which accuracy mode should be displayed.")] + public Bindable AccuracyDisplay { get; } = new Bindable(); [BackgroundDependencyLoader] private void load(ScoreProcessor scoreProcessor) @@ -24,31 +24,31 @@ namespace osu.Game.Screens.Play.HUD switch (mod.NewValue) { - case AccuracyType.Rolling: + case AccuracyDisplayMode.Standard: Current.BindTo(scoreProcessor.Accuracy); break; - case AccuracyType.Increase: - Current.BindTo(scoreProcessor.IncreaseAccuracy); + case AccuracyDisplayMode.MinimumAchievable: + Current.BindTo(scoreProcessor.MinimumAccuracy); break; - case AccuracyType.Decrease: - Current.BindTo(scoreProcessor.DecreaseAccuracy); + case AccuracyDisplayMode.MaximumAchievable: + Current.BindTo(scoreProcessor.MaximumAccuracy); break; } }, true); } - public enum AccuracyType + public enum AccuracyDisplayMode { - [Description("Rolling")] - Rolling, + [Description("Standard")] + Standard, - [Description("Best achievable")] - Increase, + [Description("Maximum achievable")] + MaximumAchievable, - [Description("Worst achievable")] - Decrease + [Description("Minimum achievable")] + MinimumAchievable } } } From bb2822a175a44604a4bd2b08b04ff63c30bad788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 20:43:23 +0100 Subject: [PATCH 070/121] xmldoc pass --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index c379691c52..ab4422b2ef 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -40,12 +40,14 @@ namespace osu.Game.Rulesets.Scoring public readonly BindableDouble Accuracy = new BindableDouble(1) { MinValue = 0, MaxValue = 1 }; /// - /// The accuracy which increase from 0%. + /// The minimum achievable accuracy for the whole beatmap at this stage of gameplay. + /// Assumes that all objects that have not been judged yet will receive the minimum hit result. /// public readonly BindableDouble MinimumAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; /// - /// The accuracy which Decrease from 100%. + /// The maximum achievable accuracy for the whole beatmap at this stage of gameplay. + /// Assumes that all objects that have not been judged yet will receive the maximum hit result. /// public readonly BindableDouble MaximumAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; From 8ace635249edccfc3eae7ac2f1519a821d518674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 20:43:47 +0100 Subject: [PATCH 071/121] Adjust minimum values --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index ab4422b2ef..2fec68f0b0 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -43,13 +43,13 @@ namespace osu.Game.Rulesets.Scoring /// The minimum achievable accuracy for the whole beatmap at this stage of gameplay. /// Assumes that all objects that have not been judged yet will receive the minimum hit result. /// - public readonly BindableDouble MinimumAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; + public readonly BindableDouble MinimumAccuracy = new BindableDouble { MinValue = 0, MaxValue = 1 }; /// /// The maximum achievable accuracy for the whole beatmap at this stage of gameplay. /// Assumes that all objects that have not been judged yet will receive the maximum hit result. /// - public readonly BindableDouble MaximumAccuracy = new BindableDouble(0) { MinValue = 0, MaxValue = 1 }; + public readonly BindableDouble MaximumAccuracy = new BindableDouble(1) { MinValue = 0, MaxValue = 1 }; /// /// The current combo. From ae026e2d2db216ee35aeeb776f677af84fad512e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 20:52:05 +0100 Subject: [PATCH 072/121] Add test coverage --- .../Gameplay/TestSceneScoreProcessor.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs index 3ce7aa72d9..90c7688443 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Judgements; @@ -139,6 +140,29 @@ namespace osu.Game.Tests.Gameplay Assert.That(score.MaximumStatistics[HitResult.LargeBonus], Is.EqualTo(1)); } + [Test] + public void TestAccuracyModes() + { + var beatmap = new Beatmap + { + HitObjects = Enumerable.Range(0, 4).Select(_ => new TestHitObject(HitResult.Great)).ToList() + }; + + var scoreProcessor = new ScoreProcessor(new OsuRuleset()); + scoreProcessor.ApplyBeatmap(beatmap); + + Assert.That(scoreProcessor.Accuracy.Value, Is.EqualTo(1)); + Assert.That(scoreProcessor.MinimumAccuracy.Value, Is.EqualTo(0)); + Assert.That(scoreProcessor.MaximumAccuracy.Value, Is.EqualTo(1)); + + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], beatmap.HitObjects[0].CreateJudgement()) { Type = HitResult.Ok }); + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[1], beatmap.HitObjects[1].CreateJudgement()) { Type = HitResult.Great }); + + Assert.That(scoreProcessor.Accuracy.Value, Is.EqualTo((double)(100 + 300) / (2 * 300)).Within(Precision.DOUBLE_EPSILON)); + Assert.That(scoreProcessor.MinimumAccuracy.Value, Is.EqualTo((double)(100 + 300) / (4 * 300)).Within(Precision.DOUBLE_EPSILON)); + Assert.That(scoreProcessor.MaximumAccuracy.Value, Is.EqualTo((double)(100 + 3 * 300) / (4 * 300)).Within(Precision.DOUBLE_EPSILON)); + } + private class TestJudgement : Judgement { public override HitResult MaxResult { get; } From 6ed474d4fbb1be6523bbf809273dee21748bf926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 20:56:54 +0100 Subject: [PATCH 073/121] Rearrange formula for maximum accuracy Feels like it's easier to understand this way. The difference of the maximum scoring values for the entire beatmap and the max values for the part of the beatmap that has already been played represents the act of filling the rest of the unjudged objects with maximum results. --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 2fec68f0b0..13276a8748 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -278,7 +278,7 @@ namespace osu.Game.Rulesets.Scoring Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1; MinimumAccuracy.Value = maximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / maximumScoringValues.BaseScore : 0; MaximumAccuracy.Value = maximumScoringValues.BaseScore > 0 - ? (double)(maximumScoringValues.BaseScore - (currentMaximumScoringValues.BaseScore - currentScoringValues.BaseScore)) / maximumScoringValues.BaseScore + ? (double)(currentScoringValues.BaseScore + (maximumScoringValues.BaseScore - currentMaximumScoringValues.BaseScore)) / maximumScoringValues.BaseScore : 1; TotalScore.Value = computeScore(Mode.Value, currentScoringValues, maximumScoringValues); } From 7580ab78be796e9bf80b2b8dd8a3a96dbca2a904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 21:08:48 +0100 Subject: [PATCH 074/121] Move binding to `LoadComplete()` --- osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index 32e7827be8..210f96ce46 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -15,9 +15,13 @@ namespace osu.Game.Screens.Play.HUD [SettingSource("Accuracy display mode", "Which accuracy mode should be displayed.")] public Bindable AccuracyDisplay { get; } = new Bindable(); - [BackgroundDependencyLoader] - private void load(ScoreProcessor scoreProcessor) + [Resolved] + private ScoreProcessor scoreProcessor { get; set; } = null!; + + protected override void LoadComplete() { + base.LoadComplete(); + AccuracyDisplay.BindValueChanged(mod => { Current.UnbindBindings(); From 6509d3538c203f41049218899b1dd0471dcfa385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 21:12:29 +0100 Subject: [PATCH 075/121] Fix counter initially rolling down from 100% to 0% in minimum achievable mode --- osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index 210f96ce46..ca7fef8f73 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -41,6 +41,12 @@ namespace osu.Game.Screens.Play.HUD break; } }, true); + + // if the accuracy counter is using the "minimum achievable" mode, + // then its initial value is 0%, rather than the 100% that the base PercentageCounter assumes. + // to counteract this, manually finish transforms on DisplayedCount once after the initial callback above + // to stop it from rolling down from 100% to 0%. + FinishTransforms(targetMember: nameof(DisplayedCount)); } public enum AccuracyDisplayMode From 87250ad84707e5b7b1a5041af9fc102b9da81f43 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 1 Jan 2023 14:32:28 +0800 Subject: [PATCH 076/121] Add search keywords for beatmap colours / hitsound overrides --- osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs index e8db5fe58a..da5fc519e6 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs @@ -32,11 +32,13 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay }, new SettingsCheckbox { + Keywords = new[] { "combo", "override" }, LabelText = SkinSettingsStrings.BeatmapColours, Current = config.GetBindable(OsuSetting.BeatmapColours) }, new SettingsCheckbox { + Keywords = new[] { "samples", "override" }, LabelText = SkinSettingsStrings.BeatmapHitsounds, Current = config.GetBindable(OsuSetting.BeatmapHitsounds) }, From 9a4f0cad2c5306b6c3076b7ab5262002386f9992 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 1 Jan 2023 17:48:04 +0800 Subject: [PATCH 077/121] Fix incorrect domain root being used for recent activity entries on profile overlay Closes https://github.com/ppy/osu/issues/21980. --- .../Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 4a8b020e33..c3fa467e5f 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -224,7 +224,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent private void addBeatmapsetLink() => content.AddLink(activity.Beatmapset?.Title, LinkAction.OpenBeatmapSet, getLinkArgument(activity.Beatmapset?.Url), creationParameters: t => t.Font = getLinkFont()); - private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.APIEndpointUrl}{url}").Argument.ToString(); + private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.WebsiteRootUrl}{url}").Argument.ToString(); private FontUsage getLinkFont(FontWeight fontWeight = FontWeight.Regular) => OsuFont.GetFont(size: font_size, weight: fontWeight, italics: true); From a82f1a6abd19bc8f79f1b3e72a45806d4c2c23ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Jan 2023 18:48:56 +0100 Subject: [PATCH 078/121] Adjust method naming and copy --- osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 4 ++-- osu.Game/Tests/Visual/EditorTestScene.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs index ad49f3ac0a..d5aa71095b 100644 --- a/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs +++ b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Editing { AddStep("seek to 1000", () => EditorClock.Seek(1000)); AddAssert("time is 1000", () => EditorClock.CurrentTime == 1000); - AddStep("set current time as preview point", () => Editor.SetCurrentTimeAsPreview()); + AddStep("set current time as preview point", () => Editor.SetPreviewPointToCurrentTime()); AddAssert("preview time is 1000", () => EditorBeatmap.PreviewTime.Value == 1000); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 62bb7d3133..be4e2f9628 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -327,7 +327,7 @@ namespace osu.Game.Screens.Edit { Items = new MenuItem[] { - new EditorMenuItem("Set Current Position as Preview Point", MenuItemType.Standard, SetCurrentTimeAsPreview) + new EditorMenuItem("Set preview point to current time", MenuItemType.Standard, SetPreviewPointToCurrentTime) } } } @@ -808,7 +808,7 @@ namespace osu.Game.Screens.Edit protected void Redo() => changeHandler?.RestoreState(1); - protected void SetCurrentTimeAsPreview() + protected void SetPreviewPointToCurrentTime() { editorBeatmap.PreviewTime.Value = (int)clock.CurrentTime; } diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 9c8ac65add..6e2f1e99cd 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual public new void Redo() => base.Redo(); - public new void SetCurrentTimeAsPreview() => base.SetCurrentTimeAsPreview(); + public new void SetPreviewPointToCurrentTime() => base.SetPreviewPointToCurrentTime(); public new bool Save() => base.Save(); From 656bf12b3d43d15d38873b9993c6531fcfb2eb1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Jan 2023 19:37:19 +0100 Subject: [PATCH 079/121] Add all possible timeline elements to test for demonstrative purposes --- .../Visual/Editing/TestSceneEditorSummaryTimeline.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs index ccd2feef9c..f255dd08a8 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components.Timelines.Summary; @@ -21,7 +22,13 @@ namespace osu.Game.Tests.Visual.Editing public TestSceneEditorSummaryTimeline() { - editorBeatmap = new EditorBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)); + var beatmap = CreateBeatmap(new OsuRuleset().RulesetInfo); + + beatmap.ControlPointInfo.Add(100000, new TimingControlPoint { BeatLength = 100 }); + beatmap.ControlPointInfo.Add(50000, new DifficultyControlPoint { SliderVelocity = 2 }); + beatmap.BeatmapInfo.Bookmarks = new[] { 75000, 125000 }; + + editorBeatmap = new EditorBeatmap(beatmap); } protected override void LoadComplete() From 452ebddfd28b8740e9c268a8ee41fc48de701d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Jan 2023 19:39:21 +0100 Subject: [PATCH 080/121] Adjust visual appearance of preview time part - Use slightly different hue of green to distinguish from difficulty control points. The colour is still not ideal, but picking a distinctive enough hue is pretty hard. - Place the preview time part at the bottom rather at the top. Not sure why it was at the top; not only could it overlap with the control points, but it also looked quite badly misaligned there when bookmarks were displayed at the bottom. --- .../Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs | 2 +- .../Edit/Components/Timelines/Summary/SummaryTimeline.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs index bd34662969..9d3bbe8bff 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts } [BackgroundDependencyLoader] - private void load(OsuColour colours) => Colour = colours.Lime; + private void load(OsuColour colours) => Colour = colours.Green1; } } } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs index 41377bcb18..075d47d82e 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs @@ -44,9 +44,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary new PreviewTimePart { Anchor = Anchor.Centre, - Origin = Anchor.BottomCentre, + Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.Both, - Y = -10, Height = 0.35f }, new Container From efdd557f3b7b9a503b189d1aa864d6bd4f15421f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Jan 2023 19:45:23 +0100 Subject: [PATCH 081/121] Adjust binding logic --- .../Timelines/Summary/Parts/PreviewTimePart.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs index 9d3bbe8bff..de7f611424 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts protected override void LoadBeatmap(EditorBeatmap beatmap) { base.LoadBeatmap(beatmap); - Add(new PreviewTimeVisualisation(beatmap.PreviewTime)); + Add(new PreviewTimeVisualisation(beatmap)); beatmap.PreviewTime.BindValueChanged(s => { Alpha = s.NewValue == -1 ? 0 : 1; @@ -24,11 +24,10 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { private readonly BindableInt previewTime = new BindableInt(); - public PreviewTimeVisualisation(BindableInt time) - : base(time.Value) + public PreviewTimeVisualisation(EditorBeatmap editorBeatmap) { - previewTime.BindTo(time); - previewTime.BindValueChanged(s => X = s.NewValue); + previewTime.BindTo(editorBeatmap.PreviewTime); + previewTime.BindValueChanged(s => X = s.NewValue, true); } [BackgroundDependencyLoader] From b689ad6d80e177734a470fc0d30e6497dc9af09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Jan 2023 19:54:26 +0100 Subject: [PATCH 082/121] Fix changing preview point not prompting for save --- osu.Game/Screens/Edit/EditorBeatmap.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index dfd7328d11..1684dcf0cd 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -111,7 +111,12 @@ namespace osu.Game.Screens.Edit trackStartTime(obj); PreviewTime = new BindableInt(playableBeatmap.Metadata.PreviewTime); - PreviewTime.BindValueChanged(s => this.beatmapInfo.Metadata.PreviewTime = s.NewValue); + PreviewTime.BindValueChanged(s => + { + BeginChange(); + this.beatmapInfo.Metadata.PreviewTime = s.NewValue; + EndChange(); + }); } /// From 88e90d5fa098f7f19fa2986d44aa9a02336ab0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 13:17:59 +0100 Subject: [PATCH 083/121] Enable NRT in user profile overlay --- .../Profile/Header/BottomHeaderContainer.cs | 14 ++++---- .../Profile/Header/CentreHeaderContainer.cs | 10 +++--- .../Header/Components/ExpandDetailsButton.cs | 8 ++--- .../Header/Components/FollowersButton.cs | 4 +-- .../Profile/Header/Components/LevelBadge.cs | 13 ++++--- .../Header/Components/LevelProgressBar.cs | 10 +++--- .../Components/MappingSubscribersButton.cs | 4 +-- .../Header/Components/MessageUserButton.cs | 24 ++++++------- .../Components/OverlinedInfoContainer.cs | 2 -- .../Components/OverlinedTotalPlayTime.cs | 8 ++--- .../Header/Components/PreviousUsernames.cs | 10 +++--- .../Header/Components/ProfileHeaderButton.cs | 2 -- .../ProfileHeaderStatisticsButton.cs | 2 -- .../Components/ProfileRulesetSelector.cs | 7 ++-- .../Components/ProfileRulesetTabItem.cs | 2 -- .../Profile/Header/Components/RankGraph.cs | 8 ++--- .../Header/Components/SupporterIcon.cs | 8 ++--- .../Profile/Header/DetailHeaderContainer.cs | 18 +++++----- .../Profile/Header/MedalHeaderContainer.cs | 12 +++---- .../Profile/Header/TopHeaderContainer.cs | 24 ++++++------- osu.Game/Overlays/Profile/ProfileHeader.cs | 8 ++--- osu.Game/Overlays/Profile/ProfileSection.cs | 4 +-- .../Overlays/Profile/Sections/AboutSection.cs | 2 -- .../Sections/BeatmapMetadataContainer.cs | 6 ++-- .../Beatmaps/PaginatedBeatmapContainer.cs | 10 +++--- .../Profile/Sections/BeatmapsSection.cs | 2 -- .../Overlays/Profile/Sections/CounterPill.cs | 4 +-- .../Historical/ChartProfileSubsection.cs | 10 +++--- .../Historical/DrawableMostPlayedBeatmap.cs | 2 -- .../PaginatedMostPlayedBeatmapContainer.cs | 8 ++--- .../Historical/PlayHistorySubsection.cs | 6 ++-- .../Sections/Historical/ProfileLineChart.cs | 6 +--- .../Sections/Historical/ReplaysSubsection.cs | 6 ++-- .../Sections/Historical/UserHistoryGraph.cs | 6 +--- .../Profile/Sections/HistoricalSection.cs | 2 -- .../Kudosu/DrawableKudosuHistoryItem.cs | 4 +-- .../Profile/Sections/Kudosu/KudosuInfo.cs | 6 ++-- .../Kudosu/PaginatedKudosuHistoryContainer.cs | 8 ++--- .../Profile/Sections/KudosuSection.cs | 2 -- .../Profile/Sections/MedalsSection.cs | 2 -- .../Sections/PaginatedProfileSubsection.cs | 35 ++++++++++--------- .../Profile/Sections/ProfileItemContainer.cs | 2 -- .../Profile/Sections/ProfileSubsection.cs | 10 ++---- .../Sections/ProfileSubsectionHeader.cs | 4 +-- .../Sections/Ranks/DrawableProfileScore.cs | 13 +++---- .../Ranks/DrawableProfileWeightedScore.cs | 2 -- .../Sections/Ranks/PaginatedScoreContainer.cs | 8 ++--- .../Overlays/Profile/Sections/RanksSection.cs | 2 -- .../Sections/Recent/DrawableRecentActivity.cs | 17 +++++---- .../Profile/Sections/Recent/MedalIcon.cs | 2 -- .../PaginatedRecentActivityContainer.cs | 8 ++--- .../Profile/Sections/RecentSection.cs | 2 -- osu.Game/Overlays/Profile/UserGraph.cs | 25 +++++++------ osu.Game/Overlays/UserProfileOverlay.cs | 15 ++++---- osu.Game/Users/UserCoverBackground.cs | 12 +++---- 55 files changed, 172 insertions(+), 279 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs index 5ba3963a45..f5c7a3f87a 100644 --- a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.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; using Humanizer; using osu.Framework.Allocation; @@ -25,15 +23,15 @@ namespace osu.Game.Overlays.Profile.Header { public partial class BottomHeaderContainer : CompositeDrawable { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); - private LinkFlowContainer topLinkContainer; - private LinkFlowContainer bottomLinkContainer; + private LinkFlowContainer topLinkContainer = null!; + private LinkFlowContainer bottomLinkContainer = null!; private Color4 iconColour; [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; public BottomHeaderContainer() { @@ -78,7 +76,7 @@ namespace osu.Game.Overlays.Profile.Header User.BindValueChanged(user => updateDisplay(user.NewValue)); } - private void updateDisplay(APIUser user) + private void updateDisplay(APIUser? user) { topLinkContainer.Clear(); bottomLinkContainer.Clear(); @@ -164,7 +162,7 @@ namespace osu.Game.Overlays.Profile.Header private void addSpacer(OsuTextFlowContainer textFlow) => textFlow.AddArbitraryDrawable(new Container { Width = 15 }); - private bool tryAddInfo(IconUsage icon, string content, string link = null) + private bool tryAddInfo(IconUsage icon, string content, string? link = null) { if (string.IsNullOrEmpty(content)) return false; diff --git a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs index 5f6af7a6e2..5e4e1184a4 100644 --- a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; @@ -20,10 +18,10 @@ namespace osu.Game.Overlays.Profile.Header public partial class CentreHeaderContainer : CompositeDrawable { public readonly BindableBool DetailsVisible = new BindableBool(true); - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); - private OverlinedInfoContainer hiddenDetailGlobal; - private OverlinedInfoContainer hiddenDetailCountry; + private OverlinedInfoContainer hiddenDetailGlobal = null!; + private OverlinedInfoContainer hiddenDetailCountry = null!; public CentreHeaderContainer() { @@ -146,7 +144,7 @@ namespace osu.Game.Overlays.Profile.Header User.BindValueChanged(user => updateDisplay(user.NewValue)); } - private void updateDisplay(APIUser user) + private void updateDisplay(APIUser? user) { hiddenDetailGlobal.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; hiddenDetailCountry.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; diff --git a/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs b/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs index a778ddd2b1..e7a83c95d8 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.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 osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -23,9 +21,9 @@ namespace osu.Game.Overlays.Profile.Header.Components public override LocalisableString TooltipText => DetailsVisible.Value ? CommonStrings.ButtonsCollapse : CommonStrings.ButtonsExpand; - private SpriteIcon icon; - private Sample sampleOpen; - private Sample sampleClose; + private SpriteIcon icon = null!; + private Sample? sampleOpen; + private Sample? sampleClose; protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(); diff --git a/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs b/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs index c278a6c48b..c0bcec622a 100644 --- a/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/FollowersButton.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; @@ -14,7 +12,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class FollowersButton : ProfileHeaderStatisticsButton { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public override LocalisableString TooltipText => FriendsStrings.ButtonsDisabled; diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index ef2f35e9a8..8f84e69bac 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -20,11 +18,11 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class LevelBadge : CompositeDrawable, IHasTooltip { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public LocalisableString TooltipText { get; private set; } - private OsuSpriteText levelText; + private OsuSpriteText levelText = null!; public LevelBadge() { @@ -53,10 +51,11 @@ namespace osu.Game.Overlays.Profile.Header.Components User.BindValueChanged(user => updateLevel(user.NewValue)); } - private void updateLevel(APIUser user) + private void updateLevel(APIUser? user) { - levelText.Text = user?.Statistics?.Level.Current.ToString() ?? "0"; - TooltipText = UsersStrings.ShowStatsLevel(user?.Statistics?.Level.Current.ToString()); + string level = user?.Statistics?.Level.Current.ToString() ?? "0"; + levelText.Text = level; + TooltipText = UsersStrings.ShowStatsLevel(level); } } } diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs b/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs index 0351230fb3..ea5ca0c8bd 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; @@ -21,12 +19,12 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class LevelProgressBar : CompositeDrawable, IHasTooltip { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public LocalisableString TooltipText { get; } - private Bar levelProgressBar; - private OsuSpriteText levelProgressText; + private Bar levelProgressBar = null!; + private OsuSpriteText levelProgressText = null!; public LevelProgressBar() { @@ -61,7 +59,7 @@ namespace osu.Game.Overlays.Profile.Header.Components User.BindValueChanged(user => updateProgress(user.NewValue)); } - private void updateProgress(APIUser user) + private void updateProgress(APIUser? user) { levelProgressBar.Length = user?.Statistics?.Level.Progress / 100f ?? 0; levelProgressText.Text = user?.Statistics?.Level.Progress.ToLocalisableString("0'%'") ?? default; diff --git a/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs b/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs index 887cf10cce..c600f7622a 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; @@ -14,7 +12,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class MappingSubscribersButton : ProfileHeaderStatisticsButton { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public override LocalisableString TooltipText => FollowsStrings.MappingFollowers; diff --git a/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs b/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs index 4886324a22..3266e3c308 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -18,21 +16,21 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class MessageUserButton : ProfileHeaderButton { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public override LocalisableString TooltipText => UsersStrings.CardSendMessage; - [Resolved(CanBeNull = true)] - private ChannelManager channelManager { get; set; } - - [Resolved(CanBeNull = true)] - private UserProfileOverlay userOverlay { get; set; } - - [Resolved(CanBeNull = true)] - private ChatOverlay chatOverlay { get; set; } + [Resolved] + private ChannelManager? channelManager { get; set; } [Resolved] - private IAPIProvider apiProvider { get; set; } + private UserProfileOverlay? userOverlay { get; set; } + + [Resolved] + private ChatOverlay? chatOverlay { get; set; } + + [Resolved] + private IAPIProvider apiProvider { get; set; } = null!; public MessageUserButton() { @@ -56,7 +54,7 @@ namespace osu.Game.Overlays.Profile.Header.Components chatOverlay?.Show(); }; - User.ValueChanged += e => Content.Alpha = !e.NewValue.PMFriendsOnly && apiProvider.LocalUser.Value.Id != e.NewValue.Id ? 1 : 0; + User.ValueChanged += e => Content.Alpha = e.NewValue != null && !e.NewValue.PMFriendsOnly && apiProvider.LocalUser.Value.Id != e.NewValue.Id ? 1 : 0; } } } diff --git a/osu.Game/Overlays/Profile/Header/Components/OverlinedInfoContainer.cs b/osu.Game/Overlays/Profile/Header/Components/OverlinedInfoContainer.cs index 244f185e28..42b67865a0 100644 --- a/osu.Game/Overlays/Profile/Header/Components/OverlinedInfoContainer.cs +++ b/osu.Game/Overlays/Profile/Header/Components/OverlinedInfoContainer.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 osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; diff --git a/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs b/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs index c040f5a787..e9e277acd3 100644 --- a/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs +++ b/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -16,11 +14,11 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class OverlinedTotalPlayTime : CompositeDrawable, IHasTooltip { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public LocalisableString TooltipText { get; set; } - private OverlinedInfoContainer info; + private OverlinedInfoContainer info = null!; public OverlinedTotalPlayTime() { @@ -41,7 +39,7 @@ namespace osu.Game.Overlays.Profile.Header.Components User.BindValueChanged(updateTime, true); } - private void updateTime(ValueChangedEvent user) + private void updateTime(ValueChangedEvent user) { TooltipText = (user.NewValue?.Statistics?.PlayTime ?? 0) / 3600 + " hours"; info.Content = formatTime(user.NewValue?.Statistics?.PlayTime); diff --git a/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs b/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs index 0abc4de5ef..b722fe92e0 100644 --- a/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs +++ b/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.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; using System.Linq; using osu.Framework.Allocation; @@ -27,7 +25,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private const int width = 310; private const int move_offset = 15; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); private readonly TextFlowContainer text; private readonly Box background; @@ -109,11 +107,11 @@ namespace osu.Game.Overlays.Profile.Header.Components User.BindValueChanged(onUserChanged, true); } - private void onUserChanged(ValueChangedEvent user) + private void onUserChanged(ValueChangedEvent user) { text.Text = string.Empty; - string[] usernames = user.NewValue?.PreviousUsernames; + string[]? usernames = user.NewValue?.PreviousUsernames; if (usernames?.Any() ?? false) { @@ -149,7 +147,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private partial class HoverIconContainer : Container { - public Action ActivateHover; + public Action? ActivateHover; public HoverIconContainer() { diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderButton.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderButton.cs index c4a46440d2..414ca4d077 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderButton.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.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs index 5ad726a3ea..32c5ebee2c 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.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 osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs index 72446bde3a..684ce9088e 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs @@ -1,9 +1,8 @@ // 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.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; @@ -12,12 +11,12 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class ProfileRulesetSelector : OverlayRulesetSelector { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); protected override void LoadComplete() { base.LoadComplete(); - User.BindValueChanged(u => SetDefaultRuleset(Rulesets.GetRuleset(u.NewValue?.PlayMode ?? "osu")), true); + User.BindValueChanged(u => SetDefaultRuleset(Rulesets.GetRuleset(u.NewValue?.PlayMode ?? "osu").AsNonNull()), true); } public void SetDefaultRuleset(RulesetInfo ruleset) diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetTabItem.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetTabItem.cs index 72adc96f9a..9caa7dd1bc 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetTabItem.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetTabItem.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 osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index 51531977d2..fe1069eea1 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.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; using System.Collections.Generic; using System.Linq; @@ -21,7 +19,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { private const int ranked_days = 88; - public readonly Bindable Statistics = new Bindable(); + public readonly Bindable Statistics = new Bindable(); private readonly OsuSpriteText placeholder; @@ -42,11 +40,11 @@ namespace osu.Game.Overlays.Profile.Header.Components Statistics.BindValueChanged(statistics => updateStatistics(statistics.NewValue), true); } - private void updateStatistics(UserStatistics statistics) + private void updateStatistics(UserStatistics? statistics) { // checking both IsRanked and RankHistory is required. // see https://github.com/ppy/osu-web/blob/154ceafba0f35a1dd935df53ec98ae2ea5615f9f/resources/assets/lib/profile-page/rank-chart.tsx#L46 - int[] userRanks = statistics?.IsRanked == true ? statistics.RankHistory?.Data : null; + int[]? userRanks = statistics?.IsRanked == true ? statistics.RankHistory?.Data : null; Data = userRanks?.Select((x, index) => new KeyValuePair(index, x)).Where(x => x.Value != 0).ToArray(); } diff --git a/osu.Game/Overlays/Profile/Header/Components/SupporterIcon.cs b/osu.Game/Overlays/Profile/Header/Components/SupporterIcon.cs index 4028eb1389..92e2017659 100644 --- a/osu.Game/Overlays/Profile/Header/Components/SupporterIcon.cs +++ b/osu.Game/Overlays/Profile/Header/Components/SupporterIcon.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; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -82,10 +80,10 @@ namespace osu.Game.Overlays.Profile.Header.Components } [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; - [BackgroundDependencyLoader(true)] - private void load(OsuGame game) + [BackgroundDependencyLoader] + private void load(OsuGame? game) { background.Colour = colours.Pink; diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 44986dc178..95fead1246 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.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.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -25,14 +23,14 @@ namespace osu.Game.Overlays.Profile.Header public partial class DetailHeaderContainer : CompositeDrawable { private readonly Dictionary scoreRankInfos = new Dictionary(); - private OverlinedInfoContainer medalInfo; - private OverlinedInfoContainer ppInfo; - private OverlinedInfoContainer detailGlobalRank; - private OverlinedInfoContainer detailCountryRank; - private FillFlowContainer fillFlow; - private RankGraph rankGraph; + private OverlinedInfoContainer medalInfo = null!; + private OverlinedInfoContainer ppInfo = null!; + private OverlinedInfoContainer detailGlobalRank = null!; + private OverlinedInfoContainer detailCountryRank = null!; + private FillFlowContainer? fillFlow; + private RankGraph rankGraph = null!; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); private bool expanded = true; @@ -173,7 +171,7 @@ namespace osu.Game.Overlays.Profile.Header }; } - private void updateDisplay(APIUser user) + private void updateDisplay(APIUser? user) { medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0"; ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0"; diff --git a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs index ab800d006d..79f9eba57d 100644 --- a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.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.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -20,9 +18,9 @@ namespace osu.Game.Overlays.Profile.Header { public partial class MedalHeaderContainer : CompositeDrawable { - private FillFlowContainer badgeFlowContainer; + private FillFlowContainer badgeFlowContainer = null!; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -66,16 +64,16 @@ namespace osu.Game.Overlays.Profile.Header }; } - private CancellationTokenSource cancellationTokenSource; + private CancellationTokenSource? cancellationTokenSource; - private void updateDisplay(APIUser user) + private void updateDisplay(APIUser? user) { cancellationTokenSource?.Cancel(); cancellationTokenSource = new CancellationTokenSource(); badgeFlowContainer.Clear(); - var badges = user.Badges; + var badges = user?.Badges; if (badges?.Length > 0) { diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 8826dd982d..a6501f567f 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -29,19 +27,19 @@ namespace osu.Game.Overlays.Profile.Header { private const float avatar_size = 110; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; - private SupporterIcon supporterTag; - private UpdateableAvatar avatar; - private OsuSpriteText usernameText; - private ExternalLinkButton openUserExternally; - private OsuSpriteText titleText; - private UpdateableFlag userFlag; - private OsuSpriteText userCountryText; - private FillFlowContainer userStats; + private SupporterIcon supporterTag = null!; + private UpdateableAvatar avatar = null!; + private OsuSpriteText usernameText = null!; + private ExternalLinkButton openUserExternally = null!; + private OsuSpriteText titleText = null!; + private UpdateableFlag userFlag = null!; + private OsuSpriteText userCountryText = null!; + private FillFlowContainer userStats = null!; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -176,7 +174,7 @@ namespace osu.Game.Overlays.Profile.Header User.BindValueChanged(user => updateUser(user.NewValue)); } - private void updateUser(APIUser user) + private void updateUser(APIUser? user) { avatar.User = user; usernameText.Text = user?.Username ?? string.Empty; diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 8443678989..2b8d2503e0 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.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.Diagnostics; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -20,9 +18,9 @@ namespace osu.Game.Overlays.Profile { public partial class ProfileHeader : TabControlOverlayHeader { - private UserCoverBackground coverContainer; + private UserCoverBackground coverContainer = null!; - public Bindable User = new Bindable(); + public Bindable User = new Bindable(); private CentreHeaderContainer centreHeaderContainer; private DetailHeaderContainer detailHeaderContainer; @@ -102,7 +100,7 @@ namespace osu.Game.Overlays.Profile protected override OverlayTitle CreateTitle() => new ProfileHeaderTitle(); - private void updateDisplay(APIUser user) => coverContainer.User = user; + private void updateDisplay(APIUser? user) => coverContainer.User = user; private partial class ProfileHeaderTitle : OverlayTitle { diff --git a/osu.Game/Overlays/Profile/ProfileSection.cs b/osu.Game/Overlays/Profile/ProfileSection.cs index fc99050f73..62b40545df 100644 --- a/osu.Game/Overlays/Profile/ProfileSection.cs +++ b/osu.Game/Overlays/Profile/ProfileSection.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -31,7 +29,7 @@ namespace osu.Game.Overlays.Profile protected override Container Content => content; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); protected ProfileSection() { diff --git a/osu.Game/Overlays/Profile/Sections/AboutSection.cs b/osu.Game/Overlays/Profile/Sections/AboutSection.cs index ac3dca5107..69a8b23412 100644 --- a/osu.Game/Overlays/Profile/Sections/AboutSection.cs +++ b/osu.Game/Overlays/Profile/Sections/AboutSection.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 osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs index 5a80a4d444..499c572eac 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -25,8 +23,8 @@ namespace osu.Game.Overlays.Profile.Sections AutoSizeAxes = Axes.Both; } - [BackgroundDependencyLoader(true)] - private void load(BeatmapSetOverlay beatmapSetOverlay) + [BackgroundDependencyLoader] + private void load(BeatmapSetOverlay? beatmapSetOverlay) { Action = () => { diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 56d9fb9ec6..e327d71d25 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.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.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -24,7 +22,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps protected override int InitialItemsCount => type == BeatmapSetType.Graveyard ? 2 : 6; - public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, LocalisableString headerText) + public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, LocalisableString headerText) : base(user, headerText) { this.type = type; @@ -66,10 +64,10 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps } } - protected override APIRequest> CreateRequest(PaginationParameters pagination) => - new GetUserBeatmapsRequest(User.Value.Id, type, pagination); + protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) => + new GetUserBeatmapsRequest(user.Id, type, pagination); - protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0 + protected override Drawable? CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0 ? new BeatmapCardNormal(model) { Anchor = Anchor.TopCentre, diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs index cf80ebd66f..3b304a79ef 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.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 osu.Framework.Localisation; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Profile.Sections.Beatmaps; diff --git a/osu.Game/Overlays/Profile/Sections/CounterPill.cs b/osu.Game/Overlays/Profile/Sections/CounterPill.cs index c93cdb84f2..74cd4b218b 100644 --- a/osu.Game/Overlays/Profile/Sections/CounterPill.cs +++ b/osu.Game/Overlays/Profile/Sections/CounterPill.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 osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; @@ -18,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections { public readonly BindableInt Current = new BindableInt(); - private OsuSpriteText counter; + private OsuSpriteText counter = null!; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs index e0837320b2..c532c693ec 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.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.Collections.Generic; using System.Linq; using osu.Framework.Bindables; @@ -15,14 +13,14 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { public abstract partial class ChartProfileSubsection : ProfileSubsection { - private ProfileLineChart chart; + private ProfileLineChart chart = null!; /// /// Text describing the value being plotted on the graph, which will be displayed as a prefix to the value in the history graph tooltip. /// protected abstract LocalisableString GraphCounterName { get; } - protected ChartProfileSubsection(Bindable user, LocalisableString headerText) + protected ChartProfileSubsection(Bindable user, LocalisableString headerText) : base(user, headerText) { } @@ -46,7 +44,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical User.BindValueChanged(onUserChanged, true); } - private void onUserChanged(ValueChangedEvent e) + private void onUserChanged(ValueChangedEvent e) { var values = GetValues(e.NewValue); @@ -86,6 +84,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical return filledHistoryEntries.ToArray(); } - protected abstract APIUserHistoryCount[] GetValues(APIUser user); + protected abstract APIUserHistoryCount[]? GetValues(APIUser? user); } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs index a31ee88f3b..53447a971b 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 222969bdfd..515c1fd146 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.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.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -18,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { public partial class PaginatedMostPlayedBeatmapContainer : PaginatedProfileSubsection { - public PaginatedMostPlayedBeatmapContainer(Bindable user) + public PaginatedMostPlayedBeatmapContainer(Bindable user) : base(user, UsersStrings.ShowExtraHistoricalMostPlayedTitle) { } @@ -31,8 +29,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override int GetCount(APIUser user) => user.BeatmapPlayCountsCount; - protected override APIRequest> CreateRequest(PaginationParameters pagination) => - new GetUserMostPlayedBeatmapsRequest(User.Value.Id, pagination); + protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) => + new GetUserMostPlayedBeatmapsRequest(user.Id, pagination); protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap mostPlayed) => new DrawableMostPlayedBeatmap(mostPlayed); diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs index 186bf73898..c8a6b1da31 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.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 osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Online.API.Requests.Responses; @@ -14,11 +12,11 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { protected override LocalisableString GraphCounterName => UsersStrings.ShowExtraHistoricalMonthlyPlaycountsCountLabel; - public PlayHistorySubsection(Bindable user) + public PlayHistorySubsection(Bindable user) : base(user, UsersStrings.ShowExtraHistoricalMonthlyPlaycountsTitle) { } - protected override APIUserHistoryCount[] GetValues(APIUser user) => user?.MonthlyPlayCounts; + protected override APIUserHistoryCount[]? GetValues(APIUser? user) => user?.MonthlyPlayCounts; } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index da86d870fc..5711bfc046 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -1,11 +1,8 @@ // 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.Graphics.Containers; using osu.Framework.Graphics; -using JetBrains.Annotations; using System; using System.Linq; using osu.Game.Graphics.Sprites; @@ -22,9 +19,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { public partial class ProfileLineChart : CompositeDrawable { - private APIUserHistoryCount[] values; + private APIUserHistoryCount[] values = Array.Empty(); - [NotNull] public APIUserHistoryCount[] Values { get => values; diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs index d1d1e76e14..ac7c616a64 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.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 osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Online.API.Requests.Responses; @@ -14,11 +12,11 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { protected override LocalisableString GraphCounterName => UsersStrings.ShowExtraHistoricalReplaysWatchedCountsCountLabel; - public ReplaysSubsection(Bindable user) + public ReplaysSubsection(Bindable user) : base(user, UsersStrings.ShowExtraHistoricalReplaysWatchedCountsTitle) { } - protected override APIUserHistoryCount[] GetValues(APIUser user) => user?.ReplaysWatchedCounts; + protected override APIUserHistoryCount[]? GetValues(APIUser? user) => user?.ReplaysWatchedCounts; } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs index 3f68ffdd0e..310607e757 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs @@ -1,12 +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.Collections.Generic; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; using osu.Game.Online.API.Requests.Responses; @@ -17,8 +14,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { private readonly LocalisableString tooltipCounterName; - [CanBeNull] - public APIUserHistoryCount[] Values + public APIUserHistoryCount[]? Values { set => Data = value?.Select(v => new KeyValuePair(v.Date, v.Count)).ToArray(); } diff --git a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs index 13e0aefc65..19f7a32d4d 100644 --- a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs +++ b/osu.Game/Overlays/Profile/Sections/HistoricalSection.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 osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Online.API.Requests; diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 122b20cbfc..e7991acb89 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -20,7 +18,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu private const int height = 25; [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; private readonly APIKudosuHistory historyItem; private readonly LinkFlowContainer linkFlowContainer; diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 2b4d58b845..acf4827dfd 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.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 osu.Framework.Bindables; using osuTK; using osu.Framework.Graphics; @@ -22,9 +20,9 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { public partial class KudosuInfo : Container { - private readonly Bindable user = new Bindable(); + private readonly Bindable user = new Bindable(); - public KudosuInfo(Bindable user) + public KudosuInfo(Bindable user) { this.user.BindTo(user); CountSection total; diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs index c082c634a7..c5de810f22 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.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 osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Framework.Bindables; @@ -16,13 +14,13 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { public partial class PaginatedKudosuHistoryContainer : PaginatedProfileSubsection { - public PaginatedKudosuHistoryContainer(Bindable user) + public PaginatedKudosuHistoryContainer(Bindable user) : base(user, missingText: UsersStrings.ShowExtraKudosuEntryEmpty) { } - protected override APIRequest> CreateRequest(PaginationParameters pagination) - => new GetUserKudosuHistoryRequest(User.Value.Id, pagination); + protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) + => new GetUserKudosuHistoryRequest(user.Id, pagination); protected override Drawable CreateDrawableItem(APIKudosuHistory item) => new DrawableKudosuHistoryItem(item); } diff --git a/osu.Game/Overlays/Profile/Sections/KudosuSection.cs b/osu.Game/Overlays/Profile/Sections/KudosuSection.cs index 26cf78c537..482a853c44 100644 --- a/osu.Game/Overlays/Profile/Sections/KudosuSection.cs +++ b/osu.Game/Overlays/Profile/Sections/KudosuSection.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 osu.Framework.Graphics; using osu.Game.Overlays.Profile.Sections.Kudosu; using osu.Framework.Localisation; diff --git a/osu.Game/Overlays/Profile/Sections/MedalsSection.cs b/osu.Game/Overlays/Profile/Sections/MedalsSection.cs index a511dc95a0..42f241d662 100644 --- a/osu.Game/Overlays/Profile/Sections/MedalsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/MedalsSection.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 osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs index 530391466a..f32221747c 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.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.Collections.Generic; using System.Linq; using System.Threading; @@ -35,20 +33,20 @@ namespace osu.Game.Overlays.Profile.Sections protected virtual int InitialItemsCount => 5; [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; protected PaginationParameters? CurrentPage { get; private set; } - protected ReverseChildIDFillFlowContainer ItemsContainer { get; private set; } + protected ReverseChildIDFillFlowContainer ItemsContainer { get; private set; } = null!; - private APIRequest> retrievalRequest; - private CancellationTokenSource loadCancellation; + private APIRequest>? retrievalRequest; + private CancellationTokenSource? loadCancellation; - private ShowMoreButton moreButton; - private OsuSpriteText missing; + private ShowMoreButton moreButton = null!; + private OsuSpriteText missing = null!; private readonly LocalisableString? missingText; - protected PaginatedProfileSubsection(Bindable user, LocalisableString? headerText = null, LocalisableString? missingText = null) + protected PaginatedProfileSubsection(Bindable user, LocalisableString? headerText = null, LocalisableString? missingText = null) : base(user, headerText, CounterVisibilityState.AlwaysVisible) { this.missingText = missingText; @@ -94,7 +92,7 @@ namespace osu.Game.Overlays.Profile.Sections User.BindValueChanged(onUserChanged, true); } - private void onUserChanged(ValueChangedEvent e) + private void onUserChanged(ValueChangedEvent e) { loadCancellation?.Cancel(); retrievalRequest?.Cancel(); @@ -111,17 +109,20 @@ namespace osu.Game.Overlays.Profile.Sections private void showMore() { + if (User.Value == null) + return; + loadCancellation = new CancellationTokenSource(); CurrentPage = CurrentPage?.TakeNext(ItemsPerPage) ?? new PaginationParameters(InitialItemsCount); - retrievalRequest = CreateRequest(CurrentPage.Value); - retrievalRequest.Success += UpdateItems; + retrievalRequest = CreateRequest(User.Value, CurrentPage.Value); + retrievalRequest.Success += items => UpdateItems(items, loadCancellation); api.Queue(retrievalRequest); } - protected virtual void UpdateItems(List items) => Schedule(() => + protected virtual void UpdateItems(List items, CancellationTokenSource cancellationTokenSource) => Schedule(() => { OnItemsReceived(items); @@ -136,7 +137,7 @@ namespace osu.Game.Overlays.Profile.Sections return; } - LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables => + LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null).Cast(), drawables => { missing.Hide(); @@ -144,7 +145,7 @@ namespace osu.Game.Overlays.Profile.Sections moreButton.IsLoading = false; ItemsContainer.AddRange(drawables); - }, loadCancellation.Token); + }, cancellationTokenSource.Token); }); protected virtual int GetCount(APIUser user) => 0; @@ -153,9 +154,9 @@ namespace osu.Game.Overlays.Profile.Sections { } - protected abstract APIRequest> CreateRequest(PaginationParameters pagination); + protected abstract APIRequest> CreateRequest(APIUser user, PaginationParameters pagination); - protected abstract Drawable CreateDrawableItem(TModel model); + protected abstract Drawable? CreateDrawableItem(TModel model); protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Overlays/Profile/Sections/ProfileItemContainer.cs b/osu.Game/Overlays/Profile/Sections/ProfileItemContainer.cs index c81a08fa20..b30faee380 100644 --- a/osu.Game/Overlays/Profile/Sections/ProfileItemContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/ProfileItemContainer.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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs index 9d88645c9a..0a0e1a9298 100644 --- a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs @@ -1,13 +1,10 @@ // 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.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using JetBrains.Annotations; using osu.Framework.Localisation; using osu.Game.Online.API.Requests.Responses; @@ -15,14 +12,14 @@ namespace osu.Game.Overlays.Profile.Sections { public abstract partial class ProfileSubsection : FillFlowContainer { - protected readonly Bindable User = new Bindable(); + protected readonly Bindable User = new Bindable(); private readonly LocalisableString headerText; private readonly CounterVisibilityState counterVisibilityState; - private ProfileSubsectionHeader header; + private ProfileSubsectionHeader header = null!; - protected ProfileSubsection(Bindable user, LocalisableString? headerText = null, CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden) + protected ProfileSubsection(Bindable user, LocalisableString? headerText = null, CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden) { this.headerText = headerText ?? string.Empty; this.counterVisibilityState = counterVisibilityState; @@ -46,7 +43,6 @@ namespace osu.Game.Overlays.Profile.Sections }; } - [NotNull] protected abstract Drawable CreateContent(); protected void SetCount(int value) => header.Current.Value = value; diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs index 598ac19059..fa21535d02 100644 --- a/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs +++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.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 osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; @@ -30,7 +28,7 @@ namespace osu.Game.Overlays.Profile.Sections private readonly LocalisableString text; private readonly CounterVisibilityState counterState; - private CounterPill counterPill; + private CounterPill counterPill = null!; public ProfileSubsectionHeader(LocalisableString text, CounterVisibilityState counterState) { diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index 67df4825cc..0f3e0bc6b2 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -1,12 +1,10 @@ // 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.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -34,10 +32,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks protected readonly SoloScoreInfo Score; [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; [Resolved] - private OverlayColourProvider colourProvider { get; set; } + private OverlayColourProvider colourProvider { get; set; } = null!; public DrawableProfileScore(SoloScoreInfo score) { @@ -84,7 +82,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Spacing = new Vector2(0, 2), Children = new Drawable[] { - new ScoreBeatmapMetadataContainer(Score.Beatmap), + new ScoreBeatmapMetadataContainer(Score.Beatmap.AsNonNull()), new FillFlowContainer { AutoSizeAxes = Axes.Both, @@ -94,7 +92,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { new OsuSpriteText { - Text = $"{Score.Beatmap?.DifficultyName}", + Text = $"{Score.Beatmap.AsNonNull().DifficultyName}", Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular), Colour = colours.Yellow }, @@ -199,7 +197,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }); } - [NotNull] protected virtual Drawable CreateRightContent() => CreateDrawableAccuracy(); protected Drawable CreateDrawableAccuracy() => new Container diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs index f04d7d9733..6cfe34ec6f 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.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 osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 38fac075fb..3ef0275f50 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.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 osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests; using System; @@ -21,7 +19,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { private readonly ScoreType type; - public PaginatedScoreContainer(ScoreType type, Bindable user, LocalisableString headerText) + public PaginatedScoreContainer(ScoreType type, Bindable user, LocalisableString headerText) : base(user, headerText) { this.type = type; @@ -62,8 +60,8 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks base.OnItemsReceived(items); } - protected override APIRequest> CreateRequest(PaginationParameters pagination) => - new GetUserScoresRequest(User.Value.Id, type, pagination); + protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) => + new GetUserScoresRequest(user.Id, type, pagination); private int drawableItemIndex; diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index ca41bff2f9..ce831b30a8 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.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 osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Online.API.Requests; using osu.Framework.Localisation; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index c3fa467e5f..0479ab7c16 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -1,10 +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.Linq; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -24,14 +23,14 @@ namespace osu.Game.Overlays.Profile.Sections.Recent private const int font_size = 14; [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; [Resolved] - private IRulesetStore rulesets { get; set; } + private IRulesetStore rulesets { get; set; } = null!; private readonly APIRecentActivity activity; - private LinkFlowContainer content; + private LinkFlowContainer content = null!; public DrawableRecentActivity(APIRecentActivity activity) { @@ -216,15 +215,15 @@ namespace osu.Game.Overlays.Profile.Sections.Recent rulesets.AvailableRulesets.FirstOrDefault(r => r.ShortName == activity.Mode)?.Name ?? activity.Mode; private void addUserLink() - => content.AddLink(activity.User?.Username, LinkAction.OpenUserProfile, getLinkArgument(activity.User?.Url), creationParameters: t => t.Font = getLinkFont(FontWeight.Bold)); + => content.AddLink(activity.User.AsNonNull().Username, LinkAction.OpenUserProfile, getLinkArgument(activity.User.AsNonNull().Url), creationParameters: t => t.Font = getLinkFont(FontWeight.Bold)); private void addBeatmapLink() - => content.AddLink(activity.Beatmap?.Title, LinkAction.OpenBeatmap, getLinkArgument(activity.Beatmap?.Url), creationParameters: t => t.Font = getLinkFont()); + => content.AddLink(activity.Beatmap.AsNonNull().Title, LinkAction.OpenBeatmap, getLinkArgument(activity.Beatmap.AsNonNull().Url), creationParameters: t => t.Font = getLinkFont()); private void addBeatmapsetLink() - => content.AddLink(activity.Beatmapset?.Title, LinkAction.OpenBeatmapSet, getLinkArgument(activity.Beatmapset?.Url), creationParameters: t => t.Font = getLinkFont()); + => content.AddLink(activity.Beatmapset.AsNonNull().Title, LinkAction.OpenBeatmapSet, getLinkArgument(activity.Beatmapset.AsNonNull().Url), creationParameters: t => t.Font = getLinkFont()); - private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.WebsiteRootUrl}{url}").Argument.ToString(); + private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.WebsiteRootUrl}{url}").Argument.ToString().AsNonNull(); private FontUsage getLinkFont(FontWeight fontWeight = FontWeight.Regular) => OsuFont.GetFont(size: font_size, weight: fontWeight, italics: true); diff --git a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs index 5eeed24469..6cb439ab33 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.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 osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index b07dfc154f..4e5b11d79f 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.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 osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Framework.Bindables; @@ -18,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent { public partial class PaginatedRecentActivityContainer : PaginatedProfileSubsection { - public PaginatedRecentActivityContainer(Bindable user) + public PaginatedRecentActivityContainer(Bindable user) : base(user, missingText: EventsStrings.Empty) { } @@ -29,8 +27,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent ItemsContainer.Spacing = new Vector2(0, 8); } - protected override APIRequest> CreateRequest(PaginationParameters pagination) => - new GetUserRecentActivitiesRequest(User.Value.Id, pagination); + protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) => + new GetUserRecentActivitiesRequest(user.Id, pagination); protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model); } diff --git a/osu.Game/Overlays/Profile/Sections/RecentSection.cs b/osu.Game/Overlays/Profile/Sections/RecentSection.cs index f2ebf81504..e29dc7f635 100644 --- a/osu.Game/Overlays/Profile/Sections/RecentSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RecentSection.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 osu.Framework.Localisation; using osu.Game.Overlays.Profile.Sections.Recent; using osu.Game.Resources.Localisation.Web; diff --git a/osu.Game/Overlays/Profile/UserGraph.cs b/osu.Game/Overlays/Profile/UserGraph.cs index fa9cbe0449..63cdbea5a4 100644 --- a/osu.Game/Overlays/Profile/UserGraph.cs +++ b/osu.Game/Overlays/Profile/UserGraph.cs @@ -1,12 +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.Collections.Generic; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -26,12 +23,12 @@ namespace osu.Game.Overlays.Profile /// /// Type of data to be used for X-axis of the graph. /// Type of data to be used for Y-axis of the graph. - public abstract partial class UserGraph : Container, IHasCustomTooltip + public abstract partial class UserGraph : Container, IHasCustomTooltip { protected const float FADE_DURATION = 150; private readonly UserLineGraph graph; - private KeyValuePair[] data; + private KeyValuePair[]? data; private int hoveredIndex = -1; protected UserGraph() @@ -83,8 +80,7 @@ namespace osu.Game.Overlays.Profile /// /// Set of values which will be used to create a graph. /// - [CanBeNull] - protected KeyValuePair[] Data + protected KeyValuePair[]? Data { set { @@ -120,9 +116,9 @@ namespace osu.Game.Overlays.Profile protected virtual void ShowGraph() => graph.FadeIn(FADE_DURATION, Easing.Out); protected virtual void HideGraph() => graph.FadeOut(FADE_DURATION, Easing.Out); - public ITooltip GetCustomTooltip() => new UserGraphTooltip(); + public ITooltip GetCustomTooltip() => new UserGraphTooltip(); - public UserGraphTooltipContent TooltipContent + public UserGraphTooltipContent? TooltipContent { get { @@ -143,7 +139,7 @@ namespace osu.Game.Overlays.Profile private readonly Box ballBg; private readonly Box line; - public Action OnBallMove; + public Action? OnBallMove; public UserLineGraph() { @@ -191,7 +187,7 @@ namespace osu.Game.Overlays.Profile Vector2 position = calculateBallPosition(index); movingBall.MoveToY(position.Y, duration, Easing.OutQuint); bar.MoveToX(position.X, duration, Easing.OutQuint); - OnBallMove.Invoke(index); + OnBallMove?.Invoke(index); } public void ShowBar() => bar.FadeIn(FADE_DURATION); @@ -207,7 +203,7 @@ namespace osu.Game.Overlays.Profile } } - private partial class UserGraphTooltip : VisibilityContainer, ITooltip + private partial class UserGraphTooltip : VisibilityContainer, ITooltip { protected readonly OsuSpriteText Label, Counter, BottomText; private readonly Box background; @@ -267,8 +263,11 @@ namespace osu.Game.Overlays.Profile background.Colour = colours.Gray1; } - public void SetContent(UserGraphTooltipContent content) + public void SetContent(UserGraphTooltipContent? content) { + if (content == null) + return; + Label.Text = content.Name; Counter.Text = content.Count; BottomText.Text = content.Time; diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 386f95cf0a..1a7c4173ab 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -1,9 +1,8 @@ // 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 System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -24,11 +23,11 @@ namespace osu.Game.Overlays { public partial class UserProfileOverlay : FullscreenOverlay { - private ProfileSection lastSection; - private ProfileSection[] sections; - private GetUserRequest userReq; - private ProfileSectionsContainer sectionsContainer; - private ProfileSectionTabControl tabs; + private ProfileSection? lastSection; + private ProfileSection[]? sections; + private GetUserRequest? userReq; + private ProfileSectionsContainer? sectionsContainer; + private ProfileSectionTabControl? tabs; public const float CONTENT_X_MARGIN = 70; @@ -133,6 +132,8 @@ namespace osu.Game.Overlays private void userLoadComplete(APIUser user) { + Debug.Assert(sections != null && sectionsContainer != null && tabs != null); + Header.User.Value = user; if (user.ProfileOrder != null) diff --git a/osu.Game/Users/UserCoverBackground.cs b/osu.Game/Users/UserCoverBackground.cs index 69a5fba876..de6a306b2a 100644 --- a/osu.Game/Users/UserCoverBackground.cs +++ b/osu.Game/Users/UserCoverBackground.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; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -17,15 +15,15 @@ using osuTK.Graphics; namespace osu.Game.Users { - public partial class UserCoverBackground : ModelBackedDrawable + public partial class UserCoverBackground : ModelBackedDrawable { - public APIUser User + public APIUser? User { get => Model; set => Model = value; } - protected override Drawable CreateDrawable(APIUser user) => new Cover(user); + protected override Drawable CreateDrawable(APIUser? user) => new Cover(user); protected override double LoadDelay => 300; @@ -40,9 +38,9 @@ namespace osu.Game.Users [LongRunningLoad] private partial class Cover : CompositeDrawable { - private readonly APIUser user; + private readonly APIUser? user; - public Cover(APIUser user) + public Cover(APIUser? user) { this.user = user; From 73f14bd14fb76791d44365d33d782d519a897177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 15:05:04 +0100 Subject: [PATCH 084/121] Enable NRT in user profile overlay test scenes --- osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs | 2 -- osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs | 2 -- .../Visual/Online/TestSceneProfileRulesetSelector.cs | 4 +--- osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs | 2 -- osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs | 4 +--- osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs | 2 -- .../Visual/Online/TestSceneUserProfilePreviousUsernames.cs | 6 ++---- .../Visual/Online/TestSceneUserProfileRecentSection.cs | 2 -- osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs | 2 -- osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs | 2 -- .../UserInterface/TestSceneProfileSubsectionHeader.cs | 4 +--- 11 files changed, 5 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs index d884c0cf14..28f0e6ff9c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.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 NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; diff --git a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs index e753632474..84497245db 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.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 osu.Game.Overlays.Profile.Sections.Kudosu; using System.Collections.Generic; using System; diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs index e81b7a2ac8..a4d8238fa3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.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 osu.Framework.Graphics; using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Rulesets.Catch; @@ -24,7 +22,7 @@ namespace osu.Game.Tests.Visual.Online public TestSceneProfileRulesetSelector() { ProfileRulesetSelector selector; - var user = new Bindable(); + var user = new Bindable(); Child = selector = new ProfileRulesetSelector { diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs index d93bf059dd..454242270d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.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; using osu.Framework.Allocation; using osu.Framework.Graphics; diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs index 75743d788a..bfd6372e6f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.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; using System.Linq; using NUnit.Framework; @@ -20,7 +18,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); - private ProfileHeader header; + private ProfileHeader header = null!; [SetUpSteps] public void SetUpSteps() diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 02d01b4a46..35c7e7bf28 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.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; using System.Linq; using NUnit.Framework; diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs index fcefb31716..921738d331 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.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; using NUnit.Framework; using osu.Framework.Graphics; @@ -14,7 +12,7 @@ namespace osu.Game.Tests.Visual.Online [TestFixture] public partial class TestSceneUserProfilePreviousUsernames : OsuTestScene { - private PreviousUsernames container; + private PreviousUsernames container = null!; [SetUp] public void SetUp() => Schedule(() => @@ -50,7 +48,7 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("Is hidden", () => container.Alpha == 0); } - private static readonly APIUser[] users = + private static readonly APIUser?[] users = { new APIUser { Id = 1, PreviousUsernames = new[] { "username1" } }, new APIUser { Id = 2, PreviousUsernames = new[] { "longusername", "longerusername" } }, diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs index f8432118d4..9d0ea80533 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.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.Collections.Generic; using System.Linq; using NUnit.Framework; diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs index 6f0ef10911..5249e8694d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.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; using osu.Framework.Allocation; using osu.Framework.Graphics; diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs index ef3a677efc..fdbd8a4325 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.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 NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs index b4b45da133..c51095f360 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.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 NUnit.Framework; using osu.Game.Overlays.Profile.Sections; using osu.Framework.Testing; @@ -18,7 +16,7 @@ namespace osu.Game.Tests.Visual.UserInterface [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); - private ProfileSubsectionHeader header; + private ProfileSubsectionHeader header = null!; [Test] public void TestHiddenCounter() From 8f7ae0395a082eda458009ccdaf3504675dca9fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Jan 2023 00:55:05 +0800 Subject: [PATCH 085/121] Fix song select leaderboard potentially showing wrong scores on quick beatmap changes Closes #22002. --- .../Select/Leaderboards/BeatmapLeaderboard.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index b8a2eec526..9e8247059d 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -154,10 +154,17 @@ namespace osu.Game.Screens.Select.Leaderboards scoreRetrievalRequest = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods); - scoreRetrievalRequest.Success += response => SetScores( - scoreManager.OrderByTotalScore(response.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))), - response.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo) - ); + scoreRetrievalRequest.Success += response => Schedule(() => + { + // Beatmap may have changed since fetch request. Can't rely on request cancellation due to Schedule inside SetScores. + if (!fetchBeatmapInfo.Equals(BeatmapInfo)) + return; + + SetScores( + scoreManager.OrderByTotalScore(response.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))), + response.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo) + ); + }); return scoreRetrievalRequest; } From ac85433178f9f61992e6a2239a3e783fca9f76ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Jan 2023 09:44:34 +0800 Subject: [PATCH 086/121] Fix default volume control keys not working when chat textbox is focused Closes #22004. --- osu.Game/Graphics/UserInterface/HistoryTextBox.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index d74a4f2cdb..b6dc1fcc9b 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -45,6 +45,9 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnKeyDown(KeyDownEvent e) { + if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.ShiftPressed) + return false; + switch (e.Key) { case Key.Up: From 4491a5ba9f7c38010600bcc4db4c358cdc6c7c9e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 3 Jan 2023 13:41:08 +0300 Subject: [PATCH 087/121] Fix editor exporting beatmap combo colours in wrong order --- osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 03c63ff4f2..7e058d755e 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -300,7 +300,7 @@ namespace osu.Game.Beatmaps.Formats { var comboColour = colours[i]; - writer.Write(FormattableString.Invariant($"Combo{i}: ")); + writer.Write(FormattableString.Invariant($"Combo{1 + i}: ")); writer.Write(FormattableString.Invariant($"{(byte)(comboColour.R * byte.MaxValue)},")); writer.Write(FormattableString.Invariant($"{(byte)(comboColour.G * byte.MaxValue)},")); writer.Write(FormattableString.Invariant($"{(byte)(comboColour.B * byte.MaxValue)},")); From efbd9ba4b90946909faa4a07024484e38cd15001 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 3 Jan 2023 15:28:05 +0300 Subject: [PATCH 088/121] Fix catcher not moving when fully hidden in "No Scope" mod --- osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs index 19b4a39f97..ddeea51ecb 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs @@ -26,6 +26,9 @@ namespace osu.Game.Rulesets.Catch.Mods var catchPlayfield = (CatchPlayfield)playfield; bool shouldAlwaysShowCatcher = IsBreakTime.Value; float targetAlpha = shouldAlwaysShowCatcher ? 1 : ComboBasedAlpha; + + // AlwaysPresent required for catcher to still act on input when fully hidden. + catchPlayfield.CatcherArea.AlwaysPresent = true; catchPlayfield.CatcherArea.Alpha = (float)Interpolation.Lerp(catchPlayfield.CatcherArea.Alpha, targetAlpha, Math.Clamp(catchPlayfield.Time.Elapsed / TRANSITION_DURATION, 0, 1)); } } From 71125afcb45365a09424a7348ef20d51dc2a2392 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 3 Jan 2023 15:43:36 +0300 Subject: [PATCH 089/121] Add test coverage --- .../Mods/TestSceneCatchModNoScope.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs index 50b928d509..c48bf7adc9 100644 --- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs +++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs @@ -18,6 +18,36 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods { protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); + [Test] + public void TestAlwaysHidden() + { + CreateModTest(new ModTestData + { + Mod = new CatchModNoScope + { + HiddenComboCount = { Value = 0 }, + }, + Autoplay = true, + PassCondition = () => Player.ScoreProcessor.Combo.Value == 2, + Beatmap = new Beatmap + { + HitObjects = new List + { + new Fruit + { + X = CatchPlayfield.CENTER_X * 0.5f, + StartTime = 1000, + }, + new Fruit + { + X = CatchPlayfield.CENTER_X * 1.5f, + StartTime = 2000, + } + } + } + }); + } + [Test] public void TestVisibleDuringBreak() { From 96e81e7f41e825e2ed631a97ab212f13ec30b259 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 4 Jan 2023 01:41:21 +0800 Subject: [PATCH 090/121] Switch on NRT and add `IEquatable` to `GetScoresRequest` --- .../Online/API/Requests/GetScoresRequest.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 7d1d26b75d..f2a2daccb5 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.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; using osu.Game.Beatmaps; using osu.Game.Rulesets; @@ -11,10 +9,11 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using System.Text; using System.Collections.Generic; +using System.Linq; namespace osu.Game.Online.API.Requests { - public class GetScoresRequest : APIRequest + public class GetScoresRequest : APIRequest, IEquatable { public const int MAX_SCORES_PER_REQUEST = 50; @@ -23,7 +22,7 @@ namespace osu.Game.Online.API.Requests private readonly IRulesetInfo ruleset; private readonly IEnumerable mods; - public GetScoresRequest(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable mods = null) + public GetScoresRequest(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable? mods = null) { if (beatmapInfo.OnlineID <= 0) throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(IBeatmapInfo.OnlineID)}."); @@ -51,5 +50,16 @@ namespace osu.Game.Online.API.Requests return query.ToString(); } + + public bool Equals(GetScoresRequest? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return beatmapInfo.Equals(other.beatmapInfo) + && scope == other.scope + && ruleset.Equals(other.ruleset) + && mods.SequenceEqual(other.mods); + } } } From beb3b96aca7366fa812d436103ffbdfa5b682eee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 4 Jan 2023 01:44:00 +0800 Subject: [PATCH 091/121] Harden request equality checks --- .../Select/Leaderboards/BeatmapLeaderboard.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 9e8247059d..c419501add 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -152,12 +152,14 @@ namespace osu.Game.Screens.Select.Leaderboards else if (filterMods) requestMods = mods.Value; - scoreRetrievalRequest = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods); + scoreRetrievalRequest?.Cancel(); - scoreRetrievalRequest.Success += response => Schedule(() => + var newRequest = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods); + newRequest.Success += response => Schedule(() => { - // Beatmap may have changed since fetch request. Can't rely on request cancellation due to Schedule inside SetScores. - if (!fetchBeatmapInfo.Equals(BeatmapInfo)) + // Request may have changed since fetch request. + // Can't rely on request cancellation due to Schedule inside SetScores so let's play it safe. + if (!newRequest.Equals(scoreRetrievalRequest)) return; SetScores( @@ -166,7 +168,7 @@ namespace osu.Game.Screens.Select.Leaderboards ); }); - return scoreRetrievalRequest; + return scoreRetrievalRequest = newRequest; } protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index) => new LeaderboardScore(model, index, IsOnlineScope) From 49b098407983ec0e39a2b8e19c2df469fe0ba703 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Jan 2023 21:53:58 -0800 Subject: [PATCH 092/121] Add failing playlist no selection after deleted test --- .../TestScenePlaylistsRoomSettingsPlaylist.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs index 91e9ce5ea2..ae27db0dd1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -46,10 +47,14 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("item removed", () => !playlist.Items.Contains(selectedItem)); } - [Test] - public void TestNextItemSelectedAfterDeletion() + [TestCase(true)] + [TestCase(false)] + public void TestNextItemSelectedAfterDeletion(bool allowSelection) { - createPlaylist(); + createPlaylist(p => + { + p.AllowSelection = allowSelection; + }); moveToItem(0); AddStep("click", () => InputManager.Click(MouseButton.Left)); @@ -57,7 +62,7 @@ namespace osu.Game.Tests.Visual.Multiplayer moveToDeleteButton(0); AddStep("click delete button", () => InputManager.Click(MouseButton.Left)); - AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]); + AddAssert("item 0 is " + (allowSelection ? "selected" : "not selected"), () => playlist.SelectedItem.Value == (allowSelection ? playlist.Items[0] : null)); } [Test] @@ -117,7 +122,7 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.MoveMouseTo(item.ChildrenOfType().ElementAt(0), offset); }); - private void createPlaylist() + private void createPlaylist(Action setupPlaylist = null) { AddStep("create playlist", () => { @@ -154,6 +159,8 @@ namespace osu.Game.Tests.Visual.Multiplayer } }); } + + setupPlaylist?.Invoke(playlist); }); AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded)); From 5dfd4180c84c09bce3ef25803d66ab0168377842 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Jan 2023 21:22:24 -0800 Subject: [PATCH 093/121] Fix playlist selecting random item when not allowed after deleting --- .../OnlinePlay/Playlists/PlaylistsRoomSettingsPlaylist.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsPlaylist.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsPlaylist.cs index df502ae09c..736f09584b 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsPlaylist.cs @@ -24,7 +24,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Items.Remove(item); - SelectedItem.Value = nextItem ?? Items.LastOrDefault(); + if (AllowSelection && SelectedItem.Value == item) + SelectedItem.Value = nextItem ?? Items.LastOrDefault(); }; } } From 5fb6f220e69437c87224e4ae13c4da6205c1f87d Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Jan 2023 21:21:27 -0800 Subject: [PATCH 094/121] Fix playlist items not animating when rearranging --- osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs index f5477837b0..8abdec9ade 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs @@ -156,6 +156,8 @@ namespace osu.Game.Screens.OnlinePlay protected override FillFlowContainer> CreateListFillFlowContainer() => new FillFlowContainer> { + LayoutDuration = 200, + LayoutEasing = Easing.OutQuint, Spacing = new Vector2(0, 2) }; From d70df08f45bb4573bb28ba866036a3cf9527589a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 4 Jan 2023 16:18:33 +0300 Subject: [PATCH 095/121] Tint "argon" slider ball with combo colour --- .../Skinning/Argon/ArgonSliderBall.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs index 48b43f359d..d6ce793c7e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -21,6 +23,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private readonly Vector2 defaultIconScale = new Vector2(0.6f, 0.8f); + private readonly IBindable accentColour = new Bindable(); + [Resolved(canBeNull: true)] private DrawableHitObject? parentObject { get; set; } @@ -37,7 +41,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { fill = new Box { - Colour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")), RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -53,10 +56,22 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon }; } + [BackgroundDependencyLoader] + private void load() + { + if (parentObject != null) + accentColour.BindTo(parentObject.AccentColour); + } + protected override void LoadComplete() { base.LoadComplete(); + accentColour.BindValueChanged(colour => + { + fill.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.5f)); + }, true); + if (parentObject != null) { parentObject.ApplyCustomUpdateState += updateStateTransforms; From 760b2d98df1908064a89b54cffcec2befecff943 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 4 Jan 2023 16:19:30 +0300 Subject: [PATCH 096/121] Tint "argon" slider follow circle with combo colour --- .../Skinning/Argon/ArgonFollowCircle.cs | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs index 95c75164aa..fca3e70236 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs @@ -1,35 +1,64 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Bindables; +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.Utils; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { public partial class ArgonFollowCircle : FollowCircle { + private readonly CircularContainer circleContainer; + private readonly Box circleFill; + + private readonly IBindable accentColour = new Bindable(); + + [Resolved(canBeNull: true)] + private DrawableHitObject? parentObject { get; set; } + public ArgonFollowCircle() { - InternalChild = new CircularContainer + InternalChild = circleContainer = new CircularContainer { RelativeSizeAxes = Axes.Both, Masking = true, BorderThickness = 4, - BorderColour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")), Blending = BlendingParameters.Additive, - Child = new Box + Child = circleFill = new Box { - Colour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")), RelativeSizeAxes = Axes.Both, Alpha = 0.3f, } }; } + [BackgroundDependencyLoader] + private void load() + { + if (parentObject != null) + accentColour.BindTo(parentObject.AccentColour); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + accentColour.BindValueChanged(colour => + { + circleContainer.BorderColour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.5f)); + circleFill.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.5f)); + }, true); + } + protected override void OnSliderPress() { const float duration = 300f; From 8da7667b0b84392004fe23ada51191b69d6ebb7a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 5 Jan 2023 14:06:24 +0300 Subject: [PATCH 097/121] Decrease transition duration of extended difficulty list during hide --- .../Drawables/Cards/BeatmapCardContent.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContent.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContent.cs index d4cbe6ddd0..7deb5f768c 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContent.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContent.cs @@ -138,9 +138,18 @@ namespace osu.Game.Beatmaps.Drawables.Cards // This avoids depth issues where a hovered (scaled) card to the right of another card would be beneath the card to the left. this.ScaleTo(Expanded.Value ? 1.03f : 1, 500, Easing.OutQuint); - background.FadeTo(Expanded.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); - dropdownContent.FadeTo(Expanded.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); - borderContainer.FadeTo(Expanded.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + if (Expanded.Value) + { + background.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + dropdownContent.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + borderContainer.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + } + else + { + background.FadeOut(BeatmapCard.TRANSITION_DURATION / 3f, Easing.OutQuint); + dropdownContent.FadeOut(BeatmapCard.TRANSITION_DURATION / 3f, Easing.OutQuint); + borderContainer.FadeOut(BeatmapCard.TRANSITION_DURATION / 3f, Easing.OutQuint); + } content.TweenEdgeEffectTo(new EdgeEffectParameters { From 7d8aff8f7e75b6f5517eeb91a97cf09a401a8587 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 5 Jan 2023 14:35:57 +0300 Subject: [PATCH 098/121] Fix settings toolbox group not animating on expansion --- osu.Game/Overlays/SettingsToolboxGroup.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 56c890e9e2..86964e7ed4 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -126,7 +126,8 @@ namespace osu.Game.Overlays { base.LoadComplete(); - Expanded.BindValueChanged(updateExpandedState, true); + Expanded.BindValueChanged(_ => updateExpandedState(true)); + updateExpandedState(false); this.Delay(600).Schedule(updateFadeState); } @@ -161,21 +162,25 @@ namespace osu.Game.Overlays return base.OnInvalidate(invalidation, source); } - private void updateExpandedState(ValueChangedEvent expanded) + private void updateExpandedState(bool animate) { // clearing transforms is necessary to avoid a previous height transform // potentially continuing to get processed while content has changed to autosize. content.ClearTransforms(); - if (expanded.NewValue) + if (Expanded.Value) + { content.AutoSizeAxes = Axes.Y; + content.AutoSizeDuration = animate ? transition_duration : 0; + content.AutoSizeEasing = Easing.OutQuint; + } else { content.AutoSizeAxes = Axes.None; - content.ResizeHeightTo(0, transition_duration, Easing.OutQuint); + content.ResizeHeightTo(0, animate ? transition_duration : 0, Easing.OutQuint); } - headerContent.FadeColour(expanded.NewValue ? Color4.White : OsuColour.Gray(0.5f), 200, Easing.OutQuint); + headerContent.FadeColour(Expanded.Value ? Color4.White : OsuColour.Gray(0.5f), 200, Easing.OutQuint); } private void updateFadeState() From 86b1164e28b5f33fd0f0f11a03bf6b854ac1235f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 5 Jan 2023 14:41:26 +0300 Subject: [PATCH 099/121] Add visual test case --- .../UserInterface/TestSceneSettingsToolboxGroup.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs index 71b98ed9af..f96d2feba8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs @@ -55,6 +55,16 @@ namespace osu.Game.Tests.Visual.UserInterface }; }); + [Test] + public void TestDisplay() + { + AddRepeatStep("toggle expanded state", () => + { + InputManager.MoveMouseTo(group.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }, 5); + } + [Test] public void TestClickExpandButtonMultipleTimes() { From c6e2104ec298647d6a0bb48b86846bbdf6ea7707 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 6 Jan 2023 03:46:49 +0300 Subject: [PATCH 100/121] Refresh waveforms instead of recreating the whole component --- .../Screens/Edit/Timing/TapTimingControl.cs | 19 ++----------------- .../Edit/Timing/WaveformComparisonDisplay.cs | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 0d29b69d96..bb7a3b8be3 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -3,7 +3,6 @@ using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -30,15 +29,12 @@ namespace osu.Game.Screens.Edit.Timing [Resolved] private Bindable selectedGroup { get; set; } = null!; - private readonly IBindable track = new Bindable(); - private readonly BindableBool isHandlingTapping = new BindableBool(); private MetronomeDisplay metronome = null!; - private Container waveformContainer = null!; [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, OsuColour colours, EditorClock clock) + private void load(OverlayColourProvider colourProvider, OsuColour colours) { const float padding = 10; @@ -92,11 +88,7 @@ namespace osu.Game.Screens.Edit.Timing Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, }, - waveformContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Child = new WaveformComparisonDisplay(), - } + new WaveformComparisonDisplay() } }, } @@ -187,13 +179,6 @@ namespace osu.Game.Screens.Edit.Timing if (handling.NewValue) start(); }, true); - - track.BindTo(clock.Track); - } - - protected override void LoadComplete() - { - track.ValueChanged += _ => waveformContainer.Child = new WaveformComparisonDisplay(); } private void start() diff --git a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs index 6c17aeed54..b5a1ab29d2 100644 --- a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Audio; @@ -294,13 +295,18 @@ namespace osu.Game.Screens.Edit.Timing [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + [Resolved] + private IBindable beatmap { get; set; } = null!; + + private readonly IBindable track = new Bindable(); + public WaveformRow(bool isMainRow) { this.isMainRow = isMainRow; } [BackgroundDependencyLoader] - private void load(IBindable beatmap) + private void load(EditorClock clock) { InternalChildren = new Drawable[] { @@ -330,6 +336,13 @@ namespace osu.Game.Screens.Edit.Timing Colour = colourProvider.Content2 } }; + + track.BindTo(clock.Track); + } + + protected override void LoadComplete() + { + track.ValueChanged += _ => waveformGraph.Waveform = beatmap.Value.Waveform; } public int BeatIndex { set => beatIndexText.Text = value.ToString(); } From 408356d05e0d2f7a1178c99dc34b66e2b944324d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 6 Jan 2023 11:58:38 +0300 Subject: [PATCH 101/121] Fix gameplay leaderboard showing "-" on non-tracked scores --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 4 ++-- osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index f6f289db55..d990af32e7 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -171,13 +171,13 @@ namespace osu.Game.Screens.Play.HUD for (int i = 0; i < Flow.Count; i++) { Flow.SetLayoutPosition(orderedByScore[i], i); - orderedByScore[i].ScorePosition = CheckValidScorePosition(i + 1) ? i + 1 : null; + orderedByScore[i].ScorePosition = CheckValidScorePosition(orderedByScore[i], i + 1) ? i + 1 : null; } sorting.Validate(); } - protected virtual bool CheckValidScorePosition(int i) => true; + protected virtual bool CheckValidScorePosition(GameplayLeaderboardScore score, int position) => true; private partial class InputDisabledScrollContainer : OsuScrollContainer { diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 0f3e54ecdd..9f92880919 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -100,16 +100,16 @@ namespace osu.Game.Screens.Play.HUD local.DisplayOrder.Value = long.MaxValue; } - protected override bool CheckValidScorePosition(int i) + protected override bool CheckValidScorePosition(GameplayLeaderboardScore score, int position) { // change displayed position to '-' when there are 50 already submitted scores and tracked score is last - if (scoreSource.Value != PlayBeatmapDetailArea.TabType.Local) + if (score.Tracked && scoreSource.Value != PlayBeatmapDetailArea.TabType.Local) { - if (i == Flow.Count && Flow.Count > GetScoresRequest.MAX_SCORES_PER_REQUEST) + if (position == Flow.Count && Flow.Count > GetScoresRequest.MAX_SCORES_PER_REQUEST) return false; } - return base.CheckValidScorePosition(i); + return base.CheckValidScorePosition(score, position); } private void updateVisibility() => From 458fe382ed51b110fc476013c7db32fe8b69926b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 Jan 2023 20:06:41 +0900 Subject: [PATCH 102/121] Make selected tab items more bold --- osu.Game/Overlays/BeatmapListing/FilterTabItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 7b95ae8ea8..042efb18fb 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -81,7 +81,7 @@ namespace osu.Game.Overlays.BeatmapListing private void updateState() { text.FadeColour(IsHovered ? colourProvider.Light1 : GetStateColour(), 200, Easing.OutQuint); - text.Font = text.Font.With(weight: Active.Value ? FontWeight.SemiBold : FontWeight.Regular); + text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular); } protected virtual Color4 GetStateColour() => Active.Value ? colourProvider.Content1 : colourProvider.Light2; From 3c74d27deb556d93c52f7b10f33f7d38c7b5848f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 Jan 2023 20:35:58 +0900 Subject: [PATCH 103/121] Also add an underline to better accent current filters --- ...BeatmapSearchMultipleSelectionFilterRow.cs | 23 +++++++++++++++++++ .../Overlays/BeatmapListing/FilterTabItem.cs | 12 +++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index 5d1ccbd58b..c6cd6591a9 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -12,6 +12,7 @@ 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.Events; using osu.Framework.Localisation; using osuTK; @@ -100,9 +101,31 @@ namespace osu.Game.Overlays.BeatmapListing protected partial class MultipleSelectionFilterTabItem : FilterTabItem { + private readonly Box selectedUnderline; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + public MultipleSelectionFilterTabItem(T value) : base(value) { + // This doesn't match any actual design, but should make it easier for the user to understand + // that filters are applied until we settle on a final design. + AddInternal(selectedUnderline = new Box + { + Depth = float.MaxValue, + RelativeSizeAxes = Axes.X, + Height = 1.5f, + Anchor = Anchor.BottomLeft, + Origin = Anchor.CentreLeft, + }); + } + + protected override void UpdateState() + { + base.UpdateState(); + selectedUnderline.FadeTo(Active.Value ? 1 : 0, 200, Easing.OutQuint); + selectedUnderline.FadeColour(IsHovered ? colourProvider.Light1 : GetStateColour(), 200, Easing.OutQuint); } protected override bool OnClick(ClickEvent e) diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 7b95ae8ea8..34ade0596d 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -52,33 +52,33 @@ namespace osu.Game.Overlays.BeatmapListing { base.LoadComplete(); - updateState(); + UpdateState(); FinishTransforms(true); } protected override bool OnHover(HoverEvent e) { base.OnHover(e); - updateState(); + UpdateState(); return true; } protected override void OnHoverLost(HoverLostEvent e) { base.OnHoverLost(e); - updateState(); + UpdateState(); } - protected override void OnActivated() => updateState(); + protected override void OnActivated() => UpdateState(); - protected override void OnDeactivated() => updateState(); + protected override void OnDeactivated() => UpdateState(); /// /// Returns the label text to be used for the supplied . /// protected virtual LocalisableString LabelFor(T value) => (value as Enum)?.GetLocalisableDescription() ?? value.ToString(); - private void updateState() + protected virtual void UpdateState() { text.FadeColour(IsHovered ? colourProvider.Light1 : GetStateColour(), 200, Easing.OutQuint); text.Font = text.Font.With(weight: Active.Value ? FontWeight.SemiBold : FontWeight.Regular); From 4319937bc79a1eabc6ffbba40566087938c14323 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 Jan 2023 20:35:58 +0900 Subject: [PATCH 104/121] Also add an underline to better accent current filters --- ...BeatmapSearchMultipleSelectionFilterRow.cs | 23 +++++++++++++++++++ .../Overlays/BeatmapListing/FilterTabItem.cs | 12 +++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index 5d1ccbd58b..c6cd6591a9 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -12,6 +12,7 @@ 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.Events; using osu.Framework.Localisation; using osuTK; @@ -100,9 +101,31 @@ namespace osu.Game.Overlays.BeatmapListing protected partial class MultipleSelectionFilterTabItem : FilterTabItem { + private readonly Box selectedUnderline; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + public MultipleSelectionFilterTabItem(T value) : base(value) { + // This doesn't match any actual design, but should make it easier for the user to understand + // that filters are applied until we settle on a final design. + AddInternal(selectedUnderline = new Box + { + Depth = float.MaxValue, + RelativeSizeAxes = Axes.X, + Height = 1.5f, + Anchor = Anchor.BottomLeft, + Origin = Anchor.CentreLeft, + }); + } + + protected override void UpdateState() + { + base.UpdateState(); + selectedUnderline.FadeTo(Active.Value ? 1 : 0, 200, Easing.OutQuint); + selectedUnderline.FadeColour(IsHovered ? colourProvider.Light1 : GetStateColour(), 200, Easing.OutQuint); } protected override bool OnClick(ClickEvent e) diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 042efb18fb..9a697890f3 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -52,33 +52,33 @@ namespace osu.Game.Overlays.BeatmapListing { base.LoadComplete(); - updateState(); + UpdateState(); FinishTransforms(true); } protected override bool OnHover(HoverEvent e) { base.OnHover(e); - updateState(); + UpdateState(); return true; } protected override void OnHoverLost(HoverLostEvent e) { base.OnHoverLost(e); - updateState(); + UpdateState(); } - protected override void OnActivated() => updateState(); + protected override void OnActivated() => UpdateState(); - protected override void OnDeactivated() => updateState(); + protected override void OnDeactivated() => UpdateState(); /// /// Returns the label text to be used for the supplied . /// protected virtual LocalisableString LabelFor(T value) => (value as Enum)?.GetLocalisableDescription() ?? value.ToString(); - private void updateState() + protected virtual void UpdateState() { text.FadeColour(IsHovered ? colourProvider.Light1 : GetStateColour(), 200, Easing.OutQuint); text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular); From 0ade4d92d1f70a4943c49e06643996c70bc0c010 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 6 Jan 2023 15:13:31 +0300 Subject: [PATCH 105/121] Fix multiple highlighting issues with beatmap listing tab items --- .../BeatmapSearchMultipleSelectionFilterRow.cs | 5 ++--- osu.Game/Overlays/BeatmapListing/FilterTabItem.cs | 10 +++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index c6cd6591a9..abd2643a41 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -103,8 +103,7 @@ namespace osu.Game.Overlays.BeatmapListing { private readonly Box selectedUnderline; - [Resolved] - private OverlayColourProvider colourProvider { get; set; } + protected override bool HighlightOnHoverWhenActive => true; public MultipleSelectionFilterTabItem(T value) : base(value) @@ -125,7 +124,7 @@ namespace osu.Game.Overlays.BeatmapListing { base.UpdateState(); selectedUnderline.FadeTo(Active.Value ? 1 : 0, 200, Easing.OutQuint); - selectedUnderline.FadeColour(IsHovered ? colourProvider.Light1 : GetStateColour(), 200, Easing.OutQuint); + selectedUnderline.FadeColour(IsHovered ? ColourProvider.Content2 : GetStateColour(), 200, Easing.OutQuint); } protected override bool OnClick(ClickEvent e) diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 34ade0596d..a97b2e16c3 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.BeatmapListing public partial class FilterTabItem : TabItem { [Resolved] - private OverlayColourProvider colourProvider { get; set; } + protected OverlayColourProvider ColourProvider { get; private set; } private OsuSpriteText text; @@ -78,12 +78,16 @@ namespace osu.Game.Overlays.BeatmapListing /// protected virtual LocalisableString LabelFor(T value) => (value as Enum)?.GetLocalisableDescription() ?? value.ToString(); + protected virtual bool HighlightOnHoverWhenActive => false; + protected virtual void UpdateState() { - text.FadeColour(IsHovered ? colourProvider.Light1 : GetStateColour(), 200, Easing.OutQuint); + bool highlightHover = IsHovered && (!Active.Value || HighlightOnHoverWhenActive); + + text.FadeColour(highlightHover ? ColourProvider.Content2 : GetStateColour(), 200, Easing.OutQuint); text.Font = text.Font.With(weight: Active.Value ? FontWeight.SemiBold : FontWeight.Regular); } - protected virtual Color4 GetStateColour() => Active.Value ? colourProvider.Content1 : colourProvider.Light2; + protected virtual Color4 GetStateColour() => Active.Value ? ColourProvider.Content1 : ColourProvider.Light2; } } From e90c698e62974d630865fe8962f4926e321ca345 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 6 Jan 2023 16:35:39 +0300 Subject: [PATCH 106/121] Fix WCD does not take into account start time of control points --- osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs index b5a1ab29d2..3b3acea935 100644 --- a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs @@ -151,7 +151,7 @@ namespace osu.Game.Screens.Edit.Timing if (!displayLocked.Value) { float trackLength = (float)beatmap.Value.Track.Length; - int totalBeatsAvailable = (int)(trackLength / timingPoint.BeatLength); + int totalBeatsAvailable = (int)((trackLength - timingPoint.Time) / timingPoint.BeatLength); Scheduler.AddOnce(showFromBeat, (int)(e.MousePosition.X / DrawWidth * totalBeatsAvailable)); } From 9364c7775d57e18e1abea1b7d5fe0d1416c45f03 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 6 Jan 2023 19:26:30 +0300 Subject: [PATCH 107/121] Refresh background on file change in editor --- .../Screens/Backgrounds/BackgroundScreenBeatmap.cs | 12 ++++++++++++ osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index 42a81ad3fa..312fd496a1 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -99,6 +99,18 @@ namespace osu.Game.Screens.Backgrounds } } + /// + /// Reloads beatmap's background. + /// + public void RefreshBackground() + { + Schedule(() => + { + cancellationSource?.Cancel(); + LoadComponentAsync(new BeatmapBackground(beatmap), switchBackground, (cancellationSource = new CancellationTokenSource()).Token); + }); + } + private void switchBackground(BeatmapBackground b) { float newDepth = 0; diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index ca0f50cd34..c79d9d6632 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -33,6 +33,9 @@ namespace osu.Game.Screens.Edit.Setup [Resolved] private EditorBeatmap editorBeatmap { get; set; } + [Resolved] + private Editor editor { get; set; } + [Resolved] private SetupScreenHeader header { get; set; } @@ -93,6 +96,8 @@ namespace osu.Game.Screens.Edit.Setup working.Value.Metadata.BackgroundFile = destination.Name; header.Background.UpdateBackground(); + editor.ApplyToBackground(bg => bg.RefreshBackground()); + return true; } From 53d7dcefe5c4d4da6c0a642bf9556e419a3cb2ce Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 5 Jan 2023 14:40:18 -0800 Subject: [PATCH 108/121] Fix osu! logo not being draggable on player loader --- osu.Game/Screens/Menu/OsuLogo.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 2d6a0736e9..7a5a26226b 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -282,7 +282,7 @@ namespace osu.Game.Screens.Menu if (beatIndex < 0) return; - if (IsHovered) + if (Action != null && IsHovered) { this.Delay(early_activation).Schedule(() => { @@ -361,11 +361,11 @@ namespace osu.Game.Screens.Menu } } - public override bool HandlePositionalInput => base.HandlePositionalInput && Action != null && Alpha > 0.2f; + public override bool HandlePositionalInput => base.HandlePositionalInput && Alpha > 0.2f; protected override bool OnMouseDown(MouseDownEvent e) { - if (e.Button != MouseButton.Left) return false; + if (Action == null || e.Button != MouseButton.Left) return false; logoBounceContainer.ScaleTo(0.9f, 1000, Easing.Out); return true; @@ -380,7 +380,9 @@ namespace osu.Game.Screens.Menu protected override bool OnClick(ClickEvent e) { - if (Action?.Invoke() ?? true) + if (Action == null) return false; + + if (Action.Invoke()) sampleClick.Play(); flashLayer.ClearTransforms(); @@ -391,6 +393,8 @@ namespace osu.Game.Screens.Menu protected override bool OnHover(HoverEvent e) { + if (Action == null) return false; + logoHoverContainer.ScaleTo(1.1f, 500, Easing.OutElastic); return true; } From 7f970f3cd846068bb775586f398e8fce73329089 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 29 Dec 2022 21:17:24 -0800 Subject: [PATCH 109/121] Display nominators on beatmap set overlay --- .../API/Requests/Responses/APIBeatmapSet.cs | 6 ++ .../Responses/BeatmapSetOnlineNominations.cs | 22 +++++++ osu.Game/Overlays/BeatmapSet/Info.cs | 4 ++ .../BeatmapSet/MetadataSectionNominators.cs | 62 +++++++++++++++++++ osu.Game/Overlays/BeatmapSet/MetadataType.cs | 5 +- 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Online/API/Requests/Responses/BeatmapSetOnlineNominations.cs create mode 100644 osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 717a1de6b5..eb39b7489d 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -111,6 +111,12 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"language")] public BeatmapSetOnlineLanguage Language { get; set; } + [JsonProperty(@"current_nominations")] + public BeatmapSetOnlineNominations[] CurrentNominations { get; set; } = Array.Empty(); + + [JsonProperty(@"related_users")] + public APIUser[] RelatedUsers { get; set; } = Array.Empty(); + public string Source { get; set; } = string.Empty; [JsonProperty(@"tags")] diff --git a/osu.Game/Online/API/Requests/Responses/BeatmapSetOnlineNominations.cs b/osu.Game/Online/API/Requests/Responses/BeatmapSetOnlineNominations.cs new file mode 100644 index 0000000000..5d0a3ea38b --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/BeatmapSetOnlineNominations.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public struct BeatmapSetOnlineNominations + { + [JsonProperty(@"beatmapset_id")] + public int BeatmapsetId { get; set; } + + [JsonProperty(@"reset")] + public bool Reset { get; set; } + + [JsonProperty(@"rulesets")] + public string[]? Rulesets { get; set; } + + [JsonProperty(@"user_id")] + public int UserId { get; set; } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index d184f0d0fd..dbeea74f6f 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -36,6 +37,7 @@ namespace osu.Game.Overlays.BeatmapSet public Info() { + MetadataSectionNominators nominators; MetadataSection source, tags; MetadataSectionGenre genre; MetadataSectionLanguage language; @@ -82,6 +84,7 @@ namespace osu.Game.Overlays.BeatmapSet Direction = FillDirection.Full, Children = new Drawable[] { + nominators = new MetadataSectionNominators(), source = new MetadataSectionSource(), genre = new MetadataSectionGenre { Width = 0.5f }, language = new MetadataSectionLanguage { Width = 0.5f }, @@ -122,6 +125,7 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.ValueChanged += b => { + nominators.Metadata = (b.NewValue?.CurrentNominations ?? Array.Empty(), b.NewValue?.RelatedUsers ?? Array.Empty()); source.Metadata = b.NewValue?.Source ?? string.Empty; tags.Metadata = b.NewValue?.Tags ?? string.Empty; genre.Metadata = b.NewValue?.Genre ?? new BeatmapSetOnlineGenre { Id = (int)SearchGenre.Unspecified }; diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs new file mode 100644 index 0000000000..78a3fe7cd5 --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs @@ -0,0 +1,62 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using osu.Framework.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Overlays.BeatmapSet +{ + public partial class MetadataSectionNominators : MetadataSection<(BeatmapSetOnlineNominations[] CurrentNominations, APIUser[] RelatedUsers)> + { + public override (BeatmapSetOnlineNominations[] CurrentNominations, APIUser[] RelatedUsers) Metadata + { + set + { + if (value.CurrentNominations.Length == 0) + { + this.FadeOut(TRANSITION_DURATION); + return; + } + + base.Metadata = value; + } + } + + public MetadataSectionNominators(Action<(BeatmapSetOnlineNominations[] CurrentNominations, APIUser[] RelatedUsers)>? searchAction = null) + : base(MetadataType.Nominators, searchAction) + { + } + + protected override void AddMetadata((BeatmapSetOnlineNominations[] CurrentNominations, APIUser[] RelatedUsers) metadata, LinkFlowContainer loaded) + { + int[] nominatorIds = metadata.CurrentNominations.Select(n => n.UserId).ToArray(); + + int nominatorsFound = 0; + + foreach (int nominatorId in nominatorIds) + { + foreach (var user in metadata.RelatedUsers) + { + if (nominatorId != user.OnlineID) continue; + + nominatorsFound++; + + loaded.AddUserLink(new APIUser + { + Username = user.Username, + Id = nominatorId, + }); + + if (nominatorsFound < nominatorIds.Length) + loaded.AddText(CommonStrings.ArrayAndWordsConnector); + + break; + } + } + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/MetadataType.cs b/osu.Game/Overlays/BeatmapSet/MetadataType.cs index 924e020641..dc96ce99e9 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataType.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataType.cs @@ -23,6 +23,9 @@ namespace osu.Game.Overlays.BeatmapSet Genre, [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoLanguage))] - Language + Language, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoNominators))] + Nominators, } } From e449d8dda067cc671b648330e6089d3e5f53cf9c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 6 Jan 2023 22:39:46 +0300 Subject: [PATCH 110/121] Fix friends list duplicating on connection failure --- osu.Game/Online/API/APIAccess.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index f2b9b6e968..757f6598e7 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -259,7 +259,11 @@ namespace osu.Game.Online.API var friendsReq = new GetFriendsRequest(); friendsReq.Failure += _ => state.Value = APIState.Failing; - friendsReq.Success += res => friends.AddRange(res); + friendsReq.Success += res => + { + friends.Clear(); + friends.AddRange(res); + }; if (!handleRequest(friendsReq)) { From 167ac8b5dda3b0b4d3bf42512fd1234547c525ef Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 03:03:52 +0300 Subject: [PATCH 111/121] Fix editor object being requered --- osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index c79d9d6632..8565843170 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.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.IO; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -34,7 +32,7 @@ namespace osu.Game.Screens.Edit.Setup private EditorBeatmap editorBeatmap { get; set; } [Resolved] - private Editor editor { get; set; } + private Editor? editor { get; set; } [Resolved] private SetupScreenHeader header { get; set; } @@ -96,7 +94,7 @@ namespace osu.Game.Screens.Edit.Setup working.Value.Metadata.BackgroundFile = destination.Name; header.Background.UpdateBackground(); - editor.ApplyToBackground(bg => bg.RefreshBackground()); + editor?.ApplyToBackground(bg => bg.RefreshBackground()); return true; } From b47cef838c689f551abbd5bcf1dc1f9b132c6173 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 03:08:02 +0300 Subject: [PATCH 112/121] Nullability --- .../Screens/Edit/Setup/ResourcesSection.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 8565843170..901101dcec 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -14,28 +14,28 @@ namespace osu.Game.Screens.Edit.Setup { internal partial class ResourcesSection : SetupSection { - private LabelledFileChooser audioTrackChooser; - private LabelledFileChooser backgroundChooser; + private LabelledFileChooser audioTrackChooser = null!; + private LabelledFileChooser backgroundChooser = null!; public override LocalisableString Title => EditorSetupStrings.ResourcesHeader; [Resolved] - private MusicController music { get; set; } + private MusicController music { get; set; } = null!; [Resolved] - private BeatmapManager beatmaps { get; set; } + private BeatmapManager beatmaps { get; set; } = null!; [Resolved] - private IBindable working { get; set; } + private IBindable working { get; set; } = null!; [Resolved] - private EditorBeatmap editorBeatmap { get; set; } + private EditorBeatmap editorBeatmap { get; set; } = null!; [Resolved] private Editor? editor { get; set; } [Resolved] - private SetupScreenHeader header { get; set; } + private SetupScreenHeader header { get; set; } = null!; [BackgroundDependencyLoader] private void load() @@ -128,17 +128,17 @@ namespace osu.Game.Screens.Edit.Setup return true; } - private void backgroundChanged(ValueChangedEvent file) + private void backgroundChanged(ValueChangedEvent file) { - if (!ChangeBackgroundImage(file.NewValue)) + if (!ChangeBackgroundImage(file.NewValue!)) backgroundChooser.Current.Value = file.OldValue; updatePlaceholderText(); } - private void audioTrackChanged(ValueChangedEvent file) + private void audioTrackChanged(ValueChangedEvent file) { - if (!ChangeAudioTrack(file.NewValue)) + if (!ChangeAudioTrack(file.NewValue!)) audioTrackChooser.Current.Value = file.OldValue; updatePlaceholderText(); From 904c76e437114a214ec5fcc649066ad4daadf30f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 7 Jan 2023 14:23:31 +0300 Subject: [PATCH 113/121] Use sane `BeatmapInfo` for preview time mutation `EditorBeatmap.BeatmapInfo` is usually the correct instance for mutating properties that should persist in the database. --- osu.Game/Screens/Edit/EditorBeatmap.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 1684dcf0cd..dc1fda13f4 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -110,11 +110,11 @@ namespace osu.Game.Screens.Edit foreach (var obj in HitObjects) trackStartTime(obj); - PreviewTime = new BindableInt(playableBeatmap.Metadata.PreviewTime); + PreviewTime = new BindableInt(BeatmapInfo.Metadata.PreviewTime); PreviewTime.BindValueChanged(s => { BeginChange(); - this.beatmapInfo.Metadata.PreviewTime = s.NewValue; + BeatmapInfo.Metadata.PreviewTime = s.NewValue; EndChange(); }); } From abca13eb6cb934dc81f3791f8352ee4ac1ef0a95 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 7 Jan 2023 14:30:01 +0300 Subject: [PATCH 114/121] Rewrite visualisation piece to bind once and without potential event leak --- .../Visual/Editing/TestScenePreviewTime.cs | 4 ++-- .../Summary/Parts/PreviewTimePart.cs | 20 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs index d5aa71095b..3319788c8a 100644 --- a/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs +++ b/osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs @@ -27,9 +27,9 @@ namespace osu.Game.Tests.Visual.Editing public void TestScenePreviewTimeline() { AddStep("set preview time to -1", () => EditorBeatmap.PreviewTime.Value = -1); - AddAssert("preview time line should not show", () => Editor.ChildrenOfType().Single().Alpha == 0); + AddAssert("preview time line should not show", () => !Editor.ChildrenOfType().Single().Children.Any()); AddStep("set preview time to 1000", () => EditorBeatmap.PreviewTime.Value = 1000); - AddAssert("preview time line should show", () => Editor.ChildrenOfType().Single().Alpha == 1); + AddAssert("preview time line should show", () => Editor.ChildrenOfType().Single().Children.Single().Alpha == 1); } } } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs index de7f611424..c63bb7ac24 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/PreviewTimePart.cs @@ -10,24 +10,28 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { public partial class PreviewTimePart : TimelinePart { + private readonly BindableInt previewTime = new BindableInt(); + protected override void LoadBeatmap(EditorBeatmap beatmap) { base.LoadBeatmap(beatmap); - Add(new PreviewTimeVisualisation(beatmap)); - beatmap.PreviewTime.BindValueChanged(s => + + previewTime.UnbindAll(); + previewTime.BindTo(beatmap.PreviewTime); + previewTime.BindValueChanged(t => { - Alpha = s.NewValue == -1 ? 0 : 1; + Clear(); + + if (t.NewValue >= 0) + Add(new PreviewTimeVisualisation(t.NewValue)); }, true); } private partial class PreviewTimeVisualisation : PointVisualisation { - private readonly BindableInt previewTime = new BindableInt(); - - public PreviewTimeVisualisation(EditorBeatmap editorBeatmap) + public PreviewTimeVisualisation(double time) + : base(time) { - previewTime.BindTo(editorBeatmap.PreviewTime); - previewTime.BindValueChanged(s => X = s.NewValue, true); } [BackgroundDependencyLoader] From aaeb43fbb2f48ce1f364c9ffd267abddcdcb3898 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 18:15:57 +0300 Subject: [PATCH 115/121] Return older file if new one is null --- osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 901101dcec..8c84ad90ba 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Edit.Setup private void backgroundChanged(ValueChangedEvent file) { - if (!ChangeBackgroundImage(file.NewValue!)) + if (file.NewValue == null || !ChangeBackgroundImage(file.NewValue)) backgroundChooser.Current.Value = file.OldValue; updatePlaceholderText(); @@ -138,7 +138,7 @@ namespace osu.Game.Screens.Edit.Setup private void audioTrackChanged(ValueChangedEvent file) { - if (!ChangeAudioTrack(file.NewValue!)) + if (file.NewValue == null || !ChangeAudioTrack(file.NewValue)) audioTrackChooser.Current.Value = file.OldValue; updatePlaceholderText(); From 0f6735564eeefca5ea9ef14dd85771da117b3366 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 7 Jan 2023 10:54:48 -0800 Subject: [PATCH 116/121] Move and rename nomination response model to singular --- .../BeatmapSetOnlineNomination.cs} | 4 ++-- osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs | 2 +- osu.Game/Overlays/BeatmapSet/Info.cs | 2 +- .../Overlays/BeatmapSet/MetadataSectionNominators.cs | 9 +++++---- 4 files changed, 9 insertions(+), 8 deletions(-) rename osu.Game/{Online/API/Requests/Responses/BeatmapSetOnlineNominations.cs => Beatmaps/BeatmapSetOnlineNomination.cs} (84%) diff --git a/osu.Game/Online/API/Requests/Responses/BeatmapSetOnlineNominations.cs b/osu.Game/Beatmaps/BeatmapSetOnlineNomination.cs similarity index 84% rename from osu.Game/Online/API/Requests/Responses/BeatmapSetOnlineNominations.cs rename to osu.Game/Beatmaps/BeatmapSetOnlineNomination.cs index 5d0a3ea38b..f6de414628 100644 --- a/osu.Game/Online/API/Requests/Responses/BeatmapSetOnlineNominations.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineNomination.cs @@ -3,9 +3,9 @@ using Newtonsoft.Json; -namespace osu.Game.Online.API.Requests.Responses +namespace osu.Game.Beatmaps { - public struct BeatmapSetOnlineNominations + public struct BeatmapSetOnlineNomination { [JsonProperty(@"beatmapset_id")] public int BeatmapsetId { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index eb39b7489d..fc740f1eec 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -112,7 +112,7 @@ namespace osu.Game.Online.API.Requests.Responses public BeatmapSetOnlineLanguage Language { get; set; } [JsonProperty(@"current_nominations")] - public BeatmapSetOnlineNominations[] CurrentNominations { get; set; } = Array.Empty(); + public BeatmapSetOnlineNomination[] CurrentNominations { get; set; } = Array.Empty(); [JsonProperty(@"related_users")] public APIUser[] RelatedUsers { get; set; } = Array.Empty(); diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index dbeea74f6f..58739eb471 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -125,7 +125,7 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.ValueChanged += b => { - nominators.Metadata = (b.NewValue?.CurrentNominations ?? Array.Empty(), b.NewValue?.RelatedUsers ?? Array.Empty()); + nominators.Metadata = (b.NewValue?.CurrentNominations ?? Array.Empty(), b.NewValue?.RelatedUsers ?? Array.Empty()); source.Metadata = b.NewValue?.Source ?? string.Empty; tags.Metadata = b.NewValue?.Tags ?? string.Empty; genre.Metadata = b.NewValue?.Genre ?? new BeatmapSetOnlineGenre { Id = (int)SearchGenre.Unspecified }; diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs b/osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs index 78a3fe7cd5..76dbda3d5e 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs @@ -4,15 +4,16 @@ using System; using System.Linq; using osu.Framework.Graphics; +using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet { - public partial class MetadataSectionNominators : MetadataSection<(BeatmapSetOnlineNominations[] CurrentNominations, APIUser[] RelatedUsers)> + public partial class MetadataSectionNominators : MetadataSection<(BeatmapSetOnlineNomination[] CurrentNominations, APIUser[] RelatedUsers)> { - public override (BeatmapSetOnlineNominations[] CurrentNominations, APIUser[] RelatedUsers) Metadata + public override (BeatmapSetOnlineNomination[] CurrentNominations, APIUser[] RelatedUsers) Metadata { set { @@ -26,12 +27,12 @@ namespace osu.Game.Overlays.BeatmapSet } } - public MetadataSectionNominators(Action<(BeatmapSetOnlineNominations[] CurrentNominations, APIUser[] RelatedUsers)>? searchAction = null) + public MetadataSectionNominators(Action<(BeatmapSetOnlineNomination[] CurrentNominations, APIUser[] RelatedUsers)>? searchAction = null) : base(MetadataType.Nominators, searchAction) { } - protected override void AddMetadata((BeatmapSetOnlineNominations[] CurrentNominations, APIUser[] RelatedUsers) metadata, LinkFlowContainer loaded) + protected override void AddMetadata((BeatmapSetOnlineNomination[] CurrentNominations, APIUser[] RelatedUsers) metadata, LinkFlowContainer loaded) { int[] nominatorIds = metadata.CurrentNominations.Select(n => n.UserId).ToArray(); From 9d32fde5928f1c77804090c3c1802397b58fa036 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 7 Jan 2023 11:04:42 -0800 Subject: [PATCH 117/121] Mark current nominations and related users as nullable --- osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index fc740f1eec..aeae3edde2 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -112,10 +112,10 @@ namespace osu.Game.Online.API.Requests.Responses public BeatmapSetOnlineLanguage Language { get; set; } [JsonProperty(@"current_nominations")] - public BeatmapSetOnlineNomination[] CurrentNominations { get; set; } = Array.Empty(); + public BeatmapSetOnlineNomination[]? CurrentNominations { get; set; } [JsonProperty(@"related_users")] - public APIUser[] RelatedUsers { get; set; } = Array.Empty(); + public APIUser[]? RelatedUsers { get; set; } public string Source { get; set; } = string.Empty; From bae3a6851bf256040aad4f4ab07af15437aec0ca Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 7 Jan 2023 11:15:51 -0800 Subject: [PATCH 118/121] Block hover events behind logo even if action is null --- osu.Game/Screens/Menu/OsuLogo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 7a5a26226b..e95d0384ba 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -393,7 +393,7 @@ namespace osu.Game.Screens.Menu protected override bool OnHover(HoverEvent e) { - if (Action == null) return false; + if (Action == null) return true; logoHoverContainer.ScaleTo(1.1f, 500, Easing.OutElastic); return true; From 750b55d9b7101e22473249688c7ff41d4971abb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 8 Jan 2023 22:28:19 +0900 Subject: [PATCH 119/121] Update other events to have matching return types (and animate more) --- osu.Game/Screens/Menu/OsuLogo.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index e95d0384ba..9430a1cda8 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -365,7 +365,7 @@ namespace osu.Game.Screens.Menu protected override bool OnMouseDown(MouseDownEvent e) { - if (Action == null || e.Button != MouseButton.Left) return false; + if (e.Button != MouseButton.Left) return true; logoBounceContainer.ScaleTo(0.9f, 1000, Easing.Out); return true; @@ -380,22 +380,21 @@ namespace osu.Game.Screens.Menu protected override bool OnClick(ClickEvent e) { - if (Action == null) return false; - - if (Action.Invoke()) - sampleClick.Play(); - flashLayer.ClearTransforms(); flashLayer.Alpha = 0.4f; flashLayer.FadeOut(1500, Easing.OutExpo); + + if (Action?.Invoke() == true) + sampleClick.Play(); + return true; } protected override bool OnHover(HoverEvent e) { - if (Action == null) return true; + if (Action != null) + logoHoverContainer.ScaleTo(1.1f, 500, Easing.OutElastic); - logoHoverContainer.ScaleTo(1.1f, 500, Easing.OutElastic); return true; } From f6b1dfc7b0f0f390e9fa9733aa528847a7fa648d Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 28 May 2022 21:41:23 -0700 Subject: [PATCH 120/121] Fix channel listing items overflowing at high ui scaling --- .../Chat/Listing/ChannelListingItem.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs b/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs index 22a3bdc06f..9c85c73ee4 100644 --- a/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs +++ b/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs @@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Chat.Listing private Box hoverBox = null!; private SpriteIcon checkbox = null!; private OsuSpriteText channelText = null!; - private OsuSpriteText topicText = null!; + private OsuTextFlowContainer topicText = null!; private IBindable channelJoined = null!; [Resolved] @@ -65,8 +65,8 @@ namespace osu.Game.Overlays.Chat.Listing Masking = true; CornerRadius = 5; - RelativeSizeAxes = Axes.X; - Height = 20 + (vertical_margin * 2); + RelativeSizeAxes = Content.RelativeSizeAxes = Axes.X; + AutoSizeAxes = Content.AutoSizeAxes = Axes.Y; Children = new Drawable[] { @@ -79,14 +79,19 @@ namespace osu.Game.Overlays.Chat.Listing }, new GridContainer { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, ColumnDimensions = new[] { new Dimension(GridSizeMode.Absolute, 40), new Dimension(GridSizeMode.Absolute, 200), - new Dimension(GridSizeMode.Absolute, 400), + new Dimension(maxSize: 400), new Dimension(GridSizeMode.AutoSize), - new Dimension(), + new Dimension(GridSizeMode.Absolute, 50), // enough for any 5 digit user count + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize, minSize: 20 + (vertical_margin * 2)), }, Content = new[] { @@ -108,12 +113,13 @@ namespace osu.Game.Overlays.Chat.Listing Font = OsuFont.Torus.With(size: text_size, weight: FontWeight.SemiBold), Margin = new MarginPadding { Bottom = 2 }, }, - topicText = new OsuSpriteText + topicText = new OsuTextFlowContainer(t => t.Font = OsuFont.Torus.With(size: text_size)) { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Text = Channel.Topic, - Font = OsuFont.Torus.With(size: text_size), Margin = new MarginPadding { Bottom = 2 }, }, new SpriteIcon From 4a77105e78f15b1a72d1b10a61b6dc5e8346ddc1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Jan 2023 16:28:08 +0900 Subject: [PATCH 121/121] Rename `LockPlayfieldAspect` and add comment explaining the change --- osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs | 2 +- osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs | 4 ++-- .../UI/TaikoPlayfieldAdjustmentContainer.cs | 9 +++++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index f7fdd447d6..3b3b3e606c 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset; - drawableTaikoRuleset.LockPlayfieldAspect.Value = false; + drawableTaikoRuleset.LockPlayfieldMaxAspect.Value = false; var playfield = (TaikoPlayfield)drawableRuleset.Playfield; playfield.ClassicHitTargetPosition.Value = true; diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 32a83d87b8..146daa8c27 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.UI { public new BindableDouble TimeRange => base.TimeRange; - public readonly BindableBool LockPlayfieldAspect = new BindableBool(true); + public readonly BindableBool LockPlayfieldMaxAspect = new BindableBool(true); protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; @@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Taiko.UI public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer { - LockPlayfieldAspect = { BindTarget = LockPlayfieldAspect } + LockPlayfieldMaxAspect = { BindTarget = LockPlayfieldMaxAspect } }; protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo); diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs index d42aaddf9e..42732d90e4 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.UI private const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768; private const float default_aspect = 16f / 9f; - public readonly IBindable LockPlayfieldAspect = new BindableBool(true); + public readonly IBindable LockPlayfieldMaxAspect = new BindableBool(true); protected override void Update() { @@ -21,7 +21,12 @@ namespace osu.Game.Rulesets.Taiko.UI float height = default_relative_height; - if (LockPlayfieldAspect.Value && Parent.ChildSize.X / Parent.ChildSize.Y > default_aspect) + // Players coming from stable expect to be able to change the aspect ratio regardless of the window size. + // We originally wanted to limit this more, but there was considerable pushback from the community. + // + // As a middle-ground, the aspect ratio can still be adjusted in the downwards direction but has a maximum limit. + // This is still a bit weird, because readability changes with window size, but it is what it is. + if (LockPlayfieldMaxAspect.Value && Parent.ChildSize.X / Parent.ChildSize.Y > default_aspect) height *= Math.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect; Height = height;